[
  {
    "path": ".codecov.yml",
    "content": "coverage:\n  status:\n    # pull-requests only\n    patch:\n      default:\n        threshold: 0.1%\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/any-questions-on-canal.md",
    "content": "---\nname: Any Questions on Canal\nabout: Ask whatever you want to know or confusion about Canal\n\n---\n\n## Question\n<!-- You can ask any question about this project -->\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report-for-canal.md",
    "content": "---\nname: Bug Report for Canal\nabout: Create a report to help us improve\n\n---\n\n- [ ] I have searched the [issues](https://github.com/alibaba/canal/issues) of this repository and believe that this is not a duplicate.\n- [ ] I have checked the [FAQ](https://github.com/alibaba/canal/wiki/FAQ) of this repository and believe that this is not a duplicate.\n\n### environment\n\n* canal version\n* mysql version\n\n### Issue Description\n\n\n### Steps to reproduce\n\n### Expected behaviour\n\n### Actual behaviour\n\n\nIf there is an exception, please attach the exception trace:\n\n```\nJust put your stack trace here!\n```"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature-request-of-canal.md",
    "content": "---\nname: Feature Request of Canal\nabout: Suggest an idea for this project\n\n---\n\n## Why you need it?\n<!-- Is your feature request related to a problem? Please describe in details  -->\n\n\n## How it could be?\n<!--A clear and concise description of what you want to happen. For a computer fan,  you can explain more about input of the feature, and output of it.-->\n\n\n## Other related information\n<!-- Add any other context or screenshots about the feature request here.-->\n"
  },
  {
    "path": ".github/workflows/maven.yml",
    "content": "# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time\n# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven\n\n# This workflow uses actions that are not certified by GitHub.\n# They are provided by a third-party and are governed by\n# separate terms of service, privacy policy, and support\n# documentation.\n\nname: Java CI with Maven\n\non:\n  push:\n    branches: [ \"master\" ]\n  pull_request:\n    branches: [ \"master\" ]\n\npermissions:\n  contents: read\n\njobs:\n  test:\n    runs-on: ${{ matrix.os }}\n    permissions:\n      contents: read\n    strategy:\n      matrix:\n        os: [ ubuntu-latest ]\n        java: [ 8, 11, 17, 21 ]\n      fail-fast: false\n      max-parallel: 16\n    name: Test JDK ${{ matrix.java }}, ${{ matrix.os }}\n\n    steps:\n      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2\n      - name: Set up JDK\n        uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1\n        with:\n          distribution: 'temurin'\n          java-version: ${{ matrix.java }}\n          cache: 'maven'\n      - name: Build with Maven if test jdk8\n        if: ${{ matrix.java == '8' || matrix.java == '11'}}\n        run: ./mvnw -Pgen-javadoc clean package -B\n      - name: Build with Maven if test jdk17\n        if: ${{ matrix.java == '17' || matrix.java == '21' }}\n        run: ./mvnw -Penable-for-jdk17+,gen-code-cov clean package -B\n"
  },
  {
    "path": ".gitignore",
    "content": ".svn/\ntarget/\ntest-output/\n*.class\n.classpath\n.project\n.settings/\ntmp\ntemp\nlogs/\n*.log\nantx.properties\notter.properties\njtester.properties\n.idea/\n*.iml\n.DS_Store\n*.tar.gz\n*.rpm\nclient-adapter/example/\n*.dat\nconf/\ncanal-admin/canal-admin-ui/dist/\ncanal-admin/canal-admin-ui/node/\ncanal-admin/canal-admin-ui/node_modules/\ncanal-admin/canal-admin-server/src/main/resources/conf/\n"
  },
  {
    "path": ".mvn/wrapper/maven-wrapper.properties",
    "content": "distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.0/apache-maven-3.5.0-bin.zip\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: java\nsudo: false # faster builds\n\njdk:\n  - oraclejdk12\n  - openjdk11\n  - oraclejdk11\n  - openjdk8\n\ncache:\n  directories:\n    - $HOME/.m2\n\ninstall: true\n\nscript:\n  - travis_wait 30 ./mvnw -T 1C clean install -DskipTests=false -Dcheckstyle.skip=true -Dmaven.javadoc.skip=true\n\nafter_success:\n  - bash <(curl -s https://codecov.io/bash)\n\nafter_failure:\n  - if [ -f canal.log ]; then echo \"------TAIL of canal.log------\"; tail -n 1000 canal.log; echo \"------END of canal.log------\"; fi\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "\r\n                                 Apache License\r\n                           Version 2.0, January 2004\r\n                        http://www.apache.org/licenses/\r\n\r\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\r\n\r\n   1. Definitions.\r\n\r\n      \"License\" shall mean the terms and conditions for use, reproduction,\r\n      and distribution as defined by Sections 1 through 9 of this document.\r\n\r\n      \"Licensor\" shall mean the copyright owner or entity authorized by\r\n      the copyright owner that is granting the License.\r\n\r\n      \"Legal Entity\" shall mean the union of the acting entity and all\r\n      other entities that control, are controlled by, or are under common\r\n      control with that entity. For the purposes of this definition,\r\n      \"control\" means (i) the power, direct or indirect, to cause the\r\n      direction or management of such entity, whether by contract or\r\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\r\n      outstanding shares, or (iii) beneficial ownership of such entity.\r\n\r\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\r\n      exercising permissions granted by this License.\r\n\r\n      \"Source\" form shall mean the preferred form for making modifications,\r\n      including but not limited to software source code, documentation\r\n      source, and configuration files.\r\n\r\n      \"Object\" form shall mean any form resulting from mechanical\r\n      transformation or translation of a Source form, including but\r\n      not limited to compiled object code, generated documentation,\r\n      and conversions to other media types.\r\n\r\n      \"Work\" shall mean the work of authorship, whether in Source or\r\n      Object form, made available under the License, as indicated by a\r\n      copyright notice that is included in or attached to the work\r\n      (an example is provided in the Appendix below).\r\n\r\n      \"Derivative Works\" shall mean any work, whether in Source or Object\r\n      form, that is based on (or derived from) the Work and for which the\r\n      editorial revisions, annotations, elaborations, or other modifications\r\n      represent, as a whole, an original work of authorship. For the purposes\r\n      of this License, Derivative Works shall not include works that remain\r\n      separable from, or merely link (or bind by name) to the interfaces of,\r\n      the Work and Derivative Works thereof.\r\n\r\n      \"Contribution\" shall mean any work of authorship, including\r\n      the original version of the Work and any modifications or additions\r\n      to that Work or Derivative Works thereof, that is intentionally\r\n      submitted to Licensor for inclusion in the Work by the copyright owner\r\n      or by an individual or Legal Entity authorized to submit on behalf of\r\n      the copyright owner. For the purposes of this definition, \"submitted\"\r\n      means any form of electronic, verbal, or written communication sent\r\n      to the Licensor or its representatives, including but not limited to\r\n      communication on electronic mailing lists, source code control systems,\r\n      and issue tracking systems that are managed by, or on behalf of, the\r\n      Licensor for the purpose of discussing and improving the Work, but\r\n      excluding communication that is conspicuously marked or otherwise\r\n      designated in writing by the copyright owner as \"Not a Contribution.\"\r\n\r\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\r\n      on behalf of whom a Contribution has been received by Licensor and\r\n      subsequently incorporated within the Work.\r\n\r\n   2. Grant of Copyright License. Subject to the terms and conditions of\r\n      this License, each Contributor hereby grants to You a perpetual,\r\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r\n      copyright license to reproduce, prepare Derivative Works of,\r\n      publicly display, publicly perform, sublicense, and distribute the\r\n      Work and such Derivative Works in Source or Object form.\r\n\r\n   3. Grant of Patent License. Subject to the terms and conditions of\r\n      this License, each Contributor hereby grants to You a perpetual,\r\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r\n      (except as stated in this section) patent license to make, have made,\r\n      use, offer to sell, sell, import, and otherwise transfer the Work,\r\n      where such license applies only to those patent claims licensable\r\n      by such Contributor that are necessarily infringed by their\r\n      Contribution(s) alone or by combination of their Contribution(s)\r\n      with the Work to which such Contribution(s) was submitted. If You\r\n      institute patent litigation against any entity (including a\r\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\r\n      or a Contribution incorporated within the Work constitutes direct\r\n      or contributory patent infringement, then any patent licenses\r\n      granted to You under this License for that Work shall terminate\r\n      as of the date such litigation is filed.\r\n\r\n   4. Redistribution. You may reproduce and distribute copies of the\r\n      Work or Derivative Works thereof in any medium, with or without\r\n      modifications, and in Source or Object form, provided that You\r\n      meet the following conditions:\r\n\r\n      (a) You must give any other recipients of the Work or\r\n          Derivative Works a copy of this License; and\r\n\r\n      (b) You must cause any modified files to carry prominent notices\r\n          stating that You changed the files; and\r\n\r\n      (c) You must retain, in the Source form of any Derivative Works\r\n          that You distribute, all copyright, patent, trademark, and\r\n          attribution notices from the Source form of the Work,\r\n          excluding those notices that do not pertain to any part of\r\n          the Derivative Works; and\r\n\r\n      (d) If the Work includes a \"NOTICE\" text file as part of its\r\n          distribution, then any Derivative Works that You distribute must\r\n          include a readable copy of the attribution notices contained\r\n          within such NOTICE file, excluding those notices that do not\r\n          pertain to any part of the Derivative Works, in at least one\r\n          of the following places: within a NOTICE text file distributed\r\n          as part of the Derivative Works; within the Source form or\r\n          documentation, if provided along with the Derivative Works; or,\r\n          within a display generated by the Derivative Works, if and\r\n          wherever such third-party notices normally appear. The contents\r\n          of the NOTICE file are for informational purposes only and\r\n          do not modify the License. You may add Your own attribution\r\n          notices within Derivative Works that You distribute, alongside\r\n          or as an addendum to the NOTICE text from the Work, provided\r\n          that such additional attribution notices cannot be construed\r\n          as modifying the License.\r\n\r\n      You may add Your own copyright statement to Your modifications and\r\n      may provide additional or different license terms and conditions\r\n      for use, reproduction, or distribution of Your modifications, or\r\n      for any such Derivative Works as a whole, provided Your use,\r\n      reproduction, and distribution of the Work otherwise complies with\r\n      the conditions stated in this License.\r\n\r\n   5. Submission of Contributions. Unless You explicitly state otherwise,\r\n      any Contribution intentionally submitted for inclusion in the Work\r\n      by You to the Licensor shall be under the terms and conditions of\r\n      this License, without any additional terms or conditions.\r\n      Notwithstanding the above, nothing herein shall supersede or modify\r\n      the terms of any separate license agreement you may have executed\r\n      with Licensor regarding such Contributions.\r\n\r\n   6. Trademarks. This License does not grant permission to use the trade\r\n      names, trademarks, service marks, or product names of the Licensor,\r\n      except as required for reasonable and customary use in describing the\r\n      origin of the Work and reproducing the content of the NOTICE file.\r\n\r\n   7. Disclaimer of Warranty. Unless required by applicable law or\r\n      agreed to in writing, Licensor provides the Work (and each\r\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\r\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\r\n      implied, including, without limitation, any warranties or conditions\r\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\r\n      PARTICULAR PURPOSE. You are solely responsible for determining the\r\n      appropriateness of using or redistributing the Work and assume any\r\n      risks associated with Your exercise of permissions under this License.\r\n\r\n   8. Limitation of Liability. In no event and under no legal theory,\r\n      whether in tort (including negligence), contract, or otherwise,\r\n      unless required by applicable law (such as deliberate and grossly\r\n      negligent acts) or agreed to in writing, shall any Contributor be\r\n      liable to You for damages, including any direct, indirect, special,\r\n      incidental, or consequential damages of any character arising as a\r\n      result of this License or out of the use or inability to use the\r\n      Work (including but not limited to damages for loss of goodwill,\r\n      work stoppage, computer failure or malfunction, or any and all\r\n      other commercial damages or losses), even if such Contributor\r\n      has been advised of the possibility of such damages.\r\n\r\n   9. Accepting Warranty or Additional Liability. While redistributing\r\n      the Work or Derivative Works thereof, You may choose to offer,\r\n      and charge a fee for, acceptance of support, warranty, indemnity,\r\n      or other liability obligations and/or rights consistent with this\r\n      License. However, in accepting such obligations, You may act only\r\n      on Your own behalf and on Your sole responsibility, not on behalf\r\n      of any other Contributor, and only if You agree to indemnify,\r\n      defend, and hold each Contributor harmless for any liability\r\n      incurred by, or claims asserted against, such Contributor by reason\r\n      of your accepting any such warranty or additional liability.\r\n\r\n   END OF TERMS AND CONDITIONS\r\n\r\n   APPENDIX: How to apply the Apache License to your work.\r\n\r\n      To apply the Apache License to your work, attach the following\r\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\r\n      replaced with your own identifying information. (Don't include\r\n      the brackets!)  The text should be enclosed in the appropriate\r\n      comment syntax for the file format. We also recommend that a\r\n      file or class name and description of purpose be included on the\r\n      same \"printed page\" as the copyright notice for easier\r\n      identification within third-party archives.\r\n\r\n   Copyright [yyyy] [name of copyright owner]\r\n\r\n   Licensed under the Apache License, Version 2.0 (the \"License\");\r\n   you may not use this file except in compliance with the License.\r\n   You may obtain a copy of the License at\r\n\r\n       http://www.apache.org/licenses/LICENSE-2.0\r\n\r\n   Unless required by applicable law or agreed to in writing, software\r\n   distributed under the License is distributed on an \"AS IS\" BASIS,\r\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n   See the License for the specific language governing permissions and\r\n   limitations under the License.\r\n"
  },
  {
    "path": "README.md",
    "content": "[![build status](https://travis-ci.com/alibaba/canal.svg?branch=master)](https://travis-ci.com/alibaba/canal)\n[![codecov](https://codecov.io/gh/alibaba/canal/branch/master/graph/badge.svg)](https://codecov.io/gh/alibaba/canal)\n![maven](https://img.shields.io/maven-central/v/com.alibaba.otter/canal.svg)\n![license](https://img.shields.io/github/license/alibaba/canal.svg)\n[![average time to resolve an issue](http://isitmaintained.com/badge/resolution/alibaba/canal.svg)](http://isitmaintained.com/project/alibaba/canal \"average time to resolve an issue\")\n[![percentage of issues still open](http://isitmaintained.com/badge/open/alibaba/canal.svg)](http://isitmaintained.com/project/alibaba/canal \"percentage of issues still open\")\n[![Leaderboard](https://img.shields.io/badge/Canal-%E6%9F%A5%E7%9C%8B%E8%B4%A1%E7%8C%AE%E6%8E%92%E8%A1%8C%E6%A6%9C-orange)](https://opensource.alibaba.com/contribution_leaderboard/details?projectValue=canal)\n\n\n## 简介\n\n![](https://img-blog.csdnimg.cn/20191104101735947.png)\n\n**canal [kə'næl]**，译意为水道/管道/沟渠，主要用途是基于 MySQL 数据库增量日志解析，提供增量数据订阅和消费\n\n早期阿里巴巴因为杭州和美国双机房部署，存在跨机房同步的业务需求，实现方式主要是基于业务 trigger 获取增量变更。从 2010 年开始，业务逐步尝试数据库日志解析获取增量变更进行同步，由此衍生出了大量的数据库增量订阅和消费业务。\n\n基于日志增量订阅和消费的业务包括\n- 数据库镜像\n- 数据库实时备份\n- 索引构建和实时维护(拆分异构索引、倒排索引等)\n- 业务 cache 刷新\n- 带业务逻辑的增量数据处理\n\n当前的 canal 支持源端 MySQL 版本包括 5.1.x , 5.5.x , 5.6.x , 5.7.x , 8.0.x\n\n## 工作原理\n\n#### MySQL主备复制原理\n![](http://dl.iteye.com/upload/attachment/0080/3086/468c1a14-e7ad-3290-9d3d-44ac501a7227.jpg)\n\n- MySQL master 将数据变更写入二进制日志( binary log, 其中记录叫做二进制日志事件binary log events，可以通过 show binlog events 进行查看)\n- MySQL slave 将 master 的 binary log events 拷贝到它的中继日志(relay log)\n- MySQL slave 重放 relay log 中事件，将数据变更反映它自己的数据\n\n#### canal 工作原理\n\n- canal 模拟 MySQL slave 的交互协议，伪装自己为 MySQL slave ，向 MySQL master 发送dump 协议\n- MySQL master 收到 dump 请求，开始推送 binary log 给 slave (即 canal )\n- canal 解析 binary log 对象(原始为 byte 流)\n\n## 重要版本更新说明\n\n1. canal 1.1.x 版本（[release_note](https://github.com/alibaba/canal/releases)）,性能与功能层面有较大的突破,重要提升包括:\n\n- 整体性能测试&优化,提升了150%. #726 参考: [Performance](https://github.com/alibaba/canal/wiki/Performance)\n- 原生支持prometheus监控 #765 [Prometheus QuickStart](https://github.com/alibaba/canal/wiki/Prometheus-QuickStart)\n- 原生支持kafka消息投递 #695 [Canal Kafka/RocketMQ QuickStart](https://github.com/alibaba/canal/wiki/Canal-Kafka-RocketMQ-QuickStart)\n- 原生支持aliyun rds的binlog订阅 (解决自动主备切换/oss binlog离线解析) 参考: [Aliyun RDS QuickStart](https://github.com/alibaba/canal/wiki/aliyun-RDS-QuickStart)\n- 原生支持docker镜像 #801 参考: [Docker QuickStart](https://github.com/alibaba/canal/wiki/Docker-QuickStart)\n\n2.  canal 1.1.4版本，迎来最重要的WebUI能力，引入canal-admin工程，支持面向WebUI的canal动态管理能力，支持配置、任务、日志等在线白屏运维能力，具体文档：[Canal Admin Guide](https://github.com/alibaba/canal/wiki/Canal-Admin-Guide)\n\n## 文档\n\n- [Home](https://github.com/alibaba/canal/wiki/Home)\n- [Introduction](https://github.com/alibaba/canal/wiki/Introduction)\n- [QuickStart](https://github.com/alibaba/canal/wiki/QuickStart)\n  - [Docker QuickStart](https://github.com/alibaba/canal/wiki/Docker-QuickStart)\n  - [Canal Kafka/RocketMQ QuickStart](https://github.com/alibaba/canal/wiki/Canal-Kafka-RocketMQ-QuickStart\")\n  - [Aliyun RDS for MySQL QuickStart](https://github.com/alibaba/canal/wiki/aliyun-RDS-QuickStart)\n  - [Prometheus QuickStart](https://github.com/alibaba/canal/wiki/Prometheus-QuickStart)\n- Canal Admin\n  - [Canal Admin QuickStart](https://github.com/alibaba/canal/wiki/Canal-Admin-QuickStart)\n  - [Canal Admin Guide](https://github.com/alibaba/canal/wiki/Canal-Admin-Guide)\n  - [Canal Admin ServerGuide](https://github.com/alibaba/canal/wiki/Canal-Admin-ServerGuide)\n  - [Canal Admin Docker](https://github.com/alibaba/canal/wiki/Canal-Admin-Docker)\n- [AdminGuide](https://github.com/alibaba/canal/wiki/AdminGuide)\n- [ClientExample](https://github.com/alibaba/canal/wiki/ClientExample)\n- [ClientAPI](https://github.com/alibaba/canal/wiki/ClientAPI)\n- [Performance](https://github.com/alibaba/canal/wiki/Performance)\n- [DevGuide](https://github.com/alibaba/canal/wiki/DevGuide)\n- [BinlogChange(MySQL 5.6)](https://github.com/alibaba/canal/wiki/BinlogChange%28mysql5.6%29)\n- [BinlogChange(MariaDB)](https://github.com/alibaba/canal/wiki/BinlogChange%28MariaDB%29)\n- [TableMetaTSDB](https://github.com/alibaba/canal/wiki/TableMetaTSDB)\n- [ReleaseNotes](http://alibaba.github.com/canal/release.html)\n- [Download](https://github.com/alibaba/canal/releases)\n- [FAQ](https://github.com/alibaba/canal/wiki/FAQ)\n\n## 多语言\n\ncanal 特别设计了 client-server 模式，交互协议使用 protobuf 3.0 , client 端可采用不同语言实现不同的消费逻辑，欢迎大家提交 pull request \n  \n- canal java 客户端: [https://github.com/alibaba/canal/wiki/ClientExample](https://github.com/alibaba/canal/wiki/ClientExample)\n- canal c# 客户端: [https://github.com/dotnetcore/CanalSharp](https://github.com/dotnetcore/CanalSharp)\n- canal go客户端: [https://github.com/CanalClient/canal-go](https://github.com/CanalClient/canal-go)\n- canal php客户端: [https://github.com/xingwenge/canal-php](https://github.com/xingwenge/canal-php)\n- canal Python客户端：[https://github.com/haozi3156666/canal-python](https://github.com/haozi3156666/canal-python)\n- canal Rust客户端：[https://github.com/laohanlinux/canal-rs](https://github.com/laohanlinux/canal-rs)\n- canal Nodejs客户端：[https://github.com/marmot-z/canal-nodejs](https://github.com/marmot-z/canal-nodejs)\n\ncanal 作为 MySQL binlog 增量获取和解析工具，可将变更记录投递到 MQ 系统中，比如 Kafka/RocketMQ，可以借助于 MQ 的多语言能力 \n\n- 参考文档: [Canal Kafka/RocketMQ QuickStart](https://github.com/alibaba/canal/wiki/Canal-Kafka-RocketMQ-QuickStart)\n\n## 基于canal开发的工具\n\n-  canal2sql(基于binlog生成SQL) : [https://github.com/zhuchao941/canal2sql]\n\n## 相关开源&产品\n\n- [canal 消费端开源项目: Otter](http://github.com/alibaba/otter)\n- [阿里巴巴去 Oracle 数据迁移同步工具: yugong](http://github.com/alibaba/yugong)\n- [阿里巴巴离线同步开源项目 DataX](https://github.com/alibaba/datax)\n- [阿里巴巴数据库连接池开源项目 Druid](https://github.com/alibaba/druid)\n- [阿里巴巴实时数据同步工具 DTS](https://www.aliyun.com/product/dts)\n\n## 问题反馈\n- 报告 issue: [github issues](https://github.com/alibaba/canal/issues)\n\n本项目的Issues会被同步沉淀至[阿里云开发者社区](https://developer.aliyun.com/ask)\n"
  },
  {
    "path": "RELEASE.txt",
    "content": "release link : https://alibaba.github.com/canal/release.html\n\ndownload link : https://github.com/alibaba/canal/releases\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# 漏洞奖励计划 \n## 报告\n如果您认为自己在本程序中发现了任何安全（技术）漏洞，欢迎您通过 https://security.alibaba.com 向我们提交漏洞报告。\n如果您报告任何安全漏洞，请注意您可能包含以下信息（合格报告）：\n* git程序URL地址，运行的环境\n* 包含必要屏幕截图的详细说明\n* 重现漏洞的步骤以及修复漏洞的建议。\n* 其他有用信息\n\n## 处理\nASRC（Alibaba Security Response Center阿里安全响应中心）将尽快审核并回复您的提交内容，并在我们努力修复您提交的漏洞时随时通知您。如有必要，我们可能会与您联系以获取更多信息。\n\n\n## 条款和条件\n1. 仅接受技术漏洞并对其进行评级\n2. 出于安全原因，上报者同意与ASRC合作完成他/她提交的漏洞，不向任何第三方透露任何漏洞信息\n3. 如果不止一个人报告相同的安全漏洞，奖励将给予完成合格报告的第一个人\n4. 为了保护程序的用户，请在修复之前不要直接提交git的issue，也不要在社区讨论任何漏洞信息\n5. 所有奖励和声誉积分将提供给仅向ASRC提交其安全漏洞的上报者\n6. 安全漏洞奖励的解释权利归ASRC所有\n\n## 收集范围\n我们的主要收集漏洞类别是：\n* 服务器端请求伪造（SSRF）\n* SQL注入\n* 拒绝服务攻击\n* 远程执行代码（RCE）\n* XML外部实体攻击（XXE）\n* 访问控制问题（不安全的直接对象参考问题等）\n* 敏感目录遍历问题\n* 本地文件读取（LFD）\n* 敏感信息泄露（密钥，Cookie，Session等）\n\n## 奖励\n* 可直接导致严重问题的每个漏洞奖励7000元人民币\n* 存在限制及需要一定特殊环境下才能利用的问题将给予700-5600元人民币不等的奖励，比如需要用户主动点击才会触发的问题或需要admin权限\n* 只有在指定环境下才可以运行的利用将有可能被收纳但不给予奖励，或直接被忽略，比如只在fastjson+linux特定版本才会出现的问题\n\n## 不在收集范围的报告\n* 影响过时浏览器或平台用户的漏洞\n* Self-XSS\n* 会话固定\n* 内容欺骗\n* 缺少cookie标记\n* 混合内容警告\n* SSL / TLS问题\n* Clickjacking \n* 基于Flash的漏洞\n* 反射文件下载攻击（RFD）\n* 物理或社会工程攻击\n* 未验证自动化工具或扫描仪的结果\n* 登录/注销/未认证/低影响CSRF\n* 需要MITM或物理访问用户设备的攻击\n* 与网络协议或行业标准相关的问题\n* 不能用于直接攻击的错误信息泄露\n* 缺少与安全相关的HTTP标头等\n\n\n\n\n\n# Vulnerability Reward Program\n## Reporting\nIf you believe you have found any security (technical) vulnerability in the Program, you are welcomed to submit a vulnerability report to us at https://security.alibaba.com \nIn case of reporting any security vulnerability, please be noted that you may including following information (Qualified Reporting):\n* The git program URL and running version \n* A detailed description with necessary screenshots\n* Steps to reappearance the vulnerability and your advice to fix it\n* Other useful information\n\n\n## Processing\nASRC (Alibaba Security Response Center) will review and respond as quickly as possible to your submission, and keep you informed as we work to fix the vulnerability you submitted. We may contact you for further information if necessary.\n\n\n## Terms and Conditions\n1. ONLY technical vulnerabilities will be accepted and rated.\n2. With regarding to security reasons, reporters agree to cooperate with ASRC exclusively on the vulnerability he/she submitted and not disclose any information of vulnerability to any third-parties.\n3. In the case that more than one person report the same security vulnerability, the reward will be given to the first person who accomplish a Qualified Reporting.\n4. To protect users of the program, please do not directly submit issue on github or discuss anything with the community \n5. All Rewards and Reputation Credits are given to the reporters who submit his/her security vulnerabilities ONLY to ASRC.\n6. All rights for the security vulnerability rewards are reserved by ASRC.\n\n## Scope of Collecting\nThe main categories of vulnerabilities that we are sincerely looking for are:\n* Server-Side Request Forgery (SSRF)\n* SQL Injection\n* Denial of Service Attack\n* Remote Code Execution (RCE)\n* XML External Entity Attacks (XXE)\n* Access Control Issues (Insecure Direct Object Reference issues, etc.)\n* Directory Traversal Issues\n* Local File Disclosure (LFD)\n* Sensitive Information Leakage (Key, Cookie, Session etc.)\n\n## Reward\n* $1,000 for one valid report\n* $100-$800 for Vuls which is limited. For example, Vuls that need user interactions or administrator authority\n* Vuls which only work on the special version will be accepted but no reward, or directly rejected. For example, Vul runs only on a special linux version\n\n## Ineligible Reports\n* Vulnerabilities affecting users of outdated browsers or platforms\n* \"Self\" XSS\n* Session fixation\n* Content Spoofing\n* Missing cookie flags\n* Mixed content warnings\n* SSL/TLS best practices\n* Clickjacking/UI redressing\n* Flash-based vulnerabilities\n* Reflected file download attacks (RFD)\n* Physical or social engineering attacks\n* Unverified Results of automated tools or scanners\n* Login/logout/unauthenticated/low-impact CSRF\n* Attacks requiring MITM or physical access to a user's device\n* Issues related to networking protocols or industry standards\n* Error information disclosure that cannot be used to make a direct attack\n* Missing security-related HTTP headers which do not lead directly to a vulnerability\n"
  },
  {
    "path": "admin/admin-ui/.editorconfig",
    "content": "# http://editorconfig.org\nroot = true\n\n[*]\ncharset = utf-8\nindent_style = space\nindent_size = 2\nend_of_line = lf\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n\n[*.md]\ninsert_final_newline = false\ntrim_trailing_whitespace = false\n"
  },
  {
    "path": "admin/admin-ui/.eslintignore",
    "content": "build/*.js\nsrc/assets\npublic\ndist\n"
  },
  {
    "path": "admin/admin-ui/.eslintrc.js",
    "content": "module.exports = {\n  root: true,\n  parserOptions: {\n    parser: 'babel-eslint',\n    sourceType: 'module'\n  },\n  env: {\n    browser: true,\n    node: true,\n    es6: true,\n  },\n  extends: ['plugin:vue/recommended', 'eslint:recommended'],\n\n  // add your custom rules here\n  //it is base on https://github.com/vuejs/eslint-config-vue\n  rules: {\n    \"vue/max-attributes-per-line\": [2, {\n      \"singleline\": 10,\n      \"multiline\": {\n        \"max\": 1,\n        \"allowFirstLine\": false\n      }\n    }],\n    \"vue/singleline-html-element-content-newline\": \"off\",\n    \"vue/multiline-html-element-content-newline\":\"off\",\n    \"vue/name-property-casing\": [\"error\", \"PascalCase\"],\n    \"vue/no-v-html\": \"off\",\n    'accessor-pairs': 2,\n    'arrow-spacing': [2, {\n      'before': true,\n      'after': true\n    }],\n    'block-spacing': [2, 'always'],\n    'brace-style': [2, '1tbs', {\n      'allowSingleLine': true\n    }],\n    'camelcase': [0, {\n      'properties': 'always'\n    }],\n    'comma-dangle': [2, 'never'],\n    'comma-spacing': [2, {\n      'before': false,\n      'after': true\n    }],\n    'comma-style': [2, 'last'],\n    'constructor-super': 2,\n    'curly': [2, 'multi-line'],\n    'dot-location': [2, 'property'],\n    'eol-last': 2,\n    'eqeqeq': [\"error\", \"always\", {\"null\": \"ignore\"}],\n    'generator-star-spacing': [2, {\n      'before': true,\n      'after': true\n    }],\n    'handle-callback-err': [2, '^(err|error)$'],\n    'indent': [2, 2, {\n      'SwitchCase': 1\n    }],\n    'jsx-quotes': [2, 'prefer-single'],\n    'key-spacing': [2, {\n      'beforeColon': false,\n      'afterColon': true\n    }],\n    'keyword-spacing': [2, {\n      'before': true,\n      'after': true\n    }],\n    'new-cap': [2, {\n      'newIsCap': true,\n      'capIsNew': false\n    }],\n    'new-parens': 2,\n    'no-array-constructor': 2,\n    'no-caller': 2,\n    'no-console': 'off',\n    'no-class-assign': 2,\n    'no-cond-assign': 2,\n    'no-const-assign': 2,\n    'no-control-regex': 0,\n    'no-delete-var': 2,\n    'no-dupe-args': 2,\n    'no-dupe-class-members': 2,\n    'no-dupe-keys': 2,\n    'no-duplicate-case': 2,\n    'no-empty-character-class': 2,\n    'no-empty-pattern': 2,\n    'no-eval': 2,\n    'no-ex-assign': 2,\n    'no-extend-native': 2,\n    'no-extra-bind': 2,\n    'no-extra-boolean-cast': 2,\n    'no-extra-parens': [2, 'functions'],\n    'no-fallthrough': 2,\n    'no-floating-decimal': 2,\n    'no-func-assign': 2,\n    'no-implied-eval': 2,\n    'no-inner-declarations': [2, 'functions'],\n    'no-invalid-regexp': 2,\n    'no-irregular-whitespace': 2,\n    'no-iterator': 2,\n    'no-label-var': 2,\n    'no-labels': [2, {\n      'allowLoop': false,\n      'allowSwitch': false\n    }],\n    'no-lone-blocks': 2,\n    'no-mixed-spaces-and-tabs': 2,\n    'no-multi-spaces': 2,\n    'no-multi-str': 2,\n    'no-multiple-empty-lines': [2, {\n      'max': 1\n    }],\n    'no-native-reassign': 2,\n    'no-negated-in-lhs': 2,\n    'no-new-object': 2,\n    'no-new-require': 2,\n    'no-new-symbol': 2,\n    'no-new-wrappers': 2,\n    'no-obj-calls': 2,\n    'no-octal': 2,\n    'no-octal-escape': 2,\n    'no-path-concat': 2,\n    'no-proto': 2,\n    'no-redeclare': 2,\n    'no-regex-spaces': 2,\n    'no-return-assign': [2, 'except-parens'],\n    'no-self-assign': 2,\n    'no-self-compare': 2,\n    'no-sequences': 2,\n    'no-shadow-restricted-names': 2,\n    'no-spaced-func': 2,\n    'no-sparse-arrays': 2,\n    'no-this-before-super': 2,\n    'no-throw-literal': 2,\n    'no-trailing-spaces': 2,\n    'no-undef': 2,\n    'no-undef-init': 2,\n    'no-unexpected-multiline': 2,\n    'no-unmodified-loop-condition': 2,\n    'no-unneeded-ternary': [2, {\n      'defaultAssignment': false\n    }],\n    'no-unreachable': 2,\n    'no-unsafe-finally': 2,\n    'no-unused-vars': [2, {\n      'vars': 'all',\n      'args': 'none'\n    }],\n    'no-useless-call': 2,\n    'no-useless-computed-key': 2,\n    'no-useless-constructor': 2,\n    'no-useless-escape': 0,\n    'no-whitespace-before-property': 2,\n    'no-with': 2,\n    'one-var': [2, {\n      'initialized': 'never'\n    }],\n    'operator-linebreak': [2, 'after', {\n      'overrides': {\n        '?': 'before',\n        ':': 'before'\n      }\n    }],\n    'padded-blocks': [2, 'never'],\n    'quotes': [2, 'single', {\n      'avoidEscape': true,\n      'allowTemplateLiterals': true\n    }],\n    'semi': [2, 'never'],\n    'semi-spacing': [2, {\n      'before': false,\n      'after': true\n    }],\n    'space-before-blocks': [2, 'always'],\n    'space-before-function-paren': [2, 'never'],\n    'space-in-parens': [2, 'never'],\n    'space-infix-ops': 2,\n    'space-unary-ops': [2, {\n      'words': true,\n      'nonwords': false\n    }],\n    'spaced-comment': [2, 'always', {\n      'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']\n    }],\n    'template-curly-spacing': [2, 'never'],\n    'use-isnan': 2,\n    'valid-typeof': 2,\n    'wrap-iife': [2, 'any'],\n    'yield-star-spacing': [2, 'both'],\n    'yoda': [2, 'never'],\n    'prefer-const': 2,\n    'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,\n    'object-curly-spacing': [2, 'always', {\n      objectsInObjects: false\n    }],\n    'array-bracket-spacing': [2, 'never']\n  }\n}\n"
  },
  {
    "path": "admin/admin-ui/.gitignore",
    "content": ".DS_Store\nnode_modules/\ndist/\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npackage-lock.json\ntests/**/coverage/\ntarget/\n\n# Editor directories and files\n.idea\n.vscode\n*.suo\n*.ntvs*\n*.njsproj\n*.sln\n"
  },
  {
    "path": "admin/admin-ui/.travis.yml",
    "content": "language: node_js\nnode_js: 10\nscript: npm run test\nnotifications:\n  email: false\n"
  },
  {
    "path": "admin/admin-ui/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017-present PanJiaChen\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "admin/admin-ui/babel.config.js",
    "content": "module.exports = {\n  presets: [\n    '@vue/app'\n  ]\n}\n"
  },
  {
    "path": "admin/admin-ui/build/index.js",
    "content": "const { run } = require('runjs')\nconst chalk = require('chalk')\nconst config = require('../vue.config.js')\nconst rawArgv = process.argv.slice(2)\nconst args = rawArgv.join(' ')\n\nif (process.env.npm_config_preview || rawArgv.includes('--preview')) {\n  const report = rawArgv.includes('--report')\n\n  run(`vue-cli-service build ${args}`)\n\n  const port = 9526\n  const publicPath = config.publicPath\n\n  var connect = require('connect')\n  var serveStatic = require('serve-static')\n  const app = connect()\n\n  app.use(\n    publicPath,\n    serveStatic('./target/dist', {\n      index: ['index.html', '/']\n    })\n  )\n\n  app.listen(port, function () {\n    console.log(chalk.green(`> Preview at  http://localhost:${port}${publicPath}`))\n    if (report) {\n      console.log(chalk.green(`> Report at  http://localhost:${port}${publicPath}report.html`))\n    }\n\n  })\n} else {\n  run(`vue-cli-service build ${args}`)\n}\n"
  },
  {
    "path": "admin/admin-ui/jest.config.js",
    "content": "module.exports = {\n  moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],\n  transform: {\n    '^.+\\\\.vue$': 'vue-jest',\n    '.+\\\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$':\n      'jest-transform-stub',\n    '^.+\\\\.jsx?$': 'babel-jest'\n  },\n  moduleNameMapper: {\n    '^@/(.*)$': '<rootDir>/src/$1'\n  },\n  snapshotSerializers: ['jest-serializer-vue'],\n  testMatch: [\n    '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'\n  ],\n  collectCoverageFrom: ['src/utils/**/*.{js,vue}', '!src/utils/auth.js', '!src/utils/request.js', 'src/components/**/*.{js,vue}'],\n  coverageDirectory: '<rootDir>/tests/unit/coverage',\n  // 'collectCoverage': true,\n  'coverageReporters': [\n    'lcov',\n    'text-summary'\n  ],\n  testURL: 'http://localhost/'\n}\n"
  },
  {
    "path": "admin/admin-ui/mock/index.js",
    "content": "import Mock from 'mockjs'\nimport { param2Obj } from '../src/utils'\n\nimport user from './user'\nimport table from './table'\n\nconst mocks = [\n  ...user,\n  ...table\n]\n\n// for front mock\n// please use it cautiously, it will redefine XMLHttpRequest,\n// which will cause many of your third-party libraries to be invalidated(like progress event).\nexport function mockXHR() {\n  // mock patch\n  // https://github.com/nuysoft/Mock/issues/300\n  Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send\n  Mock.XHR.prototype.send = function() {\n    if (this.custom.xhr) {\n      this.custom.xhr.withCredentials = this.withCredentials || false\n\n      if (this.responseType) {\n        this.custom.xhr.responseType = this.responseType\n      }\n    }\n    this.proxy_send(...arguments)\n  }\n\n  function XHR2ExpressReqWrap(respond) {\n    return function(options) {\n      let result = null\n      if (respond instanceof Function) {\n        const { body, type, url } = options\n        // https://expressjs.com/en/4x/api.html#req\n        result = respond({\n          method: type,\n          body: JSON.parse(body),\n          query: param2Obj(url)\n        })\n      } else {\n        result = respond\n      }\n      return Mock.mock(result)\n    }\n  }\n\n  for (const i of mocks) {\n    Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response))\n  }\n}\n\n// for mock server\nconst responseFake = (url, type, respond) => {\n  return {\n    url: new RegExp(`/mock${url}`),\n    type: type || 'get',\n    response(req, res) {\n      res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond))\n    }\n  }\n}\n\nexport default mocks.map(route => {\n  return responseFake(route.url, route.type, route.response)\n})\n"
  },
  {
    "path": "admin/admin-ui/mock/mock-server.js",
    "content": "const chokidar = require('chokidar')\nconst bodyParser = require('body-parser')\nconst chalk = require('chalk')\nconst path = require('path')\n\nconst mockDir = path.join(process.cwd(), 'mock')\n\nfunction registerRoutes(app) {\n  let mockLastIndex\n  const { default: mocks } = require('./index.js')\n  for (const mock of mocks) {\n    app[mock.type](mock.url, mock.response)\n    mockLastIndex = app._router.stack.length\n  }\n  const mockRoutesLength = Object.keys(mocks).length\n  return {\n    mockRoutesLength: mockRoutesLength,\n    mockStartIndex: mockLastIndex - mockRoutesLength\n  }\n}\n\nfunction unregisterRoutes() {\n  Object.keys(require.cache).forEach(i => {\n    if (i.includes(mockDir)) {\n      delete require.cache[require.resolve(i)]\n    }\n  })\n}\n\nmodule.exports = app => {\n  // es6 polyfill\n  require('@babel/register')\n\n  // parse app.body\n  // https://expressjs.com/en/4x/api.html#req.body\n  app.use(bodyParser.json())\n  app.use(bodyParser.urlencoded({\n    extended: true\n  }))\n\n  const mockRoutes = registerRoutes(app)\n  var mockRoutesLength = mockRoutes.mockRoutesLength\n  var mockStartIndex = mockRoutes.mockStartIndex\n\n  // watch files, hot reload mock server\n  chokidar.watch(mockDir, {\n    ignored: /mock-server/,\n    ignoreInitial: true\n  }).on('all', (event, path) => {\n    if (event === 'change' || event === 'add') {\n      try {\n        // remove mock routes stack\n        app._router.stack.splice(mockStartIndex, mockRoutesLength)\n\n        // clear routes cache\n        unregisterRoutes()\n\n        const mockRoutes = registerRoutes(app)\n        mockRoutesLength = mockRoutes.mockRoutesLength\n        mockStartIndex = mockRoutes.mockStartIndex\n\n        console.log(chalk.magentaBright(`\\n > Mock Server hot reload success! changed  ${path}`))\n      } catch (error) {\n        console.log(chalk.redBright(error))\n      }\n    }\n  })\n}\n"
  },
  {
    "path": "admin/admin-ui/mock/table.js",
    "content": "import Mock from 'mockjs'\n\nconst data = Mock.mock({\n  'items|30': [{\n    id: '@id',\n    title: '@sentence(10, 20)',\n    'status|1': ['published', 'draft', 'deleted'],\n    author: 'name',\n    display_time: '@datetime',\n    pageviews: '@integer(300, 5000)'\n  }]\n})\n\nexport default [\n  {\n    url: '/table/list',\n    type: 'get',\n    response: config => {\n      const items = data.items\n      return {\n        code: 20000,\n        data: {\n          total: items.length,\n          items: items\n        }\n      }\n    }\n  }\n]\n"
  },
  {
    "path": "admin/admin-ui/mock/user.js",
    "content": "\nconst tokens = {\n  admin: {\n    token: 'admin-token'\n  },\n  editor: {\n    token: 'editor-token'\n  }\n}\n\nconst users = {\n  'admin-token': {\n    roles: ['admin'],\n    introduction: 'I am a super administrator',\n    avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',\n    name: 'Super Admin'\n  },\n  'editor-token': {\n    roles: ['editor'],\n    introduction: 'I am an editor',\n    avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',\n    name: 'Normal Editor'\n  }\n}\n\nexport default [\n  // user login\n  {\n    url: '/user/login',\n    type: 'post',\n    response: config => {\n      const { username } = config.body\n      const token = tokens[username]\n\n      // mock error\n      if (!token) {\n        return {\n          code: 60204,\n          message: 'Account and password are incorrect.'\n        }\n      }\n\n      return {\n        code: 20000,\n        data: token\n      }\n    }\n  },\n\n  // get user info\n  {\n    url: '/user/info\\.*',\n    type: 'get',\n    response: config => {\n      const { token } = config.query\n      const info = users[token]\n\n      // mock error\n      if (!info) {\n        return {\n          code: 50008,\n          message: 'Login failed, unable to get user details.'\n        }\n      }\n\n      return {\n        code: 20000,\n        data: info\n      }\n    }\n  },\n\n  // user logout\n  {\n    url: '/user/logout',\n    type: 'post',\n    response: _ => {\n      return {\n        code: 20000,\n        data: 'success'\n      }\n    }\n  }\n]\n"
  },
  {
    "path": "admin/admin-ui/package.json",
    "content": "{\n  \"name\": \"canal-admin-ui\",\n  \"version\": \"1.1.4\",\n  \"description\": \"A canal-admin ui with Element UI & axios & iconfont & permission control & lint\",\n  \"author\": \"Machengyuan <rewerma@163.com>\",\n  \"license\": \"MIT\",\n  \"scripts\": {\n    \"dev\": \"vue-cli-service serve\",\n    \"build\": \"vue-cli-service build\",\n    \"build:stage\": \"vue-cli-service build --mode staging\",\n    \"preview\": \"node build/index.js --preview\",\n    \"lint\": \"eslint --ext .js,.vue src\",\n    \"test:unit\": \"jest --clearCache && vue-cli-service test:unit\",\n    \"test:ci\": \"npm run lint && npm run test:unit\",\n    \"svgo\": \"svgo -f src/icons/svg --config=src/icons/svgo.yml\"\n  },\n  \"dependencies\": {\n    \"axios\": \"0.18.1\",\n    \"element-ui\": \"2.7.2\",\n    \"js-cookie\": \"2.2.0\",\n    \"normalize.css\": \"7.0.0\",\n    \"nprogress\": \"0.2.0\",\n    \"path-to-regexp\": \"2.4.0\",\n    \"vue\": \"2.6.10\",\n    \"vue-router\": \"3.0.6\",\n    \"vuex\": \"3.1.0\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"7.0.0\",\n    \"@babel/register\": \"7.0.0\",\n    \"@vue/cli-plugin-babel\": \"3.6.0\",\n    \"@vue/cli-plugin-eslint\": \"^3.9.1\",\n    \"@vue/cli-plugin-unit-jest\": \"3.6.3\",\n    \"@vue/cli-service\": \"3.6.0\",\n    \"@vue/test-utils\": \"1.0.0-beta.29\",\n    \"autoprefixer\": \"^9.5.1\",\n    \"babel-core\": \"7.0.0-bridge.0\",\n    \"babel-eslint\": \"10.0.1\",\n    \"babel-jest\": \"23.6.0\",\n    \"chalk\": \"2.4.2\",\n    \"connect\": \"3.6.6\",\n    \"eslint\": \"5.15.3\",\n    \"eslint-plugin-vue\": \"5.2.2\",\n    \"html-webpack-plugin\": \"3.2.0\",\n    \"mockjs\": \"1.0.1-beta3\",\n    \"node-sass\": \"^4.9.0\",\n    \"runjs\": \"^4.3.2\",\n    \"sass-loader\": \"^7.1.0\",\n    \"script-ext-html-webpack-plugin\": \"2.1.3\",\n    \"script-loader\": \"0.7.2\",\n    \"serve-static\": \"^1.13.2\",\n    \"svg-sprite-loader\": \"4.1.3\",\n    \"svgo\": \"1.2.2\",\n    \"vue-template-compiler\": \"2.6.10\",\n    \"vue2-ace-editor\": \"^0.0.13\"\n  },\n  \"engines\": {\n    \"node\": \">=8.9\",\n    \"npm\": \">= 3.0.0\"\n  },\n  \"browserslist\": [\n    \"> 1%\",\n    \"last 2 versions\"\n  ]\n}\n"
  },
  {
    "path": "admin/admin-ui/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <parent>\n    <artifactId>canal.admin</artifactId>\n    <groupId>com.alibaba.otter</groupId>\n    <version>1.1.9-SNAPSHOT</version>\n  </parent>\n  <modelVersion>4.0.0</modelVersion>\n\n  <artifactId>canal.admin-ui</artifactId>\n  <name>canal admin-ui module for otter ${project.version}</name>\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n    <java.version>1.8</java.version>\n    <frontend-maven-plugin.version>1.6</frontend-maven-plugin.version>\n  </properties>\n\n  <profiles>\n    <profile>\n      <id>npm</id>\n      <activation>\n        <property>\n          <name>env</name>\n          <value>npm</value>\n        </property>\n      </activation>\n      <build>\n        <plugins>\n          <plugin>\n            <groupId>com.github.eirslett</groupId>\n            <artifactId>frontend-maven-plugin</artifactId>\n            <version>${frontend-maven-plugin.version}</version>\n            <executions>\n              <execution>\n                <id>install node and npm</id>\n                <goals>\n                  <goal>install-node-and-npm</goal>\n                </goals>\n                <configuration>\n                  <nodeVersion>v9.11.1</nodeVersion>\n                </configuration>\n              </execution>\n              <!-- Install all project dependencies -->\n              <execution>\n                <id>npm install</id>\n                <goals>\n                  <goal>npm</goal>\n                </goals>\n                <!-- optional: default phase is \"generate-resources\" -->\n                <phase>generate-resources</phase>\n                <!-- Optional configuration which provides for running any npm command -->\n                <configuration>\n                  <arguments>install</arguments>\n                </configuration>\n              </execution>\n              <!-- Build and minify static files -->\n              <execution>\n                <id>npm run build</id>\n                <goals>\n                  <goal>npm</goal>\n                </goals>\n                <configuration>\n                  <arguments>run build</arguments>\n                </configuration>\n              </execution>\n            </executions>\n          </plugin>\n        </plugins>\n      </build>\n    </profile>\n  </profiles>\n</project>\n"
  },
  {
    "path": "admin/admin-ui/postcss.config.js",
    "content": "// https://github.com/michael-ciniawsky/postcss-load-config\n\nmodule.exports = {\n  'plugins': {\n    // to edit target browsers: use \"browserslist\" field in package.json\n    'autoprefixer': {}\n  }\n}\n"
  },
  {
    "path": "admin/admin-ui/public/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\">\n    <link rel=\"icon\" href=\"<%= BASE_URL %>favicon.ico\">\n    <title><%= webpackConfig.name %></title>\n  </head>\n  <body>\n    <noscript>\n      <strong>We're sorry but <%= webpackConfig.name %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>\n    </noscript>\n    <div id=\"app\"></div>\n    <!-- built files will be auto injected -->\n  </body>\n</html>\n"
  },
  {
    "path": "admin/admin-ui/src/App.vue",
    "content": "<template>\n  <div id=\"app\">\n    <router-view />\n  </div>\n</template>\n\n<script>\nexport default {\n  name: 'App'\n}\n</script>\n"
  },
  {
    "path": "admin/admin-ui/src/api/canalCluster.js",
    "content": "import request from '@/utils/request'\n\nexport function getCanalClusters(params) {\n  return request({\n    url: '/canal/clusters',\n    method: 'get',\n    params: params\n  })\n}\n\nexport function addCanalCluster(data) {\n  return request({\n    url: '/canal/cluster',\n    method: 'post',\n    data\n  })\n}\n\nexport function canalClusterDetail(id) {\n  return request({\n    url: '/canal/cluster/' + id,\n    method: 'get'\n  })\n}\n\nexport function updateCanalCluster(data) {\n  return request({\n    url: '/canal/cluster',\n    method: 'put',\n    data\n  })\n}\n\nexport function deleteCanalCluster(id) {\n  return request({\n    url: '/canal/cluster/' + id,\n    method: 'delete'\n  })\n}\n\nexport function getClustersAndServers() {\n  return request({\n    url: '/canal/clustersAndServers',\n    method: 'get'\n  })\n}\n"
  },
  {
    "path": "admin/admin-ui/src/api/canalConfig.js",
    "content": "import request from '@/utils/request'\n\nexport function getCanalConfig(clusterId, serverId) {\n  return request({\n    url: '/canal/config/' + clusterId + '/' + serverId,\n    method: 'get'\n  })\n}\n\nexport function updateCanalConfig(data) {\n  return request({\n    url: '/canal/config',\n    method: 'put',\n    data\n  })\n}\n\nexport function getTemplateConfig() {\n  return request({\n    url: '/canal/config/template',\n    method: 'get'\n  })\n}\n"
  },
  {
    "path": "admin/admin-ui/src/api/canalInstance.js",
    "content": "import request from '@/utils/request'\n\nexport function getCanalInstances(params) {\n  return request({\n    url: '/canal/instances',\n    method: 'get',\n    params: params\n  })\n}\n\nexport function canalInstanceDetail(id) {\n  return request({\n    url: '/canal/instance/' + id,\n    method: 'get'\n  })\n}\n\nexport function updateCanalInstance(data) {\n  return request({\n    url: '/canal/instance',\n    method: 'put',\n    data\n  })\n}\n\nexport function addCanalInstance(data) {\n  return request({\n    url: '/canal/instance',\n    method: 'post',\n    data\n  })\n}\n\nexport function deleteCanalInstance(id) {\n  return request({\n    url: '/canal/instance/' + id,\n    method: 'delete'\n  })\n}\n\nexport function startInstance(id, nodeId) {\n  return request({\n    url: '/canal/instance/start/' + id + '/' + nodeId,\n    method: 'put'\n  })\n}\n\nexport function stopInstance(id, nodeId) {\n  return request({\n    url: '/canal/instance/stop/' + id + '/' + nodeId,\n    method: 'put'\n  })\n}\n\nexport function instanceLog(id, nodeId) {\n  return request({\n    url: '/canal/instance/log/' + id + '/' + nodeId,\n    method: 'get'\n  })\n}\n\nexport function instanceStatus(id, option) {\n  return request({\n    url: '/canal/instance/status/' + id + '?option=' + option,\n    method: 'put'\n  })\n}\n\nexport function getActiveInstances(serverId) {\n  return request({\n    url: '/canal/active/instances/' + serverId,\n    method: 'get'\n  })\n}\n\nexport function getTemplateInstance() {\n  return request({\n    url: '/canal/instance/template',\n    method: 'get'\n  })\n}\n"
  },
  {
    "path": "admin/admin-ui/src/api/nodeServer.js",
    "content": "import request from '@/utils/request'\n\nexport function getNodeServers(params) {\n  return request({\n    url: '/nodeServers',\n    method: 'get',\n    params: params\n  })\n}\n\nexport function addNodeServer(data) {\n  return request({\n    url: '/nodeServer',\n    method: 'post',\n    data\n  })\n}\n\nexport function nodeServerDetail(id) {\n  return request({\n    url: '/nodeServer/' + id,\n    method: 'get'\n  })\n}\n\nexport function updateNodeServer(data) {\n  return request({\n    url: '/nodeServer',\n    method: 'put',\n    data\n  })\n}\n\nexport function deleteNodeServer(id) {\n  return request({\n    url: '/nodeServer/' + id,\n    method: 'delete'\n  })\n}\n\nexport function startNodeServer(id) {\n  return request({\n    url: '/nodeServer/start/' + id,\n    method: 'put'\n  })\n}\n\nexport function stopNodeServer(id) {\n  return request({\n    url: '/nodeServer/stop/' + id,\n    method: 'put'\n  })\n}\n\nexport function nodeServerLog(id) {\n  return request({\n    url: '/nodeServer/log/' + id,\n    method: 'get'\n  })\n}\n"
  },
  {
    "path": "admin/admin-ui/src/api/table.js",
    "content": "import request from '@/utils/request'\n\nexport function getList(params) {\n  return request({\n    url: '/table/list',\n    method: 'get',\n    params\n  })\n}\n"
  },
  {
    "path": "admin/admin-ui/src/api/user.js",
    "content": "import request from '@/utils/request'\n\nexport function login(data) {\n  return request({\n    url: '/user/login',\n    method: 'post',\n    data\n  })\n}\n\nexport function getInfo(token) {\n  return request({\n    url: '/user/info',\n    method: 'get',\n    params: { token }\n  })\n}\n\nexport function logout() {\n  return request({\n    url: '/user/logout',\n    method: 'post'\n  })\n}\n\nexport function updateUser(data) {\n  return request({\n    url: '/user',\n    method: 'put',\n    data\n  })\n}\n"
  },
  {
    "path": "admin/admin-ui/src/components/Breadcrumb/index.vue",
    "content": "<template>\n  <el-breadcrumb class=\"app-breadcrumb\" separator=\"/\">\n    <transition-group name=\"breadcrumb\">\n      <el-breadcrumb-item v-for=\"(item,index) in levelList\" :key=\"item.path\">\n        <span v-if=\"item.redirect==='noRedirect'||index==levelList.length-1\" class=\"no-redirect\">{{ item.meta.title }}</span>\n        <a v-else @click.prevent=\"handleLink(item)\">{{ item.meta.title }}</a>\n      </el-breadcrumb-item>\n    </transition-group>\n  </el-breadcrumb>\n</template>\n\n<script>\nimport pathToRegexp from 'path-to-regexp'\n\nexport default {\n  data() {\n    return {\n      levelList: null\n    }\n  },\n  watch: {\n    $route() {\n      this.getBreadcrumb()\n    }\n  },\n  created() {\n    this.getBreadcrumb()\n  },\n  methods: {\n    getBreadcrumb() {\n      // only show routes with meta.title\n      let matched = this.$route.matched.filter(item => item.meta && item.meta.title)\n      const first = matched[0]\n\n      if (!this.isDashboard(first)) {\n        matched = [{ path: '/dashboard', meta: { title: '主页' }}].concat(matched)\n      }\n\n      this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)\n    },\n    isDashboard(route) {\n      const name = route && route.name\n      if (!name) {\n        return false\n      }\n      return name.trim().toLocaleLowerCase() === 'Dashboard'.toLocaleLowerCase()\n    },\n    pathCompile(path) {\n      // To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561\n      const { params } = this.$route\n      var toPath = pathToRegexp.compile(path)\n      return toPath(params)\n    },\n    handleLink(item) {\n      const { redirect, path } = item\n      if (redirect) {\n        this.$router.push(redirect)\n        return\n      }\n      this.$router.push(this.pathCompile(path))\n    }\n  }\n}\n</script>\n\n<style lang=\"scss\" scoped>\n.app-breadcrumb.el-breadcrumb {\n  display: inline-block;\n  font-size: 14px;\n  line-height: 50px;\n  margin-left: 8px;\n\n  .no-redirect {\n    color: #97a8be;\n    cursor: text;\n  }\n}\n</style>\n"
  },
  {
    "path": "admin/admin-ui/src/components/Hamburger/index.vue",
    "content": "<template>\n  <div style=\"padding: 0 15px;\" @click=\"toggleClick\">\n    <svg\n      :class=\"{'is-active':isActive}\"\n      class=\"hamburger\"\n      viewBox=\"0 0 1024 1024\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n      width=\"64\"\n      height=\"64\"\n    >\n      <path d=\"M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z\" />\n    </svg>\n  </div>\n</template>\n\n<script>\nexport default {\n  name: 'Hamburger',\n  props: {\n    isActive: {\n      type: Boolean,\n      default: false\n    }\n  },\n  methods: {\n    toggleClick() {\n      this.$emit('toggleClick')\n    }\n  }\n}\n</script>\n\n<style scoped>\n.hamburger {\n  display: inline-block;\n  vertical-align: middle;\n  width: 20px;\n  height: 20px;\n}\n\n.hamburger.is-active {\n  transform: rotate(180deg);\n}\n</style>\n"
  },
  {
    "path": "admin/admin-ui/src/components/Pagination/index.vue",
    "content": "<template>\n  <div :class=\"{'hidden':hidden}\" class=\"pagination-container\">\n    <el-pagination\n      :background=\"background\"\n      :current-page.sync=\"currentPage\"\n      :page-size.sync=\"pageSize\"\n      :layout=\"layout\"\n      :page-sizes=\"pageSizes\"\n      :total=\"total\"\n      v-bind=\"$attrs\"\n      @size-change=\"handleSizeChange\"\n      @current-change=\"handleCurrentChange\"\n    />\n  </div>\n</template>\n\n<script>\nimport { scrollTo } from '@/utils/scrollTo'\n\nexport default {\n  name: 'Pagination',\n  props: {\n    total: {\n      required: true,\n      type: Number\n    },\n    page: {\n      type: Number,\n      default: 1\n    },\n    limit: {\n      type: Number,\n      default: 20\n    },\n    pageSizes: {\n      type: Array,\n      default() {\n        return [10, 20, 30, 50]\n      }\n    },\n    layout: {\n      type: String,\n      default: 'total, sizes, prev, pager, next, jumper'\n    },\n    background: {\n      type: Boolean,\n      default: true\n    },\n    autoScroll: {\n      type: Boolean,\n      default: true\n    },\n    hidden: {\n      type: Boolean,\n      default: false\n    }\n  },\n  computed: {\n    currentPage: {\n      get() {\n        return this.page\n      },\n      set(val) {\n        this.$emit('update:page', val)\n      }\n    },\n    pageSize: {\n      get() {\n        return this.limit\n      },\n      set(val) {\n        this.$emit('update:limit', val)\n      }\n    }\n  },\n  methods: {\n    handleSizeChange(val) {\n      this.$emit('pagination', { page: this.currentPage, limit: val })\n      if (this.autoScroll) {\n        scrollTo(0, 800)\n      }\n    },\n    handleCurrentChange(val) {\n      this.$emit('pagination', { page: val, limit: this.pageSize })\n      if (this.autoScroll) {\n        scrollTo(0, 800)\n      }\n    }\n  }\n}\n</script>\n\n<style scoped>\n.pagination-container {\n  background: #fff;\n  padding: 32px 16px;\n}\n.pagination-container.hidden {\n  display: none;\n}\n</style>\n"
  },
  {
    "path": "admin/admin-ui/src/components/SvgIcon/index.vue",
    "content": "<template>\n  <div v-if=\"isExternal\" :style=\"styleExternalIcon\" class=\"svg-external-icon svg-icon\" v-on=\"$listeners\" />\n  <svg v-else :class=\"svgClass\" aria-hidden=\"true\" v-on=\"$listeners\">\n    <use :xlink:href=\"iconName\" />\n  </svg>\n</template>\n\n<script>\n// doc: https://panjiachen.github.io/vue-element-admin-site/feature/component/svg-icon.html#usage\nimport { isExternal } from '@/utils/validate'\n\nexport default {\n  name: 'SvgIcon',\n  props: {\n    iconClass: {\n      type: String,\n      required: true\n    },\n    className: {\n      type: String,\n      default: ''\n    }\n  },\n  computed: {\n    isExternal() {\n      return isExternal(this.iconClass)\n    },\n    iconName() {\n      return `#icon-${this.iconClass}`\n    },\n    svgClass() {\n      if (this.className) {\n        return 'svg-icon ' + this.className\n      } else {\n        return 'svg-icon'\n      }\n    },\n    styleExternalIcon() {\n      return {\n        mask: `url(${this.iconClass}) no-repeat 50% 50%`,\n        '-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`\n      }\n    }\n  }\n}\n</script>\n\n<style scoped>\n.svg-icon {\n  width: 1em;\n  height: 1em;\n  vertical-align: -0.15em;\n  fill: currentColor;\n  overflow: hidden;\n}\n\n.svg-external-icon {\n  background-color: currentColor;\n  mask-size: cover!important;\n  display: inline-block;\n}\n</style>\n"
  },
  {
    "path": "admin/admin-ui/src/icons/index.js",
    "content": "import Vue from 'vue'\nimport SvgIcon from '@/components/SvgIcon'// svg component\n\n// register globally\nVue.component('svg-icon', SvgIcon)\n\nconst req = require.context('./svg', false, /\\.svg$/)\nconst requireAll = requireContext => requireContext.keys().map(requireContext)\nrequireAll(req)\n"
  },
  {
    "path": "admin/admin-ui/src/icons/svgo.yml",
    "content": "# replace default config\n\n# multipass: true\n# full: true\n\nplugins:\n\n  # - name\n  #\n  # or:\n  # - name: false\n  # - name: true\n  #\n  # or:\n  # - name:\n  #     param1: 1\n  #     param2: 2\n\n- removeAttrs:\n    attrs:\n      - 'fill'\n      - 'fill-rule'\n"
  },
  {
    "path": "admin/admin-ui/src/layout/components/AppMain.vue",
    "content": "<template>\n  <section class=\"app-main\">\n    <transition name=\"fade-transform\" mode=\"out-in\">\n      <router-view :key=\"key\" />\n    </transition>\n  </section>\n</template>\n\n<script>\nexport default {\n  name: 'AppMain',\n  computed: {\n    key() {\n      return this.$route.path\n    }\n  }\n}\n</script>\n\n<style scoped>\n.app-main {\n  /*50 = navbar  */\n  min-height: calc(100vh - 50px);\n  width: 100%;\n  position: relative;\n  overflow: hidden;\n}\n.fixed-header+.app-main {\n  padding-top: 50px;\n}\n</style>\n\n<style lang=\"scss\">\n// fix css style bug in open el-dialog\n.el-popup-parent--hidden {\n  .fixed-header {\n    padding-right: 15px;\n  }\n}\n</style>\n"
  },
  {
    "path": "admin/admin-ui/src/layout/components/Navbar.vue",
    "content": "<template>\n  <div class=\"navbar\">\n    <hamburger :is-active=\"sidebar.opened\" class=\"hamburger-container\" @toggleClick=\"toggleSideBar\" />\n\n    <breadcrumb class=\"breadcrumb-container\" />\n\n    <div class=\"right-menu\">\n      <el-dropdown class=\"avatar-container\" trigger=\"click\">\n        <div class=\"avatar-wrapper\">\n          <!-- avatar+'?imageView2/1/w/80/h/80' -->\n          <img :src=\"avat+'?imageView2/1/w/80/h/80'\" class=\"user-avatar\">\n          <i class=\"el-icon-caret-bottom\" />\n        </div>\n        <el-dropdown-menu slot=\"dropdown\" class=\"user-dropdown\">\n          <router-link to=\"/\">\n            <el-dropdown-item>\n              主页\n            </el-dropdown-item>\n          </router-link>\n          <router-link to=\"/sys/user\">\n            <el-dropdown-item>账号管理</el-dropdown-item>\n          </router-link>\n          <el-dropdown-item divided>\n            <span style=\"display:block;\" @click=\"logout\">退出</span>\n          </el-dropdown-item>\n        </el-dropdown-menu>\n      </el-dropdown>\n    </div>\n  </div>\n</template>\n\n<script>\nimport { mapGetters } from 'vuex'\nimport Breadcrumb from '@/components/Breadcrumb'\nimport Hamburger from '@/components/Hamburger'\n\nexport default {\n  components: {\n    Breadcrumb,\n    Hamburger\n  },\n  data() {\n    return {\n      avat: './avatar.gif'\n    }\n  },\n  computed: {\n    ...mapGetters([\n      'sidebar',\n      'avatar'\n    ])\n  },\n  methods: {\n    toggleSideBar() {\n      this.$store.dispatch('app/toggleSideBar')\n    },\n    async logout() {\n      await this.$store.dispatch('user/logout')\n      this.$router.push(`/login?redirect=${this.$route.fullPath}`)\n    }\n  }\n}\n</script>\n\n<style lang=\"scss\" scoped>\n.navbar {\n  height: 50px;\n  overflow: hidden;\n  position: relative;\n  background: #fff;\n  box-shadow: 0 1px 4px rgba(0,21,41,.08);\n\n  .hamburger-container {\n    line-height: 46px;\n    height: 100%;\n    float: left;\n    cursor: pointer;\n    transition: background .3s;\n    -webkit-tap-highlight-color:transparent;\n\n    &:hover {\n      background: rgba(0, 0, 0, .025)\n    }\n  }\n\n  .breadcrumb-container {\n    float: left;\n  }\n\n  .right-menu {\n    float: right;\n    height: 100%;\n    line-height: 50px;\n\n    &:focus {\n      outline: none;\n    }\n\n    .right-menu-item {\n      display: inline-block;\n      padding: 0 8px;\n      height: 100%;\n      font-size: 18px;\n      color: #5a5e66;\n      vertical-align: text-bottom;\n\n      &.hover-effect {\n        cursor: pointer;\n        transition: background .3s;\n\n        &:hover {\n          background: rgba(0, 0, 0, .025)\n        }\n      }\n    }\n\n    .avatar-container {\n      margin-right: 30px;\n\n      .avatar-wrapper {\n        margin-top: 5px;\n        position: relative;\n\n        .user-avatar {\n          cursor: pointer;\n          width: 40px;\n          height: 40px;\n          border-radius: 10px;\n        }\n\n        .el-icon-caret-bottom {\n          cursor: pointer;\n          position: absolute;\n          right: -20px;\n          top: 25px;\n          font-size: 12px;\n        }\n      }\n    }\n  }\n}\n</style>\n"
  },
  {
    "path": "admin/admin-ui/src/layout/components/Sidebar/FixiOSBug.js",
    "content": "export default {\n  computed: {\n    device() {\n      return this.$store.state.app.device\n    }\n  },\n  mounted() {\n    // In order to fix the click on menu on the ios device will trigger the mouseleave bug\n    // https://github.com/PanJiaChen/vue-element-admin/issues/1135\n    this.fixBugIniOS()\n  },\n  methods: {\n    fixBugIniOS() {\n      const $subMenu = this.$refs.subMenu\n      if ($subMenu) {\n        const handleMouseleave = $subMenu.handleMouseleave\n        $subMenu.handleMouseleave = (e) => {\n          if (this.device === 'mobile') {\n            return\n          }\n          handleMouseleave(e)\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "admin/admin-ui/src/layout/components/Sidebar/Item.vue",
    "content": "<script>\nexport default {\n  name: 'MenuItem',\n  functional: true,\n  props: {\n    icon: {\n      type: String,\n      default: ''\n    },\n    title: {\n      type: String,\n      default: ''\n    }\n  },\n  render(h, context) {\n    const { icon, title } = context.props\n    const vnodes = []\n\n    if (icon) {\n      vnodes.push(<svg-icon icon-class={icon}/>)\n    }\n\n    if (title) {\n      vnodes.push(<span slot='title'>{(title)}</span>)\n    }\n    return vnodes\n  }\n}\n</script>\n"
  },
  {
    "path": "admin/admin-ui/src/layout/components/Sidebar/Link.vue",
    "content": "\n<template>\n  <!-- eslint-disable vue/require-component-is -->\n  <component v-bind=\"linkProps(to)\">\n    <slot />\n  </component>\n</template>\n\n<script>\nimport { isExternal } from '@/utils/validate'\n\nexport default {\n  props: {\n    to: {\n      type: String,\n      required: true\n    }\n  },\n  methods: {\n    linkProps(url) {\n      if (isExternal(url)) {\n        return {\n          is: 'a',\n          href: url,\n          target: '_blank',\n          rel: 'noopener'\n        }\n      }\n      return {\n        is: 'router-link',\n        to: url\n      }\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "admin/admin-ui/src/layout/components/Sidebar/Logo.vue",
    "content": "<template>\n  <div class=\"sidebar-logo-container\" :class=\"{'collapse':collapse}\">\n    <transition name=\"sidebarLogoFade\">\n      <router-link v-if=\"collapse\" key=\"collapse\" class=\"sidebar-logo-link\" to=\"/\">\n        <img v-if=\"logo\" :src=\"logo\" class=\"sidebar-logo\">\n        <h1 v-else class=\"sidebar-title\">{{ title }} </h1>\n      </router-link>\n      <router-link v-else key=\"expand\" class=\"sidebar-logo-link\" to=\"/\">\n        <img v-if=\"logo\" :src=\"logo\" class=\"sidebar-logo\">\n        <h1 class=\"sidebar-title\">{{ title }} </h1>\n      </router-link>\n    </transition>\n  </div>\n</template>\n\n<script>\nexport default {\n  name: 'SidebarLogo',\n  props: {\n    collapse: {\n      type: Boolean,\n      required: true\n    }\n  },\n  data() {\n    return {\n      title: '',\n      logo: './logo.png'\n    }\n  }\n}\n</script>\n\n<style lang=\"scss\" scoped>\n.sidebarLogoFade-enter-active {\n  transition: opacity 1.5s;\n}\n\n.sidebarLogoFade-enter,\n.sidebarLogoFade-leave-to {\n  opacity: 0;\n}\n\n.sidebar-logo-container {\n  position: relative;\n  width: 100%;\n  height: 50px;\n  line-height: 50px;\n  background: #2b2f3a;\n  text-align: center;\n  overflow: hidden;\n\n  & .sidebar-logo-link {\n    height: 100%;\n    width: 100%;\n\n    & .sidebar-logo {\n      width: 55px;\n      // height: 32px;\n      vertical-align: middle;\n      margin-right: 12px;\n    }\n\n    & .sidebar-title {\n      display: inline-block;\n      margin: 0;\n      color: #fff;\n      font-weight: 600;\n      line-height: 50px;\n      font-size: 14px;\n      font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;\n      vertical-align: middle;\n    }\n  }\n\n  &.collapse {\n    .sidebar-logo {\n      margin-right: 0px;\n    }\n  }\n}\n</style>\n"
  },
  {
    "path": "admin/admin-ui/src/layout/components/Sidebar/SidebarItem.vue",
    "content": "<template>\n  <div v-if=\"!item.hidden\" class=\"menu-wrapper\">\n    <template v-if=\"hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow\">\n      <app-link v-if=\"onlyOneChild.meta\" :to=\"resolvePath(onlyOneChild.path)\">\n        <el-menu-item :index=\"resolvePath(onlyOneChild.path)\" :class=\"{'submenu-title-noDropdown':!isNest}\">\n          <item :icon=\"onlyOneChild.meta.icon||(item.meta&&item.meta.icon)\" :title=\"onlyOneChild.meta.title\" />\n        </el-menu-item>\n      </app-link>\n    </template>\n\n    <el-submenu v-else ref=\"subMenu\" :index=\"resolvePath(item.path)\" popper-append-to-body>\n      <template slot=\"title\">\n        <item v-if=\"item.meta\" :icon=\"item.meta && item.meta.icon\" :title=\"item.meta.title\" />\n      </template>\n      <sidebar-item\n        v-for=\"child in item.children\"\n        :key=\"child.path\"\n        :is-nest=\"true\"\n        :item=\"child\"\n        :base-path=\"resolvePath(child.path)\"\n        class=\"nest-menu\"\n      />\n    </el-submenu>\n  </div>\n</template>\n\n<script>\nimport path from 'path'\nimport { isExternal } from '@/utils/validate'\nimport Item from './Item'\nimport AppLink from './Link'\nimport FixiOSBug from './FixiOSBug'\n\nexport default {\n  name: 'SidebarItem',\n  components: { Item, AppLink },\n  mixins: [FixiOSBug],\n  props: {\n    // route object\n    item: {\n      type: Object,\n      required: true\n    },\n    isNest: {\n      type: Boolean,\n      default: false\n    },\n    basePath: {\n      type: String,\n      default: ''\n    }\n  },\n  data() {\n    // To fix https://github.com/PanJiaChen/vue-admin-template/issues/237\n    // TODO: refactor with render function\n    this.onlyOneChild = null\n    return {}\n  },\n  methods: {\n    hasOneShowingChild(children = [], parent) {\n      const showingChildren = children.filter(item => {\n        if (item.hidden) {\n          return false\n        } else {\n          // Temp set(will be used if only has one showing child)\n          this.onlyOneChild = item\n          return true\n        }\n      })\n\n      // When there is only one child router, the child router is displayed by default\n      if (showingChildren.length === 1) {\n        return true\n      }\n\n      // Show parent if there are no child router to display\n      if (showingChildren.length === 0) {\n        this.onlyOneChild = { ... parent, path: '', noShowingChildren: true }\n        return true\n      }\n\n      return false\n    },\n    resolvePath(routePath) {\n      if (isExternal(routePath)) {\n        return routePath\n      }\n      if (isExternal(this.basePath)) {\n        return this.basePath\n      }\n      return path.resolve(this.basePath, routePath)\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "admin/admin-ui/src/layout/components/Sidebar/index.vue",
    "content": "<template>\n  <div :class=\"{'has-logo':showLogo}\">\n    <logo v-if=\"showLogo\" :collapse=\"isCollapse\" />\n    <el-scrollbar wrap-class=\"scrollbar-wrapper\">\n      <el-menu\n        :default-active=\"activeMenu\"\n        :collapse=\"isCollapse\"\n        :background-color=\"variables.menuBg\"\n        :text-color=\"variables.menuText\"\n        :unique-opened=\"false\"\n        :active-text-color=\"variables.menuActiveText\"\n        :collapse-transition=\"false\"\n        mode=\"vertical\"\n      >\n        <sidebar-item v-for=\"route in routes\" :key=\"route.path\" :item=\"route\" :base-path=\"route.path\" />\n      </el-menu>\n    </el-scrollbar>\n  </div>\n</template>\n\n<script>\nimport { mapGetters } from 'vuex'\nimport Logo from './Logo'\nimport SidebarItem from './SidebarItem'\nimport variables from '@/styles/variables.scss'\n\nexport default {\n  components: { SidebarItem, Logo },\n  computed: {\n    ...mapGetters([\n      'sidebar'\n    ]),\n    routes() {\n      return this.$router.options.routes\n    },\n    activeMenu() {\n      const route = this.$route\n      const { meta, path } = route\n      // if set path, the sidebar will highlight the path you set\n      if (meta.activeMenu) {\n        return meta.activeMenu\n      }\n      return path\n    },\n    showLogo() {\n      return this.$store.state.settings.sidebarLogo\n    },\n    variables() {\n      return variables\n    },\n    isCollapse() {\n      return !this.sidebar.opened\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "admin/admin-ui/src/layout/components/index.js",
    "content": "export { default as Navbar } from './Navbar'\nexport { default as Sidebar } from './Sidebar'\nexport { default as AppMain } from './AppMain'\n"
  },
  {
    "path": "admin/admin-ui/src/layout/index.vue",
    "content": "<template>\n  <div :class=\"classObj\" class=\"app-wrapper\">\n    <div v-if=\"device==='mobile'&&sidebar.opened\" class=\"drawer-bg\" @click=\"handleClickOutside\" />\n    <sidebar class=\"sidebar-container\" />\n    <div class=\"main-container\">\n      <div :class=\"{'fixed-header':fixedHeader}\">\n        <navbar />\n      </div>\n      <app-main />\n    </div>\n  </div>\n</template>\n\n<script>\nimport { Navbar, Sidebar, AppMain } from './components'\nimport ResizeMixin from './mixin/ResizeHandler'\n\nexport default {\n  name: 'Layout',\n  components: {\n    Navbar,\n    Sidebar,\n    AppMain\n  },\n  mixins: [ResizeMixin],\n  computed: {\n    sidebar() {\n      return this.$store.state.app.sidebar\n    },\n    device() {\n      return this.$store.state.app.device\n    },\n    fixedHeader() {\n      return this.$store.state.settings.fixedHeader\n    },\n    classObj() {\n      return {\n        hideSidebar: !this.sidebar.opened,\n        openSidebar: this.sidebar.opened,\n        withoutAnimation: this.sidebar.withoutAnimation,\n        mobile: this.device === 'mobile'\n      }\n    }\n  },\n  methods: {\n    handleClickOutside() {\n      this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })\n    }\n  }\n}\n</script>\n\n<style lang=\"scss\" scoped>\n  @import \"~@/styles/mixin.scss\";\n  @import \"~@/styles/variables.scss\";\n\n  .app-wrapper {\n    @include clearfix;\n    position: relative;\n    height: 100%;\n    width: 100%;\n    &.mobile.openSidebar{\n      position: fixed;\n      top: 0;\n    }\n  }\n  .drawer-bg {\n    background: #000;\n    opacity: 0.3;\n    width: 100%;\n    top: 0;\n    height: 100%;\n    position: absolute;\n    z-index: 999;\n  }\n\n  .fixed-header {\n    position: fixed;\n    top: 0;\n    right: 0;\n    z-index: 9;\n    width: calc(100% - #{$sideBarWidth});\n    transition: width 0.28s;\n  }\n\n  .hideSidebar .fixed-header {\n    width: calc(100% - 54px)\n  }\n\n  .mobile .fixed-header {\n    width: 100%;\n  }\n</style>\n"
  },
  {
    "path": "admin/admin-ui/src/layout/mixin/ResizeHandler.js",
    "content": "import store from '@/store'\n\nconst { body } = document\nconst WIDTH = 992 // refer to Bootstrap's responsive design\n\nexport default {\n  watch: {\n    $route(route) {\n      if (this.device === 'mobile' && this.sidebar.opened) {\n        store.dispatch('app/closeSideBar', { withoutAnimation: false })\n      }\n    }\n  },\n  beforeMount() {\n    window.addEventListener('resize', this.$_resizeHandler)\n  },\n  beforeDestroy() {\n    window.removeEventListener('resize', this.$_resizeHandler)\n  },\n  mounted() {\n    const isMobile = this.$_isMobile()\n    if (isMobile) {\n      store.dispatch('app/toggleDevice', 'mobile')\n      store.dispatch('app/closeSideBar', { withoutAnimation: true })\n    }\n  },\n  methods: {\n    // use $_ for mixins properties\n    // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential\n    $_isMobile() {\n      const rect = body.getBoundingClientRect()\n      return rect.width - 1 < WIDTH\n    },\n    $_resizeHandler() {\n      if (!document.hidden) {\n        const isMobile = this.$_isMobile()\n        store.dispatch('app/toggleDevice', isMobile ? 'mobile' : 'desktop')\n\n        if (isMobile) {\n          store.dispatch('app/closeSideBar', { withoutAnimation: true })\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "admin/admin-ui/src/main.js",
    "content": "import Vue from 'vue'\n\nimport 'normalize.css/normalize.css' // A modern alternative to CSS resets\n\nimport ElementUI from 'element-ui'\nimport 'element-ui/lib/theme-chalk/index.css'\nimport locale from 'element-ui/lib/locale/lang/en' // lang i18n\n\nimport '@/styles/index.scss' // global css\n\nimport App from './App'\nimport store from './store'\nimport router from './router'\n\nimport '@/icons' // icon\nimport '@/permission' // permission control\n\n/**\n * If you don't want to use mock-server\n * you want to use MockJs for mock api\n * you can execute: mockXHR()\n *\n * Currently MockJs will be used in the production environment,\n * please remove it before going online! ! !\n */\n// import { mockXHR } from '../mock'\n// if (process.env.NODE_ENV === 'production') {\n//   mockXHR()\n// }\n\n// set ElementUI lang to EN\nVue.use(ElementUI, {\n  size: 'small',\n  locale\n})\n\nVue.config.productionTip = false\n\nnew Vue({\n  el: '#app',\n  router,\n  store,\n  render: h => h(App)\n})\n"
  },
  {
    "path": "admin/admin-ui/src/permission.js",
    "content": "import router from './router'\nimport store from './store'\nimport { Message } from 'element-ui'\nimport NProgress from 'nprogress' // progress bar\nimport 'nprogress/nprogress.css' // progress bar style\nimport { getToken } from '@/utils/auth' // get token from cookie\nimport getPageTitle from '@/utils/get-page-title'\n\nNProgress.configure({ showSpinner: false }) // NProgress Configuration\n\nconst whiteList = ['/login'] // no redirect whitelist\n\nrouter.beforeEach(async(to, from, next) => {\n  // start progress bar\n  NProgress.start()\n\n  // set page title\n  document.title = getPageTitle(to.meta.title)\n\n  // determine whether the user has logged in\n  const hasToken = getToken()\n\n  if (hasToken) {\n    if (to.path === '/login') {\n      // if is logged in, redirect to the home page\n      next({ path: '/' })\n      NProgress.done()\n    } else {\n      const hasGetUserInfo = store.getters.name\n      if (hasGetUserInfo) {\n        next()\n      } else {\n        try {\n          // get user info\n          await store.dispatch('user/getInfo')\n\n          next()\n        } catch (error) {\n          // remove token and go to login page to re-login\n          await store.dispatch('user/resetToken')\n          Message.error(error || 'Has Error')\n          next(`/login?redirect=${to.path}`)\n          NProgress.done()\n        }\n      }\n    }\n  } else {\n    /* has no token*/\n\n    if (whiteList.indexOf(to.path) !== -1) {\n      // in the free login whitelist, go directly\n      next()\n    } else {\n      // other pages that do not have permission to access are redirected to the login page.\n      next(`/login?redirect=${to.path}`)\n      NProgress.done()\n    }\n  }\n})\n\nrouter.afterEach(() => {\n  // finish progress bar\n  NProgress.done()\n})\n"
  },
  {
    "path": "admin/admin-ui/src/router/index.js",
    "content": "import Vue from 'vue'\nimport Router from 'vue-router'\n\nVue.use(Router)\n\n/* Layout */\nimport Layout from '@/layout'\n\n/**\n * Note: sub-menu only appear when route children.length >= 1\n * Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html\n *\n * hidden: true                   if set true, item will not show in the sidebar(default is false)\n * alwaysShow: true               if set true, will always show the root menu\n *                                if not set alwaysShow, when item has more than one children route,\n *                                it will becomes nested mode, otherwise not show the root menu\n * redirect: noRedirect           if set noRedirect will no redirect in the breadcrumb\n * name:'router-name'             the name is used by <keep-alive> (must set!!!)\n * meta : {\n    roles: ['admin','editor']    control the page roles (you can set multiple roles)\n    title: 'title'               the name show in sidebar and breadcrumb (recommend set)\n    icon: 'svg-name'             the icon show in the sidebar\n    breadcrumb: false            if set false, the item will hidden in breadcrumb(default is true)\n    activeMenu: '/example/list'  if set path, the sidebar will highlight the path you set\n  }\n */\n\n/**\n * constantRoutes\n * a base page that does not have permission requirements\n * all roles can be accessed\n */\nexport const constantRoutes = [\n  {\n    path: '/login',\n    component: () => import('@/views/login/index'),\n    hidden: true\n  },\n\n  {\n    path: '/404',\n    component: () => import('@/views/404'),\n    hidden: true\n  },\n\n  {\n    path: '/',\n    component: Layout,\n    redirect: '/dashboard',\n    children: [{\n      path: 'dashboard',\n      name: '主页',\n      component: () => import('@/views/dashboard/index'),\n      meta: { title: '主页', icon: 'dashboard' }\n    }],\n    hidden: true\n  },\n\n  {\n    path: '/sys',\n    component: Layout,\n    redirect: '/user',\n    children: [{\n      path: 'user',\n      name: '用户信息',\n      component: () => import('@/views/sys/UserInfo'),\n      meta: { title: '用户信息' }\n    }],\n    hidden: true\n  },\n\n  {\n    path: '/canalServer',\n    component: Layout,\n    redirect: '/canalServer/nodeServers',\n    name: 'Canal Server',\n    meta: { title: 'Canal Server', icon: 'example' },\n    children: [\n      {\n        path: 'canalClusters',\n        name: 'Canal 集群管理',\n        component: () => import('@/views/canalServer/CanalCluster'),\n        meta: { title: '集群管理', icon: 'tree' }\n      },\n      {\n        path: 'nodeServers',\n        name: 'Server 状态',\n        component: () => import('@/views/canalServer/NodeServer'),\n        meta: { title: 'Server 管理', icon: 'form' }\n      },\n      {\n        path: 'nodeServer/config',\n        name: 'Server 配置',\n        component: () => import('@/views/canalServer/CanalConfig'),\n        meta: { title: 'Server 配置' },\n        hidden: true\n      },\n      {\n        path: 'canalInstances',\n        name: 'Instance 管理',\n        component: () => import('@/views/canalServer/CanalInstance'),\n        meta: { title: 'Instance 管理', icon: 'nested' }\n      },\n      {\n        path: 'canalInstance/add',\n        name: '新建Instance配置',\n        component: () => import('@/views/canalServer/CanalInstanceAdd'),\n        meta: { title: '新建Instance配置' },\n        hidden: true\n      },\n      {\n        path: 'canalInstance/modify',\n        name: '修改Instance配置',\n        component: () => import('@/views/canalServer/CanalInstanceUpdate'),\n        meta: { title: '修改Instance配置' },\n        hidden: true\n      },\n      {\n        path: 'nodeServer/log',\n        name: 'Server 日志',\n        component: () => import('@/views/canalServer/CanalLogDetail'),\n        meta: { title: 'Server 日志' },\n        hidden: true\n      },\n      {\n        path: 'canalInstance/log',\n        name: 'Instance 日志',\n        component: () => import('@/views/canalServer/CanalInstanceLogDetail'),\n        meta: { title: 'Instance 日志' },\n        hidden: true\n      }\n    ]\n  },\n\n  // 404 page must be placed at the end !!!\n  { path: '*', redirect: '/404', hidden: true }\n]\n\nconst createRouter = () => new Router({\n  // mode: 'history', // require service support\n  scrollBehavior: () => ({ y: 0 }),\n  routes: constantRoutes\n})\n\nconst router = createRouter()\n\n// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465\nexport function resetRouter() {\n  const newRouter = createRouter()\n  router.matcher = newRouter.matcher // reset router\n}\n\nexport default router\n"
  },
  {
    "path": "admin/admin-ui/src/settings.js",
    "content": "module.exports = {\n\n  title: 'Canal Admin',\n\n  /**\n   * @type {boolean} true | false\n   * @description Whether fix the header\n   */\n  fixedHeader: true,\n\n  /**\n   * @type {boolean} true | false\n   * @description Whether show the logo in sidebar\n   */\n  sidebarLogo: true\n}\n"
  },
  {
    "path": "admin/admin-ui/src/store/getters.js",
    "content": "const getters = {\n  sidebar: state => state.app.sidebar,\n  device: state => state.app.device,\n  token: state => state.user.token,\n  avatar: state => state.user.avatar,\n  name: state => state.user.name\n}\nexport default getters\n"
  },
  {
    "path": "admin/admin-ui/src/store/index.js",
    "content": "import Vue from 'vue'\nimport Vuex from 'vuex'\nimport getters from './getters'\nimport app from './modules/app'\nimport settings from './modules/settings'\nimport user from './modules/user'\n\nVue.use(Vuex)\n\nconst store = new Vuex.Store({\n  modules: {\n    app,\n    settings,\n    user\n  },\n  getters\n})\n\nexport default store\n"
  },
  {
    "path": "admin/admin-ui/src/store/modules/app.js",
    "content": "import Cookies from 'js-cookie'\n\nconst state = {\n  sidebar: {\n    opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,\n    withoutAnimation: false\n  },\n  device: 'desktop'\n}\n\nconst mutations = {\n  TOGGLE_SIDEBAR: state => {\n    state.sidebar.opened = !state.sidebar.opened\n    state.sidebar.withoutAnimation = false\n    if (state.sidebar.opened) {\n      Cookies.set('sidebarStatus', 1)\n    } else {\n      Cookies.set('sidebarStatus', 0)\n    }\n  },\n  CLOSE_SIDEBAR: (state, withoutAnimation) => {\n    Cookies.set('sidebarStatus', 0)\n    state.sidebar.opened = false\n    state.sidebar.withoutAnimation = withoutAnimation\n  },\n  TOGGLE_DEVICE: (state, device) => {\n    state.device = device\n  }\n}\n\nconst actions = {\n  toggleSideBar({ commit }) {\n    commit('TOGGLE_SIDEBAR')\n  },\n  closeSideBar({ commit }, { withoutAnimation }) {\n    commit('CLOSE_SIDEBAR', withoutAnimation)\n  },\n  toggleDevice({ commit }, device) {\n    commit('TOGGLE_DEVICE', device)\n  }\n}\n\nexport default {\n  namespaced: true,\n  state,\n  mutations,\n  actions\n}\n"
  },
  {
    "path": "admin/admin-ui/src/store/modules/settings.js",
    "content": "import defaultSettings from '@/settings'\n\nconst { showSettings, fixedHeader, sidebarLogo } = defaultSettings\n\nconst state = {\n  showSettings: showSettings,\n  fixedHeader: fixedHeader,\n  sidebarLogo: sidebarLogo\n}\n\nconst mutations = {\n  CHANGE_SETTING: (state, { key, value }) => {\n    if (state.hasOwnProperty(key)) {\n      state[key] = value\n    }\n  }\n}\n\nconst actions = {\n  changeSetting({ commit }, data) {\n    commit('CHANGE_SETTING', data)\n  }\n}\n\nexport default {\n  namespaced: true,\n  state,\n  mutations,\n  actions\n}\n\n"
  },
  {
    "path": "admin/admin-ui/src/store/modules/user.js",
    "content": "import { login, logout, getInfo } from '@/api/user'\nimport { getToken, setToken, removeToken } from '@/utils/auth'\nimport { resetRouter } from '@/router'\n\nconst state = {\n  token: getToken(),\n  name: '',\n  avatar: ''\n}\n\nconst mutations = {\n  SET_TOKEN: (state, token) => {\n    state.token = token\n  },\n  SET_NAME: (state, name) => {\n    state.name = name\n  },\n  SET_AVATAR: (state, avatar) => {\n    state.avatar = avatar\n  }\n}\n\nconst actions = {\n  // user login\n  login({ commit }, userInfo) {\n    const { username, password } = userInfo\n    return new Promise((resolve, reject) => {\n      login({ username: username.trim(), password: password }).then(response => {\n        const { data } = response\n        commit('SET_TOKEN', data.token)\n        setToken(data.token)\n        resolve()\n      }).catch(error => {\n        reject(error)\n      })\n    })\n  },\n\n  // get user info\n  getInfo({ commit, state }) {\n    return new Promise((resolve, reject) => {\n      getInfo(state.token).then(response => {\n        const { data } = response\n\n        if (!data) {\n          reject('Verification failed, please Login again.')\n        }\n\n        const { name, avatar } = data\n\n        commit('SET_NAME', name)\n        commit('SET_AVATAR', avatar)\n        resolve(data)\n      }).catch(error => {\n        reject(error)\n      })\n    })\n  },\n\n  // user logout\n  logout({ commit, state }) {\n    return new Promise((resolve, reject) => {\n      logout(state.token).then(() => {\n        commit('SET_TOKEN', '')\n        removeToken()\n        resetRouter()\n        resolve()\n      }).catch(error => {\n        reject(error)\n      })\n    })\n  },\n\n  // remove token\n  resetToken({ commit }) {\n    return new Promise(resolve => {\n      commit('SET_TOKEN', '')\n      removeToken()\n      resolve()\n    })\n  }\n}\n\nexport default {\n  namespaced: true,\n  state,\n  mutations,\n  actions\n}\n\n"
  },
  {
    "path": "admin/admin-ui/src/styles/element-ui.scss",
    "content": "// cover some element-ui styles\n\n.el-breadcrumb__inner,\n.el-breadcrumb__inner a {\n  font-weight: 400 !important;\n}\n\n.el-upload {\n  input[type=\"file\"] {\n    display: none !important;\n  }\n}\n\n.el-upload__input {\n  display: none;\n}\n\n\n// to fixed https://github.com/ElemeFE/element/issues/2461\n.el-dialog {\n  transform: none;\n  left: 0;\n  position: relative;\n  margin: 0 auto;\n}\n\n// refine element ui upload\n.upload-container {\n  .el-upload {\n    width: 100%;\n\n    .el-upload-dragger {\n      width: 100%;\n      height: 200px;\n    }\n  }\n}\n\n// dropdown\n.el-dropdown-menu {\n  a {\n    display: block\n  }\n}\n"
  },
  {
    "path": "admin/admin-ui/src/styles/index.scss",
    "content": "@import './variables.scss';\n@import './mixin.scss';\n@import './transition.scss';\n@import './element-ui.scss';\n@import './sidebar.scss';\n\nbody {\n  height: 100%;\n  -moz-osx-font-smoothing: grayscale;\n  -webkit-font-smoothing: antialiased;\n  text-rendering: optimizeLegibility;\n  font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;\n}\n\nlabel {\n  font-weight: 700;\n}\n\nhtml {\n  height: 100%;\n  box-sizing: border-box;\n}\n\n#app {\n  height: 100%;\n}\n\n*,\n*:before,\n*:after {\n  box-sizing: inherit;\n}\n\na:focus,\na:active {\n  outline: none;\n}\n\na,\na:focus,\na:hover {\n  cursor: pointer;\n  color: inherit;\n  text-decoration: none;\n}\n\ndiv:focus {\n  outline: none;\n}\n\n.clearfix {\n  &:after {\n    visibility: hidden;\n    display: block;\n    font-size: 0;\n    content: \" \";\n    clear: both;\n    height: 0;\n  }\n}\n\n// main-container global css\n.app-container {\n  padding: 20px;\n}\n\n.filter-container {\n  padding-bottom: 10px;\n  .filter-item {\n    display: inline-block;\n    vertical-align: middle;\n    margin-bottom: 10px;\n  }\n}"
  },
  {
    "path": "admin/admin-ui/src/styles/mixin.scss",
    "content": "@mixin clearfix {\n  &:after {\n    content: \"\";\n    display: table;\n    clear: both;\n  }\n}\n\n@mixin scrollBar {\n  &::-webkit-scrollbar-track-piece {\n    background: #d3dce6;\n  }\n\n  &::-webkit-scrollbar {\n    width: 6px;\n  }\n\n  &::-webkit-scrollbar-thumb {\n    background: #99a9bf;\n    border-radius: 20px;\n  }\n}\n\n@mixin relative {\n  position: relative;\n  width: 100%;\n  height: 100%;\n}\n"
  },
  {
    "path": "admin/admin-ui/src/styles/sidebar.scss",
    "content": "#app {\n\n  .main-container {\n    min-height: 100%;\n    transition: margin-left .28s;\n    margin-left: $sideBarWidth;\n    position: relative;\n  }\n\n  .sidebar-container {\n    transition: width 0.28s;\n    width: $sideBarWidth !important;\n    background-color: $menuBg;\n    height: 100%;\n    position: fixed;\n    font-size: 0px;\n    top: 0;\n    bottom: 0;\n    left: 0;\n    z-index: 1001;\n    overflow: hidden;\n\n    // reset element-ui css\n    .horizontal-collapse-transition {\n      transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out;\n    }\n\n    .scrollbar-wrapper {\n      overflow-x: hidden !important;\n    }\n\n    .el-scrollbar__bar.is-vertical {\n      right: 0px;\n    }\n\n    .el-scrollbar {\n      height: 100%;\n    }\n\n    &.has-logo {\n      .el-scrollbar {\n        height: calc(100% - 50px);\n      }\n    }\n\n    .is-horizontal {\n      display: none;\n    }\n\n    a {\n      display: inline-block;\n      width: 100%;\n      overflow: hidden;\n    }\n\n    .svg-icon {\n      margin-right: 16px;\n    }\n\n    .el-menu {\n      border: none;\n      height: 100%;\n      width: 100% !important;\n    }\n\n    // menu hover\n    .submenu-title-noDropdown,\n    .el-submenu__title {\n      &:hover {\n        background-color: $menuHover !important;\n      }\n    }\n\n    .is-active>.el-submenu__title {\n      color: $subMenuActiveText !important;\n    }\n\n    & .nest-menu .el-submenu>.el-submenu__title,\n    & .el-submenu .el-menu-item {\n      min-width: $sideBarWidth !important;\n      background-color: $subMenuBg !important;\n\n      &:hover {\n        background-color: $subMenuHover !important;\n      }\n    }\n  }\n\n  .hideSidebar {\n    .sidebar-container {\n      width: 54px !important;\n    }\n\n    .main-container {\n      margin-left: 54px;\n    }\n\n    .submenu-title-noDropdown {\n      padding: 0 !important;\n      position: relative;\n\n      .el-tooltip {\n        padding: 0 !important;\n\n        .svg-icon {\n          margin-left: 20px;\n        }\n      }\n    }\n\n    .el-submenu {\n      overflow: hidden;\n\n      &>.el-submenu__title {\n        padding: 0 !important;\n\n        .svg-icon {\n          margin-left: 20px;\n        }\n\n        .el-submenu__icon-arrow {\n          display: none;\n        }\n      }\n    }\n\n    .el-menu--collapse {\n      .el-submenu {\n        &>.el-submenu__title {\n          &>span {\n            height: 0;\n            width: 0;\n            overflow: hidden;\n            visibility: hidden;\n            display: inline-block;\n          }\n        }\n      }\n    }\n  }\n\n  .el-menu--collapse .el-menu .el-submenu {\n    min-width: $sideBarWidth !important;\n  }\n\n  // mobile responsive\n  .mobile {\n    .main-container {\n      margin-left: 0px;\n    }\n\n    .sidebar-container {\n      transition: transform .28s;\n      width: $sideBarWidth !important;\n    }\n\n    &.hideSidebar {\n      .sidebar-container {\n        pointer-events: none;\n        transition-duration: 0.3s;\n        transform: translate3d(-$sideBarWidth, 0, 0);\n      }\n    }\n  }\n\n  .withoutAnimation {\n\n    .main-container,\n    .sidebar-container {\n      transition: none;\n    }\n  }\n}\n\n// when menu collapsed\n.el-menu--vertical {\n  &>.el-menu {\n    .svg-icon {\n      margin-right: 16px;\n    }\n  }\n\n  .nest-menu .el-submenu>.el-submenu__title,\n  .el-menu-item {\n    &:hover {\n      // you can use $subMenuHover\n      background-color: $menuHover !important;\n    }\n  }\n\n  // the scroll bar appears when the subMenu is too long\n  >.el-menu--popup {\n    max-height: 100vh;\n    overflow-y: auto;\n\n    &::-webkit-scrollbar-track-piece {\n      background: #d3dce6;\n    }\n\n    &::-webkit-scrollbar {\n      width: 6px;\n    }\n\n    &::-webkit-scrollbar-thumb {\n      background: #99a9bf;\n      border-radius: 20px;\n    }\n  }\n}\n"
  },
  {
    "path": "admin/admin-ui/src/styles/transition.scss",
    "content": "// global transition css\n\n/* fade */\n.fade-enter-active,\n.fade-leave-active {\n  transition: opacity 0.28s;\n}\n\n.fade-enter,\n.fade-leave-active {\n  opacity: 0;\n}\n\n/* fade-transform */\n.fade-transform-leave-active,\n.fade-transform-enter-active {\n  transition: all .5s;\n}\n\n.fade-transform-enter {\n  opacity: 0;\n  transform: translateX(-30px);\n}\n\n.fade-transform-leave-to {\n  opacity: 0;\n  transform: translateX(30px);\n}\n\n/* breadcrumb transition */\n.breadcrumb-enter-active,\n.breadcrumb-leave-active {\n  transition: all .5s;\n}\n\n.breadcrumb-enter,\n.breadcrumb-leave-active {\n  opacity: 0;\n  transform: translateX(20px);\n}\n\n.breadcrumb-move {\n  transition: all .5s;\n}\n\n.breadcrumb-leave-active {\n  position: absolute;\n}\n"
  },
  {
    "path": "admin/admin-ui/src/styles/variables.scss",
    "content": "// sidebar\n$menuText:#bfcbd9;\n$menuActiveText:#409EFF;\n$subMenuActiveText:#f4f4f5; //https://github.com/ElemeFE/element/issues/12951\n\n$menuBg:#304156;\n$menuHover:#263445;\n\n$subMenuBg:#1f2d3d;\n$subMenuHover:#001528;\n\n$sideBarWidth: 210px;\n\n// the :export directive is the magic sauce for webpack\n// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass\n:export {\n  menuText: $menuText;\n  menuActiveText: $menuActiveText;\n  subMenuActiveText: $subMenuActiveText;\n  menuBg: $menuBg;\n  menuHover: $menuHover;\n  subMenuBg: $subMenuBg;\n  subMenuHover: $subMenuHover;\n  sideBarWidth: $sideBarWidth;\n}\n"
  },
  {
    "path": "admin/admin-ui/src/utils/auth.js",
    "content": "import Cookies from 'js-cookie'\n\nconst TokenKey = 'canal_admin_token'\n\nexport function getToken() {\n  return Cookies.get(TokenKey)\n}\n\nexport function setToken(token) {\n  return Cookies.set(TokenKey, token, { maxAge: 0 })\n}\n\nexport function removeToken() {\n  return Cookies.remove(TokenKey)\n}\n"
  },
  {
    "path": "admin/admin-ui/src/utils/get-page-title.js",
    "content": "import defaultSettings from '@/settings'\n\nconst title = defaultSettings.title || 'Vue Admin Template'\n\nexport default function getPageTitle(pageTitle) {\n  if (pageTitle) {\n    return `${pageTitle} - ${title}`\n  }\n  return `${title}`\n}\n"
  },
  {
    "path": "admin/admin-ui/src/utils/index.js",
    "content": "/**\n * Created by PanJiaChen on 16/11/18.\n */\n\n/**\n * Parse the time to string\n * @param {(Object|string|number)} time\n * @param {string} cFormat\n * @returns {string}\n */\nexport function parseTime(time, cFormat) {\n  if (arguments.length === 0) {\n    return null\n  }\n  const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'\n  let date\n  if (typeof time === 'object') {\n    date = time\n  } else {\n    if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {\n      time = parseInt(time)\n    }\n    if ((typeof time === 'number') && (time.toString().length === 10)) {\n      time = time * 1000\n    }\n    date = new Date(time)\n  }\n  const formatObj = {\n    y: date.getFullYear(),\n    m: date.getMonth() + 1,\n    d: date.getDate(),\n    h: date.getHours(),\n    i: date.getMinutes(),\n    s: date.getSeconds(),\n    a: date.getDay()\n  }\n  const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {\n    let value = formatObj[key]\n    // Note: getDay() returns 0 on Sunday\n    if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] }\n    if (result.length > 0 && value < 10) {\n      value = '0' + value\n    }\n    return value || 0\n  })\n  return time_str\n}\n\n/**\n * @param {number} time\n * @param {string} option\n * @returns {string}\n */\nexport function formatTime(time, option) {\n  if (('' + time).length === 10) {\n    time = parseInt(time) * 1000\n  } else {\n    time = +time\n  }\n  const d = new Date(time)\n  const now = Date.now()\n\n  const diff = (now - d) / 1000\n\n  if (diff < 30) {\n    return '刚刚'\n  } else if (diff < 3600) {\n    // less 1 hour\n    return Math.ceil(diff / 60) + '分钟前'\n  } else if (diff < 3600 * 24) {\n    return Math.ceil(diff / 3600) + '小时前'\n  } else if (diff < 3600 * 24 * 2) {\n    return '1天前'\n  }\n  if (option) {\n    return parseTime(time, option)\n  } else {\n    return (\n      d.getMonth() +\n      1 +\n      '月' +\n      d.getDate() +\n      '日' +\n      d.getHours() +\n      '时' +\n      d.getMinutes() +\n      '分'\n    )\n  }\n}\n\n/**\n * @param {string} url\n * @returns {Object}\n */\nexport function param2Obj(url) {\n  const search = url.split('?')[1]\n  if (!search) {\n    return {}\n  }\n  return JSON.parse(\n    '{\"' +\n      decodeURIComponent(search)\n        .replace(/\"/g, '\\\\\"')\n        .replace(/&/g, '\",\"')\n        .replace(/=/g, '\":\"')\n        .replace(/\\+/g, ' ') +\n      '\"}'\n  )\n}\n"
  },
  {
    "path": "admin/admin-ui/src/utils/request.js",
    "content": "import axios from 'axios'\nimport { MessageBox, Message } from 'element-ui'\nimport store from '@/store'\nimport { getToken } from '@/utils/auth'\n\n// create an axios instance\nconst service = axios.create({\n  baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url\n  // withCredentials: true, // send cookies when cross-domain requests\n  timeout: 60000 // request timeout\n})\n\n// request interceptor\nservice.interceptors.request.use(\n  config => {\n    // do something before request is sent\n\n    if (store.getters.token) {\n      // let each request carry token\n      // ['X-Token'] is a custom headers key\n      // please modify it according to the actual situation\n      config.headers['X-Token'] = getToken()\n    }\n    return config\n  },\n  error => {\n    // do something with request error\n    console.log(error) // for debug\n    return Promise.reject(error)\n  }\n)\n\n// response interceptor\nservice.interceptors.response.use(\n  /**\n   * If you want to get http information such as headers or status\n   * Please return  response => response\n  */\n\n  /**\n   * Determine the request status by custom code\n   * Here is just an example\n   * You can also judge the status by HTTP Status Code\n   */\n  response => {\n    const res = response.data\n\n    // if the custom code is not 20000, it is judged as an error.\n    if (res.code !== 20000) {\n      Message({\n        message: res.message || 'Error',\n        type: 'error',\n        duration: 5 * 1000\n      })\n\n      // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;\n      if (res.code === 50008 || res.code === 50012 || res.code === 50014) {\n        // to re-login\n        MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {\n          confirmButtonText: 'Re-Login',\n          cancelButtonText: 'Cancel',\n          type: 'warning'\n        }).then(() => {\n          store.dispatch('user/resetToken').then(() => {\n            location.reload()\n          })\n        })\n      }\n      return Promise.reject(new Error(res.message || 'Error'))\n    } else {\n      return res\n    }\n  },\n  error => {\n    console.log('err' + error) // for debug\n    Message({\n      message: error.message,\n      type: 'error',\n      duration: 5 * 1000\n    })\n    return Promise.reject(error)\n  }\n)\n\nexport default service\n"
  },
  {
    "path": "admin/admin-ui/src/utils/scrollTo.js",
    "content": "Math.easeInOutQuad = function(t, b, c, d) {\n  t /= d / 2\n  if (t < 1) {\n    return c / 2 * t * t + b\n  }\n  t--\n  return -c / 2 * (t * (t - 2) - 1) + b\n}\n\n// requestAnimationFrame for Smart Animating http://goo.gl/sx5sts\nvar requestAnimFrame = (function() {\n  return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60) }\n})()\n\n// because it's so fucking difficult to detect the scrolling element, just move them all\nfunction move(amount) {\n  document.documentElement.scrollTop = amount\n  document.body.parentNode.scrollTop = amount\n  document.body.scrollTop = amount\n}\n\nfunction position() {\n  return document.documentElement.scrollTop || document.body.parentNode.scrollTop || document.body.scrollTop\n}\n\nexport function scrollTo(to, duration, callback) {\n  const start = position()\n  const change = to - start\n  const increment = 20\n  let currentTime = 0\n  duration = (typeof (duration) === 'undefined') ? 500 : duration\n  var animateScroll = function() {\n    // increment the time\n    currentTime += increment\n    // find the value with the quadratic in-out easing function\n    var val = Math.easeInOutQuad(currentTime, start, change, duration)\n    // move the document.body\n    move(val)\n    // do the animation unless its over\n    if (currentTime < duration) {\n      requestAnimFrame(animateScroll)\n    } else {\n      if (callback && typeof (callback) === 'function') {\n        // the animation is done so lets callback\n        callback()\n      }\n    }\n  }\n  animateScroll()\n}\n"
  },
  {
    "path": "admin/admin-ui/src/utils/validate.js",
    "content": "/**\n * Created by PanJiaChen on 16/11/18.\n */\n\n/**\n * @param {string} path\n * @returns {Boolean}\n */\nexport function isExternal(path) {\n  return /^(https?:|mailto:|tel:)/.test(path)\n}\n\n/**\n * @param {string} str\n * @returns {Boolean}\n */\nexport function validUsername(str) {\n  const valid_map = ['admin', 'editor']\n  return valid_map.indexOf(str.trim()) >= 0\n}\n"
  },
  {
    "path": "admin/admin-ui/src/views/404.vue",
    "content": "<template>\n  <div class=\"wscn-http404-container\">\n    <div class=\"wscn-http404\">\n      <div class=\"pic-404\">\n        <img class=\"pic-404__parent\" src=\"@/assets/404_images/404.png\" alt=\"404\">\n        <img class=\"pic-404__child left\" src=\"@/assets/404_images/404_cloud.png\" alt=\"404\">\n        <img class=\"pic-404__child mid\" src=\"@/assets/404_images/404_cloud.png\" alt=\"404\">\n        <img class=\"pic-404__child right\" src=\"@/assets/404_images/404_cloud.png\" alt=\"404\">\n      </div>\n      <div class=\"bullshit\">\n        <div class=\"bullshit__oops\">OOPS!</div>\n        <div class=\"bullshit__info\">All rights reserved\n          <a style=\"color:#20a0ff\" href=\"https://wallstreetcn.com\" target=\"_blank\">wallstreetcn</a>\n        </div>\n        <div class=\"bullshit__headline\">{{ message }}</div>\n        <div class=\"bullshit__info\">Please check that the URL you entered is correct, or click the button below to return to the homepage.</div>\n        <a href=\"\" class=\"bullshit__return-home\">Back to home</a>\n      </div>\n    </div>\n  </div>\n</template>\n\n<script>\n\nexport default {\n  name: 'Page404',\n  computed: {\n    message() {\n      return 'The webmaster said that you can not enter this page...'\n    }\n  }\n}\n</script>\n\n<style lang=\"scss\" scoped>\n.wscn-http404-container{\n  transform: translate(-50%,-50%);\n  position: absolute;\n  top: 40%;\n  left: 50%;\n}\n.wscn-http404 {\n  position: relative;\n  width: 1200px;\n  padding: 0 50px;\n  overflow: hidden;\n  .pic-404 {\n    position: relative;\n    float: left;\n    width: 600px;\n    overflow: hidden;\n    &__parent {\n      width: 100%;\n    }\n    &__child {\n      position: absolute;\n      &.left {\n        width: 80px;\n        top: 17px;\n        left: 220px;\n        opacity: 0;\n        animation-name: cloudLeft;\n        animation-duration: 2s;\n        animation-timing-function: linear;\n        animation-fill-mode: forwards;\n        animation-delay: 1s;\n      }\n      &.mid {\n        width: 46px;\n        top: 10px;\n        left: 420px;\n        opacity: 0;\n        animation-name: cloudMid;\n        animation-duration: 2s;\n        animation-timing-function: linear;\n        animation-fill-mode: forwards;\n        animation-delay: 1.2s;\n      }\n      &.right {\n        width: 62px;\n        top: 100px;\n        left: 500px;\n        opacity: 0;\n        animation-name: cloudRight;\n        animation-duration: 2s;\n        animation-timing-function: linear;\n        animation-fill-mode: forwards;\n        animation-delay: 1s;\n      }\n      @keyframes cloudLeft {\n        0% {\n          top: 17px;\n          left: 220px;\n          opacity: 0;\n        }\n        20% {\n          top: 33px;\n          left: 188px;\n          opacity: 1;\n        }\n        80% {\n          top: 81px;\n          left: 92px;\n          opacity: 1;\n        }\n        100% {\n          top: 97px;\n          left: 60px;\n          opacity: 0;\n        }\n      }\n      @keyframes cloudMid {\n        0% {\n          top: 10px;\n          left: 420px;\n          opacity: 0;\n        }\n        20% {\n          top: 40px;\n          left: 360px;\n          opacity: 1;\n        }\n        70% {\n          top: 130px;\n          left: 180px;\n          opacity: 1;\n        }\n        100% {\n          top: 160px;\n          left: 120px;\n          opacity: 0;\n        }\n      }\n      @keyframes cloudRight {\n        0% {\n          top: 100px;\n          left: 500px;\n          opacity: 0;\n        }\n        20% {\n          top: 120px;\n          left: 460px;\n          opacity: 1;\n        }\n        80% {\n          top: 180px;\n          left: 340px;\n          opacity: 1;\n        }\n        100% {\n          top: 200px;\n          left: 300px;\n          opacity: 0;\n        }\n      }\n    }\n  }\n  .bullshit {\n    position: relative;\n    float: left;\n    width: 300px;\n    padding: 30px 0;\n    overflow: hidden;\n    &__oops {\n      font-size: 32px;\n      font-weight: bold;\n      line-height: 40px;\n      color: #1482f0;\n      opacity: 0;\n      margin-bottom: 20px;\n      animation-name: slideUp;\n      animation-duration: 0.5s;\n      animation-fill-mode: forwards;\n    }\n    &__headline {\n      font-size: 20px;\n      line-height: 24px;\n      color: #222;\n      font-weight: bold;\n      opacity: 0;\n      margin-bottom: 10px;\n      animation-name: slideUp;\n      animation-duration: 0.5s;\n      animation-delay: 0.1s;\n      animation-fill-mode: forwards;\n    }\n    &__info {\n      font-size: 13px;\n      line-height: 21px;\n      color: grey;\n      opacity: 0;\n      margin-bottom: 30px;\n      animation-name: slideUp;\n      animation-duration: 0.5s;\n      animation-delay: 0.2s;\n      animation-fill-mode: forwards;\n    }\n    &__return-home {\n      display: block;\n      float: left;\n      width: 110px;\n      height: 36px;\n      background: #1482f0;\n      border-radius: 100px;\n      text-align: center;\n      color: #ffffff;\n      opacity: 0;\n      font-size: 14px;\n      line-height: 36px;\n      cursor: pointer;\n      animation-name: slideUp;\n      animation-duration: 0.5s;\n      animation-delay: 0.3s;\n      animation-fill-mode: forwards;\n    }\n    @keyframes slideUp {\n      0% {\n        transform: translateY(60px);\n        opacity: 0;\n      }\n      100% {\n        transform: translateY(0);\n        opacity: 1;\n      }\n    }\n  }\n}\n</style>\n"
  },
  {
    "path": "admin/admin-ui/src/views/canalServer/CanalCluster.vue",
    "content": "<template>\n  <div class=\"app-container\">\n    <div class=\"filter-container\">\n      <!-- <el-input v-model=\"listQuery.name\" placeholder=\"Server 名称\" style=\"width: 200px;\" class=\"filter-item\" />\n      <el-input v-model=\"listQuery.ip\" placeholder=\"Server IP\" style=\"width: 200px;\" class=\"filter-item\" />\n      <el-button class=\"filter-item\" type=\"primary\" icon=\"el-icon-search\" plain @click=\"fetchData()\">查询</el-button> -->\n      <el-button class=\"filter-item\" type=\"primary\" @click=\"handleCreate()\">新建集群</el-button>\n    </div>\n    <el-table\n      v-loading=\"listLoading\"\n      :data=\"list\"\n      element-loading-text=\"Loading\"\n      border\n      fit\n      highlight-current-row\n    >\n      <el-table-column label=\"集群名称\" min-width=\"200\" align=\"center\">\n        <template slot-scope=\"scope\">\n          {{ scope.row.name }}\n        </template>\n      </el-table-column>\n      <el-table-column label=\"ZK地址\" min-width=\"300\" align=\"center\">\n        <template slot-scope=\"scope\">\n          <span>{{ scope.row.zkHosts }}</span>\n        </template>\n      </el-table-column>\n      <el-table-column align=\"center\" prop=\"created_at\" label=\"操作\" min-width=\"150\">\n        <template slot-scope=\"scope\">\n          <el-dropdown trigger=\"click\">\n            <el-button type=\"primary\" size=\"mini\">\n              操作<i class=\"el-icon-arrow-down el-icon--right\" />\n            </el-button>\n            <el-dropdown-menu slot=\"dropdown\">\n              <el-dropdown-item @click.native=\"handleConfig(scope.row)\">主配置</el-dropdown-item>\n              <el-dropdown-item @click.native=\"handleUpdate(scope.row)\">修改集群</el-dropdown-item>\n              <el-dropdown-item @click.native=\"handleDelete(scope.row)\">删除集群</el-dropdown-item>\n              <el-dropdown-item @click.native=\"handleView(scope.row)\">查看Server</el-dropdown-item>\n            </el-dropdown-menu>\n          </el-dropdown>\n        </template>\n      </el-table-column>\n    </el-table>\n    <el-dialog :visible.sync=\"dialogFormVisible\" :title=\"textMap[dialogStatus]\" width=\"600px\">\n      <el-form ref=\"dataForm\" :rules=\"rules\" :model=\"canalCluster\" label-position=\"left\" label-width=\"120px\" style=\"width: 400px; margin-left:30px;\">\n        <el-form-item label=\"集群名称\" prop=\"name\">\n          <el-input v-model=\"canalCluster.name\" />\n        </el-form-item>\n        <el-form-item label=\"ZK地址\" prop=\"zkHosts\">\n          <el-input v-model=\"canalCluster.zkHosts\" />\n        </el-form-item>\n      </el-form>\n      <div slot=\"footer\" class=\"dialog-footer\">\n        <el-button @click=\"dialogFormVisible = false\">取消</el-button>\n        <el-button type=\"primary\" @click=\"dataOperation()\">确定</el-button>\n      </div>\n    </el-dialog>\n  </div>\n</template>\n\n<script>\nimport { addCanalCluster, getCanalClusters, updateCanalCluster, deleteCanalCluster } from '@/api/canalCluster'\n\nexport default {\n  filters: {\n    statusFilter(status) {\n      const statusMap = {\n        '1': 'success',\n        '0': 'gray',\n        '-1': 'danger'\n      }\n      return statusMap[status]\n    },\n    statusLabel(status) {\n      const statusMap = {\n        '1': '启动',\n        '0': '停止',\n        '-1': '断开'\n      }\n      return statusMap[status]\n    }\n  },\n  data() {\n    return {\n      list: null,\n      listLoading: true,\n      listQuery: {\n        name: '',\n        ip: ''\n      },\n      dialogFormVisible: false,\n      textMap: {\n        create: '新建集群信息',\n        update: '修改集群信息'\n      },\n      canalCluster: {\n        id: null,\n        name: null,\n        zkHosts: null\n      },\n      rules: {\n        name: [{ required: true, message: '集群名称不能为空', trigger: 'change' }],\n        zkHosts: [{ required: true, message: 'zk地址不能为空', trigger: 'change' }]\n      },\n      dialogStatus: 'create'\n    }\n  },\n  created() {\n    this.fetchData()\n  },\n  methods: {\n    fetchData() {\n      this.listLoading = true\n      getCanalClusters(this.listQuery).then(res => {\n        this.list = res.data\n      }).finally(() => {\n        this.listLoading = false\n      })\n    },\n    resetModel() {\n      this.canalCluster = {\n        id: null,\n        name: null,\n        zkHosts: null\n      }\n    },\n    handleCreate() {\n      this.resetModel()\n      this.dialogStatus = 'create'\n      this.dialogFormVisible = true\n      this.$nextTick(() => {\n        this.$refs['dataForm'].clearValidate()\n      })\n    },\n    dataOperation() {\n      this.$refs['dataForm'].validate((valid) => {\n        if (valid) {\n          if (this.dialogStatus === 'create') {\n            addCanalCluster(this.canalCluster).then(res => {\n              this.operationRes(res)\n            })\n          }\n          if (this.dialogStatus === 'update') {\n            updateCanalCluster(this.canalCluster).then(res => {\n              this.operationRes(res)\n            })\n          }\n        }\n      })\n    },\n    operationRes(res) {\n      if (res.data === 'success') {\n        this.fetchData()\n        this.dialogFormVisible = false\n        this.$message({\n          message: this.textMap[this.dialogStatus] + '成功',\n          type: 'success'\n        })\n      } else {\n        this.$message({\n          message: this.textMap[this.dialogStatus] + '失败',\n          type: 'error'\n        })\n      }\n    },\n    handleView(row) {\n      this.$router.push('/canalServer/nodeServers?clusterId=' + row.id)\n    },\n    handleConfig(row) {\n      this.$router.push('/canalServer/nodeServer/config?clusterId=' + row.id)\n    },\n    handleUpdate(row) {\n      this.resetModel()\n      this.canalCluster = Object.assign({}, row)\n      this.dialogStatus = 'update'\n      this.dialogFormVisible = true\n      this.$nextTick(() => {\n        this.$refs['dataForm'].clearValidate()\n      })\n    },\n    handleDelete(row) {\n      this.$confirm('删除集群信息会导致服务停止', '确定删除集群信息', {\n        confirmButtonText: '确定',\n        cancelButtonText: '取消',\n        type: 'warning'\n      }).then(() => {\n        deleteCanalCluster(row.id).then((res) => {\n          if (res.data === 'success') {\n            this.fetchData()\n            this.$message({\n              message: '删除集群信息成功',\n              type: 'success'\n            })\n          } else {\n            this.$message({\n              message: '删除集群信息失败',\n              type: 'error'\n            })\n          }\n        })\n      })\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "admin/admin-ui/src/views/canalServer/CanalConfig.vue",
    "content": "<template>\n  <div>\n    <el-form ref=\"form\" :model=\"form\">\n      <div style=\"padding-left: 10px;padding-top: 20px;\">\n        <el-form-item>\n          {{ form.name }}&nbsp;&nbsp;&nbsp;&nbsp;\n          <el-button type=\"primary\" @click=\"onSubmit\">保存</el-button>\n          <el-button type=\"warning\" @click=\"onCancel\">重置</el-button>\n          <el-button type=\"success\" @click=\"onLoadTemplate\">载入模板</el-button>\n          <el-button type=\"info\" @click=\"onBack\">返回</el-button>\n        </el-form-item>\n      </div>\n      <editor v-model=\"form.content\" lang=\"properties\" theme=\"chrome\" width=\"100%\" :height=\"800\" @init=\"editorInit\" />\n    </el-form>\n  </div>\n</template>\n\n<script>\nimport { getCanalConfig, updateCanalConfig, getTemplateConfig } from '@/api/canalConfig'\n\nexport default {\n  components: {\n    editor: require('vue2-ace-editor')\n  },\n  data() {\n    return {\n      form: {\n        id: null,\n        name: '',\n        content: '',\n        serverId: null,\n        clusterId: null\n      }\n    }\n  },\n  created() {\n    this.loadCanalConfig()\n  },\n  methods: {\n    editorInit() {\n      require('brace/ext/language_tools')\n      require('brace/mode/html')\n      require('brace/mode/yaml')\n      require('brace/mode/properties')\n      require('brace/mode/javascript')\n      require('brace/mode/less')\n      require('brace/theme/chrome')\n      require('brace/snippets/javascript')\n    },\n    loadCanalConfig() {\n      let clusterId = 0\n      let serverId = 0\n      if (this.$route.query.clusterId) {\n        clusterId = this.$route.query.clusterId\n      } else if (this.$route.query.serverId) {\n        serverId = this.$route.query.serverId\n      }\n      getCanalConfig(clusterId, serverId).then(response => {\n        const data = response.data\n        this.form.id = data.id\n        this.form.name = data.name\n        this.form.content = data.content\n        this.form.serverId = this.$route.query.serverId\n        this.form.clusterId = this.$route.query.clusterId\n      })\n    },\n    onSubmit() {\n      if (this.form.content === null || this.form.content === '') {\n        this.$message({\n          message: '配置内容不能为空',\n          type: 'error'\n        })\n        return\n      }\n      this.$confirm(\n        '修改主配置可能会导致Server重启，是否继续？',\n        '确定修改',\n        {\n          confirmButtonText: '确定',\n          cancelButtonText: '取消',\n          type: 'warning'\n        }\n      ).then(() => {\n        updateCanalConfig(this.form).then(response => {\n          if (response.data === 'success') {\n            this.$message({\n              message: '保存成功',\n              type: 'success'\n            })\n            this.loadCanalConfig()\n          } else {\n            this.$message({\n              message: '保存失败',\n              type: 'error'\n            })\n          }\n        })\n      })\n    },\n    onCancel() {\n      this.loadCanalConfig()\n    },\n    onBack() {\n      history.go(-1)\n    },\n    onLoadTemplate() {\n      getTemplateConfig().then(res => {\n        this.form.content = res.data\n      })\n    }\n  }\n}\n</script>\n\n<style scoped>\n.line{\n  text-align: center;\n}\n</style>\n\n"
  },
  {
    "path": "admin/admin-ui/src/views/canalServer/CanalInstance.vue",
    "content": "<template>\n  <div class=\"app-container\">\n    <div class=\"filter-container\">\n      <el-input v-model=\"listQuery.name\" placeholder=\"Instance 名称\" style=\"width: 200px;\" class=\"filter-item\" />\n      <el-select v-model=\"listQuery.clusterServerId\" placeholder=\"所属集群/主机\" class=\"filter-item\">\n        <el-option key=\"\" label=\"所属集群/主机\" value=\"\" />\n        <el-option-group v-for=\"group in options\" :key=\"group.label\" :label=\"group.label\">\n          <el-option v-for=\"item in group.options\" :key=\"item.value\" :label=\"item.label\" :value=\"item.value\" />\n        </el-option-group>\n      </el-select>\n      <el-button class=\"filter-item\" type=\"primary\" icon=\"el-icon-search\" plain @click=\"queryData()\">查询</el-button>\n      &nbsp;&nbsp;\n      <el-button class=\"filter-item\" type=\"primary\" @click=\"handleCreate()\">新建 Instance</el-button>\n      <el-button class=\"filter-item\" type=\"info\" @click=\"fetchData()\">刷新列表</el-button>\n    </div>\n    <el-table\n      v-loading=\"listLoading\"\n      :data=\"list\"\n      element-loading-text=\"Loading\"\n      border\n      fit\n      highlight-current-row\n    >\n      <el-table-column label=\"Instance 名称\" min-width=\"200\" align=\"center\">\n        <template slot-scope=\"scope\">\n          {{ scope.row.name }}\n        </template>\n      </el-table-column>\n      <el-table-column label=\"所属集群\" min-width=\"200\" align=\"center\">\n        <template slot-scope=\"scope\">\n          <span v-if=\"scope.row.canalCluster !== null\">\n            {{ scope.row.canalCluster.name }}\n          </span>\n          <span v-else>-</span>\n        </template>\n      </el-table-column>\n      <el-table-column label=\"所属主机\" min-width=\"200\" align=\"center\">\n        <template slot-scope=\"scope\">\n          <span v-if=\"scope.row.nodeServer !== null\">\n            {{ scope.row.nodeServer.name }}\n          </span>\n          <span v-else>-</span>\n        </template>\n      </el-table-column>\n      <el-table-column class-name=\"status-col\" label=\"状态\" min-width=\"150\" align=\"center\">\n        <template slot-scope=\"scope\">\n          <el-tag :type=\"scope.row.runningStatus | statusFilter\">{{ scope.row.runningStatus | statusLabel }}</el-tag>\n        </template>\n      </el-table-column>\n      <el-table-column label=\"修改时间\" min-width=\"200\" align=\"center\">\n        <template slot-scope=\"scope\">\n          {{ scope.row.modifiedTime }}\n        </template>\n      </el-table-column>\n      <el-table-column align=\"center\" prop=\"created_at\" label=\"操作\" min-width=\"150\">\n        <template slot-scope=\"scope\">\n          <el-dropdown trigger=\"click\">\n            <el-button type=\"primary\" size=\"mini\">\n              操作<i class=\"el-icon-arrow-down el-icon--right\" />\n            </el-button>\n            <el-dropdown-menu slot=\"dropdown\">\n              <el-dropdown-item @click.native=\"handleUpdate(scope.row)\">修改</el-dropdown-item>\n              <el-dropdown-item @click.native=\"handleDelete(scope.row)\">删除</el-dropdown-item>\n              <el-dropdown-item @click.native=\"handleStart(scope.row)\">启动</el-dropdown-item>\n              <el-dropdown-item @click.native=\"handleStop(scope.row)\">停止</el-dropdown-item>\n              <el-dropdown-item @click.native=\"handleLog(scope.row)\">日志</el-dropdown-item>\n            </el-dropdown-menu>\n          </el-dropdown>\n        </template>\n      </el-table-column>\n    </el-table>\n    <pagination v-show=\"count>0\" :total=\"count\" :page.sync=\"listQuery.page\" :limit.sync=\"listQuery.size\" @pagination=\"fetchData()\" />\n  </div>\n</template>\n\n<script>\nimport { getCanalInstances, deleteCanalInstance, instanceStatus } from '@/api/canalInstance'\nimport Pagination from '@/components/Pagination'\nimport { getClustersAndServers } from '@/api/canalCluster'\n\nexport default {\n  components: { Pagination },\n  filters: {\n    statusFilter(status) {\n      const statusMap = {\n        '1': 'success',\n        '0': 'gray'\n      }\n      return statusMap[status]\n    },\n    statusLabel(status) {\n      const statusMap = {\n        '1': '启动',\n        '0': '停止'\n      }\n      return statusMap[status]\n    }\n  },\n  data() {\n    return {\n      list: null,\n      listLoading: true,\n      dialogFormVisible: false,\n      nodeServices: [],\n      count: 0,\n      options: [],\n      listQuery: {\n        name: '',\n        clusterServerId: '',\n        page: 1,\n        size: 20\n      },\n      currentId: null,\n      rules: {\n        id: [{ required: true, message: '请选择运行Server', trigger: 'change' }]\n      }\n    }\n  },\n  created() {\n    getClustersAndServers().then((res) => {\n      this.options = res.data\n    })\n    this.fetchData()\n  },\n  methods: {\n    queryData() {\n      this.listQuery.page = 1\n      this.fetchData()\n    },\n    fetchData() {\n      this.listLoading = true\n      getCanalInstances(this.listQuery).then(res => {\n        this.list = res.data.items\n        this.count = res.data.count\n      }).finally(() => {\n        this.listLoading = false\n      })\n    },\n    handleCreate() {\n      this.$router.push('/canalServer/canalInstance/add')\n    },\n    handleUpdate(row) {\n      this.$router.push('/canalServer/canalInstance/modify?id=' + row.id)\n    },\n    handleDelete(row) {\n      this.$confirm('删除Instance配置会导致停止', '确定删除Instance信息', {\n        confirmButtonText: '确定',\n        cancelButtonText: '取消',\n        type: 'warning'\n      }).then(() => {\n        deleteCanalInstance(row.id).then((res) => {\n          if (res.data === 'success') {\n            this.fetchData()\n            this.$message({\n              message: '删除Instance信息成功',\n              type: 'success'\n            })\n          } else {\n            this.$message({\n              message: '删除Instance信息失败',\n              type: 'error'\n            })\n          }\n        })\n      })\n    },\n    handleStart(row) {\n      // if (row.runningStatus === '1') {\n      //   this.$message({ message: '当前Instance已处于启动状态！', type: 'error' })\n      //   return\n      // }\n      this.$confirm('启动Instance: ' + row.name, '确定启动Instance服务', {\n        confirmButtonText: '确定',\n        cancelButtonText: '取消',\n        type: 'warning'\n      }).then(() => {\n        instanceStatus(row.id, 'start').then((res) => {\n          if (res.data) {\n            this.fetchData()\n            this.$message({\n              message: '启动成功, 稍后请刷新列表查看状态',\n              type: 'success'\n            })\n          } else {\n            this.$message({\n              message: '启动Instance出现异常',\n              type: 'error'\n            })\n          }\n        })\n      })\n    },\n    handleStop(row) {\n      // if (row.runningStatus === '0') {\n      //   this.$message({ message: '当前Instance已处于停止状态！', type: 'error' })\n      //   return\n      // }\n      this.$confirm('停止Instance: ' + row.name, '确定停止Instance服务', {\n        confirmButtonText: '确定',\n        cancelButtonText: '取消',\n        type: 'warning'\n      }).then(() => {\n        instanceStatus(row.id, 'stop').then((res) => {\n          if (res.data) {\n            this.fetchData()\n            this.$message({\n              message: '停止成功, 稍后请刷新列表查看状态',\n              type: 'success'\n            })\n          } else {\n            this.$message({\n              message: '停止Instance出现异常',\n              type: 'error'\n            })\n          }\n        })\n      })\n    },\n    handleLog(row) {\n      if (row.nodeId === null) {\n        this.$message({ message: '当前Instance不是启动状态，无法查看日志', type: 'warning' })\n        return\n      }\n      this.$router.push('canalInstance/log?id=' + row.id + '&nodeId=' + row.nodeServer.id)\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "admin/admin-ui/src/views/canalServer/CanalInstanceAdd.vue",
    "content": "<template>\n  <div>\n    <el-form ref=\"form\" :model=\"form\">\n      <div class=\"filter-container\" style=\"padding-left: 10px;padding-top: 20px;\">\n        <el-input v-model=\"form.name\" placeholder=\"Instance名称\" style=\"width: 200px;\" class=\"filter-item\" />\n        <el-select v-model=\"form.clusterServerId\" placeholder=\"所属集群/主机\" class=\"filter-item\">\n          <el-option-group v-for=\"group in options\" :key=\"group.label\" :label=\"group.label\">\n            <el-option v-for=\"item in group.options\" :key=\"item.value\" :label=\"item.label\" :value=\"item.value\" />\n          </el-option-group>\n        </el-select>\n        <el-button class=\"filter-item\" type=\"primary\" @click=\"onSubmit\">保存</el-button>\n        <el-button class=\"filter-item\" type=\"success\" @click=\"onLoadTemplate\">载入模板</el-button>\n        <el-button class=\"filter-item\" type=\"info\" @click=\"onBack\">返回</el-button>\n      </div>\n      <editor v-model=\"form.content\" lang=\"properties\" theme=\"chrome\" width=\"100%\" :height=\"800\" @init=\"editorInit\" />\n    </el-form>\n  </div>\n</template>\n\n<script>\nimport { addCanalInstance, getTemplateInstance } from '@/api/canalInstance'\nimport { getClustersAndServers } from '@/api/canalCluster'\n\nexport default {\n  components: {\n    editor: require('vue2-ace-editor')\n  },\n  data() {\n    return {\n      options: [],\n      form: {\n        name: '',\n        content: '',\n        clusterServerId: ''\n      }\n    }\n  },\n  created() {\n    getClustersAndServers().then((res) => {\n      this.options = res.data\n    })\n  },\n  methods: {\n    editorInit() {\n      require('brace/ext/language_tools')\n      require('brace/mode/html')\n      require('brace/mode/yaml')\n      require('brace/mode/properties')\n      require('brace/mode/javascript')\n      require('brace/mode/less')\n      require('brace/theme/chrome')\n      require('brace/snippets/javascript')\n    },\n    onSubmit() {\n      if (this.form.name === '') {\n        this.$message({\n          message: '请输入Instance名称',\n          type: 'error'\n        })\n        return\n      }\n      if (this.form.clusterServerId === '') {\n        this.$message({\n          message: '请选择所属集群/主机',\n          type: 'error'\n        })\n        return\n      }\n      if (this.form.content === null || this.form.content === '') {\n        this.$message({\n          message: '请输入配置内容',\n          type: 'error'\n        })\n        return\n      }\n      this.$confirm(\n        '确定新建',\n        '确定新建',\n        {\n          confirmButtonText: '确定',\n          cancelButtonText: '取消',\n          type: 'warning'\n        }\n      ).then(() => {\n        addCanalInstance(this.form).then(response => {\n          if (response.data === 'success') {\n            this.$message({\n              message: '新建成功',\n              type: 'success'\n            })\n            this.$router.push('/canalServer/canalInstances')\n          } else {\n            this.$message({\n              message: '新建失败',\n              type: 'error'\n            })\n          }\n        })\n      })\n    },\n    onBack() {\n      history.go(-1)\n    },\n    onLoadTemplate() {\n      getTemplateInstance().then(res => {\n        this.form.content = res.data\n      })\n    }\n  }\n}\n</script>\n\n<style scoped>\n.line{\n  text-align: center;\n}\n</style>\n\n"
  },
  {
    "path": "admin/admin-ui/src/views/canalServer/CanalInstanceLogDetail.vue",
    "content": "<template>\n  <div>\n    <el-form ref=\"form\" :model=\"form\">\n      <div style=\"padding-left: 10px;padding-right: 10px;padding-top: 20px;\">\n        <el-form-item>\n          {{ form.instance }}&nbsp;&nbsp;&nbsp;&nbsp;\n          <el-button type=\"primary\" @click=\"onRefresh\">刷新</el-button>\n          <el-button type=\"info\" @click=\"onBack\">返回</el-button>\n        </el-form-item>\n        <el-input v-model=\"form.desc\" :rows=\"35\" :readonly=\"'readonly'\" type=\"textarea\" />\n      </div>\n    </el-form>\n  </div>\n</template>\n\n<script>\nimport { instanceLog } from '@/api/canalInstance'\n\nexport default {\n  data() {\n    return {\n      form: {\n        instance: '',\n        desc: ''\n      }\n    }\n  },\n  created() {\n    this.fetchData()\n  },\n  methods: {\n    fetchData() {\n      instanceLog(this.$route.query.id, this.$route.query.nodeId).then(res => {\n        this.form.instance = res.data.instance + '.log'\n        this.form.desc = res.data.log\n      })\n    },\n    onRefresh() {\n      this.fetchData()\n    },\n    onBack() {\n      history.go(-1)\n    }\n  }\n}\n</script>\n\n<style scoped>\n.line{\n  text-align: center;\n}\n</style>\n\n"
  },
  {
    "path": "admin/admin-ui/src/views/canalServer/CanalInstanceUpdate.vue",
    "content": "<template>\n  <div>\n    <el-form ref=\"form\" :model=\"form\">\n      <div style=\"padding-left: 10px;padding-top: 20px;\">\n        <el-form-item>\n          {{ form.name }}&nbsp;&nbsp;&nbsp;&nbsp;\n          <el-select v-model=\"form.clusterServerId\" placeholder=\"所属集群/主机\" class=\"filter-item\">\n            <el-option-group v-for=\"group in options\" :key=\"group.label\" :label=\"group.label\">\n              <el-option v-for=\"item in group.options\" :key=\"item.value\" :label=\"item.label\" :value=\"item.value\" />\n            </el-option-group>\n          </el-select>\n          <el-button type=\"primary\" @click=\"onSubmit\">修改</el-button>\n          <el-button type=\"warning\" @click=\"onCancel\">重置</el-button>\n          <el-button type=\"info\" @click=\"onBack\">返回</el-button>\n        </el-form-item>\n      </div>\n      <editor v-model=\"form.content\" lang=\"properties\" theme=\"chrome\" width=\"100%\" :height=\"800\" @init=\"editorInit\" />\n    </el-form>\n  </div>\n</template>\n\n<script>\nimport { canalInstanceDetail, updateCanalInstance } from '@/api/canalInstance'\nimport { getClustersAndServers } from '@/api/canalCluster'\n\nexport default {\n  components: {\n    editor: require('vue2-ace-editor')\n  },\n  data() {\n    return {\n      options: [],\n      form: {\n        id: null,\n        name: '',\n        content: '',\n        clusterServerId: ''\n      }\n    }\n  },\n  created() {\n    this.loadCanalConfig()\n    getClustersAndServers().then((res) => {\n      this.options = res.data\n    })\n  },\n  methods: {\n    editorInit() {\n      require('brace/ext/language_tools')\n      require('brace/mode/html')\n      require('brace/mode/yaml')\n      require('brace/mode/properties')\n      require('brace/mode/javascript')\n      require('brace/mode/less')\n      require('brace/theme/chrome')\n      require('brace/snippets/javascript')\n    },\n    loadCanalConfig() {\n      canalInstanceDetail(this.$route.query.id).then(response => {\n        const data = response.data\n        this.form.id = data.id\n        this.form.name = data.name + '/instance.properties'\n        this.form.content = data.content\n        this.form.clusterServerId = data.clusterServerId\n      })\n    },\n    onSubmit() {\n      this.$confirm(\n        '修改Instance配置可能会导致重启，是否继续？',\n        '确定修改',\n        {\n          confirmButtonText: '确定',\n          cancelButtonText: '取消',\n          type: 'warning'\n        }\n      ).then(() => {\n        updateCanalInstance(this.form).then(response => {\n          if (response.data === 'success') {\n            this.$message({\n              message: '修改成功',\n              type: 'success'\n            })\n            this.loadCanalConfig()\n          } else {\n            this.$message({\n              message: '修改失败',\n              type: 'error'\n            })\n          }\n        })\n      })\n    },\n    onCancel() {\n      this.loadCanalConfig()\n    },\n    onBack() {\n      history.go(-1)\n    }\n  }\n}\n</script>\n\n<style scoped>\n.line{\n  text-align: center;\n}\n</style>\n\n"
  },
  {
    "path": "admin/admin-ui/src/views/canalServer/CanalLogDetail.vue",
    "content": "<template>\n  <div>\n    <el-form ref=\"form\" :model=\"form\">\n      <div style=\"padding-left: 10px;padding-right: 10px;padding-top: 20px;\">\n        <el-form-item>\n          canal.log&nbsp;&nbsp;&nbsp;&nbsp;\n          <el-button type=\"primary\" @click=\"onRefresh\">刷新</el-button>\n          <el-button type=\"info\" @click=\"onBack\">返回</el-button>\n        </el-form-item>\n        <el-input v-model=\"form.desc\" :rows=\"35\" :readonly=\"'readonly'\" type=\"textarea\" />\n      </div>\n    </el-form>\n  </div>\n</template>\n\n<script>\nimport { nodeServerLog } from '@/api/nodeServer'\n\nexport default {\n  data() {\n    return {\n      form: {\n        desc: ''\n      }\n    }\n  },\n  created() {\n    this.fetchData()\n  },\n  methods: {\n    fetchData() {\n      nodeServerLog(this.$route.query.id).then(res => {\n        this.form.desc = res.data\n      })\n    },\n    onRefresh() {\n      this.fetchData()\n    },\n    onBack() {\n      history.go(-1)\n    }\n  }\n}\n</script>\n\n<style scoped>\n.line{\n  text-align: center;\n}\n</style>\n\n"
  },
  {
    "path": "admin/admin-ui/src/views/canalServer/NodeServer.vue",
    "content": "<template>\n  <div class=\"app-container\">\n    <div class=\"filter-container\">\n      <!--<el-input v-model=\"listQuery.name\" placeholder=\"Server 名称\" style=\"width: 200px;\" class=\"filter-item\" />-->\n      <el-select v-model=\"listQuery.clusterId\" placeholder=\"所属集群\" class=\"filter-item\">\n        <el-option key=\"\" label=\"所属集群\" value=\"\" />\n        <el-option key=\"-1\" label=\"单机\" value=\"-1\" />\n        <el-option v-for=\"item in canalClusters\" :key=\"item.id\" :label=\"item.name\" :value=\"item.id\" />\n      </el-select>\n      <el-input v-model=\"listQuery.ip\" placeholder=\"Server IP\" style=\"width: 200px;\" class=\"filter-item\" />\n      <el-button class=\"filter-item\" type=\"primary\" icon=\"el-icon-search\" plain @click=\"queryData()\">查询</el-button>\n      <el-button class=\"filter-item\" type=\"primary\" @click=\"handleCreate()\">新建Server</el-button>\n      <el-button class=\"filter-item\" type=\"info\" @click=\"fetchData()\">刷新列表</el-button>\n    </div>\n    <el-table\n      v-loading=\"listLoading\"\n      :data=\"list\"\n      element-loading-text=\"Loading\"\n      border\n      fit\n      highlight-current-row\n    >\n      <el-table-column label=\"所属集群\" min-width=\"200\" align=\"center\">\n        <template slot-scope=\"scope\">\n          <span v-if=\"scope.row.canalCluster !== null\">\n            {{ scope.row.canalCluster.name }}\n          </span>\n          <span v-else>\n            -\n          </span>\n        </template>\n      </el-table-column>\n      <el-table-column label=\"Server 名称\" min-width=\"200\" align=\"center\">\n        <template slot-scope=\"scope\">\n          {{ scope.row.name }}\n        </template>\n      </el-table-column>\n      <el-table-column label=\"Server IP\" min-width=\"200\" align=\"center\">\n        <template slot-scope=\"scope\">\n          <span>{{ scope.row.ip }}</span>\n        </template>\n      </el-table-column>\n      <el-table-column label=\"admin 端口\" min-width=\"100\" align=\"center\">\n        <template slot-scope=\"scope\">\n          {{ scope.row.adminPort }}\n        </template>\n      </el-table-column>\n      <el-table-column label=\"tcp 端口\" min-width=\"100\" align=\"center\">\n        <template slot-scope=\"scope\">\n          {{ scope.row.tcpPort }}\n        </template>\n      </el-table-column>\n      <el-table-column label=\"metric 端口\" min-width=\"100\" align=\"center\">\n        <template slot-scope=\"scope\">\n          {{ scope.row.metricPort }}\n        </template>\n      </el-table-column>\n      <el-table-column class-name=\"status-col\" label=\"状态\" min-width=\"150\" align=\"center\">\n        <template slot-scope=\"scope\">\n          <el-tag :type=\"scope.row.status | statusFilter\">{{ scope.row.status | statusLabel }}</el-tag>\n        </template>\n      </el-table-column>\n      <el-table-column align=\"center\" prop=\"created_at\" label=\"操作\" min-width=\"150\">\n        <template slot-scope=\"scope\">\n          <el-dropdown trigger=\"click\">\n            <el-button type=\"primary\" size=\"mini\">\n              操作<i class=\"el-icon-arrow-down el-icon--right\" />\n            </el-button>\n            <el-dropdown-menu slot=\"dropdown\">\n              <el-dropdown-item @click.native=\"handleConfig(scope.row)\">配置</el-dropdown-item>\n              <el-dropdown-item @click.native=\"handleUpdate(scope.row)\">修改</el-dropdown-item>\n              <el-dropdown-item @click.native=\"handleDelete(scope.row)\">删除</el-dropdown-item>\n              <el-dropdown-item @click.native=\"handleStart(scope.row)\">启动</el-dropdown-item>\n              <el-dropdown-item @click.native=\"handleStop(scope.row)\">停止</el-dropdown-item>\n              <el-dropdown-item @click.native=\"handleInstances(scope.row)\">详情</el-dropdown-item>\n              <el-dropdown-item @click.native=\"handleLog(scope.row)\">日志</el-dropdown-item>\n            </el-dropdown-menu>\n          </el-dropdown>\n        </template>\n      </el-table-column>\n    </el-table>\n    <pagination v-show=\"count>0\" :total=\"count\" :page.sync=\"listQuery.page\" :limit.sync=\"listQuery.size\" @pagination=\"fetchData()\" />\n    <el-dialog :visible.sync=\"dialogFormVisible\" :title=\"textMap[dialogStatus]\" width=\"600px\">\n      <el-form ref=\"dataForm\" :rules=\"rules\" :model=\"nodeModel\" label-position=\"left\" label-width=\"120px\" style=\"width: 400px; margin-left:30px;\">\n        <el-form-item label=\"所属集群\" prop=\"clusterId\">\n          <el-select v-if=\"dialogStatus === 'create'\" v-model=\"nodeModel.clusterId\" placeholder=\"选择所属集群\">\n            <el-option key=\"\" label=\"单机\" value=\"\" />\n            <el-option v-for=\"item in canalClusters\" :key=\"item.id\" :label=\"item.name\" :value=\"item.id\" />\n          </el-select>\n          <el-select v-else v-model=\"nodeModel.clusterId\" placeholder=\"选择所属集群\" disabled=\"disabled\">\n            <el-option key=\"\" label=\"单机\" value=\"\" />\n            <el-option v-for=\"item in canalClusters\" :key=\"item.id\" :label=\"item.name\" :value=\"item.id\" />\n          </el-select>\n        </el-form-item>\n        <el-form-item label=\"Server 名称\" prop=\"name\">\n          <el-input v-model=\"nodeModel.name\" />\n        </el-form-item>\n        <el-form-item label=\"Server IP\" prop=\"ip\">\n          <el-input v-model=\"nodeModel.ip\" />\n        </el-form-item>\n        <el-form-item label=\"admin 端口\" prop=\"adminPort\">\n          <el-input v-model=\"nodeModel.adminPort\" placeholder=\"11110\" type=\"number\" />\n        </el-form-item>\n        <el-form-item label=\"tcp 端口\" prop=\"tcpPort\">\n          <el-input v-model=\"nodeModel.tcpPort\" placeholder=\"11111\" type=\"number\" />\n        </el-form-item>\n        <el-form-item label=\"metric 端口\" prop=\"metricPort\">\n          <el-input v-model=\"nodeModel.metricPort\" placeholder=\"11112\" type=\"number\" />\n        </el-form-item>\n      </el-form>\n      <div slot=\"footer\" class=\"dialog-footer\">\n        <el-button @click=\"dialogFormVisible = false\">取消</el-button>\n        <el-button type=\"primary\" @click=\"dataOperation()\">确定</el-button>\n      </div>\n    </el-dialog>\n    <el-dialog :visible.sync=\"dialogInstances\" title=\"instance 列表\" width=\"800px\">\n      <div class=\"filter-container\">\n        <el-button class=\"filter-item\" type=\"info\" @click=\"activeInstances()\">刷新列表</el-button>\n      </div>\n      <el-table\n        v-loading=\"listLoading2\"\n        :data=\"instanceList\"\n        element-loading-text=\"Loading\"\n        border\n        fit\n        highlight-current-row\n      >\n        <el-table-column label=\"Instance 名称\" min-width=\"200\" align=\"center\">\n          <template slot-scope=\"scope\">\n            {{ scope.row.name }}\n          </template>\n        </el-table-column>\n        <el-table-column label=\"状态\" min-width=\"200\" align=\"center\">\n          <template slot-scope=\"scope\">\n            <el-tag :type=\"scope.row.runningStatus | statusFilter\">{{ scope.row.runningStatus | statusLabel }}</el-tag>\n          </template>\n        </el-table-column>\n        <el-table-column label=\"操作\" min-width=\"200\" align=\"center\">\n          <template slot-scope=\"scope\">\n            <el-dropdown trigger=\"click\">\n              <el-button type=\"primary\" size=\"mini\">\n                操作<i class=\"el-icon-arrow-down el-icon--right\" />\n              </el-button>\n              <el-dropdown-menu slot=\"dropdown\">\n                <el-dropdown-item @click.native=\"handleStartInstance(scope.row)\">启动</el-dropdown-item>\n                <el-dropdown-item @click.native=\"handleStopInstance(scope.row)\">停止</el-dropdown-item>\n              </el-dropdown-menu>\n            </el-dropdown>\n          </template>\n        </el-table-column>\n      </el-table>\n    </el-dialog>\n  </div>\n</template>\n\n<script>\nimport { addNodeServer, getNodeServers, updateNodeServer, deleteNodeServer, startNodeServer, stopNodeServer } from '@/api/nodeServer'\nimport { getActiveInstances, stopInstance, startInstance } from '@/api/canalInstance'\nimport { getCanalClusters } from '@/api/canalCluster'\nimport Pagination from '@/components/Pagination'\n\nexport default {\n  components: { Pagination },\n  filters: {\n    statusFilter(status) {\n      const statusMap = {\n        '1': 'success',\n        '0': 'gray',\n        '-1': 'danger'\n      }\n      return statusMap[status]\n    },\n    statusLabel(status) {\n      const statusMap = {\n        '1': '启动',\n        '0': '停止',\n        '-1': '断开'\n      }\n      return statusMap[status]\n    }\n  },\n  data() {\n    return {\n      list: null,\n      instanceList: null,\n      listLoading: true,\n      listLoading2: true,\n      serverIdTmp: null,\n      canalClusters: [],\n      count: 0,\n      listQuery: {\n        name: '',\n        ip: '',\n        clusterId: null,\n        page: 1,\n        size: 20\n      },\n      dialogFormVisible: false,\n      dialogInstances: false,\n      textMap: {\n        create: '新建Server信息',\n        update: '修改Server信息'\n      },\n      nodeModel: {\n        id: undefined,\n        clusterId: null,\n        name: null,\n        ip: null,\n        adminPort: 11110,\n        tcpPort: 11111,\n        metricPort: 11112\n      },\n      rules: {\n        name: [{ required: true, message: 'Server 名称不能为空', trigger: 'change' }],\n        ip: [{ required: true, message: 'Server IP不能为空', trigger: 'change' }],\n        adminPort: [{ required: true, message: 'Server admin端口不能为空', trigger: 'change' }]\n      },\n      dialogStatus: 'create'\n    }\n  },\n  // { min: 2, max: 5, message: '长度在 2 到 5 个字符', trigger: 'change' }\n  created() {\n    getCanalClusters().then((res) => {\n      this.canalClusters = res.data\n    })\n    if (this.$route.query.clusterId) {\n      try {\n        this.listQuery.clusterId = Number(this.$route.query.clusterId)\n      } catch (e) {\n        console.log(e)\n      }\n    }\n    this.fetchData()\n  },\n  methods: {\n    fetchData() {\n      this.listLoading = true\n      getNodeServers(this.listQuery).then(res => {\n        this.list = res.data.items\n        this.count = res.data.count\n      }).finally(() => {\n        this.listLoading = false\n      })\n    },\n    queryData() {\n      this.listQuery.page = 1\n      this.fetchData()\n    },\n    resetModel() {\n      this.nodeModel = {\n        id: undefined,\n        clusterId: null,\n        name: null,\n        ip: null,\n        adminPort: null,\n        tcpPort: null,\n        metricPort: null\n      }\n    },\n    handleCreate() {\n      this.resetModel()\n      this.dialogStatus = 'create'\n      this.dialogFormVisible = true\n      this.$nextTick(() => {\n        this.$refs['dataForm'].clearValidate()\n      })\n    },\n    handleInstances(row) {\n      this.serverIdTmp = row.id\n      this.activeInstances()\n    },\n    activeInstances() {\n      this.listLoading2 = true\n      this.dialogInstances = true\n      getActiveInstances(this.serverIdTmp).then(res => {\n        this.instanceList = res.data\n      }).finally(() => {\n        this.listLoading2 = false\n      })\n    },\n    dataOperation() {\n      this.$refs['dataForm'].validate((valid) => {\n        if (valid) {\n          if (this.dialogStatus === 'create') {\n            addNodeServer(this.nodeModel).then(res => {\n              this.operationRes(res)\n            })\n          }\n          if (this.dialogStatus === 'update') {\n            updateNodeServer(this.nodeModel).then(res => {\n              this.operationRes(res)\n            })\n          }\n        }\n      })\n    },\n    operationRes(res) {\n      if (res.data === 'success') {\n        this.fetchData()\n        this.dialogFormVisible = false\n        this.$message({\n          message: this.textMap[this.dialogStatus] + '成功',\n          type: 'success'\n        })\n      } else {\n        this.$message({\n          message: this.textMap[this.dialogStatus] + '失败',\n          type: 'error'\n        })\n      }\n    },\n    handleConfig(row) {\n      if (row.canalCluster !== null) {\n        this.$message({ message: '集群模式Server不允许单独变更配置，请在集群配置变更', type: 'error' })\n        return\n      }\n      this.$router.push('/canalServer/nodeServer/config?serverId=' + row.id)\n    },\n    handleUpdate(row) {\n      this.resetModel()\n      this.nodeModel = Object.assign({}, row)\n      this.dialogStatus = 'update'\n      this.dialogFormVisible = true\n      this.$nextTick(() => {\n        this.$refs['dataForm'].clearValidate()\n      })\n    },\n    handleDelete(row) {\n      this.$confirm('删除Server信息会导致节点服务停止', '确定删除Server信息', {\n        confirmButtonText: '确定',\n        cancelButtonText: '取消',\n        type: 'warning'\n      }).then(() => {\n        deleteNodeServer(row.id).then((res) => {\n          if (res.data === 'success') {\n            this.fetchData()\n            this.$message({\n              message: '删除Server信息成功',\n              type: 'success'\n            })\n          } else {\n            this.$message({\n              message: '删除Server信息失败',\n              type: 'error'\n            })\n          }\n        })\n      })\n    },\n    handleStart(row) {\n      if (row.status !== '0') {\n        this.$message({ message: '当前Server不是停止状态，无法启动', type: 'error' })\n        return\n      }\n      this.$confirm('启动Server服务', '确定启动Server服务', {\n        confirmButtonText: '确定',\n        cancelButtonText: '取消',\n        type: 'warning'\n      }).then(() => {\n        startNodeServer(row.id).then((res) => {\n          if (res.data) {\n            this.fetchData()\n            this.$message({\n              message: '启动成功',\n              type: 'success'\n            })\n          } else {\n            this.$message({\n              message: '启动Server服务出现异常',\n              type: 'error'\n            })\n          }\n        })\n      })\n    },\n    handleStop(row) {\n      if (row.status !== '1') {\n        this.$message({ message: '当前Server不是启动状态，无法停止', type: 'error' })\n        return\n      }\n      this.$confirm('停止Server服务会导致所有Instance都停止服务', '确定停止Server服务', {\n        confirmButtonText: '确定',\n        cancelButtonText: '取消',\n        type: 'warning'\n      }).then(() => {\n        stopNodeServer(row.id).then((res) => {\n          if (res.data) {\n            this.fetchData()\n            this.$message({\n              message: '停止成功',\n              type: 'success'\n            })\n          } else {\n            this.$message({\n              message: '停止Server服务出现异常',\n              type: 'error'\n            })\n          }\n        })\n      })\n    },\n    handleLog(row) {\n      this.$router.push('nodeServer/log?id=' + row.id)\n    },\n    handleStartInstance(row) {\n      if (row.runningStatus !== '0') {\n        this.$message({ message: '当前Instance不是停止状态，无法启动', type: 'error' })\n        return\n      }\n      this.$confirm('启动Instance服务', '确定启动Instance服务', {\n        confirmButtonText: '确定',\n        cancelButtonText: '取消',\n        type: 'warning'\n      }).then(() => {\n        startInstance(row.id, this.serverIdTmp).then((res) => {\n          if (res.data) {\n            this.activeInstances()\n            this.$message({\n              message: '启动成功, 稍后请刷新列表查看状态',\n              type: 'success'\n            })\n          } else {\n            this.$message({\n              message: '启动Instance服务出现异常',\n              type: 'error'\n            })\n          }\n        })\n      })\n    },\n    handleStopInstance(row) {\n      if (row.runningStatus !== '1') {\n        this.$message({ message: '当前Instance不是运行状态，无法停止', type: 'error' })\n        return\n      }\n      this.$confirm('集群模式下停止实例其它主机将会抢占执行该实例', '停止 Instance 服务', {\n        confirmButtonText: '确定',\n        cancelButtonText: '取消',\n        type: 'warning'\n      }).then(() => {\n        stopInstance(row.id, this.serverIdTmp).then((res) => {\n          if (res.data) {\n            this.activeInstances()\n            this.$message({\n              message: '停止成功, 稍后请刷新列表查看状态',\n              type: 'success'\n            })\n          } else {\n            this.$message({\n              message: '停止Instance服务出现异常',\n              type: 'error'\n            })\n          }\n        })\n      })\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "admin/admin-ui/src/views/dashboard/index.vue",
    "content": "<template>\n  <div class=\"dashboard-container\">\n    <div class=\"dashboard-text\">&nbsp;</div>\n  </div>\n</template>\n\n<script>\nimport { mapGetters } from 'vuex'\n\nexport default {\n  name: 'Dashboard',\n  computed: {\n    ...mapGetters([\n      'name'\n    ])\n  },\n  mounted() {\n    this.$router.push('/canalServer')\n  }\n}\n</script>\n\n<style lang=\"scss\" scoped>\n.dashboard {\n  &-container {\n    margin: 30px;\n  }\n  &-text {\n    font-size: 30px;\n    line-height: 46px;\n  }\n}\n</style>\n"
  },
  {
    "path": "admin/admin-ui/src/views/login/index.vue",
    "content": "<template>\n  <div class=\"login-container\">\n    <el-form ref=\"loginForm\" :model=\"loginForm\" :rules=\"loginRules\" class=\"login-form\" auto-complete=\"on\" label-position=\"left\">\n\n      <div class=\"title-container\">\n        <h3 class=\"title\">Canal Admin Login</h3>\n      </div>\n\n      <el-form-item prop=\"username\">\n        <span class=\"svg-container\">\n          <svg-icon icon-class=\"user\" />\n        </span>\n        <el-input\n          ref=\"username\"\n          v-model=\"loginForm.username\"\n          placeholder=\"Username\"\n          name=\"username\"\n          type=\"text\"\n          tabindex=\"1\"\n          auto-complete=\"on\"\n        />\n      </el-form-item>\n\n      <el-form-item prop=\"password\">\n        <span class=\"svg-container\">\n          <svg-icon icon-class=\"password\" />\n        </span>\n        <el-input\n          :key=\"passwordType\"\n          ref=\"password\"\n          v-model=\"loginForm.password\"\n          :type=\"passwordType\"\n          placeholder=\"Password\"\n          name=\"password\"\n          tabindex=\"2\"\n          auto-complete=\"on\"\n          @keyup.enter.native=\"handleLogin\"\n        />\n        <span class=\"show-pwd\" @click=\"showPwd\">\n          <svg-icon :icon-class=\"passwordType === 'password' ? 'eye' : 'eye-open'\" />\n        </span>\n      </el-form-item>\n\n      <el-button :loading=\"loading\" type=\"primary\" style=\"width:100%;margin-bottom:30px;\" @click.native.prevent=\"handleLogin\">Login</el-button>\n\n      <div class=\"tips\">\n        <!-- <span style=\"margin-right:20px;\">username: admin</span>\n        <span> password: any</span> -->\n      </div>\n\n    </el-form>\n  </div>\n</template>\n\n<script>\nimport { validUsername } from '@/utils/validate'\n\nexport default {\n  name: 'Login',\n  data() {\n    const validateUsername = (rule, value, callback) => {\n      if (!validUsername(value)) {\n        callback(new Error('Please enter the correct user name'))\n      } else {\n        callback()\n      }\n    }\n    const validatePassword = (rule, value, callback) => {\n      if (value.length < 5) {\n        callback(new Error('The password can not be less than 5 digits'))\n      } else {\n        callback()\n      }\n    }\n    return {\n      loginForm: {\n        username: '',\n        password: ''\n      },\n      loginRules: {\n        username: [{ required: true, trigger: 'blur', validator: validateUsername }],\n        password: [{ required: true, trigger: 'blur', validator: validatePassword }]\n      },\n      loading: false,\n      passwordType: 'password',\n      redirect: undefined\n    }\n  },\n  watch: {\n    $route: {\n      handler: function(route) {\n        this.redirect = route.query && route.query.redirect\n      },\n      immediate: true\n    }\n  },\n  methods: {\n    showPwd() {\n      if (this.passwordType === 'password') {\n        this.passwordType = ''\n      } else {\n        this.passwordType = 'password'\n      }\n      this.$nextTick(() => {\n        this.$refs.password.focus()\n      })\n    },\n    handleLogin() {\n      this.$refs.loginForm.validate(valid => {\n        if (valid) {\n          this.loading = true\n          this.$store.dispatch('user/login', this.loginForm).then(() => {\n            this.$router.push({ path: this.redirect || '/' })\n            this.loading = false\n          }).catch(() => {\n            this.loading = false\n          })\n        } else {\n          console.log('error submit!!')\n          return false\n        }\n      })\n    }\n  }\n}\n</script>\n\n<style lang=\"scss\">\n/* 修复input 背景不协调 和光标变色 */\n/* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */\n\n$bg:#283443;\n$light_gray:#fff;\n$cursor: #fff;\n\n@supports (-webkit-mask: none) and (not (cater-color: $cursor)) {\n  .login-container .el-input input {\n    color: $cursor;\n  }\n}\n\n/* reset element-ui css */\n.login-container {\n  .el-input {\n    display: inline-block;\n    height: 47px;\n    width: 85%;\n\n    input {\n      background: transparent;\n      border: 0px;\n      -webkit-appearance: none;\n      border-radius: 0px;\n      padding: 12px 5px 12px 15px;\n      color: $light_gray;\n      height: 47px;\n      caret-color: $cursor;\n\n      &:-webkit-autofill {\n        box-shadow: 0 0 0px 1000px $bg inset !important;\n        -webkit-text-fill-color: $cursor !important;\n      }\n    }\n  }\n\n  .el-form-item {\n    border: 1px solid rgba(255, 255, 255, 0.1);\n    background: rgba(0, 0, 0, 0.1);\n    border-radius: 5px;\n    color: #454545;\n  }\n}\n</style>\n\n<style lang=\"scss\" scoped>\n$bg:#2d3a4b;\n$dark_gray:#889aa4;\n$light_gray:#eee;\n\n.login-container {\n  min-height: 100%;\n  width: 100%;\n  background-color: $bg;\n  overflow: hidden;\n\n  .login-form {\n    position: relative;\n    width: 520px;\n    max-width: 100%;\n    padding: 160px 35px 0;\n    margin: 0 auto;\n    overflow: hidden;\n  }\n\n  .tips {\n    font-size: 14px;\n    color: #fff;\n    margin-bottom: 10px;\n\n    span {\n      &:first-of-type {\n        margin-right: 16px;\n      }\n    }\n  }\n\n  .svg-container {\n    padding: 6px 5px 6px 15px;\n    color: $dark_gray;\n    vertical-align: middle;\n    width: 30px;\n    display: inline-block;\n  }\n\n  .title-container {\n    position: relative;\n\n    .title {\n      font-size: 26px;\n      color: $light_gray;\n      margin: 0px auto 40px auto;\n      text-align: center;\n      font-weight: bold;\n    }\n  }\n\n  .show-pwd {\n    position: absolute;\n    right: 10px;\n    top: 7px;\n    font-size: 16px;\n    color: $dark_gray;\n    cursor: pointer;\n    user-select: none;\n  }\n}\n</style>\n"
  },
  {
    "path": "admin/admin-ui/src/views/sys/UserInfo.vue",
    "content": "<template>\n  <div class=\"app-container\" style=\"width: 600px;\">\n    <el-form ref=\"form\" :rules=\"rules\" :model=\"form\" label-width=\"120px\">\n      <el-form-item label=\"用户名\" prop=\"username\">\n        <el-input v-model=\"form.username\" style=\"width: 200px;\" />\n      </el-form-item>\n      <el-form-item label=\"旧密码\" prop=\"oldPassword\">\n        <el-input v-model=\"form.oldPassword\" type=\"password\" style=\"width: 200px;\" />\n      </el-form-item>\n      <el-form-item label=\"密码\" prop=\"password\">\n        <el-input v-model=\"form.password\" placeholder=\"空为不修改密码\" type=\"password\" style=\"width: 200px;\" />\n      </el-form-item>\n      <el-form-item>\n        <el-button type=\"primary\" @click=\"onSubmit\">修改</el-button>\n        <el-button @click=\"onCancel\">取消</el-button>\n      </el-form-item>\n    </el-form>\n  </div>\n</template>\n\n<script>\nimport { getInfo, updateUser } from '@/api/user'\nimport { getToken } from '@/utils/auth'\n\nexport default {\n  data() {\n    return {\n      form: {\n        username: '',\n        oldPassword: '',\n        password: null\n      },\n      rules: {\n        username: [{ required: true, message: '用户名能为空', trigger: 'change' }],\n        oldPassword: [{ required: true, message: '旧密码不能为空', trigger: 'change' }]\n      }\n    }\n  },\n  created() {\n    this.fetchUserInfo()\n  },\n  methods: {\n    fetchUserInfo() {\n      getInfo(getToken()).then(res => {\n        this.form.username = res.data.username\n      })\n    },\n    onSubmit() {\n      this.$refs['form'].validate((valid) => {\n        if (valid) {\n          updateUser(this.form).then(res => {\n            if (res.data === 'success') {\n              this.form.oldPassword = ''\n              this.form.password = null\n              this.$nextTick(() => {\n                this.$refs['form'].clearValidate()\n              })\n              this.$message({\n                message: '修改用户信息成功',\n                type: 'success'\n              })\n            } else {\n              this.$message({\n                message: '修改用户信息成功',\n                type: 'error'\n              })\n            }\n          })\n        }\n      })\n    },\n    onCancel() {\n      history.go(-1)\n    }\n  }\n}\n</script>\n\n<style scoped>\n.line{\n  text-align: center;\n}\n</style>\n\n"
  },
  {
    "path": "admin/admin-ui/tests/unit/.eslintrc.js",
    "content": "module.exports = {\n  env: {\n    jest: true\n  }\n}\n"
  },
  {
    "path": "admin/admin-ui/tests/unit/components/Breadcrumb.spec.js",
    "content": "import { mount, createLocalVue } from '@vue/test-utils'\nimport VueRouter from 'vue-router'\nimport ElementUI from 'element-ui'\nimport Breadcrumb from '@/components/Breadcrumb/index.vue'\n\nconst localVue = createLocalVue()\nlocalVue.use(VueRouter)\nlocalVue.use(ElementUI)\n\nconst routes = [\n  {\n    path: '/',\n    name: 'home',\n    children: [{\n      path: 'dashboard',\n      name: 'dashboard'\n    }]\n  },\n  {\n    path: '/menu',\n    name: 'menu',\n    children: [{\n      path: 'menu1',\n      name: 'menu1',\n      meta: { title: 'menu1' },\n      children: [{\n        path: 'menu1-1',\n        name: 'menu1-1',\n        meta: { title: 'menu1-1' }\n      },\n      {\n        path: 'menu1-2',\n        name: 'menu1-2',\n        redirect: 'noredirect',\n        meta: { title: 'menu1-2' },\n        children: [{\n          path: 'menu1-2-1',\n          name: 'menu1-2-1',\n          meta: { title: 'menu1-2-1' }\n        },\n        {\n          path: 'menu1-2-2',\n          name: 'menu1-2-2'\n        }]\n      }]\n    }]\n  }]\n\nconst router = new VueRouter({\n  routes\n})\n\ndescribe('Breadcrumb.vue', () => {\n  const wrapper = mount(Breadcrumb, {\n    localVue,\n    router\n  })\n  it('dashboard', () => {\n    router.push('/dashboard')\n    const len = wrapper.findAll('.el-breadcrumb__inner').length\n    expect(len).toBe(1)\n  })\n  it('normal route', () => {\n    router.push('/menu/menu1')\n    const len = wrapper.findAll('.el-breadcrumb__inner').length\n    expect(len).toBe(2)\n  })\n  it('nested route', () => {\n    router.push('/menu/menu1/menu1-2/menu1-2-1')\n    const len = wrapper.findAll('.el-breadcrumb__inner').length\n    expect(len).toBe(4)\n  })\n  it('no meta.title', () => {\n    router.push('/menu/menu1/menu1-2/menu1-2-2')\n    const len = wrapper.findAll('.el-breadcrumb__inner').length\n    expect(len).toBe(3)\n  })\n  // it('click link', () => {\n  //   router.push('/menu/menu1/menu1-2/menu1-2-2')\n  //   const breadcrumbArray = wrapper.findAll('.el-breadcrumb__inner')\n  //   const second = breadcrumbArray.at(1)\n  //   console.log(breadcrumbArray)\n  //   const href = second.find('a').attributes().href\n  //   expect(href).toBe('#/menu/menu1')\n  // })\n  // it('noRedirect', () => {\n  //   router.push('/menu/menu1/menu1-2/menu1-2-1')\n  //   const breadcrumbArray = wrapper.findAll('.el-breadcrumb__inner')\n  //   const redirectBreadcrumb = breadcrumbArray.at(2)\n  //   expect(redirectBreadcrumb.contains('a')).toBe(false)\n  // })\n  it('last breadcrumb', () => {\n    router.push('/menu/menu1/menu1-2/menu1-2-1')\n    const breadcrumbArray = wrapper.findAll('.el-breadcrumb__inner')\n    const redirectBreadcrumb = breadcrumbArray.at(3)\n    expect(redirectBreadcrumb.contains('a')).toBe(false)\n  })\n})\n"
  },
  {
    "path": "admin/admin-ui/tests/unit/components/Hamburger.spec.js",
    "content": "import { shallowMount } from '@vue/test-utils'\nimport Hamburger from '@/components/Hamburger/index.vue'\ndescribe('Hamburger.vue', () => {\n  it('toggle click', () => {\n    const wrapper = shallowMount(Hamburger)\n    const mockFn = jest.fn()\n    wrapper.vm.$on('toggleClick', mockFn)\n    wrapper.find('.hamburger').trigger('click')\n    expect(mockFn).toBeCalled()\n  })\n  it('prop isActive', () => {\n    const wrapper = shallowMount(Hamburger)\n    wrapper.setProps({ isActive: true })\n    expect(wrapper.contains('.is-active')).toBe(true)\n    wrapper.setProps({ isActive: false })\n    expect(wrapper.contains('.is-active')).toBe(false)\n  })\n})\n"
  },
  {
    "path": "admin/admin-ui/tests/unit/components/SvgIcon.spec.js",
    "content": "import { shallowMount } from '@vue/test-utils'\nimport SvgIcon from '@/components/SvgIcon/index.vue'\ndescribe('SvgIcon.vue', () => {\n  it('iconClass', () => {\n    const wrapper = shallowMount(SvgIcon, {\n      propsData: {\n        iconClass: 'test'\n      }\n    })\n    expect(wrapper.find('use').attributes().href).toBe('#icon-test')\n  })\n  it('className', () => {\n    const wrapper = shallowMount(SvgIcon, {\n      propsData: {\n        iconClass: 'test'\n      }\n    })\n    expect(wrapper.classes().length).toBe(1)\n    wrapper.setProps({ className: 'test' })\n    expect(wrapper.classes().includes('test')).toBe(true)\n  })\n})\n"
  },
  {
    "path": "admin/admin-ui/tests/unit/utils/formatTime.spec.js",
    "content": "import { formatTime } from '@/utils/index.js'\n\ndescribe('Utils:formatTime', () => {\n  const d = new Date('2018-07-13 17:54:01') // \"2018-07-13 17:54:01\"\n  const retrofit = 5 * 1000\n\n  it('ten digits timestamp', () => {\n    expect(formatTime((d / 1000).toFixed(0))).toBe('7月13日17时54分')\n  })\n  it('test now', () => {\n    expect(formatTime(+new Date() - 1)).toBe('刚刚')\n  })\n  it('less two minute', () => {\n    expect(formatTime(+new Date() - 60 * 2 * 1000 + retrofit)).toBe('2分钟前')\n  })\n  it('less two hour', () => {\n    expect(formatTime(+new Date() - 60 * 60 * 2 * 1000 + retrofit)).toBe('2小时前')\n  })\n  it('less one day', () => {\n    expect(formatTime(+new Date() - 60 * 60 * 24 * 1 * 1000)).toBe('1天前')\n  })\n  it('more than one day', () => {\n    expect(formatTime(d)).toBe('7月13日17时54分')\n  })\n  it('format', () => {\n    expect(formatTime(d, '{y}-{m}-{d} {h}:{i}')).toBe('2018-07-13 17:54')\n    expect(formatTime(d, '{y}-{m}-{d}')).toBe('2018-07-13')\n    expect(formatTime(d, '{y}/{m}/{d} {h}-{i}')).toBe('2018/07/13 17-54')\n  })\n})\n"
  },
  {
    "path": "admin/admin-ui/tests/unit/utils/parseTime.spec.js",
    "content": "import { parseTime } from '@/utils/index.js'\n\ndescribe('Utils:parseTime', () => {\n  const d = new Date('2018-07-13 17:54:01') // \"2018-07-13 17:54:01\"\n  it('timestamp', () => {\n    expect(parseTime(d)).toBe('2018-07-13 17:54:01')\n  })\n  it('ten digits timestamp', () => {\n    expect(parseTime((d / 1000).toFixed(0))).toBe('2018-07-13 17:54:01')\n  })\n  it('new Date', () => {\n    expect(parseTime(new Date(d))).toBe('2018-07-13 17:54:01')\n  })\n  it('format', () => {\n    expect(parseTime(d, '{y}-{m}-{d} {h}:{i}')).toBe('2018-07-13 17:54')\n    expect(parseTime(d, '{y}-{m}-{d}')).toBe('2018-07-13')\n    expect(parseTime(d, '{y}/{m}/{d} {h}-{i}')).toBe('2018/07/13 17-54')\n  })\n  it('get the day of the week', () => {\n    expect(parseTime(d, '{a}')).toBe('五') // 星期五\n  })\n  it('get the day of the week', () => {\n    expect(parseTime(+d + 1000 * 60 * 60 * 24 * 2, '{a}')).toBe('日') // 星期日\n  })\n  it('empty argument', () => {\n    expect(parseTime()).toBeNull()\n  })\n})\n"
  },
  {
    "path": "admin/admin-ui/tests/unit/utils/validate.spec.js",
    "content": "import { validUsername, isExternal } from '@/utils/validate.js'\n\ndescribe('Utils:validate', () => {\n  it('validUsername', () => {\n    expect(validUsername('admin')).toBe(true)\n    expect(validUsername('editor')).toBe(true)\n    expect(validUsername('xxxx')).toBe(false)\n  })\n  it('isExternal', () => {\n    expect(isExternal('https://github.com/PanJiaChen/vue-element-admin')).toBe(true)\n    expect(isExternal('http://github.com/PanJiaChen/vue-element-admin')).toBe(true)\n    expect(isExternal('github.com/PanJiaChen/vue-element-admin')).toBe(false)\n    expect(isExternal('/dashboard')).toBe(false)\n    expect(isExternal('./dashboard')).toBe(false)\n    expect(isExternal('dashboard')).toBe(false)\n  })\n})\n"
  },
  {
    "path": "admin/admin-ui/vue.config.js",
    "content": "'use strict'\nconst path = require('path')\nconst defaultSettings = require('./src/settings.js')\n\nfunction resolve(dir) {\n  return path.join(__dirname, dir)\n}\n\nconst name = defaultSettings.title || 'vue Admin Template' // page title\n\n// If your port is set to 80,\n// use administrator privileges to execute the command line.\n// For example, Mac: sudo npm run\n// You can change the port by the following methods:\n// port = 9528 npm run dev OR npm run dev --port = 9528\nconst port = process.env.port || process.env.npm_config_port || 9528 // dev port\n\n// All configuration item explanations can be find in https://cli.vuejs.org/config/\nmodule.exports = {\n  /**\n   * You will need to set publicPath if you plan to deploy your site under a sub path,\n   * for example GitHub Pages. If you plan to deploy your site to https://foo.github.io/bar/,\n   * then publicPath should be set to \"/bar/\".\n   * In most cases please use '/' !!!\n   * Detail: https://cli.vuejs.org/config/#publicpath\n   */\n  publicPath: '/',\n  outputDir: 'target/dist',\n  assetsDir: 'static',\n  lintOnSave: process.env.NODE_ENV === 'development',\n  productionSourceMap: false,\n  devServer: {\n    port: port,\n    open: true,\n    overlay: {\n      warnings: false,\n      errors: true\n    },\n    proxy: {\n      // change xxx-api/login => mock/login\n      // detail: https://cli.vuejs.org/config/#devserver-proxy\n      [process.env.VUE_APP_BASE_API]: {\n        target: `http://127.0.0.1:${port}/mock`,\n        changeOrigin: true,\n        pathRewrite: {\n          ['^' + process.env.VUE_APP_BASE_API]: ''\n        }\n      }\n    },\n    after: require('./mock/mock-server.js')\n  },\n  configureWebpack: {\n    // provide the app's title in webpack's name field, so that\n    // it can be accessed in index.html to inject the correct title.\n    name: name,\n    resolve: {\n      alias: {\n        '@': resolve('src')\n      }\n    }\n  },\n  chainWebpack(config) {\n    config.plugins.delete('preload') // TODO: need test\n    config.plugins.delete('prefetch') // TODO: need test\n\n    // set svg-sprite-loader\n    config.module\n      .rule('svg')\n      .exclude.add(resolve('src/icons'))\n      .end()\n    config.module\n      .rule('icons')\n      .test(/\\.svg$/)\n      .include.add(resolve('src/icons'))\n      .end()\n      .use('svg-sprite-loader')\n      .loader('svg-sprite-loader')\n      .options({\n        symbolId: 'icon-[name]'\n      })\n      .end()\n\n    // set preserveWhitespace\n    config.module\n      .rule('vue')\n      .use('vue-loader')\n      .loader('vue-loader')\n      .tap(options => {\n        options.compilerOptions.preserveWhitespace = true\n        return options\n      })\n      .end()\n\n    config\n    // https://webpack.js.org/configuration/devtool/#development\n      .when(process.env.NODE_ENV === 'development',\n        config => config.devtool('cheap-source-map')\n      )\n\n    config\n      .when(process.env.NODE_ENV !== 'development',\n        config => {\n          config\n            .plugin('ScriptExtHtmlWebpackPlugin')\n            .after('html')\n            .use('script-ext-html-webpack-plugin', [{\n            // `runtime` must same as runtimeChunk name. default is `runtime`\n              inline: /runtime\\..*\\.js$/\n            }])\n            .end()\n          config\n            .optimization.splitChunks({\n              chunks: 'all',\n              cacheGroups: {\n                libs: {\n                  name: 'chunk-libs',\n                  test: /[\\\\/]node_modules[\\\\/]/,\n                  priority: 10,\n                  chunks: 'initial' // only package third parties that are initially dependent\n                },\n                elementUI: {\n                  name: 'chunk-elementUI', // split elementUI into a single package\n                  priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app\n                  test: /[\\\\/]node_modules[\\\\/]_?element-ui(.*)/ // in order to adapt to cnpm\n                },\n                commons: {\n                  name: 'chunk-commons',\n                  test: resolve('src/components'), // can customize your rules\n                  minChunks: 3, //  minimum common number\n                  priority: 5,\n                  reuseExistingChunk: true\n                }\n              }\n            })\n          config.optimization.runtimeChunk('single')\n        }\n      )\n  }\n}\n"
  },
  {
    "path": "admin/admin-web/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>canal.admin</artifactId>\n        <groupId>com.alibaba.otter</groupId>\n        <version>1.1.9-SNAPSHOT</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n    <artifactId>canal.admin-web</artifactId>\n    <name>canal admin-web for otter ${project.version}</name>\n    <dependencies>\n    \t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.protocol</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-jdbc</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <!-- 支持arm64需要mysql 8.0,升级为8.0的新版驱动 -->\n            <version>8.0.33</version>\n        </dependency>\n        <dependency>\n            <groupId>com.github.ben-manes.caffeine</groupId>\n            <artifactId>caffeine</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>io.ebean</groupId>\n            <artifactId>ebean</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>commons-beanutils</groupId>\n            <artifactId>commons-beanutils</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>commons-lang</groupId>\n            <artifactId>commons-lang</artifactId>\n        </dependency>\n\t\t<!-- junit -->\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n    </dependencies>\n\n    <build>\n        <finalName>canal-admin-${project.version}</finalName>\n        <plugins>\n            <plugin>\n                <groupId>io.repaint.maven</groupId>\n                <artifactId>tiles-maven-plugin</artifactId>\n                <version>2.12</version>\n                <extensions>true</extensions>\n                <configuration>\n                    <tiles>\n                        <tile>io.ebean.tile:enhancement:11.41.1</tile>\n                    </tiles>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-assembly-plugin</artifactId>\n                <version>2.2.1</version>\n                <executions>\n                    <execution>\n                        <id>assemble</id>\n                        <goals>\n                            <goal>single</goal>\n                        </goals>\n                        <phase>package</phase>\n                    </execution>\n                </executions>\n                <configuration>\n                    <appendAssemblyId>false</appendAssemblyId>\n                    <attach>false</attach>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-jar-plugin</artifactId>\n                <version>3.0.2</version>\n                <configuration>\n                    <archive>\n                        <manifest>\n                            <addClasspath>true</addClasspath>\n                            <classpathPrefix>lib/</classpathPrefix>\n                            <mainClass>com.alibaba.otter.canal.admin.CanalAdminApplication</mainClass>\n                        </manifest>\n                    </archive>\n                    <excludes>\n                        <exclude>**/*.properties</exclude>\n                        <exclude>**/*.xml</exclude>\n                        <exclude>**/*.yml</exclude>\n                        <exclude>static/**</exclude>\n                        <exclude>public/**</exclude>\n                        <exclude>templates/**</exclude>\n                    </excludes>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n    <profiles>\n        <profile>\n            <id>npm</id>\n            <activation>\n                <property>\n                    <name>env</name>\n                    <value>npm</value>\n                </property>\n            </activation>\n            <build>\n                <plugins>\n                    <plugin>\n                        <artifactId>maven-clean-plugin</artifactId>\n                        <version>3.0.0</version>\n                        <configuration>\n                            <filesets>\n                                <fileset>\n                                    <directory>src/main/resources/public</directory>\n                                </fileset>\n                            </filesets>\n                        </configuration>\n                    </plugin>\n                    <plugin>\n                        <artifactId>maven-resources-plugin</artifactId>\n                        <version>3.0.2</version>\n                        <executions>\n                            <execution>\n                                <id>copy Vue.js frontend content</id>\n                                <phase>generate-resources</phase>\n                                <goals>\n                                    <goal>copy-resources</goal>\n                                </goals>\n                                <configuration>\n                                    <outputDirectory>src/main/resources/public</outputDirectory>\n                                    <overwrite>true</overwrite>\n                                    <resources>\n                                        <resource>\n                                            <directory>${project.parent.basedir}/admin-ui/target/dist</directory>\n                                            <includes>\n                                                <include>static/</include>\n                                                <include>index.html</include>\n                                                <include>avatar.gif</include>\n                                                <include>logo.png</include>\n                                            </includes>\n                                        </resource>\n                                    </resources>\n                                </configuration>\n                            </execution>\n                        </executions>\n                    </plugin>\n                </plugins>\n            </build>\n        </profile>\n\n        <profile>\n            <id>dev</id>\n            <activation>\n                <activeByDefault>true</activeByDefault>\n                <property>\n                    <name>env</name>\n                    <value>!release</value>\n                </property>\n            </activation>\n\n            <build>\n                <plugins>\n                    <plugin>\n                        <artifactId>maven-assembly-plugin</artifactId>\n                        <configuration>\n                            <descriptors>\n                                <descriptor>${basedir}/src/main/assembly/dev.xml</descriptor>\n                            </descriptors>\n                            <finalName>canal-admin</finalName>\n                            <outputDirectory>${project.build.directory}</outputDirectory>\n                        </configuration>\n                    </plugin>\n                </plugins>\n            </build>\n\n        </profile>\n\n        <profile>\n            <id>release</id>\n            <activation>\n                <property>\n                    <name>env</name>\n                    <value>release</value>\n                </property>\n            </activation>\n\n            <build>\n                <plugins>\n                    <plugin>\n                        <artifactId>maven-assembly-plugin</artifactId>\n                        <configuration>\n                            <descriptors>\n                                <descriptor>${basedir}/src/main/assembly/release.xml</descriptor>\n                            </descriptors>\n                            <finalName>canal.admin-${project.version}</finalName>\n                            <outputDirectory>${project.basedir}/../../target</outputDirectory>\n                        </configuration>\n                    </plugin>\n                </plugins>\n            </build>\n        </profile>\n    </profiles>\n\n</project>\n"
  },
  {
    "path": "admin/admin-web/src/main/assembly/dev.xml",
    "content": "<assembly xmlns=\"http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd\">\n\t<id>dist</id>\n\t<formats>\n\t\t<format>dir</format>\n\t</formats>\n\t<includeBaseDirectory>false</includeBaseDirectory>\n\t<fileSets>\n        <fileSet>\n            <directory>.</directory>\n            <outputDirectory>/</outputDirectory>\n            <includes>\n                <include>README*</include>\n            </includes>\n        </fileSet>\n        <fileSet>\n            <directory>./src/main/bin</directory>\n            <outputDirectory>bin</outputDirectory>\n            <includes>\n                <include>**/*</include>\n            </includes>\n            <fileMode>0755</fileMode>\n        </fileSet>\n        <fileSet>\n            <directory>./src/main/resources</directory>\n            <outputDirectory>/conf</outputDirectory>\n            <includes>\n                <include>application.yml</include>\n                <include>logback.xml</include>\n                <include>public/**</include>\n                <include>canal_manager.sql</include>\n                <include>canal-template.properties</include>\n                <include>instance-template.properties</include>\n            </includes>\n        </fileSet>\n        <fileSet>\n            <directory>target</directory>\n            <outputDirectory>logs</outputDirectory>\n            <excludes>\n                <exclude>**/*</exclude>\n            </excludes>\n        </fileSet>\n    </fileSets>\n    <dependencySets>\n        <dependencySet>\n            <outputDirectory>lib</outputDirectory>\n            <excludes>\n                <exclude>junit:junit</exclude>\n            </excludes>\n        </dependencySet>\n    </dependencySets>\n</assembly>\n"
  },
  {
    "path": "admin/admin-web/src/main/assembly/release.xml",
    "content": "<assembly xmlns=\"http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0\"\n          xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n          xsi:schemaLocation=\"http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd\">\n    <id>dist</id>\n    <formats>\n        <format>tar.gz</format>\n    </formats>\n    <includeBaseDirectory>false</includeBaseDirectory>\n    <fileSets>\n        <fileSet>\n            <directory>.</directory>\n            <outputDirectory>/</outputDirectory>\n            <includes>\n                <include>README*</include>\n            </includes>\n        </fileSet>\n        <fileSet>\n            <directory>./src/main/bin</directory>\n            <outputDirectory>bin</outputDirectory>\n            <includes>\n                <include>**/*</include>\n            </includes>\n            <fileMode>0755</fileMode>\n        </fileSet>\n        <fileSet>\n            <directory>./src/main/resources</directory>\n            <outputDirectory>/conf</outputDirectory>\n            <includes>\n                <include>application.yml</include>\n                <include>logback.xml</include>\n                <include>public/**</include>\n                <include>canal_manager.sql</include>\n                <include>canal-template.properties</include>\n                <include>instance-template.properties</include>\n            </includes>\n        </fileSet>\n        <fileSet>\n            <directory>target</directory>\n            <outputDirectory>logs</outputDirectory>\n            <excludes>\n                <exclude>**/*</exclude>\n            </excludes>\n        </fileSet>\n    </fileSets>\n    <dependencySets>\n        <dependencySet>\n            <outputDirectory>lib</outputDirectory>\n            <excludes>\n                <exclude>junit:junit</exclude>\n            </excludes>\n        </dependencySet>\n    </dependencySets>\n</assembly>\n"
  },
  {
    "path": "admin/admin-web/src/main/bin/restart.sh",
    "content": "#!/bin/bash\n\ncase $(uname) in\nLinux)\n  bin_abs_path=$(readlink -f $(dirname $0))\n  ;;\n*)\n  bin_abs_path=$(cd $(dirname $0) ||exit ; pwd)\n  ;;\nesac\n\nsh \"$bin_abs_path\"/stop.sh\nsh \"$bin_abs_path\"/startup.sh\n"
  },
  {
    "path": "admin/admin-web/src/main/bin/startup.bat",
    "content": "@echo off\n@if not \"%ECHO%\" == \"\"  echo %ECHO%\n@if \"%OS%\" == \"Windows_NT\"  setlocal\n\nset ENV_PATH=.\\\nif \"%OS%\" == \"Windows_NT\" set ENV_PATH=%~dp0%\n\nset conf_dir=%ENV_PATH%\\..\\conf\n\nset CLASSPATH=%conf_dir%\nset CLASSPATH=%conf_dir%\\..\\lib\\*;%CLASSPATH%\n\nset JAVA_MEM_OPTS= -Xms128m -Xmx512m\nset JAVA_OPTS_EXT= -Djava.awt.headless=true -Djava.net.preferIPv4Stack=false -Dapplication.codeset=UTF-8 -Dfile.encoding=UTF-8\nset ADAPTER_OPTS= -DappName=canal-admin\n\nset JAVA_OPTS= %JAVA_MEM_OPTS% %JAVA_OPTS_EXT% %ADAPTER_OPTS%\n\nset CMD_STR= java %JAVA_OPTS% -classpath \"%CLASSPATH%\" com.alibaba.otter.canal.admin.CanalAdminApplication\necho start cmd : %CMD_STR%\n\njava %JAVA_OPTS% -classpath \"%CLASSPATH%\" com.alibaba.otter.canal.admin.CanalAdminApplication\n"
  },
  {
    "path": "admin/admin-web/src/main/bin/startup.sh",
    "content": "#!/bin/bash\n\ncurrent_path=`pwd`\ncase \"`uname`\" in\n    Linux)\n\t\tbin_abs_path=$(readlink -f $(dirname $0))\n\t\t;;\n\t*)\n\t\tbin_abs_path=`cd $(dirname $0); pwd`\n\t\t;;\nesac\nbase=${bin_abs_path}/..\nexport LANG=en_US.UTF-8\nexport BASE=$base\n\nif [ -f $base/bin/adapter.pid ] ; then\n\techo \"found adapter.pid , Please run stop.sh first ,then startup.sh\" 2>&2\n    exit 1\nfi\n\nif [ ! -d $base/logs ] ; then\n\tmkdir -p $base/logs\nfi\n\n## set java path\nif [ -z \"$JAVA\" ] ; then\n  JAVA=$(which java)\nfi\n\nALIBABA_JAVA=\"/usr/alibaba/java/bin/java\"\nTAOBAO_JAVA=\"/opt/taobao/java/bin/java\"\nif [ -z \"$JAVA\" ]; then\n  if [ -f $ALIBABA_JAVA ] ; then\n  \tJAVA=$ALIBABA_JAVA\n  elif [ -f $TAOBAO_JAVA ] ; then\n  \tJAVA=$TAOBAO_JAVA\n  else\n  \techo \"Cannot find a Java JDK. Please set either set JAVA or put java (>=1.5) in your PATH.\" 2>&2\n    exit 1\n  fi\nfi\n\ncase \"$#\"\nin\n0 )\n  ;;\n2 )\n  if [ \"$1\" = \"debug\" ]; then\n    DEBUG_PORT=$2\n    DEBUG_SUSPEND=\"n\"\n    JAVA_DEBUG_OPT=\"-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=$DEBUG_PORT,server=y,suspend=$DEBUG_SUSPEND\"\n  fi\n  ;;\n* )\n  echo \"THE PARAMETERS MUST BE TWO OR LESS.PLEASE CHECK AGAIN.\"\n  exit;;\nesac\n\nJavaVersion=`$JAVA -version 2>&1 |awk 'NR==1{ gsub(/\"/,\"\"); print $3 }' | awk  -F '.' '{print $1}'`\nstr=`file -L $JAVA | grep 64-bit`\n\nJAVA_OPTS=\"$JAVA_OPTS -Xss1m -XX:+AggressiveOpts -XX:-UseBiasedLocking -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$base/logs\"\nif [ $JavaVersion -ge 11 ] ; then\n  #JAVA_OPTS=\"$JAVA_OPTS -Xlog:gc*:$base_log/gc.log:time \"\n  JAVA_OPTS=\"$JAVA_OPTS\"\nelse\n  #JAVA_OPTS=\"$JAVA_OPTS -Xloggc:$base/logs/canal/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime\"\n  JAVA_OPTS=\"$JAVA_OPTS -XX:+UseFastAccessorMethods -XX:+PrintAdaptiveSizePolicy -XX:+PrintTenuringDistribution\"\nfi\n\nif [ -n \"$str\" ]; then\n\tif [ $JavaVersion -ge 11 ] ; then\n    # For G1\n    JAVA_OPTS=\"-server -Xms2g -Xmx3g -XX:+UseG1GC -XX:MaxGCPauseMillis=250 -XX:+UseGCOverheadLimit -XX:+ExplicitGCInvokesConcurrent $JAVA_OPTS\"\n  else\n\t  JAVA_OPTS=\"-server -Xms2g -Xmx3g -Xmn1g -XX:SurvivorRatio=2 -XX:PermSize=96m -XX:MaxPermSize=256m -XX:MaxTenuringThreshold=15 -XX:+DisableExplicitGC $JAVA_OPTS\"\n\tfi\nelse\n\tJAVA_OPTS=\"-server -Xms1024m -Xmx1024m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:MaxPermSize=128m $JAVA_OPTS\"\nfi\n\nJAVA_OPTS=\" $JAVA_OPTS -Djava.awt.headless=true -Djava.net.preferIPv4Stack=false -Dfile.encoding=UTF-8\"\nCANAL_OPTS=\"-DappName=canal-admin\"\n\nfor i in $base/lib/*;\n    do CLASSPATH=$i:\"$CLASSPATH\";\ndone\n\nCLASSPATH=\"$base/conf:$CLASSPATH\";\n\necho \"cd to $bin_abs_path for workaround relative path\"\ncd $bin_abs_path\n\necho CLASSPATH :$CLASSPATH\n$JAVA $JAVA_OPTS $JAVA_DEBUG_OPT $CANAL_OPTS -classpath .:$CLASSPATH com.alibaba.otter.canal.admin.CanalAdminApplication 1>>/dev/null 2>&1 &\necho $! > $base/bin/admin.pid\n\necho \"cd to $current_path for continue\"\ncd $current_path\n"
  },
  {
    "path": "admin/admin-web/src/main/bin/stop.sh",
    "content": "#!/bin/bash\n\ncygwin=false;\nlinux=false;\ncase \"`uname`\" in\n    CYGWIN*)\n        cygwin=true\n        ;;\n    Linux*)\n    \tlinux=true\n    \t;;\nesac\n\nget_pid() {\t\n\tSTR=$1\n\tPID=$2\n    if $cygwin; then\n        JAVA_CMD=\"$JAVA_HOME\\bin\\java\"\n        JAVA_CMD=`cygpath --path --unix $JAVA_CMD`\n        JAVA_PID=`ps |grep $JAVA_CMD |awk '{print $1}'`\n    else\n    \tif $linux; then\n\t        if [ ! -z \"$PID\" ]; then\n\t        \tJAVA_PID=`ps -C java -f --width 1000|grep \"$STR\"|grep \"$PID\"|grep -v grep|awk '{print $2}'`\n\t\t    else \n\t\t        JAVA_PID=`ps -C java -f --width 1000|grep \"$STR\"|grep -v grep|awk '{print $2}'`\n\t        fi\n\t    else\n\t    \tif [ ! -z \"$PID\" ]; then\n\t        \tJAVA_PID=`ps aux |grep \"$STR\"|grep \"$PID\"|grep -v grep|awk '{print $2}'`\n\t\t    else \n\t\t        JAVA_PID=`ps aux |grep \"$STR\"|grep -v grep|awk '{print $2}'`\n\t        fi\n\t    fi\n    fi\n    echo $JAVA_PID;\n}\n\nbase=`dirname $0`/..\npidfile=$base/bin/admin.pid\nif [ ! -f \"$pidfile\" ];then\n\techo \"canal-admin is not running. exists\"\n\texit\nfi\n\npid=`cat $pidfile`\nif [ \"$pid\" == \"\" ] ; then\n\tpid=`get_pid \"appName=canal-admin\"`\nfi\n\necho -e \"`hostname`: stopping canal $pid ... \"\nkill $pid\n\nLOOPS=0\nwhile (true); \ndo \n\tgpid=`get_pid \"appName=canal-admin\" \"$pid\"`\n    if [ \"$gpid\" == \"\" ] ; then\n    \techo \"Oook! cost:$LOOPS\"\n    \t`rm $pidfile`\n    \tbreak;\n    fi\n    let LOOPS=LOOPS+1\n    sleep 1\ndone"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/CanalAdminApplication.java",
    "content": "package com.alibaba.otter.canal.admin;\n\nimport org.springframework.boot.Banner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * 启动入口\n *\n * @author rewerma @ 2018-10-20\n * @version 1.0.0\n */\n@SpringBootApplication\npublic class CanalAdminApplication {\n\n    public static void main(String[] args) {\n        SpringApplication application = new SpringApplication(CanalAdminApplication.class);\n        application.setBannerMode(Banner.Mode.OFF);\n        application.run(args);\n    }\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/common/DaemonThreadFactory.java",
    "content": "package com.alibaba.otter.canal.admin.common;\n\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ThreadFactory;\n\npublic class DaemonThreadFactory implements ThreadFactory {\n\n    public static final ThreadFactory daemonThreadFactory = new DaemonThreadFactory();\n\n    public Thread newThread(Runnable r) {\n        Thread t = Executors.defaultThreadFactory().newThread(r);\n        t.setDaemon(true);\n        return t;\n    }\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/common/TemplateConfigLoader.java",
    "content": "package com.alibaba.otter.canal.admin.common;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URL;\nimport java.nio.charset.StandardCharsets;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class TemplateConfigLoader {\n\n    private static final Logger logger              = LoggerFactory.getLogger(TemplateConfigLoader.class);\n\n    public static final String  CONF_DIR            = \"conf\";\n    public static final String  CANAL_CONFIG_TMP    = \"canal-template.properties\";\n    public static final String  INSTANCE_CONFIG_TMP = \"instance-template.properties\";\n\n    public static String loadCanalConfig() {\n        return loadFile(CANAL_CONFIG_TMP);\n    }\n\n    public static String loadInstanceConfig() {\n        return loadFile(INSTANCE_CONFIG_TMP);\n    }\n\n    private static String loadFile(String fileName) {\n        File configFile = new File(\"..\" + File.separator + CONF_DIR + File.separator + fileName);\n        if (!configFile.exists()) {\n            URL url = TemplateConfigLoader.class.getClassLoader().getResource(\"\");\n            if (url != null) {\n                configFile = new File(url.getPath() + fileName + File.separator);\n            }\n        }\n        if (!configFile.exists()) {\n            return null;\n        }\n        try (InputStream in = new FileInputStream(configFile)) {\n            byte[] bytes = new byte[in.available()];\n            in.read(bytes);\n            return new String(bytes, StandardCharsets.UTF_8);\n        } catch (IOException e) {\n            logger.error(\"Read \" + fileName + \" error\", e);\n        }\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/common/Threads.java",
    "content": "package com.alibaba.otter.canal.admin.common;\n\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\npublic class Threads {\n\n    public static int                   pool            = 60;\n    public static final ExecutorService executorService = new ThreadPoolExecutor(pool,\n                                                            pool,\n                                                            0L,\n                                                            TimeUnit.MILLISECONDS,\n                                                            new ArrayBlockingQueue<>(pool * 20),\n                                                            DaemonThreadFactory.daemonThreadFactory);\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/common/exception/ServiceException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.otter.canal.admin.common.exception;\n\nimport org.springframework.http.HttpStatus;\nimport org.springframework.web.bind.annotation.ResponseStatus;\n\n/**\n * Service Logic Exception\n */\n@ResponseStatus(value = HttpStatus.SERVICE_UNAVAILABLE)\npublic class ServiceException extends RuntimeException {\n\n    private static final long serialVersionUID = -663217666968123330L;\n\n    public ServiceException(){\n    }\n\n    public ServiceException(String message){\n        super(message);\n    }\n\n    public ServiceException(String message, Throwable cause){\n        super(message, cause);\n    }\n\n    public ServiceException(Throwable cause){\n        super(cause);\n    }\n\n    public ServiceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace){\n        super(message, cause, enableSuppression, writableStackTrace);\n    }\n\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/config/EbeanConfig.java",
    "content": "package com.alibaba.otter.canal.admin.config;\n\nimport io.ebean.EbeanServer;\nimport io.ebean.EbeanServerFactory;\nimport io.ebean.config.ServerConfig;\nimport io.ebean.config.UnderscoreNamingConvention;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Ebean 配置\n *\n * @author rewerma 2019-07-13 下午05:12:16\n * @version 1.0.0\n */\n@Configuration\npublic class EbeanConfig {\n\n    @Bean(\"ebeanServer\")\n    public EbeanServer ebeanServer(DataSource dataSource) {\n        ServerConfig serverConfig = new ServerConfig();\n        serverConfig.setDefaultServer(true);\n        serverConfig.setNamingConvention(new UnderscoreNamingConvention());\n        List<String> packages = new ArrayList<>();\n        packages.add(\"com.alibaba.otter.canal.admin.model\");\n        serverConfig.setPackages(packages);\n        serverConfig.setName(\"ebeanServer\");\n        serverConfig.setDataSource(dataSource);\n        serverConfig.setDatabaseSequenceBatchSize(1);\n        serverConfig.setDdlGenerate(false);\n        serverConfig.setDdlRun(false);\n        return EbeanServerFactory.create(serverConfig);\n    }\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/config/SpringContext.java",
    "content": "package com.alibaba.otter.canal.admin.config;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.stereotype.Component;\n\n/**\n * spring util配置类\n *\n * @author rewerma @ 2018-10-20\n * @version 1.0.0\n */\n@Component\npublic class SpringContext implements ApplicationContextAware {\n\n    private static ApplicationContext context;\n\n    /*\n     * 注入ApplicationContext\n     */\n    public void setApplicationContext(final ApplicationContext context) throws BeansException {\n        // 在加载Spring时自动获得context\n        SpringContext.context = context;\n    }\n\n    public static Object getBean(final String beanName) {\n        return SpringContext.context.getBean(beanName);\n    }\n\n    public static Object getBean(final Class<?> clz) {\n        return context.getBean(clz);\n    }\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/config/WebConfig.java",
    "content": "package com.alibaba.otter.canal.admin.config;\n\nimport java.io.PrintWriter;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.web.servlet.HandlerInterceptor;\nimport org.springframework.web.servlet.config.annotation.InterceptorRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n\nimport com.alibaba.otter.canal.admin.controller.UserController;\nimport com.alibaba.otter.canal.admin.model.BaseModel;\nimport com.alibaba.otter.canal.admin.model.User;\nimport com.fasterxml.jackson.databind.ObjectMapper;\n\n/**\n * 相关MVC拦截器配置\n *\n * @author rewerma 2019-07-13 下午05:12:16\n * @version 1.0.0\n */\n@Configuration\npublic class WebConfig implements WebMvcConfigurer {\n\n    @Value(value = \"${canal.adminUser}\")\n    private String user;\n\n    @Value(value = \"${canal.adminPasswd}\")\n    private String passwd;\n\n    @Override\n    public void addInterceptors(InterceptorRegistry registry) {\n        if (StringUtils.isEmpty(user)) {\n            throw new IllegalArgumentException(\n                \"canal.adminUser is empty , pls check https://github.com/alibaba/canal/issues/4941\");\n        }\n\n        if (StringUtils.isEmpty(passwd)) {\n            throw new IllegalArgumentException(\n                \"canal.adminPasswd is empty , pls check https://github.com/alibaba/canal/issues/4941\");\n        }\n\n        registry.addInterceptor(new HandlerInterceptor() {\n\n            @Override\n            public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,\n                                     Object o) throws Exception {\n                httpServletResponse.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n                httpServletResponse.setHeader(\"Access-Control-Allow-Methods\", \"*\");\n                httpServletResponse.setHeader(\"Access-Control-Allow-Headers\",\n                    \"Origin, X-Requested-With, Content-Type, Accept, Authorization, X-Token\");\n                httpServletResponse.setHeader(\"Access-Control-Allow-Credentials\", \"true\");\n                httpServletResponse.setHeader(\"Access-Control-Max-Age\", String.valueOf(3600 * 24));\n\n                if (HttpMethod.OPTIONS.toString().equals(httpServletRequest.getMethod())) {\n                    httpServletResponse.setStatus(HttpStatus.NO_CONTENT.value());\n                    return false;\n                }\n\n                return true;\n            }\n        }).addPathPatterns(\"/api/**\");\n\n        registry.addInterceptor(new HandlerInterceptor() {\n\n            @Override\n            public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,\n                                     Object o) throws Exception {\n                String token = httpServletRequest.getHeader(\"X-Token\");\n                boolean valid = false;\n                if (token != null) {\n                    User user = UserController.loginUsers.getIfPresent(token);\n                    if (user != null) {\n                        valid = true;\n                        httpServletRequest.setAttribute(\"user\", user);\n                        httpServletRequest.setAttribute(\"token\", token);\n                    }\n                }\n                if (!valid) {\n                    BaseModel baseModel = BaseModel.getInstance(null);\n                    baseModel.setCode(50014);\n                    baseModel.setMessage(\"Expired token\");\n                    ObjectMapper mapper = new ObjectMapper();\n                    String json = mapper.writeValueAsString(baseModel);\n                    try {\n                        httpServletResponse.setContentType(\"application/json;charset=UTF-8\");\n                        PrintWriter out = httpServletResponse.getWriter();\n                        out.print(json);\n                    } catch (Throwable e) {\n                        throw new RuntimeException(e);\n                    }\n                    return false;\n                }\n\n                return true;\n            }\n        })\n            .addPathPatterns(\"/api/**\")\n            .excludePathPatterns(\"/api/**/config/server_polling\")\n            .excludePathPatterns(\"/api/**/config/instances_polling\")\n            .excludePathPatterns(\"/api/**/config/instance_polling/**\")\n            .excludePathPatterns(\"/api/**/user/login\")\n            .excludePathPatterns(\"/api/**/user/logout\")\n            .excludePathPatterns(\"/api/**/user/info\");\n    }\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/connector/AdminConnector.java",
    "content": "package com.alibaba.otter.canal.admin.connector;\n\nimport com.alibaba.otter.canal.admin.common.exception.ServiceException;\nimport com.alibaba.otter.canal.protocol.exception.CanalClientException;\n\n/**\n * canal admin操作客户端\n * \n * @author agapple 2019年8月31日 下午12:46:29\n * @since 1.1.4\n */\npublic interface AdminConnector {\n\n    /**\n     * 链接对应的canal server\n     * \n     * @throws CanalClientException\n     */\n    void connect() throws ServiceException;\n\n    /**\n     * 释放链接\n     * \n     * @throws CanalClientException\n     */\n    void disconnect() throws ServiceException;\n\n    /**\n     * 获取Canal Server状态\n     *\n     * @return 状态代码\n     */\n    boolean check();\n\n    /**\n     * 启动Canal Server\n     *\n     * @return 是否成功\n     */\n    boolean start();\n\n    /**\n     * 停止Canal Server\n     *\n     * @return 是否成功\n     */\n    boolean stop();\n\n    /**\n     * 重启Canal Server\n     *\n     * @return 是否成功\n     */\n    boolean restart();\n\n    /**\n     * 获取所有当前节点下运行中的实例\n     *\n     * @return 实例信息\n     */\n    String getRunningInstances();\n\n    /**\n     * 通过实例名检查\n     * \n     * @param destination\n     * @return\n     */\n    boolean checkInstance(String destination);\n\n    /**\n     * 通过实例名启动实例\n     *\n     * @param destination 实例名\n     * @return 是否成功\n     */\n    boolean startInstance(String destination);\n\n    /**\n     * 通过实例名关闭实例\n     *\n     * @param destination 实例名\n     * @return 是否成功\n     */\n    boolean stopInstance(String destination);\n\n    /**\n     * 通过实例名释放,主要针对cluster模式有效(通知当前主机释放instance运行交给其他人来抢占)\n     *\n     * @param destination 实例名\n     * @return 是否成功\n     */\n    boolean releaseInstance(String destination);\n\n    /**\n     * 通过实例名重启实例\n     *\n     * @param destination 实例名\n     * @return 是否成功\n     */\n    boolean restartInstance(String destination);\n\n    /**\n     * 获取Canal Server日志列表\n     *\n     * @return 日志信息\n     */\n    String listCanalLog();\n\n    /**\n     * 获取Canal Server日志\n     *\n     * @return 日志信息\n     */\n    String canalLog(int lines);\n\n    /**\n     * 获取Instance的机器日志列表\n     * \n     * @param destination\n     */\n    String listInstanceLog(String destination);\n\n    /**\n     * 通过实例名获取实例日志\n     *\n     * @return 日志信息\n     */\n    String instanceLog(String destination, String fileName, int lines);\n\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/connector/SimpleAdminConnector.java",
    "content": "package com.alibaba.otter.canal.admin.connector;\n\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.net.SocketAddress;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.channels.Channel;\nimport java.nio.channels.Channels;\nimport java.nio.channels.ReadableByteChannel;\nimport java.nio.channels.SocketChannel;\nimport java.nio.channels.WritableByteChannel;\nimport java.security.NoSuchAlgorithmException;\n\nimport org.apache.commons.lang.BooleanUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.admin.common.exception.ServiceException;\nimport com.alibaba.otter.canal.protocol.AdminPacket.Ack;\nimport com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth;\nimport com.alibaba.otter.canal.protocol.AdminPacket.Handshake;\nimport com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin;\nimport com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin;\nimport com.alibaba.otter.canal.protocol.AdminPacket.Packet;\nimport com.alibaba.otter.canal.protocol.AdminPacket.PacketType;\nimport com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin;\nimport com.alibaba.otter.canal.protocol.SecurityUtil;\nimport com.alibaba.otter.canal.protocol.exception.CanalClientException;\nimport com.google.protobuf.ByteString;\n\n/**\n * 基于netty实现的admin控制\n *\n * @author agapple 2019年8月26日 上午10:23:44\n * @since 1.1.4\n */\npublic class SimpleAdminConnector implements AdminConnector {\n\n    private static final Logger logger      = LoggerFactory.getLogger(SimpleAdminConnector.class);\n    private String              user;\n    private String              passwd;\n    private SocketAddress       address;\n    private int                 soTimeout   = 60000;                                              // milliseconds\n    private int                 idleTimeout = 60 * 60 * 1000;                                     // client和server之间的空闲链接超时的时间,默认为1小时\n    private final ByteBuffer    readHeader  = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN);\n    private final ByteBuffer    writeHeader = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN);\n    private SocketChannel       channel;\n    private ReadableByteChannel readableChannel;\n    private WritableByteChannel writableChannel;\n    private volatile boolean    connected   = false;\n\n    public SimpleAdminConnector(String ip, int port, String user, String passwd){\n        this.address = new InetSocketAddress(ip, port);\n        this.user = user;\n        this.passwd = passwd;\n    }\n\n    @Override\n    public void connect() throws ServiceException {\n        try {\n            if (connected) {\n                return;\n            }\n\n            channel = SocketChannel.open();\n            channel.socket().setSoTimeout(soTimeout);\n            channel.connect(address);\n            readableChannel = Channels.newChannel(channel.socket().getInputStream());\n            writableChannel = Channels.newChannel(channel.socket().getOutputStream());\n            Packet p = Packet.parseFrom(readNextPacket());\n            if (p.getVersion() != 1) {\n                throw new CanalClientException(\"unsupported version at this client.\");\n            }\n\n            if (p.getType() != PacketType.HANDSHAKE) {\n                throw new CanalClientException(\"expect handshake but found other type.\");\n            }\n\n            Handshake handshake = Handshake.parseFrom(p.getBody());\n            ByteString seed = handshake.getSeeds(); // seed for auth\n            String newPasswd = passwd;\n            if (passwd != null) {\n                // encode passwd\n                newPasswd = SecurityUtil.byte2HexStr(SecurityUtil.scramble411(passwd.getBytes(), seed.toByteArray()));\n            }\n\n            ClientAuth ca = ClientAuth.newBuilder()\n                .setUsername(user != null ? user : \"\")\n                .setPassword(ByteString.copyFromUtf8(newPasswd != null ? newPasswd : \"\"))\n                .setNetReadTimeout(idleTimeout)\n                .setNetWriteTimeout(idleTimeout)\n                .build();\n            writeWithHeader(Packet.newBuilder()\n                .setType(PacketType.CLIENTAUTHENTICATION)\n                .setBody(ca.toByteString())\n                .build()\n                .toByteArray());\n            //\n            Packet ack = Packet.parseFrom(readNextPacket());\n            if (ack.getType() != PacketType.ACK) {\n                throw new CanalClientException(\"unexpected packet type when ack is expected\");\n            }\n\n            Ack ackBody = Ack.parseFrom(ack.getBody());\n            if (ackBody.getCode() > 0) {\n                throw new ServiceException(\"something goes wrong when doing authentication: \" + ackBody.getMessage());\n            }\n\n            connected = true;\n        } catch (IOException | NoSuchAlgorithmException e) {\n            throw new ServiceException(e);\n        }\n    }\n\n    @Override\n    public void disconnect() throws ServiceException {\n        if (!connected) {\n            return;\n        }\n\n        connected = false;\n        if (readableChannel != null) {\n            quietlyClose(readableChannel);\n            readableChannel = null;\n        }\n        if (writableChannel != null) {\n            quietlyClose(writableChannel);\n            writableChannel = null;\n        }\n        if (channel != null) {\n            quietlyClose(channel);\n            channel = null;\n        }\n    }\n\n    @Override\n    public boolean check() {\n        return BooleanUtils.toBoolean(Integer.parseInt(doServerAdmin(\"check\")));\n    }\n\n    @Override\n    public boolean start() {\n        return BooleanUtils.toBoolean(Integer.parseInt(doServerAdmin(\"start\")));\n    }\n\n    @Override\n    public boolean stop() {\n        return BooleanUtils.toBoolean(Integer.parseInt(doServerAdmin(\"stop\")));\n    }\n\n    @Override\n    public boolean restart() {\n        return BooleanUtils.toBoolean(Integer.parseInt(doServerAdmin(\"restart\")));\n    }\n\n    @Override\n    public String getRunningInstances() {\n        return doServerAdmin(\"list\");\n    }\n\n    @Override\n    public boolean checkInstance(String destination) {\n        return BooleanUtils.toBoolean(Integer.parseInt(doInstanceAdmin(destination, \"check\")));\n    }\n\n    @Override\n    public boolean startInstance(String destination) {\n        return BooleanUtils.toBoolean(Integer.parseInt(doInstanceAdmin(destination, \"start\")));\n    }\n\n    @Override\n    public boolean stopInstance(String destination) {\n        return BooleanUtils.toBoolean(Integer.parseInt(doInstanceAdmin(destination, \"stop\")));\n    }\n\n    @Override\n    public boolean releaseInstance(String destination) {\n        return BooleanUtils.toBoolean(Integer.parseInt(doInstanceAdmin(destination, \"release\")));\n    }\n\n    @Override\n    public boolean restartInstance(String destination) {\n        return BooleanUtils.toBoolean(Integer.parseInt(doInstanceAdmin(destination, \"restart\")));\n    }\n\n    @Override\n    public String listCanalLog() {\n        return doLogAdmin(\"server\", \"list\", null, null, 0);\n    }\n\n    @Override\n    public String canalLog(int lines) {\n        return doLogAdmin(\"server\", \"file\", null, null, lines);\n    }\n\n    @Override\n    public String listInstanceLog(String destination) {\n        return doLogAdmin(\"instance\", \"list\", destination, null, 0);\n    }\n\n    @Override\n    public String instanceLog(String destination, String fileName, int lines) {\n        return doLogAdmin(\"instance\", \"file\", destination, fileName, lines);\n    }\n\n    // ==================== helper method ====================\n\n    private String doServerAdmin(String action) {\n        try {\n            writeWithHeader(Packet.newBuilder()\n                .setType(PacketType.SERVER)\n                .setBody(ServerAdmin.newBuilder().setAction(action).build().toByteString())\n                .build()\n                .toByteArray());\n\n            Packet p = Packet.parseFrom(readNextPacket());\n            Ack ack = Ack.parseFrom(p.getBody());\n            if (ack.getCode() > 0) {\n                throw new ServiceException(\"failed to subscribe with reason: \" + ack.getMessage());\n            }\n\n            return ack.getMessage();\n        } catch (IOException e) {\n            throw new ServiceException(e);\n        }\n    }\n\n    private String doInstanceAdmin(String destination, String action) {\n        try {\n            writeWithHeader(Packet.newBuilder()\n                .setType(PacketType.INSTANCE)\n                .setBody(InstanceAdmin.newBuilder()\n                    .setDestination(destination)\n                    .setAction(action)\n                    .build()\n                    .toByteString())\n                .build()\n                .toByteArray());\n\n            Packet p = Packet.parseFrom(readNextPacket());\n            Ack ack = Ack.parseFrom(p.getBody());\n            if (ack.getCode() > 0) {\n                throw new ServiceException(\"failed to subscribe with reason: \" + ack.getMessage());\n            }\n\n            return ack.getMessage();\n        } catch (IOException e) {\n            throw new ServiceException(e);\n        }\n    }\n\n    private String doLogAdmin(String type, String action, String destination, String file, int count) {\n        try {\n            writeWithHeader(Packet.newBuilder()\n                .setType(PacketType.LOG)\n                .setBody(LogAdmin.newBuilder()\n                    .setType(type)\n                    .setAction(action)\n                    .setDestination(destination == null ? \"\" : destination)\n                    .setFile(file == null ? \"\" : file)\n                    .setCount(count)\n                    .build()\n                    .toByteString())\n                .build()\n                .toByteArray());\n\n            Packet p = Packet.parseFrom(readNextPacket());\n            Ack ack = Ack.parseFrom(p.getBody());\n            if (ack.getCode() > 0) {\n                throw new ServiceException(\"failed to subscribe with reason: \" + ack.getMessage());\n            }\n\n            return ack.getMessage();\n        } catch (IOException e) {\n            throw new ServiceException(e);\n        }\n    }\n\n    private void writeWithHeader(byte[] body) throws IOException {\n        writeWithHeader(writableChannel, body);\n    }\n\n    private byte[] readNextPacket() throws IOException {\n        return readNextPacket(readableChannel);\n    }\n\n    private void writeWithHeader(WritableByteChannel channel, byte[] body) throws IOException {\n        writeHeader.clear();\n        writeHeader.putInt(body.length);\n        writeHeader.flip();\n        channel.write(writeHeader);\n        channel.write(ByteBuffer.wrap(body));\n    }\n\n    private byte[] readNextPacket(ReadableByteChannel channel) throws IOException {\n        readHeader.clear();\n        read(channel, readHeader);\n        int bodyLen = readHeader.getInt(0);\n        ByteBuffer bodyBuf = ByteBuffer.allocate(bodyLen).order(ByteOrder.BIG_ENDIAN);\n        read(channel, bodyBuf);\n        return bodyBuf.array();\n    }\n\n    private void read(ReadableByteChannel channel, ByteBuffer buffer) throws IOException {\n        while (buffer.hasRemaining()) {\n            int r = channel.read(buffer);\n            if (r == -1) {\n                throw new IOException(\"end of stream when reading header\");\n            }\n        }\n    }\n\n    private void quietlyClose(Channel channel) {\n        try {\n            channel.close();\n        } catch (IOException e) {\n            logger.warn(\"exception on closing channel:{} \\n {}\", channel, e);\n        }\n    }\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/connector/SimpleAdminConnectors.java",
    "content": "package com.alibaba.otter.canal.admin.connector;\n\nimport java.util.function.Function;\n\nimport org.assertj.core.util.Strings;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.core.env.Environment;\n\nimport com.alibaba.otter.canal.admin.config.SpringContext;\n\npublic class SimpleAdminConnectors {\n\n    private static final Logger logger = LoggerFactory.getLogger(SimpleAdminConnectors.class);\n\n    public static <R> R execute(String ip, int port, Function<AdminConnector, R> function) {\n        Environment env = (Environment) SpringContext.getBean(Environment.class);\n        String defaultUser = env.getProperty(\"canal.adminUser\", \"admin\");\n        String defaultPasswd = env.getProperty(\"canal.adminPasswd\", \"admin\");\n\n        return execute(ip, port, defaultUser, defaultPasswd, function);\n    }\n\n    public static <R> R execute(String ip, int port, String user, String passwd, Function<AdminConnector, R> function) {\n        SimpleAdminConnector connector = new SimpleAdminConnector(ip, port, user, passwd);\n        try {\n            connector.connect();\n            return function.apply(connector);\n        } catch (Exception e) {\n            logger.error(\"connect to ip:{},port:{},user:{},password:{}, failed\",\n                    ip, port, user, getDesensitizationPassword(passwd));\n            logger.error(e.getMessage());\n        } finally {\n            connector.disconnect();\n        }\n\n        return null;\n    }\n\n    private static String getDesensitizationPassword(String password) {\n        String defaultPassword = \"*****\";\n\n        if (Strings.isNullOrEmpty(password) || password.length() < 5) {\n            return defaultPassword;\n        } else {\n            return String.format(\"%s*****\", password.substring(0, 3));\n        }\n    }\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/controller/CanalClusterController.java",
    "content": "package com.alibaba.otter.canal.admin.controller;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.DeleteMapping;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.PutMapping;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport com.alibaba.fastjson2.JSONArray;\nimport com.alibaba.fastjson2.JSONObject;\nimport com.alibaba.otter.canal.admin.model.BaseModel;\nimport com.alibaba.otter.canal.admin.model.CanalCluster;\nimport com.alibaba.otter.canal.admin.model.NodeServer;\nimport com.alibaba.otter.canal.admin.service.CanalClusterService;\nimport com.alibaba.otter.canal.admin.service.NodeServerService;\n\n@RestController\n@RequestMapping(\"/api/{env}/canal\")\npublic class CanalClusterController {\n\n    @Autowired\n    CanalClusterService canalClusterServic;\n\n    @Autowired\n    NodeServerService   nodeServerService;\n\n    @GetMapping(value = \"/clusters\")\n    public BaseModel<List<CanalCluster>> clusters(CanalCluster canalCluster, @PathVariable String env) {\n        return BaseModel.getInstance(canalClusterServic.findList(canalCluster));\n    }\n\n    @PostMapping(value = \"/cluster\")\n    public BaseModel<String> save(@RequestBody CanalCluster canalCluster, @PathVariable String env) {\n        canalClusterServic.save(canalCluster);\n        return BaseModel.getInstance(\"success\");\n    }\n\n    @GetMapping(value = \"/cluster/{id}\")\n    public BaseModel<CanalCluster> detail(@PathVariable Long id, @PathVariable String env) {\n        return BaseModel.getInstance(canalClusterServic.detail(id));\n    }\n\n    @PutMapping(value = \"/cluster\")\n    public BaseModel<String> update(@RequestBody CanalCluster canalCluster, @PathVariable String env) {\n        canalClusterServic.update(canalCluster);\n        return BaseModel.getInstance(\"success\");\n    }\n\n    @DeleteMapping(value = \"/cluster/{id}\")\n    public BaseModel<String> delete(@PathVariable Long id, @PathVariable String env) {\n        canalClusterServic.delete(id);\n        return BaseModel.getInstance(\"success\");\n    }\n\n    @GetMapping(value = \"/clustersAndServers\")\n    public BaseModel<List<?>> clustersAndServers(@PathVariable String env) {\n        List<CanalCluster> clusters = canalClusterServic.findList(new CanalCluster());\n        JSONObject group = new JSONObject();\n        group.put(\"label\", \"集群\");\n        JSONArray jsonArray = new JSONArray();\n        clusters.forEach(cluster -> {\n            JSONObject item = new JSONObject();\n            item.put(\"label\", cluster.getName());\n            item.put(\"value\", \"cluster:\" + cluster.getId());\n            jsonArray.add(item);\n        });\n        group.put(\"options\", jsonArray);\n\n        NodeServer param = new NodeServer();\n        param.setClusterId(-1L);\n        List<NodeServer> servers = nodeServerService.findAll(param); // 取所有standalone的节点\n        JSONObject group2 = new JSONObject();\n        group2.put(\"label\", \"单机主机\");\n        JSONArray jsonArray2 = new JSONArray();\n        servers.forEach(server -> {\n            JSONObject item = new JSONObject();\n            item.put(\"label\", server.getName());\n            item.put(\"value\", \"server:\" + server.getId());\n            jsonArray2.add(item);\n        });\n        group2.put(\"options\", jsonArray2);\n\n        List<JSONObject> result = new ArrayList<>();\n        result.add(group);\n        result.add(group2);\n        return BaseModel.getInstance(result);\n    }\n\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/controller/CanalConfigController.java",
    "content": "package com.alibaba.otter.canal.admin.controller;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.PutMapping;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport com.alibaba.otter.canal.admin.common.TemplateConfigLoader;\nimport com.alibaba.otter.canal.admin.model.BaseModel;\nimport com.alibaba.otter.canal.admin.model.CanalConfig;\nimport com.alibaba.otter.canal.admin.service.CanalConfigService;\n\n/**\n * Canal主配置管理控制层\n *\n * @author rewerma 2019-07-13 下午05:12:16\n * @version 1.0.0\n */\n@RestController\n@RequestMapping(\"/api/{env}/canal\")\npublic class CanalConfigController {\n\n    @Autowired\n    CanalConfigService canalConfigService;\n\n    /**\n     * 获取配置信息\n     *\n     * @param env 环境变量\n     * @return 配置信息\n     */\n    @GetMapping(value = \"/config/{clusterId}/{serverId}\")\n    public BaseModel<CanalConfig> canalConfig(@PathVariable Long clusterId, @PathVariable Long serverId,\n                                              @PathVariable String env) {\n        return BaseModel.getInstance(canalConfigService.getCanalConfig(clusterId, serverId));\n    }\n\n    /**\n     * 修改配置\n     *\n     * @param canalConfig 配置信息对象\n     * @param env 环境变量\n     * @return 是否成功\n     */\n    @PutMapping(value = \"/config\")\n    public BaseModel<String> updateConfig(@RequestBody CanalConfig canalConfig, @PathVariable String env) {\n        canalConfigService.updateContent(canalConfig);\n        return BaseModel.getInstance(\"success\");\n    }\n\n    @GetMapping(value = \"/config/template\")\n    public BaseModel<String> template(@PathVariable String env) {\n        return BaseModel.getInstance(TemplateConfigLoader.loadCanalConfig());\n    }\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/controller/CanalInstanceController.java",
    "content": "package com.alibaba.otter.canal.admin.controller;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.DeleteMapping;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.PutMapping;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport com.alibaba.otter.canal.admin.common.TemplateConfigLoader;\nimport com.alibaba.otter.canal.admin.model.BaseModel;\nimport com.alibaba.otter.canal.admin.model.CanalInstanceConfig;\nimport com.alibaba.otter.canal.admin.model.Pager;\nimport com.alibaba.otter.canal.admin.service.CanalInstanceService;\n\n/**\n * Canal Instance配置管理控制层\n *\n * @author rewerma 2019-07-13 下午05:12:16\n * @version 1.0.0\n */\n@RestController\n@RequestMapping(\"/api/{env}/canal\")\npublic class CanalInstanceController {\n\n    @Autowired\n    CanalInstanceService canalInstanceConfigService;\n\n    /**\n     * 实例配置列表\n     *\n     * @param canalInstanceConfig 查询对象\n     * @param env 环境变量\n     * @return 实例列表\n     */\n    @GetMapping(value = \"/instances\")\n    public BaseModel<Pager<CanalInstanceConfig>> list(CanalInstanceConfig canalInstanceConfig,\n                                                      Pager<CanalInstanceConfig> pager, @PathVariable String env) {\n        return BaseModel.getInstance(canalInstanceConfigService.findList(canalInstanceConfig, pager));\n    }\n\n    /**\n     * 保存实例配置\n     *\n     * @param canalInstanceConfig 实例配置对象\n     * @param env 环境变量\n     * @return 是否成功\n     */\n    @PostMapping(value = \"/instance\")\n    public BaseModel<String> save(@RequestBody CanalInstanceConfig canalInstanceConfig, @PathVariable String env) {\n        canalInstanceConfigService.save(canalInstanceConfig);\n        return BaseModel.getInstance(\"success\");\n    }\n\n    /**\n     * 实例详情信息\n     *\n     * @param id 实例配置id\n     * @param env 环境变量\n     * @return 实例信息\n     */\n    @GetMapping(value = \"/instance\")\n    public BaseModel<CanalInstanceConfig> config(@PathVariable Long id, @PathVariable String env) {\n        return BaseModel.getInstance(canalInstanceConfigService.detail(id));\n    }\n\n    /**\n     * 实例详情信息\n     *\n     * @param id 实例配置id\n     * @param env 环境变量\n     * @return 实例信息\n     */\n    @GetMapping(value = \"/instance/{id}\")\n    public BaseModel<CanalInstanceConfig> detail(@PathVariable Long id, @PathVariable String env) {\n        return BaseModel.getInstance(canalInstanceConfigService.detail(id));\n    }\n\n    /**\n     * 修改实例配置\n     *\n     * @param canalInstanceConfig 实例配置信息\n     * @param env 环境变量\n     * @return 是否成功\n     */\n    @PutMapping(value = \"/instance\")\n    public BaseModel<String> update(@RequestBody CanalInstanceConfig canalInstanceConfig, @PathVariable String env) {\n        canalInstanceConfigService.updateContent(canalInstanceConfig);\n        return BaseModel.getInstance(\"success\");\n    }\n\n    /**\n     * 删除实例配置\n     *\n     * @param id 实例配置id\n     * @param env 环境变量\n     * @return 是否成功\n     */\n    @DeleteMapping(value = \"/instance/{id}\")\n    public BaseModel<String> delete(@PathVariable Long id, @PathVariable String env) {\n        canalInstanceConfigService.delete(id);\n        return BaseModel.getInstance(\"success\");\n    }\n\n    /**\n     * 启动远程实例\n     *\n     * @param id 实例配置id\n     * @param env 环境变量\n     * @return 是否成功\n     */\n    @PutMapping(value = \"/instance/start/{id}/{nodeId}\")\n    public BaseModel<Boolean> start(@PathVariable Long id, @PathVariable Long nodeId, @PathVariable String env) {\n        return BaseModel.getInstance(canalInstanceConfigService.remoteOperation(id, nodeId, \"start\"));\n    }\n\n    /**\n     * 关闭远程实例\n     *\n     * @param id 实例配置id\n     * @param nodeId 节点id\n     * @param env 环境变量\n     * @return 是否成功\n     */\n    @PutMapping(value = \"/instance/stop/{id}/{nodeId}\")\n    public BaseModel<Boolean> stop(@PathVariable Long id, @PathVariable Long nodeId, @PathVariable String env) {\n        return BaseModel.getInstance(canalInstanceConfigService.remoteOperation(id, nodeId, \"stop\"));\n    }\n\n    /**\n     * 通过操作instance状态启动/停止远程instance\n     *\n     * @param id 实例配置id\n     * @param option 操作类型: start/stop\n     * @param env 环境变量\n     * @return 是否成功\n     */\n    @PutMapping(value = \"/instance/status/{id}\")\n    public BaseModel<Boolean> instanceStart(@PathVariable Long id, @RequestParam String option, @PathVariable String env) {\n        return BaseModel.getInstance(canalInstanceConfigService.instanceOperation(id, option));\n    }\n\n    /**\n     * 获取远程实例运行日志\n     *\n     * @param id 实例配置id\n     * @param nodeId 节点id\n     * @param env 环境变量\n     * @return 实例日志信息\n     */\n    @GetMapping(value = \"/instance/log/{id}/{nodeId}\")\n    public BaseModel<Map<String, String>> instanceLog(@PathVariable Long id, @PathVariable Long nodeId,\n                                                      @PathVariable String env) {\n        return BaseModel.getInstance(canalInstanceConfigService.remoteInstanceLog(id, nodeId));\n    }\n\n    /**\n     * 通过Server id获取所有活动的Instance\n     *\n     * @param serverId 节点id\n     * @param env 环境变量\n     * @return 实例列表\n     */\n    @GetMapping(value = \"/active/instances/{serverId}\")\n    public BaseModel<List<CanalInstanceConfig>> activeInstances(@PathVariable Long serverId, @PathVariable String env) {\n        return BaseModel.getInstance(canalInstanceConfigService.findActiveInstanceByServerId(serverId));\n    }\n\n    @GetMapping(value = \"/instance/template\")\n    public BaseModel<String> template(@PathVariable String env) {\n        return BaseModel.getInstance(TemplateConfigLoader.loadInstanceConfig());\n    }\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/controller/NodeServerController.java",
    "content": "package com.alibaba.otter.canal.admin.controller;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.DeleteMapping;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.PutMapping;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport com.alibaba.otter.canal.admin.model.BaseModel;\nimport com.alibaba.otter.canal.admin.model.NodeServer;\nimport com.alibaba.otter.canal.admin.model.Pager;\nimport com.alibaba.otter.canal.admin.service.NodeServerService;\n\n/**\n * 节点信息控制层\n *\n * @author rewerma 2019-07-13 下午05:12:16\n * @version 1.0.0\n */\n@RestController\n@RequestMapping(\"/api/{env}\")\npublic class NodeServerController {\n\n    @Autowired\n    NodeServerService nodeServerService;\n\n    /**\n     * 获取所有节点信息列表\n     *\n     * @param nodeServer 筛选条件\n     * @param env 环境变量\n     * @return 节点信息列表\n     */\n    @GetMapping(value = \"/nodeServers\")\n    public BaseModel<Pager<NodeServer>> nodeServers(NodeServer nodeServer, Pager<NodeServer> pager,\n                                                    @PathVariable String env) {\n        return BaseModel.getInstance(nodeServerService.findList(nodeServer, pager));\n    }\n\n    /**\n     * 保存节点信息\n     *\n     * @param nodeServer 节点信息\n     * @param env 环境变量\n     * @return 是否成功\n     */\n    @PostMapping(value = \"/nodeServer\")\n    public BaseModel<String> save(@RequestBody NodeServer nodeServer, @PathVariable String env) {\n        nodeServerService.save(nodeServer);\n        return BaseModel.getInstance(\"success\");\n    }\n\n    /**\n     * 获取节点信息详情\n     *\n     * @param id 节点信息id\n     * @param env 环境变量\n     * @return 检点信息\n     */\n    @GetMapping(value = \"/nodeServer/{id}\")\n    public BaseModel<NodeServer> detail(@PathVariable Long id, @PathVariable String env) {\n        return BaseModel.getInstance(nodeServerService.detail(id));\n    }\n\n    /**\n     * 修改节点信息\n     *\n     * @param nodeServer 节点信息\n     * @param env 环境变量\n     * @return 是否成功\n     */\n    @PutMapping(value = \"/nodeServer\")\n    public BaseModel<String> update(@RequestBody NodeServer nodeServer, @PathVariable String env) {\n        nodeServerService.update(nodeServer);\n        return BaseModel.getInstance(\"success\");\n    }\n\n    /**\n     * 删除节点信息\n     *\n     * @param id 节点信息id\n     * @param env 环境变量\n     * @return 是否成功\n     */\n    @DeleteMapping(value = \"/nodeServer/{id}\")\n    public BaseModel<String> delete(@PathVariable Long id, @PathVariable String env) {\n        nodeServerService.delete(id);\n        return BaseModel.getInstance(\"success\");\n    }\n\n    /**\n     * 获取远程节点运行状态\n     *\n     * @param ip 节点ip\n     * @param port 节点端口\n     * @param env 环境变量\n     * @return 状态信息\n     */\n    @GetMapping(value = \"/nodeServer/status\")\n    public BaseModel<Integer> status(@RequestParam String ip, @RequestParam Integer port, @PathVariable String env) {\n        return BaseModel.getInstance(nodeServerService.remoteNodeStatus(ip, port));\n    }\n\n    /**\n     * 启动远程节点\n     *\n     * @param id 节点id\n     * @param env 环境变量\n     * @return 是否成功\n     */\n    @PutMapping(value = \"/nodeServer/start/{id}\")\n    public BaseModel<Boolean> start(@PathVariable Long id, @PathVariable String env) {\n        return BaseModel.getInstance(nodeServerService.remoteOperation(id, \"start\"));\n    }\n\n    /**\n     * 获取远程节点日志\n     *\n     * @param id 节点id\n     * @param env 环境变量\n     * @return 节点日志\n     */\n    @GetMapping(value = \"/nodeServer/log/{id}\")\n    public BaseModel<String> log(@PathVariable Long id, @PathVariable String env) {\n        return BaseModel.getInstance(nodeServerService.remoteCanalLog(id));\n    }\n\n    /**\n     * 关闭远程节点\n     *\n     * @param id 节点id\n     * @param env 环境变量\n     * @return 是否成功\n     */\n    @PutMapping(value = \"/nodeServer/stop/{id}\")\n    public BaseModel<Boolean> stop(@PathVariable Long id, @PathVariable String env) {\n        return BaseModel.getInstance(nodeServerService.remoteOperation(id, \"stop\"));\n    }\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/controller/PollingConfigController.java",
    "content": "package com.alibaba.otter.canal.admin.controller;\n\nimport java.security.NoSuchAlgorithmException;\n\nimport org.apache.commons.lang.RandomStringUtils;\nimport org.apache.commons.lang.StringUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.web.bind.annotation.*;\n\nimport com.alibaba.otter.canal.admin.model.BaseModel;\nimport com.alibaba.otter.canal.admin.model.CanalConfig;\nimport com.alibaba.otter.canal.admin.model.CanalInstanceConfig;\nimport com.alibaba.otter.canal.admin.service.PollingConfigService;\nimport com.alibaba.otter.canal.protocol.SecurityUtil;\n\n/**\n * Canal Instance配置管理控制层\n *\n * @author rewerma 2019-07-13 下午05:12:16\n * @version 1.0.0\n */\n@RestController\n@RequestMapping(\"/api/{env}/config\")\npublic class PollingConfigController {\n\n    private static final byte[] seeds = RandomStringUtils.random(16).getBytes();\n\n    @Value(value = \"${canal.adminUser}\")\n    String                      user;\n\n    @Value(value = \"${canal.adminPasswd}\")\n    String                      passwd;\n\n    @Autowired\n    PollingConfigService        pollingConfigService;\n\n    /**\n     * 获取server全局配置\n     */\n    @GetMapping(value = \"/server_polling\")\n    public BaseModel<CanalConfig> canalConfigPoll(@RequestHeader String user, @RequestHeader String passwd,\n                                                  @RequestParam String ip, @RequestParam Integer port,\n                                                  @RequestParam String md5, @RequestParam boolean register,\n                                                  @RequestParam String cluster, @RequestParam String name,\n                                                  @PathVariable String env) {\n        if (!auth(user, passwd)) {\n            throw new RuntimeException(\"auth :\" + user + \" is failed\");\n        }\n\n        if (StringUtils.isEmpty(md5) && register) {\n            // do something\n            pollingConfigService.autoRegister(ip, port, cluster, StringUtils.trimToNull(name));\n        }\n\n        CanalConfig canalConfig = pollingConfigService.getChangedConfig(ip, port, md5);\n        return BaseModel.getInstance(canalConfig);\n    }\n\n    /**\n     * 获取单个instance的配置\n     */\n    @GetMapping(value = \"/instance_polling/{destination}\")\n    public BaseModel<CanalInstanceConfig> instanceConfigPoll(@RequestHeader String user, @RequestHeader String passwd,\n                                                             @PathVariable String env,\n                                                             @PathVariable String destination, @RequestParam String md5) {\n        if (!auth(user, passwd)) {\n            throw new RuntimeException(\"auth :\" + user + \" is failed\");\n        }\n\n        CanalInstanceConfig canalInstanceConfig = pollingConfigService.getInstanceConfig(destination, md5);\n        return BaseModel.getInstance(canalInstanceConfig);\n    }\n\n    /**\n     * 获取对应server(ip+port)所需要运行的instance列表\n     */\n    @GetMapping(value = \"/instances_polling\")\n    public BaseModel<CanalInstanceConfig> instancesPoll(@RequestHeader String user, @RequestHeader String passwd,\n                                                        @RequestParam String ip, @RequestParam Integer port,\n                                                        @RequestParam String md5, @PathVariable String env) {\n        if (!auth(user, passwd)) {\n            throw new RuntimeException(\"auth :\" + user + \" is failed\");\n        }\n\n        CanalInstanceConfig canalInstanceConfig = pollingConfigService.getInstancesConfig(ip, port, md5);\n        return BaseModel.getInstance(canalInstanceConfig);\n    }\n\n    private boolean auth(String user, String passwd) {\n        // 如果user/passwd密码为空,则任何用户账户都能登录\n        if ((StringUtils.isEmpty(this.user) || StringUtils.equals(this.user, user))) {\n            if (StringUtils.isEmpty(this.passwd)) {\n                return true;\n            } else if (StringUtils.isEmpty(passwd)) {\n                // 如果server密码有配置,客户端密码为空,则拒绝\n                return false;\n            }\n\n            try {\n                // manager这里保存了原始密码，反过来和canal发送过来的进行校验\n                byte[] passForClient = SecurityUtil.scramble411(this.passwd.getBytes(), seeds);\n                return SecurityUtil.scrambleServerAuth(passForClient, SecurityUtil.hexStr2Bytes(passwd), seeds);\n            } catch (NoSuchAlgorithmException e) {\n                return false;\n            }\n        }\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/controller/UserController.java",
    "content": "package com.alibaba.otter.canal.admin.controller;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.UUID;\nimport java.util.concurrent.TimeUnit;\n\nimport javax.servlet.http.HttpServletRequest;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.PutMapping;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport com.alibaba.otter.canal.admin.model.BaseModel;\nimport com.alibaba.otter.canal.admin.model.User;\nimport com.alibaba.otter.canal.admin.service.UserService;\nimport com.github.benmanes.caffeine.cache.Caffeine;\nimport com.github.benmanes.caffeine.cache.LoadingCache;\n\n/**\n * 用户管理控制层\n *\n * @author rewerma 2019-07-13 下午05:12:16\n * @version 1.0.0\n */\n@RestController\n@RequestMapping(\"/api/{env}/user\")\npublic class UserController {\n\n    public static final LoadingCache<String, User> loginUsers = Caffeine.newBuilder()\n                                                                  .maximumSize(10_000)\n                                                                  .expireAfterAccess(30, TimeUnit.MINUTES)\n                                                                  .build(key -> null); // 用户登录信息缓存\n\n    @Autowired\n    UserService                                    userService;\n\n    /**\n     * 用户登录\n     *\n     * @param user 账号密码\n     * @param env 环境变量\n     * @return token\n     */\n    @PostMapping(value = \"/login\")\n    public BaseModel<Map<String, String>> login(@RequestBody User user, @PathVariable String env) {\n        User loginUser = userService.find4Login(user.getUsername(), user.getPassword());\n        if (loginUser != null) {\n            Map<String, String> tokenResp = new HashMap<>();\n            String token = UUID.randomUUID().toString();\n            loginUsers.put(token, loginUser);\n            tokenResp.put(\"token\", token);\n            return BaseModel.getInstance(tokenResp);\n        } else {\n            BaseModel<Map<String, String>> model = BaseModel.getInstance(null);\n            model.setCode(40001);\n            model.setMessage(\"Invalid username or password\");\n            return model;\n        }\n    }\n\n    /**\n     * 获取用户信息\n     *\n     * @param token token\n     * @param env 环境变量\n     * @return 用户信息\n     */\n    @GetMapping(value = \"/info\")\n    public BaseModel<User> info(@RequestParam String token, @PathVariable String env) {\n        User user = loginUsers.getIfPresent(token);\n        if (user != null) {\n            return BaseModel.getInstance(user);\n        } else {\n            BaseModel<User> model = BaseModel.getInstance(null);\n            model.setCode(50014);\n            model.setMessage(\"Invalid token\");\n            return model;\n        }\n    }\n\n    /**\n     * 修改用户信息\n     *\n     * @param user 用户信息\n     * @param env 环境变量\n     * @param httpServletRequest httpServletRequest\n     * @return 是否成功\n     */\n    @PutMapping(value = \"\")\n    public BaseModel<String> update(@RequestBody User user, @PathVariable String env,\n                                    HttpServletRequest httpServletRequest) {\n        userService.update(user);\n        String token = (String) httpServletRequest.getAttribute(\"token\");\n        loginUsers.put(token, user);\n        return BaseModel.getInstance(\"success\");\n    }\n\n    /**\n     * 用户退出\n     *\n     * @param env 环境变量\n     * @return 是否成功\n     */\n    @PostMapping(value = \"/logout\")\n    public BaseModel<String> logout(@PathVariable String env) {\n        return BaseModel.getInstance(\"success\");\n    }\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/handler/CustomExceptionHandler.java",
    "content": "package com.alibaba.otter.canal.admin.handler;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.web.bind.annotation.ControllerAdvice;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.bind.annotation.ResponseStatus;\n\nimport com.alibaba.otter.canal.admin.common.exception.ServiceException;\nimport com.alibaba.otter.canal.admin.model.BaseModel;\n\n/**\n * MVC异常拦截器\n *\n * @author rewerma 2019-07-13 下午05:12:16\n * @version 1.0.0\n */\n@ControllerAdvice(annotations = ResponseBody.class)\npublic class CustomExceptionHandler {\n\n    private static Logger logger = LoggerFactory.getLogger(CustomExceptionHandler.class);\n\n    /**\n     * 通用异常处理\n     *\n     * @param e 异常\n     * @return\n     */\n    @ResponseBody\n    @ResponseStatus(HttpStatus.OK)\n    @ExceptionHandler(value = Exception.class)\n    public BaseModel commonExceptionHandle(Exception e) {\n        if (e instanceof ServiceException) {\n            logger.error(e.getMessage());\n        } else {\n            logger.error(e.getMessage(), e);\n        }\n        BaseModel res = new BaseModel();\n        res.setCode(50000);\n        res.setMessage(e.getMessage());\n        return res;\n    }\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/model/BaseModel.java",
    "content": "package com.alibaba.otter.canal.admin.model;\n\n/**\n * 基础Model\n *\n * @author rewerma 2019-07-13 下午05:12:16\n * @version 1.0.0\n */\npublic class BaseModel<T> {\n\n    private Integer code = 20000;\n    private String  message;\n    private T       data;\n\n    public Integer getCode() {\n        return code;\n    }\n\n    public void setCode(Integer code) {\n        this.code = code;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n\n    public T getData() {\n        return data;\n    }\n\n    public void setData(T data) {\n        this.data = data;\n    }\n\n    public static <T> BaseModel<T> getInstance(T data) {\n        BaseModel<T> baseModel = new BaseModel<>();\n        baseModel.data = data;\n        return baseModel;\n    }\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/model/CanalCluster.java",
    "content": "package com.alibaba.otter.canal.admin.model;\n\nimport io.ebean.Finder;\nimport io.ebean.annotation.WhenModified;\n\nimport java.util.Date;\n\nimport javax.persistence.Entity;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\n\n/**\n * Canal集群信息实体类\n *\n * @author rewerma 2019-07-13 下午05:12:16\n * @version 1.0.0\n */\n@Entity\n@Table(name = \"canal_cluster\")\npublic class CanalCluster extends Model {\n\n    public static final CanalClusterFinder find = new CanalClusterFinder();\n\n    public static class CanalClusterFinder extends Finder<Long, CanalCluster> {\n\n        /**\n         * Construct using the default EbeanServer.\n         */\n        public CanalClusterFinder(){\n            super(CanalCluster.class);\n        }\n\n    }\n\n    @Id\n    private Long   id;\n    private String name;\n    private String zkHosts;\n    @WhenModified\n    private Date   modifiedTime;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getZkHosts() {\n        return zkHosts;\n    }\n\n    public void setZkHosts(String zkHosts) {\n        this.zkHosts = zkHosts;\n    }\n\n    public Date getModifiedTime() {\n        return modifiedTime;\n    }\n\n    public void setModifiedTime(Date modifiedTime) {\n        this.modifiedTime = modifiedTime;\n    }\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/model/CanalConfig.java",
    "content": "package com.alibaba.otter.canal.admin.model;\n\nimport io.ebean.Finder;\nimport io.ebean.annotation.WhenModified;\n\nimport java.util.Date;\n\nimport javax.persistence.Entity;\nimport javax.persistence.Id;\n\n/**\n * Canal主配置实体类\n *\n * @author rewerma 2019-07-13 下午05:12:16\n * @version 1.0.0\n */\n@Entity\npublic class CanalConfig extends Model {\n\n    public static final CanalConfigFinder find = new CanalConfigFinder();\n\n    public static class CanalConfigFinder extends Finder<Long, CanalConfig> {\n\n        /**\n         * Construct using the default EbeanServer.\n         */\n        public CanalConfigFinder(){\n            super(CanalConfig.class);\n        }\n\n    }\n\n    @Id\n    private Long   id;\n    private Long   clusterId;\n    private Long   serverId;\n    private String name;\n    private String content;\n    private String contentMd5;\n    private String status;\n    @WhenModified\n    private Date   modifiedTime;\n\n    public void init() {\n        this.name = \"canal.properties\";\n    }\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public Long getClusterId() {\n        return clusterId;\n    }\n\n    public void setClusterId(Long clusterId) {\n        this.clusterId = clusterId;\n    }\n\n    public Long getServerId() {\n        return serverId;\n    }\n\n    public void setServerId(Long serverId) {\n        this.serverId = serverId;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getContent() {\n        return content;\n    }\n\n    public void setContent(String content) {\n        this.content = content;\n    }\n\n    public String getContentMd5() {\n        return contentMd5;\n    }\n\n    public void setContentMd5(String contentMd5) {\n        this.contentMd5 = contentMd5;\n    }\n\n    public Date getModifiedTime() {\n        return modifiedTime;\n    }\n\n    public void setModifiedTime(Date modifiedTime) {\n        this.modifiedTime = modifiedTime;\n    }\n\n    public String getStatus() {\n        return status;\n    }\n\n    public void setStatus(String status) {\n        this.status = status;\n    }\n\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/model/CanalInstanceConfig.java",
    "content": "package com.alibaba.otter.canal.admin.model;\n\nimport io.ebean.Finder;\nimport io.ebean.annotation.WhenModified;\n\nimport java.util.Date;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.FetchType;\nimport javax.persistence.Id;\nimport javax.persistence.JoinColumn;\nimport javax.persistence.ManyToOne;\nimport javax.persistence.Transient;\n\n/**\n * Canal实例配置信息实体类\n *\n * @author rewerma 2019-07-13 下午05:12:16\n * @version 1.0.0\n */\n@Entity\npublic class CanalInstanceConfig extends Model {\n\n    public static final CanalInstanceConfigFinder find = new CanalInstanceConfigFinder();\n\n    public static class CanalInstanceConfigFinder extends Finder<Long, CanalInstanceConfig> {\n\n        /**\n         * Construct using the default EbeanServer.\n         */\n        public CanalInstanceConfigFinder(){\n            super(CanalInstanceConfig.class);\n        }\n\n    }\n\n    @Id\n    private Long         id;\n    @Column(name = \"cluster_id\")\n    private Long         clusterId;\n    @ManyToOne(fetch = FetchType.LAZY)\n    @JoinColumn(name = \"cluster_id\", updatable = false, insertable = false)\n    private CanalCluster canalCluster;\n    @Column(name = \"server_id\")\n    private Long         serverId;\n    @ManyToOne(fetch = FetchType.LAZY)\n    @JoinColumn(name = \"server_id\", updatable = false, insertable = false)\n    private NodeServer   nodeServer;\n    private String       name;\n    private String       content;\n    private String       contentMd5;\n    private String       status;             // 1: 正常 0: 停止\n    @WhenModified\n    private Date         modifiedTime;\n\n    @Transient\n    private String       clusterServerId;\n    @Transient\n    private String       runningStatus = \"0\"; // 1: 运行中 0: 停止\n\n    public void init() {\n        status = \"1\";\n    }\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public Long getClusterId() {\n        return clusterId;\n    }\n\n    public void setClusterId(Long clusterId) {\n        this.clusterId = clusterId;\n    }\n\n    public CanalCluster getCanalCluster() {\n        return canalCluster;\n    }\n\n    public void setCanalCluster(CanalCluster canalCluster) {\n        this.canalCluster = canalCluster;\n    }\n\n    public Long getServerId() {\n        return serverId;\n    }\n\n    public void setServerId(Long serverId) {\n        this.serverId = serverId;\n    }\n\n    public NodeServer getNodeServer() {\n        return nodeServer;\n    }\n\n    public void setNodeServer(NodeServer nodeServer) {\n        this.nodeServer = nodeServer;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getContent() {\n        return content;\n    }\n\n    public void setContent(String content) {\n        this.content = content;\n    }\n\n    public String getContentMd5() {\n        return contentMd5;\n    }\n\n    public void setContentMd5(String contentMd5) {\n        this.contentMd5 = contentMd5;\n    }\n\n    public String getStatus() {\n        return status;\n    }\n\n    public void setStatus(String status) {\n        this.status = status;\n    }\n\n    public Date getModifiedTime() {\n        return modifiedTime;\n    }\n\n    public void setModifiedTime(Date modifiedTime) {\n        this.modifiedTime = modifiedTime;\n    }\n\n    public String getClusterServerId() {\n        return clusterServerId;\n    }\n\n    public void setClusterServerId(String clusterServerId) {\n        this.clusterServerId = clusterServerId;\n    }\n\n    public String getRunningStatus() {\n        return runningStatus;\n    }\n\n    public void setRunningStatus(String runningStatus) {\n        this.runningStatus = runningStatus;\n    }\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/model/Model.java",
    "content": "package com.alibaba.otter.canal.admin.model;\n\nimport io.ebean.Ebean;\nimport io.ebean.EbeanServer;\n\nimport javax.persistence.MappedSuperclass;\nimport javax.persistence.OptimisticLockException;\n\nimport org.apache.commons.beanutils.PropertyUtils;\n\n/**\n * EBean Model扩展类\n *\n * @author rewerma 2019-07-13 下午05:12:16\n * @version 1.0.0\n */\n@MappedSuperclass\npublic abstract class Model extends io.ebean.Model {\n\n    public void init() {\n    }\n\n    public void save() {\n        init();\n        super.save();\n    }\n\n    public void insert() {\n        init();\n        super.insert();\n    }\n\n    public void saveOrUpdate() {\n        try {\n            EbeanServer ebeanServer = Ebean.getDefaultServer();\n            Object id = ebeanServer.getBeanId(this);\n            if (id == null) {\n                init();\n                this.save();\n            } else {\n                this.update();\n            }\n        } catch (Exception e) {\n            throw new OptimisticLockException(e);\n        }\n    }\n\n    public void update(String... propertiesNames) {\n        try {\n            EbeanServer ebeanServer = Ebean.getDefaultServer();\n            Object id = ebeanServer.getBeanId(this);\n            if (id == null) {\n                return;\n            }\n            Object model = ebeanServer.createQuery(this.getClass()).where().idEq(id).findOne();\n            if (model == null) {\n                return;\n            }\n            for (String propertyName : propertiesNames) {\n                if (propertyName.startsWith(\"nn:\")) { // not null\n                    propertyName = propertyName.substring(3);\n                    Object val = PropertyUtils.getProperty(this, propertyName);\n                    if (val != null) {\n                        PropertyUtils.setProperty(model, propertyName, val);\n                    }\n                } else {\n                    Object val = PropertyUtils.getProperty(this, propertyName);\n                    PropertyUtils.setProperty(model, propertyName, val);\n                }\n            }\n            ebeanServer.update(model);\n        } catch (Exception e) {\n            throw new OptimisticLockException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/model/NodeServer.java",
    "content": "package com.alibaba.otter.canal.admin.model;\n\nimport io.ebean.Finder;\nimport io.ebean.annotation.WhenModified;\n\nimport java.util.Date;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.FetchType;\nimport javax.persistence.Id;\nimport javax.persistence.JoinColumn;\nimport javax.persistence.ManyToOne;\nimport javax.persistence.Table;\n\n/**\n * 节点信息实体类\n *\n * @author rewerma 2019-07-13 下午05:12:16\n * @version 1.0.0\n */\n@Entity\n@Table(name = \"canal_node_server\")\npublic class NodeServer extends Model {\n\n    public static final NodeServerFinder find = new NodeServerFinder();\n\n    public static class NodeServerFinder extends Finder<Long, NodeServer> {\n\n        /**\n         * Construct using the default EbeanServer.\n         */\n        public NodeServerFinder(){\n            super(NodeServer.class);\n        }\n\n    }\n\n    @Id\n    private Long         id;\n    @ManyToOne(fetch = FetchType.LAZY)\n    @JoinColumn(name = \"cluster_id\", updatable = false, insertable = false)\n    private CanalCluster canalCluster;\n    @Column(name = \"cluster_id\")\n    private Long         clusterId;\n    private String       name;\n    private String       ip;\n    private Integer      adminPort;\n    private Integer      metricPort;\n    private Integer      tcpPort;\n    private String       status;\n    @WhenModified\n    private Date         modifiedTime;\n\n    public void init() {\n        status = \"-1\";\n    }\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public CanalCluster getCanalCluster() {\n        return canalCluster;\n    }\n\n    public void setCanalCluster(CanalCluster canalCluster) {\n        this.canalCluster = canalCluster;\n    }\n\n    public Long getClusterId() {\n        return clusterId;\n    }\n\n    public void setClusterId(Long clusterId) {\n        this.clusterId = clusterId;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getIp() {\n        return ip;\n    }\n\n    public void setIp(String ip) {\n        this.ip = ip;\n    }\n\n    public Integer getAdminPort() {\n        return adminPort;\n    }\n\n    public void setAdminPort(Integer adminPort) {\n        this.adminPort = adminPort;\n    }\n\n    public Integer getMetricPort() {\n        return metricPort;\n    }\n\n    public void setMetricPort(Integer metricPort) {\n        this.metricPort = metricPort;\n    }\n\n    public Integer getTcpPort() {\n        return tcpPort;\n    }\n\n    public void setTcpPort(Integer tcpPort) {\n        this.tcpPort = tcpPort;\n    }\n\n    public String getStatus() {\n        return status;\n    }\n\n    public void setStatus(String status) {\n        this.status = status;\n    }\n\n    public Date getModifiedTime() {\n        return modifiedTime;\n    }\n\n    public void setModifiedTime(Date modifiedTime) {\n        this.modifiedTime = modifiedTime;\n    }\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/model/Pager.java",
    "content": "package com.alibaba.otter.canal.admin.model;\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class Pager<T> implements Serializable {\n\n    private static final long serialVersionUID = -986577815091763517L;\n\n    private Long              count            = 0L;\n    private List<T>           items            = new ArrayList<>();\n    private Integer           page             = 1;\n    private Integer           size             = 20;\n    private Long              offset           = 0L;\n\n    public Pager(){\n\n    }\n\n    public Pager(Integer page, Integer size){\n        this.page = page;\n        this.size = size;\n    }\n\n    public Pager(Long count, List<T> items){\n        this.count = count;\n        this.items = items;\n    }\n\n    public String toString() {\n        return \"PageResult[count=\" + this.count + \", items=\" + this.items + \"]\";\n    }\n\n    public Long getCount() {\n        return this.count;\n    }\n\n    public void setCount(Long count) {\n        this.count = count;\n    }\n\n    public List<T> getItems() {\n        return items;\n    }\n\n    public void setItems(List<T> items) {\n        this.items = items;\n    }\n\n    public Integer getPage() {\n        if (page == null) {\n            page = 1;\n        }\n        return page;\n    }\n\n    public void setPage(Integer page) {\n        this.page = page;\n    }\n\n    public Integer getSize() {\n        if (size == null) {\n            size = 20;\n        }\n        return size;\n    }\n\n    public void setSize(Integer size) {\n        this.size = size;\n    }\n\n    public Long getOffset() {\n        offset = (long) (getPage() - 1) * (long) getSize();\n        return offset;\n    }\n\n    public void setOffset(Long offset) {\n        this.offset = offset;\n    }\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/model/User.java",
    "content": "package com.alibaba.otter.canal.admin.model;\n\nimport io.ebean.Finder;\nimport io.ebean.annotation.WhenCreated;\n\nimport java.util.Date;\n\nimport javax.persistence.Entity;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\nimport javax.persistence.Transient;\n\n/**\n * 用户信息实体类\n */\n@Entity\n@Table(name = \"canal_user\")\npublic class User extends Model {\n\n    public static final UserFinder find = new UserFinder();\n\n    public static class UserFinder extends Finder<Long, User> {\n\n        /**\n         * Construct using the default EbeanServer.\n         */\n        public UserFinder(){\n            super(User.class);\n        }\n\n    }\n\n    @Id\n    private Long   id;\n    private String username;\n    private String password;\n    private String roles;\n    private String introduction;\n    private String avatar;\n    private String name;\n    @WhenCreated\n    private Date   creationDate;\n\n    @Transient\n    private String oldPassword;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public String getUsername() {\n        return username;\n    }\n\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    public String getRoles() {\n        return roles;\n    }\n\n    public void setRoles(String roles) {\n        this.roles = roles;\n    }\n\n    public String getIntroduction() {\n        return introduction;\n    }\n\n    public void setIntroduction(String introduction) {\n        this.introduction = introduction;\n    }\n\n    public String getAvatar() {\n        return avatar;\n    }\n\n    public void setAvatar(String avatar) {\n        this.avatar = avatar;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public Date getCreationDate() {\n        return creationDate;\n    }\n\n    public void setCreationDate(Date creationDate) {\n        this.creationDate = creationDate;\n    }\n\n    public String getOldPassword() {\n        return oldPassword;\n    }\n\n    public void setOldPassword(String oldPassword) {\n        this.oldPassword = oldPassword;\n    }\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/service/CanalClusterService.java",
    "content": "package com.alibaba.otter.canal.admin.service;\n\nimport java.util.List;\n\nimport com.alibaba.otter.canal.admin.model.CanalCluster;\n\npublic interface CanalClusterService {\n\n    void save(CanalCluster canalCluster);\n\n    CanalCluster detail(Long id);\n\n    void update(CanalCluster canalCluster);\n\n    void delete(Long id);\n\n    List<CanalCluster> findList(CanalCluster canalCluster);\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/service/CanalConfigService.java",
    "content": "package com.alibaba.otter.canal.admin.service;\n\nimport com.alibaba.otter.canal.admin.model.CanalConfig;\n\npublic interface CanalConfigService {\n\n    CanalConfig getCanalConfig(Long clusterId, Long serverId);\n\n    CanalConfig getCanalConfigSummary();\n\n    CanalConfig getAdapterConfig();\n\n    void updateContent(CanalConfig canalConfig);\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/service/CanalInstanceService.java",
    "content": "package com.alibaba.otter.canal.admin.service;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport com.alibaba.otter.canal.admin.model.CanalInstanceConfig;\nimport com.alibaba.otter.canal.admin.model.Pager;\n\n/**\n * Canal实例配置信息业务层接口\n *\n * @author rewerma 2019-07-13 下午05:12:16\n * @version 1.0.0\n */\npublic interface CanalInstanceService {\n\n    Pager<CanalInstanceConfig> findList(CanalInstanceConfig canalInstanceConfig, Pager<CanalInstanceConfig> pager);\n\n    void save(CanalInstanceConfig canalInstanceConfig);\n\n    CanalInstanceConfig detail(Long id);\n\n    void updateContent(CanalInstanceConfig canalInstanceConfig);\n\n    void delete(Long id);\n\n    Map<String, String> remoteInstanceLog(Long id, Long nodeId);\n\n    boolean remoteOperation(Long id, Long nodeId, String option);\n\n    boolean instanceOperation(Long id, String option);\n\n    List<CanalInstanceConfig> findActiveInstanceByServerId(Long serverId);\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/service/NodeServerService.java",
    "content": "package com.alibaba.otter.canal.admin.service;\n\nimport java.util.List;\n\nimport com.alibaba.otter.canal.admin.model.NodeServer;\nimport com.alibaba.otter.canal.admin.model.Pager;\n\npublic interface NodeServerService {\n\n    void save(NodeServer nodeServer);\n\n    NodeServer detail(Long id);\n\n    void update(NodeServer nodeServer);\n\n    void delete(Long id);\n\n    List<NodeServer> findAll(NodeServer nodeServer);\n\n    Pager<NodeServer> findList(NodeServer nodeServer, Pager<NodeServer> pager);\n\n    int remoteNodeStatus(String ip, Integer port);\n\n    String remoteCanalLog(Long id);\n\n    boolean remoteOperation(Long id, String option);\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/service/PollingConfigService.java",
    "content": "package com.alibaba.otter.canal.admin.service;\n\nimport com.alibaba.otter.canal.admin.model.CanalConfig;\nimport com.alibaba.otter.canal.admin.model.CanalInstanceConfig;\n\npublic interface PollingConfigService {\n\n    public boolean autoRegister(String ip, Integer adminPort, String cluster, String name);\n\n    CanalConfig getChangedConfig(String ip, Integer port, String md5);\n\n    CanalInstanceConfig getInstancesConfig(String ip, Integer port, String md5);\n\n    CanalInstanceConfig getInstanceConfig(String destination, String md5);\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/service/UserService.java",
    "content": "package com.alibaba.otter.canal.admin.service;\n\nimport com.alibaba.otter.canal.admin.model.User;\n\npublic interface UserService {\n\n    User find4Login(String username, String password);\n\n    void update(User user);\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/service/impl/CanalClusterServiceImpl.java",
    "content": "package com.alibaba.otter.canal.admin.service.impl;\n\nimport io.ebean.Query;\n\nimport java.util.List;\n\nimport org.springframework.stereotype.Service;\n\nimport com.alibaba.otter.canal.admin.common.exception.ServiceException;\nimport com.alibaba.otter.canal.admin.model.CanalCluster;\nimport com.alibaba.otter.canal.admin.model.CanalInstanceConfig;\nimport com.alibaba.otter.canal.admin.model.NodeServer;\nimport com.alibaba.otter.canal.admin.service.CanalClusterService;\n\n@Service\npublic class CanalClusterServiceImpl implements CanalClusterService {\n\n    public void save(CanalCluster canalCluster) {\n        canalCluster.save();\n    }\n\n    public CanalCluster detail(Long id) {\n        return CanalCluster.find.byId(id);\n    }\n\n    public void update(CanalCluster canalCluster) {\n        canalCluster.update(\"name\", \"zkHosts\");\n    }\n\n    public void delete(Long id) {\n        // 判断集群下是否存在server信息\n        int serverCnt = NodeServer.find.query().where().eq(\"clusterId\", id).findCount();\n        if (serverCnt > 0) {\n            throw new ServiceException(\"当前集群下存在Server, 无法删除\");\n        }\n\n        // 判断集群下是否存在instance信息\n        int instanceCnt = CanalInstanceConfig.find.query().where().eq(\"clusterId\", id).findCount();\n        if (instanceCnt > 0) {\n            throw new ServiceException(\"当前集群下存在Instance配置，无法删除\");\n        }\n\n        CanalCluster canalCluster = CanalCluster.find.byId(id);\n        if (canalCluster != null) {\n            canalCluster.delete();\n        }\n    }\n\n    public List<CanalCluster> findList(CanalCluster canalCluster) {\n        Query<CanalCluster> query = CanalCluster.find.query();\n        query.order().asc(\"id\");\n        return query.findList();\n    }\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/service/impl/CanalConfigServiceImpl.java",
    "content": "package com.alibaba.otter.canal.admin.service.impl;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.Date;\n\nimport org.apache.commons.io.IOUtils;\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.stereotype.Service;\n\nimport com.alibaba.otter.canal.admin.common.exception.ServiceException;\nimport com.alibaba.otter.canal.admin.model.CanalConfig;\nimport com.alibaba.otter.canal.admin.model.NodeServer;\nimport com.alibaba.otter.canal.admin.service.CanalConfigService;\nimport com.alibaba.otter.canal.protocol.SecurityUtil;\n\n/**\n * Canal配置信息业务层\n *\n * @author rewerma 2019-07-13 下午05:12:16\n * @version 1.0.0\n */\n@Service\npublic class CanalConfigServiceImpl implements CanalConfigService {\n\n    private Logger              logger               = LoggerFactory.getLogger(CanalConfigServiceImpl.class);\n\n    private static final String CANAL_GLOBAL_CONFIG  = \"canal.properties\";\n    private static final String CANAL_ADAPTER_CONFIG = \"application.yml\";\n\n    public CanalConfig getCanalConfig(Long clusterId, Long serverId) {\n        CanalConfig config = null;\n        if (clusterId != null && clusterId != 0) {\n            config = CanalConfig.find.query().where().eq(\"clusterId\", clusterId).findOne();\n        } else if (serverId != null && serverId != 0) {\n            config = CanalConfig.find.query().where().eq(\"serverId\", serverId).findOne();\n            if (config == null) {\n                NodeServer nodeServer = NodeServer.find.byId(serverId);\n                if (nodeServer != null) {\n                    Long cid = nodeServer.getClusterId();\n                    if (cid != null) {\n                        config = CanalConfig.find.query().where().eq(\"clusterId\", cid).findOne();\n                    }\n                }\n            }\n        } else {\n            throw new ServiceException(\"clusterId and serverId are all empty\");\n        }\n        if (config == null) {\n            config = new CanalConfig();\n            config.setName(CANAL_GLOBAL_CONFIG);\n            return config;\n        }\n\n        return config;\n    }\n\n    public CanalConfig getCanalConfigSummary() {\n        return CanalConfig.find.query()\n            .setDisableLazyLoading(true)\n            .select(\"name, modifiedTime\")\n            .where()\n            .eq(\"id\", 1L)\n            .findOne();\n    }\n\n    public CanalConfig getAdapterConfig() {\n        long id = 2L;\n        CanalConfig config = CanalConfig.find.byId(id);\n        if (config == null) {\n            String context = loadDefaultConf(CANAL_ADAPTER_CONFIG);\n            if (context == null) {\n                return null;\n            }\n\n            config = new CanalConfig();\n            config.setId(id);\n            config.setName(CANAL_ADAPTER_CONFIG);\n            config.setModifiedTime(new Date());\n            config.setContent(context);\n            return config;\n        }\n\n        return config;\n    }\n\n    public void updateContent(CanalConfig canalConfig) {\n        try {\n            String contentMd5 = SecurityUtil.md5String(canalConfig.getContent());\n            canalConfig.setContentMd5(contentMd5);\n        } catch (NoSuchAlgorithmException e) {\n            // ignore\n        }\n        if (canalConfig.getId() != null) {\n            CanalConfig canalConfigTmp = CanalConfig.find.byId(canalConfig.getId());\n            if (canalConfigTmp != null && canalConfigTmp.getClusterId() != null) {\n                canalConfig.setServerId(null);\n            }\n            canalConfig.update(\"serverId\", \"content\", \"contentMd5\");\n        } else {\n            canalConfig.save();\n        }\n    }\n\n    private String loadDefaultConf(String confFileName) {\n        InputStream input = null;\n        try {\n            input = Thread.currentThread().getContextClassLoader().getResourceAsStream(\"conf/\" + confFileName);\n            if (input == null) {\n                return null;\n            }\n\n            return StringUtils.join(IOUtils.readLines(input), \"\\n\");\n        } catch (IOException e) {\n            logger.error(\"find \" + confFileName + \" is error!\", e);\n            return null;\n        } finally {\n            if (input != null) {\n                IOUtils.closeQuietly(input);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/service/impl/CanalInstanceServiceImpl.java",
    "content": "package com.alibaba.otter.canal.admin.service.impl;\n\nimport io.ebean.Query;\n\nimport java.security.NoSuchAlgorithmException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.springframework.stereotype.Service;\n\nimport com.alibaba.otter.canal.admin.common.Threads;\nimport com.alibaba.otter.canal.admin.common.exception.ServiceException;\nimport com.alibaba.otter.canal.admin.connector.AdminConnector;\nimport com.alibaba.otter.canal.admin.connector.SimpleAdminConnectors;\nimport com.alibaba.otter.canal.admin.model.CanalInstanceConfig;\nimport com.alibaba.otter.canal.admin.model.NodeServer;\nimport com.alibaba.otter.canal.admin.model.Pager;\nimport com.alibaba.otter.canal.admin.service.CanalInstanceService;\nimport com.alibaba.otter.canal.protocol.SecurityUtil;\nimport com.google.common.collect.Lists;\n\n/**\n * Canal实例配置信息业务层\n *\n * @author rewerma 2019-07-13 下午05:12:16\n * @version 1.0.0\n */\n@Service\npublic class CanalInstanceServiceImpl implements CanalInstanceService {\n\n    public Pager<CanalInstanceConfig> findList(CanalInstanceConfig canalInstanceConfig, Pager<CanalInstanceConfig> pager) {\n        Query<CanalInstanceConfig> query = CanalInstanceConfig.find.query()\n            .setDisableLazyLoading(true)\n            .select(\"clusterId, serverId, name, modifiedTime\")\n            .fetch(\"canalCluster\", \"name\")\n            .fetch(\"nodeServer\", \"name,ip,adminPort\");\n        if (canalInstanceConfig != null) {\n            if (StringUtils.isNotEmpty(canalInstanceConfig.getName())) {\n                query.where().like(\"name\", \"%\" + canalInstanceConfig.getName() + \"%\");\n            }\n            if (StringUtils.isNotEmpty(canalInstanceConfig.getClusterServerId())) {\n                if (canalInstanceConfig.getClusterServerId().startsWith(\"cluster:\")) {\n                    query.where()\n                        .eq(\"clusterId\", Long.parseLong(canalInstanceConfig.getClusterServerId().substring(8)));\n                } else if (canalInstanceConfig.getClusterServerId().startsWith(\"server:\")) {\n                    query.where().eq(\"serverId\", Long.parseLong(canalInstanceConfig.getClusterServerId().substring(7)));\n                }\n            }\n        }\n\n        Query<CanalInstanceConfig> queryCnt = query.copy();\n        int count = queryCnt.findCount();\n        pager.setCount((long) count);\n\n        query.setFirstRow(pager.getOffset().intValue()).setMaxRows(pager.getSize()).order().asc(\"id\");\n        List<CanalInstanceConfig> canalInstanceConfigs = query.findList();\n        pager.setItems(canalInstanceConfigs);\n\n        if (canalInstanceConfigs.isEmpty()) {\n            return pager;\n        }\n\n        // check all canal instances running status\n        List<Future<Void>> futures = new ArrayList<>(canalInstanceConfigs.size());\n        for (CanalInstanceConfig canalInstanceConfig1 : canalInstanceConfigs) {\n            futures.add(Threads.executorService.submit(() -> {\n                List<NodeServer> nodeServers;\n                if (canalInstanceConfig1.getClusterId() != null) { // 集群模式\n                    nodeServers = NodeServer.find.query()\n                        .where()\n                        .eq(\"clusterId\", canalInstanceConfig1.getClusterId())\n                        .findList();\n                } else if (canalInstanceConfig1.getServerId() != null) { // 单机模式\n                    nodeServers = Collections.singletonList(canalInstanceConfig1.getNodeServer());\n                } else {\n                    return null;\n                }\n\n                for (NodeServer nodeServer : nodeServers) {\n                    String runningInstances = SimpleAdminConnectors.execute(nodeServer.getIp(),\n                        nodeServer.getAdminPort(),\n                        AdminConnector::getRunningInstances);\n                    if (runningInstances == null) {\n                        continue;\n                    }\n                    String[] instances = runningInstances.split(\",\");\n                    for (String instance : instances) {\n                        if (instance.equals(canalInstanceConfig1.getName())) {\n                            // 集群模式下server对象为空\n                            if (canalInstanceConfig1.getNodeServer() == null) {\n                                canalInstanceConfig1.setNodeServer(nodeServer);\n                            }\n                            canalInstanceConfig1.setRunningStatus(\"1\");\n                            break;\n                        }\n                    }\n                }\n\n                return null;\n            }));\n        }\n\n        for (Future<Void> f : futures) {\n            try {\n                f.get(3, TimeUnit.SECONDS);\n            } catch (InterruptedException | ExecutionException e) {\n                // ignore\n            } catch (TimeoutException e) {\n                break;\n            }\n        }\n        return pager;\n    }\n\n    /**\n     * 通过Server id获取当前Server下所有运行的Instance\n     *\n     * @param serverId server id\n     */\n    public List<CanalInstanceConfig> findActiveInstanceByServerId(Long serverId) {\n        NodeServer nodeServer = NodeServer.find.byId(serverId);\n        if (nodeServer == null) {\n            return null;\n        }\n        String runningInstances = SimpleAdminConnectors.execute(nodeServer.getIp(),\n            nodeServer.getAdminPort(),\n            AdminConnector::getRunningInstances);\n        if (runningInstances == null) {\n            return null;\n        }\n\n        String[] instances = runningInstances.split(\",\");\n        Object obj[] = Lists.newArrayList(instances).toArray();\n        // 单机模式和集群模式区分处理\n        if (nodeServer.getClusterId() != null) { // 集群模式\n            List<CanalInstanceConfig> list = CanalInstanceConfig.find.query()\n                .setDisableLazyLoading(true)\n                .select(\"clusterId, serverId, name, modifiedTime\")\n                .where()\n                // 暂停的实例也显示 .eq(\"status\", \"1\")\n                .in(\"name\", obj)\n                .findList();\n            list.forEach(config -> config.setRunningStatus(\"1\"));\n            return list; // 集群模式直接返回当前运行的Instances\n        } else { // 单机模式\n            // 当前Server所配置的所有Instance\n            List<CanalInstanceConfig> list = CanalInstanceConfig.find.query()\n                .setDisableLazyLoading(true)\n                .select(\"clusterId, serverId, name, modifiedTime\")\n                .where()\n                // 暂停的实例也显示 .eq(\"status\", \"1\")\n                .eq(\"serverId\", serverId)\n                .findList();\n            List<String> instanceList = Arrays.asList(instances);\n            list.forEach(config -> {\n                if (instanceList.contains(config.getName())) {\n                    config.setRunningStatus(\"1\");\n                }\n            });\n            return list;\n        }\n    }\n\n    public void save(CanalInstanceConfig canalInstanceConfig) {\n        if (StringUtils.isEmpty(canalInstanceConfig.getClusterServerId())) {\n            throw new ServiceException(\"empty cluster or server id\");\n        }\n        if (canalInstanceConfig.getClusterServerId().startsWith(\"cluster:\")) {\n            Long clusterId = Long.parseLong(canalInstanceConfig.getClusterServerId().substring(8));\n            canalInstanceConfig.setClusterId(clusterId);\n        } else if (canalInstanceConfig.getClusterServerId().startsWith(\"server:\")) {\n            Long serverId = Long.parseLong(canalInstanceConfig.getClusterServerId().substring(7));\n            canalInstanceConfig.setServerId(serverId);\n        }\n\n        try {\n            String contentMd5 = SecurityUtil.md5String(canalInstanceConfig.getContent());\n            canalInstanceConfig.setContentMd5(contentMd5);\n        } catch (NoSuchAlgorithmException e) {\n            // ignore\n        }\n\n        canalInstanceConfig.insert();\n    }\n\n    public CanalInstanceConfig detail(Long id) {\n        CanalInstanceConfig canalInstanceConfig = CanalInstanceConfig.find.byId(id);\n        if (canalInstanceConfig != null) {\n            if (canalInstanceConfig.getClusterId() != null) {\n                canalInstanceConfig.setClusterServerId(\"cluster:\" + canalInstanceConfig.getClusterId());\n            } else if (canalInstanceConfig.getServerId() != null) {\n                canalInstanceConfig.setClusterServerId(\"server:\" + canalInstanceConfig.getServerId());\n            }\n        }\n        return canalInstanceConfig;\n    }\n\n    public void updateContent(CanalInstanceConfig canalInstanceConfig) {\n        if (StringUtils.isEmpty(canalInstanceConfig.getClusterServerId())) {\n            throw new ServiceException(\"empty cluster or server id\");\n        }\n        if (canalInstanceConfig.getClusterServerId().startsWith(\"cluster:\")) {\n            Long clusterId = Long.parseLong(canalInstanceConfig.getClusterServerId().substring(8));\n            canalInstanceConfig.setClusterId(clusterId);\n            canalInstanceConfig.setServerId(null);\n        } else if (canalInstanceConfig.getClusterServerId().startsWith(\"server:\")) {\n            Long serverId = Long.parseLong(canalInstanceConfig.getClusterServerId().substring(7));\n            canalInstanceConfig.setServerId(serverId);\n            canalInstanceConfig.setClusterId(null);\n        }\n\n        try {\n            String contentMd5 = SecurityUtil.md5String(canalInstanceConfig.getContent());\n            canalInstanceConfig.setContentMd5(contentMd5);\n        } catch (NoSuchAlgorithmException e) {\n            // ignore\n        }\n\n        canalInstanceConfig.update(\"content\", \"contentMd5\", \"clusterId\", \"serverId\");\n    }\n\n    public void delete(Long id) {\n        CanalInstanceConfig canalInstanceConfig = CanalInstanceConfig.find.byId(id);\n        if (canalInstanceConfig != null) {\n            canalInstanceConfig.delete();\n        }\n    }\n\n    public Map<String, String> remoteInstanceLog(Long id, Long nodeId) {\n        Map<String, String> result = new HashMap<>();\n\n        NodeServer nodeServer = NodeServer.find.byId(nodeId);\n        if (nodeServer == null) {\n            return result;\n        }\n        CanalInstanceConfig canalInstanceConfig = CanalInstanceConfig.find.byId(id);\n        if (canalInstanceConfig == null) {\n            return result;\n        }\n\n        String log = SimpleAdminConnectors.execute(nodeServer.getIp(),\n            nodeServer.getAdminPort(),\n            adminConnector -> adminConnector.instanceLog(canalInstanceConfig.getName(), null, 100));\n\n        result.put(\"instance\", canalInstanceConfig.getName());\n        result.put(\"log\", log);\n        return result;\n    }\n\n    public boolean remoteOperation(Long id, Long nodeId, String option) {\n        NodeServer nodeServer = null;\n        if (\"start\".equals(option)) {\n            if (nodeId != null) {\n                nodeServer = NodeServer.find.byId(nodeId);\n            } else {\n                nodeServer = NodeServer.find.query().findOne();\n            }\n        } else {\n            if (nodeId == null) {\n                return false;\n            }\n            nodeServer = NodeServer.find.byId(nodeId);\n        }\n        if (nodeServer == null) {\n            return false;\n        }\n        CanalInstanceConfig canalInstanceConfig = CanalInstanceConfig.find.byId(id);\n        if (canalInstanceConfig == null) {\n            return false;\n        }\n        Boolean result = null;\n        if (\"start\".equals(option)) {\n            if (nodeServer.getClusterId() == null) { // 非集群模式\n                return instanceOperation(id, \"start\");\n            } else {\n                throw new ServiceException(\"集群模式不允许指定server启动\");\n            }\n        } else if (\"stop\".equals(option)) {\n            if (nodeServer.getClusterId() != null) {\n                // 集群模式,通知主动释放\n                result = SimpleAdminConnectors.execute(nodeServer.getIp(),\n                    nodeServer.getAdminPort(),\n                    adminConnector -> adminConnector.releaseInstance(canalInstanceConfig.getName()));\n            } else { // 非集群模式下直接将状态置为0\n                return instanceOperation(id, \"stop\");\n            }\n        } else {\n            return false;\n        }\n\n        if (result == null) {\n            result = false;\n        }\n        return result;\n    }\n\n    public boolean instanceOperation(Long id, String option) {\n        CanalInstanceConfig canalInstanceConfig = CanalInstanceConfig.find.byId(id);\n        if (canalInstanceConfig == null) {\n            return false;\n        }\n        if (\"stop\".equals(option)) {\n            canalInstanceConfig.setStatus(\"0\");\n            canalInstanceConfig.update(\"status\");\n        } else if (\"start\".equals(option)) {\n            canalInstanceConfig.setStatus(\"1\");\n            canalInstanceConfig.update(\"status\");\n        } else {\n            return false;\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/service/impl/NodeServerServiceImpl.java",
    "content": "package com.alibaba.otter.canal.admin.service.impl;\n\nimport io.ebean.Query;\n\nimport java.security.NoSuchAlgorithmException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.springframework.stereotype.Service;\n\nimport com.alibaba.otter.canal.admin.common.TemplateConfigLoader;\nimport com.alibaba.otter.canal.admin.common.Threads;\nimport com.alibaba.otter.canal.admin.common.exception.ServiceException;\nimport com.alibaba.otter.canal.admin.connector.AdminConnector;\nimport com.alibaba.otter.canal.admin.connector.SimpleAdminConnectors;\nimport com.alibaba.otter.canal.admin.model.CanalConfig;\nimport com.alibaba.otter.canal.admin.model.CanalInstanceConfig;\nimport com.alibaba.otter.canal.admin.model.NodeServer;\nimport com.alibaba.otter.canal.admin.model.Pager;\nimport com.alibaba.otter.canal.admin.service.NodeServerService;\nimport com.alibaba.otter.canal.protocol.SecurityUtil;\n\n/**\n * 节点信息业务层\n *\n * @author rewerma 2019-07-13 下午05:12:16\n * @version 1.0.0\n */\n@Service\npublic class NodeServerServiceImpl implements NodeServerService {\n\n    public void save(NodeServer nodeServer) {\n        int cnt = NodeServer.find.query()\n            .where()\n            .eq(\"ip\", nodeServer.getIp())\n            .eq(\"adminPort\", nodeServer.getAdminPort())\n            .findCount();\n        if (cnt > 0) {\n            throw new ServiceException(\"节点信息已存在\");\n        }\n\n        nodeServer.save();\n\n        if (nodeServer.getClusterId() == null) { // 单机模式\n            CanalConfig canalConfig = new CanalConfig();\n            canalConfig.setServerId(nodeServer.getId());\n            String configTmp = TemplateConfigLoader.loadCanalConfig();\n            canalConfig.setContent(configTmp);\n            try {\n                String contentMd5 = SecurityUtil.md5String(canalConfig.getContent());\n                canalConfig.setContentMd5(contentMd5);\n            } catch (NoSuchAlgorithmException e) {\n            }\n            canalConfig.save();\n        }\n    }\n\n    public NodeServer detail(Long id) {\n        return NodeServer.find.byId(id);\n    }\n\n    public void update(NodeServer nodeServer) {\n        int cnt = NodeServer.find.query()\n            .where()\n            .eq(\"ip\", nodeServer.getIp())\n            .eq(\"adminPort\", nodeServer.getAdminPort())\n            .ne(\"id\", nodeServer.getId())\n            .findCount();\n        if (cnt > 0) {\n            throw new ServiceException(\"节点信息已存在\");\n        }\n\n        nodeServer.update(\"name\", \"ip\", \"adminPort\", \"tcpPort\", \"metricPort\", \"clusterId\");\n    }\n\n    public void delete(Long id) {\n        NodeServer nodeServer = NodeServer.find.byId(id);\n        if (nodeServer != null) {\n            // 判断是否存在实例\n            int cnt = CanalInstanceConfig.find.query().where().eq(\"serverId\", nodeServer.getId()).findCount();\n            if (cnt > 0) {\n                throw new ServiceException(\"当前Server下存在Instance配置, 无法删除\");\n            }\n\n            // 同时删除配置\n            CanalConfig canalConfig = CanalConfig.find.query().where().eq(\"serverId\", id).findOne();\n            if (canalConfig != null) {\n                canalConfig.delete();\n            }\n\n            nodeServer.delete();\n        }\n    }\n\n    private Query<NodeServer> getBaseQuery(NodeServer nodeServer) {\n        Query<NodeServer> query = NodeServer.find.query();\n        query.fetch(\"canalCluster\", \"name\").setDisableLazyLoading(true);\n\n        if (nodeServer != null) {\n            if (StringUtils.isNotEmpty(nodeServer.getName())) {\n                query.where().like(\"name\", \"%\" + nodeServer.getName() + \"%\");\n            }\n            if (StringUtils.isNotEmpty(nodeServer.getIp())) {\n                query.where().eq(\"ip\", nodeServer.getIp());\n            }\n            if (nodeServer.getClusterId() != null) {\n                if (nodeServer.getClusterId() == -1) {\n                    query.where().isNull(\"clusterId\");\n                } else {\n                    query.where().eq(\"clusterId\", nodeServer.getClusterId());\n                }\n            }\n        }\n\n        return query;\n    }\n\n    public List<NodeServer> findAll(NodeServer nodeServer) {\n        Query<NodeServer> query = getBaseQuery(nodeServer);\n        query.order().asc(\"id\");\n        return query.findList();\n    }\n\n    public Pager<NodeServer> findList(NodeServer nodeServer, Pager<NodeServer> pager) {\n\n        Query<NodeServer> query = getBaseQuery(nodeServer);\n        Query<NodeServer> queryCnt = query.copy();\n\n        int count = queryCnt.findCount();\n        pager.setCount((long) count);\n\n        List<NodeServer> nodeServers = query.order()\n            .asc(\"id\")\n            .setFirstRow(pager.getOffset().intValue())\n            .setMaxRows(pager.getSize())\n            .findList();\n        pager.setItems(nodeServers);\n\n        if (nodeServers.isEmpty()) {\n            return pager;\n        }\n\n        List<Future<Boolean>> futures = new ArrayList<>(nodeServers.size());\n        // get all nodes status\n        for (NodeServer ns : nodeServers) {\n            futures.add(Threads.executorService.submit(() -> {\n                boolean status = SimpleAdminConnectors.execute(ns.getIp(), ns.getAdminPort(), AdminConnector::check);\n                ns.setStatus(status ? \"1\" : \"0\");\n                return !status;\n            }));\n        }\n        for (Future<Boolean> f : futures) {\n            try {\n                f.get(3, TimeUnit.SECONDS);\n            } catch (InterruptedException | ExecutionException e) {\n                // ignore\n            } catch (TimeoutException e) {\n                break;\n            }\n        }\n\n        return pager;\n    }\n\n    public int remoteNodeStatus(String ip, Integer port) {\n        boolean result = SimpleAdminConnectors.execute(ip, port, AdminConnector::check);\n        return result ? 1 : 0;\n    }\n\n    public String remoteCanalLog(Long id) {\n        NodeServer nodeServer = NodeServer.find.byId(id);\n        if (nodeServer == null) {\n            return \"\";\n        }\n        return SimpleAdminConnectors.execute(nodeServer.getIp(),\n            nodeServer.getAdminPort(),\n            adminConnector -> adminConnector.canalLog(100));\n    }\n\n    public boolean remoteOperation(Long id, String option) {\n        NodeServer nodeServer = NodeServer.find.byId(id);\n        if (nodeServer == null) {\n            return false;\n        }\n        Boolean result = null;\n        if (\"start\".equals(option)) {\n            result = SimpleAdminConnectors.execute(nodeServer.getIp(), nodeServer.getAdminPort(), AdminConnector::start);\n        } else if (\"stop\".equals(option)) {\n            result = SimpleAdminConnectors.execute(nodeServer.getIp(), nodeServer.getAdminPort(), AdminConnector::stop);\n        } else {\n            return false;\n        }\n\n        if (result == null) {\n            result = false;\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/service/impl/PollingConfigServiceImpl.java",
    "content": "package com.alibaba.otter.canal.admin.service.impl;\n\nimport java.security.NoSuchAlgorithmException;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.stream.Collectors;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport com.alibaba.otter.canal.admin.common.exception.ServiceException;\nimport com.alibaba.otter.canal.admin.model.CanalCluster;\nimport com.alibaba.otter.canal.admin.model.CanalConfig;\nimport com.alibaba.otter.canal.admin.model.CanalInstanceConfig;\nimport com.alibaba.otter.canal.admin.model.NodeServer;\nimport com.alibaba.otter.canal.admin.service.CanalClusterService;\nimport com.alibaba.otter.canal.admin.service.NodeServerService;\nimport com.alibaba.otter.canal.admin.service.PollingConfigService;\nimport com.alibaba.otter.canal.protocol.SecurityUtil;\nimport com.google.common.base.Joiner;\n\n@Service\npublic class PollingConfigServiceImpl implements PollingConfigService {\n\n    @Autowired\n    NodeServerService   nodeServerService;\n\n    @Autowired\n    CanalClusterService canalClusterService;\n\n    public boolean autoRegister(String ip, Integer adminPort, String cluster, String name) {\n        NodeServer server = NodeServer.find.query().where().eq(\"ip\", ip).eq(\"adminPort\", adminPort).findOne();\n        if (server == null) {\n            server = new NodeServer();\n            server.setName(Optional.ofNullable(name).orElse(ip));\n            server.setIp(ip);\n            server.setAdminPort(adminPort);\n            server.setTcpPort(adminPort + 1);\n            server.setMetricPort(adminPort + 2);\n            if (StringUtils.isNotEmpty(cluster)) {\n                CanalCluster clusterConfig = CanalCluster.find.query().where().eq(\"name\", cluster).findOne();\n                if (clusterConfig == null) {\n                    throw new ServiceException(\"auto cluster : \" + cluster + \" is not found.\");\n                }\n\n                server.setClusterId(clusterConfig.getId());\n            }\n            nodeServerService.save(server);\n        }\n\n        return true;\n    }\n\n    public CanalConfig getChangedConfig(String ip, Integer port, String md5) {\n        NodeServer server = NodeServer.find.query().where().eq(\"ip\", ip).eq(\"adminPort\", port).findOne();\n        if (server == null) {\n            return null;\n        }\n        CanalConfig canalConfig;\n        if (server.getClusterId() != null) { // 集群模式\n            canalConfig = CanalConfig.find.query().where().eq(\"clusterId\", server.getClusterId()).findOne();\n        } else { // 单机模式\n            canalConfig = CanalConfig.find.query().where().eq(\"serverId\", server.getId()).findOne();\n        }\n        if (canalConfig == null) {\n            throw new ServiceException(\"canal.properties config is empty\");\n        }\n\n        if (!canalConfig.getContentMd5().equals(md5)) { // 内容发生变化\n            return canalConfig;\n        }\n        return null;\n    }\n\n    public CanalInstanceConfig getInstancesConfig(String ip, Integer port, String md5) {\n        NodeServer server = NodeServer.find.query().where().eq(\"ip\", ip).eq(\"adminPort\", port).findOne();\n        if (server == null) {\n            return null;\n        }\n        List<CanalInstanceConfig> canalInstanceConfigs;\n        if (server.getClusterId() != null) { // 集群模式\n            canalInstanceConfigs = CanalInstanceConfig.find.query()\n                .where()\n                .eq(\"status\", \"1\")\n                .eq(\"clusterId\", server.getClusterId())\n                .findList(); // 取属于该集群的所有instance config\n        } else { // 单机模式\n            canalInstanceConfigs = CanalInstanceConfig.find.query()\n                .where()\n                .eq(\"status\", \"1\")\n                .eq(\"serverId\", server.getId())\n                .findList();\n        }\n\n        CanalInstanceConfig canalInstanceConfig = new CanalInstanceConfig();\n        List<String> instances = canalInstanceConfigs.stream()\n            .map(CanalInstanceConfig::getName)\n            .collect(Collectors.toList());\n        String data = Joiner.on(',').join(instances);\n        canalInstanceConfig.setContent(data);\n        if (!StringUtils.isEmpty(md5)) {\n            try {\n                String newMd5 = SecurityUtil.md5String(canalInstanceConfig.getContent());\n                if (StringUtils.equals(md5, newMd5)) {\n                    canalInstanceConfig.setContent(null);\n                }\n            } catch (NoSuchAlgorithmException e) {\n                // ignore\n            }\n        }\n        return canalInstanceConfig;\n    }\n\n    public CanalInstanceConfig getInstanceConfig(String destination, String md5) {\n        CanalInstanceConfig instanceConfig = CanalInstanceConfig.find.query().where().eq(\"name\", destination).findOne();\n        if (instanceConfig == null) {\n            return null;\n        }\n        if (StringUtils.isEmpty(md5)) {\n            return instanceConfig;\n        } else {\n            try {\n                String newMd5 = SecurityUtil.md5String(instanceConfig.getContent());\n                if (StringUtils.equals(md5, newMd5)) {\n                    instanceConfig.setContent(null);\n                }\n            } catch (NoSuchAlgorithmException e) {\n                // ignore\n            }\n\n            return instanceConfig;\n        }\n    }\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/service/impl/UserServiceImpl.java",
    "content": "package com.alibaba.otter.canal.admin.service.impl;\n\nimport java.security.NoSuchAlgorithmException;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.springframework.stereotype.Service;\n\nimport com.alibaba.otter.canal.admin.common.exception.ServiceException;\nimport com.alibaba.otter.canal.admin.model.User;\nimport com.alibaba.otter.canal.admin.service.UserService;\nimport com.alibaba.otter.canal.protocol.SecurityUtil;\n\n/**\n * 用户信息业务层\n *\n * @author rewerma 2019-07-13 下午05:12:16\n * @version 1.0.0\n */\n@Service\npublic class UserServiceImpl implements UserService {\n\n    private static byte[] seeds = \"canal is best!\".getBytes();\n\n    private static final Integer PASSWORD_LENGTH = 5;\n\n    public User find4Login(String username, String password) {\n        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {\n            return null;\n        }\n        User user = User.find.query().where().eq(\"username\", username).findOne();\n        if (user == null) {\n            throw new ServiceException(\"user:\" + username + \" auth failed!\");\n        }\n        try {\n            byte[] pass = SecurityUtil.scramble411(password.getBytes(), seeds);\n            if (!SecurityUtil.scrambleServerAuth(pass, SecurityUtil.hexStr2Bytes(user.getPassword()), seeds)) {\n                throw new ServiceException(\"user:\" + user.getName() + \" passwd incorrect!\");\n            }\n        } catch (NoSuchAlgorithmException e) {\n            throw new ServiceException(\"user:\" + user.getName() + \" auth failed!\");\n        }\n\n        user.setPassword(\"\");\n        return user;\n    }\n\n    public void update(User user) {\n        if (user.getPassword().length() < PASSWORD_LENGTH) {\n            throw new ServiceException(\"The new password is too short,must more than 6 digits\");\n        }\n        User userTmp = User.find.query().where().eq(\"username\", user.getUsername()).findOne();\n        if (userTmp == null) {\n            throw new ServiceException();\n        }\n\n        try {\n            byte[] pass = SecurityUtil.scramble411(user.getOldPassword().getBytes(), seeds);\n            if (!SecurityUtil.scrambleServerAuth(pass, SecurityUtil.hexStr2Bytes(userTmp.getPassword()), seeds)) {\n                throw new ServiceException(\"old passwd is unmatch\");\n            }\n\n            user.setId(userTmp.getId());\n            user.setPassword(SecurityUtil.scrambleGenPass(user.getPassword().getBytes()));\n        } catch (NoSuchAlgorithmException e) {\n            throw new ServiceException(\"passwd process failed\");\n        }\n\n        user.update(\"username\", \"nn:password\");\n    }\n}\n"
  },
  {
    "path": "admin/admin-web/src/main/resources/application.yml",
    "content": "server:\n  port: 8089\nspring:\n  jackson:\n    date-format: yyyy-MM-dd HH:mm:ss\n    time-zone: GMT+8\n\nspring.datasource:\n  address: 127.0.0.1:3306\n  database: canal_manager\n  username: canal\n  password: canal\n  driver-class-name: com.mysql.jdbc.Driver\n  url: jdbc:mysql://${spring.datasource.address}/${spring.datasource.database}?useUnicode=true&characterEncoding=UTF-8&useSSL=false\n  hikari:\n    maximum-pool-size: 30\n    minimum-idle: 1\n\ncanal:\n  adminUser: admin\n  adminPasswd:\n"
  },
  {
    "path": "admin/admin-web/src/main/resources/canal-template.properties",
    "content": "#################################################\n######### \t\tcommon argument\t\t#############\n#################################################\n# tcp bind ip\ncanal.ip =\n# register ip to zookeeper\ncanal.register.ip =\ncanal.port = 11111\ncanal.metrics.pull.port = 11112\n# canal instance user/passwd\n# canal.user = canal\n# canal.passwd = E3619321C1A937C46A0D8BD1DAC39F93B27D4458\n\n# canal admin config\n#canal.admin.manager = 127.0.0.1:8089\ncanal.admin.port = 11110\ncanal.admin.user = admin\ncanal.admin.passwd = 4ACFE3202A5FF5CF467898FC58AAB1D615029441\n# admin auto register\n#canal.admin.register.auto = true\n#canal.admin.register.cluster =\n#canal.admin.register.name =\n\ncanal.zkServers =\n# flush data to zk\ncanal.zookeeper.flush.period = 1000\ncanal.withoutNetty = false\n# tcp, kafka, rocketMQ, rabbitMQ, pulsarMQ\ncanal.serverMode = tcp\n# flush meta cursor/parse position to file\ncanal.file.data.dir = ${canal.conf.dir}\ncanal.file.flush.period = 1000\n## memory store RingBuffer size, should be Math.pow(2,n)\ncanal.instance.memory.buffer.size = 16384\n## memory store RingBuffer used memory unit size , default 1kb\ncanal.instance.memory.buffer.memunit = 1024 \n## meory store gets mode used MEMSIZE or ITEMSIZE\ncanal.instance.memory.batch.mode = MEMSIZE\ncanal.instance.memory.rawEntry = true\n\n## detecing config\ncanal.instance.detecting.enable = false\n#canal.instance.detecting.sql = insert into retl.xdual values(1,now()) on duplicate key update x=now()\ncanal.instance.detecting.sql = select 1\ncanal.instance.detecting.interval.time = 3\ncanal.instance.detecting.retry.threshold = 3\ncanal.instance.detecting.heartbeatHaEnable = false\n\n# support maximum transaction size, more than the size of the transaction will be cut into multiple transactions delivery\ncanal.instance.transaction.size =  1024\n# mysql fallback connected to new master should fallback times\ncanal.instance.fallbackIntervalInSeconds = 60\n\n# network config\ncanal.instance.network.receiveBufferSize = 16384\ncanal.instance.network.sendBufferSize = 16384\ncanal.instance.network.soTimeout = 30\n\n# binlog filter config\ncanal.instance.filter.druid.ddl = true\ncanal.instance.filter.query.dcl = false\ncanal.instance.filter.query.dml = false\ncanal.instance.filter.query.ddl = false\ncanal.instance.filter.table.error = false\ncanal.instance.filter.rows = false\ncanal.instance.filter.transaction.entry = false\ncanal.instance.filter.dml.insert = false\ncanal.instance.filter.dml.update = false\ncanal.instance.filter.dml.delete = false\n\n# binlog format/image check\ncanal.instance.binlog.format = ROW,STATEMENT,MIXED \ncanal.instance.binlog.image = FULL,MINIMAL,NOBLOB\n\n# binlog ddl isolation\ncanal.instance.get.ddl.isolation = false\n\n# parallel parser config\ncanal.instance.parser.parallel = true\n## concurrent thread number, default 60% available processors, suggest not to exceed Runtime.getRuntime().availableProcessors()\n#canal.instance.parser.parallelThreadSize = 16\n## disruptor ringbuffer size, must be power of 2\ncanal.instance.parser.parallelBufferSize = 256\n\n# table meta tsdb info\ncanal.instance.tsdb.enable = true\ncanal.instance.tsdb.dir = ${canal.file.data.dir:../conf}/${canal.instance.destination:}\ncanal.instance.tsdb.url = jdbc:h2:${canal.instance.tsdb.dir}/h2;CACHE_SIZE=1000;MODE=MYSQL;\ncanal.instance.tsdb.dbUsername = canal\ncanal.instance.tsdb.dbPassword = canal\n# dump snapshot interval, default 24 hour\ncanal.instance.tsdb.snapshot.interval = 24\n# purge snapshot expire , default 360 hour(15 days)\ncanal.instance.tsdb.snapshot.expire = 360\n\n#################################################\n######### \t\tdestinations\t\t#############\n#################################################\ncanal.destinations =\n# conf root dir\ncanal.conf.dir = ../conf\n# auto scan instance dir add/remove and start/stop instance\ncanal.auto.scan = true\ncanal.auto.scan.interval = 5\n# set this value to 'true' means that when binlog pos not found, skip to latest.\n# WARN: pls keep 'false' in production env, or if you know what you want.\ncanal.auto.reset.latest.pos.mode = false\n\ncanal.instance.tsdb.spring.xml = classpath:spring/tsdb/h2-tsdb.xml\n#canal.instance.tsdb.spring.xml = classpath:spring/tsdb/mysql-tsdb.xml\n\ncanal.instance.global.mode = manager\ncanal.instance.global.lazy = false\ncanal.instance.global.manager.address = ${canal.admin.manager}\n#canal.instance.global.spring.xml = classpath:spring/memory-instance.xml\ncanal.instance.global.spring.xml = classpath:spring/file-instance.xml\n#canal.instance.global.spring.xml = classpath:spring/default-instance.xml\n\n##################################################\n######### \t      MQ Properties      #############\n##################################################\n# aliyun ak/sk , support rds/mq\ncanal.aliyun.accessKey =\ncanal.aliyun.secretKey =\ncanal.aliyun.uid=\n\ncanal.mq.flatMessage = true\ncanal.mq.canalBatchSize = 50\ncanal.mq.canalGetTimeout = 100\n# Set this value to \"cloud\", if you want open message trace feature in aliyun.\ncanal.mq.accessChannel = local\n\ncanal.mq.database.hash = true\ncanal.mq.send.thread.size = 30\ncanal.mq.build.thread.size = 8\n\n##################################################\n######### \t\t     Kafka \t\t     #############\n##################################################\nkafka.bootstrap.servers = 127.0.0.1:6667\nkafka.acks = all\nkafka.compression.type = none\nkafka.batch.size = 16384\nkafka.linger.ms = 1\nkafka.max.request.size = 1048576\nkafka.buffer.memory = 33554432\nkafka.max.in.flight.requests.per.connection = 1\nkafka.retries = 0\n\nkafka.kerberos.enable = false\nkafka.kerberos.krb5.file = ../conf/kerberos/krb5.conf\nkafka.kerberos.jaas.file = ../conf/kerberos/jaas.conf\n\n# sasl demo\n# kafka.sasl.jaas.config = org.apache.kafka.common.security.scram.ScramLoginModule required \\\\n username=\\\"alice\\\" \\\\npassword=\"alice-secret\\\";\n# kafka.sasl.mechanism = SCRAM-SHA-512\n# kafka.security.protocol = SASL_PLAINTEXT\n\n##################################################\n######### \t\t    RocketMQ\t     #############\n##################################################\nrocketmq.producer.group = test\nrocketmq.enable.message.trace = false\nrocketmq.customized.trace.topic =\nrocketmq.namespace =\nrocketmq.namesrv.addr = 127.0.0.1:9876\nrocketmq.retry.times.when.send.failed = 0\nrocketmq.vip.channel.enabled = false\nrocketmq.tag =\n\n##################################################\n######### \t\t    RabbitMQ\t     #############\n##################################################\nrabbitmq.host =\nrabbitmq.virtual.host =\nrabbitmq.exchange =\nrabbitmq.username =\nrabbitmq.password =\nrabbitmq.deliveryMode =\n\n\n##################################################\n######### \t\t      Pulsar         #############\n##################################################\npulsarmq.serverUrl =\npulsarmq.roleToken =\npulsarmq.topicTenantPrefix =\n"
  },
  {
    "path": "admin/admin-web/src/main/resources/canal_manager.sql",
    "content": "CREATE DATABASE /*!32312 IF NOT EXISTS*/ `canal_manager` /*!40100 DEFAULT CHARACTER SET utf8 COLLATE utf8_bin */;\n\nUSE `canal_manager`;\n\nSET NAMES utf8;\nSET FOREIGN_KEY_CHECKS = 0;\n\n-- ----------------------------\n-- Table structure for canal_adapter_config\n-- ----------------------------\nDROP TABLE IF EXISTS `canal_adapter_config`;\nCREATE TABLE `canal_adapter_config` (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT,\n  `category` varchar(255) NOT NULL,\n  `name` varchar(255) NOT NULL,\n  `status` varchar(45) DEFAULT NULL,\n  `content` text NOT NULL,\n  `modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Table structure for canal_cluster\n-- ----------------------------\nDROP TABLE IF EXISTS `canal_cluster`;\nCREATE TABLE `canal_cluster` (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT,\n  `name` varchar(255) NOT NULL,\n  `zk_hosts` varchar(255) NOT NULL,\n  `modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Table structure for canal_config\n-- ----------------------------\nDROP TABLE IF EXISTS `canal_config`;\nCREATE TABLE `canal_config` (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT,\n  `cluster_id` bigint(20) DEFAULT NULL,\n  `server_id` bigint(20) DEFAULT NULL,\n  `name` varchar(255) NOT NULL,\n  `status` varchar(45) DEFAULT NULL,\n  `content` text NOT NULL,\n  `content_md5` varchar(128) NOT NULL,\n  `modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n  PRIMARY KEY (`id`),\n  UNIQUE KEY `sid_UNIQUE` (`server_id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Table structure for canal_instance_config\n-- ----------------------------\nDROP TABLE IF EXISTS `canal_instance_config`;\nCREATE TABLE `canal_instance_config` (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT,\n  `cluster_id` bigint(20) DEFAULT NULL,\n  `server_id` bigint(20) DEFAULT NULL,\n  `name` varchar(255) NOT NULL,\n  `status` varchar(45) DEFAULT NULL,\n  `content` text NOT NULL,\n  `content_md5` varchar(128) DEFAULT NULL,\n  `modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n  PRIMARY KEY (`id`),\n  UNIQUE KEY `name_UNIQUE` (`name`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Table structure for canal_node_server\n-- ----------------------------\nDROP TABLE IF EXISTS `canal_node_server`;\nCREATE TABLE `canal_node_server` (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT,\n  `cluster_id` bigint(20) DEFAULT NULL,\n  `name` varchar(255) NOT NULL,\n  `ip` varchar(255) NOT NULL,\n  `admin_port` int(11) DEFAULT NULL,\n  `tcp_port` int(11) DEFAULT NULL,\n  `metric_port` int(11) DEFAULT NULL,\n  `status` varchar(45) DEFAULT NULL,\n  `modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Table structure for canal_user\n-- ----------------------------\nDROP TABLE IF EXISTS `canal_user`;\nCREATE TABLE `canal_user` (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT,\n  `username` varchar(255) NOT NULL,\n  `password` varchar(255) NOT NULL,\n  `name` varchar(255) NOT NULL,\n  `roles` varchar(255) NOT NULL,\n  `introduction` varchar(255) DEFAULT NULL,\n  `avatar` varchar(255) DEFAULT NULL,\n  `creation_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nSET FOREIGN_KEY_CHECKS = 1;\n\n-- ----------------------------\n-- Records of canal_user\n-- ----------------------------\nBEGIN;\nINSERT INTO `canal_user` VALUES (1, 'admin', '6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9', 'Canal Manager', 'admin', NULL, NULL, '2019-07-14 00:05:28');\nCOMMIT;\n\nSET FOREIGN_KEY_CHECKS = 1;\n"
  },
  {
    "path": "admin/admin-web/src/main/resources/instance-template.properties",
    "content": "#################################################\n## mysql serverId , v1.0.26+ will autoGen\n# canal.instance.mysql.slaveId=0\n\n# enable gtid use true/false\ncanal.instance.gtidon=false\n\n# position info\ncanal.instance.master.address=127.0.0.1:3306\ncanal.instance.master.journal.name=\ncanal.instance.master.position=\ncanal.instance.master.timestamp=\ncanal.instance.master.gtid=\n\n# rds oss binlog\ncanal.instance.rds.accesskey=\ncanal.instance.rds.secretkey=\ncanal.instance.rds.instanceId=\n\n# table meta tsdb info\ncanal.instance.tsdb.enable=true\n#canal.instance.tsdb.url=jdbc:mysql://127.0.0.1:3306/canal_tsdb\n#canal.instance.tsdb.dbUsername=canal\n#canal.instance.tsdb.dbPassword=canal\n\n#canal.instance.standby.address =\n#canal.instance.standby.journal.name =\n#canal.instance.standby.position =\n#canal.instance.standby.timestamp =\n#canal.instance.standby.gtid=\n\n# username/password\ncanal.instance.dbUsername=canal\ncanal.instance.dbPassword=canal\ncanal.instance.connectionCharset = UTF-8\n# enable druid Decrypt database password\ncanal.instance.enableDruid=false\n#canal.instance.pwdPublicKey=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALK4BUxdDltRRE5/zXpVEVPUgunvscYFtEip3pmLlhrWpacX7y7GCMo2/JM6LeHmiiNdH1FWgGCpUfircSwlWKUCAwEAAQ==\n\n# table regex\ncanal.instance.filter.regex=.*\\\\..*\n# table black regex\ncanal.instance.filter.black.regex=\n# table field filter(format: schema1.tableName1:field1/field2,schema2.tableName2:field1/field2)\n#canal.instance.filter.field=test1.t_product:id/subject/keywords,test2.t_company:id/name/contact/ch\n# table field black filter(format: schema1.tableName1:field1/field2,schema2.tableName2:field1/field2)\n#canal.instance.filter.black.field=test1.t_product:subject/product_image,test2.t_company:id/name/contact/ch\n\n# mq config\ncanal.mq.topic=example\n# dynamic topic route by schema or table regex\n#canal.mq.dynamicTopic=mytest1.user,mytest2\\\\..*,.*\\\\..*\ncanal.mq.partition=0\n# hash partition config\n#canal.mq.partitionsNum=3\n#canal.mq.partitionHash=test.table:id^name,.*\\\\..*\n#################################################\n"
  },
  {
    "path": "admin/admin-web/src/main/resources/logback.xml",
    "content": "<configuration scan=\"true\" scanPeriod=\" 5 seconds\">\n\t<jmxConfigurator />\n\t<appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n\t\t<encoder>\n\t\t\t<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{56} - %msg%n\n\t\t\t</pattern>\n\t\t</encoder>\n\t</appender>\n\n\t<appender name=\"CANAL-ROOT\" class=\"ch.qos.logback.classic.sift.SiftingAppender\">\n        <discriminator>\n            <Key>admin</Key>\n            <DefaultValue>admin</DefaultValue>\n        </discriminator>\n\t\t<sift>\n\t\t\t<appender name=\"FILE-admin\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n\t\t\t\t<File>../logs/admin.log</File>\n\t\t\t\t<rollingPolicy\n\t\t\t\t\t\tclass=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n\t\t\t\t\t<!-- rollover daily -->\n\t\t\t\t\t<fileNamePattern>../logs/admin/%d{yyyy-MM-dd}/admin-%d{yyyy-MM-dd}-%i.log.gz</fileNamePattern>\n\t\t\t\t\t<timeBasedFileNamingAndTriggeringPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP\">\n\t\t\t\t\t\t<!-- or whenever the file size reaches 100MB -->\n\t\t\t\t\t\t<maxFileSize>512MB</maxFileSize>\n\t\t\t\t\t</timeBasedFileNamingAndTriggeringPolicy>\n\t\t\t\t\t<maxHistory>60</maxHistory>\n\t\t\t\t</rollingPolicy>\n\t\t\t\t<encoder>\n\t\t\t\t\t<pattern>\n\t\t\t\t\t\t%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{56} - %msg%n\n\t\t\t\t\t</pattern>\n\t\t\t\t</encoder>\n\t\t\t</appender>\n\t\t</sift>\n\t</appender>\n\n\t<root level=\"INFO\">\n\t\t<appender-ref ref=\"STDOUT\"/>\n\t\t<appender-ref ref=\"CANAL-ROOT\" />\n\t</root>\n\n\t<logger name=\"io.ebean.SQL\" additivity=\"false\">\n\t\t<level value=\"INFO\" />\n\t\t<appender-ref ref=\"STDOUT\"/>\n\t\t<appender-ref ref=\"CANAL-ROOT\" />\n\t</logger>\n</configuration>\n"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/index.html",
    "content": "<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content=\"IE=edge,chrome=1\"><meta name=viewport content=\"width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no\"><link rel=icon href=/favicon.ico><title>Canal Admin</title><link href=/static/css/chunk-elementUI.18b11d0e.css rel=stylesheet><link href=/static/css/chunk-libs.5cf311f0.css rel=stylesheet><link href=/static/css/app.bb951cb3.css rel=stylesheet></head><body><noscript><strong>We're sorry but Canal Admin doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=/static/js/chunk-elementUI.667f4c87.js></script><script src=/static/js/chunk-libs.c04beefc.js></script><script>(function(e){function n(n){for(var c,r,o=n[0],f=n[1],i=n[2],d=0,h=[];d<o.length;d++)r=o[d],u[r]&&h.push(u[r][0]),u[r]=0;for(c in f)Object.prototype.hasOwnProperty.call(f,c)&&(e[c]=f[c]);l&&l(n);while(h.length)h.shift()();return a.push.apply(a,i||[]),t()}function t(){for(var e,n=0;n<a.length;n++){for(var t=a[n],c=!0,r=1;r<t.length;r++){var o=t[r];0!==u[o]&&(c=!1)}c&&(a.splice(n--,1),e=f(f.s=t[0]))}return e}var c={},r={runtime:0},u={runtime:0},a=[];function o(e){return f.p+\"static/js/\"+({}[e]||e)+\".\"+{\"chunk-0dca2f22\":\"a2bc28b8\",\"chunk-5afa45f5\":\"79ddcc04\",\"chunk-5b373aad\":\"90a2d8e7\",\"chunk-bd1d44ee\":\"8e2c4851\",\"chunk-101fc062\":\"bc898027\",\"chunk-2b9b6c5c\":\"cc2181b9\",\"chunk-37c49cbf\":\"64d26540\",\"chunk-49959c8b\":\"6d226f70\",\"chunk-4f09fed2\":\"ff28d88d\",\"chunk-55380ff2\":\"681c71c9\",\"chunk-69386cf0\":\"76d77f5c\",\"chunk-7ec889b7\":\"bd1ca803\",\"chunk-da289616\":\"7def925e\"}[e]+\".js\"}function f(n){if(c[n])return c[n].exports;var t=c[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,f),t.l=!0,t.exports}f.e=function(e){var n=[],t={\"chunk-5afa45f5\":1,\"chunk-5b373aad\":1,\"chunk-bd1d44ee\":1,\"chunk-101fc062\":1,\"chunk-2b9b6c5c\":1,\"chunk-37c49cbf\":1,\"chunk-49959c8b\":1,\"chunk-4f09fed2\":1,\"chunk-69386cf0\":1,\"chunk-7ec889b7\":1,\"chunk-da289616\":1};r[e]?n.push(r[e]):0!==r[e]&&t[e]&&n.push(r[e]=new Promise(function(n,t){for(var c=\"static/css/\"+({}[e]||e)+\".\"+{\"chunk-0dca2f22\":\"31d6cfe0\",\"chunk-5afa45f5\":\"a34bb177\",\"chunk-5b373aad\":\"b966d36b\",\"chunk-bd1d44ee\":\"1528199a\",\"chunk-101fc062\":\"fad9926f\",\"chunk-2b9b6c5c\":\"c89f8844\",\"chunk-37c49cbf\":\"efc21a9c\",\"chunk-49959c8b\":\"e8e2beee\",\"chunk-4f09fed2\":\"70ec0b86\",\"chunk-55380ff2\":\"31d6cfe0\",\"chunk-69386cf0\":\"741ff14e\",\"chunk-7ec889b7\":\"c0585512\",\"chunk-da289616\":\"c89f8844\"}[e]+\".css\",u=f.p+c,a=document.getElementsByTagName(\"link\"),o=0;o<a.length;o++){var i=a[o],d=i.getAttribute(\"data-href\")||i.getAttribute(\"href\");if(\"stylesheet\"===i.rel&&(d===c||d===u))return n()}var h=document.getElementsByTagName(\"style\");for(o=0;o<h.length;o++){i=h[o],d=i.getAttribute(\"data-href\");if(d===c||d===u)return n()}var l=document.createElement(\"link\");l.rel=\"stylesheet\",l.type=\"text/css\",l.onload=n,l.onerror=function(n){var c=n&&n.target&&n.target.src||u,a=new Error(\"Loading CSS chunk \"+e+\" failed.\\n(\"+c+\")\");a.code=\"CSS_CHUNK_LOAD_FAILED\",a.request=c,delete r[e],l.parentNode.removeChild(l),t(a)},l.href=u;var s=document.getElementsByTagName(\"head\")[0];s.appendChild(l)}).then(function(){r[e]=0}));var c=u[e];if(0!==c)if(c)n.push(c[2]);else{var a=new Promise(function(n,t){c=u[e]=[n,t]});n.push(c[2]=a);var i,d=document.createElement(\"script\");d.charset=\"utf-8\",d.timeout=120,f.nc&&d.setAttribute(\"nonce\",f.nc),d.src=o(e),i=function(n){d.onerror=d.onload=null,clearTimeout(h);var t=u[e];if(0!==t){if(t){var c=n&&(\"load\"===n.type?\"missing\":n.type),r=n&&n.target&&n.target.src,a=new Error(\"Loading chunk \"+e+\" failed.\\n(\"+c+\": \"+r+\")\");a.type=c,a.request=r,t[1](a)}u[e]=void 0}};var h=setTimeout(function(){i({type:\"timeout\",target:d})},12e4);d.onerror=d.onload=i,document.head.appendChild(d)}return Promise.all(n)},f.m=e,f.c=c,f.d=function(e,n,t){f.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},f.r=function(e){\"undefined\"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(e,\"__esModule\",{value:!0})},f.t=function(e,n){if(1&n&&(e=f(e)),8&n)return e;if(4&n&&\"object\"===typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,\"default\",{enumerable:!0,value:e}),2&n&&\"string\"!=typeof e)for(var c in e)f.d(t,c,function(n){return e[n]}.bind(null,c));return t},f.n=function(e){var n=e&&e.__esModule?function(){return e[\"default\"]}:function(){return e};return f.d(n,\"a\",n),n},f.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},f.p=\"/\",f.oe=function(e){throw console.error(e),e};var i=window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[],d=i.push.bind(i);i.push=n,i=i.slice();for(var h=0;h<i.length;h++)n(i[h]);var l=d;t()})([]);</script><script src=/static/js/app.6845b228.js></script></body></html>"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/css/app.bb951cb3.css",
    "content": ".fade-enter-active,.fade-leave-active{-webkit-transition:opacity .28s;transition:opacity .28s}.fade-enter,.fade-leave-active{opacity:0}.fade-transform-enter-active,.fade-transform-leave-active{-webkit-transition:all .5s;transition:all .5s}.fade-transform-enter{opacity:0;-webkit-transform:translateX(-30px);transform:translateX(-30px)}.fade-transform-leave-to{opacity:0;-webkit-transform:translateX(30px);transform:translateX(30px)}.breadcrumb-enter-active,.breadcrumb-leave-active{-webkit-transition:all .5s;transition:all .5s}.breadcrumb-enter,.breadcrumb-leave-active{opacity:0;-webkit-transform:translateX(20px);transform:translateX(20px)}.breadcrumb-move{-webkit-transition:all .5s;transition:all .5s}.breadcrumb-leave-active{position:absolute}.el-breadcrumb__inner,.el-breadcrumb__inner a{font-weight:400!important}.el-upload input[type=file]{display:none!important}.el-upload__input{display:none}.el-dialog{-webkit-transform:none;transform:none;left:0;position:relative;margin:0 auto}.upload-container .el-upload{width:100%}.upload-container .el-upload .el-upload-dragger{width:100%;height:200px}.el-dropdown-menu a{display:block}#app .main-container{min-height:100%;-webkit-transition:margin-left .28s;transition:margin-left .28s;margin-left:210px;position:relative}#app .sidebar-container{-webkit-transition:width .28s;transition:width .28s;width:210px!important;background-color:#304156;height:100%;position:fixed;font-size:0;top:0;bottom:0;left:0;z-index:1001;overflow:hidden}#app .sidebar-container .horizontal-collapse-transition{-webkit-transition:width 0s ease-in-out,padding-left 0s ease-in-out,padding-right 0s ease-in-out;transition:width 0s ease-in-out,padding-left 0s ease-in-out,padding-right 0s ease-in-out}#app .sidebar-container .scrollbar-wrapper{overflow-x:hidden!important}#app .sidebar-container .el-scrollbar__bar.is-vertical{right:0}#app .sidebar-container .el-scrollbar{height:100%}#app .sidebar-container.has-logo .el-scrollbar{height:calc(100% - 50px)}#app .sidebar-container .is-horizontal{display:none}#app .sidebar-container a{display:inline-block;width:100%;overflow:hidden}#app .sidebar-container .svg-icon{margin-right:16px}#app .sidebar-container .el-menu{border:none;height:100%;width:100%!important}#app .sidebar-container .el-submenu__title:hover,#app .sidebar-container .submenu-title-noDropdown:hover{background-color:#263445!important}#app .sidebar-container .is-active>.el-submenu__title{color:#f4f4f5!important}#app .sidebar-container .el-submenu .el-menu-item,#app .sidebar-container .nest-menu .el-submenu>.el-submenu__title{min-width:210px!important;background-color:#1f2d3d!important}#app .sidebar-container .el-submenu .el-menu-item:hover,#app .sidebar-container .nest-menu .el-submenu>.el-submenu__title:hover{background-color:#001528!important}#app .hideSidebar .sidebar-container{width:54px!important}#app .hideSidebar .main-container{margin-left:54px}#app .hideSidebar .submenu-title-noDropdown{padding:0!important;position:relative}#app .hideSidebar .submenu-title-noDropdown .el-tooltip{padding:0!important}#app .hideSidebar .submenu-title-noDropdown .el-tooltip .svg-icon{margin-left:20px}#app .hideSidebar .el-submenu{overflow:hidden}#app .hideSidebar .el-submenu>.el-submenu__title{padding:0!important}#app .hideSidebar .el-submenu>.el-submenu__title .svg-icon{margin-left:20px}#app .hideSidebar .el-submenu>.el-submenu__title .el-submenu__icon-arrow{display:none}#app .hideSidebar .el-menu--collapse .el-submenu>.el-submenu__title>span{height:0;width:0;overflow:hidden;visibility:hidden;display:inline-block}#app .el-menu--collapse .el-menu .el-submenu{min-width:210px!important}#app .mobile .main-container{margin-left:0}#app .mobile .sidebar-container{-webkit-transition:-webkit-transform .28s;transition:-webkit-transform .28s;transition:transform .28s;transition:transform .28s,-webkit-transform .28s;width:210px!important}#app .mobile.hideSidebar .sidebar-container{pointer-events:none;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transform:translate3d(-210px,0,0);transform:translate3d(-210px,0,0)}#app .withoutAnimation .main-container,#app .withoutAnimation .sidebar-container{-webkit-transition:none;transition:none}.el-menu--vertical>.el-menu .svg-icon{margin-right:16px}.el-menu--vertical .el-menu-item:hover,.el-menu--vertical .nest-menu .el-submenu>.el-submenu__title:hover{background-color:#263445!important}.el-menu--vertical>.el-menu--popup{max-height:100vh;overflow-y:auto}.el-menu--vertical>.el-menu--popup::-webkit-scrollbar-track-piece{background:#d3dce6}.el-menu--vertical>.el-menu--popup::-webkit-scrollbar{width:6px}.el-menu--vertical>.el-menu--popup::-webkit-scrollbar-thumb{background:#99a9bf;border-radius:20px}body{height:100%;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;font-family:Helvetica Neue,Helvetica,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Arial,sans-serif}label{font-weight:700}html{-webkit-box-sizing:border-box;box-sizing:border-box}#app,html{height:100%}*,:after,:before{-webkit-box-sizing:inherit;box-sizing:inherit}a:active,a:focus{outline:none}a,a:focus,a:hover{cursor:pointer;color:inherit;text-decoration:none}div:focus{outline:none}.clearfix:after{visibility:hidden;display:block;font-size:0;content:\" \";clear:both;height:0}.app-container{padding:20px}.filter-container{padding-bottom:10px}.filter-container .filter-item{display:inline-block;vertical-align:middle;margin-bottom:10px}.app-breadcrumb.el-breadcrumb[data-v-c09a31b8]{display:inline-block;font-size:14px;line-height:50px;margin-left:8px}.app-breadcrumb.el-breadcrumb .no-redirect[data-v-c09a31b8]{color:#97a8be;cursor:text}.hamburger[data-v-49e15297]{display:inline-block;vertical-align:middle;width:20px;height:20px}.hamburger.is-active[data-v-49e15297]{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.navbar[data-v-3ca66fc8]{height:50px;overflow:hidden;position:relative;background:#fff;-webkit-box-shadow:0 1px 4px rgba(0,21,41,.08);box-shadow:0 1px 4px rgba(0,21,41,.08)}.navbar .hamburger-container[data-v-3ca66fc8]{line-height:46px;height:100%;float:left;cursor:pointer;-webkit-transition:background .3s;transition:background .3s;-webkit-tap-highlight-color:transparent}.navbar .hamburger-container[data-v-3ca66fc8]:hover{background:rgba(0,0,0,.025)}.navbar .breadcrumb-container[data-v-3ca66fc8]{float:left}.navbar .right-menu[data-v-3ca66fc8]{float:right;height:100%;line-height:50px}.navbar .right-menu[data-v-3ca66fc8]:focus{outline:none}.navbar .right-menu .right-menu-item[data-v-3ca66fc8]{display:inline-block;padding:0 8px;height:100%;font-size:18px;color:#5a5e66;vertical-align:text-bottom}.navbar .right-menu .right-menu-item.hover-effect[data-v-3ca66fc8]{cursor:pointer;-webkit-transition:background .3s;transition:background .3s}.navbar .right-menu .right-menu-item.hover-effect[data-v-3ca66fc8]:hover{background:rgba(0,0,0,.025)}.navbar .right-menu .avatar-container[data-v-3ca66fc8]{margin-right:30px}.navbar .right-menu .avatar-container .avatar-wrapper[data-v-3ca66fc8]{margin-top:5px;position:relative}.navbar .right-menu .avatar-container .avatar-wrapper .user-avatar[data-v-3ca66fc8]{cursor:pointer;width:40px;height:40px;border-radius:10px}.navbar .right-menu .avatar-container .avatar-wrapper .el-icon-caret-bottom[data-v-3ca66fc8]{cursor:pointer;position:absolute;right:-20px;top:25px;font-size:12px}.sidebarLogoFade-enter-active[data-v-53202dff]{-webkit-transition:opacity 1.5s;transition:opacity 1.5s}.sidebarLogoFade-enter[data-v-53202dff],.sidebarLogoFade-leave-to[data-v-53202dff]{opacity:0}.sidebar-logo-container[data-v-53202dff]{position:relative;width:100%;height:50px;line-height:50px;background:#2b2f3a;text-align:center;overflow:hidden}.sidebar-logo-container .sidebar-logo-link[data-v-53202dff]{height:100%;width:100%}.sidebar-logo-container .sidebar-logo-link .sidebar-logo[data-v-53202dff]{width:55px;vertical-align:middle;margin-right:12px}.sidebar-logo-container .sidebar-logo-link .sidebar-title[data-v-53202dff]{display:inline-block;margin:0;color:#fff;font-weight:600;line-height:50px;font-size:14px;font-family:Avenir,Helvetica Neue,Arial,Helvetica,sans-serif;vertical-align:middle}.sidebar-logo-container.collapse .sidebar-logo[data-v-53202dff]{margin-right:0}.app-main[data-v-64cf4d83]{min-height:calc(100vh - 50px);width:100%;position:relative;overflow:hidden}.fixed-header+.app-main[data-v-64cf4d83]{padding-top:50px}.el-popup-parent--hidden .fixed-header{padding-right:15px}[data-v-4f739cf0]:export{menuText:#bfcbd9;menuActiveText:#409eff;subMenuActiveText:#f4f4f5;menuBg:#304156;menuHover:#263445;subMenuBg:#1f2d3d;subMenuHover:#001528;sideBarWidth:210px}.app-wrapper[data-v-4f739cf0]{position:relative;height:100%;width:100%}.app-wrapper[data-v-4f739cf0]:after{content:\"\";display:table;clear:both}.app-wrapper.mobile.openSidebar[data-v-4f739cf0]{position:fixed;top:0}.drawer-bg[data-v-4f739cf0]{background:#000;opacity:.3;width:100%;top:0;height:100%;position:absolute;z-index:999}.fixed-header[data-v-4f739cf0]{position:fixed;top:0;right:0;z-index:9;width:calc(100% - 210px);-webkit-transition:width .28s;transition:width .28s}.hideSidebar .fixed-header[data-v-4f739cf0]{width:calc(100% - 54px)}.mobile .fixed-header[data-v-4f739cf0]{width:100%}.svg-icon[data-v-f9f7fefc]{width:1em;height:1em;vertical-align:-.15em;fill:currentColor;overflow:hidden}.svg-external-icon[data-v-f9f7fefc]{background-color:currentColor;-webkit-mask-size:cover!important;mask-size:cover!important;display:inline-block}"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/css/chunk-101fc062.fad9926f.css",
    "content": "@supports (-webkit-mask:none) and (not (cater-color:#fff)){.login-container .el-input input{color:#fff}}.login-container .el-input{display:inline-block;height:47px;width:85%}.login-container .el-input input{background:transparent;border:0;-webkit-appearance:none;border-radius:0;padding:12px 5px 12px 15px;color:#fff;height:47px;caret-color:#fff}.login-container .el-input input:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px #283443 inset!important;box-shadow:inset 0 0 0 1000px #283443!important;-webkit-text-fill-color:#fff!important}.login-container .el-form-item{border:1px solid hsla(0,0%,100%,.1);background:rgba(0,0,0,.1);border-radius:5px;color:#454545}.login-container[data-v-31c14ebf]{min-height:100%;width:100%;background-color:#2d3a4b;overflow:hidden}.login-container .login-form[data-v-31c14ebf]{position:relative;width:520px;max-width:100%;padding:160px 35px 0;margin:0 auto;overflow:hidden}.login-container .tips[data-v-31c14ebf]{font-size:14px;color:#fff;margin-bottom:10px}.login-container .tips span[data-v-31c14ebf]:first-of-type{margin-right:16px}.login-container .svg-container[data-v-31c14ebf]{padding:6px 5px 6px 15px;color:#889aa4;vertical-align:middle;width:30px;display:inline-block}.login-container .title-container[data-v-31c14ebf]{position:relative}.login-container .title-container .title[data-v-31c14ebf]{font-size:26px;color:#eee;margin:0 auto 40px auto;text-align:center;font-weight:700}.login-container .show-pwd[data-v-31c14ebf]{position:absolute;right:10px;top:7px;font-size:16px;color:#889aa4;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/css/chunk-14b5f7a4.f3e06673.css",
    "content": ".pagination-container[data-v-cebf2f0c]{background:#fff;padding:32px 16px}.pagination-container.hidden[data-v-cebf2f0c]{display:none}"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/css/chunk-22553be3.f3e06673.css",
    "content": ".pagination-container[data-v-cebf2f0c]{background:#fff;padding:32px 16px}.pagination-container.hidden[data-v-cebf2f0c]{display:none}"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/css/chunk-2301924a.160e7b4a.css",
    "content": ".line[data-v-28f0cd0f]{text-align:center}"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/css/chunk-2b9b6c5c.c89f8844.css",
    "content": ".pagination-container[data-v-38ef71f0]{background:#fff;padding:32px 16px}.pagination-container.hidden[data-v-38ef71f0]{display:none}"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/css/chunk-37c49cbf.efc21a9c.css",
    "content": ".dashboard-container[data-v-42037c2b]{margin:30px}.dashboard-text[data-v-42037c2b]{font-size:30px;line-height:46px}"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/css/chunk-49959c8b.e8e2beee.css",
    "content": ".wscn-http404-container[data-v-c095f994]{-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);position:absolute;top:40%;left:50%}.wscn-http404[data-v-c095f994]{position:relative;width:1200px;padding:0 50px;overflow:hidden}.wscn-http404 .pic-404[data-v-c095f994]{position:relative;float:left;width:600px;overflow:hidden}.wscn-http404 .pic-404__parent[data-v-c095f994]{width:100%}.wscn-http404 .pic-404__child[data-v-c095f994]{position:absolute}.wscn-http404 .pic-404__child.left[data-v-c095f994]{width:80px;top:17px;left:220px;opacity:0;-webkit-animation-name:cloudLeft-data-v-c095f994;animation-name:cloudLeft-data-v-c095f994;-webkit-animation-duration:2s;animation-duration:2s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-delay:1s;animation-delay:1s}.wscn-http404 .pic-404__child.mid[data-v-c095f994]{width:46px;top:10px;left:420px;opacity:0;-webkit-animation-name:cloudMid-data-v-c095f994;animation-name:cloudMid-data-v-c095f994;-webkit-animation-duration:2s;animation-duration:2s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-delay:1.2s;animation-delay:1.2s}.wscn-http404 .pic-404__child.right[data-v-c095f994]{width:62px;top:100px;left:500px;opacity:0;-webkit-animation-name:cloudRight-data-v-c095f994;animation-name:cloudRight-data-v-c095f994;-webkit-animation-duration:2s;animation-duration:2s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-delay:1s;animation-delay:1s}@-webkit-keyframes cloudLeft-data-v-c095f994{0%{top:17px;left:220px;opacity:0}20%{top:33px;left:188px;opacity:1}80%{top:81px;left:92px;opacity:1}to{top:97px;left:60px;opacity:0}}@keyframes cloudLeft-data-v-c095f994{0%{top:17px;left:220px;opacity:0}20%{top:33px;left:188px;opacity:1}80%{top:81px;left:92px;opacity:1}to{top:97px;left:60px;opacity:0}}@-webkit-keyframes cloudMid-data-v-c095f994{0%{top:10px;left:420px;opacity:0}20%{top:40px;left:360px;opacity:1}70%{top:130px;left:180px;opacity:1}to{top:160px;left:120px;opacity:0}}@keyframes cloudMid-data-v-c095f994{0%{top:10px;left:420px;opacity:0}20%{top:40px;left:360px;opacity:1}70%{top:130px;left:180px;opacity:1}to{top:160px;left:120px;opacity:0}}@-webkit-keyframes cloudRight-data-v-c095f994{0%{top:100px;left:500px;opacity:0}20%{top:120px;left:460px;opacity:1}80%{top:180px;left:340px;opacity:1}to{top:200px;left:300px;opacity:0}}@keyframes cloudRight-data-v-c095f994{0%{top:100px;left:500px;opacity:0}20%{top:120px;left:460px;opacity:1}80%{top:180px;left:340px;opacity:1}to{top:200px;left:300px;opacity:0}}.wscn-http404 .bullshit[data-v-c095f994]{position:relative;float:left;width:300px;padding:30px 0;overflow:hidden}.wscn-http404 .bullshit__oops[data-v-c095f994]{font-size:32px;line-height:40px;color:#1482f0;margin-bottom:20px;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}.wscn-http404 .bullshit__headline[data-v-c095f994],.wscn-http404 .bullshit__oops[data-v-c095f994]{font-weight:700;opacity:0;-webkit-animation-name:slideUp-data-v-c095f994;animation-name:slideUp-data-v-c095f994;-webkit-animation-duration:.5s;animation-duration:.5s}.wscn-http404 .bullshit__headline[data-v-c095f994]{font-size:20px;line-height:24px;color:#222;margin-bottom:10px;-webkit-animation-delay:.1s;animation-delay:.1s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}.wscn-http404 .bullshit__info[data-v-c095f994]{font-size:13px;line-height:21px;color:grey;margin-bottom:30px;-webkit-animation-delay:.2s;animation-delay:.2s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}.wscn-http404 .bullshit__info[data-v-c095f994],.wscn-http404 .bullshit__return-home[data-v-c095f994]{opacity:0;-webkit-animation-name:slideUp-data-v-c095f994;animation-name:slideUp-data-v-c095f994;-webkit-animation-duration:.5s;animation-duration:.5s}.wscn-http404 .bullshit__return-home[data-v-c095f994]{display:block;float:left;width:110px;height:36px;background:#1482f0;border-radius:100px;text-align:center;color:#fff;font-size:14px;line-height:36px;cursor:pointer;-webkit-animation-delay:.3s;animation-delay:.3s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}@-webkit-keyframes slideUp-data-v-c095f994{0%{-webkit-transform:translateY(60px);transform:translateY(60px);opacity:0}to{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}@keyframes slideUp-data-v-c095f994{0%{-webkit-transform:translateY(60px);transform:translateY(60px);opacity:0}to{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/css/chunk-4f09fed2.70ec0b86.css",
    "content": ".line[data-v-64c3fae5]{text-align:center}"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/css/chunk-5afa45f5.a34bb177.css",
    "content": ".line[data-v-2e6a6604]{text-align:center}"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/css/chunk-5b373aad.b966d36b.css",
    "content": ".line[data-v-e884438a]{text-align:center}"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/css/chunk-69386cf0.741ff14e.css",
    "content": ".line[data-v-756ebb70]{text-align:center}"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/css/chunk-7ec889b7.c0585512.css",
    "content": ".line[data-v-0b80198c]{text-align:center}"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/css/chunk-98f505d0.5280f88f.css",
    "content": ".line[data-v-35af5ff9]{text-align:center}"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/css/chunk-bd1d44ee.1528199a.css",
    "content": ".line[data-v-5c332416]{text-align:center}"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/css/chunk-da289616.c89f8844.css",
    "content": ".pagination-container[data-v-38ef71f0]{background:#fff;padding:32px 16px}.pagination-container.hidden[data-v-38ef71f0]{display:none}"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/css/chunk-elementUI.18b11d0e.css",
    "content": ".el-pagination--small .arrow.disabled,.el-table--hidden,.el-table .hidden-columns,.el-table td.is-hidden>*,.el-table th.is-hidden>*{visibility:hidden}.el-input__suffix,.el-tree.is-dragging .el-tree-node__content *{pointer-events:none}.el-dropdown .el-dropdown-selfdefine:focus:active,.el-dropdown .el-dropdown-selfdefine:focus:not(.focusing),.el-message__closeBtn:focus,.el-message__content:focus,.el-popover:focus,.el-popover:focus:active,.el-popover__reference:focus:hover,.el-popover__reference:focus:not(.focusing),.el-rate:active,.el-rate:focus,.el-tooltip:focus:hover,.el-tooltip:focus:not(.focusing),.el-upload-list__item.is-success:active,.el-upload-list__item.is-success:not(.focusing):focus{outline-width:0}@font-face{font-family:element-icons;src:url(../../static/fonts/element-icons.2fad952a.woff) format(\"woff\"),url(../../static/fonts/element-icons.6f0a7632.ttf) format(\"truetype\");font-weight:400;font-style:normal}[class*=\" el-icon-\"],[class^=el-icon-]{font-family:element-icons!important;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;vertical-align:baseline;display:inline-block;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.el-icon-info:before{content:\"\\E61A\"}.el-icon-error:before{content:\"\\E62C\"}.el-icon-success:before{content:\"\\E62D\"}.el-icon-warning:before{content:\"\\E62E\"}.el-icon-question:before{content:\"\\E634\"}.el-icon-back:before{content:\"\\E606\"}.el-icon-arrow-left:before{content:\"\\E600\"}.el-icon-arrow-down:before{content:\"\\E603\"}.el-icon-arrow-right:before{content:\"\\E604\"}.el-icon-arrow-up:before{content:\"\\E605\"}.el-icon-caret-left:before{content:\"\\E60A\"}.el-icon-caret-bottom:before{content:\"\\E60B\"}.el-icon-caret-top:before{content:\"\\E60C\"}.el-icon-caret-right:before{content:\"\\E60E\"}.el-icon-d-arrow-left:before{content:\"\\E610\"}.el-icon-d-arrow-right:before{content:\"\\E613\"}.el-icon-minus:before{content:\"\\E621\"}.el-icon-plus:before{content:\"\\E62B\"}.el-icon-remove:before{content:\"\\E635\"}.el-icon-circle-plus:before{content:\"\\E601\"}.el-icon-remove-outline:before{content:\"\\E63C\"}.el-icon-circle-plus-outline:before{content:\"\\E602\"}.el-icon-close:before{content:\"\\E60F\"}.el-icon-check:before{content:\"\\E611\"}.el-icon-circle-close:before{content:\"\\E607\"}.el-icon-circle-check:before{content:\"\\E639\"}.el-icon-circle-close-outline:before{content:\"\\E609\"}.el-icon-circle-check-outline:before{content:\"\\E63E\"}.el-icon-zoom-out:before{content:\"\\E645\"}.el-icon-zoom-in:before{content:\"\\E641\"}.el-icon-d-caret:before{content:\"\\E615\"}.el-icon-sort:before{content:\"\\E640\"}.el-icon-sort-down:before{content:\"\\E630\"}.el-icon-sort-up:before{content:\"\\E631\"}.el-icon-tickets:before{content:\"\\E63F\"}.el-icon-document:before{content:\"\\E614\"}.el-icon-goods:before{content:\"\\E618\"}.el-icon-sold-out:before{content:\"\\E63B\"}.el-icon-news:before{content:\"\\E625\"}.el-icon-message:before{content:\"\\E61B\"}.el-icon-date:before{content:\"\\E608\"}.el-icon-printer:before{content:\"\\E62F\"}.el-icon-time:before{content:\"\\E642\"}.el-icon-bell:before{content:\"\\E622\"}.el-icon-mobile-phone:before{content:\"\\E624\"}.el-icon-service:before{content:\"\\E63A\"}.el-icon-view:before{content:\"\\E643\"}.el-icon-menu:before{content:\"\\E620\"}.el-icon-more:before{content:\"\\E646\"}.el-icon-more-outline:before{content:\"\\E626\"}.el-icon-star-on:before{content:\"\\E637\"}.el-icon-star-off:before{content:\"\\E63D\"}.el-icon-location:before{content:\"\\E61D\"}.el-icon-location-outline:before{content:\"\\E61F\"}.el-icon-phone:before{content:\"\\E627\"}.el-icon-phone-outline:before{content:\"\\E628\"}.el-icon-picture:before{content:\"\\E629\"}.el-icon-picture-outline:before{content:\"\\E62A\"}.el-icon-delete:before{content:\"\\E612\"}.el-icon-search:before{content:\"\\E619\"}.el-icon-edit:before{content:\"\\E61C\"}.el-icon-edit-outline:before{content:\"\\E616\"}.el-icon-rank:before{content:\"\\E632\"}.el-icon-refresh:before{content:\"\\E633\"}.el-icon-share:before{content:\"\\E636\"}.el-icon-setting:before{content:\"\\E638\"}.el-icon-upload:before{content:\"\\E60D\"}.el-icon-upload2:before{content:\"\\E644\"}.el-icon-download:before{content:\"\\E617\"}.el-icon-loading:before{content:\"\\E61E\"}.el-icon-loading{-webkit-animation:rotating 2s linear infinite;animation:rotating 2s linear infinite}.el-icon--right{margin-left:5px}.el-icon--left{margin-right:5px}@-webkit-keyframes rotating{0%{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes rotating{0%{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.el-pagination{white-space:nowrap;padding:2px 5px;color:#303133;font-weight:700}.el-pagination:after,.el-pagination:before{display:table;content:\"\"}.el-pagination:after{clear:both}.el-pagination button,.el-pagination span:not([class*=suffix]){display:inline-block;font-size:13px;min-width:35.5px;height:28px;line-height:28px;vertical-align:top;-webkit-box-sizing:border-box;box-sizing:border-box}.el-pagination .el-input__inner{text-align:center;-moz-appearance:textfield;line-height:normal}.el-pagination .el-input__suffix{right:0;-webkit-transform:scale(.8);transform:scale(.8)}.el-pagination .el-select .el-input{width:100px;margin:0 5px}.el-pagination .el-select .el-input .el-input__inner{padding-right:25px;border-radius:3px}.el-pagination button{border:none;padding:0 6px;background:0 0}.el-pagination button:focus{outline:0}.el-pagination button:hover{color:#409eff}.el-pagination button:disabled{color:#c0c4cc;background-color:#fff;cursor:not-allowed}.el-pagination .btn-next,.el-pagination .btn-prev{background:50% no-repeat #fff;background-size:16px;cursor:pointer;margin:0;color:#303133}.el-pagination .btn-next .el-icon,.el-pagination .btn-prev .el-icon{display:block;font-size:12px;font-weight:700}.el-pagination .btn-prev{padding-right:12px}.el-pagination .btn-next{padding-left:12px}.el-pagination .el-pager li.disabled{color:#c0c4cc;cursor:not-allowed}.el-pager li,.el-pager li.btn-quicknext:hover,.el-pager li.btn-quickprev:hover{cursor:pointer}.el-pagination--small .btn-next,.el-pagination--small .btn-prev,.el-pagination--small .el-pager li,.el-pagination--small .el-pager li.btn-quicknext,.el-pagination--small .el-pager li.btn-quickprev,.el-pagination--small .el-pager li:last-child{border-color:transparent;font-size:12px;line-height:22px;height:22px;min-width:22px}.el-pagination--small .more:before,.el-pagination--small li.more:before{line-height:24px}.el-pagination--small button,.el-pagination--small span:not([class*=suffix]){height:22px;line-height:22px}.el-pagination--small .el-pagination__editor,.el-pagination--small .el-pagination__editor.el-input .el-input__inner{height:22px}.el-pagination__sizes{margin:0 10px 0 0;font-weight:400;color:#606266}.el-pagination__sizes .el-input .el-input__inner{font-size:13px;padding-left:8px}.el-pagination__sizes .el-input .el-input__inner:hover{border-color:#409eff}.el-pagination__total{margin-right:10px;font-weight:400;color:#606266}.el-pagination__jump{margin-left:24px;font-weight:400;color:#606266}.el-pagination__jump .el-input__inner{padding:0 3px}.el-pagination__rightwrapper{float:right}.el-pagination__editor{line-height:18px;padding:0 2px;height:28px;text-align:center;margin:0 2px;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:3px}.el-pager,.el-pagination.is-background .btn-next,.el-pagination.is-background .btn-prev{padding:0}.el-pagination__editor.el-input{width:50px}.el-pagination__editor.el-input .el-input__inner{height:28px}.el-pagination__editor .el-input__inner::-webkit-inner-spin-button,.el-pagination__editor .el-input__inner::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.el-pagination.is-background .btn-next,.el-pagination.is-background .btn-prev,.el-pagination.is-background .el-pager li{margin:0 5px;background-color:#f4f4f5;color:#606266;min-width:30px;border-radius:2px}.el-pagination.is-background .btn-next.disabled,.el-pagination.is-background .btn-next:disabled,.el-pagination.is-background .btn-prev.disabled,.el-pagination.is-background .btn-prev:disabled,.el-pagination.is-background .el-pager li.disabled{color:#c0c4cc}.el-pagination.is-background .el-pager li:not(.disabled):hover{color:#409eff}.el-pagination.is-background .el-pager li:not(.disabled).active{background-color:#409eff;color:#fff}.el-dialog,.el-pager li{background:#fff;-webkit-box-sizing:border-box}.el-pagination.is-background.el-pagination--small .btn-next,.el-pagination.is-background.el-pagination--small .btn-prev,.el-pagination.is-background.el-pagination--small .el-pager li{margin:0 3px;min-width:22px}.el-pager,.el-pager li{vertical-align:top;margin:0;display:inline-block}.el-pager{user-select:none;list-style:none;font-size:0}.el-pager,.el-radio,.el-table th{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.el-pager .more:before{line-height:30px}.el-pager li{padding:0 4px;font-size:13px;min-width:35.5px;height:28px;line-height:28px;-webkit-box-sizing:border-box;box-sizing:border-box;text-align:center}.el-menu--collapse .el-menu .el-submenu,.el-menu--popup{min-width:200px}.el-pager li.btn-quicknext,.el-pager li.btn-quickprev{line-height:28px;color:#303133}.el-pager li.btn-quicknext.disabled,.el-pager li.btn-quickprev.disabled{color:#c0c4cc}.el-pager li.active+li{border-left:0}.el-pager li:hover{color:#409eff}.el-pager li.active{color:#409eff;cursor:default}@-webkit-keyframes v-modal-in{0%{opacity:0}}@-webkit-keyframes v-modal-out{to{opacity:0}}.el-dialog{position:relative;margin:0 auto 50px;border-radius:2px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,.3);box-shadow:0 1px 3px rgba(0,0,0,.3);-webkit-box-sizing:border-box;box-sizing:border-box;width:50%}.el-dialog.is-fullscreen{width:100%;margin-top:0;margin-bottom:0;height:100%;overflow:auto}.el-dialog__wrapper{position:fixed;top:0;right:0;bottom:0;left:0;overflow:auto;margin:0}.el-dialog__header{padding:20px 20px 10px}.el-dialog__headerbtn{position:absolute;top:20px;right:20px;padding:0;background:0 0;border:none;outline:0;cursor:pointer;font-size:16px}.el-dialog__headerbtn .el-dialog__close{color:#909399}.el-dialog__headerbtn:focus .el-dialog__close,.el-dialog__headerbtn:hover .el-dialog__close{color:#409eff}.el-dialog__title{line-height:24px;font-size:18px;color:#303133}.el-dialog__body{padding:30px 20px;color:#606266;font-size:14px}.el-dialog__footer{padding:10px 20px 20px;text-align:right;-webkit-box-sizing:border-box;box-sizing:border-box}.el-dialog--center{text-align:center}.el-dialog--center .el-dialog__body{text-align:initial;padding:25px 25px 30px}.el-dialog--center .el-dialog__footer{text-align:inherit}.dialog-fade-enter-active{-webkit-animation:dialog-fade-in .3s;animation:dialog-fade-in .3s}.dialog-fade-leave-active{-webkit-animation:dialog-fade-out .3s;animation:dialog-fade-out .3s}@-webkit-keyframes dialog-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}to{-webkit-transform:translateZ(0);transform:translateZ(0);opacity:1}}@keyframes dialog-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}to{-webkit-transform:translateZ(0);transform:translateZ(0);opacity:1}}@-webkit-keyframes dialog-fade-out{0%{-webkit-transform:translateZ(0);transform:translateZ(0);opacity:1}to{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}@keyframes dialog-fade-out{0%{-webkit-transform:translateZ(0);transform:translateZ(0);opacity:1}to{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}.el-autocomplete{position:relative;display:inline-block}.el-autocomplete-suggestion{margin:5px 0;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);border-radius:4px;border:1px solid #e4e7ed;-webkit-box-sizing:border-box;box-sizing:border-box;background-color:#fff}.el-dropdown-menu,.el-menu--collapse .el-submenu .el-menu{z-index:10;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-autocomplete-suggestion__wrap{max-height:280px;padding:10px 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-autocomplete-suggestion__list{margin:0;padding:0}.el-autocomplete-suggestion li{padding:0 20px;margin:0;line-height:34px;cursor:pointer;color:#606266;font-size:14px;list-style:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.el-autocomplete-suggestion li.highlighted,.el-autocomplete-suggestion li:hover{background-color:#f5f7fa}.el-autocomplete-suggestion li.divider{margin-top:6px;border-top:1px solid #000}.el-autocomplete-suggestion li.divider:last-child{margin-bottom:-6px}.el-autocomplete-suggestion.is-loading li{text-align:center;height:100px;line-height:100px;font-size:20px;color:#999}.el-autocomplete-suggestion.is-loading li:after{display:inline-block;content:\"\";height:100%;vertical-align:middle}.el-autocomplete-suggestion.is-loading li:hover{background-color:#fff}.el-autocomplete-suggestion.is-loading .el-icon-loading{vertical-align:middle}.el-dropdown{display:inline-block;position:relative;color:#606266;font-size:14px}.el-dropdown .el-button-group{display:block}.el-dropdown .el-button-group .el-button{float:none}.el-dropdown .el-dropdown__caret-button{padding-left:5px;padding-right:5px;position:relative;border-left:none}.el-dropdown .el-dropdown__caret-button:before{content:\"\";position:absolute;display:block;width:1px;top:5px;bottom:5px;left:0;background:hsla(0,0%,100%,.5)}.el-dropdown .el-dropdown__caret-button:hover:before{top:0;bottom:0}.el-dropdown .el-dropdown__caret-button .el-dropdown__icon{padding-left:0}.el-dropdown__icon{font-size:12px;margin:0 3px}.el-dropdown-menu{position:absolute;top:0;left:0;padding:10px 0;margin:5px 0;background-color:#fff;border:1px solid #ebeef5;border-radius:4px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);max-height:400px;overflow:auto}.el-dropdown-menu__item{list-style:none;line-height:36px;padding:0 20px;margin:0;font-size:14px;color:#606266;cursor:pointer;outline:0}.el-dropdown-menu__item:focus,.el-dropdown-menu__item:not(.is-disabled):hover{background-color:#ecf5ff;color:#66b1ff}.el-dropdown-menu__item i{margin-right:5px}.el-dropdown-menu__item--divided{position:relative;margin-top:6px;border-top:1px solid #ebeef5}.el-dropdown-menu__item--divided:before{content:\"\";height:6px;display:block;margin:0 -20px;background-color:#fff}.el-menu:after,.el-menu:before,.el-radio__inner:after,.el-switch__core:after{content:\"\"}.el-dropdown-menu__item.is-disabled{cursor:default;color:#bbb;pointer-events:none}.el-dropdown-menu--medium{padding:6px 0}.el-dropdown-menu--medium .el-dropdown-menu__item{line-height:30px;padding:0 17px;font-size:14px}.el-dropdown-menu--medium .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:6px}.el-dropdown-menu--medium .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:6px;margin:0 -17px}.el-dropdown-menu--small{padding:6px 0}.el-dropdown-menu--small .el-dropdown-menu__item{line-height:27px;padding:0 15px;font-size:13px}.el-dropdown-menu--small .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:4px}.el-dropdown-menu--small .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:4px;margin:0 -15px}.el-dropdown-menu--mini{padding:3px 0}.el-dropdown-menu--mini .el-dropdown-menu__item{line-height:24px;padding:0 10px;font-size:12px}.el-dropdown-menu--mini .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:3px}.el-dropdown-menu--mini .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:3px;margin:0 -10px}.el-menu{border-right:1px solid #e6e6e6;list-style:none;position:relative;margin:0;padding-left:0}.el-menu,.el-menu--horizontal>.el-menu-item:not(.is-disabled):focus,.el-menu--horizontal>.el-menu-item:not(.is-disabled):hover,.el-menu--horizontal>.el-submenu .el-submenu__title:hover{background-color:#fff}.el-menu:after,.el-menu:before{display:table}.el-menu:after{clear:both}.el-menu.el-menu--horizontal{border-bottom:1px solid #e6e6e6}.el-menu--horizontal{border-right:none}.el-menu--horizontal>.el-menu-item{float:left;height:60px;line-height:60px;margin:0;border-bottom:2px solid transparent;color:#909399}.el-menu--horizontal>.el-menu-item a,.el-menu--horizontal>.el-menu-item a:hover{color:inherit}.el-menu--horizontal>.el-submenu{float:left}.el-menu--horizontal>.el-submenu:focus,.el-menu--horizontal>.el-submenu:hover{outline:0}.el-menu--horizontal>.el-submenu:focus .el-submenu__title,.el-menu--horizontal>.el-submenu:hover .el-submenu__title{color:#303133}.el-menu--horizontal>.el-submenu.is-active .el-submenu__title{border-bottom:2px solid #409eff;color:#303133}.el-menu--horizontal>.el-submenu .el-submenu__title{height:60px;line-height:60px;border-bottom:2px solid transparent;color:#909399}.el-menu--horizontal>.el-submenu .el-submenu__icon-arrow{position:static;vertical-align:middle;margin-left:8px;margin-top:-3px}.el-menu--horizontal .el-menu .el-menu-item,.el-menu--horizontal .el-menu .el-submenu__title{background-color:#fff;float:none;height:36px;line-height:36px;padding:0 10px;color:#909399}.el-menu--horizontal .el-menu .el-menu-item.is-active,.el-menu--horizontal .el-menu .el-submenu.is-active>.el-submenu__title{color:#303133}.el-menu--horizontal .el-menu-item:not(.is-disabled):focus,.el-menu--horizontal .el-menu-item:not(.is-disabled):hover{outline:0;color:#303133}.el-menu--horizontal>.el-menu-item.is-active{border-bottom:2px solid #409eff;color:#303133}.el-menu--collapse{width:64px}.el-menu--collapse>.el-menu-item [class^=el-icon-],.el-menu--collapse>.el-submenu>.el-submenu__title [class^=el-icon-]{margin:0;vertical-align:middle;width:24px;text-align:center}.el-menu--collapse>.el-menu-item .el-submenu__icon-arrow,.el-menu--collapse>.el-submenu>.el-submenu__title .el-submenu__icon-arrow{display:none}.el-menu--collapse>.el-menu-item span,.el-menu--collapse>.el-submenu>.el-submenu__title span{height:0;width:0;overflow:hidden;visibility:hidden;display:inline-block}.el-menu--collapse>.el-menu-item.is-active i{color:inherit}.el-menu--collapse .el-submenu{position:relative}.el-menu--collapse .el-submenu .el-menu{position:absolute;margin-left:5px;top:0;left:100%;border:1px solid #e4e7ed;border-radius:2px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-menu-item,.el-submenu__title{height:56px;line-height:56px;position:relative;-webkit-box-sizing:border-box;white-space:nowrap;list-style:none}.el-menu--collapse .el-submenu.is-opened>.el-submenu__title .el-submenu__icon-arrow{-webkit-transform:none;transform:none}.el-menu--popup{z-index:100;border:none;padding:5px 0;border-radius:2px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-menu--popup-bottom-start{margin-top:5px}.el-menu--popup-right-start{margin-left:5px;margin-right:5px}.el-menu-item{font-size:14px;color:#303133;padding:0 20px;cursor:pointer;-webkit-transition:border-color .3s,background-color .3s,color .3s;transition:border-color .3s,background-color .3s,color .3s;-webkit-box-sizing:border-box;box-sizing:border-box}.el-menu-item *{vertical-align:middle}.el-menu-item i{color:#909399}.el-menu-item:focus,.el-menu-item:hover{outline:0;background-color:#ecf5ff}.el-menu-item.is-disabled{opacity:.25;cursor:not-allowed;background:0 0!important}.el-menu-item [class^=el-icon-]{margin-right:5px;width:24px;text-align:center;font-size:18px;vertical-align:middle}.el-menu-item.is-active{color:#409eff}.el-menu-item.is-active i{color:inherit}.el-submenu{list-style:none;margin:0;padding-left:0}.el-submenu__title{font-size:14px;color:#303133;padding:0 20px;cursor:pointer;-webkit-transition:border-color .3s,background-color .3s,color .3s;transition:border-color .3s,background-color .3s,color .3s;-webkit-box-sizing:border-box;box-sizing:border-box}.el-submenu__title *{vertical-align:middle}.el-submenu__title i{color:#909399}.el-submenu__title:focus,.el-submenu__title:hover{outline:0;background-color:#ecf5ff}.el-submenu__title.is-disabled{opacity:.25;cursor:not-allowed;background:0 0!important}.el-submenu__title:hover{background-color:#ecf5ff}.el-submenu .el-menu{border:none}.el-submenu .el-menu-item{height:50px;line-height:50px;padding:0 45px;min-width:200px}.el-submenu__icon-arrow{position:absolute;top:50%;right:20px;margin-top:-7px;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-size:12px}.el-radio,.el-radio__inner,.el-radio__input{position:relative;display:inline-block}.el-submenu.is-active .el-submenu__title{border-bottom-color:#409eff}.el-submenu.is-opened>.el-submenu__title .el-submenu__icon-arrow{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.el-submenu.is-disabled .el-menu-item,.el-submenu.is-disabled .el-submenu__title{opacity:.25;cursor:not-allowed;background:0 0!important}.el-submenu [class^=el-icon-]{vertical-align:middle;margin-right:5px;width:24px;text-align:center;font-size:18px}.el-menu-item-group>ul{padding:0}.el-menu-item-group__title{padding:7px 0 7px 20px;line-height:normal;font-size:12px;color:#909399}.el-radio,.el-radio--medium.is-bordered .el-radio__label{font-size:14px}.horizontal-collapse-transition .el-submenu__title .el-submenu__icon-arrow{-webkit-transition:.2s;transition:.2s;opacity:0}.el-radio{color:#606266;font-weight:500;line-height:1;cursor:pointer;white-space:nowrap;outline:0;margin-right:30px}.el-radio.is-bordered{padding:12px 20px 0 10px;border-radius:4px;border:1px solid #dcdfe6;-webkit-box-sizing:border-box;box-sizing:border-box;height:40px}.el-radio.is-bordered.is-checked{border-color:#409eff}.el-radio.is-bordered.is-disabled{cursor:not-allowed;border-color:#ebeef5}.el-radio__input.is-disabled .el-radio__inner,.el-radio__input.is-disabled.is-checked .el-radio__inner{background-color:#f5f7fa;border-color:#e4e7ed}.el-radio.is-bordered+.el-radio.is-bordered{margin-left:10px}.el-radio--medium.is-bordered{padding:10px 20px 0 10px;border-radius:4px;height:36px}.el-radio--mini.is-bordered .el-radio__label,.el-radio--small.is-bordered .el-radio__label{font-size:12px}.el-radio--medium.is-bordered .el-radio__inner{height:14px;width:14px}.el-radio--small.is-bordered{padding:8px 15px 0 10px;border-radius:3px;height:32px}.el-radio--small.is-bordered .el-radio__inner{height:12px;width:12px}.el-radio--mini.is-bordered{padding:6px 15px 0 10px;border-radius:3px;height:28px}.el-radio--mini.is-bordered .el-radio__inner{height:12px;width:12px}.el-radio:last-child{margin-right:0}.el-radio__input{white-space:nowrap;cursor:pointer;outline:0;line-height:1;vertical-align:middle}.el-radio__input.is-disabled .el-radio__inner{cursor:not-allowed}.el-radio__input.is-disabled .el-radio__inner:after{cursor:not-allowed;background-color:#f5f7fa}.el-radio__input.is-disabled .el-radio__inner+.el-radio__label{cursor:not-allowed}.el-radio__input.is-disabled.is-checked .el-radio__inner:after{background-color:#c0c4cc}.el-radio__input.is-disabled+span.el-radio__label{color:#c0c4cc;cursor:not-allowed}.el-radio__input.is-checked .el-radio__inner{border-color:#409eff;background:#409eff}.el-radio__input.is-checked .el-radio__inner:after{-webkit-transform:translate(-50%,-50%) scale(1);transform:translate(-50%,-50%) scale(1)}.el-radio__input.is-checked+.el-radio__label{color:#409eff}.el-radio__input.is-focus .el-radio__inner{border-color:#409eff}.el-radio__inner{border:1px solid #dcdfe6;border-radius:100%;width:14px;height:14px;background-color:#fff;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box}.el-radio__inner:hover{border-color:#409eff}.el-radio__inner:after{width:4px;height:4px;border-radius:100%;background-color:#fff;position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%) scale(0);transform:translate(-50%,-50%) scale(0);-webkit-transition:-webkit-transform .15s ease-in;transition:-webkit-transform .15s ease-in;transition:transform .15s ease-in;transition:transform .15s ease-in,-webkit-transform .15s ease-in}.el-radio__original{opacity:0;outline:0;position:absolute;z-index:-1;top:0;left:0;right:0;bottom:0;margin:0}.el-radio-button,.el-radio-button__inner{display:inline-block;position:relative;outline:0}.el-radio:focus:not(.is-focus):not(:active):not(.is-disabled) .el-radio__inner{-webkit-box-shadow:0 0 2px 2px #409eff;box-shadow:0 0 2px 2px #409eff}.el-radio__label{font-size:14px;padding-left:10px}.el-radio-group{display:inline-block;line-height:1;vertical-align:middle;font-size:0}.el-radio-button__inner{line-height:1;white-space:nowrap;vertical-align:middle;background:#fff;border:1px solid #dcdfe6;font-weight:500;border-left:0;color:#606266;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;cursor:pointer;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);padding:12px 20px;font-size:14px;border-radius:0}.el-radio-button__inner.is-round{padding:12px 20px}.el-radio-button__inner:hover{color:#409eff}.el-radio-button__inner [class*=el-icon-]{line-height:.9}.el-radio-button__inner [class*=el-icon-]+span{margin-left:5px}.el-radio-button:first-child .el-radio-button__inner{border-left:1px solid #dcdfe6;border-radius:4px 0 0 4px;-webkit-box-shadow:none!important;box-shadow:none!important}.el-radio-button__orig-radio{opacity:0;outline:0;position:absolute;z-index:-1}.el-radio-button__orig-radio:checked+.el-radio-button__inner{color:#fff;background-color:#409eff;border-color:#409eff;-webkit-box-shadow:-1px 0 0 0 #409eff;box-shadow:-1px 0 0 0 #409eff}.el-radio-button__orig-radio:disabled+.el-radio-button__inner{color:#c0c4cc;cursor:not-allowed;background-image:none;background-color:#fff;border-color:#ebeef5;-webkit-box-shadow:none;box-shadow:none}.el-radio-button__orig-radio:disabled:checked+.el-radio-button__inner{background-color:#f2f6fc}.el-radio-button:last-child .el-radio-button__inner{border-radius:0 4px 4px 0}.el-popover,.el-radio-button:first-child:last-child .el-radio-button__inner{border-radius:4px}.el-radio-button--medium .el-radio-button__inner{padding:10px 20px;font-size:14px;border-radius:0}.el-radio-button--medium .el-radio-button__inner.is-round{padding:10px 20px}.el-radio-button--small .el-radio-button__inner{padding:9px 15px;font-size:12px;border-radius:0}.el-radio-button--small .el-radio-button__inner.is-round{padding:9px 15px}.el-radio-button--mini .el-radio-button__inner{padding:7px 15px;font-size:12px;border-radius:0}.el-radio-button--mini .el-radio-button__inner.is-round{padding:7px 15px}.el-radio-button:focus:not(.is-focus):not(:active):not(.is-disabled){-webkit-box-shadow:0 0 2px 2px #409eff;box-shadow:0 0 2px 2px #409eff}.el-switch{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;position:relative;font-size:14px;line-height:20px;height:20px;vertical-align:middle}.el-switch__core,.el-switch__label{display:inline-block;cursor:pointer}.el-switch.is-disabled .el-switch__core,.el-switch.is-disabled .el-switch__label{cursor:not-allowed}.el-switch__label{-webkit-transition:.2s;transition:.2s;height:20px;font-size:14px;font-weight:500;vertical-align:middle;color:#303133}.el-switch__label.is-active{color:#409eff}.el-switch__label--left{margin-right:10px}.el-switch__label--right{margin-left:10px}.el-switch__label *{line-height:1;font-size:14px;display:inline-block}.el-switch__input{position:absolute;width:0;height:0;opacity:0;margin:0}.el-switch__core{margin:0;position:relative;width:40px;height:20px;border:1px solid #dcdfe6;outline:0;border-radius:10px;-webkit-box-sizing:border-box;box-sizing:border-box;background:#dcdfe6;-webkit-transition:border-color .3s,background-color .3s;transition:border-color .3s,background-color .3s;vertical-align:middle}.el-switch__core:after{position:absolute;top:1px;left:1px;border-radius:100%;-webkit-transition:all .3s;transition:all .3s;width:16px;height:16px;background-color:#fff}.el-switch.is-checked .el-switch__core{border-color:#409eff;background-color:#409eff}.el-switch.is-checked .el-switch__core:after{left:100%;margin-left:-17px}.el-switch.is-disabled{opacity:.6}.el-switch--wide .el-switch__label.el-switch__label--left span{left:10px}.el-switch--wide .el-switch__label.el-switch__label--right span{right:10px}.el-switch .label-fade-enter,.el-switch .label-fade-leave-active{opacity:0}.el-select-dropdown{position:absolute;z-index:1001;border:1px solid #e4e7ed;border-radius:4px;background-color:#fff;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-box-sizing:border-box;box-sizing:border-box;margin:5px 0}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected{color:#409eff;background-color:#fff}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected.hover{background-color:#f5f7fa}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected:after{position:absolute;right:20px;font-family:element-icons;content:\"\\E611\";font-size:12px;font-weight:700;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.el-select-dropdown .el-scrollbar.is-empty .el-select-dropdown__list{padding:0}.el-select-dropdown__empty{padding:10px 0;margin:0;text-align:center;color:#999;font-size:14px}.el-select-dropdown__wrap{max-height:274px}.el-select-dropdown__list{list-style:none;padding:6px 0;margin:0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-select-dropdown__item{font-size:14px;padding:0 20px;position:relative;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#606266;height:34px;line-height:34px;box-sizing:border-box;cursor:pointer}.el-select-dropdown__item,.el-select .el-tag,.el-table{-webkit-box-sizing:border-box}.el-select-dropdown__item.is-disabled{color:#c0c4cc;cursor:not-allowed}.el-select-dropdown__item.is-disabled:hover{background-color:#fff}.el-select-dropdown__item.hover,.el-select-dropdown__item:hover{background-color:#f5f7fa}.el-select-dropdown__item.selected{color:#409eff;font-weight:700}.el-select-group{margin:0;padding:0}.el-select-group__wrap{position:relative;list-style:none;margin:0;padding:0}.el-select-group__wrap:not(:last-of-type){padding-bottom:24px}.el-select-group__wrap:not(:last-of-type):after{content:\"\";position:absolute;display:block;left:20px;right:20px;bottom:12px;height:1px;background:#e4e7ed}.el-select-group__title{padding-left:20px;font-size:12px;color:#909399;line-height:30px}.el-select-group .el-select-dropdown__item{padding-left:20px}.el-select{display:inline-block;position:relative}.el-select .el-select__tags>span{display:contents}.el-select:hover .el-input__inner{border-color:#c0c4cc}.el-select .el-input__inner{cursor:pointer;padding-right:35px}.el-select .el-input__inner:focus{border-color:#409eff}.el-select .el-input .el-select__caret{color:#c0c4cc;font-size:14px;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;-webkit-transform:rotate(180deg);transform:rotate(180deg);cursor:pointer}.el-select .el-input .el-select__caret.is-reverse{-webkit-transform:rotate(0);transform:rotate(0)}.el-select .el-input .el-select__caret.is-show-close{font-size:14px;text-align:center;-webkit-transform:rotate(180deg);transform:rotate(180deg);border-radius:100%;color:#c0c4cc;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1)}.el-select .el-input .el-select__caret.is-show-close:hover{color:#909399}.el-select .el-input.is-disabled .el-input__inner{cursor:not-allowed}.el-select .el-input.is-disabled .el-input__inner:hover{border-color:#e4e7ed}.el-select .el-input.is-focus .el-input__inner{border-color:#409eff}.el-select>.el-input{display:block}.el-select__input{border:none;outline:0;padding:0;margin-left:15px;color:#666;font-size:14px;-webkit-appearance:none;-moz-appearance:none;appearance:none;height:28px;background-color:transparent}.el-select__input.is-mini{height:14px}.el-select__close{cursor:pointer;position:absolute;top:8px;z-index:1000;right:25px;color:#c0c4cc;line-height:18px;font-size:14px}.el-select__close:hover{color:#909399}.el-select__tags{position:absolute;line-height:normal;white-space:normal;z-index:1;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-wrap:wrap;flex-wrap:wrap}.el-select .el-tag__close{margin-top:-2px}.el-select .el-tag{-webkit-box-sizing:border-box;box-sizing:border-box;border-color:transparent;margin:2px 0 2px 6px;background-color:#f0f2f5}.el-select .el-tag__close.el-icon-close{background-color:#c0c4cc;right:-7px;top:0;color:#fff}.el-select .el-tag__close.el-icon-close:hover{background-color:#909399}.el-table,.el-table__expanded-cell{background-color:#fff}.el-select .el-tag__close.el-icon-close:before{display:block;-webkit-transform:translateY(.5px);transform:translateY(.5px)}.el-table{position:relative;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-box-flex:1;-ms-flex:1;flex:1;width:100%;max-width:100%;font-size:14px;color:#606266}.el-table--mini,.el-table--small,.el-table__expand-icon{font-size:12px}.el-table__empty-block{min-height:60px;text-align:center;width:100%;height:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-table__empty-text{line-height:60px;width:50%;color:#909399}.el-table__expand-column .cell{padding:0;text-align:center}.el-table__expand-icon{position:relative;cursor:pointer;color:#666;-webkit-transition:-webkit-transform .2s ease-in-out;transition:-webkit-transform .2s ease-in-out;transition:transform .2s ease-in-out;transition:transform .2s ease-in-out,-webkit-transform .2s ease-in-out;height:20px}.el-table__expand-icon--expanded{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-table__expand-icon>.el-icon{position:absolute;left:50%;top:50%;margin-left:-5px;margin-top:-5px}.el-table__expanded-cell[class*=cell]{padding:20px 50px}.el-table__expanded-cell:hover{background-color:transparent!important}.el-table__placeholder{display:inline-block;width:20px}.el-table--fit{border-right:0;border-bottom:0}.el-table--fit td.gutter,.el-table--fit th.gutter{border-right-width:1px}.el-table--scrollable-x .el-table__body-wrapper{overflow-x:auto}.el-table--scrollable-y .el-table__body-wrapper{overflow-y:auto}.el-table thead{color:#909399;font-weight:500}.el-table thead.is-group th{background:#f5f7fa}.el-table th,.el-table tr{background-color:#fff}.el-table td,.el-table th{padding:12px 0;min-width:0;-webkit-box-sizing:border-box;box-sizing:border-box;text-overflow:ellipsis;vertical-align:middle;position:relative;text-align:left}.el-table td.is-center,.el-table th.is-center{text-align:center}.el-table td.is-right,.el-table th.is-right{text-align:right}.el-table td.gutter,.el-table th.gutter{width:15px;border-right-width:0;border-bottom-width:0;padding:0}.el-table--medium td,.el-table--medium th{padding:10px 0}.el-table--small td,.el-table--small th{padding:8px 0}.el-table--mini td,.el-table--mini th{padding:6px 0}.el-table .cell,.el-table th div{padding-right:10px;overflow:hidden;text-overflow:ellipsis}.el-table--border td:first-child .cell,.el-table--border th:first-child .cell,.el-table .cell,.el-table th div{padding-left:10px}.el-table tr input[type=checkbox]{margin:0}.el-table td,.el-table th.is-leaf{border-bottom:1px solid #ebeef5}.el-table th.is-sortable{cursor:pointer}.el-table th{white-space:nowrap;overflow:hidden;-webkit-user-select:none;user-select:none}.el-slider__button-wrapper,.el-table th,.el-time-panel{-moz-user-select:none;-ms-user-select:none}.el-table th div{line-height:40px;white-space:nowrap}.el-table th>.cell,.el-table th div{display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box}.el-table th>.cell{position:relative;word-wrap:normal;text-overflow:ellipsis;vertical-align:middle;width:100%}.el-table th>.cell.highlight{color:#409eff}.el-table th.required>div:before{display:inline-block;content:\"\";width:8px;height:8px;border-radius:50%;background:#ff4d51;margin-right:5px;vertical-align:middle}.el-table td div{-webkit-box-sizing:border-box;box-sizing:border-box}.el-table td.gutter{width:0}.el-table .cell{-webkit-box-sizing:border-box;box-sizing:border-box;white-space:normal;word-break:break-all;line-height:23px}.el-table .cell.el-tooltip{white-space:nowrap;min-width:50px}.el-table--border,.el-table--group{border:1px solid #ebeef5}.el-table--border:after,.el-table--group:after,.el-table:before{content:\"\";position:absolute;background-color:#ebeef5;z-index:1}.el-table--border:after,.el-table--group:after{top:0;right:0;width:1px;height:100%}.el-table:before{left:0;bottom:0;width:100%;height:1px}.el-table--border{border-right:none;border-bottom:none}.el-table--border.el-loading-parent--relative{border-color:transparent}.el-table--border td,.el-table--border th,.el-table__body-wrapper .el-table--border.is-scrolling-left~.el-table__fixed{border-right:1px solid #ebeef5}.el-table--border th.gutter:last-of-type{border-bottom:1px solid #ebeef5;border-bottom-width:1px}.el-table--border th,.el-table__fixed-right-patch{border-bottom:1px solid #ebeef5}.el-table__fixed,.el-table__fixed-right{position:absolute;top:0;left:0;overflow-x:hidden;overflow-y:hidden;-webkit-box-shadow:0 0 10px rgba(0,0,0,.12);box-shadow:0 0 10px rgba(0,0,0,.12)}.el-table__fixed-right:before,.el-table__fixed:before{content:\"\";position:absolute;left:0;bottom:0;width:100%;height:1px;background-color:#ebeef5;z-index:4}.el-table__fixed-right-patch{position:absolute;top:-1px;right:0;background-color:#fff}.el-table__fixed-right{top:0;left:auto;right:0}.el-table__fixed-right .el-table__fixed-body-wrapper,.el-table__fixed-right .el-table__fixed-footer-wrapper,.el-table__fixed-right .el-table__fixed-header-wrapper{left:auto;right:0}.el-table__fixed-header-wrapper{position:absolute;left:0;top:0;z-index:3}.el-table__fixed-footer-wrapper{position:absolute;left:0;bottom:0;z-index:3}.el-table__fixed-footer-wrapper tbody td{border-top:1px solid #ebeef5;background-color:#f5f7fa;color:#606266}.el-table__fixed-body-wrapper{position:absolute;left:0;top:37px;overflow:hidden;z-index:3}.el-table__body-wrapper,.el-table__footer-wrapper,.el-table__header-wrapper{width:100%}.el-table__footer-wrapper{margin-top:-1px}.el-table__footer-wrapper td{border-top:1px solid #ebeef5}.el-table__body,.el-table__footer,.el-table__header{table-layout:fixed;border-collapse:separate}.el-table__footer-wrapper,.el-table__header-wrapper{overflow:hidden}.el-table__footer-wrapper tbody td,.el-table__header-wrapper tbody td{background-color:#f5f7fa;color:#606266}.el-table__body-wrapper{overflow:hidden;position:relative}.el-table__body-wrapper.is-scrolling-left~.el-table__fixed,.el-table__body-wrapper.is-scrolling-none~.el-table__fixed,.el-table__body-wrapper.is-scrolling-none~.el-table__fixed-right,.el-table__body-wrapper.is-scrolling-right~.el-table__fixed-right{-webkit-box-shadow:none;box-shadow:none}.el-picker-panel,.el-table-filter{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-table__body-wrapper .el-table--border.is-scrolling-right~.el-table__fixed-right{border-left:1px solid #ebeef5}.el-table .caret-wrapper{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:34px;width:24px;vertical-align:middle;cursor:pointer;overflow:initial;position:relative}.el-table .sort-caret{width:0;height:0;border:5px solid transparent;position:absolute;left:7px}.el-table .sort-caret.ascending{border-bottom-color:#c0c4cc;top:5px}.el-table .sort-caret.descending{border-top-color:#c0c4cc;bottom:7px}.el-table .ascending .sort-caret.ascending{border-bottom-color:#409eff}.el-table .descending .sort-caret.descending{border-top-color:#409eff}.el-table .hidden-columns{position:absolute;z-index:-1}.el-table--striped .el-table__body tr.el-table__row--striped td{background:#fafafa}.el-table--striped .el-table__body tr.el-table__row--striped.current-row td,.el-table__body tr.current-row>td,.el-table__body tr.hover-row.current-row>td,.el-table__body tr.hover-row.el-table__row--striped.current-row>td,.el-table__body tr.hover-row.el-table__row--striped>td,.el-table__body tr.hover-row>td{background-color:#ecf5ff}.el-table__column-resize-proxy{position:absolute;left:200px;top:0;bottom:0;width:0;border-left:1px solid #ebeef5;z-index:10}.el-table__column-filter-trigger{display:inline-block;line-height:34px;cursor:pointer}.el-table__column-filter-trigger i{color:#909399;font-size:12px;-webkit-transform:scale(.75);transform:scale(.75)}.el-table--enable-row-transition .el-table__body td{-webkit-transition:background-color .25s ease;transition:background-color .25s ease}.el-table--enable-row-hover .el-table__body tr:hover>td{background-color:#f5f7fa}.el-table--fluid-height .el-table__fixed,.el-table--fluid-height .el-table__fixed-right{bottom:0;overflow:hidden}.el-table [class*=el-table__row--level] .el-table__expand-icon{display:inline-block;width:14px;vertical-align:middle;margin-right:5px}.el-table-column--selection .cell{padding-left:14px;padding-right:14px}.el-table-filter{border:1px solid #ebeef5;border-radius:2px;background-color:#fff;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-box-sizing:border-box;box-sizing:border-box;margin:2px 0}.el-date-table td,.el-date-table td div{height:30px;-webkit-box-sizing:border-box}.el-table-filter__list{padding:5px 0;margin:0;list-style:none;min-width:100px}.el-table-filter__list-item{line-height:36px;padding:0 10px;cursor:pointer;font-size:14px}.el-table-filter__list-item:hover{background-color:#ecf5ff;color:#66b1ff}.el-table-filter__list-item.is-active{background-color:#409eff;color:#fff}.el-table-filter__content{min-width:100px}.el-table-filter__bottom{border-top:1px solid #ebeef5;padding:8px}.el-table-filter__bottom button{background:0 0;border:none;color:#606266;cursor:pointer;font-size:13px;padding:0 3px}.el-date-table.is-week-mode .el-date-table__row.current div,.el-date-table.is-week-mode .el-date-table__row:hover div,.el-date-table td.in-range div,.el-date-table td.in-range div:hover{background-color:#f2f6fc}.el-table-filter__bottom button:hover{color:#409eff}.el-table-filter__bottom button:focus{outline:0}.el-table-filter__bottom button.is-disabled{color:#c0c4cc;cursor:not-allowed}.el-table-filter__wrap{max-height:280px}.el-table-filter__checkbox-group{padding:10px}.el-table-filter__checkbox-group label.el-checkbox{display:block;margin-right:5px;margin-bottom:8px;margin-left:5px}.el-table-filter__checkbox-group .el-checkbox:last-child{margin-bottom:0}.el-date-table{font-size:12px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.el-date-table.is-week-mode .el-date-table__row:hover td.available:hover{color:#606266}.el-date-table.is-week-mode .el-date-table__row:hover td:first-child div{margin-left:5px;border-top-left-radius:15px;border-bottom-left-radius:15px}.el-date-table.is-week-mode .el-date-table__row:hover td:last-child div{margin-right:5px;border-top-right-radius:15px;border-bottom-right-radius:15px}.el-date-table td{width:32px;padding:4px 0;text-align:center;cursor:pointer;position:relative}.el-date-table td,.el-date-table td div{-webkit-box-sizing:border-box;box-sizing:border-box}.el-date-table td div{padding:3px 0}.el-date-table td span{width:24px;height:24px;display:block;margin:0 auto;line-height:24px;position:absolute;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%);border-radius:50%}.el-date-table td.next-month,.el-date-table td.prev-month{color:#c0c4cc}.el-date-table td.today{position:relative}.el-date-table td.today span{color:#409eff;font-weight:700}.el-date-table td.today.end-date span,.el-date-table td.today.start-date span{color:#fff}.el-date-table td.available:hover{color:#409eff}.el-date-table td.current:not(.disabled) span{color:#fff;background-color:#409eff}.el-date-table td.end-date div,.el-date-table td.start-date div{color:#fff}.el-date-table td.end-date span,.el-date-table td.start-date span{background-color:#409eff}.el-date-table td.start-date div{margin-left:5px;border-top-left-radius:15px;border-bottom-left-radius:15px}.el-date-table td.end-date div{margin-right:5px;border-top-right-radius:15px;border-bottom-right-radius:15px}.el-date-table td.disabled div{background-color:#f5f7fa;opacity:1;cursor:not-allowed;color:#c0c4cc}.el-date-table td.selected div{margin-left:5px;margin-right:5px;background-color:#f2f6fc;border-radius:15px}.el-date-table td.selected div:hover{background-color:#f2f6fc}.el-date-table td.selected span{background-color:#409eff;color:#fff;border-radius:15px}.el-date-table td.week{font-size:80%;color:#606266}.el-month-table,.el-year-table{font-size:12px;border-collapse:collapse}.el-date-table th{padding:5px;color:#606266;font-weight:400;border-bottom:1px solid #ebeef5}.el-month-table{margin:-1px}.el-month-table td{text-align:center;padding:8px 0;cursor:pointer}.el-month-table td div{height:48px;padding:6px 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-month-table td.today .cell{color:#409eff;font-weight:700}.el-month-table td.today.end-date .cell,.el-month-table td.today.start-date .cell{color:#fff}.el-month-table td.disabled .cell{background-color:#f5f7fa;cursor:not-allowed;color:#c0c4cc}.el-month-table td.disabled .cell:hover{color:#c0c4cc}.el-month-table td .cell{width:60px;height:36px;display:block;line-height:36px;color:#606266;margin:0 auto;border-radius:18px}.el-month-table td .cell:hover{color:#409eff}.el-month-table td.in-range div,.el-month-table td.in-range div:hover{background-color:#f2f6fc}.el-month-table td.end-date div,.el-month-table td.start-date div{color:#fff}.el-month-table td.end-date .cell,.el-month-table td.start-date .cell{color:#fff;background-color:#409eff}.el-month-table td.start-date div{border-top-left-radius:24px;border-bottom-left-radius:24px}.el-month-table td.end-date div{border-top-right-radius:24px;border-bottom-right-radius:24px}.el-month-table td.current:not(.disabled) .cell{color:#409eff}.el-year-table{margin:-1px}.el-year-table .el-icon{color:#303133}.el-year-table td{text-align:center;padding:20px 3px;cursor:pointer}.el-year-table td.today .cell{color:#409eff;font-weight:700}.el-year-table td.disabled .cell{background-color:#f5f7fa;cursor:not-allowed;color:#c0c4cc}.el-year-table td.disabled .cell:hover{color:#c0c4cc}.el-year-table td .cell{width:48px;height:32px;display:block;line-height:32px;color:#606266;margin:0 auto}.el-year-table td .cell:hover,.el-year-table td.current:not(.disabled) .cell{color:#409eff}.el-date-range-picker{width:646px}.el-date-range-picker.has-sidebar{width:756px}.el-date-range-picker table{table-layout:fixed;width:100%}.el-date-range-picker .el-picker-panel__body{min-width:513px}.el-date-range-picker .el-picker-panel__content{margin:0}.el-date-range-picker__header{position:relative;text-align:center;height:28px}.el-date-range-picker__header [class*=arrow-left]{float:left}.el-date-range-picker__header [class*=arrow-right]{float:right}.el-date-range-picker__header div{font-size:16px;font-weight:500;margin-right:50px}.el-date-range-picker__content{float:left;width:50%;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:16px}.el-date-range-picker__content.is-left{border-right:1px solid #e4e4e4}.el-date-range-picker__content .el-date-range-picker__header div{margin-left:50px;margin-right:50px}.el-date-range-picker__editors-wrap{-webkit-box-sizing:border-box;box-sizing:border-box;display:table-cell}.el-date-range-picker__editors-wrap.is-right{text-align:right}.el-date-range-picker__time-header{position:relative;border-bottom:1px solid #e4e4e4;font-size:12px;padding:8px 5px 5px;display:table;width:100%;-webkit-box-sizing:border-box;box-sizing:border-box}.el-date-range-picker__time-header>.el-icon-arrow-right{font-size:20px;vertical-align:middle;display:table-cell;color:#303133}.el-date-range-picker__time-picker-wrap{position:relative;display:table-cell;padding:0 5px}.el-date-range-picker__time-picker-wrap .el-picker-panel{position:absolute;top:13px;right:0;z-index:1;background:#fff}.el-date-picker{width:322px}.el-date-picker.has-sidebar.has-time{width:434px}.el-date-picker.has-sidebar{width:438px}.el-date-picker.has-time .el-picker-panel__body-wrapper{position:relative}.el-date-picker .el-picker-panel__content{width:292px}.el-date-picker table{table-layout:fixed;width:100%}.el-date-picker__editor-wrap{position:relative;display:table-cell;padding:0 5px}.el-date-picker__time-header{position:relative;border-bottom:1px solid #e4e4e4;font-size:12px;padding:8px 5px 5px;display:table;width:100%;-webkit-box-sizing:border-box;box-sizing:border-box}.el-date-picker__header{margin:12px;text-align:center}.el-date-picker__header--bordered{margin-bottom:0;padding-bottom:12px;border-bottom:1px solid #ebeef5}.el-date-picker__header--bordered+.el-picker-panel__content{margin-top:0}.el-date-picker__header-label{font-size:16px;font-weight:500;padding:0 5px;line-height:22px;text-align:center;cursor:pointer;color:#606266}.el-date-picker__header-label.active,.el-date-picker__header-label:hover{color:#409eff}.el-date-picker__prev-btn{float:left}.el-date-picker__next-btn{float:right}.el-date-picker__time-wrap{padding:10px;text-align:center}.el-date-picker__time-label{float:left;cursor:pointer;line-height:30px;margin-left:10px}.time-select{margin:5px 0;min-width:0}.time-select .el-picker-panel__content{max-height:200px;margin:0}.time-select-item{padding:8px 10px;font-size:14px;line-height:20px}.time-select-item.selected:not(.disabled){color:#409eff;font-weight:700}.time-select-item.disabled{color:#e4e7ed;cursor:not-allowed}.time-select-item:hover{background-color:#f5f7fa;font-weight:700;cursor:pointer}.el-date-editor{position:relative;display:inline-block;text-align:left}.el-date-editor.el-input,.el-date-editor.el-input__inner{width:220px}.el-date-editor--monthrange.el-input,.el-date-editor--monthrange.el-input__inner{width:300px}.el-date-editor--daterange.el-input,.el-date-editor--daterange.el-input__inner,.el-date-editor--timerange.el-input,.el-date-editor--timerange.el-input__inner{width:350px}.el-date-editor--datetimerange.el-input,.el-date-editor--datetimerange.el-input__inner{width:400px}.el-date-editor--dates .el-input__inner{text-overflow:ellipsis;white-space:nowrap}.el-date-editor .el-icon-circle-close{cursor:pointer}.el-date-editor .el-range__icon{font-size:14px;margin-left:-5px;color:#c0c4cc;float:left;line-height:32px}.el-date-editor .el-range-input,.el-date-editor .el-range-separator{height:100%;margin:0;text-align:center;display:inline-block;font-size:14px}.el-date-editor .el-range-input{-webkit-appearance:none;-moz-appearance:none;appearance:none;border:none;outline:0;padding:0;width:39%;color:#606266}.el-date-editor .el-range-input::-webkit-input-placeholder{color:#c0c4cc}.el-date-editor .el-range-input:-ms-input-placeholder{color:#c0c4cc}.el-date-editor .el-range-input::-ms-input-placeholder{color:#c0c4cc}.el-date-editor .el-range-input::-moz-placeholder{color:#c0c4cc}.el-date-editor .el-range-input::placeholder{color:#c0c4cc}.el-date-editor .el-range-separator{padding:0 5px;line-height:32px;width:5%;color:#303133}.el-date-editor .el-range__close-icon{font-size:14px;color:#c0c4cc;width:25px;display:inline-block;float:right;line-height:32px}.el-range-editor.el-input__inner{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:3px 10px}.el-range-editor .el-range-input{line-height:1}.el-range-editor.is-active,.el-range-editor.is-active:hover{border-color:#409eff}.el-range-editor--medium.el-input__inner{height:36px}.el-range-editor--medium .el-range-separator{line-height:28px;font-size:14px}.el-range-editor--medium .el-range-input{font-size:14px}.el-range-editor--medium .el-range__close-icon,.el-range-editor--medium .el-range__icon{line-height:28px}.el-range-editor--small.el-input__inner{height:32px}.el-range-editor--small .el-range-separator{line-height:24px;font-size:13px}.el-range-editor--small .el-range-input{font-size:13px}.el-range-editor--small .el-range__close-icon,.el-range-editor--small .el-range__icon{line-height:24px}.el-range-editor--mini.el-input__inner{height:28px}.el-range-editor--mini .el-range-separator{line-height:20px;font-size:12px}.el-range-editor--mini .el-range-input{font-size:12px}.el-range-editor--mini .el-range__close-icon,.el-range-editor--mini .el-range__icon{line-height:20px}.el-range-editor.is-disabled{background-color:#f5f7fa;border-color:#e4e7ed;color:#c0c4cc;cursor:not-allowed}.el-range-editor.is-disabled:focus,.el-range-editor.is-disabled:hover{border-color:#e4e7ed}.el-range-editor.is-disabled input{background-color:#f5f7fa;color:#c0c4cc;cursor:not-allowed}.el-range-editor.is-disabled input::-webkit-input-placeholder{color:#c0c4cc}.el-range-editor.is-disabled input:-ms-input-placeholder{color:#c0c4cc}.el-range-editor.is-disabled input::-ms-input-placeholder{color:#c0c4cc}.el-range-editor.is-disabled input::-moz-placeholder{color:#c0c4cc}.el-range-editor.is-disabled input::placeholder{color:#c0c4cc}.el-range-editor.is-disabled .el-range-separator{color:#c0c4cc}.el-picker-panel{color:#606266;border:1px solid #e4e7ed;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);background:#fff;border-radius:4px;line-height:30px;margin:5px 0}.el-picker-panel,.el-popover,.el-time-panel{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-picker-panel__body-wrapper:after,.el-picker-panel__body:after{content:\"\";display:table;clear:both}.el-picker-panel__content{position:relative;margin:15px}.el-picker-panel__footer{border-top:1px solid #e4e4e4;padding:4px;text-align:right;background-color:#fff;position:relative;font-size:0}.el-picker-panel__shortcut{display:block;width:100%;border:0;background-color:transparent;line-height:28px;font-size:14px;color:#606266;padding-left:12px;text-align:left;outline:0;cursor:pointer}.el-picker-panel__shortcut:hover{color:#409eff}.el-picker-panel__shortcut.active{background-color:#e6f1fe;color:#409eff}.el-picker-panel__btn{border:1px solid #dcdcdc;color:#333;line-height:24px;border-radius:2px;padding:0 20px;cursor:pointer;background-color:transparent;outline:0;font-size:12px}.el-picker-panel__btn[disabled]{color:#ccc;cursor:not-allowed}.el-picker-panel__icon-btn{font-size:12px;color:#303133;border:0;background:0 0;cursor:pointer;outline:0;margin-top:8px}.el-picker-panel__icon-btn:hover{color:#409eff}.el-picker-panel__icon-btn.is-disabled{color:#bbb}.el-picker-panel__icon-btn.is-disabled:hover{cursor:not-allowed}.el-picker-panel__link-btn{vertical-align:middle}.el-picker-panel [slot=sidebar],.el-picker-panel__sidebar{position:absolute;top:0;bottom:0;width:110px;border-right:1px solid #e4e4e4;-webkit-box-sizing:border-box;box-sizing:border-box;padding-top:6px;background-color:#fff;overflow:auto}.el-picker-panel [slot=sidebar]+.el-picker-panel__body,.el-picker-panel__sidebar+.el-picker-panel__body{margin-left:110px}.el-time-spinner.has-seconds .el-time-spinner__wrapper{width:33.3%}.el-time-spinner__wrapper{max-height:190px;overflow:auto;display:inline-block;width:50%;vertical-align:top;position:relative}.el-time-spinner__wrapper .el-scrollbar__wrap:not(.el-scrollbar__wrap--hidden-default){padding-bottom:15px}.el-time-spinner__input.el-input .el-input__inner,.el-time-spinner__list{padding:0;text-align:center}.el-time-spinner__wrapper.is-arrow{-webkit-box-sizing:border-box;box-sizing:border-box;text-align:center;overflow:hidden}.el-time-spinner__wrapper.is-arrow .el-time-spinner__list{-webkit-transform:translateY(-32px);transform:translateY(-32px)}.el-time-spinner__wrapper.is-arrow .el-time-spinner__item:hover:not(.disabled):not(.active){background:#fff;cursor:default}.el-time-spinner__arrow{font-size:12px;color:#909399;position:absolute;left:0;width:100%;z-index:1;text-align:center;height:30px;line-height:30px;cursor:pointer}.el-time-spinner__arrow:hover{color:#409eff}.el-time-spinner__arrow.el-icon-arrow-up{top:10px}.el-time-spinner__arrow.el-icon-arrow-down{bottom:10px}.el-time-spinner__input.el-input{width:70%}.el-time-spinner__list{margin:0;list-style:none}.el-time-spinner__list:after,.el-time-spinner__list:before{content:\"\";display:block;width:100%;height:80px}.el-time-spinner__item{height:32px;line-height:32px;font-size:12px;color:#606266}.el-time-spinner__item:hover:not(.disabled):not(.active){background:#f5f7fa;cursor:pointer}.el-time-spinner__item.active:not(.disabled){color:#303133;font-weight:700}.el-time-spinner__item.disabled{color:#c0c4cc;cursor:not-allowed}.el-time-panel{margin:5px 0;border:1px solid #e4e7ed;background-color:#fff;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);border-radius:2px;position:absolute;width:180px;left:0;z-index:1000;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-box-sizing:content-box;box-sizing:content-box}.el-time-panel__content{font-size:0;position:relative;overflow:hidden}.el-time-panel__content:after,.el-time-panel__content:before{content:\"\";top:50%;position:absolute;margin-top:-15px;height:32px;z-index:-1;left:0;right:0;-webkit-box-sizing:border-box;box-sizing:border-box;padding-top:6px;text-align:left;border-top:1px solid #e4e7ed;border-bottom:1px solid #e4e7ed}.el-time-panel__content:after{left:50%;margin-left:12%;margin-right:12%}.el-time-panel__content:before{padding-left:50%;margin-right:12%;margin-left:12%}.el-time-panel__content.has-seconds:after{left:66.66667%}.el-time-panel__content.has-seconds:before{padding-left:33.33333%}.el-time-panel__footer{border-top:1px solid #e4e4e4;padding:4px;height:36px;line-height:25px;text-align:right;-webkit-box-sizing:border-box;box-sizing:border-box}.el-time-panel__btn{border:none;line-height:28px;padding:0 5px;margin:0 5px;cursor:pointer;background-color:transparent;outline:0;font-size:12px;color:#303133}.el-time-panel__btn.confirm{font-weight:800;color:#409eff}.el-time-range-picker{width:354px;overflow:visible}.el-time-range-picker__content{position:relative;text-align:center;padding:10px}.el-time-range-picker__cell{-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:4px 7px 7px;width:50%;display:inline-block}.el-time-range-picker__header{margin-bottom:5px;text-align:center;font-size:14px}.el-time-range-picker__body{border-radius:2px;border:1px solid #e4e7ed}.el-popover{position:absolute;background:#fff;min-width:150px;border:1px solid #ebeef5;padding:12px;z-index:2000;color:#606266;line-height:1.4;text-align:justify;font-size:14px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);word-break:break-all}.el-popover--plain{padding:18px 20px}.el-popover__title{color:#303133;font-size:16px;line-height:1;margin-bottom:12px}.v-modal-enter{-webkit-animation:v-modal-in .2s ease;animation:v-modal-in .2s ease}.v-modal-leave{-webkit-animation:v-modal-out .2s ease forwards;animation:v-modal-out .2s ease forwards}@keyframes v-modal-in{0%{opacity:0}}@keyframes v-modal-out{to{opacity:0}}.v-modal{position:fixed;left:0;top:0;width:100%;height:100%;opacity:.5;background:#000}.el-popup-parent--hidden{overflow:hidden}.el-message-box{display:inline-block;width:420px;padding-bottom:10px;vertical-align:middle;background-color:#fff;border-radius:4px;border:1px solid #ebeef5;font-size:18px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);text-align:left;overflow:hidden;-webkit-backface-visibility:hidden;backface-visibility:hidden}.el-message-box__wrapper{position:fixed;top:0;bottom:0;left:0;right:0;text-align:center}.el-message-box__wrapper:after{content:\"\";display:inline-block;height:100%;width:0;vertical-align:middle}.el-message-box__header{position:relative;padding:15px 15px 10px}.el-message-box__title{padding-left:0;margin-bottom:0;font-size:18px;line-height:1;color:#303133}.el-message-box__headerbtn{position:absolute;top:15px;right:15px;padding:0;border:none;outline:0;background:0 0;font-size:16px;cursor:pointer}.el-form-item.is-error .el-input__inner,.el-form-item.is-error .el-input__inner:focus,.el-form-item.is-error .el-textarea__inner,.el-form-item.is-error .el-textarea__inner:focus,.el-message-box__input input.invalid,.el-message-box__input input.invalid:focus{border-color:#f56c6c}.el-message-box__headerbtn .el-message-box__close{color:#909399}.el-message-box__headerbtn:focus .el-message-box__close,.el-message-box__headerbtn:hover .el-message-box__close{color:#409eff}.el-message-box__content{position:relative;padding:10px 15px;color:#606266;font-size:14px}.el-message-box__input{padding-top:15px}.el-message-box__status{position:absolute;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);font-size:24px!important}.el-message-box__status:before{padding-left:1px}.el-message-box__status+.el-message-box__message{padding-left:36px;padding-right:12px}.el-message-box__status.el-icon-success{color:#67c23a}.el-message-box__status.el-icon-info{color:#909399}.el-message-box__status.el-icon-warning{color:#e6a23c}.el-message-box__status.el-icon-error{color:#f56c6c}.el-message-box__message{margin:0}.el-message-box__message p{margin:0;line-height:24px}.el-message-box__errormsg{color:#f56c6c;font-size:12px;min-height:18px;margin-top:2px}.el-message-box__btns{padding:5px 15px 0;text-align:right}.el-message-box__btns button:nth-child(2){margin-left:10px}.el-message-box__btns-reverse{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.el-message-box--center{padding-bottom:30px}.el-message-box--center .el-message-box__header{padding-top:30px}.el-message-box--center .el-message-box__title{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-message-box--center .el-message-box__status{position:relative;top:auto;padding-right:5px;text-align:center;-webkit-transform:translateY(-1px);transform:translateY(-1px)}.el-message-box--center .el-message-box__message{margin-left:0}.el-message-box--center .el-message-box__btns,.el-message-box--center .el-message-box__content{text-align:center}.el-message-box--center .el-message-box__content{padding-left:27px;padding-right:27px}.msgbox-fade-enter-active{-webkit-animation:msgbox-fade-in .3s;animation:msgbox-fade-in .3s}.msgbox-fade-leave-active{-webkit-animation:msgbox-fade-out .3s;animation:msgbox-fade-out .3s}@-webkit-keyframes msgbox-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}to{-webkit-transform:translateZ(0);transform:translateZ(0);opacity:1}}@keyframes msgbox-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}to{-webkit-transform:translateZ(0);transform:translateZ(0);opacity:1}}@-webkit-keyframes msgbox-fade-out{0%{-webkit-transform:translateZ(0);transform:translateZ(0);opacity:1}to{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}@keyframes msgbox-fade-out{0%{-webkit-transform:translateZ(0);transform:translateZ(0);opacity:1}to{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}.el-breadcrumb{font-size:14px;line-height:1}.el-breadcrumb:after,.el-breadcrumb:before{display:table;content:\"\"}.el-breadcrumb:after{clear:both}.el-breadcrumb__separator{margin:0 9px;font-weight:700;color:#c0c4cc}.el-breadcrumb__separator[class*=icon]{margin:0 6px;font-weight:400}.el-breadcrumb__item{float:left}.el-breadcrumb__inner{color:#606266}.el-breadcrumb__inner.is-link,.el-breadcrumb__inner a{font-weight:700;text-decoration:none;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1);color:#303133}.el-breadcrumb__inner.is-link:hover,.el-breadcrumb__inner a:hover{color:#409eff;cursor:pointer}.el-breadcrumb__item:last-child .el-breadcrumb__inner,.el-breadcrumb__item:last-child .el-breadcrumb__inner:hover,.el-breadcrumb__item:last-child .el-breadcrumb__inner a,.el-breadcrumb__item:last-child .el-breadcrumb__inner a:hover{font-weight:400;color:#606266;cursor:text}.el-breadcrumb__item:last-child .el-breadcrumb__separator{display:none}.el-form--label-left .el-form-item__label{text-align:left}.el-form--label-top .el-form-item__label{float:none;display:inline-block;text-align:left;padding:0 0 10px}.el-form--inline .el-form-item{display:inline-block;margin-right:10px;vertical-align:top}.el-form--inline .el-form-item__label{float:none;display:inline-block}.el-form--inline .el-form-item__content{display:inline-block;vertical-align:top}.el-form-item__content .el-input-group,.el-form-item__label,.el-tag .el-icon-close{vertical-align:middle}.el-form--inline.el-form--label-top .el-form-item__content{display:block}.el-form-item{margin-bottom:22px}.el-form-item:after,.el-form-item:before{display:table;content:\"\"}.el-form-item:after{clear:both}.el-form-item .el-form-item{margin-bottom:0}.el-form-item--mini.el-form-item,.el-form-item--small.el-form-item{margin-bottom:18px}.el-form-item .el-input__validateIcon{display:none}.el-form-item--medium .el-form-item__content,.el-form-item--medium .el-form-item__label{line-height:36px}.el-form-item--small .el-form-item__content,.el-form-item--small .el-form-item__label{line-height:32px}.el-form-item--small .el-form-item__error{padding-top:2px}.el-form-item--mini .el-form-item__content,.el-form-item--mini .el-form-item__label{line-height:28px}.el-form-item--mini .el-form-item__error{padding-top:1px}.el-form-item__label-wrap{float:left;text-align:right}.el-form-item__label-wrap .el-form-item__label{display:inline-block;float:none}.el-form-item__label{text-align:right;float:left;font-size:14px;color:#606266;line-height:40px;padding:0 12px 0 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-form-item__content{line-height:40px;position:relative;font-size:14px}.el-form-item__content:after,.el-form-item__content:before{display:table;content:\"\"}.el-form-item__content:after{clear:both}.el-form-item__error{color:#f56c6c;font-size:12px;line-height:1;padding-top:4px;position:absolute;top:100%;left:0}.el-form-item__error--inline{position:relative;top:auto;left:auto;display:inline-block;margin-left:10px}.el-form-item.is-required:not(.is-no-asterisk)>.el-form-item__label:before{content:\"*\";color:#f56c6c;margin-right:4px}.el-form-item.is-error .el-input-group__append .el-input__inner,.el-form-item.is-error .el-input-group__prepend .el-input__inner{border-color:transparent}.el-form-item.is-error .el-input__validateIcon{color:#f56c6c}.el-form-item.is-success .el-input__inner,.el-form-item.is-success .el-input__inner:focus,.el-form-item.is-success .el-textarea__inner,.el-form-item.is-success .el-textarea__inner:focus{border-color:#67c23a}.el-form-item.is-success .el-input-group__append .el-input__inner,.el-form-item.is-success .el-input-group__prepend .el-input__inner{border-color:transparent}.el-form-item.is-success .el-input__validateIcon{color:#67c23a}.el-form-item--feedback .el-input__validateIcon{display:inline-block}.el-tabs__header{padding:0;position:relative;margin:0 0 15px}.el-tabs__active-bar{position:absolute;bottom:0;left:0;height:2px;background-color:#409eff;z-index:1;-webkit-transition:-webkit-transform .3s cubic-bezier(.645,.045,.355,1);transition:-webkit-transform .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1),-webkit-transform .3s cubic-bezier(.645,.045,.355,1);list-style:none}.el-tabs__new-tab{float:right;border:1px solid #d3dce6;height:18px;width:18px;line-height:18px;margin:12px 0 9px 10px;border-radius:3px;text-align:center;font-size:12px;color:#d3dce6;cursor:pointer;-webkit-transition:all .15s;transition:all .15s}.el-tabs__new-tab .el-icon-plus{-webkit-transform:scale(.8);transform:scale(.8)}.el-tabs__new-tab:hover{color:#409eff}.el-tabs__nav-wrap{overflow:hidden;margin-bottom:-1px;position:relative}.el-tabs__nav-wrap:after{content:\"\";position:absolute;left:0;bottom:0;width:100%;height:2px;background-color:#e4e7ed;z-index:1}.el-tabs--border-card>.el-tabs__header .el-tabs__nav-wrap:after,.el-tabs--card>.el-tabs__header .el-tabs__nav-wrap:after{content:none}.el-tabs__nav-wrap.is-scrollable{padding:0 20px;-webkit-box-sizing:border-box;box-sizing:border-box}.el-tabs__nav-scroll{overflow:hidden}.el-tabs__nav-next,.el-tabs__nav-prev{position:absolute;cursor:pointer;line-height:44px;font-size:12px;color:#909399}.el-tabs__nav-next{right:0}.el-tabs__nav-prev{left:0}.el-tabs__nav{white-space:nowrap;position:relative;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;float:left;z-index:2}.el-tabs__nav.is-stretch{min-width:100%;display:-webkit-box;display:-ms-flexbox;display:flex}.el-tabs__nav.is-stretch>*{-webkit-box-flex:1;-ms-flex:1;flex:1;text-align:center}.el-tabs__item{padding:0 20px;height:40px;-webkit-box-sizing:border-box;box-sizing:border-box;line-height:40px;display:inline-block;list-style:none;font-size:14px;font-weight:500;color:#303133;position:relative}.el-tabs__item:focus,.el-tabs__item:focus:active{outline:0}.el-tabs__item:focus.is-active.is-focus:not(:active){-webkit-box-shadow:0 0 2px 2px #409eff inset;box-shadow:inset 0 0 2px 2px #409eff;border-radius:3px}.el-tabs__item .el-icon-close{border-radius:50%;text-align:center;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);margin-left:5px}.el-tabs__item .el-icon-close:before{-webkit-transform:scale(.9);transform:scale(.9);display:inline-block}.el-tabs__item .el-icon-close:hover{background-color:#c0c4cc;color:#fff}.el-tabs__item.is-active{color:#409eff}.el-tabs__item:hover{color:#409eff;cursor:pointer}.el-tabs__item.is-disabled{color:#c0c4cc;cursor:default}.el-tabs__content{overflow:hidden;position:relative}.el-tabs--card>.el-tabs__header{border-bottom:1px solid #e4e7ed}.el-tabs--card>.el-tabs__header .el-tabs__nav{border:1px solid #e4e7ed;border-bottom:none;border-radius:4px 4px 0 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-alert,.el-tag{-webkit-box-sizing:border-box}.el-tabs--card>.el-tabs__header .el-tabs__active-bar{display:none}.el-tabs--card>.el-tabs__header .el-tabs__item .el-icon-close{position:relative;font-size:12px;width:0;height:14px;vertical-align:middle;line-height:15px;overflow:hidden;top:-1px;right:-2px;-webkit-transform-origin:100% 50%;transform-origin:100% 50%}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active.is-closable .el-icon-close,.el-tabs--card>.el-tabs__header .el-tabs__item.is-closable:hover .el-icon-close{width:14px}.el-tabs--card>.el-tabs__header .el-tabs__item{border-bottom:1px solid transparent;border-left:1px solid #e4e7ed;-webkit-transition:color .3s cubic-bezier(.645,.045,.355,1),padding .3s cubic-bezier(.645,.045,.355,1);transition:color .3s cubic-bezier(.645,.045,.355,1),padding .3s cubic-bezier(.645,.045,.355,1)}.el-tabs--card>.el-tabs__header .el-tabs__item:first-child{border-left:none}.el-tabs--card>.el-tabs__header .el-tabs__item.is-closable:hover{padding-left:13px;padding-right:13px}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active{border-bottom-color:#fff}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active.is-closable{padding-left:20px;padding-right:20px}.el-tabs--border-card{background:#fff;border:1px solid #dcdfe6;-webkit-box-shadow:0 2px 4px 0 rgba(0,0,0,.12),0 0 6px 0 rgba(0,0,0,.04);box-shadow:0 2px 4px 0 rgba(0,0,0,.12),0 0 6px 0 rgba(0,0,0,.04)}.el-tabs--border-card>.el-tabs__content{padding:15px}.el-tabs--border-card>.el-tabs__header{background-color:#f5f7fa;border-bottom:1px solid #e4e7ed;margin:0}.el-tabs--border-card>.el-tabs__header .el-tabs__item{-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);border:1px solid transparent;margin-top:-1px;color:#909399}.el-tabs--border-card>.el-tabs__header .el-tabs__item+.el-tabs__item,.el-tabs--border-card>.el-tabs__header .el-tabs__item:first-child{margin-left:-1px}.el-tabs--border-card>.el-tabs__header .el-tabs__item.is-active{color:#409eff;background-color:#fff;border-right-color:#dcdfe6;border-left-color:#dcdfe6}.el-tabs--border-card>.el-tabs__header .el-tabs__item:not(.is-disabled):hover{color:#409eff}.el-tabs--border-card>.el-tabs__header .el-tabs__item.is-disabled{color:#c0c4cc}.el-tabs--border-card>.el-tabs__header .is-scrollable .el-tabs__item:first-child{margin-left:0}.el-tabs--bottom .el-tabs__item.is-bottom:nth-child(2),.el-tabs--bottom .el-tabs__item.is-top:nth-child(2),.el-tabs--top .el-tabs__item.is-bottom:nth-child(2),.el-tabs--top .el-tabs__item.is-top:nth-child(2){padding-left:0}.el-tabs--bottom .el-tabs__item.is-bottom:last-child,.el-tabs--bottom .el-tabs__item.is-top:last-child,.el-tabs--top .el-tabs__item.is-bottom:last-child,.el-tabs--top .el-tabs__item.is-top:last-child{padding-right:0}.el-tabs--bottom.el-tabs--border-card .el-tabs__item:nth-child(2),.el-tabs--bottom.el-tabs--card .el-tabs__item:nth-child(2),.el-tabs--bottom .el-tabs--left .el-tabs__item:nth-child(2),.el-tabs--bottom .el-tabs--right .el-tabs__item:nth-child(2),.el-tabs--top.el-tabs--border-card .el-tabs__item:nth-child(2),.el-tabs--top.el-tabs--card .el-tabs__item:nth-child(2),.el-tabs--top .el-tabs--left .el-tabs__item:nth-child(2),.el-tabs--top .el-tabs--right .el-tabs__item:nth-child(2){padding-left:20px}.el-tabs--bottom.el-tabs--border-card .el-tabs__item:last-child,.el-tabs--bottom.el-tabs--card .el-tabs__item:last-child,.el-tabs--bottom .el-tabs--left .el-tabs__item:last-child,.el-tabs--bottom .el-tabs--right .el-tabs__item:last-child,.el-tabs--top.el-tabs--border-card .el-tabs__item:last-child,.el-tabs--top.el-tabs--card .el-tabs__item:last-child,.el-tabs--top .el-tabs--left .el-tabs__item:last-child,.el-tabs--top .el-tabs--right .el-tabs__item:last-child{padding-right:20px}.el-tabs--bottom .el-tabs__header.is-bottom{margin-bottom:0;margin-top:10px}.el-tabs--bottom.el-tabs--border-card .el-tabs__header.is-bottom{border-bottom:0;border-top:1px solid #dcdfe6}.el-tabs--bottom.el-tabs--border-card .el-tabs__nav-wrap.is-bottom{margin-top:-1px;margin-bottom:0}.el-tabs--bottom.el-tabs--border-card .el-tabs__item.is-bottom:not(.is-active){border:1px solid transparent}.el-tabs--bottom.el-tabs--border-card .el-tabs__item.is-bottom{margin:0 -1px -1px}.el-tabs--left,.el-tabs--right{overflow:hidden}.el-tabs--left .el-tabs__header.is-left,.el-tabs--left .el-tabs__header.is-right,.el-tabs--left .el-tabs__nav-scroll,.el-tabs--left .el-tabs__nav-wrap.is-left,.el-tabs--left .el-tabs__nav-wrap.is-right,.el-tabs--right .el-tabs__header.is-left,.el-tabs--right .el-tabs__header.is-right,.el-tabs--right .el-tabs__nav-scroll,.el-tabs--right .el-tabs__nav-wrap.is-left,.el-tabs--right .el-tabs__nav-wrap.is-right{height:100%}.el-tabs--left .el-tabs__active-bar.is-left,.el-tabs--left .el-tabs__active-bar.is-right,.el-tabs--right .el-tabs__active-bar.is-left,.el-tabs--right .el-tabs__active-bar.is-right{top:0;bottom:auto;width:2px;height:auto}.el-tabs--left .el-tabs__nav-wrap.is-left,.el-tabs--left .el-tabs__nav-wrap.is-right,.el-tabs--right .el-tabs__nav-wrap.is-left,.el-tabs--right .el-tabs__nav-wrap.is-right{margin-bottom:0}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev{height:30px;line-height:30px;width:100%;text-align:center;cursor:pointer}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next i,.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev i,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next i,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev i,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next i,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev i,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next i,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev i{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev{left:auto;top:0}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next{right:auto;bottom:0}.el-tabs--left .el-tabs__active-bar.is-left,.el-tabs--left .el-tabs__nav-wrap.is-left:after{right:0;left:auto}.el-tabs--left .el-tabs__nav-wrap.is-left.is-scrollable,.el-tabs--left .el-tabs__nav-wrap.is-right.is-scrollable,.el-tabs--right .el-tabs__nav-wrap.is-left.is-scrollable,.el-tabs--right .el-tabs__nav-wrap.is-right.is-scrollable{padding:30px 0}.el-tabs--left .el-tabs__nav-wrap.is-left:after,.el-tabs--left .el-tabs__nav-wrap.is-right:after,.el-tabs--right .el-tabs__nav-wrap.is-left:after,.el-tabs--right .el-tabs__nav-wrap.is-right:after{height:100%;width:2px;bottom:auto;top:0}.el-tabs--left .el-tabs__nav.is-left,.el-tabs--left .el-tabs__nav.is-right,.el-tabs--right .el-tabs__nav.is-left,.el-tabs--right .el-tabs__nav.is-right{float:none}.el-tabs--left .el-tabs__item.is-left,.el-tabs--left .el-tabs__item.is-right,.el-tabs--right .el-tabs__item.is-left,.el-tabs--right .el-tabs__item.is-right{display:block}.el-tabs--left.el-tabs--card .el-tabs__active-bar.is-left,.el-tabs--right.el-tabs--card .el-tabs__active-bar.is-right{display:none}.el-tabs--left .el-tabs__header.is-left{float:left;margin-bottom:0;margin-right:10px}.el-tabs--left .el-tabs__nav-wrap.is-left{margin-right:-1px}.el-tabs--left .el-tabs__item.is-left{text-align:right}.el-tabs--left.el-tabs--card .el-tabs__item.is-left{border-left:none;border-right:1px solid #e4e7ed;border-bottom:none;border-top:1px solid #e4e7ed}.el-tabs--left.el-tabs--card .el-tabs__item.is-left:first-child{border-right:1px solid #e4e7ed;border-top:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active{border:1px solid #e4e7ed;border-right-color:#fff;border-left:none;border-bottom:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active:first-child{border-top:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active:last-child{border-bottom:none}.el-tabs--left.el-tabs--card .el-tabs__nav{border-radius:4px 0 0 4px;border-bottom:1px solid #e4e7ed;border-right:none}.el-tabs--left.el-tabs--card .el-tabs__new-tab{float:none}.el-tabs--left.el-tabs--border-card .el-tabs__header.is-left{border-right:1px solid #dfe4ed}.el-tabs--left.el-tabs--border-card .el-tabs__item.is-left{border:1px solid transparent;margin:-1px 0 -1px -1px}.el-tabs--left.el-tabs--border-card .el-tabs__item.is-left.is-active{border-color:#d1dbe5 transparent}.el-tabs--right .el-tabs__header.is-right{float:right;margin-bottom:0;margin-left:10px}.el-tabs--right .el-tabs__nav-wrap.is-right{margin-left:-1px}.el-tabs--right .el-tabs__nav-wrap.is-right:after{left:0;right:auto}.el-tabs--right .el-tabs__active-bar.is-right{left:0}.el-tag,.slideInLeft-transition,.slideInRight-transition{display:inline-block}.el-tabs--right.el-tabs--card .el-tabs__item.is-right{border-bottom:none;border-top:1px solid #e4e7ed}.el-tabs--right.el-tabs--card .el-tabs__item.is-right:first-child{border-left:1px solid #e4e7ed;border-top:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active{border:1px solid #e4e7ed;border-left-color:#fff;border-right:none;border-bottom:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active:first-child{border-top:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active:last-child{border-bottom:none}.el-tabs--right.el-tabs--card .el-tabs__nav{border-radius:0 4px 4px 0;border-bottom:1px solid #e4e7ed;border-left:none}.el-tabs--right.el-tabs--border-card .el-tabs__header.is-right{border-left:1px solid #dfe4ed}.el-tabs--right.el-tabs--border-card .el-tabs__item.is-right{border:1px solid transparent;margin:-1px -1px -1px 0}.el-tabs--right.el-tabs--border-card .el-tabs__item.is-right.is-active{border-color:#d1dbe5 transparent}.slideInRight-enter{-webkit-animation:slideInRight-enter .3s;animation:slideInRight-enter .3s}.slideInRight-leave{position:absolute;left:0;right:0;-webkit-animation:slideInRight-leave .3s;animation:slideInRight-leave .3s}.slideInLeft-enter{-webkit-animation:slideInLeft-enter .3s;animation:slideInLeft-enter .3s}.slideInLeft-leave{position:absolute;left:0;right:0;-webkit-animation:slideInLeft-leave .3s;animation:slideInLeft-leave .3s}@-webkit-keyframes slideInRight-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes slideInRight-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@-webkit-keyframes slideInRight-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}to{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%);opacity:0}}@keyframes slideInRight-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}to{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%);opacity:0}}@-webkit-keyframes slideInLeft-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes slideInLeft-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@-webkit-keyframes slideInLeft-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}to{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%);opacity:0}}@keyframes slideInLeft-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}to{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%);opacity:0}}.el-tag{background-color:rgba(64,158,255,.1);padding:0 10px;height:32px;line-height:30px;font-size:12px;color:#409eff;border-radius:4px;-webkit-box-sizing:border-box;box-sizing:border-box;border:1px solid rgba(64,158,255,.2);white-space:nowrap}.el-tag .el-icon-close{border-radius:50%;text-align:center;position:relative;cursor:pointer;font-size:12px;height:16px;width:16px;line-height:16px;top:-1px;right:-5px;color:#409eff}.el-tag .el-icon-close:before{display:block}.el-tag .el-icon-close:hover{background-color:#409eff;color:#fff}.el-tag--info,.el-tag--info .el-tag__close{color:#909399}.el-tag--info{background-color:rgba(144,147,153,.1);border-color:rgba(144,147,153,.2)}.el-tag--info.is-hit{border-color:#909399}.el-tag--info .el-tag__close:hover{background-color:#909399;color:#fff}.el-tag--success{background-color:rgba(103,194,58,.1);border-color:rgba(103,194,58,.2);color:#67c23a}.el-tag--success.is-hit{border-color:#67c23a}.el-tag--success .el-tag__close{color:#67c23a}.el-tag--success .el-tag__close:hover{background-color:#67c23a;color:#fff}.el-tag--warning{background-color:rgba(230,162,60,.1);border-color:rgba(230,162,60,.2);color:#e6a23c}.el-tag--warning.is-hit{border-color:#e6a23c}.el-tag--warning .el-tag__close{color:#e6a23c}.el-tag--warning .el-tag__close:hover{background-color:#e6a23c;color:#fff}.el-tag--danger{background-color:rgba(245,108,108,.1);border-color:rgba(245,108,108,.2);color:#f56c6c}.el-tag--danger.is-hit{border-color:#f56c6c}.el-tag--danger .el-tag__close{color:#f56c6c}.el-tag--danger .el-tag__close:hover{background-color:#f56c6c;color:#fff}.el-tag--medium{height:28px;line-height:26px}.el-tag--medium .el-icon-close{-webkit-transform:scale(.8);transform:scale(.8)}.el-tag--small{height:24px;padding:0 8px;line-height:22px}.el-tag--small .el-icon-close{-webkit-transform:scale(.8);transform:scale(.8)}.el-tag--mini{height:20px;padding:0 5px;line-height:19px}.el-tag--mini .el-icon-close{margin-left:-3px;-webkit-transform:scale(.7);transform:scale(.7)}.el-tree{position:relative;cursor:default;background:#fff;color:#606266}.el-tree__empty-block{position:relative;min-height:60px;text-align:center;width:100%;height:100%}.el-tree__empty-text{position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);color:#909399}.el-tree__drop-indicator{position:absolute;left:0;right:0;height:1px;background-color:#409eff}.el-tree-node{white-space:nowrap;outline:0}.el-tree-node:focus>.el-tree-node__content{background-color:#f5f7fa}.el-tree-node.is-drop-inner>.el-tree-node__content .el-tree-node__label{background-color:#409eff;color:#fff}.el-tree-node__content{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:26px;cursor:pointer}.el-tree-node__content>.el-tree-node__expand-icon{padding:6px}.el-tree-node__content>.el-checkbox{margin-right:8px}.el-tree-node__content:hover{background-color:#f5f7fa}.el-tree.is-dragging .el-tree-node__content{cursor:move}.el-tree.is-dragging.is-drop-not-allow .el-tree-node__content{cursor:not-allowed}.el-tree-node__expand-icon{cursor:pointer;color:#c0c4cc;font-size:12px;-webkit-transform:rotate(0);transform:rotate(0);-webkit-transition:-webkit-transform .3s ease-in-out;transition:-webkit-transform .3s ease-in-out;transition:transform .3s ease-in-out;transition:transform .3s ease-in-out,-webkit-transform .3s ease-in-out}.el-tree-node__expand-icon.expanded{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-tree-node__expand-icon.is-leaf{color:transparent;cursor:default}.el-tree-node__label{font-size:14px}.el-tree-node__loading-icon{margin-right:8px;font-size:14px;color:#c0c4cc}.el-tree-node>.el-tree-node__children{overflow:hidden;background-color:transparent}.el-tree-node.is-expanded>.el-tree-node__children{display:block}.el-tree--highlight-current .el-tree-node.is-current>.el-tree-node__content{background-color:#f0f7ff}.el-alert{width:100%;padding:8px 16px;margin:0;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:4px;position:relative;background-color:#fff;overflow:hidden;opacity:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:opacity .2s;transition:opacity .2s}.el-alert.is-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-alert--success{background-color:#f0f9eb;color:#67c23a}.el-alert--success .el-alert__description{color:#67c23a}.el-alert--info{background-color:#f4f4f5;color:#909399}.el-alert--info .el-alert__description{color:#909399}.el-alert--warning{background-color:#fdf6ec;color:#e6a23c}.el-alert--warning .el-alert__description{color:#e6a23c}.el-alert--error{background-color:#fef0f0;color:#f56c6c}.el-alert--error .el-alert__description{color:#f56c6c}.el-alert__content{display:table-cell;padding:0 8px}.el-alert__icon{font-size:16px;width:16px}.el-alert__icon.is-big{font-size:28px;width:28px}.el-alert__title{font-size:13px;line-height:18px}.el-alert__title.is-bold{font-weight:700}.el-alert .el-alert__description{font-size:12px;margin:5px 0 0}.el-alert__closebtn{font-size:12px;color:#c0c4cc;opacity:1;position:absolute;top:12px;right:15px;cursor:pointer}.el-alert-fade-enter,.el-alert-fade-leave-active,.el-loading-fade-enter,.el-loading-fade-leave-active,.el-notification-fade-leave-active{opacity:0}.el-alert__closebtn.is-customed{font-style:normal;font-size:13px;top:9px}.el-notification{display:-webkit-box;display:-ms-flexbox;display:flex;width:330px;padding:14px 26px 14px 13px;border-radius:8px;-webkit-box-sizing:border-box;box-sizing:border-box;border:1px solid #ebeef5;position:fixed;background-color:#fff;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-transition:opacity .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;transition:opacity .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;transition:opacity .3s,transform .3s,left .3s,right .3s,top .4s,bottom .3s;transition:opacity .3s,transform .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;overflow:hidden}.el-notification.right{right:16px}.el-notification.left{left:16px}.el-notification__group{margin-left:13px}.el-notification__title{font-weight:700;font-size:16px;color:#303133;margin:0}.el-notification__content{font-size:14px;line-height:21px;margin:6px 0 0;color:#606266;text-align:justify}.el-notification__content p{margin:0}.el-notification__icon{height:24px;width:24px;font-size:24px}.el-notification__closeBtn{position:absolute;top:18px;right:15px;cursor:pointer;color:#909399;font-size:16px}.el-notification__closeBtn:hover{color:#606266}.el-notification .el-icon-success{color:#67c23a}.el-notification .el-icon-error{color:#f56c6c}.el-notification .el-icon-info{color:#909399}.el-notification .el-icon-warning{color:#e6a23c}.el-notification-fade-enter.right{right:0;-webkit-transform:translateX(100%);transform:translateX(100%)}.el-notification-fade-enter.left{left:0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}.el-input-number{position:relative;display:inline-block;width:180px;line-height:38px}.el-input-number .el-input{display:block}.el-input-number .el-input__inner{-webkit-appearance:none;padding-left:50px;padding-right:50px;text-align:center}.el-input-number__decrease,.el-input-number__increase{position:absolute;z-index:1;top:1px;width:40px;height:auto;text-align:center;background:#f5f7fa;color:#606266;cursor:pointer;font-size:13px}.el-input-number__decrease:hover,.el-input-number__increase:hover{color:#409eff}.el-input-number__decrease:hover:not(.is-disabled)~.el-input .el-input__inner:not(.is-disabled),.el-input-number__increase:hover:not(.is-disabled)~.el-input .el-input__inner:not(.is-disabled){border-color:#409eff}.el-input-number__decrease.is-disabled,.el-input-number__increase.is-disabled{color:#c0c4cc;cursor:not-allowed}.el-input-number__increase{right:1px;border-radius:0 4px 4px 0;border-left:1px solid #dcdfe6}.el-input-number__decrease{left:1px;border-radius:4px 0 0 4px;border-right:1px solid #dcdfe6}.el-input-number.is-disabled .el-input-number__decrease,.el-input-number.is-disabled .el-input-number__increase{border-color:#e4e7ed;color:#e4e7ed}.el-input-number.is-disabled .el-input-number__decrease:hover,.el-input-number.is-disabled .el-input-number__increase:hover{color:#e4e7ed;cursor:not-allowed}.el-input-number--medium{width:200px;line-height:34px}.el-input-number--medium .el-input-number__decrease,.el-input-number--medium .el-input-number__increase{width:36px;font-size:14px}.el-input-number--medium .el-input__inner{padding-left:43px;padding-right:43px}.el-input-number--small{width:130px;line-height:30px}.el-input-number--small .el-input-number__decrease,.el-input-number--small .el-input-number__increase{width:32px;font-size:13px}.el-input-number--small .el-input-number__decrease [class*=el-icon],.el-input-number--small .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.9);transform:scale(.9)}.el-input-number--small .el-input__inner{padding-left:39px;padding-right:39px}.el-input-number--mini{width:130px;line-height:26px}.el-input-number--mini .el-input-number__decrease,.el-input-number--mini .el-input-number__increase{width:28px;font-size:12px}.el-input-number--mini .el-input-number__decrease [class*=el-icon],.el-input-number--mini .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.8);transform:scale(.8)}.el-input-number--mini .el-input__inner{padding-left:35px;padding-right:35px}.el-input-number.is-without-controls .el-input__inner{padding-left:15px;padding-right:15px}.el-input-number.is-controls-right .el-input__inner{padding-left:15px;padding-right:50px}.el-input-number.is-controls-right .el-input-number__decrease,.el-input-number.is-controls-right .el-input-number__increase{height:auto;line-height:19px}.el-input-number.is-controls-right .el-input-number__decrease [class*=el-icon],.el-input-number.is-controls-right .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.8);transform:scale(.8)}.el-input-number.is-controls-right .el-input-number__increase{border-radius:0 4px 0 0;border-bottom:1px solid #dcdfe6}.el-input-number.is-controls-right .el-input-number__decrease{right:1px;bottom:1px;top:auto;left:auto;border-right:none;border-left:1px solid #dcdfe6;border-radius:0 0 4px}.el-input-number.is-controls-right[class*=medium] [class*=decrease],.el-input-number.is-controls-right[class*=medium] [class*=increase]{line-height:17px}.el-input-number.is-controls-right[class*=small] [class*=decrease],.el-input-number.is-controls-right[class*=small] [class*=increase]{line-height:15px}.el-input-number.is-controls-right[class*=mini] [class*=decrease],.el-input-number.is-controls-right[class*=mini] [class*=increase]{line-height:13px}.el-tooltip__popper{position:absolute;border-radius:4px;padding:10px;z-index:2000;font-size:12px;line-height:1.2;min-width:10px;word-wrap:break-word}.el-tooltip__popper .popper__arrow,.el-tooltip__popper .popper__arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.el-tooltip__popper .popper__arrow{border-width:6px}.el-tooltip__popper .popper__arrow:after{content:\" \";border-width:5px}.el-progress-bar__inner:after,.el-row:after,.el-row:before,.el-slider:after,.el-slider:before,.el-slider__button-wrapper:after,.el-upload-cover:after{content:\"\"}.el-tooltip__popper[x-placement^=top]{margin-bottom:12px}.el-tooltip__popper[x-placement^=top] .popper__arrow{bottom:-6px;border-top-color:#303133;border-bottom-width:0}.el-tooltip__popper[x-placement^=top] .popper__arrow:after{bottom:1px;margin-left:-5px;border-top-color:#303133;border-bottom-width:0}.el-tooltip__popper[x-placement^=bottom]{margin-top:12px}.el-tooltip__popper[x-placement^=bottom] .popper__arrow{top:-6px;border-top-width:0;border-bottom-color:#303133}.el-tooltip__popper[x-placement^=bottom] .popper__arrow:after{top:1px;margin-left:-5px;border-top-width:0;border-bottom-color:#303133}.el-tooltip__popper[x-placement^=right]{margin-left:12px}.el-tooltip__popper[x-placement^=right] .popper__arrow{left:-6px;border-right-color:#303133;border-left-width:0}.el-tooltip__popper[x-placement^=right] .popper__arrow:after{bottom:-5px;left:1px;border-right-color:#303133;border-left-width:0}.el-tooltip__popper[x-placement^=left]{margin-right:12px}.el-tooltip__popper[x-placement^=left] .popper__arrow{right:-6px;border-right-width:0;border-left-color:#303133}.el-tooltip__popper[x-placement^=left] .popper__arrow:after{right:1px;bottom:-5px;margin-left:-5px;border-right-width:0;border-left-color:#303133}.el-tooltip__popper.is-dark{background:#303133;color:#fff}.el-tooltip__popper.is-light{background:#fff;border:1px solid #303133}.el-tooltip__popper.is-light[x-placement^=top] .popper__arrow{border-top-color:#303133}.el-tooltip__popper.is-light[x-placement^=top] .popper__arrow:after{border-top-color:#fff}.el-tooltip__popper.is-light[x-placement^=bottom] .popper__arrow{border-bottom-color:#303133}.el-tooltip__popper.is-light[x-placement^=bottom] .popper__arrow:after{border-bottom-color:#fff}.el-tooltip__popper.is-light[x-placement^=left] .popper__arrow{border-left-color:#303133}.el-tooltip__popper.is-light[x-placement^=left] .popper__arrow:after{border-left-color:#fff}.el-tooltip__popper.is-light[x-placement^=right] .popper__arrow{border-right-color:#303133}.el-tooltip__popper.is-light[x-placement^=right] .popper__arrow:after{border-right-color:#fff}.el-slider:after,.el-slider:before{display:table}.el-slider__button-wrapper .el-tooltip,.el-slider__button-wrapper:after{vertical-align:middle;display:inline-block}.el-slider:after{clear:both}.el-slider__runway{width:100%;height:6px;margin:16px 0;background-color:#e4e7ed;border-radius:3px;position:relative;cursor:pointer;vertical-align:middle}.el-slider__runway.show-input{margin-right:160px;width:auto}.el-slider__runway.disabled{cursor:default}.el-slider__runway.disabled .el-slider__bar{background-color:#c0c4cc}.el-slider__runway.disabled .el-slider__button{border-color:#c0c4cc}.el-slider__runway.disabled .el-slider__button-wrapper.dragging,.el-slider__runway.disabled .el-slider__button-wrapper.hover,.el-slider__runway.disabled .el-slider__button-wrapper:hover{cursor:not-allowed}.el-slider__runway.disabled .el-slider__button.dragging,.el-slider__runway.disabled .el-slider__button.hover,.el-slider__runway.disabled .el-slider__button:hover{-webkit-transform:scale(1);transform:scale(1);cursor:not-allowed}.el-slider__input{float:right;margin-top:3px;width:130px}.el-slider__input.el-input-number--mini{margin-top:5px}.el-slider__input.el-input-number--medium{margin-top:0}.el-slider__input.el-input-number--large{margin-top:-2px}.el-slider__bar{height:6px;background-color:#409eff;border-top-left-radius:3px;border-bottom-left-radius:3px;position:absolute}.el-slider__button-wrapper{height:36px;width:36px;position:absolute;z-index:1001;top:-15px;-webkit-transform:translateX(-50%);transform:translateX(-50%);background-color:transparent;text-align:center;-webkit-user-select:none;user-select:none;line-height:normal}.el-slider__button,.el-slider__button-wrapper,.el-step__icon-inner{-moz-user-select:none;-ms-user-select:none}.el-slider__button-wrapper:after{height:100%}.el-slider__button-wrapper.hover,.el-slider__button-wrapper:hover{cursor:-webkit-grab;cursor:grab}.el-slider__button-wrapper.dragging{cursor:-webkit-grabbing;cursor:grabbing}.el-slider__button{width:16px;height:16px;border:2px solid #409eff;background-color:#fff;border-radius:50%;-webkit-transition:.2s;transition:.2s;-moz-user-select:none;-ms-user-select:none;user-select:none}.el-button,.el-checkbox,.el-slider__button,.el-step__icon-inner{-webkit-user-select:none}.el-slider__button.dragging,.el-slider__button.hover,.el-slider__button:hover{-webkit-transform:scale(1.2);transform:scale(1.2)}.el-slider__button.hover,.el-slider__button:hover{cursor:-webkit-grab;cursor:grab}.el-slider__button.dragging{cursor:-webkit-grabbing;cursor:grabbing}.el-slider__stop{position:absolute;height:6px;width:6px;border-radius:100%;background-color:#fff;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.el-slider.is-vertical{position:relative}.el-slider.is-vertical .el-slider__runway{width:6px;height:100%;margin:0 16px}.el-slider.is-vertical .el-slider__bar{width:6px;height:auto;border-radius:0 0 3px 3px}.el-slider.is-vertical .el-slider__button-wrapper{top:auto;left:-15px}.el-slider.is-vertical .el-slider__button-wrapper,.el-slider.is-vertical .el-slider__stop{-webkit-transform:translateY(50%);transform:translateY(50%)}.el-slider.is-vertical.el-slider--with-input{padding-bottom:58px}.el-slider.is-vertical.el-slider--with-input .el-slider__input{overflow:visible;float:none;position:absolute;bottom:22px;width:36px;margin-top:15px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input__inner{text-align:center;padding-left:5px;padding-right:5px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase{top:32px;margin-top:-1px;border:1px solid #dcdfe6;line-height:20px;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1)}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__decrease{width:18px;right:18px;border-bottom-left-radius:4px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase{width:19px;border-bottom-right-radius:4px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase~.el-input .el-input__inner{border-bottom-left-radius:0;border-bottom-right-radius:0}.el-slider.is-vertical.el-slider--with-input .el-slider__input:hover .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input:hover .el-input-number__increase{border-color:#c0c4cc}.el-slider.is-vertical.el-slider--with-input .el-slider__input:active .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input:active .el-input-number__increase{border-color:#409eff}.el-loading-parent--relative{position:relative!important}.el-loading-parent--hidden{overflow:hidden!important}.el-loading-mask{position:absolute;z-index:2000;background-color:hsla(0,0%,100%,.9);margin:0;top:0;right:0;bottom:0;left:0;-webkit-transition:opacity .3s;transition:opacity .3s}.el-loading-mask.is-fullscreen{position:fixed}.el-loading-mask.is-fullscreen .el-loading-spinner{margin-top:-25px}.el-loading-mask.is-fullscreen .el-loading-spinner .circular{height:50px;width:50px}.el-loading-spinner{top:50%;margin-top:-21px;width:100%;text-align:center;position:absolute}.el-col-pull-0,.el-col-pull-1,.el-col-pull-2,.el-col-pull-3,.el-col-pull-4,.el-col-pull-5,.el-col-pull-6,.el-col-pull-7,.el-col-pull-8,.el-col-pull-9,.el-col-pull-10,.el-col-pull-11,.el-col-pull-13,.el-col-pull-14,.el-col-pull-15,.el-col-pull-16,.el-col-pull-17,.el-col-pull-18,.el-col-pull-19,.el-col-pull-20,.el-col-pull-21,.el-col-pull-22,.el-col-pull-23,.el-col-pull-24,.el-col-push-0,.el-col-push-1,.el-col-push-2,.el-col-push-3,.el-col-push-4,.el-col-push-5,.el-col-push-6,.el-col-push-7,.el-col-push-8,.el-col-push-9,.el-col-push-10,.el-col-push-11,.el-col-push-12,.el-col-push-13,.el-col-push-14,.el-col-push-15,.el-col-push-16,.el-col-push-17,.el-col-push-18,.el-col-push-19,.el-col-push-20,.el-col-push-21,.el-col-push-22,.el-col-push-23,.el-col-push-24,.el-row{position:relative}.el-loading-spinner .el-loading-text{color:#409eff;margin:3px 0;font-size:14px}.el-loading-spinner .circular{height:42px;width:42px;-webkit-animation:loading-rotate 2s linear infinite;animation:loading-rotate 2s linear infinite}.el-loading-spinner .path{-webkit-animation:loading-dash 1.5s ease-in-out infinite;animation:loading-dash 1.5s ease-in-out infinite;stroke-dasharray:90,150;stroke-dashoffset:0;stroke-width:2;stroke:#409eff;stroke-linecap:round}.el-loading-spinner i{color:#409eff}@-webkit-keyframes loading-rotate{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes loading-rotate{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@-webkit-keyframes loading-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-40px}to{stroke-dasharray:90,150;stroke-dashoffset:-120px}}@keyframes loading-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-40px}to{stroke-dasharray:90,150;stroke-dashoffset:-120px}}.el-row{-webkit-box-sizing:border-box;box-sizing:border-box}.el-row:after,.el-row:before{display:table}.el-row:after{clear:both}.el-row--flex{display:-webkit-box;display:-ms-flexbox;display:flex}.el-col-0,.el-row--flex:after,.el-row--flex:before{display:none}.el-row--flex.is-justify-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-row--flex.is-justify-end{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.el-row--flex.is-justify-space-between{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.el-row--flex.is-justify-space-around{-ms-flex-pack:distribute;justify-content:space-around}.el-row--flex.is-align-middle{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-row--flex.is-align-bottom{-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end}[class*=el-col-]{float:left;-webkit-box-sizing:border-box;box-sizing:border-box}.el-upload--picture-card,.el-upload-dragger{-webkit-box-sizing:border-box;cursor:pointer}.el-col-0{width:0}.el-col-offset-0{margin-left:0}.el-col-pull-0{right:0}.el-col-push-0{left:0}.el-col-1{width:4.16667%}.el-col-offset-1{margin-left:4.16667%}.el-col-pull-1{right:4.16667%}.el-col-push-1{left:4.16667%}.el-col-2{width:8.33333%}.el-col-offset-2{margin-left:8.33333%}.el-col-pull-2{right:8.33333%}.el-col-push-2{left:8.33333%}.el-col-3{width:12.5%}.el-col-offset-3{margin-left:12.5%}.el-col-pull-3{right:12.5%}.el-col-push-3{left:12.5%}.el-col-4{width:16.66667%}.el-col-offset-4{margin-left:16.66667%}.el-col-pull-4{right:16.66667%}.el-col-push-4{left:16.66667%}.el-col-5{width:20.83333%}.el-col-offset-5{margin-left:20.83333%}.el-col-pull-5{right:20.83333%}.el-col-push-5{left:20.83333%}.el-col-6{width:25%}.el-col-offset-6{margin-left:25%}.el-col-pull-6{right:25%}.el-col-push-6{left:25%}.el-col-7{width:29.16667%}.el-col-offset-7{margin-left:29.16667%}.el-col-pull-7{right:29.16667%}.el-col-push-7{left:29.16667%}.el-col-8{width:33.33333%}.el-col-offset-8{margin-left:33.33333%}.el-col-pull-8{right:33.33333%}.el-col-push-8{left:33.33333%}.el-col-9{width:37.5%}.el-col-offset-9{margin-left:37.5%}.el-col-pull-9{right:37.5%}.el-col-push-9{left:37.5%}.el-col-10{width:41.66667%}.el-col-offset-10{margin-left:41.66667%}.el-col-pull-10{right:41.66667%}.el-col-push-10{left:41.66667%}.el-col-11{width:45.83333%}.el-col-offset-11{margin-left:45.83333%}.el-col-pull-11{right:45.83333%}.el-col-push-11{left:45.83333%}.el-col-12{width:50%}.el-col-offset-12{margin-left:50%}.el-col-pull-12{position:relative;right:50%}.el-col-push-12{left:50%}.el-col-13{width:54.16667%}.el-col-offset-13{margin-left:54.16667%}.el-col-pull-13{right:54.16667%}.el-col-push-13{left:54.16667%}.el-col-14{width:58.33333%}.el-col-offset-14{margin-left:58.33333%}.el-col-pull-14{right:58.33333%}.el-col-push-14{left:58.33333%}.el-col-15{width:62.5%}.el-col-offset-15{margin-left:62.5%}.el-col-pull-15{right:62.5%}.el-col-push-15{left:62.5%}.el-col-16{width:66.66667%}.el-col-offset-16{margin-left:66.66667%}.el-col-pull-16{right:66.66667%}.el-col-push-16{left:66.66667%}.el-col-17{width:70.83333%}.el-col-offset-17{margin-left:70.83333%}.el-col-pull-17{right:70.83333%}.el-col-push-17{left:70.83333%}.el-col-18{width:75%}.el-col-offset-18{margin-left:75%}.el-col-pull-18{right:75%}.el-col-push-18{left:75%}.el-col-19{width:79.16667%}.el-col-offset-19{margin-left:79.16667%}.el-col-pull-19{right:79.16667%}.el-col-push-19{left:79.16667%}.el-col-20{width:83.33333%}.el-col-offset-20{margin-left:83.33333%}.el-col-pull-20{right:83.33333%}.el-col-push-20{left:83.33333%}.el-col-21{width:87.5%}.el-col-offset-21{margin-left:87.5%}.el-col-pull-21{right:87.5%}.el-col-push-21{left:87.5%}.el-col-22{width:91.66667%}.el-col-offset-22{margin-left:91.66667%}.el-col-pull-22{right:91.66667%}.el-col-push-22{left:91.66667%}.el-col-23{width:95.83333%}.el-col-offset-23{margin-left:95.83333%}.el-col-pull-23{right:95.83333%}.el-col-push-23{left:95.83333%}.el-col-24{width:100%}.el-col-offset-24{margin-left:100%}.el-col-pull-24{right:100%}.el-col-push-24{left:100%}@media only screen and (max-width:767px){.el-col-xs-0{display:none;width:0}.el-col-xs-offset-0{margin-left:0}.el-col-xs-pull-0{position:relative;right:0}.el-col-xs-push-0{position:relative;left:0}.el-col-xs-1{width:4.16667%}.el-col-xs-offset-1{margin-left:4.16667%}.el-col-xs-pull-1{position:relative;right:4.16667%}.el-col-xs-push-1{position:relative;left:4.16667%}.el-col-xs-2{width:8.33333%}.el-col-xs-offset-2{margin-left:8.33333%}.el-col-xs-pull-2{position:relative;right:8.33333%}.el-col-xs-push-2{position:relative;left:8.33333%}.el-col-xs-3{width:12.5%}.el-col-xs-offset-3{margin-left:12.5%}.el-col-xs-pull-3{position:relative;right:12.5%}.el-col-xs-push-3{position:relative;left:12.5%}.el-col-xs-4{width:16.66667%}.el-col-xs-offset-4{margin-left:16.66667%}.el-col-xs-pull-4{position:relative;right:16.66667%}.el-col-xs-push-4{position:relative;left:16.66667%}.el-col-xs-5{width:20.83333%}.el-col-xs-offset-5{margin-left:20.83333%}.el-col-xs-pull-5{position:relative;right:20.83333%}.el-col-xs-push-5{position:relative;left:20.83333%}.el-col-xs-6{width:25%}.el-col-xs-offset-6{margin-left:25%}.el-col-xs-pull-6{position:relative;right:25%}.el-col-xs-push-6{position:relative;left:25%}.el-col-xs-7{width:29.16667%}.el-col-xs-offset-7{margin-left:29.16667%}.el-col-xs-pull-7{position:relative;right:29.16667%}.el-col-xs-push-7{position:relative;left:29.16667%}.el-col-xs-8{width:33.33333%}.el-col-xs-offset-8{margin-left:33.33333%}.el-col-xs-pull-8{position:relative;right:33.33333%}.el-col-xs-push-8{position:relative;left:33.33333%}.el-col-xs-9{width:37.5%}.el-col-xs-offset-9{margin-left:37.5%}.el-col-xs-pull-9{position:relative;right:37.5%}.el-col-xs-push-9{position:relative;left:37.5%}.el-col-xs-10{width:41.66667%}.el-col-xs-offset-10{margin-left:41.66667%}.el-col-xs-pull-10{position:relative;right:41.66667%}.el-col-xs-push-10{position:relative;left:41.66667%}.el-col-xs-11{width:45.83333%}.el-col-xs-offset-11{margin-left:45.83333%}.el-col-xs-pull-11{position:relative;right:45.83333%}.el-col-xs-push-11{position:relative;left:45.83333%}.el-col-xs-12{width:50%}.el-col-xs-offset-12{margin-left:50%}.el-col-xs-pull-12{position:relative;right:50%}.el-col-xs-push-12{position:relative;left:50%}.el-col-xs-13{width:54.16667%}.el-col-xs-offset-13{margin-left:54.16667%}.el-col-xs-pull-13{position:relative;right:54.16667%}.el-col-xs-push-13{position:relative;left:54.16667%}.el-col-xs-14{width:58.33333%}.el-col-xs-offset-14{margin-left:58.33333%}.el-col-xs-pull-14{position:relative;right:58.33333%}.el-col-xs-push-14{position:relative;left:58.33333%}.el-col-xs-15{width:62.5%}.el-col-xs-offset-15{margin-left:62.5%}.el-col-xs-pull-15{position:relative;right:62.5%}.el-col-xs-push-15{position:relative;left:62.5%}.el-col-xs-16{width:66.66667%}.el-col-xs-offset-16{margin-left:66.66667%}.el-col-xs-pull-16{position:relative;right:66.66667%}.el-col-xs-push-16{position:relative;left:66.66667%}.el-col-xs-17{width:70.83333%}.el-col-xs-offset-17{margin-left:70.83333%}.el-col-xs-pull-17{position:relative;right:70.83333%}.el-col-xs-push-17{position:relative;left:70.83333%}.el-col-xs-18{width:75%}.el-col-xs-offset-18{margin-left:75%}.el-col-xs-pull-18{position:relative;right:75%}.el-col-xs-push-18{position:relative;left:75%}.el-col-xs-19{width:79.16667%}.el-col-xs-offset-19{margin-left:79.16667%}.el-col-xs-pull-19{position:relative;right:79.16667%}.el-col-xs-push-19{position:relative;left:79.16667%}.el-col-xs-20{width:83.33333%}.el-col-xs-offset-20{margin-left:83.33333%}.el-col-xs-pull-20{position:relative;right:83.33333%}.el-col-xs-push-20{position:relative;left:83.33333%}.el-col-xs-21{width:87.5%}.el-col-xs-offset-21{margin-left:87.5%}.el-col-xs-pull-21{position:relative;right:87.5%}.el-col-xs-push-21{position:relative;left:87.5%}.el-col-xs-22{width:91.66667%}.el-col-xs-offset-22{margin-left:91.66667%}.el-col-xs-pull-22{position:relative;right:91.66667%}.el-col-xs-push-22{position:relative;left:91.66667%}.el-col-xs-23{width:95.83333%}.el-col-xs-offset-23{margin-left:95.83333%}.el-col-xs-pull-23{position:relative;right:95.83333%}.el-col-xs-push-23{position:relative;left:95.83333%}.el-col-xs-24{width:100%}.el-col-xs-offset-24{margin-left:100%}.el-col-xs-pull-24{position:relative;right:100%}.el-col-xs-push-24{position:relative;left:100%}}@media only screen and (min-width:768px){.el-col-sm-0{display:none;width:0}.el-col-sm-offset-0{margin-left:0}.el-col-sm-pull-0{position:relative;right:0}.el-col-sm-push-0{position:relative;left:0}.el-col-sm-1{width:4.16667%}.el-col-sm-offset-1{margin-left:4.16667%}.el-col-sm-pull-1{position:relative;right:4.16667%}.el-col-sm-push-1{position:relative;left:4.16667%}.el-col-sm-2{width:8.33333%}.el-col-sm-offset-2{margin-left:8.33333%}.el-col-sm-pull-2{position:relative;right:8.33333%}.el-col-sm-push-2{position:relative;left:8.33333%}.el-col-sm-3{width:12.5%}.el-col-sm-offset-3{margin-left:12.5%}.el-col-sm-pull-3{position:relative;right:12.5%}.el-col-sm-push-3{position:relative;left:12.5%}.el-col-sm-4{width:16.66667%}.el-col-sm-offset-4{margin-left:16.66667%}.el-col-sm-pull-4{position:relative;right:16.66667%}.el-col-sm-push-4{position:relative;left:16.66667%}.el-col-sm-5{width:20.83333%}.el-col-sm-offset-5{margin-left:20.83333%}.el-col-sm-pull-5{position:relative;right:20.83333%}.el-col-sm-push-5{position:relative;left:20.83333%}.el-col-sm-6{width:25%}.el-col-sm-offset-6{margin-left:25%}.el-col-sm-pull-6{position:relative;right:25%}.el-col-sm-push-6{position:relative;left:25%}.el-col-sm-7{width:29.16667%}.el-col-sm-offset-7{margin-left:29.16667%}.el-col-sm-pull-7{position:relative;right:29.16667%}.el-col-sm-push-7{position:relative;left:29.16667%}.el-col-sm-8{width:33.33333%}.el-col-sm-offset-8{margin-left:33.33333%}.el-col-sm-pull-8{position:relative;right:33.33333%}.el-col-sm-push-8{position:relative;left:33.33333%}.el-col-sm-9{width:37.5%}.el-col-sm-offset-9{margin-left:37.5%}.el-col-sm-pull-9{position:relative;right:37.5%}.el-col-sm-push-9{position:relative;left:37.5%}.el-col-sm-10{width:41.66667%}.el-col-sm-offset-10{margin-left:41.66667%}.el-col-sm-pull-10{position:relative;right:41.66667%}.el-col-sm-push-10{position:relative;left:41.66667%}.el-col-sm-11{width:45.83333%}.el-col-sm-offset-11{margin-left:45.83333%}.el-col-sm-pull-11{position:relative;right:45.83333%}.el-col-sm-push-11{position:relative;left:45.83333%}.el-col-sm-12{width:50%}.el-col-sm-offset-12{margin-left:50%}.el-col-sm-pull-12{position:relative;right:50%}.el-col-sm-push-12{position:relative;left:50%}.el-col-sm-13{width:54.16667%}.el-col-sm-offset-13{margin-left:54.16667%}.el-col-sm-pull-13{position:relative;right:54.16667%}.el-col-sm-push-13{position:relative;left:54.16667%}.el-col-sm-14{width:58.33333%}.el-col-sm-offset-14{margin-left:58.33333%}.el-col-sm-pull-14{position:relative;right:58.33333%}.el-col-sm-push-14{position:relative;left:58.33333%}.el-col-sm-15{width:62.5%}.el-col-sm-offset-15{margin-left:62.5%}.el-col-sm-pull-15{position:relative;right:62.5%}.el-col-sm-push-15{position:relative;left:62.5%}.el-col-sm-16{width:66.66667%}.el-col-sm-offset-16{margin-left:66.66667%}.el-col-sm-pull-16{position:relative;right:66.66667%}.el-col-sm-push-16{position:relative;left:66.66667%}.el-col-sm-17{width:70.83333%}.el-col-sm-offset-17{margin-left:70.83333%}.el-col-sm-pull-17{position:relative;right:70.83333%}.el-col-sm-push-17{position:relative;left:70.83333%}.el-col-sm-18{width:75%}.el-col-sm-offset-18{margin-left:75%}.el-col-sm-pull-18{position:relative;right:75%}.el-col-sm-push-18{position:relative;left:75%}.el-col-sm-19{width:79.16667%}.el-col-sm-offset-19{margin-left:79.16667%}.el-col-sm-pull-19{position:relative;right:79.16667%}.el-col-sm-push-19{position:relative;left:79.16667%}.el-col-sm-20{width:83.33333%}.el-col-sm-offset-20{margin-left:83.33333%}.el-col-sm-pull-20{position:relative;right:83.33333%}.el-col-sm-push-20{position:relative;left:83.33333%}.el-col-sm-21{width:87.5%}.el-col-sm-offset-21{margin-left:87.5%}.el-col-sm-pull-21{position:relative;right:87.5%}.el-col-sm-push-21{position:relative;left:87.5%}.el-col-sm-22{width:91.66667%}.el-col-sm-offset-22{margin-left:91.66667%}.el-col-sm-pull-22{position:relative;right:91.66667%}.el-col-sm-push-22{position:relative;left:91.66667%}.el-col-sm-23{width:95.83333%}.el-col-sm-offset-23{margin-left:95.83333%}.el-col-sm-pull-23{position:relative;right:95.83333%}.el-col-sm-push-23{position:relative;left:95.83333%}.el-col-sm-24{width:100%}.el-col-sm-offset-24{margin-left:100%}.el-col-sm-pull-24{position:relative;right:100%}.el-col-sm-push-24{position:relative;left:100%}}@media only screen and (min-width:992px){.el-col-md-0{display:none;width:0}.el-col-md-offset-0{margin-left:0}.el-col-md-pull-0{position:relative;right:0}.el-col-md-push-0{position:relative;left:0}.el-col-md-1{width:4.16667%}.el-col-md-offset-1{margin-left:4.16667%}.el-col-md-pull-1{position:relative;right:4.16667%}.el-col-md-push-1{position:relative;left:4.16667%}.el-col-md-2{width:8.33333%}.el-col-md-offset-2{margin-left:8.33333%}.el-col-md-pull-2{position:relative;right:8.33333%}.el-col-md-push-2{position:relative;left:8.33333%}.el-col-md-3{width:12.5%}.el-col-md-offset-3{margin-left:12.5%}.el-col-md-pull-3{position:relative;right:12.5%}.el-col-md-push-3{position:relative;left:12.5%}.el-col-md-4{width:16.66667%}.el-col-md-offset-4{margin-left:16.66667%}.el-col-md-pull-4{position:relative;right:16.66667%}.el-col-md-push-4{position:relative;left:16.66667%}.el-col-md-5{width:20.83333%}.el-col-md-offset-5{margin-left:20.83333%}.el-col-md-pull-5{position:relative;right:20.83333%}.el-col-md-push-5{position:relative;left:20.83333%}.el-col-md-6{width:25%}.el-col-md-offset-6{margin-left:25%}.el-col-md-pull-6{position:relative;right:25%}.el-col-md-push-6{position:relative;left:25%}.el-col-md-7{width:29.16667%}.el-col-md-offset-7{margin-left:29.16667%}.el-col-md-pull-7{position:relative;right:29.16667%}.el-col-md-push-7{position:relative;left:29.16667%}.el-col-md-8{width:33.33333%}.el-col-md-offset-8{margin-left:33.33333%}.el-col-md-pull-8{position:relative;right:33.33333%}.el-col-md-push-8{position:relative;left:33.33333%}.el-col-md-9{width:37.5%}.el-col-md-offset-9{margin-left:37.5%}.el-col-md-pull-9{position:relative;right:37.5%}.el-col-md-push-9{position:relative;left:37.5%}.el-col-md-10{width:41.66667%}.el-col-md-offset-10{margin-left:41.66667%}.el-col-md-pull-10{position:relative;right:41.66667%}.el-col-md-push-10{position:relative;left:41.66667%}.el-col-md-11{width:45.83333%}.el-col-md-offset-11{margin-left:45.83333%}.el-col-md-pull-11{position:relative;right:45.83333%}.el-col-md-push-11{position:relative;left:45.83333%}.el-col-md-12{width:50%}.el-col-md-offset-12{margin-left:50%}.el-col-md-pull-12{position:relative;right:50%}.el-col-md-push-12{position:relative;left:50%}.el-col-md-13{width:54.16667%}.el-col-md-offset-13{margin-left:54.16667%}.el-col-md-pull-13{position:relative;right:54.16667%}.el-col-md-push-13{position:relative;left:54.16667%}.el-col-md-14{width:58.33333%}.el-col-md-offset-14{margin-left:58.33333%}.el-col-md-pull-14{position:relative;right:58.33333%}.el-col-md-push-14{position:relative;left:58.33333%}.el-col-md-15{width:62.5%}.el-col-md-offset-15{margin-left:62.5%}.el-col-md-pull-15{position:relative;right:62.5%}.el-col-md-push-15{position:relative;left:62.5%}.el-col-md-16{width:66.66667%}.el-col-md-offset-16{margin-left:66.66667%}.el-col-md-pull-16{position:relative;right:66.66667%}.el-col-md-push-16{position:relative;left:66.66667%}.el-col-md-17{width:70.83333%}.el-col-md-offset-17{margin-left:70.83333%}.el-col-md-pull-17{position:relative;right:70.83333%}.el-col-md-push-17{position:relative;left:70.83333%}.el-col-md-18{width:75%}.el-col-md-offset-18{margin-left:75%}.el-col-md-pull-18{position:relative;right:75%}.el-col-md-push-18{position:relative;left:75%}.el-col-md-19{width:79.16667%}.el-col-md-offset-19{margin-left:79.16667%}.el-col-md-pull-19{position:relative;right:79.16667%}.el-col-md-push-19{position:relative;left:79.16667%}.el-col-md-20{width:83.33333%}.el-col-md-offset-20{margin-left:83.33333%}.el-col-md-pull-20{position:relative;right:83.33333%}.el-col-md-push-20{position:relative;left:83.33333%}.el-col-md-21{width:87.5%}.el-col-md-offset-21{margin-left:87.5%}.el-col-md-pull-21{position:relative;right:87.5%}.el-col-md-push-21{position:relative;left:87.5%}.el-col-md-22{width:91.66667%}.el-col-md-offset-22{margin-left:91.66667%}.el-col-md-pull-22{position:relative;right:91.66667%}.el-col-md-push-22{position:relative;left:91.66667%}.el-col-md-23{width:95.83333%}.el-col-md-offset-23{margin-left:95.83333%}.el-col-md-pull-23{position:relative;right:95.83333%}.el-col-md-push-23{position:relative;left:95.83333%}.el-col-md-24{width:100%}.el-col-md-offset-24{margin-left:100%}.el-col-md-pull-24{position:relative;right:100%}.el-col-md-push-24{position:relative;left:100%}}@media only screen and (min-width:1200px){.el-col-lg-0{display:none;width:0}.el-col-lg-offset-0{margin-left:0}.el-col-lg-pull-0{position:relative;right:0}.el-col-lg-push-0{position:relative;left:0}.el-col-lg-1{width:4.16667%}.el-col-lg-offset-1{margin-left:4.16667%}.el-col-lg-pull-1{position:relative;right:4.16667%}.el-col-lg-push-1{position:relative;left:4.16667%}.el-col-lg-2{width:8.33333%}.el-col-lg-offset-2{margin-left:8.33333%}.el-col-lg-pull-2{position:relative;right:8.33333%}.el-col-lg-push-2{position:relative;left:8.33333%}.el-col-lg-3{width:12.5%}.el-col-lg-offset-3{margin-left:12.5%}.el-col-lg-pull-3{position:relative;right:12.5%}.el-col-lg-push-3{position:relative;left:12.5%}.el-col-lg-4{width:16.66667%}.el-col-lg-offset-4{margin-left:16.66667%}.el-col-lg-pull-4{position:relative;right:16.66667%}.el-col-lg-push-4{position:relative;left:16.66667%}.el-col-lg-5{width:20.83333%}.el-col-lg-offset-5{margin-left:20.83333%}.el-col-lg-pull-5{position:relative;right:20.83333%}.el-col-lg-push-5{position:relative;left:20.83333%}.el-col-lg-6{width:25%}.el-col-lg-offset-6{margin-left:25%}.el-col-lg-pull-6{position:relative;right:25%}.el-col-lg-push-6{position:relative;left:25%}.el-col-lg-7{width:29.16667%}.el-col-lg-offset-7{margin-left:29.16667%}.el-col-lg-pull-7{position:relative;right:29.16667%}.el-col-lg-push-7{position:relative;left:29.16667%}.el-col-lg-8{width:33.33333%}.el-col-lg-offset-8{margin-left:33.33333%}.el-col-lg-pull-8{position:relative;right:33.33333%}.el-col-lg-push-8{position:relative;left:33.33333%}.el-col-lg-9{width:37.5%}.el-col-lg-offset-9{margin-left:37.5%}.el-col-lg-pull-9{position:relative;right:37.5%}.el-col-lg-push-9{position:relative;left:37.5%}.el-col-lg-10{width:41.66667%}.el-col-lg-offset-10{margin-left:41.66667%}.el-col-lg-pull-10{position:relative;right:41.66667%}.el-col-lg-push-10{position:relative;left:41.66667%}.el-col-lg-11{width:45.83333%}.el-col-lg-offset-11{margin-left:45.83333%}.el-col-lg-pull-11{position:relative;right:45.83333%}.el-col-lg-push-11{position:relative;left:45.83333%}.el-col-lg-12{width:50%}.el-col-lg-offset-12{margin-left:50%}.el-col-lg-pull-12{position:relative;right:50%}.el-col-lg-push-12{position:relative;left:50%}.el-col-lg-13{width:54.16667%}.el-col-lg-offset-13{margin-left:54.16667%}.el-col-lg-pull-13{position:relative;right:54.16667%}.el-col-lg-push-13{position:relative;left:54.16667%}.el-col-lg-14{width:58.33333%}.el-col-lg-offset-14{margin-left:58.33333%}.el-col-lg-pull-14{position:relative;right:58.33333%}.el-col-lg-push-14{position:relative;left:58.33333%}.el-col-lg-15{width:62.5%}.el-col-lg-offset-15{margin-left:62.5%}.el-col-lg-pull-15{position:relative;right:62.5%}.el-col-lg-push-15{position:relative;left:62.5%}.el-col-lg-16{width:66.66667%}.el-col-lg-offset-16{margin-left:66.66667%}.el-col-lg-pull-16{position:relative;right:66.66667%}.el-col-lg-push-16{position:relative;left:66.66667%}.el-col-lg-17{width:70.83333%}.el-col-lg-offset-17{margin-left:70.83333%}.el-col-lg-pull-17{position:relative;right:70.83333%}.el-col-lg-push-17{position:relative;left:70.83333%}.el-col-lg-18{width:75%}.el-col-lg-offset-18{margin-left:75%}.el-col-lg-pull-18{position:relative;right:75%}.el-col-lg-push-18{position:relative;left:75%}.el-col-lg-19{width:79.16667%}.el-col-lg-offset-19{margin-left:79.16667%}.el-col-lg-pull-19{position:relative;right:79.16667%}.el-col-lg-push-19{position:relative;left:79.16667%}.el-col-lg-20{width:83.33333%}.el-col-lg-offset-20{margin-left:83.33333%}.el-col-lg-pull-20{position:relative;right:83.33333%}.el-col-lg-push-20{position:relative;left:83.33333%}.el-col-lg-21{width:87.5%}.el-col-lg-offset-21{margin-left:87.5%}.el-col-lg-pull-21{position:relative;right:87.5%}.el-col-lg-push-21{position:relative;left:87.5%}.el-col-lg-22{width:91.66667%}.el-col-lg-offset-22{margin-left:91.66667%}.el-col-lg-pull-22{position:relative;right:91.66667%}.el-col-lg-push-22{position:relative;left:91.66667%}.el-col-lg-23{width:95.83333%}.el-col-lg-offset-23{margin-left:95.83333%}.el-col-lg-pull-23{position:relative;right:95.83333%}.el-col-lg-push-23{position:relative;left:95.83333%}.el-col-lg-24{width:100%}.el-col-lg-offset-24{margin-left:100%}.el-col-lg-pull-24{position:relative;right:100%}.el-col-lg-push-24{position:relative;left:100%}}@media only screen and (min-width:1920px){.el-col-xl-0{display:none;width:0}.el-col-xl-offset-0{margin-left:0}.el-col-xl-pull-0{position:relative;right:0}.el-col-xl-push-0{position:relative;left:0}.el-col-xl-1{width:4.16667%}.el-col-xl-offset-1{margin-left:4.16667%}.el-col-xl-pull-1{position:relative;right:4.16667%}.el-col-xl-push-1{position:relative;left:4.16667%}.el-col-xl-2{width:8.33333%}.el-col-xl-offset-2{margin-left:8.33333%}.el-col-xl-pull-2{position:relative;right:8.33333%}.el-col-xl-push-2{position:relative;left:8.33333%}.el-col-xl-3{width:12.5%}.el-col-xl-offset-3{margin-left:12.5%}.el-col-xl-pull-3{position:relative;right:12.5%}.el-col-xl-push-3{position:relative;left:12.5%}.el-col-xl-4{width:16.66667%}.el-col-xl-offset-4{margin-left:16.66667%}.el-col-xl-pull-4{position:relative;right:16.66667%}.el-col-xl-push-4{position:relative;left:16.66667%}.el-col-xl-5{width:20.83333%}.el-col-xl-offset-5{margin-left:20.83333%}.el-col-xl-pull-5{position:relative;right:20.83333%}.el-col-xl-push-5{position:relative;left:20.83333%}.el-col-xl-6{width:25%}.el-col-xl-offset-6{margin-left:25%}.el-col-xl-pull-6{position:relative;right:25%}.el-col-xl-push-6{position:relative;left:25%}.el-col-xl-7{width:29.16667%}.el-col-xl-offset-7{margin-left:29.16667%}.el-col-xl-pull-7{position:relative;right:29.16667%}.el-col-xl-push-7{position:relative;left:29.16667%}.el-col-xl-8{width:33.33333%}.el-col-xl-offset-8{margin-left:33.33333%}.el-col-xl-pull-8{position:relative;right:33.33333%}.el-col-xl-push-8{position:relative;left:33.33333%}.el-col-xl-9{width:37.5%}.el-col-xl-offset-9{margin-left:37.5%}.el-col-xl-pull-9{position:relative;right:37.5%}.el-col-xl-push-9{position:relative;left:37.5%}.el-col-xl-10{width:41.66667%}.el-col-xl-offset-10{margin-left:41.66667%}.el-col-xl-pull-10{position:relative;right:41.66667%}.el-col-xl-push-10{position:relative;left:41.66667%}.el-col-xl-11{width:45.83333%}.el-col-xl-offset-11{margin-left:45.83333%}.el-col-xl-pull-11{position:relative;right:45.83333%}.el-col-xl-push-11{position:relative;left:45.83333%}.el-col-xl-12{width:50%}.el-col-xl-offset-12{margin-left:50%}.el-col-xl-pull-12{position:relative;right:50%}.el-col-xl-push-12{position:relative;left:50%}.el-col-xl-13{width:54.16667%}.el-col-xl-offset-13{margin-left:54.16667%}.el-col-xl-pull-13{position:relative;right:54.16667%}.el-col-xl-push-13{position:relative;left:54.16667%}.el-col-xl-14{width:58.33333%}.el-col-xl-offset-14{margin-left:58.33333%}.el-col-xl-pull-14{position:relative;right:58.33333%}.el-col-xl-push-14{position:relative;left:58.33333%}.el-col-xl-15{width:62.5%}.el-col-xl-offset-15{margin-left:62.5%}.el-col-xl-pull-15{position:relative;right:62.5%}.el-col-xl-push-15{position:relative;left:62.5%}.el-col-xl-16{width:66.66667%}.el-col-xl-offset-16{margin-left:66.66667%}.el-col-xl-pull-16{position:relative;right:66.66667%}.el-col-xl-push-16{position:relative;left:66.66667%}.el-col-xl-17{width:70.83333%}.el-col-xl-offset-17{margin-left:70.83333%}.el-col-xl-pull-17{position:relative;right:70.83333%}.el-col-xl-push-17{position:relative;left:70.83333%}.el-col-xl-18{width:75%}.el-col-xl-offset-18{margin-left:75%}.el-col-xl-pull-18{position:relative;right:75%}.el-col-xl-push-18{position:relative;left:75%}.el-col-xl-19{width:79.16667%}.el-col-xl-offset-19{margin-left:79.16667%}.el-col-xl-pull-19{position:relative;right:79.16667%}.el-col-xl-push-19{position:relative;left:79.16667%}.el-col-xl-20{width:83.33333%}.el-col-xl-offset-20{margin-left:83.33333%}.el-col-xl-pull-20{position:relative;right:83.33333%}.el-col-xl-push-20{position:relative;left:83.33333%}.el-col-xl-21{width:87.5%}.el-col-xl-offset-21{margin-left:87.5%}.el-col-xl-pull-21{position:relative;right:87.5%}.el-col-xl-push-21{position:relative;left:87.5%}.el-col-xl-22{width:91.66667%}.el-col-xl-offset-22{margin-left:91.66667%}.el-col-xl-pull-22{position:relative;right:91.66667%}.el-col-xl-push-22{position:relative;left:91.66667%}.el-col-xl-23{width:95.83333%}.el-col-xl-offset-23{margin-left:95.83333%}.el-col-xl-pull-23{position:relative;right:95.83333%}.el-col-xl-push-23{position:relative;left:95.83333%}.el-col-xl-24{width:100%}.el-col-xl-offset-24{margin-left:100%}.el-col-xl-pull-24{position:relative;right:100%}.el-col-xl-push-24{position:relative;left:100%}}@-webkit-keyframes progress{0%{background-position:0 0}to{background-position:32px 0}}.el-upload{display:inline-block;text-align:center;cursor:pointer;outline:0}.el-upload__input{display:none}.el-upload__tip{font-size:12px;color:#606266;margin-top:7px}.el-upload iframe{position:absolute;z-index:-1;top:0;left:0;opacity:0;filter:alpha(opacity=0)}.el-upload--picture-card{background-color:#fbfdff;border:1px dashed #c0ccda;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;width:148px;height:148px;line-height:146px;vertical-align:top}.el-upload--picture-card i{font-size:28px;color:#8c939d}.el-upload--picture-card:hover,.el-upload:focus{border-color:#409eff;color:#409eff}.el-upload:focus .el-upload-dragger{border-color:#409eff}.el-upload-dragger{background-color:#fff;border:1px dashed #d9d9d9;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;width:360px;height:180px;text-align:center;position:relative;overflow:hidden}.el-upload-dragger .el-icon-upload{font-size:67px;color:#c0c4cc;margin:40px 0 16px;line-height:50px}.el-upload-dragger+.el-upload__tip{text-align:center}.el-upload-dragger~.el-upload__files{border-top:1px solid #dcdfe6;margin-top:7px;padding-top:5px}.el-upload-dragger .el-upload__text{color:#606266;font-size:14px;text-align:center}.el-upload-dragger .el-upload__text em{color:#409eff;font-style:normal}.el-upload-dragger:hover{border-color:#409eff}.el-upload-dragger.is-dragover{background-color:rgba(32,159,255,.06);border:2px dashed #409eff}.el-upload-list{margin:0;padding:0;list-style:none}.el-upload-list__item{-webkit-transition:all .5s cubic-bezier(.55,0,.1,1);transition:all .5s cubic-bezier(.55,0,.1,1);font-size:14px;color:#606266;line-height:1.8;margin-top:5px;position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:4px;width:100%}.el-upload-list__item .el-progress{position:absolute;top:20px;width:100%}.el-upload-list__item .el-progress__text{position:absolute;right:0;top:-13px}.el-upload-list__item .el-progress-bar{margin-right:0;padding-right:0}.el-upload-list__item:first-child{margin-top:10px}.el-upload-list__item .el-icon-upload-success{color:#67c23a}.el-upload-list__item .el-icon-close{display:none;position:absolute;top:5px;right:5px;cursor:pointer;opacity:.75;color:#606266}.el-upload-list__item .el-icon-close:hover{opacity:1}.el-upload-list__item .el-icon-close-tip{display:none;position:absolute;top:5px;right:5px;font-size:12px;cursor:pointer;opacity:1;color:#409eff}.el-upload-list__item:hover{background-color:#f5f7fa}.el-upload-list__item:hover .el-icon-close{display:inline-block}.el-upload-list__item:hover .el-progress__text{display:none}.el-upload-list__item.is-success .el-upload-list__item-status-label{display:block}.el-upload-list__item.is-success .el-upload-list__item-name:focus,.el-upload-list__item.is-success .el-upload-list__item-name:hover{color:#409eff;cursor:pointer}.el-upload-list__item.is-success:focus:not(:hover) .el-icon-close-tip{display:inline-block}.el-upload-list__item.is-success:active .el-icon-close-tip,.el-upload-list__item.is-success:focus .el-upload-list__item-status-label,.el-upload-list__item.is-success:hover .el-upload-list__item-status-label,.el-upload-list__item.is-success:not(.focusing):focus .el-icon-close-tip{display:none}.el-upload-list.is-disabled .el-upload-list__item:hover .el-upload-list__item-status-label{display:block}.el-upload-list__item-name{color:#606266;display:block;margin-right:40px;overflow:hidden;padding-left:4px;text-overflow:ellipsis;-webkit-transition:color .3s;transition:color .3s;white-space:nowrap}.el-upload-list__item-name [class^=el-icon]{height:100%;margin-right:7px;color:#909399;line-height:inherit}.el-upload-list__item-status-label{position:absolute;right:5px;top:0;line-height:inherit;display:none}.el-upload-list__item-delete{position:absolute;right:10px;top:0;font-size:12px;color:#606266;display:none}.el-upload-list__item-delete:hover{color:#409eff}.el-upload-list--picture-card{margin:0;display:inline;vertical-align:top}.el-upload-list--picture-card .el-upload-list__item{overflow:hidden;background-color:#fff;border:1px solid #c0ccda;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;width:148px;height:148px;margin:0 8px 8px 0;display:inline-block}.el-upload-list--picture-card .el-upload-list__item .el-icon-check,.el-upload-list--picture-card .el-upload-list__item .el-icon-circle-check{color:#fff}.el-upload-list--picture-card .el-upload-list__item .el-icon-close,.el-upload-list--picture-card .el-upload-list__item:hover .el-upload-list__item-status-label{display:none}.el-upload-list--picture-card .el-upload-list__item:hover .el-progress__text{display:block}.el-upload-list--picture-card .el-upload-list__item-name{display:none}.el-upload-list--picture-card .el-upload-list__item-thumbnail{width:100%;height:100%}.el-upload-list--picture-card .el-upload-list__item-status-label{position:absolute;right:-15px;top:-6px;width:40px;height:24px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 0 1pc 1px rgba(0,0,0,.2);box-shadow:0 0 1pc 1px rgba(0,0,0,.2)}.el-upload-list--picture-card .el-upload-list__item-status-label i{font-size:12px;margin-top:11px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.el-upload-list--picture-card .el-upload-list__item-actions{position:absolute;width:100%;height:100%;left:0;top:0;cursor:default;text-align:center;color:#fff;opacity:0;font-size:20px;background-color:rgba(0,0,0,.5);-webkit-transition:opacity .3s;transition:opacity .3s}.el-upload-list--picture-card .el-upload-list__item-actions:after{display:inline-block;content:\"\";height:100%;vertical-align:middle}.el-upload-list--picture-card .el-upload-list__item-actions span{display:none;cursor:pointer}.el-upload-list--picture-card .el-upload-list__item-actions span+span{margin-left:15px}.el-upload-list--picture-card .el-upload-list__item-actions .el-upload-list__item-delete{position:static;font-size:inherit;color:inherit}.el-upload-list--picture-card .el-upload-list__item-actions:hover{opacity:1}.el-upload-list--picture-card .el-upload-list__item-actions:hover span{display:inline-block}.el-upload-list--picture-card .el-progress{top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);bottom:auto;width:126px}.el-upload-list--picture-card .el-progress .el-progress__text{top:50%}.el-upload-list--picture .el-upload-list__item{overflow:hidden;z-index:0;background-color:#fff;border:1px solid #c0ccda;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;margin-top:10px;padding:10px 10px 10px 90px;height:92px}.el-upload-list--picture .el-upload-list__item .el-icon-check,.el-upload-list--picture .el-upload-list__item .el-icon-circle-check{color:#fff}.el-upload-list--picture .el-upload-list__item:hover .el-upload-list__item-status-label{background:0 0;-webkit-box-shadow:none;box-shadow:none;top:-2px;right:-12px}.el-upload-list--picture .el-upload-list__item:hover .el-progress__text{display:block}.el-upload-list--picture .el-upload-list__item.is-success .el-upload-list__item-name{line-height:70px;margin-top:0}.el-upload-list--picture .el-upload-list__item.is-success .el-upload-list__item-name i{display:none}.el-upload-list--picture .el-upload-list__item-thumbnail{vertical-align:middle;display:inline-block;width:70px;height:70px;float:left;position:relative;z-index:1;margin-left:-80px}.el-upload-list--picture .el-upload-list__item-name{display:block;margin-top:20px}.el-upload-list--picture .el-upload-list__item-name i{font-size:70px;line-height:1;position:absolute;left:9px;top:10px}.el-upload-list--picture .el-upload-list__item-status-label{position:absolute;right:-17px;top:-7px;width:46px;height:26px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 1px 1px #ccc;box-shadow:0 1px 1px #ccc}.el-upload-list--picture .el-upload-list__item-status-label i{font-size:12px;margin-top:12px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.el-upload-list--picture .el-progress{position:relative;top:-7px}.el-upload-cover{position:absolute;left:0;top:0;width:100%;height:100%;overflow:hidden;z-index:10;cursor:default}.el-upload-cover:after{display:inline-block;height:100%;vertical-align:middle}.el-upload-cover img{display:block;width:100%;height:100%}.el-upload-cover__label{position:absolute;right:-15px;top:-6px;width:40px;height:24px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 0 1pc 1px rgba(0,0,0,.2);box-shadow:0 0 1pc 1px rgba(0,0,0,.2)}.el-upload-cover__label i{font-size:12px;margin-top:11px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);color:#fff}.el-upload-cover__progress{display:inline-block;vertical-align:middle;position:static;width:243px}.el-upload-cover__progress+.el-upload__inner{opacity:0}.el-upload-cover__content{position:absolute;top:0;left:0;width:100%;height:100%}.el-upload-cover__interact{position:absolute;bottom:0;left:0;width:100%;height:100%;background-color:rgba(0,0,0,.72);text-align:center}.el-upload-cover__interact .btn{display:inline-block;color:#fff;font-size:14px;cursor:pointer;vertical-align:middle;-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);margin-top:60px}.el-upload-cover__interact .btn span{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.el-upload-cover__interact .btn:not(:first-child){margin-left:35px}.el-upload-cover__interact .btn:hover{-webkit-transform:translateY(-13px);transform:translateY(-13px)}.el-upload-cover__interact .btn:hover span{opacity:1}.el-upload-cover__interact .btn i{color:#fff;display:block;font-size:24px;line-height:inherit;margin:0 auto 5px}.el-upload-cover__title{position:absolute;bottom:0;left:0;background-color:#fff;height:36px;width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:400;text-align:left;padding:0 10px;margin:0;line-height:36px;font-size:14px;color:#303133}.el-upload-cover+.el-upload__inner{opacity:0;position:relative;z-index:1}.el-progress{position:relative;line-height:1}.el-progress__text{font-size:14px;color:#606266;display:inline-block;vertical-align:middle;margin-left:10px;line-height:1}.el-progress__text i{vertical-align:middle;display:block}.el-progress--circle{display:inline-block}.el-progress--circle .el-progress__text{position:absolute;top:50%;left:0;width:100%;text-align:center;margin:0;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.el-progress--circle .el-progress__text i{vertical-align:middle;display:inline-block}.el-progress--without-text .el-progress__text{display:none}.el-progress--without-text .el-progress-bar{padding-right:0;margin-right:0;display:block}.el-progress-bar,.el-progress-bar__inner:after,.el-progress-bar__innerText,.el-spinner{display:inline-block;vertical-align:middle}.el-progress--text-inside .el-progress-bar{padding-right:0;margin-right:0}.el-progress.is-success .el-progress-bar__inner{background-color:#67c23a}.el-progress.is-success .el-progress__text{color:#67c23a}.el-progress.is-exception .el-progress-bar__inner{background-color:#f56c6c}.el-progress.is-exception .el-progress__text{color:#f56c6c}.el-progress-bar{padding-right:50px;width:100%;margin-right:-55px;-webkit-box-sizing:border-box;box-sizing:border-box}.el-progress-bar__outer{height:6px;border-radius:100px;background-color:#ebeef5;overflow:hidden;position:relative;vertical-align:middle}.el-progress-bar__inner{position:absolute;left:0;top:0;height:100%;background-color:#409eff;text-align:right;border-radius:100px;line-height:1;white-space:nowrap;-webkit-transition:width .6s ease;transition:width .6s ease}.el-card,.el-message{border-radius:4px;overflow:hidden}.el-progress-bar__inner:after{height:100%}.el-progress-bar__innerText{color:#fff;font-size:12px;margin:0 5px}@keyframes progress{0%{background-position:0 0}to{background-position:32px 0}}.el-time-spinner{width:100%;white-space:nowrap}.el-spinner-inner{-webkit-animation:rotate 2s linear infinite;animation:rotate 2s linear infinite;width:50px;height:50px}.el-spinner-inner .path{stroke:#ececec;stroke-linecap:round;-webkit-animation:dash 1.5s ease-in-out infinite;animation:dash 1.5s ease-in-out infinite}@-webkit-keyframes rotate{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes rotate{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@-webkit-keyframes dash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}to{stroke-dasharray:90,150;stroke-dashoffset:-124}}@keyframes dash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}to{stroke-dasharray:90,150;stroke-dashoffset:-124}}.el-message{min-width:380px;-webkit-box-sizing:border-box;box-sizing:border-box;border-width:1px;border-style:solid;border-color:#ebeef5;position:fixed;left:50%;top:20px;-webkit-transform:translateX(-50%);transform:translateX(-50%);background-color:#edf2fc;-webkit-transition:opacity .3s,-webkit-transform .4s;transition:opacity .3s,-webkit-transform .4s;transition:opacity .3s,transform .4s;transition:opacity .3s,transform .4s,-webkit-transform .4s;padding:15px 15px 15px 20px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-message.is-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-message.is-closable .el-message__content{padding-right:16px}.el-message p{margin:0}.el-message--info .el-message__content{color:#909399}.el-message--success{background-color:#f0f9eb;border-color:#e1f3d8}.el-message--success .el-message__content{color:#67c23a}.el-message--warning{background-color:#fdf6ec;border-color:#faecd8}.el-message--warning .el-message__content{color:#e6a23c}.el-message--error{background-color:#fef0f0;border-color:#fde2e2}.el-message--error .el-message__content{color:#f56c6c}.el-message__icon{margin-right:10px}.el-message__content{padding:0;font-size:14px;line-height:1}.el-message__closeBtn{position:absolute;top:50%;right:15px;-webkit-transform:translateY(-50%);transform:translateY(-50%);cursor:pointer;color:#c0c4cc;font-size:16px}.el-message__closeBtn:hover{color:#909399}.el-message .el-icon-success{color:#67c23a}.el-message .el-icon-error{color:#f56c6c}.el-message .el-icon-info{color:#909399}.el-message .el-icon-warning{color:#e6a23c}.el-message-fade-enter,.el-message-fade-leave-active{opacity:0;-webkit-transform:translate(-50%,-100%);transform:translate(-50%,-100%)}.el-badge{position:relative;vertical-align:middle;display:inline-block}.el-badge__content{background-color:#f56c6c;border-radius:10px;color:#fff;display:inline-block;font-size:12px;height:18px;line-height:18px;padding:0 6px;text-align:center;white-space:nowrap;border:1px solid #fff}.el-badge__content.is-fixed{position:absolute;top:0;right:10px;-webkit-transform:translateY(-50%) translateX(100%);transform:translateY(-50%) translateX(100%)}.el-rate__icon,.el-rate__item{position:relative;display:inline-block}.el-badge__content.is-fixed.is-dot{right:5px}.el-badge__content.is-dot{height:8px;width:8px;padding:0;right:0;border-radius:50%}.el-badge__content--primary{background-color:#409eff}.el-badge__content--success{background-color:#67c23a}.el-badge__content--warning{background-color:#e6a23c}.el-badge__content--info{background-color:#909399}.el-badge__content--danger{background-color:#f56c6c}.el-card{border:1px solid #ebeef5;background-color:#fff;color:#303133;-webkit-transition:.3s;transition:.3s}.el-card.is-always-shadow,.el-card.is-hover-shadow:focus,.el-card.is-hover-shadow:hover{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-card__header{padding:18px 20px;border-bottom:1px solid #ebeef5;-webkit-box-sizing:border-box;box-sizing:border-box}.el-card__body{padding:20px}.el-rate{height:20px;line-height:1}.el-rate__item{font-size:0;vertical-align:middle}.el-rate__icon{font-size:18px;margin-right:6px;color:#c0c4cc;-webkit-transition:.3s;transition:.3s}.el-rate__decimal,.el-rate__icon .path2{position:absolute;top:0;left:0}.el-rate__icon.hover{-webkit-transform:scale(1.15);transform:scale(1.15)}.el-rate__decimal{display:inline-block;overflow:hidden}.el-step.is-vertical,.el-steps{display:-webkit-box;display:-ms-flexbox}.el-rate__text{font-size:14px;vertical-align:middle}.el-steps{display:-webkit-box;display:-ms-flexbox;display:flex}.el-steps--simple{padding:13px 8%;border-radius:4px;background:#f5f7fa}.el-steps--horizontal{white-space:nowrap}.el-steps--vertical{height:100%;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-flow:column;flex-flow:column}.el-step{position:relative;-ms-flex-negative:1;flex-shrink:1}.el-step:last-of-type .el-step__line{display:none}.el-step:last-of-type.is-flex{-ms-flex-preferred-size:auto!important;flex-basis:auto!important;-ms-flex-negative:0;flex-shrink:0;-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0}.el-step:last-of-type .el-step__description,.el-step:last-of-type .el-step__main{padding-right:0}.el-step__head{position:relative;width:100%}.el-step__head.is-process{color:#303133;border-color:#303133}.el-step__head.is-wait{color:#c0c4cc;border-color:#c0c4cc}.el-step__head.is-success{color:#67c23a;border-color:#67c23a}.el-step__head.is-error{color:#f56c6c;border-color:#f56c6c}.el-step__head.is-finish{color:#409eff;border-color:#409eff}.el-step__icon{position:relative;z-index:1;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:24px;height:24px;font-size:14px;-webkit-box-sizing:border-box;box-sizing:border-box;background:#fff;-webkit-transition:.15s ease-out;transition:.15s ease-out}.el-step__icon.is-text{border-radius:50%;border:2px solid;border-color:inherit}.el-step__icon.is-icon{width:40px}.el-step__icon-inner{display:inline-block;-webkit-user-select:none;user-select:none;text-align:center;font-weight:700;line-height:1;color:inherit}.el-button,.el-checkbox,.el-step__icon-inner{-moz-user-select:none;-ms-user-select:none}.el-step__icon-inner[class*=el-icon]:not(.is-status){font-size:25px;font-weight:400}.el-step__icon-inner.is-status{-webkit-transform:translateY(1px);transform:translateY(1px)}.el-step__line{position:absolute;border-color:inherit;background-color:#c0c4cc}.el-step__line-inner{display:block;border-width:1px;border-style:solid;border-color:inherit;-webkit-transition:.15s ease-out;transition:.15s ease-out;-webkit-box-sizing:border-box;box-sizing:border-box;width:0;height:0}.el-step__main{white-space:normal;text-align:left}.el-step__title{font-size:16px;line-height:38px}.el-step__title.is-process{font-weight:700;color:#303133}.el-step__title.is-wait{color:#c0c4cc}.el-step__title.is-success{color:#67c23a}.el-step__title.is-error{color:#f56c6c}.el-step__title.is-finish{color:#409eff}.el-step__description{padding-right:10%;margin-top:-5px;font-size:12px;line-height:20px;font-weight:400}.el-step__description.is-process{color:#303133}.el-step__description.is-wait{color:#c0c4cc}.el-step__description.is-success{color:#67c23a}.el-step__description.is-error{color:#f56c6c}.el-step__description.is-finish{color:#409eff}.el-step.is-horizontal{display:inline-block}.el-step.is-horizontal .el-step__line{height:2px;top:11px;left:0;right:0}.el-step.is-vertical{display:-webkit-box;display:-ms-flexbox;display:flex}.el-step.is-vertical .el-step__head{-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0;width:24px}.el-step.is-vertical .el-step__main{padding-left:10px;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.el-step.is-vertical .el-step__title{line-height:24px;padding-bottom:8px}.el-step.is-vertical .el-step__line{width:2px;top:0;bottom:0;left:11px}.el-step.is-vertical .el-step__icon.is-icon{width:24px}.el-step.is-center .el-step__head,.el-step.is-center .el-step__main{text-align:center}.el-step.is-center .el-step__description{padding-left:20%;padding-right:20%}.el-step.is-center .el-step__line{left:50%;right:-50%}.el-step.is-simple{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-step.is-simple .el-step__head{width:auto;font-size:0;padding-right:10px}.el-step.is-simple .el-step__icon{background:0 0;width:16px;height:16px;font-size:12px}.el-step.is-simple .el-step__icon-inner[class*=el-icon]:not(.is-status){font-size:18px}.el-step.is-simple .el-step__icon-inner.is-status{-webkit-transform:scale(.8) translateY(1px);transform:scale(.8) translateY(1px)}.el-step.is-simple .el-step__main{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.el-step.is-simple .el-step__title{font-size:16px;line-height:20px}.el-step.is-simple:not(:last-of-type) .el-step__title{max-width:50%;word-break:break-all}.el-step.is-simple .el-step__arrow{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-step.is-simple .el-step__arrow:after,.el-step.is-simple .el-step__arrow:before{content:\"\";display:inline-block;position:absolute;height:15px;width:1px;background:#c0c4cc}.el-step.is-simple .el-step__arrow:before{-webkit-transform:rotate(-45deg) translateY(-4px);transform:rotate(-45deg) translateY(-4px);-webkit-transform-origin:0 0;transform-origin:0 0}.el-step.is-simple .el-step__arrow:after{-webkit-transform:rotate(45deg) translateY(4px);transform:rotate(45deg) translateY(4px);-webkit-transform-origin:100% 100%;transform-origin:100% 100%}.el-step.is-simple:last-of-type .el-step__arrow{display:none}.el-carousel{overflow-x:hidden;position:relative}.el-carousel__container{position:relative;height:300px}.el-carousel__arrow{border:none;outline:0;padding:0;margin:0;height:36px;width:36px;cursor:pointer;-webkit-transition:.3s;transition:.3s;border-radius:50%;background-color:rgba(31,45,61,.11);color:#fff;position:absolute;top:50%;z-index:10;-webkit-transform:translateY(-50%);transform:translateY(-50%);text-align:center;font-size:12px}.el-carousel__arrow--left{left:16px}.el-carousel__arrow--right{right:16px}.el-carousel__arrow:hover{background-color:rgba(31,45,61,.23)}.el-carousel__arrow i{cursor:pointer}.el-carousel__indicators{position:absolute;list-style:none;bottom:0;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%);margin:0;padding:0;z-index:2}.el-carousel__indicators--outside{bottom:26px;text-align:center;position:static;-webkit-transform:none;transform:none}.el-carousel__indicators--outside .el-carousel__indicator:hover button{opacity:.64}.el-carousel__indicators--outside button{background-color:#c0c4cc;opacity:.24}.el-carousel__indicators--labels{left:0;right:0;-webkit-transform:none;transform:none;text-align:center}.el-carousel__indicators--labels .el-carousel__button{height:auto;width:auto;padding:2px 18px;font-size:12px}.el-carousel__indicators--labels .el-carousel__indicator{padding:6px 4px}.el-carousel__indicator{display:inline-block;background-color:transparent;padding:12px 4px;cursor:pointer}.el-carousel__indicator:hover button{opacity:.72}.el-carousel__indicator.is-active button{opacity:1}.el-carousel__button{display:block;opacity:.48;width:30px;height:2px;background-color:#fff;border:none;outline:0;padding:0;margin:0;cursor:pointer;-webkit-transition:.3s;transition:.3s}.carousel-arrow-left-enter,.carousel-arrow-left-leave-active{-webkit-transform:translateY(-50%) translateX(-10px);transform:translateY(-50%) translateX(-10px);opacity:0}.carousel-arrow-right-enter,.carousel-arrow-right-leave-active{-webkit-transform:translateY(-50%) translateX(10px);transform:translateY(-50%) translateX(10px);opacity:0}.el-scrollbar{overflow:hidden;position:relative}.el-scrollbar:active>.el-scrollbar__bar,.el-scrollbar:focus>.el-scrollbar__bar,.el-scrollbar:hover>.el-scrollbar__bar{opacity:1;-webkit-transition:opacity .34s ease-out;transition:opacity .34s ease-out}.el-scrollbar__wrap{overflow:scroll;height:100%}.el-scrollbar__wrap--hidden-default::-webkit-scrollbar{width:0;height:0}.el-scrollbar__thumb{position:relative;display:block;width:0;height:0;cursor:pointer;border-radius:inherit;background-color:rgba(144,147,153,.3);-webkit-transition:background-color .3s;transition:background-color .3s}.el-scrollbar__thumb:hover{background-color:rgba(144,147,153,.5)}.el-scrollbar__bar{position:absolute;right:2px;bottom:2px;z-index:1;border-radius:4px;opacity:0;-webkit-transition:opacity .12s ease-out;transition:opacity .12s ease-out}.el-scrollbar__bar.is-vertical{width:6px;top:2px}.el-scrollbar__bar.is-vertical>div{width:100%}.el-scrollbar__bar.is-horizontal{height:6px;left:2px}.el-carousel__item,.el-carousel__mask{height:100%;top:0;left:0;position:absolute}.el-scrollbar__bar.is-horizontal>div{height:100%}.el-carousel__item{width:100%;display:inline-block;overflow:hidden;z-index:0}.el-carousel__item.is-active{z-index:2}.el-carousel__item--card,.el-carousel__item.is-animating{-webkit-transition:-webkit-transform .4s ease-in-out;transition:-webkit-transform .4s ease-in-out;transition:transform .4s ease-in-out;transition:transform .4s ease-in-out,-webkit-transform .4s ease-in-out}.el-carousel__item--card{width:50%}.el-carousel__item--card.is-in-stage{cursor:pointer;z-index:1}.el-carousel__item--card.is-in-stage.is-hover .el-carousel__mask,.el-carousel__item--card.is-in-stage:hover .el-carousel__mask{opacity:.12}.el-carousel__item--card.is-active{z-index:2}.el-carousel__mask{width:100%;background-color:#fff;opacity:.24;-webkit-transition:.2s;transition:.2s}.el-fade-in-enter,.el-fade-in-leave-active,.el-fade-in-linear-enter,.el-fade-in-linear-leave,.el-fade-in-linear-leave-active,.fade-in-linear-enter,.fade-in-linear-leave,.fade-in-linear-leave-active{opacity:0}.el-fade-in-linear-enter-active,.el-fade-in-linear-leave-active,.fade-in-linear-enter-active,.fade-in-linear-leave-active{-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.el-fade-in-enter-active,.el-fade-in-leave-active,.el-zoom-in-center-enter-active,.el-zoom-in-center-leave-active{-webkit-transition:all .3s cubic-bezier(.55,0,.1,1);transition:all .3s cubic-bezier(.55,0,.1,1)}.el-zoom-in-center-enter,.el-zoom-in-center-leave-active{opacity:0;-webkit-transform:scaleX(0);transform:scaleX(0)}.el-zoom-in-top-enter-active,.el-zoom-in-top-leave-active{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:center top;transform-origin:center top}.el-zoom-in-top-enter,.el-zoom-in-top-leave-active{opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}.el-zoom-in-bottom-enter-active,.el-zoom-in-bottom-leave-active{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:center bottom;transform-origin:center bottom}.el-zoom-in-bottom-enter,.el-zoom-in-bottom-leave-active{opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}.el-zoom-in-left-enter-active,.el-zoom-in-left-leave-active{opacity:1;-webkit-transform:scale(1);transform:scale(1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:top left;transform-origin:top left}.el-zoom-in-left-enter,.el-zoom-in-left-leave-active{opacity:0;-webkit-transform:scale(.45);transform:scale(.45)}.collapse-transition{-webkit-transition:height .3s ease-in-out,padding-top .3s ease-in-out,padding-bottom .3s ease-in-out;transition:height .3s ease-in-out,padding-top .3s ease-in-out,padding-bottom .3s ease-in-out}.horizontal-collapse-transition{-webkit-transition:width .3s ease-in-out,padding-left .3s ease-in-out,padding-right .3s ease-in-out;transition:width .3s ease-in-out,padding-left .3s ease-in-out,padding-right .3s ease-in-out}.el-list-enter-active,.el-list-leave-active{-webkit-transition:all 1s;transition:all 1s}.el-list-enter,.el-list-leave-active{opacity:0;-webkit-transform:translateY(-30px);transform:translateY(-30px)}.el-opacity-transition{-webkit-transition:opacity .3s cubic-bezier(.55,0,.1,1);transition:opacity .3s cubic-bezier(.55,0,.1,1)}.el-collapse{border-top:1px solid #ebeef5;border-bottom:1px solid #ebeef5}.el-collapse-item__header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:48px;line-height:48px;background-color:#fff;color:#303133;cursor:pointer;border-bottom:1px solid #ebeef5;font-size:13px;font-weight:500;-webkit-transition:border-bottom-color .3s;transition:border-bottom-color .3s;outline:0}.el-collapse-item__arrow{margin:0 8px 0 auto;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-weight:300}.el-collapse-item__arrow.is-active{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-collapse-item__header.focusing:focus:not(:hover){color:#409eff}.el-collapse-item__header.is-active{border-bottom-color:transparent}.el-collapse-item__wrap{will-change:height;background-color:#fff;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;border-bottom:1px solid #ebeef5}.el-collapse-item__content{padding-bottom:25px;font-size:13px;color:#303133;line-height:1.769230769230769}.el-collapse-item:last-child{margin-bottom:-1px}.el-popper .popper__arrow,.el-popper .popper__arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.el-popper .popper__arrow{border-width:6px;-webkit-filter:drop-shadow(0 2px 12px rgba(0,0,0,.03));filter:drop-shadow(0 2px 12px rgba(0,0,0,.03))}.el-popper .popper__arrow:after{content:\" \";border-width:6px}.el-popper[x-placement^=top]{margin-bottom:12px}.el-popper[x-placement^=top] .popper__arrow{bottom:-6px;left:50%;margin-right:3px;border-top-color:#ebeef5;border-bottom-width:0}.el-popper[x-placement^=top] .popper__arrow:after{bottom:1px;margin-left:-6px;border-top-color:#fff;border-bottom-width:0}.el-popper[x-placement^=bottom]{margin-top:12px}.el-popper[x-placement^=bottom] .popper__arrow{top:-6px;left:50%;margin-right:3px;border-top-width:0;border-bottom-color:#ebeef5}.el-popper[x-placement^=bottom] .popper__arrow:after{top:1px;margin-left:-6px;border-top-width:0;border-bottom-color:#fff}.el-popper[x-placement^=right]{margin-left:12px}.el-popper[x-placement^=right] .popper__arrow{top:50%;left:-6px;margin-bottom:3px;border-right-color:#ebeef5;border-left-width:0}.el-popper[x-placement^=right] .popper__arrow:after{bottom:-6px;left:1px;border-right-color:#fff;border-left-width:0}.el-popper[x-placement^=left]{margin-right:12px}.el-popper[x-placement^=left] .popper__arrow{top:50%;right:-6px;margin-bottom:3px;border-right-width:0;border-left-color:#ebeef5}.el-popper[x-placement^=left] .popper__arrow:after{right:1px;bottom:-6px;margin-left:-6px;border-right-width:0;border-left-color:#fff}.el-cascader{display:inline-block;position:relative;font-size:14px;line-height:40px}.el-cascader .el-input,.el-cascader .el-input__inner{cursor:pointer}.el-cascader .el-input.is-focus .el-input__inner{border-color:#409eff}.el-cascader .el-input__icon{-webkit-transition:none;transition:none}.el-cascader .el-icon-arrow-down{-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-size:14px}.el-cascader .el-icon-arrow-down.is-reverse{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.el-cascader .el-icon-circle-close{z-index:2;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1)}.el-cascader .el-icon-circle-close:hover{color:#909399}.el-cascader__clearIcon{z-index:2;position:relative}.el-cascader__label{position:absolute;left:0;top:0;height:100%;padding:0 25px 0 15px;color:#606266;width:100%;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;cursor:pointer;text-align:left;font-size:inherit}.el-cascader__label span{color:#000}.el-cascader--medium{font-size:14px;line-height:36px}.el-cascader--small{font-size:13px;line-height:32px}.el-cascader--mini{font-size:12px;line-height:28px}.el-cascader.is-disabled .el-cascader__label{z-index:2;color:#c0c4cc}.el-cascader-menus{white-space:nowrap;background:#fff;position:absolute;margin:5px 0;z-index:2;border:1px solid #e4e7ed;border-radius:2px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-cascader-menu,.el-cascader-menu__item.is-disabled:hover{background-color:#fff}.el-cascader-menu{display:inline-block;vertical-align:top;height:204px;overflow:auto;border-right:1px solid #e4e7ed;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:6px 0;min-width:160px}.el-cascader-menu:last-child{border-right:0}.el-cascader-menu__item{font-size:14px;padding:8px 20px;position:relative;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#606266;height:34px;line-height:1.5;-webkit-box-sizing:border-box;box-sizing:border-box;cursor:pointer;outline:0}.el-cascader-menu__item span{padding-right:10px}.el-cascader-menu__item--extensible:after{font-family:element-icons;content:\"\\E604\";font-size:14px;color:#bfcbd9;position:absolute;right:15px}.el-cascader-menu__item.is-disabled{color:#c0c4cc;background-color:#fff;cursor:not-allowed}.el-cascader-menu__item.is-active{color:#409eff}.el-cascader-menu__item:focus:not(:active),.el-cascader-menu__item:hover{background-color:#f5f7fa}.el-cascader-menu__item.selected{color:#fff;background-color:#f5f7fa}.el-cascader-menu__item__keyword{font-weight:700}.el-cascader-menu--flexible{height:auto;max-height:180px;overflow:auto}.el-cascader-menu--flexible .el-cascader-menu__item{overflow:visible}.el-color-predefine{font-size:12px;margin-top:8px;width:280px}.el-color-predefine,.el-color-predefine__colors{display:-webkit-box;display:-ms-flexbox;display:flex}.el-color-predefine__colors{-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-wrap:wrap;flex-wrap:wrap}.el-color-predefine__color-selector{margin:0 0 8px 8px;width:20px;height:20px;border-radius:4px;cursor:pointer}.el-color-predefine__color-selector:nth-child(10n+1){margin-left:0}.el-color-predefine__color-selector.selected{-webkit-box-shadow:0 0 3px 2px #409eff;box-shadow:0 0 3px 2px #409eff}.el-color-predefine__color-selector>div{display:-webkit-box;display:-ms-flexbox;display:flex;height:100%;border-radius:3px}.el-color-predefine__color-selector.is-alpha{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-hue-slider{position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;width:280px;height:12px;background-color:red;padding:0 2px}.el-color-hue-slider__bar{position:relative;background:-webkit-gradient(linear,left top,right top,color-stop(0,red),color-stop(17%,#ff0),color-stop(33%,#0f0),color-stop(50%,#0ff),color-stop(67%,#00f),color-stop(83%,#f0f),to(red));background:linear-gradient(90deg,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red);height:100%}.el-color-hue-slider__thumb{position:absolute;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box;left:0;top:0;width:4px;height:100%;border-radius:1px;background:#fff;border:1px solid #f0f0f0;-webkit-box-shadow:0 0 2px rgba(0,0,0,.6);box-shadow:0 0 2px rgba(0,0,0,.6);z-index:1}.el-color-hue-slider.is-vertical{width:12px;height:180px;padding:2px 0}.el-color-hue-slider.is-vertical .el-color-hue-slider__bar{background:-webkit-gradient(linear,left top,left bottom,color-stop(0,red),color-stop(17%,#ff0),color-stop(33%,#0f0),color-stop(50%,#0ff),color-stop(67%,#00f),color-stop(83%,#f0f),to(red));background:linear-gradient(180deg,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red)}.el-color-hue-slider.is-vertical .el-color-hue-slider__thumb{left:0;top:0;width:100%;height:4px}.el-color-svpanel{position:relative;width:280px;height:180px}.el-color-svpanel__black,.el-color-svpanel__white{position:absolute;top:0;left:0;right:0;bottom:0}.el-color-svpanel__white{background:-webkit-gradient(linear,left top,right top,from(#fff),to(hsla(0,0%,100%,0)));background:linear-gradient(90deg,#fff,hsla(0,0%,100%,0))}.el-color-svpanel__black{background:-webkit-gradient(linear,left bottom,left top,from(#000),to(transparent));background:linear-gradient(0deg,#000,transparent)}.el-color-svpanel__cursor{position:absolute}.el-color-svpanel__cursor>div{cursor:head;width:4px;height:4px;-webkit-box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgba(0,0,0,.3),0 0 1px 2px rgba(0,0,0,.4);box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgba(0,0,0,.3),0 0 1px 2px rgba(0,0,0,.4);border-radius:50%;-webkit-transform:translate(-2px,-2px);transform:translate(-2px,-2px)}.el-color-alpha-slider{position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;width:280px;height:12px;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-alpha-slider__bar{position:relative;background:-webkit-gradient(linear,left top,right top,color-stop(0,hsla(0,0%,100%,0)),to(#fff));background:linear-gradient(90deg,hsla(0,0%,100%,0) 0,#fff);height:100%}.el-color-alpha-slider__thumb{position:absolute;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box;left:0;top:0;width:4px;height:100%;border-radius:1px;background:#fff;border:1px solid #f0f0f0;-webkit-box-shadow:0 0 2px rgba(0,0,0,.6);box-shadow:0 0 2px rgba(0,0,0,.6);z-index:1}.el-color-alpha-slider.is-vertical{width:20px;height:180px}.el-color-alpha-slider.is-vertical .el-color-alpha-slider__bar{background:-webkit-gradient(linear,left top,left bottom,color-stop(0,hsla(0,0%,100%,0)),to(#fff));background:linear-gradient(180deg,hsla(0,0%,100%,0) 0,#fff)}.el-color-alpha-slider.is-vertical .el-color-alpha-slider__thumb{left:0;top:0;width:100%;height:4px}.el-color-dropdown{width:300px}.el-color-dropdown__main-wrapper{margin-bottom:6px}.el-color-dropdown__main-wrapper:after{content:\"\";display:table;clear:both}.el-color-dropdown__btns{margin-top:6px;text-align:right}.el-color-dropdown__value{float:left;line-height:26px;font-size:12px;color:#000;width:160px}.el-color-dropdown__btn{border:1px solid #dcdcdc;color:#333;line-height:24px;border-radius:2px;padding:0 20px;cursor:pointer;background-color:transparent;outline:0;font-size:12px}.el-color-dropdown__btn[disabled]{color:#ccc;cursor:not-allowed}.el-color-dropdown__btn:hover{color:#409eff;border-color:#409eff}.el-color-dropdown__link-btn{cursor:pointer;color:#409eff;text-decoration:none;padding:15px;font-size:12px}.el-color-dropdown__link-btn:hover{color:tint(#409eff,20%)}.el-color-picker{display:inline-block;position:relative;line-height:normal;height:40px}.el-color-picker.is-disabled .el-color-picker__trigger{cursor:not-allowed}.el-color-picker--medium{height:36px}.el-color-picker--medium .el-color-picker__trigger{height:36px;width:36px}.el-color-picker--medium .el-color-picker__mask{height:34px;width:34px}.el-color-picker--small{height:32px}.el-color-picker--small .el-color-picker__trigger{height:32px;width:32px}.el-color-picker--small .el-color-picker__mask{height:30px;width:30px}.el-color-picker--small .el-color-picker__empty,.el-color-picker--small .el-color-picker__icon{-webkit-transform:translate3d(-50%,-50%,0) scale(.8);transform:translate3d(-50%,-50%,0) scale(.8)}.el-color-picker--mini{height:28px}.el-color-picker--mini .el-color-picker__trigger{height:28px;width:28px}.el-color-picker--mini .el-color-picker__mask{height:26px;width:26px}.el-color-picker--mini .el-color-picker__empty,.el-color-picker--mini .el-color-picker__icon{-webkit-transform:translate3d(-50%,-50%,0) scale(.8);transform:translate3d(-50%,-50%,0) scale(.8)}.el-color-picker__mask{height:38px;width:38px;border-radius:4px;position:absolute;top:1px;left:1px;z-index:1;cursor:not-allowed;background-color:hsla(0,0%,100%,.7)}.el-color-picker__trigger{display:inline-block;height:40px;width:40px;padding:4px;border:1px solid #e6e6e6;border-radius:4px;font-size:0;cursor:pointer}.el-color-picker__color,.el-color-picker__trigger{-webkit-box-sizing:border-box;box-sizing:border-box;position:relative}.el-color-picker__color{display:block;border:1px solid #999;border-radius:2px;width:100%;height:100%;text-align:center}.el-color-picker__color.is-alpha{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-picker__color-inner{position:absolute;left:0;top:0;right:0;bottom:0}.el-color-picker__empty,.el-color-picker__icon{top:50%;left:50%;font-size:12px;position:absolute}.el-color-picker__empty{color:#999}.el-color-picker__empty,.el-color-picker__icon{-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0)}.el-color-picker__icon{display:inline-block;width:100%;color:#fff;text-align:center}.el-color-picker__panel{position:absolute;z-index:10;padding:6px;-webkit-box-sizing:content-box;box-sizing:content-box;background-color:#fff;border:1px solid #ebeef5;border-radius:4px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-textarea{display:inline-block;width:100%;vertical-align:bottom;font-size:14px}.el-textarea__inner{display:block;resize:vertical;padding:5px 15px;line-height:1.5;-webkit-box-sizing:border-box;box-sizing:border-box;width:100%;font-size:inherit;color:#606266;background-color:#fff;background-image:none;border:1px solid #dcdfe6;border-radius:4px;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1)}.el-textarea__inner::-webkit-input-placeholder{color:#c0c4cc}.el-textarea__inner:-ms-input-placeholder{color:#c0c4cc}.el-textarea__inner::-ms-input-placeholder{color:#c0c4cc}.el-textarea__inner::-moz-placeholder{color:#c0c4cc}.el-textarea__inner::placeholder{color:#c0c4cc}.el-textarea__inner:hover{border-color:#c0c4cc}.el-textarea__inner:focus{outline:0;border-color:#409eff}.el-textarea.is-disabled .el-textarea__inner{background-color:#f5f7fa;border-color:#e4e7ed;color:#c0c4cc;cursor:not-allowed}.el-textarea.is-disabled .el-textarea__inner::-webkit-input-placeholder{color:#c0c4cc}.el-textarea.is-disabled .el-textarea__inner:-ms-input-placeholder{color:#c0c4cc}.el-textarea.is-disabled .el-textarea__inner::-ms-input-placeholder{color:#c0c4cc}.el-textarea.is-disabled .el-textarea__inner::-moz-placeholder{color:#c0c4cc}.el-textarea.is-disabled .el-textarea__inner::placeholder{color:#c0c4cc}.el-input{position:relative;font-size:14px;display:inline-block;width:100%}.el-input::-webkit-scrollbar{z-index:11;width:6px}.el-button-group>.el-button.is-active,.el-button-group>.el-button.is-disabled,.el-button-group>.el-button:active,.el-button-group>.el-button:focus,.el-button-group>.el-button:hover{z-index:1}.el-input::-webkit-scrollbar:horizontal{height:6px}.el-input::-webkit-scrollbar-thumb{border-radius:5px;width:6px;background:#b4bccc}.el-input::-webkit-scrollbar-corner,.el-input::-webkit-scrollbar-track{background:#fff}.el-input::-webkit-scrollbar-track-piece{background:#fff;width:6px}.el-input .el-input__clear{color:#c0c4cc;font-size:14px;line-height:16px;cursor:pointer;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1)}.el-input .el-input__clear:hover{color:#909399}.el-input__inner{-webkit-appearance:none;background-color:#fff;background-image:none;border-radius:4px;border:1px solid #dcdfe6;-webkit-box-sizing:border-box;box-sizing:border-box;color:#606266;display:inline-block;font-size:inherit;height:40px;line-height:40px;outline:0;padding:0 15px;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1);width:100%}.el-input__prefix,.el-input__suffix{position:absolute;top:0;-webkit-transition:all .3s;height:100%;color:#c0c4cc;text-align:center}.el-input__inner::-webkit-input-placeholder{color:#c0c4cc}.el-input__inner:-ms-input-placeholder{color:#c0c4cc}.el-input__inner::-ms-input-placeholder{color:#c0c4cc}.el-input__inner::-moz-placeholder{color:#c0c4cc}.el-input__inner::placeholder{color:#c0c4cc}.el-input__inner:hover{border-color:#c0c4cc}.el-input.is-active .el-input__inner,.el-input__inner:focus{border-color:#409eff;outline:0}.el-input__suffix{right:5px;-webkit-transition:all .3s;transition:all .3s}.el-input__suffix-inner{pointer-events:all}.el-input__prefix{left:5px}.el-input__icon,.el-input__prefix{-webkit-transition:all .3s;transition:all .3s}.el-input__icon{height:100%;width:25px;text-align:center;line-height:40px}.el-input__icon:after{content:\"\";height:100%;width:0;display:inline-block;vertical-align:middle}.el-input__validateIcon{pointer-events:none}.el-input.is-disabled .el-input__inner{background-color:#f5f7fa;border-color:#e4e7ed;color:#c0c4cc;cursor:not-allowed}.el-input.is-disabled .el-input__inner::-webkit-input-placeholder{color:#c0c4cc}.el-input.is-disabled .el-input__inner:-ms-input-placeholder{color:#c0c4cc}.el-input.is-disabled .el-input__inner::-ms-input-placeholder{color:#c0c4cc}.el-input.is-disabled .el-input__inner::-moz-placeholder{color:#c0c4cc}.el-input.is-disabled .el-input__inner::placeholder{color:#c0c4cc}.el-input.is-disabled .el-input__icon{cursor:not-allowed}.el-input--suffix .el-input__inner{padding-right:30px}.el-input--prefix .el-input__inner{padding-left:30px}.el-input--medium{font-size:14px}.el-input--medium .el-input__inner{height:36px;line-height:36px}.el-input--medium .el-input__icon{line-height:36px}.el-input--small{font-size:13px}.el-input--small .el-input__inner{height:32px;line-height:32px}.el-input--small .el-input__icon{line-height:32px}.el-input--mini{font-size:12px}.el-input--mini .el-input__inner{height:28px;line-height:28px}.el-input--mini .el-input__icon{line-height:28px}.el-input-group{line-height:normal;display:inline-table;width:100%;border-collapse:separate;border-spacing:0}.el-input-group>.el-input__inner{vertical-align:middle;display:table-cell}.el-input-group__append,.el-input-group__prepend{background-color:#f5f7fa;color:#909399;vertical-align:middle;display:table-cell;position:relative;border:1px solid #dcdfe6;border-radius:4px;padding:0 20px;width:1px;white-space:nowrap}.el-input-group--prepend .el-input__inner,.el-input-group__append{border-top-left-radius:0;border-bottom-left-radius:0}.el-input-group--append .el-input__inner,.el-input-group__prepend{border-top-right-radius:0;border-bottom-right-radius:0}.el-input-group__append:focus,.el-input-group__prepend:focus{outline:0}.el-input-group__append .el-button,.el-input-group__append .el-select,.el-input-group__prepend .el-button,.el-input-group__prepend .el-select{display:inline-block;margin:-10px -20px}.el-input-group__append button.el-button,.el-input-group__append div.el-select .el-input__inner,.el-input-group__append div.el-select:hover .el-input__inner,.el-input-group__prepend button.el-button,.el-input-group__prepend div.el-select .el-input__inner,.el-input-group__prepend div.el-select:hover .el-input__inner{border-color:transparent;background-color:transparent;color:inherit;border-top:0;border-bottom:0}.el-input-group__append .el-button,.el-input-group__append .el-input,.el-input-group__prepend .el-button,.el-input-group__prepend .el-input{font-size:inherit}.el-input-group__prepend{border-right:0}.el-input-group__append{border-left:0}.el-input-group--append .el-select .el-input.is-focus .el-input__inner,.el-input-group--prepend .el-select .el-input.is-focus .el-input__inner{border-color:transparent}.el-input__inner::-ms-clear{display:none;width:0;height:0}.el-button{display:inline-block;line-height:1;white-space:nowrap;cursor:pointer;background:#fff;border:1px solid #dcdfe6;color:#606266;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;outline:0;margin:0;-webkit-transition:.1s;transition:.1s;font-weight:500;padding:12px 20px;font-size:14px;border-radius:4px}.el-button+.el-button{margin-left:10px}.el-button:focus,.el-button:hover{color:#409eff;border-color:#c6e2ff;background-color:#ecf5ff}.el-button:active{color:#3a8ee6;border-color:#3a8ee6;outline:0}.el-button::-moz-focus-inner{border:0}.el-button [class*=el-icon-]+span{margin-left:5px}.el-button.is-plain:focus,.el-button.is-plain:hover{background:#fff;border-color:#409eff;color:#409eff}.el-button.is-active,.el-button.is-plain:active{color:#3a8ee6;border-color:#3a8ee6}.el-button.is-plain:active{background:#fff;outline:0}.el-button.is-disabled,.el-button.is-disabled:focus,.el-button.is-disabled:hover{color:#c0c4cc;cursor:not-allowed;background-image:none;background-color:#fff;border-color:#ebeef5}.el-button.is-disabled.el-button--text{background-color:transparent}.el-button.is-disabled.is-plain,.el-button.is-disabled.is-plain:focus,.el-button.is-disabled.is-plain:hover{background-color:#fff;border-color:#ebeef5;color:#c0c4cc}.el-button.is-loading{position:relative;pointer-events:none}.el-button.is-loading:before{pointer-events:none;content:\"\";position:absolute;left:-1px;top:-1px;right:-1px;bottom:-1px;border-radius:inherit;background-color:hsla(0,0%,100%,.35)}.el-button.is-round{border-radius:20px;padding:12px 23px}.el-button.is-circle{border-radius:50%;padding:12px}.el-button--primary{color:#fff;background-color:#409eff;border-color:#409eff}.el-button--primary:focus,.el-button--primary:hover{background:#66b1ff;border-color:#66b1ff;color:#fff}.el-button--primary.is-active,.el-button--primary:active{background:#3a8ee6;border-color:#3a8ee6;color:#fff}.el-button--primary:active{outline:0}.el-button--primary.is-disabled,.el-button--primary.is-disabled:active,.el-button--primary.is-disabled:focus,.el-button--primary.is-disabled:hover{color:#fff;background-color:#a0cfff;border-color:#a0cfff}.el-button--primary.is-plain{color:#409eff;background:#ecf5ff;border-color:#b3d8ff}.el-button--primary.is-plain:focus,.el-button--primary.is-plain:hover{background:#409eff;border-color:#409eff;color:#fff}.el-button--primary.is-plain:active{background:#3a8ee6;border-color:#3a8ee6;color:#fff;outline:0}.el-button--primary.is-plain.is-disabled,.el-button--primary.is-plain.is-disabled:active,.el-button--primary.is-plain.is-disabled:focus,.el-button--primary.is-plain.is-disabled:hover{color:#8cc5ff;background-color:#ecf5ff;border-color:#d9ecff}.el-button--success{color:#fff;background-color:#67c23a;border-color:#67c23a}.el-button--success:focus,.el-button--success:hover{background:#85ce61;border-color:#85ce61;color:#fff}.el-button--success.is-active,.el-button--success:active{background:#5daf34;border-color:#5daf34;color:#fff}.el-button--success:active{outline:0}.el-button--success.is-disabled,.el-button--success.is-disabled:active,.el-button--success.is-disabled:focus,.el-button--success.is-disabled:hover{color:#fff;background-color:#b3e19d;border-color:#b3e19d}.el-button--success.is-plain{color:#67c23a;background:#f0f9eb;border-color:#c2e7b0}.el-button--success.is-plain:focus,.el-button--success.is-plain:hover{background:#67c23a;border-color:#67c23a;color:#fff}.el-button--success.is-plain:active{background:#5daf34;border-color:#5daf34;color:#fff;outline:0}.el-button--success.is-plain.is-disabled,.el-button--success.is-plain.is-disabled:active,.el-button--success.is-plain.is-disabled:focus,.el-button--success.is-plain.is-disabled:hover{color:#a4da89;background-color:#f0f9eb;border-color:#e1f3d8}.el-button--warning{color:#fff;background-color:#e6a23c;border-color:#e6a23c}.el-button--warning:focus,.el-button--warning:hover{background:#ebb563;border-color:#ebb563;color:#fff}.el-button--warning.is-active,.el-button--warning:active{background:#cf9236;border-color:#cf9236;color:#fff}.el-button--warning:active{outline:0}.el-button--warning.is-disabled,.el-button--warning.is-disabled:active,.el-button--warning.is-disabled:focus,.el-button--warning.is-disabled:hover{color:#fff;background-color:#f3d19e;border-color:#f3d19e}.el-button--warning.is-plain{color:#e6a23c;background:#fdf6ec;border-color:#f5dab1}.el-button--warning.is-plain:focus,.el-button--warning.is-plain:hover{background:#e6a23c;border-color:#e6a23c;color:#fff}.el-button--warning.is-plain:active{background:#cf9236;border-color:#cf9236;color:#fff;outline:0}.el-button--warning.is-plain.is-disabled,.el-button--warning.is-plain.is-disabled:active,.el-button--warning.is-plain.is-disabled:focus,.el-button--warning.is-plain.is-disabled:hover{color:#f0c78a;background-color:#fdf6ec;border-color:#faecd8}.el-button--danger{color:#fff;background-color:#f56c6c;border-color:#f56c6c}.el-button--danger:focus,.el-button--danger:hover{background:#f78989;border-color:#f78989;color:#fff}.el-button--danger.is-active,.el-button--danger:active{background:#dd6161;border-color:#dd6161;color:#fff}.el-button--danger:active{outline:0}.el-button--danger.is-disabled,.el-button--danger.is-disabled:active,.el-button--danger.is-disabled:focus,.el-button--danger.is-disabled:hover{color:#fff;background-color:#fab6b6;border-color:#fab6b6}.el-button--danger.is-plain{color:#f56c6c;background:#fef0f0;border-color:#fbc4c4}.el-button--danger.is-plain:focus,.el-button--danger.is-plain:hover{background:#f56c6c;border-color:#f56c6c;color:#fff}.el-button--danger.is-plain:active{background:#dd6161;border-color:#dd6161;color:#fff;outline:0}.el-button--danger.is-plain.is-disabled,.el-button--danger.is-plain.is-disabled:active,.el-button--danger.is-plain.is-disabled:focus,.el-button--danger.is-plain.is-disabled:hover{color:#f9a7a7;background-color:#fef0f0;border-color:#fde2e2}.el-button--info{color:#fff;background-color:#909399;border-color:#909399}.el-button--info:focus,.el-button--info:hover{background:#a6a9ad;border-color:#a6a9ad;color:#fff}.el-button--info.is-active,.el-button--info:active{background:#82848a;border-color:#82848a;color:#fff}.el-button--info:active{outline:0}.el-button--info.is-disabled,.el-button--info.is-disabled:active,.el-button--info.is-disabled:focus,.el-button--info.is-disabled:hover{color:#fff;background-color:#c8c9cc;border-color:#c8c9cc}.el-button--info.is-plain{color:#909399;background:#f4f4f5;border-color:#d3d4d6}.el-button--info.is-plain:focus,.el-button--info.is-plain:hover{background:#909399;border-color:#909399;color:#fff}.el-button--info.is-plain:active{background:#82848a;border-color:#82848a;color:#fff;outline:0}.el-button--info.is-plain.is-disabled,.el-button--info.is-plain.is-disabled:active,.el-button--info.is-plain.is-disabled:focus,.el-button--info.is-plain.is-disabled:hover{color:#bcbec2;background-color:#f4f4f5;border-color:#e9e9eb}.el-button--text,.el-button--text.is-disabled,.el-button--text.is-disabled:focus,.el-button--text.is-disabled:hover,.el-button--text:active{border-color:transparent}.el-button--medium{padding:10px 20px;font-size:14px;border-radius:4px}.el-button--mini,.el-button--small{font-size:12px;border-radius:3px}.el-button--medium.is-round{padding:10px 20px}.el-button--medium.is-circle{padding:10px}.el-button--small,.el-button--small.is-round{padding:9px 15px}.el-button--small.is-circle{padding:9px}.el-button--mini,.el-button--mini.is-round{padding:7px 15px}.el-button--mini.is-circle{padding:7px}.el-button--text{color:#409eff;background:0 0;padding-left:0;padding-right:0}.el-button--text:focus,.el-button--text:hover{color:#66b1ff;border-color:transparent;background-color:transparent}.el-button--text:active{color:#3a8ee6;background-color:transparent}.el-button-group{display:inline-block;vertical-align:middle}.el-button-group:after,.el-button-group:before{display:table;content:\"\"}.el-checkbox,.el-checkbox__input{display:inline-block;position:relative;white-space:nowrap}.el-button-group:after{clear:both}.el-button-group>.el-button{float:left;position:relative}.el-button-group>.el-button+.el-button{margin-left:0}.el-button-group>.el-button:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.el-button-group>.el-button:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.el-button-group>.el-button:first-child:last-child{border-radius:4px}.el-button-group>.el-button:first-child:last-child.is-round{border-radius:20px}.el-button-group>.el-button:first-child:last-child.is-circle{border-radius:50%}.el-button-group>.el-button:not(:first-child):not(:last-child){border-radius:0}.el-button-group>.el-button:not(:last-child){margin-right:-1px}.el-button-group>.el-dropdown>.el-button{border-top-left-radius:0;border-bottom-left-radius:0;border-left-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--primary:first-child{border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--primary:last-child{border-left-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--primary:not(:first-child):not(:last-child){border-left-color:hsla(0,0%,100%,.5);border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--success:first-child{border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--success:last-child{border-left-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--success:not(:first-child):not(:last-child){border-left-color:hsla(0,0%,100%,.5);border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--warning:first-child{border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--warning:last-child{border-left-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--warning:not(:first-child):not(:last-child){border-left-color:hsla(0,0%,100%,.5);border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--danger:first-child{border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--danger:last-child{border-left-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--danger:not(:first-child):not(:last-child){border-left-color:hsla(0,0%,100%,.5);border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--info:first-child{border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--info:last-child{border-left-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--info:not(:first-child):not(:last-child){border-left-color:hsla(0,0%,100%,.5);border-right-color:hsla(0,0%,100%,.5)}.el-checkbox{color:#606266;font-weight:500;font-size:14px;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;margin-right:30px}.el-checkbox.is-bordered{padding:9px 20px 9px 10px;border-radius:4px;border:1px solid #dcdfe6;-webkit-box-sizing:border-box;box-sizing:border-box;line-height:normal;height:40px}.el-checkbox.is-bordered.is-checked{border-color:#409eff}.el-checkbox.is-bordered.is-disabled{border-color:#ebeef5;cursor:not-allowed}.el-checkbox.is-bordered+.el-checkbox.is-bordered{margin-left:10px}.el-checkbox.is-bordered.el-checkbox--medium{padding:7px 20px 7px 10px;border-radius:4px;height:36px}.el-checkbox.is-bordered.el-checkbox--medium .el-checkbox__label{line-height:17px;font-size:14px}.el-checkbox.is-bordered.el-checkbox--medium .el-checkbox__inner{height:14px;width:14px}.el-checkbox.is-bordered.el-checkbox--small{padding:5px 15px 5px 10px;border-radius:3px;height:32px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__label{line-height:15px;font-size:12px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner{height:12px;width:12px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner:after{height:6px;width:2px}.el-checkbox.is-bordered.el-checkbox--mini{padding:3px 15px 3px 10px;border-radius:3px;height:28px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__label{line-height:12px;font-size:12px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__inner{height:12px;width:12px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__inner:after{height:6px;width:2px}.el-checkbox__input{cursor:pointer;outline:0;line-height:1;vertical-align:middle}.el-checkbox__input.is-disabled .el-checkbox__inner{background-color:#edf2fc;border-color:#dcdfe6;cursor:not-allowed}.el-checkbox__input.is-disabled .el-checkbox__inner:after{cursor:not-allowed;border-color:#c0c4cc}.el-checkbox__input.is-disabled .el-checkbox__inner+.el-checkbox__label{cursor:not-allowed}.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner{background-color:#f2f6fc;border-color:#dcdfe6}.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner:after{border-color:#c0c4cc}.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner{background-color:#f2f6fc;border-color:#dcdfe6}.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner:before{background-color:#c0c4cc;border-color:#c0c4cc}.el-checkbox__input.is-checked .el-checkbox__inner,.el-checkbox__input.is-indeterminate .el-checkbox__inner{background-color:#409eff;border-color:#409eff}.el-checkbox__input.is-disabled+span.el-checkbox__label{color:#c0c4cc;cursor:not-allowed}.el-checkbox__input.is-checked .el-checkbox__inner:after{-webkit-transform:rotate(45deg) scaleY(1);transform:rotate(45deg) scaleY(1)}.el-checkbox__input.is-checked+.el-checkbox__label{color:#409eff}.el-checkbox__input.is-focus .el-checkbox__inner{border-color:#409eff}.el-checkbox__input.is-indeterminate .el-checkbox__inner:before{content:\"\";position:absolute;display:block;background-color:#fff;height:2px;-webkit-transform:scale(.5);transform:scale(.5);left:0;right:0;top:5px}.el-checkbox__input.is-indeterminate .el-checkbox__inner:after{display:none}.el-checkbox__inner{display:inline-block;position:relative;border:1px solid #dcdfe6;border-radius:2px;-webkit-box-sizing:border-box;box-sizing:border-box;width:14px;height:14px;background-color:#fff;z-index:1;-webkit-transition:border-color .25s cubic-bezier(.71,-.46,.29,1.46),background-color .25s cubic-bezier(.71,-.46,.29,1.46);transition:border-color .25s cubic-bezier(.71,-.46,.29,1.46),background-color .25s cubic-bezier(.71,-.46,.29,1.46)}.el-checkbox__inner:hover{border-color:#409eff}.el-checkbox__inner:after{-webkit-box-sizing:content-box;box-sizing:content-box;content:\"\";border:1px solid #fff;border-left:0;border-top:0;height:7px;left:4px;position:absolute;top:1px;-webkit-transform:rotate(45deg) scaleY(0);transform:rotate(45deg) scaleY(0);width:3px;-webkit-transition:-webkit-transform .15s ease-in .05s;transition:-webkit-transform .15s ease-in .05s;transition:transform .15s ease-in .05s;transition:transform .15s ease-in .05s,-webkit-transform .15s ease-in .05s;-webkit-transform-origin:center;transform-origin:center}.el-checkbox__original{opacity:0;outline:0;position:absolute;margin:0;width:0;height:0;z-index:-1}.el-checkbox-button,.el-checkbox-button__inner{position:relative;display:inline-block}.el-checkbox__label{display:inline-block;padding-left:10px;line-height:19px;font-size:14px}.el-checkbox:last-child{margin-right:0}.el-checkbox-button__inner{line-height:1;font-weight:500;white-space:nowrap;vertical-align:middle;cursor:pointer;background:#fff;border:1px solid #dcdfe6;border-left:0;color:#606266;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;outline:0;margin:0;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;padding:12px 20px;font-size:14px;border-radius:0}.el-checkbox-button__inner.is-round{padding:12px 20px}.el-checkbox-button__inner:hover{color:#409eff}.el-checkbox-button__inner [class*=el-icon-]{line-height:.9}.el-checkbox-button__inner [class*=el-icon-]+span{margin-left:5px}.el-checkbox-button__original{opacity:0;outline:0;position:absolute;margin:0;z-index:-1}.el-checkbox-button.is-checked .el-checkbox-button__inner{color:#fff;background-color:#409eff;border-color:#409eff;-webkit-box-shadow:-1px 0 0 0 #8cc5ff;box-shadow:-1px 0 0 0 #8cc5ff}.el-checkbox-button.is-checked:first-child .el-checkbox-button__inner{border-left-color:#409eff}.el-checkbox-button.is-disabled .el-checkbox-button__inner{color:#c0c4cc;cursor:not-allowed;background-image:none;background-color:#fff;border-color:#ebeef5;-webkit-box-shadow:none;box-shadow:none}.el-checkbox-button.is-disabled:first-child .el-checkbox-button__inner{border-left-color:#ebeef5}.el-checkbox-button:first-child .el-checkbox-button__inner{border-left:1px solid #dcdfe6;border-radius:4px 0 0 4px;-webkit-box-shadow:none!important;box-shadow:none!important}.el-checkbox-button.is-focus .el-checkbox-button__inner{border-color:#409eff}.el-checkbox-button:last-child .el-checkbox-button__inner{border-radius:0 4px 4px 0}.el-checkbox-button--medium .el-checkbox-button__inner{padding:10px 20px;font-size:14px;border-radius:0}.el-checkbox-button--medium .el-checkbox-button__inner.is-round{padding:10px 20px}.el-checkbox-button--small .el-checkbox-button__inner{padding:9px 15px;font-size:12px;border-radius:0}.el-checkbox-button--small .el-checkbox-button__inner.is-round{padding:9px 15px}.el-checkbox-button--mini .el-checkbox-button__inner{padding:7px 15px;font-size:12px;border-radius:0}.el-checkbox-button--mini .el-checkbox-button__inner.is-round{padding:7px 15px}.el-checkbox-group{font-size:0}.el-transfer{font-size:14px}.el-transfer__buttons{display:inline-block;vertical-align:middle;padding:0 30px}.el-transfer__button{display:block;margin:0 auto;padding:10px;border-radius:50%;color:#fff;background-color:#409eff;font-size:0}.el-transfer-panel__item+.el-transfer-panel__item,.el-transfer__button [class*=el-icon-]+span{margin-left:0}.el-transfer__button.is-with-texts{border-radius:4px}.el-transfer__button.is-disabled,.el-transfer__button.is-disabled:hover{border:1px solid #dcdfe6;background-color:#f5f7fa;color:#c0c4cc}.el-transfer__button:first-child{margin-bottom:10px}.el-transfer__button:nth-child(2){margin:0}.el-transfer__button i,.el-transfer__button span{font-size:14px}.el-transfer-panel{border:1px solid #ebeef5;border-radius:4px;overflow:hidden;background:#fff;display:inline-block;vertical-align:middle;width:200px;max-height:100%;-webkit-box-sizing:border-box;box-sizing:border-box;position:relative}.el-transfer-panel__body{height:246px}.el-transfer-panel__body.is-with-footer{padding-bottom:40px}.el-transfer-panel__list{margin:0;padding:6px 0;list-style:none;height:246px;overflow:auto;-webkit-box-sizing:border-box;box-sizing:border-box}.el-transfer-panel__list.is-filterable{height:194px;padding-top:0}.el-transfer-panel__item{height:30px;line-height:30px;padding-left:15px;display:block}.el-transfer-panel__item.el-checkbox{color:#606266}.el-transfer-panel__item:hover{color:#409eff}.el-transfer-panel__item.el-checkbox .el-checkbox__label{width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;-webkit-box-sizing:border-box;box-sizing:border-box;padding-left:24px;line-height:30px}.el-transfer-panel__item .el-checkbox__input{position:absolute;top:8px}.el-transfer-panel__filter{text-align:center;margin:15px;-webkit-box-sizing:border-box;box-sizing:border-box;display:block;width:auto}.el-transfer-panel__filter .el-input__inner{height:32px;width:100%;font-size:12px;display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:16px;padding-right:10px;padding-left:30px}.el-transfer-panel__filter .el-input__icon{margin-left:5px}.el-transfer-panel__filter .el-icon-circle-close{cursor:pointer}.el-transfer-panel .el-transfer-panel__header{height:40px;line-height:40px;background:#f5f7fa;margin:0;padding-left:15px;border-bottom:1px solid #ebeef5;-webkit-box-sizing:border-box;box-sizing:border-box;color:#000}.el-container,.el-header{-webkit-box-sizing:border-box}.el-transfer-panel .el-transfer-panel__header .el-checkbox{display:block;line-height:40px}.el-transfer-panel .el-transfer-panel__header .el-checkbox .el-checkbox__label{font-size:16px;color:#303133;font-weight:400}.el-transfer-panel .el-transfer-panel__header .el-checkbox .el-checkbox__label span{position:absolute;right:15px;color:#909399;font-size:12px;font-weight:400}.el-transfer-panel .el-transfer-panel__footer{height:40px;background:#fff;margin:0;padding:0;border-top:1px solid #ebeef5;position:absolute;bottom:0;left:0;width:100%;z-index:1}.el-transfer-panel .el-transfer-panel__footer:after{display:inline-block;content:\"\";height:100%;vertical-align:middle}.el-container,.el-timeline-item__node{display:-webkit-box;display:-ms-flexbox}.el-transfer-panel .el-transfer-panel__footer .el-checkbox{padding-left:20px;color:#606266}.el-transfer-panel .el-transfer-panel__empty{margin:0;height:30px;line-height:30px;padding:6px 15px 0;color:#909399;text-align:center}.el-transfer-panel .el-checkbox__label{padding-left:8px}.el-transfer-panel .el-checkbox__inner{height:14px;width:14px;border-radius:3px}.el-transfer-panel .el-checkbox__inner:after{height:6px;width:3px;left:4px}.el-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-preferred-size:auto;flex-basis:auto;-webkit-box-sizing:border-box;box-sizing:border-box;min-width:0}.el-container.is-vertical{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.el-header{padding:0 20px;-webkit-box-sizing:border-box;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}.el-aside,.el-main{overflow:auto;-webkit-box-sizing:border-box}.el-aside{-ms-flex-negative:0;flex-shrink:0}.el-aside,.el-main{-webkit-box-sizing:border-box;box-sizing:border-box}.el-main{display:block;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-preferred-size:auto;flex-basis:auto;padding:20px}.el-footer{padding:0 20px;-webkit-box-sizing:border-box;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}.el-timeline{margin:0;font-size:14px;list-style:none}.el-timeline .el-timeline-item:last-child .el-timeline-item__tail{display:none}.el-timeline-item{position:relative;padding-bottom:20px}.el-timeline-item__wrapper{position:relative;padding-left:28px;top:-3px}.el-timeline-item__tail{position:absolute;left:4px;height:100%;border-left:2px solid #e4e7ed}.el-timeline-item__icon{color:#fff;font-size:13px}.el-timeline-item__node{position:absolute;background-color:#e4e7ed;border-radius:50%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-timeline-item__node--normal{left:-1px;width:12px;height:12px}.el-timeline-item__node--large{left:-2px;width:14px;height:14px}.el-timeline-item__node--primary{background-color:#409eff}.el-timeline-item__node--success{background-color:#67c23a}.el-timeline-item__node--warning{background-color:#e6a23c}.el-timeline-item__node--danger{background-color:#f56c6c}.el-timeline-item__node--info{background-color:#909399}.el-timeline-item__dot{position:absolute;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-timeline-item__content{color:#303133}.el-timeline-item__timestamp{color:#909399;line-height:1;font-size:13px}.el-timeline-item__timestamp.is-top{margin-bottom:8px;padding-top:4px}.el-timeline-item__timestamp.is-bottom{margin-top:8px}"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/css/chunk-libs.5cf311f0.css",
    "content": "/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:inherit;font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{-webkit-box-sizing:border-box;box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}[hidden],template{display:none}#nprogress{pointer-events:none}#nprogress .bar{background:#29d;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;-webkit-box-shadow:0 0 10px #29d,0 0 5px #29d;box-shadow:0 0 10px #29d,0 0 5px #29d;opacity:1;-webkit-transform:rotate(3deg) translateY(-4px);transform:rotate(3deg) translateY(-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}#nprogress .spinner-icon{width:18px;height:18px;-webkit-box-sizing:border-box;box-sizing:border-box;border:2px solid transparent;border-top-color:#29d;border-left-color:#29d;border-radius:50%;-webkit-animation:nprogress-spinner .4s linear infinite;animation:nprogress-spinner .4s linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute}@-webkit-keyframes nprogress-spinner{0%{-webkit-transform:rotate(0deg)}to{-webkit-transform:rotate(1turn)}}@keyframes nprogress-spinner{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/js/app.6845b228.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[\"app\"],{0:function(e,t,n){e.exports=n(\"56d7\")},\"028b\":function(e,t,n){\"use strict\";var a=n(\"a217\"),i=n.n(a);i.a},1660:function(e,t,n){\"use strict\";var a=n(\"ff7f\"),i=n.n(a);i.a},\"186a\":function(e,t,n){\"use strict\";var a=n(\"dc52\"),i=n.n(a);i.a},\"18f0\":function(e,t,n){\"use strict\";n.r(t);var a=n(\"e017\"),i=n.n(a),r=n(\"21a1\"),o=n.n(r),c=new i.a({id:\"icon-link\",use:\"icon-link-usage\",viewBox:\"0 0 128 128\",content:'<symbol xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 128 128\" id=\"icon-link\"><path d=\"M115.625 127.937H.063V12.375h57.781v12.374H12.438v90.813h90.813V70.156h12.374z\" /><path d=\"M116.426 2.821l8.753 8.753-56.734 56.734-8.753-8.745z\" /><path d=\"M127.893 37.982h-12.375V12.375H88.706V0h39.187z\" /></symbol>'});o.a.add(c);t[\"default\"]=c},\"1b09\":function(e,t,n){\"use strict\";var a=n(\"4ed7\"),i=n.n(a);i.a},2021:function(e,t,n){},\"2a3d\":function(e,t,n){\"use strict\";n.r(t);var a=n(\"e017\"),i=n.n(a),r=n(\"21a1\"),o=n.n(r),c=new i.a({id:\"icon-password\",use:\"icon-password-usage\",viewBox:\"0 0 128 128\",content:'<symbol xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 128 128\" id=\"icon-password\"><path d=\"M108.8 44.322H89.6v-5.36c0-9.04-3.308-24.163-25.6-24.163-23.145 0-25.6 16.881-25.6 24.162v5.361H19.2v-5.36C19.2 15.281 36.798 0 64 0c27.202 0 44.8 15.281 44.8 38.961v5.361zm-32 39.356c0-5.44-5.763-9.832-12.8-9.832-7.037 0-12.8 4.392-12.8 9.832 0 3.682 2.567 6.808 6.407 8.477v11.205c0 2.718 2.875 4.962 6.4 4.962 3.524 0 6.4-2.244 6.4-4.962V92.155c3.833-1.669 6.393-4.795 6.393-8.477zM128 64v49.201c0 8.158-8.645 14.799-19.2 14.799H19.2C8.651 128 0 121.359 0 113.201V64c0-8.153 8.645-14.799 19.2-14.799h89.6c10.555 0 19.2 6.646 19.2 14.799z\" /></symbol>'});o.a.add(c);t[\"default\"]=c},\"30c3\":function(e,t,n){\"use strict\";n.r(t);var a=n(\"e017\"),i=n.n(a),r=n(\"21a1\"),o=n.n(r),c=new i.a({id:\"icon-example\",use:\"icon-example-usage\",viewBox:\"0 0 128 128\",content:'<symbol xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 128 128\" id=\"icon-example\"><path d=\"M96.258 57.462h31.421C124.794 27.323 100.426 2.956 70.287.07v31.422a32.856 32.856 0 0 1 25.971 25.97zm-38.796-25.97V.07C27.323 2.956 2.956 27.323.07 57.462h31.422a32.856 32.856 0 0 1 25.97-25.97zm12.825 64.766v31.421c30.46-2.885 54.507-27.253 57.713-57.712H96.579c-2.886 13.466-13.146 23.726-26.292 26.291zM31.492 70.287H.07c2.886 30.46 27.253 54.507 57.713 57.713V96.579c-13.466-2.886-23.726-13.146-26.291-26.292z\" /></symbol>'});o.a.add(c);t[\"default\"]=c},4360:function(e,t,n){\"use strict\";var a=n(\"2b0e\"),i=n(\"2f62\"),r=(n(\"7f7f\"),{sidebar:function(e){return e.app.sidebar},device:function(e){return e.app.device},token:function(e){return e.user.token},avatar:function(e){return e.user.avatar},name:function(e){return e.user.name}}),o=r,c=n(\"a78e\"),s=n.n(c),u={sidebar:{opened:!s.a.get(\"sidebarStatus\")||!!+s.a.get(\"sidebarStatus\"),withoutAnimation:!1},device:\"desktop\"},l={TOGGLE_SIDEBAR:function(e){e.sidebar.opened=!e.sidebar.opened,e.sidebar.withoutAnimation=!1,e.sidebar.opened?s.a.set(\"sidebarStatus\",1):s.a.set(\"sidebarStatus\",0)},CLOSE_SIDEBAR:function(e,t){s.a.set(\"sidebarStatus\",0),e.sidebar.opened=!1,e.sidebar.withoutAnimation=t},TOGGLE_DEVICE:function(e,t){e.device=t}},d={toggleSideBar:function(e){var t=e.commit;t(\"TOGGLE_SIDEBAR\")},closeSideBar:function(e,t){var n=e.commit,a=t.withoutAnimation;n(\"CLOSE_SIDEBAR\",a)},toggleDevice:function(e,t){var n=e.commit;n(\"TOGGLE_DEVICE\",t)}},h={namespaced:!0,state:u,mutations:l,actions:d},f=n(\"83d6\"),m=n.n(f),p=m.a.showSettings,v=m.a.fixedHeader,b=m.a.sidebarLogo,g={showSettings:p,fixedHeader:v,sidebarLogo:b},w={CHANGE_SETTING:function(e,t){var n=t.key,a=t.value;e.hasOwnProperty(n)&&(e[n]=a)}},x={changeSetting:function(e,t){var n=e.commit;n(\"CHANGE_SETTING\",t)}},k={namespaced:!0,state:g,mutations:w,actions:x},y=n(\"c24f\"),C=n(\"5f87\"),_=n(\"a18c\"),O={token:Object(C[\"a\"])(),name:\"\",avatar:\"\"},S={SET_TOKEN:function(e,t){e.token=t},SET_NAME:function(e,t){e.name=t},SET_AVATAR:function(e,t){e.avatar=t}},z={login:function(e,t){var n=e.commit,a=t.username,i=t.password;return new Promise(function(e,t){Object(y[\"b\"])({username:a.trim(),password:i}).then(function(t){var a=t.data;n(\"SET_TOKEN\",a.token),Object(C[\"c\"])(a.token),e()}).catch(function(e){t(e)})})},getInfo:function(e){var t=e.commit,n=e.state;return new Promise(function(e,a){Object(y[\"a\"])(n.token).then(function(n){var i=n.data;i||a(\"Verification failed, please Login again.\");var r=i.name,o=i.avatar;t(\"SET_NAME\",r),t(\"SET_AVATAR\",o),e(i)}).catch(function(e){a(e)})})},logout:function(e){var t=e.commit,n=e.state;return new Promise(function(e,a){Object(y[\"c\"])(n.token).then(function(){t(\"SET_TOKEN\",\"\"),Object(C[\"b\"])(),Object(_[\"b\"])(),e()}).catch(function(e){a(e)})})},resetToken:function(e){var t=e.commit;return new Promise(function(e){t(\"SET_TOKEN\",\"\"),Object(C[\"b\"])(),e()})}},E={namespaced:!0,state:O,mutations:S,actions:z};a[\"default\"].use(i[\"a\"]);var H=new i[\"a\"].Store({modules:{app:h,settings:k,user:E},getters:o});t[\"a\"]=H},\"47f1\":function(e,t,n){\"use strict\";n.r(t);var a=n(\"e017\"),i=n.n(a),r=n(\"21a1\"),o=n.n(r),c=new i.a({id:\"icon-table\",use:\"icon-table-usage\",viewBox:\"0 0 128 128\",content:'<symbol xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 128 128\" id=\"icon-table\"><path d=\"M.006.064h127.988v31.104H.006V.064zm0 38.016h38.396v41.472H.006V38.08zm0 48.384h38.396v41.472H.006V86.464zM44.802 38.08h38.396v41.472H44.802V38.08zm0 48.384h38.396v41.472H44.802V86.464zM89.598 38.08h38.396v41.472H89.598zm0 48.384h38.396v41.472H89.598z\" /><path d=\"M.006.064h127.988v31.104H.006V.064zm0 38.016h38.396v41.472H.006V38.08zm0 48.384h38.396v41.472H.006V86.464zM44.802 38.08h38.396v41.472H44.802V38.08zm0 48.384h38.396v41.472H44.802V86.464zM89.598 38.08h38.396v41.472H89.598zm0 48.384h38.396v41.472H89.598z\" /></symbol>'});o.a.add(c);t[\"default\"]=c},\"4df5\":function(e,t,n){\"use strict\";n.r(t);var a=n(\"e017\"),i=n.n(a),r=n(\"21a1\"),o=n.n(r),c=new i.a({id:\"icon-eye\",use:\"icon-eye-usage\",viewBox:\"0 0 128 64\",content:'<symbol xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 128 64\" id=\"icon-eye\"><path d=\"M127.072 7.994c1.37-2.208.914-5.152-.914-6.87-2.056-1.717-4.797-1.226-6.396.982-.229.245-25.586 32.382-55.74 32.382-29.24 0-55.74-32.382-55.968-32.627-1.6-1.963-4.57-2.208-6.397-.49C-.17 3.086-.399 6.275 1.2 8.238c.457.736 5.94 7.36 14.62 14.72L4.17 35.96c-1.828 1.963-1.6 5.152.228 6.87.457.98 1.6 1.471 2.742 1.471s2.284-.49 3.198-1.472l12.564-13.983c5.94 4.416 13.021 8.587 20.788 11.53l-4.797 17.418c-.685 2.699.686 5.397 3.198 6.133h1.37c2.057 0 3.884-1.472 4.341-3.68L52.6 42.83c3.655.736 7.538 1.227 11.422 1.227 3.883 0 7.767-.49 11.422-1.227l4.797 17.173c.457 2.208 2.513 3.68 4.34 3.68.457 0 .914 0 1.143-.246 2.513-.736 3.883-3.434 3.198-6.133l-4.797-17.172c7.767-2.944 14.848-7.114 20.788-11.53l12.336 13.738c.913.981 2.056 1.472 3.198 1.472s2.284-.49 3.198-1.472c1.828-1.963 1.828-4.906.228-6.87l-11.65-13.001c9.366-7.36 14.849-14.474 14.849-14.474z\" /></symbol>'});o.a.add(c);t[\"default\"]=c},\"4ed7\":function(e,t,n){},\"51ff\":function(e,t,n){var a={\"./dashboard.svg\":\"f782\",\"./example.svg\":\"30c3\",\"./eye-open.svg\":\"d7ec\",\"./eye.svg\":\"4df5\",\"./form.svg\":\"eb1b\",\"./link.svg\":\"18f0\",\"./nested.svg\":\"dcf8\",\"./password.svg\":\"2a3d\",\"./table.svg\":\"47f1\",\"./tree.svg\":\"93cd\",\"./user.svg\":\"b3b5\"};function i(e){var t=r(e);return n(t)}function r(e){var t=a[e];if(!(t+1)){var n=new Error(\"Cannot find module '\"+e+\"'\");throw n.code=\"MODULE_NOT_FOUND\",n}return t}i.keys=function(){return Object.keys(a)},i.resolve=r,e.exports=i,i.id=\"51ff\"},\"56d7\":function(e,t,n){\"use strict\";n.r(t);n(\"cadf\"),n(\"551c\"),n(\"f751\"),n(\"097d\");var a=n(\"2b0e\"),i=(n(\"f5df\"),n(\"5c96\")),r=n.n(i),o=(n(\"0fae\"),n(\"b2d6\")),c=n.n(o),s=(n(\"b20f\"),function(){var e=this,t=e.$createElement,n=e._self._c||t;return n(\"div\",{attrs:{id:\"app\"}},[n(\"router-view\")],1)}),u=[],l={name:\"App\"},d=l,h=n(\"2877\"),f=Object(h[\"a\"])(d,s,u,!1,null,null,null),m=f.exports,p=n(\"4360\"),v=n(\"a18c\"),b=(n(\"ac6a\"),function(){var e=this,t=e.$createElement,n=e._self._c||t;return e.isExternal?n(\"div\",e._g({staticClass:\"svg-external-icon svg-icon\",style:e.styleExternalIcon},e.$listeners)):n(\"svg\",e._g({class:e.svgClass,attrs:{\"aria-hidden\":\"true\"}},e.$listeners),[n(\"use\",{attrs:{\"xlink:href\":e.iconName}})])}),g=[],w=n(\"61f7\"),x={name:\"SvgIcon\",props:{iconClass:{type:String,required:!0},className:{type:String,default:\"\"}},computed:{isExternal:function(){return Object(w[\"a\"])(this.iconClass)},iconName:function(){return\"#icon-\".concat(this.iconClass)},svgClass:function(){return this.className?\"svg-icon \"+this.className:\"svg-icon\"},styleExternalIcon:function(){return{mask:\"url(\".concat(this.iconClass,\") no-repeat 50% 50%\"),\"-webkit-mask\":\"url(\".concat(this.iconClass,\") no-repeat 50% 50%\")}}}},k=x,y=(n(\"68fa\"),Object(h[\"a\"])(k,b,g,!1,null,\"f9f7fefc\",null)),C=y.exports;a[\"default\"].component(\"svg-icon\",C);var _=n(\"51ff\"),O=function(e){return e.keys().map(e)};O(_);n(\"7f7f\"),n(\"96cf\");var S=n(\"3b8d\"),z=n(\"323e\"),E=n.n(z),H=(n(\"a5d8\"),n(\"5f87\")),M=n(\"83d6\"),B=n.n(M),T=B.a.title||\"Vue Admin Template\";function j(e){return e?\"\".concat(e,\" - \").concat(T):\"\".concat(T)}E.a.configure({showSpinner:!1});var L=[\"/login\"];v[\"a\"].beforeEach(function(){var e=Object(S[\"a\"])(regeneratorRuntime.mark(function e(t,n,a){var r,o;return regeneratorRuntime.wrap(function(e){while(1)switch(e.prev=e.next){case 0:if(E.a.start(),document.title=j(t.meta.title),r=Object(H[\"a\"])(),!r){e.next=29;break}if(\"/login\"!==t.path){e.next=9;break}a({path:\"/\"}),E.a.done(),e.next=27;break;case 9:if(o=p[\"a\"].getters.name,!o){e.next=14;break}a(),e.next=27;break;case 14:return e.prev=14,e.next=17,p[\"a\"].dispatch(\"user/getInfo\");case 17:a(),e.next=27;break;case 20:return e.prev=20,e.t0=e[\"catch\"](14),e.next=24,p[\"a\"].dispatch(\"user/resetToken\");case 24:i[\"Message\"].error(e.t0||\"Has Error\"),a(\"/login?redirect=\".concat(t.path)),E.a.done();case 27:e.next=30;break;case 29:-1!==L.indexOf(t.path)?a():(a(\"/login?redirect=\".concat(t.path)),E.a.done());case 30:case\"end\":return e.stop()}},e,null,[[14,20]])}));return function(t,n,a){return e.apply(this,arguments)}}()),v[\"a\"].afterEach(function(){E.a.done()}),a[\"default\"].use(r.a,{size:\"small\",locale:c.a}),a[\"default\"].config.productionTip=!1,new a[\"default\"]({el:\"#app\",router:v[\"a\"],store:p[\"a\"],render:function(e){return e(m)}})},\"5bb9\":function(e,t,n){},\"5f87\":function(e,t,n){\"use strict\";n.d(t,\"a\",function(){return o}),n.d(t,\"c\",function(){return c}),n.d(t,\"b\",function(){return s});var a=n(\"a78e\"),i=n.n(a),r=\"canal_admin_token\";function o(){return i.a.get(r)}function c(e){return i.a.set(r,e,{maxAge:0})}function s(){return i.a.remove(r)}},\"61f7\":function(e,t,n){\"use strict\";function a(e){return/^(https?:|mailto:|tel:)/.test(e)}function i(e){var t=[\"admin\",\"editor\"];return t.indexOf(e.trim())>=0}n.d(t,\"a\",function(){return a}),n.d(t,\"b\",function(){return i})},\"68fa\":function(e,t,n){\"use strict\";var a=n(\"2021\"),i=n.n(a);i.a},\"83d6\":function(e,t){e.exports={title:\"Canal Admin\",fixedHeader:!0,sidebarLogo:!0}},8902:function(e,t,n){},\"93cd\":function(e,t,n){\"use strict\";n.r(t);var a=n(\"e017\"),i=n.n(a),r=n(\"21a1\"),o=n.n(r),c=new i.a({id:\"icon-tree\",use:\"icon-tree-usage\",viewBox:\"0 0 128 128\",content:'<symbol xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 128 128\" id=\"icon-tree\"><path d=\"M126.713 90.023c.858.985 1.287 2.134 1.287 3.447v29.553c0 1.423-.429 2.6-1.287 3.53-.858.93-1.907 1.395-3.146 1.395H97.824c-1.145 0-2.146-.465-3.004-1.395-.858-.93-1.287-2.107-1.287-3.53V93.47c0-.875.19-1.696.572-2.462.382-.766.906-1.368 1.573-1.806a3.84 3.84 0 0 1 2.146-.657h9.725V69.007a3.84 3.84 0 0 0-.43-1.806 3.569 3.569 0 0 0-1.143-1.313 2.714 2.714 0 0 0-1.573-.492h-36.47v23.149h9.725c1.144 0 2.145.492 3.004 1.478.858.985 1.287 2.134 1.287 3.447v29.553c0 .876-.191 1.696-.573 2.463-.38.766-.905 1.368-1.573 1.806a3.84 3.84 0 0 1-2.145.656H51.915a3.84 3.84 0 0 1-2.145-.656c-.668-.438-1.216-1.04-1.645-1.806a4.96 4.96 0 0 1-.644-2.463V93.47c0-1.313.43-2.462 1.288-3.447.858-.986 1.907-1.478 3.146-1.478h9.582v-23.15h-37.9c-.953 0-1.74.356-2.359 1.068-.62.711-.93 1.56-.93 2.544v19.538h9.726c1.239 0 2.264.492 3.074 1.478.81.985 1.216 2.134 1.216 3.447v29.553c0 1.423-.405 2.6-1.216 3.53-.81.93-1.835 1.395-3.074 1.395H4.29c-.476 0-.93-.082-1.358-.246a4.1 4.1 0 0 1-1.144-.657 4.658 4.658 0 0 1-.93-1.067 5.186 5.186 0 0 1-.643-1.395 5.566 5.566 0 0 1-.215-1.56V93.47c0-.437.048-.875.143-1.313a3.95 3.95 0 0 1 .429-1.15c.19-.328.429-.656.715-.984.286-.329.572-.602.858-.821.286-.22.62-.383 1.001-.493.382-.11.763-.164 1.144-.164h9.726V61.619c0-.985.31-1.833.93-2.544.619-.712 1.358-1.068 2.216-1.068h44.335V39.62h-9.582c-1.24 0-2.288-.492-3.146-1.477a5.09 5.09 0 0 1-1.287-3.448V5.14c0-1.423.429-2.627 1.287-3.612.858-.985 1.907-1.477 3.146-1.477h25.743c.763 0 1.478.246 2.145.739a5.17 5.17 0 0 1 1.573 1.888c.382.766.573 1.587.573 2.462v29.553c0 1.313-.43 2.463-1.287 3.448-.859.985-1.86 1.477-3.004 1.477h-9.725v18.389h42.762c.954 0 1.74.355 2.36 1.067.62.711.93 1.56.93 2.545v26.925h9.582c1.239 0 2.288.492 3.146 1.478z\" /></symbol>'});o.a.add(c);t[\"default\"]=c},\"9f2b\":function(e,t,n){\"use strict\";var a=n(\"5bb9\"),i=n.n(a);i.a},a18c:function(e,t,n){\"use strict\";var a,i,r=n(\"2b0e\"),o=n(\"8c4f\"),c=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n(\"div\",{staticClass:\"app-wrapper\",class:e.classObj},[\"mobile\"===e.device&&e.sidebar.opened?n(\"div\",{staticClass:\"drawer-bg\",on:{click:e.handleClickOutside}}):e._e(),e._v(\" \"),n(\"sidebar\",{staticClass:\"sidebar-container\"}),e._v(\" \"),n(\"div\",{staticClass:\"main-container\"},[n(\"div\",{class:{\"fixed-header\":e.fixedHeader}},[n(\"navbar\")],1),e._v(\" \"),n(\"app-main\")],1)],1)},s=[],u=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n(\"div\",{staticClass:\"navbar\"},[n(\"hamburger\",{staticClass:\"hamburger-container\",attrs:{\"is-active\":e.sidebar.opened},on:{toggleClick:e.toggleSideBar}}),e._v(\" \"),n(\"breadcrumb\",{staticClass:\"breadcrumb-container\"}),e._v(\" \"),n(\"div\",{staticClass:\"right-menu\"},[n(\"el-dropdown\",{staticClass:\"avatar-container\",attrs:{trigger:\"click\"}},[n(\"div\",{staticClass:\"avatar-wrapper\"},[n(\"img\",{staticClass:\"user-avatar\",attrs:{src:e.avat+\"?imageView2/1/w/80/h/80\"}}),e._v(\" \"),n(\"i\",{staticClass:\"el-icon-caret-bottom\"})]),e._v(\" \"),n(\"el-dropdown-menu\",{staticClass:\"user-dropdown\",attrs:{slot:\"dropdown\"},slot:\"dropdown\"},[n(\"router-link\",{attrs:{to:\"/\"}},[n(\"el-dropdown-item\",[e._v(\"\\n            主页\\n          \")])],1),e._v(\" \"),n(\"router-link\",{attrs:{to:\"/sys/user\"}},[n(\"el-dropdown-item\",[e._v(\"账号管理\")])],1),e._v(\" \"),n(\"el-dropdown-item\",{attrs:{divided:\"\"}},[n(\"span\",{staticStyle:{display:\"block\"},on:{click:e.logout}},[e._v(\"退出\")])])],1)],1)],1)],1)},l=[],d=(n(\"96cf\"),n(\"3b8d\")),h=n(\"db72\"),f=n(\"2f62\"),m=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n(\"el-breadcrumb\",{staticClass:\"app-breadcrumb\",attrs:{separator:\"/\"}},[n(\"transition-group\",{attrs:{name:\"breadcrumb\"}},e._l(e.levelList,function(t,a){return n(\"el-breadcrumb-item\",{key:t.path},[\"noRedirect\"===t.redirect||a==e.levelList.length-1?n(\"span\",{staticClass:\"no-redirect\"},[e._v(e._s(t.meta.title))]):n(\"a\",{on:{click:function(n){return n.preventDefault(),e.handleLink(t)}}},[e._v(e._s(t.meta.title))])])}),1)],1)},p=[],v=(n(\"7f7f\"),n(\"bd11\")),b=n.n(v),g={data:function(){return{levelList:null}},watch:{$route:function(){this.getBreadcrumb()}},created:function(){this.getBreadcrumb()},methods:{getBreadcrumb:function(){var e=this.$route.matched.filter(function(e){return e.meta&&e.meta.title}),t=e[0];this.isDashboard(t)||(e=[{path:\"/dashboard\",meta:{title:\"主页\"}}].concat(e)),this.levelList=e.filter(function(e){return e.meta&&e.meta.title&&!1!==e.meta.breadcrumb})},isDashboard:function(e){var t=e&&e.name;return!!t&&t.trim().toLocaleLowerCase()===\"Dashboard\".toLocaleLowerCase()},pathCompile:function(e){var t=this.$route.params,n=b.a.compile(e);return n(t)},handleLink:function(e){var t=e.redirect,n=e.path;t?this.$router.push(t):this.$router.push(this.pathCompile(n))}}},w=g,x=(n(\"1b09\"),n(\"2877\")),k=Object(x[\"a\"])(w,m,p,!1,null,\"c09a31b8\",null),y=k.exports,C=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n(\"div\",{staticStyle:{padding:\"0 15px\"},on:{click:e.toggleClick}},[n(\"svg\",{staticClass:\"hamburger\",class:{\"is-active\":e.isActive},attrs:{viewBox:\"0 0 1024 1024\",xmlns:\"http://www.w3.org/2000/svg\",width:\"64\",height:\"64\"}},[n(\"path\",{attrs:{d:\"M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z\"}})])])},_=[],O={name:\"Hamburger\",props:{isActive:{type:Boolean,default:!1}},methods:{toggleClick:function(){this.$emit(\"toggleClick\")}}},S=O,z=(n(\"186a\"),Object(x[\"a\"])(S,C,_,!1,null,\"49e15297\",null)),E=z.exports,H={components:{Breadcrumb:y,Hamburger:E},data:function(){return{avat:\"./avatar.gif\"}},computed:Object(h[\"a\"])({},Object(f[\"b\"])([\"sidebar\",\"avatar\"])),methods:{toggleSideBar:function(){this.$store.dispatch(\"app/toggleSideBar\")},logout:function(){var e=Object(d[\"a\"])(regeneratorRuntime.mark(function e(){return regeneratorRuntime.wrap(function(e){while(1)switch(e.prev=e.next){case 0:return e.next=2,this.$store.dispatch(\"user/logout\");case 2:this.$router.push(\"/login?redirect=\".concat(this.$route.fullPath));case 3:case\"end\":return e.stop()}},e,this)}));function t(){return e.apply(this,arguments)}return t}()}},M=H,B=(n(\"d5be\"),Object(x[\"a\"])(M,u,l,!1,null,\"3ca66fc8\",null)),T=B.exports,j=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n(\"div\",{class:{\"has-logo\":e.showLogo}},[e.showLogo?n(\"logo\",{attrs:{collapse:e.isCollapse}}):e._e(),e._v(\" \"),n(\"el-scrollbar\",{attrs:{\"wrap-class\":\"scrollbar-wrapper\"}},[n(\"el-menu\",{attrs:{\"default-active\":e.activeMenu,collapse:e.isCollapse,\"background-color\":e.variables.menuBg,\"text-color\":e.variables.menuText,\"unique-opened\":!1,\"active-text-color\":e.variables.menuActiveText,\"collapse-transition\":!1,mode:\"vertical\"}},e._l(e.routes,function(e){return n(\"sidebar-item\",{key:e.path,attrs:{item:e,\"base-path\":e.path}})}),1)],1)],1)},L=[],V=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n(\"div\",{staticClass:\"sidebar-logo-container\",class:{collapse:e.collapse}},[n(\"transition\",{attrs:{name:\"sidebarLogoFade\"}},[e.collapse?n(\"router-link\",{key:\"collapse\",staticClass:\"sidebar-logo-link\",attrs:{to:\"/\"}},[e.logo?n(\"img\",{staticClass:\"sidebar-logo\",attrs:{src:e.logo}}):n(\"h1\",{staticClass:\"sidebar-title\"},[e._v(e._s(e.title)+\" \")])]):n(\"router-link\",{key:\"expand\",staticClass:\"sidebar-logo-link\",attrs:{to:\"/\"}},[e.logo?n(\"img\",{staticClass:\"sidebar-logo\",attrs:{src:e.logo}}):e._e(),e._v(\" \"),n(\"h1\",{staticClass:\"sidebar-title\"},[e._v(e._s(e.title)+\" \")])])],1)],1)},$=[],A={name:\"SidebarLogo\",props:{collapse:{type:Boolean,required:!0}},data:function(){return{title:\"\",logo:\"./logo.png\"}}},I=A,P=(n(\"1660\"),Object(x[\"a\"])(I,V,$,!1,null,\"53202dff\",null)),N=P.exports,D=function(){var e=this,t=e.$createElement,n=e._self._c||t;return e.item.hidden?e._e():n(\"div\",{staticClass:\"menu-wrapper\"},[!e.hasOneShowingChild(e.item.children,e.item)||e.onlyOneChild.children&&!e.onlyOneChild.noShowingChildren||e.item.alwaysShow?n(\"el-submenu\",{ref:\"subMenu\",attrs:{index:e.resolvePath(e.item.path),\"popper-append-to-body\":\"\"}},[n(\"template\",{slot:\"title\"},[e.item.meta?n(\"item\",{attrs:{icon:e.item.meta&&e.item.meta.icon,title:e.item.meta.title}}):e._e()],1),e._v(\" \"),e._l(e.item.children,function(t){return n(\"sidebar-item\",{key:t.path,staticClass:\"nest-menu\",attrs:{\"is-nest\":!0,item:t,\"base-path\":e.resolvePath(t.path)}})})],2):[e.onlyOneChild.meta?n(\"app-link\",{attrs:{to:e.resolvePath(e.onlyOneChild.path)}},[n(\"el-menu-item\",{class:{\"submenu-title-noDropdown\":!e.isNest},attrs:{index:e.resolvePath(e.onlyOneChild.path)}},[n(\"item\",{attrs:{icon:e.onlyOneChild.meta.icon||e.item.meta&&e.item.meta.icon,title:e.onlyOneChild.meta.title}})],1)],1):e._e()]],2)},q=[],R=n(\"df7c\"),G=n.n(R),F=n(\"61f7\"),K={name:\"MenuItem\",functional:!0,props:{icon:{type:String,default:\"\"},title:{type:String,default:\"\"}},render:function(e,t){var n=t.props,a=n.icon,i=n.title,r=[];return a&&r.push(e(\"svg-icon\",{attrs:{\"icon-class\":a}})),i&&r.push(e(\"span\",{slot:\"title\"},[i])),r}},U=K,J=Object(x[\"a\"])(U,a,i,!1,null,null,null),W=J.exports,X=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n(\"component\",e._b({},\"component\",e.linkProps(e.to),!1),[e._t(\"default\")],2)},Y=[],Q={props:{to:{type:String,required:!0}},methods:{linkProps:function(e){return Object(F[\"a\"])(e)?{is:\"a\",href:e,target:\"_blank\",rel:\"noopener\"}:{is:\"router-link\",to:e}}}},Z=Q,ee=Object(x[\"a\"])(Z,X,Y,!1,null,null,null),te=ee.exports,ne={computed:{device:function(){return this.$store.state.app.device}},mounted:function(){this.fixBugIniOS()},methods:{fixBugIniOS:function(){var e=this,t=this.$refs.subMenu;if(t){var n=t.handleMouseleave;t.handleMouseleave=function(t){\"mobile\"!==e.device&&n(t)}}}}},ae={name:\"SidebarItem\",components:{Item:W,AppLink:te},mixins:[ne],props:{item:{type:Object,required:!0},isNest:{type:Boolean,default:!1},basePath:{type:String,default:\"\"}},data:function(){return this.onlyOneChild=null,{}},methods:{hasOneShowingChild:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],n=arguments.length>1?arguments[1]:void 0,a=t.filter(function(t){return!t.hidden&&(e.onlyOneChild=t,!0)});return 1===a.length||0===a.length&&(this.onlyOneChild=Object(h[\"a\"])({},n,{path:\"\",noShowingChildren:!0}),!0)},resolvePath:function(e){return Object(F[\"a\"])(e)?e:Object(F[\"a\"])(this.basePath)?this.basePath:G.a.resolve(this.basePath,e)}}},ie=ae,re=Object(x[\"a\"])(ie,D,q,!1,null,null,null),oe=re.exports,ce=n(\"cf1e\"),se=n.n(ce),ue={components:{SidebarItem:oe,Logo:N},computed:Object(h[\"a\"])({},Object(f[\"b\"])([\"sidebar\"]),{routes:function(){return this.$router.options.routes},activeMenu:function(){var e=this.$route,t=e.meta,n=e.path;return t.activeMenu?t.activeMenu:n},showLogo:function(){return this.$store.state.settings.sidebarLogo},variables:function(){return se.a},isCollapse:function(){return!this.sidebar.opened}})},le=ue,de=Object(x[\"a\"])(le,j,L,!1,null,null,null),he=de.exports,fe=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n(\"section\",{staticClass:\"app-main\"},[n(\"transition\",{attrs:{name:\"fade-transform\",mode:\"out-in\"}},[n(\"router-view\",{key:e.key})],1)],1)},me=[],pe={name:\"AppMain\",computed:{key:function(){return this.$route.path}}},ve=pe,be=(n(\"e4de\"),n(\"028b\"),Object(x[\"a\"])(ve,fe,me,!1,null,\"64cf4d83\",null)),ge=be.exports,we=n(\"4360\"),xe=document,ke=xe.body,ye=992,Ce={watch:{$route:function(e){\"mobile\"===this.device&&this.sidebar.opened&&we[\"a\"].dispatch(\"app/closeSideBar\",{withoutAnimation:!1})}},beforeMount:function(){window.addEventListener(\"resize\",this.$_resizeHandler)},beforeDestroy:function(){window.removeEventListener(\"resize\",this.$_resizeHandler)},mounted:function(){var e=this.$_isMobile();e&&(we[\"a\"].dispatch(\"app/toggleDevice\",\"mobile\"),we[\"a\"].dispatch(\"app/closeSideBar\",{withoutAnimation:!0}))},methods:{$_isMobile:function(){var e=ke.getBoundingClientRect();return e.width-1<ye},$_resizeHandler:function(){if(!document.hidden){var e=this.$_isMobile();we[\"a\"].dispatch(\"app/toggleDevice\",e?\"mobile\":\"desktop\"),e&&we[\"a\"].dispatch(\"app/closeSideBar\",{withoutAnimation:!0})}}}},_e={name:\"Layout\",components:{Navbar:T,Sidebar:he,AppMain:ge},mixins:[Ce],computed:{sidebar:function(){return this.$store.state.app.sidebar},device:function(){return this.$store.state.app.device},fixedHeader:function(){return this.$store.state.settings.fixedHeader},classObj:function(){return{hideSidebar:!this.sidebar.opened,openSidebar:this.sidebar.opened,withoutAnimation:this.sidebar.withoutAnimation,mobile:\"mobile\"===this.device}}},methods:{handleClickOutside:function(){this.$store.dispatch(\"app/closeSideBar\",{withoutAnimation:!1})}}},Oe=_e,Se=(n(\"9f2b\"),Object(x[\"a\"])(Oe,c,s,!1,null,\"4f739cf0\",null)),ze=Se.exports;n.d(t,\"b\",function(){return Be}),r[\"default\"].use(o[\"a\"]);var Ee=[{path:\"/login\",component:function(){return n.e(\"chunk-101fc062\").then(n.bind(null,\"9ed6\"))},hidden:!0},{path:\"/404\",component:function(){return n.e(\"chunk-49959c8b\").then(n.bind(null,\"8cdb\"))},hidden:!0},{path:\"/\",component:ze,redirect:\"/dashboard\",children:[{path:\"dashboard\",name:\"主页\",component:function(){return n.e(\"chunk-37c49cbf\").then(n.bind(null,\"9406\"))},meta:{title:\"主页\",icon:\"dashboard\"}}],hidden:!0},{path:\"/sys\",component:ze,redirect:\"/user\",children:[{path:\"user\",name:\"用户信息\",component:function(){return n.e(\"chunk-69386cf0\").then(n.bind(null,\"9fb7\"))},meta:{title:\"用户信息\"}}],hidden:!0},{path:\"/canalServer\",component:ze,redirect:\"/canalServer/nodeServers\",name:\"Canal Server\",meta:{title:\"Canal Server\",icon:\"example\"},children:[{path:\"canalClusters\",name:\"Canal 集群管理\",component:function(){return n.e(\"chunk-55380ff2\").then(n.bind(null,\"e509\"))},meta:{title:\"集群管理\",icon:\"tree\"}},{path:\"nodeServers\",name:\"Server 状态\",component:function(){return n.e(\"chunk-da289616\").then(n.bind(null,\"9f66\"))},meta:{title:\"Server 管理\",icon:\"form\"}},{path:\"nodeServer/config\",name:\"Server 配置\",component:function(){return Promise.all([n.e(\"chunk-0dca2f22\"),n.e(\"chunk-5afa45f5\")]).then(n.bind(null,\"aa99\"))},meta:{title:\"Server 配置\"},hidden:!0},{path:\"canalInstances\",name:\"Instance 管理\",component:function(){return n.e(\"chunk-2b9b6c5c\").then(n.bind(null,\"1c98\"))},meta:{title:\"Instance 管理\",icon:\"nested\"}},{path:\"canalInstance/add\",name:\"新建Instance配置\",component:function(){return Promise.all([n.e(\"chunk-0dca2f22\"),n.e(\"chunk-5b373aad\")]).then(n.bind(null,\"1248\"))},meta:{title:\"新建Instance配置\"},hidden:!0},{path:\"canalInstance/modify\",name:\"修改Instance配置\",component:function(){return Promise.all([n.e(\"chunk-0dca2f22\"),n.e(\"chunk-bd1d44ee\")]).then(n.bind(null,\"b0a2\"))},meta:{title:\"修改Instance配置\"},hidden:!0},{path:\"nodeServer/log\",name:\"Server 日志\",component:function(){return n.e(\"chunk-4f09fed2\").then(n.bind(null,\"caf8\"))},meta:{title:\"Server 日志\"},hidden:!0},{path:\"canalInstance/log\",name:\"Instance 日志\",component:function(){return n.e(\"chunk-7ec889b7\").then(n.bind(null,\"7f84\"))},meta:{title:\"Instance 日志\"},hidden:!0}]},{path:\"*\",redirect:\"/404\",hidden:!0}],He=function(){return new o[\"a\"]({scrollBehavior:function(){return{y:0}},routes:Ee})},Me=He();function Be(){var e=He();Me.matcher=e.matcher}t[\"a\"]=Me},a217:function(e,t,n){},a424:function(e,t,n){},b20f:function(e,t,n){e.exports={menuText:\"#bfcbd9\",menuActiveText:\"#409EFF\",subMenuActiveText:\"#f4f4f5\",menuBg:\"#304156\",menuHover:\"#263445\",subMenuBg:\"#1f2d3d\",subMenuHover:\"#001528\",sideBarWidth:\"210px\"}},b3b5:function(e,t,n){\"use strict\";n.r(t);var a=n(\"e017\"),i=n.n(a),r=n(\"21a1\"),o=n.n(r),c=new i.a({id:\"icon-user\",use:\"icon-user-usage\",viewBox:\"0 0 130 130\",content:'<symbol xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 130 130\" id=\"icon-user\"><path d=\"M63.444 64.996c20.633 0 37.359-14.308 37.359-31.953 0-17.649-16.726-31.952-37.359-31.952-20.631 0-37.36 14.303-37.358 31.952 0 17.645 16.727 31.953 37.359 31.953zM80.57 75.65H49.434c-26.652 0-48.26 18.477-48.26 41.27v2.664c0 9.316 21.608 9.325 48.26 9.325H80.57c26.649 0 48.256-.344 48.256-9.325v-2.663c0-22.794-21.605-41.271-48.256-41.271z\" stroke=\"#979797\" /></symbol>'});o.a.add(c);t[\"default\"]=c},b775:function(e,t,n){\"use strict\";var a=n(\"bc3a\"),i=n.n(a),r=n(\"5c96\"),o=n(\"4360\"),c=n(\"5f87\"),s=i.a.create({baseURL:\"/api/v1\",timeout:6e4});s.interceptors.request.use(function(e){return o[\"a\"].getters.token&&(e.headers[\"X-Token\"]=Object(c[\"a\"])()),e},function(e){return console.log(e),Promise.reject(e)}),s.interceptors.response.use(function(e){var t=e.data;return 2e4!==t.code?(Object(r[\"Message\"])({message:t.message||\"Error\",type:\"error\",duration:5e3}),50008!==t.code&&50012!==t.code&&50014!==t.code||r[\"MessageBox\"].confirm(\"You have been logged out, you can cancel to stay on this page, or log in again\",\"Confirm logout\",{confirmButtonText:\"Re-Login\",cancelButtonText:\"Cancel\",type:\"warning\"}).then(function(){o[\"a\"].dispatch(\"user/resetToken\").then(function(){location.reload()})}),Promise.reject(new Error(t.message||\"Error\"))):t},function(e){return console.log(\"err\"+e),Object(r[\"Message\"])({message:e.message,type:\"error\",duration:5e3}),Promise.reject(e)}),t[\"a\"]=s},c24f:function(e,t,n){\"use strict\";n.d(t,\"b\",function(){return i}),n.d(t,\"a\",function(){return r}),n.d(t,\"c\",function(){return o}),n.d(t,\"d\",function(){return c});var a=n(\"b775\");function i(e){return Object(a[\"a\"])({url:\"/user/login\",method:\"post\",data:e})}function r(e){return Object(a[\"a\"])({url:\"/user/info\",method:\"get\",params:{token:e}})}function o(){return Object(a[\"a\"])({url:\"/user/logout\",method:\"post\"})}function c(e){return Object(a[\"a\"])({url:\"/user\",method:\"put\",data:e})}},cf1e:function(e,t,n){e.exports={menuText:\"#bfcbd9\",menuActiveText:\"#409EFF\",subMenuActiveText:\"#f4f4f5\",menuBg:\"#304156\",menuHover:\"#263445\",subMenuBg:\"#1f2d3d\",subMenuHover:\"#001528\",sideBarWidth:\"210px\"}},d5be:function(e,t,n){\"use strict\";var a=n(\"a424\"),i=n.n(a);i.a},d7ec:function(e,t,n){\"use strict\";n.r(t);var a=n(\"e017\"),i=n.n(a),r=n(\"21a1\"),o=n.n(r),c=new i.a({id:\"icon-eye-open\",use:\"icon-eye-open-usage\",viewBox:\"0 0 1024 1024\",content:'<symbol class=\"icon\" viewBox=\"0 0 1024 1024\" xmlns=\"http://www.w3.org/2000/svg\" id=\"icon-eye-open\"><defs><style></style></defs><path d=\"M512 128q69.675 0 135.51 21.163t115.498 54.997 93.483 74.837 73.685 82.006 51.67 74.837 32.17 54.827L1024 512q-2.347 4.992-6.315 13.483T998.87 560.17t-31.658 51.669-44.331 59.99-56.832 64.34-69.504 60.16-82.347 51.5-94.848 34.687T512 896q-69.675 0-135.51-21.163t-115.498-54.826-93.483-74.326-73.685-81.493-51.67-74.496-32.17-54.997L0 513.707q2.347-4.992 6.315-13.483t18.816-34.816 31.658-51.84 44.331-60.33 56.832-64.683 69.504-60.331 82.347-51.84 94.848-34.816T512 128.085zm0 85.333q-46.677 0-91.648 12.331t-81.152 31.83-70.656 47.146-59.648 54.485-48.853 57.686-37.675 52.821-26.325 43.99q12.33 21.674 26.325 43.52t37.675 52.351 48.853 57.003 59.648 53.845T339.2 767.02t81.152 31.488T512 810.667t91.648-12.331 81.152-31.659 70.656-46.848 59.648-54.186 48.853-57.344 37.675-52.651T927.957 512q-12.33-21.675-26.325-43.648t-37.675-52.65-48.853-57.345-59.648-54.186-70.656-46.848-81.152-31.659T512 213.334zm0 128q70.656 0 120.661 50.006T682.667 512 632.66 632.661 512 682.667 391.339 632.66 341.333 512t50.006-120.661T512 341.333zm0 85.334q-35.328 0-60.33 25.002T426.666 512t25.002 60.33T512 597.334t60.33-25.002T597.334 512t-25.002-60.33T512 426.666z\" /></symbol>'});o.a.add(c);t[\"default\"]=c},dc52:function(e,t,n){},dcf8:function(e,t,n){\"use strict\";n.r(t);var a=n(\"e017\"),i=n.n(a),r=n(\"21a1\"),o=n.n(r),c=new i.a({id:\"icon-nested\",use:\"icon-nested-usage\",viewBox:\"0 0 128 128\",content:'<symbol xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 128 128\" id=\"icon-nested\"><path d=\"M.002 9.2c0 5.044 3.58 9.133 7.998 9.133 4.417 0 7.997-4.089 7.997-9.133 0-5.043-3.58-9.132-7.997-9.132S.002 4.157.002 9.2zM31.997.066h95.981V18.33H31.997V.066zm0 45.669c0 5.044 3.58 9.132 7.998 9.132 4.417 0 7.997-4.088 7.997-9.132 0-3.263-1.524-6.278-3.998-7.91-2.475-1.63-5.524-1.63-7.998 0-2.475 1.632-4 4.647-4 7.91zM63.992 36.6h63.986v18.265H63.992V36.6zm-31.995 82.2c0 5.043 3.58 9.132 7.998 9.132 4.417 0 7.997-4.089 7.997-9.132 0-5.044-3.58-9.133-7.997-9.133s-7.998 4.089-7.998 9.133zm31.995-9.131h63.986v18.265H63.992V109.67zm0-27.404c0 5.044 3.58 9.133 7.998 9.133 4.417 0 7.997-4.089 7.997-9.133 0-3.263-1.524-6.277-3.998-7.909-2.475-1.631-5.524-1.631-7.998 0-2.475 1.632-4 4.646-4 7.91zm31.995-9.13h31.991V91.4H95.987V73.135z\" /></symbol>'});o.a.add(c);t[\"default\"]=c},e4de:function(e,t,n){\"use strict\";var a=n(\"8902\"),i=n.n(a);i.a},eb1b:function(e,t,n){\"use strict\";n.r(t);var a=n(\"e017\"),i=n.n(a),r=n(\"21a1\"),o=n.n(r),c=new i.a({id:\"icon-form\",use:\"icon-form-usage\",viewBox:\"0 0 128 128\",content:'<symbol xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 128 128\" id=\"icon-form\"><path d=\"M84.068 23.784c-1.02 0-1.877-.32-2.572-.96a8.588 8.588 0 0 1-1.738-2.237 11.524 11.524 0 0 1-1.042-2.621c-.232-.895-.348-1.641-.348-2.238V0h.278c.834 0 1.622.085 2.363.256.742.17 1.645.575 2.711 1.214 1.066.64 2.363 1.535 3.892 2.686 1.53 1.15 3.453 2.664 5.77 4.54 2.502 2.045 4.494 3.771 5.977 5.178 1.483 1.406 2.618 2.6 3.406 3.58.787.98 1.274 1.812 1.46 2.494.185.682.277 1.278.277 1.79v2.046H84.068zM127.3 84.01c.278.682.464 1.535.556 2.558.093 1.023-.37 2.003-1.39 2.94-.463.427-.88.832-1.25 1.215-.372.384-.696.704-.974.96a6.69 6.69 0 0 1-.973.767l-11.816-10.741a44.331 44.331 0 0 0 1.877-1.535 31.028 31.028 0 0 1 1.737-1.406c1.112-.938 2.317-1.343 3.615-1.215 1.297.128 2.363.405 3.197.83.927.427 1.923 1.173 2.989 2.239 1.065 1.065 1.876 2.195 2.432 3.388zM78.23 95.902c2.038 0 3.752-.511 5.143-1.534l-26.969 25.83H18.037c-1.761 0-3.684-.47-5.77-1.407a24.549 24.549 0 0 1-5.838-3.709 21.373 21.373 0 0 1-4.518-5.306c-1.204-2.003-1.807-4.07-1.807-6.202V16.495c0-1.79.44-3.665 1.32-5.626A18.41 18.41 0 0 1 5.04 5.562a21.798 21.798 0 0 1 5.213-3.964C12.198.533 14.237 0 16.37 0h53.24v15.984c0 1.62.278 3.367.834 5.242a16.704 16.704 0 0 0 2.572 5.179c1.159 1.577 2.665 2.898 4.518 3.964 1.853 1.066 4.078 1.598 6.673 1.598h20.295v42.325L85.458 92.45c1.02-1.364 1.529-2.856 1.529-4.476 0-2.216-.857-4.113-2.572-5.69-1.714-1.577-3.776-2.366-6.186-2.366H26.1c-2.409 0-4.448.789-6.116 2.366-1.668 1.577-2.502 3.474-2.502 5.69 0 2.217.834 4.092 2.502 5.626 1.668 1.535 3.707 2.302 6.117 2.302h52.13zM26.1 47.951c-2.41 0-4.449.789-6.117 2.366-1.668 1.577-2.502 3.473-2.502 5.69 0 2.216.834 4.092 2.502 5.626 1.668 1.534 3.707 2.302 6.117 2.302h52.13c2.409 0 4.47-.768 6.185-2.302 1.715-1.534 2.572-3.41 2.572-5.626 0-2.217-.857-4.113-2.572-5.69-1.714-1.577-3.776-2.366-6.186-2.366H26.1zm52.407 64.063l1.807-1.663 3.476-3.196a479.75 479.75 0 0 0 4.587-4.284 500.757 500.757 0 0 1 5.004-4.667c3.985-3.666 8.48-7.758 13.485-12.276l11.677 10.741-13.485 12.404-5.004 4.603-4.587 4.22a179.46 179.46 0 0 0-3.267 3.068c-.88.853-1.367 1.322-1.46 1.407-.463.341-.973.703-1.529 1.087-.556.383-1.112.703-1.668.959-.556.256-1.413.575-2.572.959a83.5 83.5 0 0 1-3.545 1.087 72.2 72.2 0 0 1-3.475.895c-1.112.256-1.946.426-2.502.511-1.112.17-1.854.043-2.224-.383-.371-.426-.464-1.151-.278-2.174.092-.511.278-1.279.556-2.302.278-1.023.602-2.067.973-3.132l1.042-3.005c.325-.938.58-1.577.765-1.918a10.157 10.157 0 0 1 2.224-2.941z\" /></symbol>'});o.a.add(c);t[\"default\"]=c},f782:function(e,t,n){\"use strict\";n.r(t);var a=n(\"e017\"),i=n.n(a),r=n(\"21a1\"),o=n.n(r),c=new i.a({id:\"icon-dashboard\",use:\"icon-dashboard-usage\",viewBox:\"0 0 128 100\",content:'<symbol xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 128 100\" id=\"icon-dashboard\"><path d=\"M27.429 63.638c0-2.508-.893-4.65-2.679-6.424-1.786-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.465 2.662-1.785 1.774-2.678 3.916-2.678 6.424 0 2.508.893 4.65 2.678 6.424 1.786 1.775 3.94 2.662 6.465 2.662 2.524 0 4.678-.887 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zm13.714-31.801c0-2.508-.893-4.65-2.679-6.424-1.785-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zM71.714 65.98l7.215-27.116c.285-1.23.107-2.378-.536-3.443-.643-1.064-1.56-1.762-2.75-2.094-1.19-.33-2.333-.177-3.429.462-1.095.639-1.81 1.573-2.143 2.804l-7.214 27.116c-2.857.237-5.405 1.266-7.643 3.088-2.238 1.822-3.738 4.152-4.5 6.992-.952 3.644-.476 7.098 1.429 10.364 1.905 3.265 4.69 5.37 8.357 6.317 3.667.947 7.143.474 10.429-1.42 3.285-1.892 5.404-4.66 6.357-8.305.762-2.84.619-5.607-.429-8.305-1.047-2.697-2.762-4.85-5.143-6.46zm47.143-2.342c0-2.508-.893-4.65-2.678-6.424-1.786-1.775-3.94-2.662-6.465-2.662-2.524 0-4.678.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.786 1.775 3.94 2.662 6.464 2.662 2.524 0 4.679-.887 6.465-2.662 1.785-1.775 2.678-3.916 2.678-6.424zm-45.714-45.43c0-2.509-.893-4.65-2.679-6.425C68.68 10.01 66.524 9.122 64 9.122c-2.524 0-4.679.887-6.464 2.661-1.786 1.775-2.679 3.916-2.679 6.425 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zm32 13.629c0-2.508-.893-4.65-2.679-6.424-1.785-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zM128 63.638c0 12.351-3.357 23.78-10.071 34.286-.905 1.372-2.19 2.058-3.858 2.058H13.93c-1.667 0-2.953-.686-3.858-2.058C3.357 87.465 0 76.037 0 63.638c0-8.613 1.69-16.847 5.071-24.703C8.452 31.08 13 24.312 18.714 18.634c5.715-5.68 12.524-10.199 20.429-13.559C47.048 1.715 55.333.035 64 .035c8.667 0 16.952 1.68 24.857 5.04 7.905 3.36 14.714 7.88 20.429 13.559 5.714 5.678 10.262 12.446 13.643 20.301 3.38 7.856 5.071 16.09 5.071 24.703z\" /></symbol>'});o.a.add(c);t[\"default\"]=c},ff7f:function(e,t,n){}},[[0,\"runtime\",\"chunk-elementUI\",\"chunk-libs\"]]]);"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/js/app.eee35d99.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[\"app\"],{0:function(e,t,n){e.exports=n(\"56d7\")},\"028b\":function(e,t,n){\"use strict\";var a=n(\"a217\"),i=n.n(a);i.a},1660:function(e,t,n){\"use strict\";var a=n(\"ff7f\"),i=n.n(a);i.a},\"186a\":function(e,t,n){\"use strict\";var a=n(\"dc52\"),i=n.n(a);i.a},\"18f0\":function(e,t,n){\"use strict\";n.r(t);var a=n(\"e017\"),i=n.n(a),r=n(\"21a1\"),o=n.n(r),c=new i.a({id:\"icon-link\",use:\"icon-link-usage\",viewBox:\"0 0 128 128\",content:'<symbol xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 128 128\" id=\"icon-link\"><path d=\"M115.625 127.937H.063V12.375h57.781v12.374H12.438v90.813h90.813V70.156h12.374z\" /><path d=\"M116.426 2.821l8.753 8.753-56.734 56.734-8.753-8.745z\" /><path d=\"M127.893 37.982h-12.375V12.375H88.706V0h39.187z\" /></symbol>'});o.a.add(c);t[\"default\"]=c},\"1b09\":function(e,t,n){\"use strict\";var a=n(\"4ed7\"),i=n.n(a);i.a},2021:function(e,t,n){},\"2a3d\":function(e,t,n){\"use strict\";n.r(t);var a=n(\"e017\"),i=n.n(a),r=n(\"21a1\"),o=n.n(r),c=new i.a({id:\"icon-password\",use:\"icon-password-usage\",viewBox:\"0 0 128 128\",content:'<symbol xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 128 128\" id=\"icon-password\"><path d=\"M108.8 44.322H89.6v-5.36c0-9.04-3.308-24.163-25.6-24.163-23.145 0-25.6 16.881-25.6 24.162v5.361H19.2v-5.36C19.2 15.281 36.798 0 64 0c27.202 0 44.8 15.281 44.8 38.961v5.361zm-32 39.356c0-5.44-5.763-9.832-12.8-9.832-7.037 0-12.8 4.392-12.8 9.832 0 3.682 2.567 6.808 6.407 8.477v11.205c0 2.718 2.875 4.962 6.4 4.962 3.524 0 6.4-2.244 6.4-4.962V92.155c3.833-1.669 6.393-4.795 6.393-8.477zM128 64v49.201c0 8.158-8.645 14.799-19.2 14.799H19.2C8.651 128 0 121.359 0 113.201V64c0-8.153 8.645-14.799 19.2-14.799h89.6c10.555 0 19.2 6.646 19.2 14.799z\" /></symbol>'});o.a.add(c);t[\"default\"]=c},\"30c3\":function(e,t,n){\"use strict\";n.r(t);var a=n(\"e017\"),i=n.n(a),r=n(\"21a1\"),o=n.n(r),c=new i.a({id:\"icon-example\",use:\"icon-example-usage\",viewBox:\"0 0 128 128\",content:'<symbol xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 128 128\" id=\"icon-example\"><path d=\"M96.258 57.462h31.421C124.794 27.323 100.426 2.956 70.287.07v31.422a32.856 32.856 0 0 1 25.971 25.97zm-38.796-25.97V.07C27.323 2.956 2.956 27.323.07 57.462h31.422a32.856 32.856 0 0 1 25.97-25.97zm12.825 64.766v31.421c30.46-2.885 54.507-27.253 57.713-57.712H96.579c-2.886 13.466-13.146 23.726-26.292 26.291zM31.492 70.287H.07c2.886 30.46 27.253 54.507 57.713 57.713V96.579c-13.466-2.886-23.726-13.146-26.291-26.292z\" /></symbol>'});o.a.add(c);t[\"default\"]=c},4360:function(e,t,n){\"use strict\";var a=n(\"2b0e\"),i=n(\"2f62\"),r=(n(\"7f7f\"),{sidebar:function(e){return e.app.sidebar},device:function(e){return e.app.device},token:function(e){return e.user.token},avatar:function(e){return e.user.avatar},name:function(e){return e.user.name}}),o=r,c=n(\"a78e\"),s=n.n(c),u={sidebar:{opened:!s.a.get(\"sidebarStatus\")||!!+s.a.get(\"sidebarStatus\"),withoutAnimation:!1},device:\"desktop\"},l={TOGGLE_SIDEBAR:function(e){e.sidebar.opened=!e.sidebar.opened,e.sidebar.withoutAnimation=!1,e.sidebar.opened?s.a.set(\"sidebarStatus\",1):s.a.set(\"sidebarStatus\",0)},CLOSE_SIDEBAR:function(e,t){s.a.set(\"sidebarStatus\",0),e.sidebar.opened=!1,e.sidebar.withoutAnimation=t},TOGGLE_DEVICE:function(e,t){e.device=t}},d={toggleSideBar:function(e){var t=e.commit;t(\"TOGGLE_SIDEBAR\")},closeSideBar:function(e,t){var n=e.commit,a=t.withoutAnimation;n(\"CLOSE_SIDEBAR\",a)},toggleDevice:function(e,t){var n=e.commit;n(\"TOGGLE_DEVICE\",t)}},h={namespaced:!0,state:u,mutations:l,actions:d},f=n(\"83d6\"),m=n.n(f),p=m.a.showSettings,v=m.a.fixedHeader,b=m.a.sidebarLogo,g={showSettings:p,fixedHeader:v,sidebarLogo:b},w={CHANGE_SETTING:function(e,t){var n=t.key,a=t.value;e.hasOwnProperty(n)&&(e[n]=a)}},x={changeSetting:function(e,t){var n=e.commit;n(\"CHANGE_SETTING\",t)}},k={namespaced:!0,state:g,mutations:w,actions:x},y=n(\"c24f\"),C=n(\"5f87\"),_=n(\"a18c\"),O={token:Object(C[\"a\"])(),name:\"\",avatar:\"\"},S={SET_TOKEN:function(e,t){e.token=t},SET_NAME:function(e,t){e.name=t},SET_AVATAR:function(e,t){e.avatar=t}},z={login:function(e,t){var n=e.commit,a=t.username,i=t.password;return new Promise(function(e,t){Object(y[\"b\"])({username:a.trim(),password:i}).then(function(t){var a=t.data;n(\"SET_TOKEN\",a.token),Object(C[\"c\"])(a.token),e()}).catch(function(e){t(e)})})},getInfo:function(e){var t=e.commit,n=e.state;return new Promise(function(e,a){Object(y[\"a\"])(n.token).then(function(n){var i=n.data;i||a(\"Verification failed, please Login again.\");var r=i.name,o=i.avatar;t(\"SET_NAME\",r),t(\"SET_AVATAR\",o),e(i)}).catch(function(e){a(e)})})},logout:function(e){var t=e.commit,n=e.state;return new Promise(function(e,a){Object(y[\"c\"])(n.token).then(function(){t(\"SET_TOKEN\",\"\"),Object(C[\"b\"])(),Object(_[\"b\"])(),e()}).catch(function(e){a(e)})})},resetToken:function(e){var t=e.commit;return new Promise(function(e){t(\"SET_TOKEN\",\"\"),Object(C[\"b\"])(),e()})}},E={namespaced:!0,state:O,mutations:S,actions:z};a[\"default\"].use(i[\"a\"]);var H=new i[\"a\"].Store({modules:{app:h,settings:k,user:E},getters:o});t[\"a\"]=H},\"47f1\":function(e,t,n){\"use strict\";n.r(t);var a=n(\"e017\"),i=n.n(a),r=n(\"21a1\"),o=n.n(r),c=new i.a({id:\"icon-table\",use:\"icon-table-usage\",viewBox:\"0 0 128 128\",content:'<symbol xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 128 128\" id=\"icon-table\"><path d=\"M.006.064h127.988v31.104H.006V.064zm0 38.016h38.396v41.472H.006V38.08zm0 48.384h38.396v41.472H.006V86.464zM44.802 38.08h38.396v41.472H44.802V38.08zm0 48.384h38.396v41.472H44.802V86.464zM89.598 38.08h38.396v41.472H89.598zm0 48.384h38.396v41.472H89.598z\" /><path d=\"M.006.064h127.988v31.104H.006V.064zm0 38.016h38.396v41.472H.006V38.08zm0 48.384h38.396v41.472H.006V86.464zM44.802 38.08h38.396v41.472H44.802V38.08zm0 48.384h38.396v41.472H44.802V86.464zM89.598 38.08h38.396v41.472H89.598zm0 48.384h38.396v41.472H89.598z\" /></symbol>'});o.a.add(c);t[\"default\"]=c},\"4df5\":function(e,t,n){\"use strict\";n.r(t);var a=n(\"e017\"),i=n.n(a),r=n(\"21a1\"),o=n.n(r),c=new i.a({id:\"icon-eye\",use:\"icon-eye-usage\",viewBox:\"0 0 128 64\",content:'<symbol xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 128 64\" id=\"icon-eye\"><path d=\"M127.072 7.994c1.37-2.208.914-5.152-.914-6.87-2.056-1.717-4.797-1.226-6.396.982-.229.245-25.586 32.382-55.74 32.382-29.24 0-55.74-32.382-55.968-32.627-1.6-1.963-4.57-2.208-6.397-.49C-.17 3.086-.399 6.275 1.2 8.238c.457.736 5.94 7.36 14.62 14.72L4.17 35.96c-1.828 1.963-1.6 5.152.228 6.87.457.98 1.6 1.471 2.742 1.471s2.284-.49 3.198-1.472l12.564-13.983c5.94 4.416 13.021 8.587 20.788 11.53l-4.797 17.418c-.685 2.699.686 5.397 3.198 6.133h1.37c2.057 0 3.884-1.472 4.341-3.68L52.6 42.83c3.655.736 7.538 1.227 11.422 1.227 3.883 0 7.767-.49 11.422-1.227l4.797 17.173c.457 2.208 2.513 3.68 4.34 3.68.457 0 .914 0 1.143-.246 2.513-.736 3.883-3.434 3.198-6.133l-4.797-17.172c7.767-2.944 14.848-7.114 20.788-11.53l12.336 13.738c.913.981 2.056 1.472 3.198 1.472s2.284-.49 3.198-1.472c1.828-1.963 1.828-4.906.228-6.87l-11.65-13.001c9.366-7.36 14.849-14.474 14.849-14.474z\" /></symbol>'});o.a.add(c);t[\"default\"]=c},\"4ed7\":function(e,t,n){},\"51ff\":function(e,t,n){var a={\"./dashboard.svg\":\"f782\",\"./example.svg\":\"30c3\",\"./eye-open.svg\":\"d7ec\",\"./eye.svg\":\"4df5\",\"./form.svg\":\"eb1b\",\"./link.svg\":\"18f0\",\"./nested.svg\":\"dcf8\",\"./password.svg\":\"2a3d\",\"./table.svg\":\"47f1\",\"./tree.svg\":\"93cd\",\"./user.svg\":\"b3b5\"};function i(e){var t=r(e);return n(t)}function r(e){var t=a[e];if(!(t+1)){var n=new Error(\"Cannot find module '\"+e+\"'\");throw n.code=\"MODULE_NOT_FOUND\",n}return t}i.keys=function(){return Object.keys(a)},i.resolve=r,e.exports=i,i.id=\"51ff\"},\"56d7\":function(e,t,n){\"use strict\";n.r(t);n(\"cadf\"),n(\"551c\"),n(\"f751\"),n(\"097d\");var a=n(\"2b0e\"),i=(n(\"f5df\"),n(\"5c96\")),r=n.n(i),o=(n(\"0fae\"),n(\"b2d6\")),c=n.n(o),s=(n(\"b20f\"),function(){var e=this,t=e.$createElement,n=e._self._c||t;return n(\"div\",{attrs:{id:\"app\"}},[n(\"router-view\")],1)}),u=[],l={name:\"App\"},d=l,h=n(\"2877\"),f=Object(h[\"a\"])(d,s,u,!1,null,null,null),m=f.exports,p=n(\"4360\"),v=n(\"a18c\"),b=(n(\"ac6a\"),function(){var e=this,t=e.$createElement,n=e._self._c||t;return e.isExternal?n(\"div\",e._g({staticClass:\"svg-external-icon svg-icon\",style:e.styleExternalIcon},e.$listeners)):n(\"svg\",e._g({class:e.svgClass,attrs:{\"aria-hidden\":\"true\"}},e.$listeners),[n(\"use\",{attrs:{\"xlink:href\":e.iconName}})])}),g=[],w=n(\"61f7\"),x={name:\"SvgIcon\",props:{iconClass:{type:String,required:!0},className:{type:String,default:\"\"}},computed:{isExternal:function(){return Object(w[\"a\"])(this.iconClass)},iconName:function(){return\"#icon-\".concat(this.iconClass)},svgClass:function(){return this.className?\"svg-icon \"+this.className:\"svg-icon\"},styleExternalIcon:function(){return{mask:\"url(\".concat(this.iconClass,\") no-repeat 50% 50%\"),\"-webkit-mask\":\"url(\".concat(this.iconClass,\") no-repeat 50% 50%\")}}}},k=x,y=(n(\"68fa\"),Object(h[\"a\"])(k,b,g,!1,null,\"f9f7fefc\",null)),C=y.exports;a[\"default\"].component(\"svg-icon\",C);var _=n(\"51ff\"),O=function(e){return e.keys().map(e)};O(_);n(\"7f7f\"),n(\"96cf\");var S=n(\"3b8d\"),z=n(\"323e\"),E=n.n(z),H=(n(\"a5d8\"),n(\"5f87\")),M=n(\"83d6\"),B=n.n(M),T=B.a.title||\"Vue Admin Template\";function j(e){return e?\"\".concat(e,\" - \").concat(T):\"\".concat(T)}E.a.configure({showSpinner:!1});var L=[\"/login\"];v[\"a\"].beforeEach(function(){var e=Object(S[\"a\"])(regeneratorRuntime.mark(function e(t,n,a){var r,o;return regeneratorRuntime.wrap(function(e){while(1)switch(e.prev=e.next){case 0:if(E.a.start(),document.title=j(t.meta.title),r=Object(H[\"a\"])(),!r){e.next=29;break}if(\"/login\"!==t.path){e.next=9;break}a({path:\"/\"}),E.a.done(),e.next=27;break;case 9:if(o=p[\"a\"].getters.name,!o){e.next=14;break}a(),e.next=27;break;case 14:return e.prev=14,e.next=17,p[\"a\"].dispatch(\"user/getInfo\");case 17:a(),e.next=27;break;case 20:return e.prev=20,e.t0=e[\"catch\"](14),e.next=24,p[\"a\"].dispatch(\"user/resetToken\");case 24:i[\"Message\"].error(e.t0||\"Has Error\"),a(\"/login?redirect=\".concat(t.path)),E.a.done();case 27:e.next=30;break;case 29:-1!==L.indexOf(t.path)?a():(a(\"/login?redirect=\".concat(t.path)),E.a.done());case 30:case\"end\":return e.stop()}},e,null,[[14,20]])}));return function(t,n,a){return e.apply(this,arguments)}}()),v[\"a\"].afterEach(function(){E.a.done()}),a[\"default\"].use(r.a,{size:\"small\",locale:c.a}),a[\"default\"].config.productionTip=!1,new a[\"default\"]({el:\"#app\",router:v[\"a\"],store:p[\"a\"],render:function(e){return e(m)}})},\"5bb9\":function(e,t,n){},\"5f87\":function(e,t,n){\"use strict\";n.d(t,\"a\",function(){return o}),n.d(t,\"c\",function(){return c}),n.d(t,\"b\",function(){return s});var a=n(\"a78e\"),i=n.n(a),r=\"canal_admin_token\";function o(){return i.a.get(r)}function c(e){return i.a.set(r,e,{maxAge:0})}function s(){return i.a.remove(r)}},\"61f7\":function(e,t,n){\"use strict\";function a(e){return/^(https?:|mailto:|tel:)/.test(e)}function i(e){var t=[\"admin\",\"editor\"];return t.indexOf(e.trim())>=0}n.d(t,\"a\",function(){return a}),n.d(t,\"b\",function(){return i})},\"68fa\":function(e,t,n){\"use strict\";var a=n(\"2021\"),i=n.n(a);i.a},\"83d6\":function(e,t){e.exports={title:\"Canal Admin\",fixedHeader:!0,sidebarLogo:!0}},8902:function(e,t,n){},\"93cd\":function(e,t,n){\"use strict\";n.r(t);var a=n(\"e017\"),i=n.n(a),r=n(\"21a1\"),o=n.n(r),c=new i.a({id:\"icon-tree\",use:\"icon-tree-usage\",viewBox:\"0 0 128 128\",content:'<symbol xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 128 128\" id=\"icon-tree\"><path d=\"M126.713 90.023c.858.985 1.287 2.134 1.287 3.447v29.553c0 1.423-.429 2.6-1.287 3.53-.858.93-1.907 1.395-3.146 1.395H97.824c-1.145 0-2.146-.465-3.004-1.395-.858-.93-1.287-2.107-1.287-3.53V93.47c0-.875.19-1.696.572-2.462.382-.766.906-1.368 1.573-1.806a3.84 3.84 0 0 1 2.146-.657h9.725V69.007a3.84 3.84 0 0 0-.43-1.806 3.569 3.569 0 0 0-1.143-1.313 2.714 2.714 0 0 0-1.573-.492h-36.47v23.149h9.725c1.144 0 2.145.492 3.004 1.478.858.985 1.287 2.134 1.287 3.447v29.553c0 .876-.191 1.696-.573 2.463-.38.766-.905 1.368-1.573 1.806a3.84 3.84 0 0 1-2.145.656H51.915a3.84 3.84 0 0 1-2.145-.656c-.668-.438-1.216-1.04-1.645-1.806a4.96 4.96 0 0 1-.644-2.463V93.47c0-1.313.43-2.462 1.288-3.447.858-.986 1.907-1.478 3.146-1.478h9.582v-23.15h-37.9c-.953 0-1.74.356-2.359 1.068-.62.711-.93 1.56-.93 2.544v19.538h9.726c1.239 0 2.264.492 3.074 1.478.81.985 1.216 2.134 1.216 3.447v29.553c0 1.423-.405 2.6-1.216 3.53-.81.93-1.835 1.395-3.074 1.395H4.29c-.476 0-.93-.082-1.358-.246a4.1 4.1 0 0 1-1.144-.657 4.658 4.658 0 0 1-.93-1.067 5.186 5.186 0 0 1-.643-1.395 5.566 5.566 0 0 1-.215-1.56V93.47c0-.437.048-.875.143-1.313a3.95 3.95 0 0 1 .429-1.15c.19-.328.429-.656.715-.984.286-.329.572-.602.858-.821.286-.22.62-.383 1.001-.493.382-.11.763-.164 1.144-.164h9.726V61.619c0-.985.31-1.833.93-2.544.619-.712 1.358-1.068 2.216-1.068h44.335V39.62h-9.582c-1.24 0-2.288-.492-3.146-1.477a5.09 5.09 0 0 1-1.287-3.448V5.14c0-1.423.429-2.627 1.287-3.612.858-.985 1.907-1.477 3.146-1.477h25.743c.763 0 1.478.246 2.145.739a5.17 5.17 0 0 1 1.573 1.888c.382.766.573 1.587.573 2.462v29.553c0 1.313-.43 2.463-1.287 3.448-.859.985-1.86 1.477-3.004 1.477h-9.725v18.389h42.762c.954 0 1.74.355 2.36 1.067.62.711.93 1.56.93 2.545v26.925h9.582c1.239 0 2.288.492 3.146 1.478z\" /></symbol>'});o.a.add(c);t[\"default\"]=c},\"9f2b\":function(e,t,n){\"use strict\";var a=n(\"5bb9\"),i=n.n(a);i.a},a18c:function(e,t,n){\"use strict\";var a,i,r=n(\"2b0e\"),o=n(\"8c4f\"),c=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n(\"div\",{staticClass:\"app-wrapper\",class:e.classObj},[\"mobile\"===e.device&&e.sidebar.opened?n(\"div\",{staticClass:\"drawer-bg\",on:{click:e.handleClickOutside}}):e._e(),e._v(\" \"),n(\"sidebar\",{staticClass:\"sidebar-container\"}),e._v(\" \"),n(\"div\",{staticClass:\"main-container\"},[n(\"div\",{class:{\"fixed-header\":e.fixedHeader}},[n(\"navbar\")],1),e._v(\" \"),n(\"app-main\")],1)],1)},s=[],u=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n(\"div\",{staticClass:\"navbar\"},[n(\"hamburger\",{staticClass:\"hamburger-container\",attrs:{\"is-active\":e.sidebar.opened},on:{toggleClick:e.toggleSideBar}}),e._v(\" \"),n(\"breadcrumb\",{staticClass:\"breadcrumb-container\"}),e._v(\" \"),n(\"div\",{staticClass:\"right-menu\"},[n(\"el-dropdown\",{staticClass:\"avatar-container\",attrs:{trigger:\"click\"}},[n(\"div\",{staticClass:\"avatar-wrapper\"},[n(\"img\",{staticClass:\"user-avatar\",attrs:{src:e.avat+\"?imageView2/1/w/80/h/80\"}}),e._v(\" \"),n(\"i\",{staticClass:\"el-icon-caret-bottom\"})]),e._v(\" \"),n(\"el-dropdown-menu\",{staticClass:\"user-dropdown\",attrs:{slot:\"dropdown\"},slot:\"dropdown\"},[n(\"router-link\",{attrs:{to:\"/\"}},[n(\"el-dropdown-item\",[e._v(\"\\n            主页\\n          \")])],1),e._v(\" \"),n(\"router-link\",{attrs:{to:\"/sys/user\"}},[n(\"el-dropdown-item\",[e._v(\"账号管理\")])],1),e._v(\" \"),n(\"el-dropdown-item\",{attrs:{divided:\"\"}},[n(\"span\",{staticStyle:{display:\"block\"},on:{click:e.logout}},[e._v(\"退出\")])])],1)],1)],1)],1)},l=[],d=(n(\"96cf\"),n(\"3b8d\")),h=n(\"db72\"),f=n(\"2f62\"),m=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n(\"el-breadcrumb\",{staticClass:\"app-breadcrumb\",attrs:{separator:\"/\"}},[n(\"transition-group\",{attrs:{name:\"breadcrumb\"}},e._l(e.levelList,function(t,a){return n(\"el-breadcrumb-item\",{key:t.path},[\"noRedirect\"===t.redirect||a==e.levelList.length-1?n(\"span\",{staticClass:\"no-redirect\"},[e._v(e._s(t.meta.title))]):n(\"a\",{on:{click:function(n){return n.preventDefault(),e.handleLink(t)}}},[e._v(e._s(t.meta.title))])])}),1)],1)},p=[],v=(n(\"7f7f\"),n(\"bd11\")),b=n.n(v),g={data:function(){return{levelList:null}},watch:{$route:function(){this.getBreadcrumb()}},created:function(){this.getBreadcrumb()},methods:{getBreadcrumb:function(){var e=this.$route.matched.filter(function(e){return e.meta&&e.meta.title}),t=e[0];this.isDashboard(t)||(e=[{path:\"/dashboard\",meta:{title:\"主页\"}}].concat(e)),this.levelList=e.filter(function(e){return e.meta&&e.meta.title&&!1!==e.meta.breadcrumb})},isDashboard:function(e){var t=e&&e.name;return!!t&&t.trim().toLocaleLowerCase()===\"Dashboard\".toLocaleLowerCase()},pathCompile:function(e){var t=this.$route.params,n=b.a.compile(e);return n(t)},handleLink:function(e){var t=e.redirect,n=e.path;t?this.$router.push(t):this.$router.push(this.pathCompile(n))}}},w=g,x=(n(\"1b09\"),n(\"2877\")),k=Object(x[\"a\"])(w,m,p,!1,null,\"c09a31b8\",null),y=k.exports,C=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n(\"div\",{staticStyle:{padding:\"0 15px\"},on:{click:e.toggleClick}},[n(\"svg\",{staticClass:\"hamburger\",class:{\"is-active\":e.isActive},attrs:{viewBox:\"0 0 1024 1024\",xmlns:\"http://www.w3.org/2000/svg\",width:\"64\",height:\"64\"}},[n(\"path\",{attrs:{d:\"M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z\"}})])])},_=[],O={name:\"Hamburger\",props:{isActive:{type:Boolean,default:!1}},methods:{toggleClick:function(){this.$emit(\"toggleClick\")}}},S=O,z=(n(\"186a\"),Object(x[\"a\"])(S,C,_,!1,null,\"49e15297\",null)),E=z.exports,H={components:{Breadcrumb:y,Hamburger:E},data:function(){return{avat:\"./avatar.gif\"}},computed:Object(h[\"a\"])({},Object(f[\"b\"])([\"sidebar\",\"avatar\"])),methods:{toggleSideBar:function(){this.$store.dispatch(\"app/toggleSideBar\")},logout:function(){var e=Object(d[\"a\"])(regeneratorRuntime.mark(function e(){return regeneratorRuntime.wrap(function(e){while(1)switch(e.prev=e.next){case 0:return e.next=2,this.$store.dispatch(\"user/logout\");case 2:this.$router.push(\"/login?redirect=\".concat(this.$route.fullPath));case 3:case\"end\":return e.stop()}},e,this)}));function t(){return e.apply(this,arguments)}return t}()}},M=H,B=(n(\"d5be\"),Object(x[\"a\"])(M,u,l,!1,null,\"3ca66fc8\",null)),T=B.exports,j=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n(\"div\",{class:{\"has-logo\":e.showLogo}},[e.showLogo?n(\"logo\",{attrs:{collapse:e.isCollapse}}):e._e(),e._v(\" \"),n(\"el-scrollbar\",{attrs:{\"wrap-class\":\"scrollbar-wrapper\"}},[n(\"el-menu\",{attrs:{\"default-active\":e.activeMenu,collapse:e.isCollapse,\"background-color\":e.variables.menuBg,\"text-color\":e.variables.menuText,\"unique-opened\":!1,\"active-text-color\":e.variables.menuActiveText,\"collapse-transition\":!1,mode:\"vertical\"}},e._l(e.routes,function(e){return n(\"sidebar-item\",{key:e.path,attrs:{item:e,\"base-path\":e.path}})}),1)],1)],1)},L=[],V=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n(\"div\",{staticClass:\"sidebar-logo-container\",class:{collapse:e.collapse}},[n(\"transition\",{attrs:{name:\"sidebarLogoFade\"}},[e.collapse?n(\"router-link\",{key:\"collapse\",staticClass:\"sidebar-logo-link\",attrs:{to:\"/\"}},[e.logo?n(\"img\",{staticClass:\"sidebar-logo\",attrs:{src:e.logo}}):n(\"h1\",{staticClass:\"sidebar-title\"},[e._v(e._s(e.title)+\" \")])]):n(\"router-link\",{key:\"expand\",staticClass:\"sidebar-logo-link\",attrs:{to:\"/\"}},[e.logo?n(\"img\",{staticClass:\"sidebar-logo\",attrs:{src:e.logo}}):e._e(),e._v(\" \"),n(\"h1\",{staticClass:\"sidebar-title\"},[e._v(e._s(e.title)+\" \")])])],1)],1)},$=[],A={name:\"SidebarLogo\",props:{collapse:{type:Boolean,required:!0}},data:function(){return{title:\"\",logo:\"./logo.png\"}}},I=A,P=(n(\"1660\"),Object(x[\"a\"])(I,V,$,!1,null,\"53202dff\",null)),N=P.exports,D=function(){var e=this,t=e.$createElement,n=e._self._c||t;return e.item.hidden?e._e():n(\"div\",{staticClass:\"menu-wrapper\"},[!e.hasOneShowingChild(e.item.children,e.item)||e.onlyOneChild.children&&!e.onlyOneChild.noShowingChildren||e.item.alwaysShow?n(\"el-submenu\",{ref:\"subMenu\",attrs:{index:e.resolvePath(e.item.path),\"popper-append-to-body\":\"\"}},[n(\"template\",{slot:\"title\"},[e.item.meta?n(\"item\",{attrs:{icon:e.item.meta&&e.item.meta.icon,title:e.item.meta.title}}):e._e()],1),e._v(\" \"),e._l(e.item.children,function(t){return n(\"sidebar-item\",{key:t.path,staticClass:\"nest-menu\",attrs:{\"is-nest\":!0,item:t,\"base-path\":e.resolvePath(t.path)}})})],2):[e.onlyOneChild.meta?n(\"app-link\",{attrs:{to:e.resolvePath(e.onlyOneChild.path)}},[n(\"el-menu-item\",{class:{\"submenu-title-noDropdown\":!e.isNest},attrs:{index:e.resolvePath(e.onlyOneChild.path)}},[n(\"item\",{attrs:{icon:e.onlyOneChild.meta.icon||e.item.meta&&e.item.meta.icon,title:e.onlyOneChild.meta.title}})],1)],1):e._e()]],2)},q=[],R=n(\"df7c\"),G=n.n(R),F=n(\"61f7\"),K={name:\"MenuItem\",functional:!0,props:{icon:{type:String,default:\"\"},title:{type:String,default:\"\"}},render:function(e,t){var n=t.props,a=n.icon,i=n.title,r=[];return a&&r.push(e(\"svg-icon\",{attrs:{\"icon-class\":a}})),i&&r.push(e(\"span\",{slot:\"title\"},[i])),r}},U=K,J=Object(x[\"a\"])(U,a,i,!1,null,null,null),W=J.exports,X=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n(\"component\",e._b({},\"component\",e.linkProps(e.to),!1),[e._t(\"default\")],2)},Y=[],Q={props:{to:{type:String,required:!0}},methods:{linkProps:function(e){return Object(F[\"a\"])(e)?{is:\"a\",href:e,target:\"_blank\",rel:\"noopener\"}:{is:\"router-link\",to:e}}}},Z=Q,ee=Object(x[\"a\"])(Z,X,Y,!1,null,null,null),te=ee.exports,ne={computed:{device:function(){return this.$store.state.app.device}},mounted:function(){this.fixBugIniOS()},methods:{fixBugIniOS:function(){var e=this,t=this.$refs.subMenu;if(t){var n=t.handleMouseleave;t.handleMouseleave=function(t){\"mobile\"!==e.device&&n(t)}}}}},ae={name:\"SidebarItem\",components:{Item:W,AppLink:te},mixins:[ne],props:{item:{type:Object,required:!0},isNest:{type:Boolean,default:!1},basePath:{type:String,default:\"\"}},data:function(){return this.onlyOneChild=null,{}},methods:{hasOneShowingChild:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],n=arguments.length>1?arguments[1]:void 0,a=t.filter(function(t){return!t.hidden&&(e.onlyOneChild=t,!0)});return 1===a.length||0===a.length&&(this.onlyOneChild=Object(h[\"a\"])({},n,{path:\"\",noShowingChildren:!0}),!0)},resolvePath:function(e){return Object(F[\"a\"])(e)?e:Object(F[\"a\"])(this.basePath)?this.basePath:G.a.resolve(this.basePath,e)}}},ie=ae,re=Object(x[\"a\"])(ie,D,q,!1,null,null,null),oe=re.exports,ce=n(\"cf1e\"),se=n.n(ce),ue={components:{SidebarItem:oe,Logo:N},computed:Object(h[\"a\"])({},Object(f[\"b\"])([\"sidebar\"]),{routes:function(){return this.$router.options.routes},activeMenu:function(){var e=this.$route,t=e.meta,n=e.path;return t.activeMenu?t.activeMenu:n},showLogo:function(){return this.$store.state.settings.sidebarLogo},variables:function(){return se.a},isCollapse:function(){return!this.sidebar.opened}})},le=ue,de=Object(x[\"a\"])(le,j,L,!1,null,null,null),he=de.exports,fe=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n(\"section\",{staticClass:\"app-main\"},[n(\"transition\",{attrs:{name:\"fade-transform\",mode:\"out-in\"}},[n(\"router-view\",{key:e.key})],1)],1)},me=[],pe={name:\"AppMain\",computed:{key:function(){return this.$route.path}}},ve=pe,be=(n(\"e4de\"),n(\"028b\"),Object(x[\"a\"])(ve,fe,me,!1,null,\"64cf4d83\",null)),ge=be.exports,we=n(\"4360\"),xe=document,ke=xe.body,ye=992,Ce={watch:{$route:function(e){\"mobile\"===this.device&&this.sidebar.opened&&we[\"a\"].dispatch(\"app/closeSideBar\",{withoutAnimation:!1})}},beforeMount:function(){window.addEventListener(\"resize\",this.$_resizeHandler)},beforeDestroy:function(){window.removeEventListener(\"resize\",this.$_resizeHandler)},mounted:function(){var e=this.$_isMobile();e&&(we[\"a\"].dispatch(\"app/toggleDevice\",\"mobile\"),we[\"a\"].dispatch(\"app/closeSideBar\",{withoutAnimation:!0}))},methods:{$_isMobile:function(){var e=ke.getBoundingClientRect();return e.width-1<ye},$_resizeHandler:function(){if(!document.hidden){var e=this.$_isMobile();we[\"a\"].dispatch(\"app/toggleDevice\",e?\"mobile\":\"desktop\"),e&&we[\"a\"].dispatch(\"app/closeSideBar\",{withoutAnimation:!0})}}}},_e={name:\"Layout\",components:{Navbar:T,Sidebar:he,AppMain:ge},mixins:[Ce],computed:{sidebar:function(){return this.$store.state.app.sidebar},device:function(){return this.$store.state.app.device},fixedHeader:function(){return this.$store.state.settings.fixedHeader},classObj:function(){return{hideSidebar:!this.sidebar.opened,openSidebar:this.sidebar.opened,withoutAnimation:this.sidebar.withoutAnimation,mobile:\"mobile\"===this.device}}},methods:{handleClickOutside:function(){this.$store.dispatch(\"app/closeSideBar\",{withoutAnimation:!1})}}},Oe=_e,Se=(n(\"9f2b\"),Object(x[\"a\"])(Oe,c,s,!1,null,\"4f739cf0\",null)),ze=Se.exports;n.d(t,\"b\",function(){return Be}),r[\"default\"].use(o[\"a\"]);var Ee=[{path:\"/login\",component:function(){return n.e(\"chunk-101fc062\").then(n.bind(null,\"9ed6\"))},hidden:!0},{path:\"/404\",component:function(){return n.e(\"chunk-49959c8b\").then(n.bind(null,\"8cdb\"))},hidden:!0},{path:\"/\",component:ze,redirect:\"/dashboard\",children:[{path:\"dashboard\",name:\"主页\",component:function(){return n.e(\"chunk-37c49cbf\").then(n.bind(null,\"9406\"))},meta:{title:\"主页\",icon:\"dashboard\"}}],hidden:!0},{path:\"/sys\",component:ze,redirect:\"/user\",children:[{path:\"user\",name:\"用户信息\",component:function(){return n.e(\"chunk-69386cf0\").then(n.bind(null,\"9fb7\"))},meta:{title:\"用户信息\"}}],hidden:!0},{path:\"/canalServer\",component:ze,redirect:\"/canalServer/nodeServers\",name:\"Canal Server\",meta:{title:\"Canal Server\",icon:\"example\"},children:[{path:\"canalClusters\",name:\"Canal 集群管理\",component:function(){return n.e(\"chunk-55380ff2\").then(n.bind(null,\"e509\"))},meta:{title:\"集群管理\",icon:\"tree\"}},{path:\"nodeServers\",name:\"Server 状态\",component:function(){return n.e(\"chunk-14b5f7a4\").then(n.bind(null,\"9f66\"))},meta:{title:\"Server 管理\",icon:\"form\"}},{path:\"nodeServer/config\",name:\"Server 配置\",component:function(){return Promise.all([n.e(\"chunk-0dca2f22\"),n.e(\"chunk-98f505d0\")]).then(n.bind(null,\"aa99\"))},meta:{title:\"Server 配置\"},hidden:!0},{path:\"canalInstances\",name:\"Instance 管理\",component:function(){return n.e(\"chunk-22553be3\").then(n.bind(null,\"1c98\"))},meta:{title:\"Instance 管理\",icon:\"nested\"}},{path:\"canalInstance/add\",name:\"新建Instance配置\",component:function(){return Promise.all([n.e(\"chunk-0dca2f22\"),n.e(\"chunk-2301924a\")]).then(n.bind(null,\"1248\"))},meta:{title:\"新建Instance配置\"},hidden:!0},{path:\"canalInstance/modify\",name:\"修改Instance配置\",component:function(){return Promise.all([n.e(\"chunk-0dca2f22\"),n.e(\"chunk-bd1d44ee\")]).then(n.bind(null,\"b0a2\"))},meta:{title:\"修改Instance配置\"},hidden:!0},{path:\"nodeServer/log\",name:\"Server 日志\",component:function(){return n.e(\"chunk-4f09fed2\").then(n.bind(null,\"caf8\"))},meta:{title:\"Server 日志\"},hidden:!0},{path:\"canalInstance/log\",name:\"Instance 日志\",component:function(){return n.e(\"chunk-7ec889b7\").then(n.bind(null,\"7f84\"))},meta:{title:\"Instance 日志\"},hidden:!0}]},{path:\"*\",redirect:\"/404\",hidden:!0}],He=function(){return new o[\"a\"]({scrollBehavior:function(){return{y:0}},routes:Ee})},Me=He();function Be(){var e=He();Me.matcher=e.matcher}t[\"a\"]=Me},a217:function(e,t,n){},a424:function(e,t,n){},b20f:function(e,t,n){e.exports={menuText:\"#bfcbd9\",menuActiveText:\"#409EFF\",subMenuActiveText:\"#f4f4f5\",menuBg:\"#304156\",menuHover:\"#263445\",subMenuBg:\"#1f2d3d\",subMenuHover:\"#001528\",sideBarWidth:\"210px\"}},b3b5:function(e,t,n){\"use strict\";n.r(t);var a=n(\"e017\"),i=n.n(a),r=n(\"21a1\"),o=n.n(r),c=new i.a({id:\"icon-user\",use:\"icon-user-usage\",viewBox:\"0 0 130 130\",content:'<symbol xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 130 130\" id=\"icon-user\"><path d=\"M63.444 64.996c20.633 0 37.359-14.308 37.359-31.953 0-17.649-16.726-31.952-37.359-31.952-20.631 0-37.36 14.303-37.358 31.952 0 17.645 16.727 31.953 37.359 31.953zM80.57 75.65H49.434c-26.652 0-48.26 18.477-48.26 41.27v2.664c0 9.316 21.608 9.325 48.26 9.325H80.57c26.649 0 48.256-.344 48.256-9.325v-2.663c0-22.794-21.605-41.271-48.256-41.271z\" stroke=\"#979797\" /></symbol>'});o.a.add(c);t[\"default\"]=c},b775:function(e,t,n){\"use strict\";var a=n(\"bc3a\"),i=n.n(a),r=n(\"5c96\"),o=n(\"4360\"),c=n(\"5f87\"),s=i.a.create({baseURL:\"/api/v1\",timeout:6e4});s.interceptors.request.use(function(e){return o[\"a\"].getters.token&&(e.headers[\"X-Token\"]=Object(c[\"a\"])()),e},function(e){return console.log(e),Promise.reject(e)}),s.interceptors.response.use(function(e){var t=e.data;return 2e4!==t.code?(Object(r[\"Message\"])({message:t.message||\"Error\",type:\"error\",duration:5e3}),50008!==t.code&&50012!==t.code&&50014!==t.code||r[\"MessageBox\"].confirm(\"You have been logged out, you can cancel to stay on this page, or log in again\",\"Confirm logout\",{confirmButtonText:\"Re-Login\",cancelButtonText:\"Cancel\",type:\"warning\"}).then(function(){o[\"a\"].dispatch(\"user/resetToken\").then(function(){location.reload()})}),Promise.reject(new Error(t.message||\"Error\"))):t},function(e){return console.log(\"err\"+e),Object(r[\"Message\"])({message:e.message,type:\"error\",duration:5e3}),Promise.reject(e)}),t[\"a\"]=s},c24f:function(e,t,n){\"use strict\";n.d(t,\"b\",function(){return i}),n.d(t,\"a\",function(){return r}),n.d(t,\"c\",function(){return o}),n.d(t,\"d\",function(){return c});var a=n(\"b775\");function i(e){return Object(a[\"a\"])({url:\"/user/login\",method:\"post\",data:e})}function r(e){return Object(a[\"a\"])({url:\"/user/info\",method:\"get\",params:{token:e}})}function o(){return Object(a[\"a\"])({url:\"/user/logout\",method:\"post\"})}function c(e){return Object(a[\"a\"])({url:\"/user\",method:\"put\",data:e})}},cf1e:function(e,t,n){e.exports={menuText:\"#bfcbd9\",menuActiveText:\"#409EFF\",subMenuActiveText:\"#f4f4f5\",menuBg:\"#304156\",menuHover:\"#263445\",subMenuBg:\"#1f2d3d\",subMenuHover:\"#001528\",sideBarWidth:\"210px\"}},d5be:function(e,t,n){\"use strict\";var a=n(\"a424\"),i=n.n(a);i.a},d7ec:function(e,t,n){\"use strict\";n.r(t);var a=n(\"e017\"),i=n.n(a),r=n(\"21a1\"),o=n.n(r),c=new i.a({id:\"icon-eye-open\",use:\"icon-eye-open-usage\",viewBox:\"0 0 1024 1024\",content:'<symbol class=\"icon\" viewBox=\"0 0 1024 1024\" xmlns=\"http://www.w3.org/2000/svg\" id=\"icon-eye-open\"><defs><style></style></defs><path d=\"M512 128q69.675 0 135.51 21.163t115.498 54.997 93.483 74.837 73.685 82.006 51.67 74.837 32.17 54.827L1024 512q-2.347 4.992-6.315 13.483T998.87 560.17t-31.658 51.669-44.331 59.99-56.832 64.34-69.504 60.16-82.347 51.5-94.848 34.687T512 896q-69.675 0-135.51-21.163t-115.498-54.826-93.483-74.326-73.685-81.493-51.67-74.496-32.17-54.997L0 513.707q2.347-4.992 6.315-13.483t18.816-34.816 31.658-51.84 44.331-60.33 56.832-64.683 69.504-60.331 82.347-51.84 94.848-34.816T512 128.085zm0 85.333q-46.677 0-91.648 12.331t-81.152 31.83-70.656 47.146-59.648 54.485-48.853 57.686-37.675 52.821-26.325 43.99q12.33 21.674 26.325 43.52t37.675 52.351 48.853 57.003 59.648 53.845T339.2 767.02t81.152 31.488T512 810.667t91.648-12.331 81.152-31.659 70.656-46.848 59.648-54.186 48.853-57.344 37.675-52.651T927.957 512q-12.33-21.675-26.325-43.648t-37.675-52.65-48.853-57.345-59.648-54.186-70.656-46.848-81.152-31.659T512 213.334zm0 128q70.656 0 120.661 50.006T682.667 512 632.66 632.661 512 682.667 391.339 632.66 341.333 512t50.006-120.661T512 341.333zm0 85.334q-35.328 0-60.33 25.002T426.666 512t25.002 60.33T512 597.334t60.33-25.002T597.334 512t-25.002-60.33T512 426.666z\" /></symbol>'});o.a.add(c);t[\"default\"]=c},dc52:function(e,t,n){},dcf8:function(e,t,n){\"use strict\";n.r(t);var a=n(\"e017\"),i=n.n(a),r=n(\"21a1\"),o=n.n(r),c=new i.a({id:\"icon-nested\",use:\"icon-nested-usage\",viewBox:\"0 0 128 128\",content:'<symbol xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 128 128\" id=\"icon-nested\"><path d=\"M.002 9.2c0 5.044 3.58 9.133 7.998 9.133 4.417 0 7.997-4.089 7.997-9.133 0-5.043-3.58-9.132-7.997-9.132S.002 4.157.002 9.2zM31.997.066h95.981V18.33H31.997V.066zm0 45.669c0 5.044 3.58 9.132 7.998 9.132 4.417 0 7.997-4.088 7.997-9.132 0-3.263-1.524-6.278-3.998-7.91-2.475-1.63-5.524-1.63-7.998 0-2.475 1.632-4 4.647-4 7.91zM63.992 36.6h63.986v18.265H63.992V36.6zm-31.995 82.2c0 5.043 3.58 9.132 7.998 9.132 4.417 0 7.997-4.089 7.997-9.132 0-5.044-3.58-9.133-7.997-9.133s-7.998 4.089-7.998 9.133zm31.995-9.131h63.986v18.265H63.992V109.67zm0-27.404c0 5.044 3.58 9.133 7.998 9.133 4.417 0 7.997-4.089 7.997-9.133 0-3.263-1.524-6.277-3.998-7.909-2.475-1.631-5.524-1.631-7.998 0-2.475 1.632-4 4.646-4 7.91zm31.995-9.13h31.991V91.4H95.987V73.135z\" /></symbol>'});o.a.add(c);t[\"default\"]=c},e4de:function(e,t,n){\"use strict\";var a=n(\"8902\"),i=n.n(a);i.a},eb1b:function(e,t,n){\"use strict\";n.r(t);var a=n(\"e017\"),i=n.n(a),r=n(\"21a1\"),o=n.n(r),c=new i.a({id:\"icon-form\",use:\"icon-form-usage\",viewBox:\"0 0 128 128\",content:'<symbol xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 128 128\" id=\"icon-form\"><path d=\"M84.068 23.784c-1.02 0-1.877-.32-2.572-.96a8.588 8.588 0 0 1-1.738-2.237 11.524 11.524 0 0 1-1.042-2.621c-.232-.895-.348-1.641-.348-2.238V0h.278c.834 0 1.622.085 2.363.256.742.17 1.645.575 2.711 1.214 1.066.64 2.363 1.535 3.892 2.686 1.53 1.15 3.453 2.664 5.77 4.54 2.502 2.045 4.494 3.771 5.977 5.178 1.483 1.406 2.618 2.6 3.406 3.58.787.98 1.274 1.812 1.46 2.494.185.682.277 1.278.277 1.79v2.046H84.068zM127.3 84.01c.278.682.464 1.535.556 2.558.093 1.023-.37 2.003-1.39 2.94-.463.427-.88.832-1.25 1.215-.372.384-.696.704-.974.96a6.69 6.69 0 0 1-.973.767l-11.816-10.741a44.331 44.331 0 0 0 1.877-1.535 31.028 31.028 0 0 1 1.737-1.406c1.112-.938 2.317-1.343 3.615-1.215 1.297.128 2.363.405 3.197.83.927.427 1.923 1.173 2.989 2.239 1.065 1.065 1.876 2.195 2.432 3.388zM78.23 95.902c2.038 0 3.752-.511 5.143-1.534l-26.969 25.83H18.037c-1.761 0-3.684-.47-5.77-1.407a24.549 24.549 0 0 1-5.838-3.709 21.373 21.373 0 0 1-4.518-5.306c-1.204-2.003-1.807-4.07-1.807-6.202V16.495c0-1.79.44-3.665 1.32-5.626A18.41 18.41 0 0 1 5.04 5.562a21.798 21.798 0 0 1 5.213-3.964C12.198.533 14.237 0 16.37 0h53.24v15.984c0 1.62.278 3.367.834 5.242a16.704 16.704 0 0 0 2.572 5.179c1.159 1.577 2.665 2.898 4.518 3.964 1.853 1.066 4.078 1.598 6.673 1.598h20.295v42.325L85.458 92.45c1.02-1.364 1.529-2.856 1.529-4.476 0-2.216-.857-4.113-2.572-5.69-1.714-1.577-3.776-2.366-6.186-2.366H26.1c-2.409 0-4.448.789-6.116 2.366-1.668 1.577-2.502 3.474-2.502 5.69 0 2.217.834 4.092 2.502 5.626 1.668 1.535 3.707 2.302 6.117 2.302h52.13zM26.1 47.951c-2.41 0-4.449.789-6.117 2.366-1.668 1.577-2.502 3.473-2.502 5.69 0 2.216.834 4.092 2.502 5.626 1.668 1.534 3.707 2.302 6.117 2.302h52.13c2.409 0 4.47-.768 6.185-2.302 1.715-1.534 2.572-3.41 2.572-5.626 0-2.217-.857-4.113-2.572-5.69-1.714-1.577-3.776-2.366-6.186-2.366H26.1zm52.407 64.063l1.807-1.663 3.476-3.196a479.75 479.75 0 0 0 4.587-4.284 500.757 500.757 0 0 1 5.004-4.667c3.985-3.666 8.48-7.758 13.485-12.276l11.677 10.741-13.485 12.404-5.004 4.603-4.587 4.22a179.46 179.46 0 0 0-3.267 3.068c-.88.853-1.367 1.322-1.46 1.407-.463.341-.973.703-1.529 1.087-.556.383-1.112.703-1.668.959-.556.256-1.413.575-2.572.959a83.5 83.5 0 0 1-3.545 1.087 72.2 72.2 0 0 1-3.475.895c-1.112.256-1.946.426-2.502.511-1.112.17-1.854.043-2.224-.383-.371-.426-.464-1.151-.278-2.174.092-.511.278-1.279.556-2.302.278-1.023.602-2.067.973-3.132l1.042-3.005c.325-.938.58-1.577.765-1.918a10.157 10.157 0 0 1 2.224-2.941z\" /></symbol>'});o.a.add(c);t[\"default\"]=c},f782:function(e,t,n){\"use strict\";n.r(t);var a=n(\"e017\"),i=n.n(a),r=n(\"21a1\"),o=n.n(r),c=new i.a({id:\"icon-dashboard\",use:\"icon-dashboard-usage\",viewBox:\"0 0 128 100\",content:'<symbol xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 128 100\" id=\"icon-dashboard\"><path d=\"M27.429 63.638c0-2.508-.893-4.65-2.679-6.424-1.786-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.465 2.662-1.785 1.774-2.678 3.916-2.678 6.424 0 2.508.893 4.65 2.678 6.424 1.786 1.775 3.94 2.662 6.465 2.662 2.524 0 4.678-.887 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zm13.714-31.801c0-2.508-.893-4.65-2.679-6.424-1.785-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zM71.714 65.98l7.215-27.116c.285-1.23.107-2.378-.536-3.443-.643-1.064-1.56-1.762-2.75-2.094-1.19-.33-2.333-.177-3.429.462-1.095.639-1.81 1.573-2.143 2.804l-7.214 27.116c-2.857.237-5.405 1.266-7.643 3.088-2.238 1.822-3.738 4.152-4.5 6.992-.952 3.644-.476 7.098 1.429 10.364 1.905 3.265 4.69 5.37 8.357 6.317 3.667.947 7.143.474 10.429-1.42 3.285-1.892 5.404-4.66 6.357-8.305.762-2.84.619-5.607-.429-8.305-1.047-2.697-2.762-4.85-5.143-6.46zm47.143-2.342c0-2.508-.893-4.65-2.678-6.424-1.786-1.775-3.94-2.662-6.465-2.662-2.524 0-4.678.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.786 1.775 3.94 2.662 6.464 2.662 2.524 0 4.679-.887 6.465-2.662 1.785-1.775 2.678-3.916 2.678-6.424zm-45.714-45.43c0-2.509-.893-4.65-2.679-6.425C68.68 10.01 66.524 9.122 64 9.122c-2.524 0-4.679.887-6.464 2.661-1.786 1.775-2.679 3.916-2.679 6.425 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zm32 13.629c0-2.508-.893-4.65-2.679-6.424-1.785-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zM128 63.638c0 12.351-3.357 23.78-10.071 34.286-.905 1.372-2.19 2.058-3.858 2.058H13.93c-1.667 0-2.953-.686-3.858-2.058C3.357 87.465 0 76.037 0 63.638c0-8.613 1.69-16.847 5.071-24.703C8.452 31.08 13 24.312 18.714 18.634c5.715-5.68 12.524-10.199 20.429-13.559C47.048 1.715 55.333.035 64 .035c8.667 0 16.952 1.68 24.857 5.04 7.905 3.36 14.714 7.88 20.429 13.559 5.714 5.678 10.262 12.446 13.643 20.301 3.38 7.856 5.071 16.09 5.071 24.703z\" /></symbol>'});o.a.add(c);t[\"default\"]=c},ff7f:function(e,t,n){}},[[0,\"runtime\",\"chunk-elementUI\",\"chunk-libs\"]]]);"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/js/chunk-0dca2f22.a2bc28b8.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[\"chunk-0dca2f22\"],{\"0329\":function(e,t){ace.define(\"ace/mode/css_highlight_rules\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/lib/lang\",\"ace/mode/text_highlight_rules\"],function(e,t,n){\"use strict\";var r=e(\"../lib/oop\"),i=(e(\"../lib/lang\"),e(\"./text_highlight_rules\").TextHighlightRules),o=t.supportType=\"align-content|align-items|align-self|all|animation|animation-delay|animation-direction|animation-duration|animation-fill-mode|animation-iteration-count|animation-name|animation-play-state|animation-timing-function|backface-visibility|background|background-attachment|background-blend-mode|background-clip|background-color|background-image|background-origin|background-position|background-repeat|background-size|border|border-bottom|border-bottom-color|border-bottom-left-radius|border-bottom-right-radius|border-bottom-style|border-bottom-width|border-collapse|border-color|border-image|border-image-outset|border-image-repeat|border-image-slice|border-image-source|border-image-width|border-left|border-left-color|border-left-style|border-left-width|border-radius|border-right|border-right-color|border-right-style|border-right-width|border-spacing|border-style|border-top|border-top-color|border-top-left-radius|border-top-right-radius|border-top-style|border-top-width|border-width|bottom|box-shadow|box-sizing|caption-side|clear|clip|color|column-count|column-fill|column-gap|column-rule|column-rule-color|column-rule-style|column-rule-width|column-span|column-width|columns|content|counter-increment|counter-reset|cursor|direction|display|empty-cells|filter|flex|flex-basis|flex-direction|flex-flow|flex-grow|flex-shrink|flex-wrap|float|font|font-family|font-size|font-size-adjust|font-stretch|font-style|font-variant|font-weight|hanging-punctuation|height|justify-content|left|letter-spacing|line-height|list-style|list-style-image|list-style-position|list-style-type|margin|margin-bottom|margin-left|margin-right|margin-top|max-height|max-width|min-height|min-width|nav-down|nav-index|nav-left|nav-right|nav-up|opacity|order|outline|outline-color|outline-offset|outline-style|outline-width|overflow|overflow-x|overflow-y|padding|padding-bottom|padding-left|padding-right|padding-top|page-break-after|page-break-before|page-break-inside|perspective|perspective-origin|position|quotes|resize|right|tab-size|table-layout|text-align|text-align-last|text-decoration|text-decoration-color|text-decoration-line|text-decoration-style|text-indent|text-justify|text-overflow|text-shadow|text-transform|top|transform|transform-origin|transform-style|transition|transition-delay|transition-duration|transition-property|transition-timing-function|unicode-bidi|vertical-align|visibility|white-space|width|word-break|word-spacing|word-wrap|z-index\",a=t.supportFunction=\"rgb|rgba|url|attr|counter|counters\",s=t.supportConstant=\"absolute|after-edge|after|all-scroll|all|alphabetic|always|antialiased|armenian|auto|avoid-column|avoid-page|avoid|balance|baseline|before-edge|before|below|bidi-override|block-line-height|block|bold|bolder|border-box|both|bottom|box|break-all|break-word|capitalize|caps-height|caption|center|central|char|circle|cjk-ideographic|clone|close-quote|col-resize|collapse|column|consider-shifts|contain|content-box|cover|crosshair|cubic-bezier|dashed|decimal-leading-zero|decimal|default|disabled|disc|disregard-shifts|distribute-all-lines|distribute-letter|distribute-space|distribute|dotted|double|e-resize|ease-in|ease-in-out|ease-out|ease|ellipsis|end|exclude-ruby|fill|fixed|georgian|glyphs|grid-height|groove|hand|hanging|hebrew|help|hidden|hiragana-iroha|hiragana|horizontal|icon|ideograph-alpha|ideograph-numeric|ideograph-parenthesis|ideograph-space|ideographic|inactive|include-ruby|inherit|initial|inline-block|inline-box|inline-line-height|inline-table|inline|inset|inside|inter-ideograph|inter-word|invert|italic|justify|katakana-iroha|katakana|keep-all|last|left|lighter|line-edge|line-through|line|linear|list-item|local|loose|lower-alpha|lower-greek|lower-latin|lower-roman|lowercase|lr-tb|ltr|mathematical|max-height|max-size|medium|menu|message-box|middle|move|n-resize|ne-resize|newspaper|no-change|no-close-quote|no-drop|no-open-quote|no-repeat|none|normal|not-allowed|nowrap|nw-resize|oblique|open-quote|outset|outside|overline|padding-box|page|pointer|pre-line|pre-wrap|pre|preserve-3d|progress|relative|repeat-x|repeat-y|repeat|replaced|reset-size|ridge|right|round|row-resize|rtl|s-resize|scroll|se-resize|separate|slice|small-caps|small-caption|solid|space|square|start|static|status-bar|step-end|step-start|steps|stretch|strict|sub|super|sw-resize|table-caption|table-cell|table-column-group|table-column|table-footer-group|table-header-group|table-row-group|table-row|table|tb-rl|text-after-edge|text-before-edge|text-bottom|text-size|text-top|text|thick|thin|transparent|underline|upper-alpha|upper-latin|upper-roman|uppercase|use-script|vertical-ideographic|vertical-text|visible|w-resize|wait|whitespace|z-index|zero\",l=t.supportConstantColor=\"aliceblue|antiquewhite|aqua|aquamarine|azure|beige|bisque|black|blanchedalmond|blue|blueviolet|brown|burlywood|cadetblue|chartreuse|chocolate|coral|cornflowerblue|cornsilk|crimson|cyan|darkblue|darkcyan|darkgoldenrod|darkgray|darkgreen|darkgrey|darkkhaki|darkmagenta|darkolivegreen|darkorange|darkorchid|darkred|darksalmon|darkseagreen|darkslateblue|darkslategray|darkslategrey|darkturquoise|darkviolet|deeppink|deepskyblue|dimgray|dimgrey|dodgerblue|firebrick|floralwhite|forestgreen|fuchsia|gainsboro|ghostwhite|gold|goldenrod|gray|green|greenyellow|grey|honeydew|hotpink|indianred|indigo|ivory|khaki|lavender|lavenderblush|lawngreen|lemonchiffon|lightblue|lightcoral|lightcyan|lightgoldenrodyellow|lightgray|lightgreen|lightgrey|lightpink|lightsalmon|lightseagreen|lightskyblue|lightslategray|lightslategrey|lightsteelblue|lightyellow|lime|limegreen|linen|magenta|maroon|mediumaquamarine|mediumblue|mediumorchid|mediumpurple|mediumseagreen|mediumslateblue|mediumspringgreen|mediumturquoise|mediumvioletred|midnightblue|mintcream|mistyrose|moccasin|navajowhite|navy|oldlace|olive|olivedrab|orange|orangered|orchid|palegoldenrod|palegreen|paleturquoise|palevioletred|papayawhip|peachpuff|peru|pink|plum|powderblue|purple|rebeccapurple|red|rosybrown|royalblue|saddlebrown|salmon|sandybrown|seagreen|seashell|sienna|silver|skyblue|slateblue|slategray|slategrey|snow|springgreen|steelblue|tan|teal|thistle|tomato|turquoise|violet|wheat|white|whitesmoke|yellow|yellowgreen\",c=t.supportConstantFonts=\"arial|century|comic|courier|cursive|fantasy|garamond|georgia|helvetica|impact|lucida|symbol|system|tahoma|times|trebuchet|utopia|verdana|webdings|sans-serif|serif|monospace\",u=t.numRe=\"\\\\-?(?:(?:[0-9]+(?:\\\\.[0-9]+)?)|(?:\\\\.[0-9]+))\",d=t.pseudoElements=\"(\\\\:+)\\\\b(after|before|first-letter|first-line|moz-selection|selection)\\\\b\",h=t.pseudoClasses=\"(:)\\\\b(active|checked|disabled|empty|enabled|first-child|first-of-type|focus|hover|indeterminate|invalid|last-child|last-of-type|link|not|nth-child|nth-last-child|nth-last-of-type|nth-of-type|only-child|only-of-type|acequired|root|target|valid|visited)\\\\b\",p=function(){var e=this.createKeywordMapper({\"support.function\":a,\"support.constant\":s,\"support.type\":o,\"support.constant.color\":l,\"support.constant.fonts\":c},\"text\",!0);this.$rules={start:[{include:[\"strings\",\"url\",\"comments\"]},{token:\"paren.lparen\",regex:\"\\\\{\",next:\"ruleset\"},{token:\"paren.rparen\",regex:\"\\\\}\"},{token:\"string\",regex:\"@\",next:\"media\"},{token:\"keyword\",regex:\"#[a-z0-9-_]+\"},{token:\"keyword\",regex:\"%\"},{token:\"variable\",regex:\"\\\\.[a-z0-9-_]+\"},{token:\"string\",regex:\":[a-z0-9-_]+\"},{token:\"constant.numeric\",regex:u},{token:\"constant\",regex:\"[a-z0-9-_]+\"},{caseInsensitive:!0}],media:[{include:[\"strings\",\"url\",\"comments\"]},{token:\"paren.lparen\",regex:\"\\\\{\",next:\"start\"},{token:\"paren.rparen\",regex:\"\\\\}\",next:\"start\"},{token:\"string\",regex:\";\",next:\"start\"},{token:\"keyword\",regex:\"(?:media|supports|document|charset|import|namespace|media|supports|document|page|font|keyframes|viewport|counter-style|font-feature-values|swash|ornaments|annotation|stylistic|styleset|character-variant)\"}],comments:[{token:\"comment\",regex:\"\\\\/\\\\*\",push:[{token:\"comment\",regex:\"\\\\*\\\\/\",next:\"pop\"},{defaultToken:\"comment\"}]}],ruleset:[{regex:\"-(webkit|ms|moz|o)-\",token:\"text\"},{token:\"paren.rparen\",regex:\"\\\\}\",next:\"start\"},{include:[\"strings\",\"url\",\"comments\"]},{token:[\"constant.numeric\",\"keyword\"],regex:\"(\"+u+\")(ch|cm|deg|em|ex|fr|gd|grad|Hz|in|kHz|mm|ms|pc|pt|px|rad|rem|s|turn|vh|vm|vw|%)\"},{token:\"constant.numeric\",regex:u},{token:\"constant.numeric\",regex:\"#[a-f0-9]{6}\"},{token:\"constant.numeric\",regex:\"#[a-f0-9]{3}\"},{token:[\"punctuation\",\"entity.other.attribute-name.pseudo-element.css\"],regex:d},{token:[\"punctuation\",\"entity.other.attribute-name.pseudo-class.css\"],regex:h},{include:\"url\"},{token:e,regex:\"\\\\-?[a-zA-Z_][a-zA-Z0-9_\\\\-]*\"},{caseInsensitive:!0}],url:[{token:\"support.function\",regex:\"(?:url(:?-prefix)?|domain|regexp)\\\\(\",push:[{token:\"support.function\",regex:\"\\\\)\",next:\"pop\"},{defaultToken:\"string\"}]}],strings:[{token:\"string.start\",regex:\"'\",push:[{token:\"string.end\",regex:\"'|$\",next:\"pop\"},{include:\"escapes\"},{token:\"constant.language.escape\",regex:/\\\\$/,consumeLineEnd:!0},{defaultToken:\"string\"}]},{token:\"string.start\",regex:'\"',push:[{token:\"string.end\",regex:'\"|$',next:\"pop\"},{include:\"escapes\"},{token:\"constant.language.escape\",regex:/\\\\$/,consumeLineEnd:!0},{defaultToken:\"string\"}]}],escapes:[{token:\"constant.language.escape\",regex:/\\\\([a-fA-F\\d]{1,6}|[^a-fA-F\\d])/}]},this.normalizeRules()};r.inherits(p,i),t.CssHighlightRules=p}),ace.define(\"ace/mode/less_highlight_rules\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/mode/text_highlight_rules\",\"ace/mode/css_highlight_rules\"],function(e,t,n){\"use strict\";var r=e(\"../lib/oop\"),i=e(\"./text_highlight_rules\").TextHighlightRules,o=e(\"./css_highlight_rules\"),a=function(){var e=\"@import|@media|@font-face|@keyframes|@-webkit-keyframes|@supports|@charset|@plugin|@namespace|@document|@page|@viewport|@-ms-viewport|or|and|when|not\",t=e.split(\"|\"),n=o.supportType.split(\"|\"),r=this.createKeywordMapper({\"support.constant\":o.supportConstant,keyword:e,\"support.constant.color\":o.supportConstantColor,\"support.constant.fonts\":o.supportConstantFonts},\"identifier\",!0),i=\"\\\\-?(?:(?:[0-9]+)|(?:[0-9]*\\\\.[0-9]+))\";this.$rules={start:[{token:\"comment\",regex:\"\\\\/\\\\/.*$\"},{token:\"comment\",regex:\"\\\\/\\\\*\",next:\"comment\"},{token:\"string\",regex:'[\"](?:(?:\\\\\\\\.)|(?:[^\"\\\\\\\\]))*?[\"]'},{token:\"string\",regex:\"['](?:(?:\\\\\\\\.)|(?:[^'\\\\\\\\]))*?[']\"},{token:[\"constant.numeric\",\"keyword\"],regex:\"(\"+i+\")(ch|cm|deg|em|ex|fr|gd|grad|Hz|in|kHz|mm|ms|pc|pt|px|rad|rem|s|turn|vh|vm|vw|%)\"},{token:\"constant.numeric\",regex:\"#[a-f0-9]{6}\"},{token:\"constant.numeric\",regex:\"#[a-f0-9]{3}\"},{token:\"constant.numeric\",regex:i},{token:[\"support.function\",\"paren.lparen\",\"string\",\"paren.rparen\"],regex:\"(url)(\\\\()(.*)(\\\\))\"},{token:[\"support.function\",\"paren.lparen\"],regex:\"(:extend|[a-z0-9_\\\\-]+)(\\\\()\"},{token:function(e){return t.indexOf(e.toLowerCase())>-1?\"keyword\":\"variable\"},regex:\"[@\\\\$][a-z0-9_\\\\-@\\\\$]*\\\\b\"},{token:\"variable\",regex:\"[@\\\\$]\\\\{[a-z0-9_\\\\-@\\\\$]*\\\\}\"},{token:function(e,t){return n.indexOf(e.toLowerCase())>-1?[\"support.type.property\",\"text\"]:[\"support.type.unknownProperty\",\"text\"]},regex:\"([a-z0-9-_]+)(\\\\s*:)\"},{token:\"keyword\",regex:\"&\"},{token:r,regex:\"\\\\-?[@a-z_][@a-z0-9_\\\\-]*\"},{token:\"variable.language\",regex:\"#[a-z0-9-_]+\"},{token:\"variable.language\",regex:\"\\\\.[a-z0-9-_]+\"},{token:\"variable.language\",regex:\":[a-z_][a-z0-9-_]*\"},{token:\"constant\",regex:\"[a-z0-9-_]+\"},{token:\"keyword.operator\",regex:\"<|>|<=|>=|=|!=|-|%|\\\\+|\\\\*\"},{token:\"paren.lparen\",regex:\"[[({]\"},{token:\"paren.rparen\",regex:\"[\\\\])}]\"},{token:\"text\",regex:\"\\\\s+\"},{caseInsensitive:!0}],comment:[{token:\"comment\",regex:\"\\\\*\\\\/\",next:\"start\"},{defaultToken:\"comment\"}]},this.normalizeRules()};r.inherits(a,i),t.LessHighlightRules=a}),ace.define(\"ace/mode/matching_brace_outdent\",[\"require\",\"exports\",\"module\",\"ace/range\"],function(e,t,n){\"use strict\";var r=e(\"../range\").Range,i=function(){};(function(){this.checkOutdent=function(e,t){return!!/^\\s+$/.test(e)&&/^\\s*\\}/.test(t)},this.autoOutdent=function(e,t){var n=e.getLine(t),i=n.match(/^(\\s*\\})/);if(!i)return 0;var o=i[1].length,a=e.findMatchingBracket({row:t,column:o});if(!a||a.row==t)return 0;var s=this.$getIndent(e.getLine(a.row));e.replace(new r(t,0,t,o-1),s)},this.$getIndent=function(e){return e.match(/^\\s*/)[0]}}).call(i.prototype),t.MatchingBraceOutdent=i}),ace.define(\"ace/mode/behaviour/css\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/mode/behaviour\",\"ace/mode/behaviour/cstyle\",\"ace/token_iterator\"],function(e,t,n){\"use strict\";var r=e(\"../../lib/oop\"),i=(e(\"../behaviour\").Behaviour,e(\"./cstyle\").CstyleBehaviour),o=e(\"../../token_iterator\").TokenIterator,a=function(){this.inherit(i),this.add(\"colon\",\"insertion\",function(e,t,n,r,i){if(\":\"===i){var a=n.getCursorPosition(),s=new o(r,a.row,a.column),l=s.getCurrentToken();if(l&&l.value.match(/\\s+/)&&(l=s.stepBackward()),l&&\"support.type\"===l.type){var c=r.doc.getLine(a.row),u=c.substring(a.column,a.column+1);if(\":\"===u)return{text:\"\",selection:[1,1]};if(!c.substring(a.column).match(/^\\s*;/))return{text:\":;\",selection:[1,1]}}}}),this.add(\"colon\",\"deletion\",function(e,t,n,r,i){var a=r.doc.getTextRange(i);if(!i.isMultiLine()&&\":\"===a){var s=n.getCursorPosition(),l=new o(r,s.row,s.column),c=l.getCurrentToken();if(c&&c.value.match(/\\s+/)&&(c=l.stepBackward()),c&&\"support.type\"===c.type){var u=r.doc.getLine(i.start.row),d=u.substring(i.end.column,i.end.column+1);if(\";\"===d)return i.end.column++,i}}}),this.add(\"semicolon\",\"insertion\",function(e,t,n,r,i){if(\";\"===i){var o=n.getCursorPosition(),a=r.doc.getLine(o.row),s=a.substring(o.column,o.column+1);if(\";\"===s)return{text:\"\",selection:[1,1]}}})};r.inherits(a,i),t.CssBehaviour=a}),ace.define(\"ace/mode/css_completions\",[\"require\",\"exports\",\"module\"],function(e,t,n){\"use strict\";var r={background:{\"#$0\":1},\"background-color\":{\"#$0\":1,transparent:1,fixed:1},\"background-image\":{\"url('/$0')\":1},\"background-repeat\":{repeat:1,\"repeat-x\":1,\"repeat-y\":1,\"no-repeat\":1,inherit:1},\"background-position\":{bottom:2,center:2,left:2,right:2,top:2,inherit:2},\"background-attachment\":{scroll:1,fixed:1},\"background-size\":{cover:1,contain:1},\"background-clip\":{\"border-box\":1,\"padding-box\":1,\"content-box\":1},\"background-origin\":{\"border-box\":1,\"padding-box\":1,\"content-box\":1},border:{\"solid $0\":1,\"dashed $0\":1,\"dotted $0\":1,\"#$0\":1},\"border-color\":{\"#$0\":1},\"border-style\":{solid:2,dashed:2,dotted:2,double:2,groove:2,hidden:2,inherit:2,inset:2,none:2,outset:2,ridged:2},\"border-collapse\":{collapse:1,separate:1},bottom:{px:1,em:1,\"%\":1},clear:{left:1,right:1,both:1,none:1},color:{\"#$0\":1,\"rgb(#$00,0,0)\":1},cursor:{default:1,pointer:1,move:1,text:1,wait:1,help:1,progress:1,\"n-resize\":1,\"ne-resize\":1,\"e-resize\":1,\"se-resize\":1,\"s-resize\":1,\"sw-resize\":1,\"w-resize\":1,\"nw-resize\":1},display:{none:1,block:1,inline:1,\"inline-block\":1,\"table-cell\":1},\"empty-cells\":{show:1,hide:1},float:{left:1,right:1,none:1},\"font-family\":{Arial:2,\"Comic Sans MS\":2,Consolas:2,\"Courier New\":2,Courier:2,Georgia:2,Monospace:2,\"Sans-Serif\":2,\"Segoe UI\":2,Tahoma:2,\"Times New Roman\":2,\"Trebuchet MS\":2,Verdana:1},\"font-size\":{px:1,em:1,\"%\":1},\"font-weight\":{bold:1,normal:1},\"font-style\":{italic:1,normal:1},\"font-variant\":{normal:1,\"small-caps\":1},height:{px:1,em:1,\"%\":1},left:{px:1,em:1,\"%\":1},\"letter-spacing\":{normal:1},\"line-height\":{normal:1},\"list-style-type\":{none:1,disc:1,circle:1,square:1,decimal:1,\"decimal-leading-zero\":1,\"lower-roman\":1,\"upper-roman\":1,\"lower-greek\":1,\"lower-latin\":1,\"upper-latin\":1,georgian:1,\"lower-alpha\":1,\"upper-alpha\":1},margin:{px:1,em:1,\"%\":1},\"margin-right\":{px:1,em:1,\"%\":1},\"margin-left\":{px:1,em:1,\"%\":1},\"margin-top\":{px:1,em:1,\"%\":1},\"margin-bottom\":{px:1,em:1,\"%\":1},\"max-height\":{px:1,em:1,\"%\":1},\"max-width\":{px:1,em:1,\"%\":1},\"min-height\":{px:1,em:1,\"%\":1},\"min-width\":{px:1,em:1,\"%\":1},overflow:{hidden:1,visible:1,auto:1,scroll:1},\"overflow-x\":{hidden:1,visible:1,auto:1,scroll:1},\"overflow-y\":{hidden:1,visible:1,auto:1,scroll:1},padding:{px:1,em:1,\"%\":1},\"padding-top\":{px:1,em:1,\"%\":1},\"padding-right\":{px:1,em:1,\"%\":1},\"padding-bottom\":{px:1,em:1,\"%\":1},\"padding-left\":{px:1,em:1,\"%\":1},\"page-break-after\":{auto:1,always:1,avoid:1,left:1,right:1},\"page-break-before\":{auto:1,always:1,avoid:1,left:1,right:1},position:{absolute:1,relative:1,fixed:1,static:1},right:{px:1,em:1,\"%\":1},\"table-layout\":{fixed:1,auto:1},\"text-decoration\":{none:1,underline:1,\"line-through\":1,blink:1},\"text-align\":{left:1,right:1,center:1,justify:1},\"text-transform\":{capitalize:1,uppercase:1,lowercase:1,none:1},top:{px:1,em:1,\"%\":1},\"vertical-align\":{top:1,bottom:1},visibility:{hidden:1,visible:1},\"white-space\":{nowrap:1,normal:1,pre:1,\"pre-line\":1,\"pre-wrap\":1},width:{px:1,em:1,\"%\":1},\"word-spacing\":{normal:1},filter:{\"alpha(opacity=$0100)\":1},\"text-shadow\":{\"$02px 2px 2px #777\":1},\"text-overflow\":{\"ellipsis-word\":1,clip:1,ellipsis:1},\"-moz-border-radius\":1,\"-moz-border-radius-topright\":1,\"-moz-border-radius-bottomright\":1,\"-moz-border-radius-topleft\":1,\"-moz-border-radius-bottomleft\":1,\"-webkit-border-radius\":1,\"-webkit-border-top-right-radius\":1,\"-webkit-border-top-left-radius\":1,\"-webkit-border-bottom-right-radius\":1,\"-webkit-border-bottom-left-radius\":1,\"-moz-box-shadow\":1,\"-webkit-box-shadow\":1,transform:{\"rotate($00deg)\":1,\"skew($00deg)\":1},\"-moz-transform\":{\"rotate($00deg)\":1,\"skew($00deg)\":1},\"-webkit-transform\":{\"rotate($00deg)\":1,\"skew($00deg)\":1}},i=function(){};(function(){this.completionsDefined=!1,this.defineCompletions=function(){if(document){var e=document.createElement(\"c\").style;for(var t in e)if(\"string\"===typeof e[t]){var n=t.replace(/[A-Z]/g,function(e){return\"-\"+e.toLowerCase()});r.hasOwnProperty(n)||(r[n]=1)}}this.completionsDefined=!0},this.getCompletions=function(e,t,n,r){this.completionsDefined||this.defineCompletions();var i=t.getTokenAt(n.row,n.column);if(!i)return[];if(\"ruleset\"===e){var o=t.getLine(n.row).substr(0,n.column);return/:[^;]+$/.test(o)?(/([\\w\\-]+):[^:]*$/.test(o),this.getPropertyValueCompletions(e,t,n,r)):this.getPropertyCompletions(e,t,n,r)}return[]},this.getPropertyCompletions=function(e,t,n,i){var o=Object.keys(r);return o.map(function(e){return{caption:e,snippet:e+\": $0;\",meta:\"property\",score:Number.MAX_VALUE}})},this.getPropertyValueCompletions=function(e,t,n,i){var o=t.getLine(n.row).substr(0,n.column),a=(/([\\w\\-]+):[^:]*$/.exec(o)||{})[1];if(!a)return[];var s=[];return a in r&&\"object\"===typeof r[a]&&(s=Object.keys(r[a])),s.map(function(e){return{caption:e,snippet:e,meta:\"property value\",score:Number.MAX_VALUE}})}}).call(i.prototype),t.CssCompletions=i}),ace.define(\"ace/mode/folding/cstyle\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/range\",\"ace/mode/folding/fold_mode\"],function(e,t,n){\"use strict\";var r=e(\"../../lib/oop\"),i=e(\"../../range\").Range,o=e(\"./fold_mode\").FoldMode,a=t.FoldMode=function(e){e&&(this.foldingStartMarker=new RegExp(this.foldingStartMarker.source.replace(/\\|[^|]*?$/,\"|\"+e.start)),this.foldingStopMarker=new RegExp(this.foldingStopMarker.source.replace(/\\|[^|]*?$/,\"|\"+e.end)))};r.inherits(a,o),function(){this.foldingStartMarker=/([\\{\\[\\(])[^\\}\\]\\)]*$|^\\s*(\\/\\*)/,this.foldingStopMarker=/^[^\\[\\{\\(]*([\\}\\]\\)])|^[\\s\\*]*(\\*\\/)/,this.singleLineBlockCommentRe=/^\\s*(\\/\\*).*\\*\\/\\s*$/,this.tripleStarBlockCommentRe=/^\\s*(\\/\\*\\*\\*).*\\*\\/\\s*$/,this.startRegionRe=/^\\s*(\\/\\*|\\/\\/)#?region\\b/,this._getFoldWidgetBase=this.getFoldWidget,this.getFoldWidget=function(e,t,n){var r=e.getLine(n);if(this.singleLineBlockCommentRe.test(r)&&!this.startRegionRe.test(r)&&!this.tripleStarBlockCommentRe.test(r))return\"\";var i=this._getFoldWidgetBase(e,t,n);return!i&&this.startRegionRe.test(r)?\"start\":i},this.getFoldWidgetRange=function(e,t,n,r){var i=e.getLine(n);if(this.startRegionRe.test(i))return this.getCommentRegionBlock(e,i,n);var o=i.match(this.foldingStartMarker);if(o){var a=o.index;if(o[1])return this.openingBracketBlock(e,o[1],n,a);var s=e.getCommentFoldRange(n,a+o[0].length,1);return s&&!s.isMultiLine()&&(r?s=this.getSectionRange(e,n):\"all\"!=t&&(s=null)),s}if(\"markbegin\"!==t){o=i.match(this.foldingStopMarker);if(o){a=o.index+o[0].length;return o[1]?this.closingBracketBlock(e,o[1],n,a):e.getCommentFoldRange(n,a,-1)}}},this.getSectionRange=function(e,t){var n=e.getLine(t),r=n.search(/\\S/),o=t,a=n.length;t+=1;var s=t,l=e.getLength();while(++t<l){n=e.getLine(t);var c=n.search(/\\S/);if(-1!==c){if(r>c)break;var u=this.getFoldWidgetRange(e,\"all\",t);if(u){if(u.start.row<=o)break;if(u.isMultiLine())t=u.end.row;else if(r==c)break}s=t}}return new i(o,a,s,e.getLine(s).length)},this.getCommentRegionBlock=function(e,t,n){var r=t.search(/\\s*$/),o=e.getLength(),a=n,s=/^\\s*(?:\\/\\*|\\/\\/|--)#?(end)?region\\b/,l=1;while(++n<o){t=e.getLine(n);var c=s.exec(t);if(c&&(c[1]?l--:l++,!l))break}var u=n;if(u>a)return new i(a,r,u,t.length)}}.call(a.prototype)}),ace.define(\"ace/mode/less\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/mode/text\",\"ace/mode/less_highlight_rules\",\"ace/mode/matching_brace_outdent\",\"ace/mode/behaviour/css\",\"ace/mode/css_completions\",\"ace/mode/folding/cstyle\"],function(e,t,n){\"use strict\";var r=e(\"../lib/oop\"),i=e(\"./text\").Mode,o=e(\"./less_highlight_rules\").LessHighlightRules,a=e(\"./matching_brace_outdent\").MatchingBraceOutdent,s=e(\"./behaviour/css\").CssBehaviour,l=e(\"./css_completions\").CssCompletions,c=e(\"./folding/cstyle\").FoldMode,u=function(){this.HighlightRules=o,this.$outdent=new a,this.$behaviour=new s,this.$completer=new l,this.foldingRules=new c};r.inherits(u,i),function(){this.lineCommentStart=\"//\",this.blockComment={start:\"/*\",end:\"*/\"},this.getNextLineIndent=function(e,t,n){var r=this.$getIndent(t),i=this.getTokenizer().getLineTokens(t,e).tokens;if(i.length&&\"comment\"==i[i.length-1].type)return r;var o=t.match(/^.*\\{\\s*$/);return o&&(r+=n),r},this.checkOutdent=function(e,t,n){return this.$outdent.checkOutdent(t,n)},this.autoOutdent=function(e,t,n){this.$outdent.autoOutdent(t,n)},this.getCompletions=function(e,t,n,r){return this.$completer.getCompletions(\"ruleset\",t,n,r)},this.$id=\"ace/mode/less\"}.call(u.prototype),t.Mode=u})},\"061c\":function(e,t,n){(function(){var e=\"ace\",t=function(){return this}();if(t||\"undefined\"==typeof window||(t=window),e||\"undefined\"===typeof acequirejs){var n=function(e,t,r){\"string\"===typeof e?(2==arguments.length&&(r=t),n.modules[e]||(n.payloads[e]=r,n.modules[e]=null)):n.original?n.original.apply(this,arguments):(console.error(\"dropping module because define wasn't a string.\"),console.trace())};n.modules={},n.payloads={};var r=function(e,t,n){if(\"string\"===typeof t){var r=a(e,t);if(void 0!=r)return n&&n(),r}else if(\"[object Array]\"===Object.prototype.toString.call(t)){for(var o=[],s=0,l=t.length;s<l;++s){var c=a(e,t[s]);if(void 0==c&&i.original)return;o.push(c)}return n&&n.apply(null,o)||!0}},i=function(e,t){var n=r(\"\",e,t);return void 0==n&&i.original?i.original.apply(this,arguments):n},o=function(e,t){if(-1!==t.indexOf(\"!\")){var n=t.split(\"!\");return o(e,n[0])+\"!\"+o(e,n[1])}if(\".\"==t.charAt(0)){var r=e.split(\"/\").slice(0,-1).join(\"/\");t=r+\"/\"+t;while(-1!==t.indexOf(\".\")&&i!=t){var i=t;t=t.replace(/\\/\\.\\//,\"/\").replace(/[^\\/]+\\/\\.\\.\\//,\"\")}}return t},a=function(e,t){t=o(e,t);var i=n.modules[t];if(!i){if(i=n.payloads[t],\"function\"===typeof i){var a={},s={id:t,uri:\"\",exports:a,packaged:!0},l=function(e,n){return r(t,e,n)},c=i(l,a,s);a=c||s.exports,n.modules[t]=a,delete n.payloads[t]}i=n.modules[t]=a||i}return i};s(e)}function s(e){var r=t;e&&(t[e]||(t[e]={}),r=t[e]),r.define&&r.define.packaged||(n.original=r.define,r.define=n,r.define.packaged=!0),r.acequire&&r.acequire.packaged||(i.original=r.acequire,r.acequire=i,r.acequire.packaged=!0)}})(),ace.define(\"ace/lib/regexp\",[\"require\",\"exports\",\"module\"],function(e,t,n){\"use strict\";var r={exec:RegExp.prototype.exec,test:RegExp.prototype.test,match:String.prototype.match,replace:String.prototype.replace,split:String.prototype.split},i=void 0===r.exec.call(/()??/,\"\")[1],o=function(){var e=/^/g;return r.test.call(e,\"\"),!e.lastIndex}();function a(e){return(e.global?\"g\":\"\")+(e.ignoreCase?\"i\":\"\")+(e.multiline?\"m\":\"\")+(e.extended?\"x\":\"\")+(e.sticky?\"y\":\"\")}function s(e,t,n){if(Array.prototype.indexOf)return e.indexOf(t,n);for(var r=n||0;r<e.length;r++)if(e[r]===t)return r;return-1}o&&i||(RegExp.prototype.exec=function(e){var t,n,l=r.exec.apply(this,arguments);if(\"string\"==typeof e&&l){if(!i&&l.length>1&&s(l,\"\")>-1&&(n=RegExp(this.source,r.replace.call(a(this),\"g\",\"\")),r.replace.call(e.slice(l.index),n,function(){for(var e=1;e<arguments.length-2;e++)void 0===arguments[e]&&(l[e]=void 0)})),this._xregexp&&this._xregexp.captureNames)for(var c=1;c<l.length;c++)t=this._xregexp.captureNames[c-1],t&&(l[t]=l[c]);!o&&this.global&&!l[0].length&&this.lastIndex>l.index&&this.lastIndex--}return l},o||(RegExp.prototype.test=function(e){var t=r.exec.call(this,e);return t&&this.global&&!t[0].length&&this.lastIndex>t.index&&this.lastIndex--,!!t}))}),ace.define(\"ace/lib/es5-shim\",[\"require\",\"exports\",\"module\"],function(e,t,n){function r(){}Function.prototype.bind||(Function.prototype.bind=function(e){var t=this;if(\"function\"!=typeof t)throw new TypeError(\"Function.prototype.bind called on incompatible \"+t);var n=h.call(arguments,1),i=function(){if(this instanceof i){var r=t.apply(this,n.concat(h.call(arguments)));return Object(r)===r?r:this}return t.apply(e,n.concat(h.call(arguments)))};return t.prototype&&(r.prototype=t.prototype,i.prototype=new r,r.prototype=null),i});var i,o,a,s,l,c=Function.prototype.call,u=Array.prototype,d=Object.prototype,h=u.slice,p=c.bind(d.toString),m=c.bind(d.hasOwnProperty);if((l=m(d,\"__defineGetter__\"))&&(i=c.bind(d.__defineGetter__),o=c.bind(d.__defineSetter__),a=c.bind(d.__lookupGetter__),s=c.bind(d.__lookupSetter__)),2!=[1,2].splice(0).length)if(function(){function e(e){var t=new Array(e+2);return t[0]=t[1]=0,t}var t,n=[];if(n.splice.apply(n,e(20)),n.splice.apply(n,e(26)),t=n.length,n.splice(5,0,\"XXX\"),n.length,t+1==n.length)return!0}()){var f=Array.prototype.splice;Array.prototype.splice=function(e,t){return arguments.length?f.apply(this,[void 0===e?0:e,void 0===t?this.length-e:t].concat(h.call(arguments,2))):[]}}else Array.prototype.splice=function(e,t){var n=this.length;e>0?e>n&&(e=n):void 0==e?e=0:e<0&&(e=Math.max(n+e,0)),e+t<n||(t=n-e);var r=this.slice(e,e+t),i=h.call(arguments,2),o=i.length;if(e===n)o&&this.push.apply(this,i);else{var a=Math.min(t,n-e),s=e+a,l=s+o-a,c=n-s,u=n-a;if(l<s)for(var d=0;d<c;++d)this[l+d]=this[s+d];else if(l>s)for(d=c;d--;)this[l+d]=this[s+d];if(o&&e===u)this.length=u,this.push.apply(this,i);else for(this.length=u+o,d=0;d<o;++d)this[e+d]=i[d]}return r};Array.isArray||(Array.isArray=function(e){return\"[object Array]\"==p(e)});var g,b=Object(\"a\"),v=\"a\"!=b[0]||!(0 in b);if(Array.prototype.forEach||(Array.prototype.forEach=function(e){var t=M(this),n=v&&\"[object String]\"==p(this)?this.split(\"\"):t,r=arguments[1],i=-1,o=n.length>>>0;if(\"[object Function]\"!=p(e))throw new TypeError;while(++i<o)i in n&&e.call(r,n[i],i,t)}),Array.prototype.map||(Array.prototype.map=function(e){var t=M(this),n=v&&\"[object String]\"==p(this)?this.split(\"\"):t,r=n.length>>>0,i=Array(r),o=arguments[1];if(\"[object Function]\"!=p(e))throw new TypeError(e+\" is not a function\");for(var a=0;a<r;a++)a in n&&(i[a]=e.call(o,n[a],a,t));return i}),Array.prototype.filter||(Array.prototype.filter=function(e){var t,n=M(this),r=v&&\"[object String]\"==p(this)?this.split(\"\"):n,i=r.length>>>0,o=[],a=arguments[1];if(\"[object Function]\"!=p(e))throw new TypeError(e+\" is not a function\");for(var s=0;s<i;s++)s in r&&(t=r[s],e.call(a,t,s,n)&&o.push(t));return o}),Array.prototype.every||(Array.prototype.every=function(e){var t=M(this),n=v&&\"[object String]\"==p(this)?this.split(\"\"):t,r=n.length>>>0,i=arguments[1];if(\"[object Function]\"!=p(e))throw new TypeError(e+\" is not a function\");for(var o=0;o<r;o++)if(o in n&&!e.call(i,n[o],o,t))return!1;return!0}),Array.prototype.some||(Array.prototype.some=function(e){var t=M(this),n=v&&\"[object String]\"==p(this)?this.split(\"\"):t,r=n.length>>>0,i=arguments[1];if(\"[object Function]\"!=p(e))throw new TypeError(e+\" is not a function\");for(var o=0;o<r;o++)if(o in n&&e.call(i,n[o],o,t))return!0;return!1}),Array.prototype.reduce||(Array.prototype.reduce=function(e){var t=M(this),n=v&&\"[object String]\"==p(this)?this.split(\"\"):t,r=n.length>>>0;if(\"[object Function]\"!=p(e))throw new TypeError(e+\" is not a function\");if(!r&&1==arguments.length)throw new TypeError(\"reduce of empty array with no initial value\");var i,o=0;if(arguments.length>=2)i=arguments[1];else do{if(o in n){i=n[o++];break}if(++o>=r)throw new TypeError(\"reduce of empty array with no initial value\")}while(1);for(;o<r;o++)o in n&&(i=e.call(void 0,i,n[o],o,t));return i}),Array.prototype.reduceRight||(Array.prototype.reduceRight=function(e){var t=M(this),n=v&&\"[object String]\"==p(this)?this.split(\"\"):t,r=n.length>>>0;if(\"[object Function]\"!=p(e))throw new TypeError(e+\" is not a function\");if(!r&&1==arguments.length)throw new TypeError(\"reduceRight of empty array with no initial value\");var i,o=r-1;if(arguments.length>=2)i=arguments[1];else do{if(o in n){i=n[o--];break}if(--o<0)throw new TypeError(\"reduceRight of empty array with no initial value\")}while(1);do{o in this&&(i=e.call(void 0,i,n[o],o,t))}while(o--);return i}),Array.prototype.indexOf&&-1==[0,1].indexOf(1,2)||(Array.prototype.indexOf=function(e){var t=v&&\"[object String]\"==p(this)?this.split(\"\"):M(this),n=t.length>>>0;if(!n)return-1;var r=0;for(arguments.length>1&&(r=D(arguments[1])),r=r>=0?r:Math.max(0,n+r);r<n;r++)if(r in t&&t[r]===e)return r;return-1}),Array.prototype.lastIndexOf&&-1==[0,1].lastIndexOf(0,-3)||(Array.prototype.lastIndexOf=function(e){var t=v&&\"[object String]\"==p(this)?this.split(\"\"):M(this),n=t.length>>>0;if(!n)return-1;var r=n-1;for(arguments.length>1&&(r=Math.min(r,D(arguments[1]))),r=r>=0?r:n-Math.abs(r);r>=0;r--)if(r in t&&e===t[r])return r;return-1}),Object.getPrototypeOf||(Object.getPrototypeOf=function(e){return e.__proto__||(e.constructor?e.constructor.prototype:d)}),!Object.getOwnPropertyDescriptor){var k=\"Object.getOwnPropertyDescriptor called on a non-object: \";Object.getOwnPropertyDescriptor=function(e,t){if(\"object\"!=typeof e&&\"function\"!=typeof e||null===e)throw new TypeError(k+e);if(m(e,t)){var n;if(n={enumerable:!0,configurable:!0},l){var r=e.__proto__;e.__proto__=d;var i=a(e,t),o=s(e,t);if(e.__proto__=r,i||o)return i&&(n.get=i),o&&(n.set=o),n}return n.value=e[t],n}}}(Object.getOwnPropertyNames||(Object.getOwnPropertyNames=function(e){return Object.keys(e)}),Object.create)||(g=null===Object.prototype.__proto__?function(){return{__proto__:null}}:function(){var e={};for(var t in e)e[t]=null;return e.constructor=e.hasOwnProperty=e.propertyIsEnumerable=e.isPrototypeOf=e.toLocaleString=e.toString=e.valueOf=e.__proto__=null,e},Object.create=function(e,t){var n;if(null===e)n=g();else{if(\"object\"!=typeof e)throw new TypeError(\"typeof prototype[\"+typeof e+\"] != 'object'\");var r=function(){};r.prototype=e,n=new r,n.__proto__=e}return void 0!==t&&Object.defineProperties(n,t),n});function y(e){try{return Object.defineProperty(e,\"sentinel\",{}),\"sentinel\"in e}catch(t){}}if(Object.defineProperty){var w=y({}),x=\"undefined\"==typeof document||y(document.createElement(\"div\"));if(!w||!x)var E=Object.defineProperty}if(!Object.defineProperty||E){var C=\"Property description must be an object: \",T=\"Object.defineProperty called on non-object: \",A=\"getters & setters can not be defined on this javascript engine\";Object.defineProperty=function(e,t,n){if(\"object\"!=typeof e&&\"function\"!=typeof e||null===e)throw new TypeError(T+e);if(\"object\"!=typeof n&&\"function\"!=typeof n||null===n)throw new TypeError(C+n);if(E)try{return E.call(Object,e,t,n)}catch(c){}if(m(n,\"value\"))if(l&&(a(e,t)||s(e,t))){var r=e.__proto__;e.__proto__=d,delete e[t],e[t]=n.value,e.__proto__=r}else e[t]=n.value;else{if(!l)throw new TypeError(A);m(n,\"get\")&&i(e,t,n.get),m(n,\"set\")&&o(e,t,n.set)}return e}}Object.defineProperties||(Object.defineProperties=function(e,t){for(var n in t)m(t,n)&&Object.defineProperty(e,n,t[n]);return e}),Object.seal||(Object.seal=function(e){return e}),Object.freeze||(Object.freeze=function(e){return e});try{Object.freeze(function(){})}catch(O){Object.freeze=function(e){return function(t){return\"function\"==typeof t?t:e(t)}}(Object.freeze)}if(Object.preventExtensions||(Object.preventExtensions=function(e){return e}),Object.isSealed||(Object.isSealed=function(e){return!1}),Object.isFrozen||(Object.isFrozen=function(e){return!1}),Object.isExtensible||(Object.isExtensible=function(e){if(Object(e)===e)throw new TypeError;var t=\"\";while(m(e,t))t+=\"?\";e[t]=!0;var n=m(e,t);return delete e[t],n}),!Object.keys){var S=!0,_=[\"toString\",\"toLocaleString\",\"valueOf\",\"hasOwnProperty\",\"isPrototypeOf\",\"propertyIsEnumerable\",\"constructor\"],F=_.length;for(var L in{toString:null})S=!1;Object.keys=function(e){if(\"object\"!=typeof e&&\"function\"!=typeof e||null===e)throw new TypeError(\"Object.keys called on a non-object\");var t=[];for(var n in e)m(e,n)&&t.push(n);if(S)for(var r=0,i=F;r<i;r++){var o=_[r];m(e,o)&&t.push(o)}return t}}Date.now||(Date.now=function(){return(new Date).getTime()});var R=\"\\t\\n\\v\\f\\r   ᠎             　\\u2028\\u2029\\ufeff\";if(!String.prototype.trim||R.trim()){R=\"[\"+R+\"]\";var $=new RegExp(\"^\"+R+R+\"*\"),B=new RegExp(R+R+\"*$\");String.prototype.trim=function(){return String(this).replace($,\"\").replace(B,\"\")}}function D(e){return e=+e,e!==e?e=0:0!==e&&e!==1/0&&e!==-1/0&&(e=(e>0||-1)*Math.floor(Math.abs(e))),e}var M=function(e){if(null==e)throw new TypeError(\"can't convert \"+e+\" to object\");return Object(e)}}),ace.define(\"ace/lib/fixoldbrowsers\",[\"require\",\"exports\",\"module\",\"ace/lib/regexp\",\"ace/lib/es5-shim\"],function(e,t,n){\"use strict\";e(\"./regexp\"),e(\"./es5-shim\")}),ace.define(\"ace/lib/dom\",[\"require\",\"exports\",\"module\"],function(e,t,n){\"use strict\";var r=\"http://www.w3.org/1999/xhtml\";t.getDocumentHead=function(e){return e||(e=document),e.head||e.getElementsByTagName(\"head\")[0]||e.documentElement},t.createElement=function(e,t){return document.createElementNS?document.createElementNS(t||r,e):document.createElement(e)},t.hasCssClass=function(e,t){var n=(e.className+\"\").split(/\\s+/g);return-1!==n.indexOf(t)},t.addCssClass=function(e,n){t.hasCssClass(e,n)||(e.className+=\" \"+n)},t.removeCssClass=function(e,t){var n=e.className.split(/\\s+/g);while(1){var r=n.indexOf(t);if(-1==r)break;n.splice(r,1)}e.className=n.join(\" \")},t.toggleCssClass=function(e,t){var n=e.className.split(/\\s+/g),r=!0;while(1){var i=n.indexOf(t);if(-1==i)break;r=!1,n.splice(i,1)}return r&&n.push(t),e.className=n.join(\" \"),r},t.setCssClass=function(e,n,r){r?t.addCssClass(e,n):t.removeCssClass(e,n)},t.hasCssString=function(e,t){var n,r=0;if(t=t||document,t.createStyleSheet&&(n=t.styleSheets)){while(r<n.length)if(n[r++].owningElement.id===e)return!0}else if(n=t.getElementsByTagName(\"style\"))while(r<n.length)if(n[r++].id===e)return!0;return!1},t.importCssString=function(e,n,r){if(r=r||document,n&&t.hasCssString(n,r))return null;var i;n&&(e+=\"\\n/*# sourceURL=ace/css/\"+n+\" */\"),r.createStyleSheet?(i=r.createStyleSheet(),i.cssText=e,n&&(i.owningElement.id=n)):(i=t.createElement(\"style\"),i.appendChild(r.createTextNode(e)),n&&(i.id=n),t.getDocumentHead(r).appendChild(i))},t.importCssStylsheet=function(e,n){if(n.createStyleSheet)n.createStyleSheet(e);else{var r=t.createElement(\"link\");r.rel=\"stylesheet\",r.href=e,t.getDocumentHead(n).appendChild(r)}},t.getInnerWidth=function(e){return parseInt(t.computedStyle(e,\"paddingLeft\"),10)+parseInt(t.computedStyle(e,\"paddingRight\"),10)+e.clientWidth},t.getInnerHeight=function(e){return parseInt(t.computedStyle(e,\"paddingTop\"),10)+parseInt(t.computedStyle(e,\"paddingBottom\"),10)+e.clientHeight},t.scrollbarWidth=function(e){var n=t.createElement(\"ace_inner\");n.style.width=\"100%\",n.style.minWidth=\"0px\",n.style.height=\"200px\",n.style.display=\"block\";var r=t.createElement(\"ace_outer\"),i=r.style;i.position=\"absolute\",i.left=\"-10000px\",i.overflow=\"hidden\",i.width=\"200px\",i.minWidth=\"0px\",i.height=\"150px\",i.display=\"block\",r.appendChild(n);var o=e.documentElement;o.appendChild(r);var a=n.offsetWidth;i.overflow=\"scroll\";var s=n.offsetWidth;return a==s&&(s=r.clientWidth),o.removeChild(r),a-s},\"undefined\"!=typeof document?(void 0!==window.pageYOffset?(t.getPageScrollTop=function(){return window.pageYOffset},t.getPageScrollLeft=function(){return window.pageXOffset}):(t.getPageScrollTop=function(){return document.body.scrollTop},t.getPageScrollLeft=function(){return document.body.scrollLeft}),window.getComputedStyle?t.computedStyle=function(e,t){return t?(window.getComputedStyle(e,\"\")||{})[t]||\"\":window.getComputedStyle(e,\"\")||{}}:t.computedStyle=function(e,t){return t?e.currentStyle[t]:e.currentStyle},t.setInnerHtml=function(e,t){var n=e.cloneNode(!1);return n.innerHTML=t,e.parentNode.replaceChild(n,e),n},\"textContent\"in document.documentElement?(t.setInnerText=function(e,t){e.textContent=t},t.getInnerText=function(e){return e.textContent}):(t.setInnerText=function(e,t){e.innerText=t},t.getInnerText=function(e){return e.innerText}),t.getParentWindow=function(e){return e.defaultView||e.parentWindow}):t.importCssString=function(){}}),ace.define(\"ace/lib/oop\",[\"require\",\"exports\",\"module\"],function(e,t,n){\"use strict\";t.inherits=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})},t.mixin=function(e,t){for(var n in t)e[n]=t[n];return e},t.implement=function(e,n){t.mixin(e,n)}}),ace.define(\"ace/lib/keys\",[\"require\",\"exports\",\"module\",\"ace/lib/fixoldbrowsers\",\"ace/lib/oop\"],function(e,t,n){\"use strict\";e(\"./fixoldbrowsers\");var r=e(\"./oop\"),i=function(){var e,t,n={MODIFIER_KEYS:{16:\"Shift\",17:\"Ctrl\",18:\"Alt\",224:\"Meta\"},KEY_MODS:{ctrl:1,alt:2,option:2,shift:4,super:8,meta:8,command:8,cmd:8},FUNCTION_KEYS:{8:\"Backspace\",9:\"Tab\",13:\"Return\",19:\"Pause\",27:\"Esc\",32:\"Space\",33:\"PageUp\",34:\"PageDown\",35:\"End\",36:\"Home\",37:\"Left\",38:\"Up\",39:\"Right\",40:\"Down\",44:\"Print\",45:\"Insert\",46:\"Delete\",96:\"Numpad0\",97:\"Numpad1\",98:\"Numpad2\",99:\"Numpad3\",100:\"Numpad4\",101:\"Numpad5\",102:\"Numpad6\",103:\"Numpad7\",104:\"Numpad8\",105:\"Numpad9\",\"-13\":\"NumpadEnter\",112:\"F1\",113:\"F2\",114:\"F3\",115:\"F4\",116:\"F5\",117:\"F6\",118:\"F7\",119:\"F8\",120:\"F9\",121:\"F10\",122:\"F11\",123:\"F12\",144:\"Numlock\",145:\"Scrolllock\"},PRINTABLE_KEYS:{32:\" \",48:\"0\",49:\"1\",50:\"2\",51:\"3\",52:\"4\",53:\"5\",54:\"6\",55:\"7\",56:\"8\",57:\"9\",59:\";\",61:\"=\",65:\"a\",66:\"b\",67:\"c\",68:\"d\",69:\"e\",70:\"f\",71:\"g\",72:\"h\",73:\"i\",74:\"j\",75:\"k\",76:\"l\",77:\"m\",78:\"n\",79:\"o\",80:\"p\",81:\"q\",82:\"r\",83:\"s\",84:\"t\",85:\"u\",86:\"v\",87:\"w\",88:\"x\",89:\"y\",90:\"z\",107:\"+\",109:\"-\",110:\".\",186:\";\",187:\"=\",188:\",\",189:\"-\",190:\".\",191:\"/\",192:\"`\",219:\"[\",220:\"\\\\\",221:\"]\",222:\"'\",111:\"/\",106:\"*\"}};for(t in n.FUNCTION_KEYS)e=n.FUNCTION_KEYS[t].toLowerCase(),n[e]=parseInt(t,10);for(t in n.PRINTABLE_KEYS)e=n.PRINTABLE_KEYS[t].toLowerCase(),n[e]=parseInt(t,10);return r.mixin(n,n.MODIFIER_KEYS),r.mixin(n,n.PRINTABLE_KEYS),r.mixin(n,n.FUNCTION_KEYS),n.enter=n[\"return\"],n.escape=n.esc,n.del=n[\"delete\"],n[173]=\"-\",function(){for(var e=[\"cmd\",\"ctrl\",\"alt\",\"shift\"],t=Math.pow(2,e.length);t--;)n.KEY_MODS[t]=e.filter(function(e){return t&n.KEY_MODS[e]}).join(\"-\")+\"-\"}(),n.KEY_MODS[0]=\"\",n.KEY_MODS[-1]=\"input-\",n}();r.mixin(t,i),t.keyCodeToString=function(e){var t=i[e];return\"string\"!=typeof t&&(t=String.fromCharCode(e)),t.toLowerCase()}}),ace.define(\"ace/lib/useragent\",[\"require\",\"exports\",\"module\"],function(e,t,n){\"use strict\";if(t.OS={LINUX:\"LINUX\",MAC:\"MAC\",WINDOWS:\"WINDOWS\"},t.getOS=function(){return t.isMac?t.OS.MAC:t.isLinux?t.OS.LINUX:t.OS.WINDOWS},\"object\"==typeof navigator){var r=(navigator.platform.match(/mac|win|linux/i)||[\"other\"])[0].toLowerCase(),i=navigator.userAgent;t.isWin=\"win\"==r,t.isMac=\"mac\"==r,t.isLinux=\"linux\"==r,t.isIE=\"Microsoft Internet Explorer\"==navigator.appName||navigator.appName.indexOf(\"MSAppHost\")>=0?parseFloat((i.match(/(?:MSIE |Trident\\/[0-9]+[\\.0-9]+;.*rv:)([0-9]+[\\.0-9]+)/)||[])[1]):parseFloat((i.match(/(?:Trident\\/[0-9]+[\\.0-9]+;.*rv:)([0-9]+[\\.0-9]+)/)||[])[1]),t.isOldIE=t.isIE&&t.isIE<9,t.isGecko=t.isMozilla=(window.Controllers||window.controllers)&&\"Gecko\"===window.navigator.product,t.isOldGecko=t.isGecko&&parseInt((i.match(/rv:(\\d+)/)||[])[1],10)<4,t.isOpera=window.opera&&\"[object Opera]\"==Object.prototype.toString.call(window.opera),t.isWebKit=parseFloat(i.split(\"WebKit/\")[1])||void 0,t.isChrome=parseFloat(i.split(\" Chrome/\")[1])||void 0,t.isAIR=i.indexOf(\"AdobeAIR\")>=0,t.isIPad=i.indexOf(\"iPad\")>=0,t.isChromeOS=i.indexOf(\" CrOS \")>=0,t.isIOS=/iPad|iPhone|iPod/.test(i)&&!window.MSStream,t.isIOS&&(t.isMac=!0)}}),ace.define(\"ace/lib/event\",[\"require\",\"exports\",\"module\",\"ace/lib/keys\",\"ace/lib/useragent\"],function(e,t,n){\"use strict\";var r=e(\"./keys\"),i=e(\"./useragent\"),o=null,a=0;t.addListener=function(e,t,n){if(e.addEventListener)return e.addEventListener(t,n,!1);if(e.attachEvent){var r=function(){n.call(e,window.event)};n._wrapper=r,e.attachEvent(\"on\"+t,r)}},t.removeListener=function(e,t,n){if(e.removeEventListener)return e.removeEventListener(t,n,!1);e.detachEvent&&e.detachEvent(\"on\"+t,n._wrapper||n)},t.stopEvent=function(e){return t.stopPropagation(e),t.preventDefault(e),!1},t.stopPropagation=function(e){e.stopPropagation?e.stopPropagation():e.cancelBubble=!0},t.preventDefault=function(e){e.preventDefault?e.preventDefault():e.returnValue=!1},t.getButton=function(e){return\"dblclick\"==e.type?0:\"contextmenu\"==e.type||i.isMac&&e.ctrlKey&&!e.altKey&&!e.shiftKey?2:e.preventDefault?e.button:{1:0,2:2,4:1}[e.button]},t.capture=function(e,n,r){function i(e){n&&n(e),r&&r(e),t.removeListener(document,\"mousemove\",n,!0),t.removeListener(document,\"mouseup\",i,!0),t.removeListener(document,\"dragstart\",i,!0)}return t.addListener(document,\"mousemove\",n,!0),t.addListener(document,\"mouseup\",i,!0),t.addListener(document,\"dragstart\",i,!0),i},t.addTouchMoveListener=function(e,n){var r,i;t.addListener(e,\"touchstart\",function(e){var t=e.touches,n=t[0];r=n.clientX,i=n.clientY}),t.addListener(e,\"touchmove\",function(e){var t=e.touches;if(!(t.length>1)){var o=t[0];e.wheelX=r-o.clientX,e.wheelY=i-o.clientY,r=o.clientX,i=o.clientY,n(e)}})},t.addMouseWheelListener=function(e,n){\"onmousewheel\"in e?t.addListener(e,\"mousewheel\",function(e){var t=8;void 0!==e.wheelDeltaX?(e.wheelX=-e.wheelDeltaX/t,e.wheelY=-e.wheelDeltaY/t):(e.wheelX=0,e.wheelY=-e.wheelDelta/t),n(e)}):\"onwheel\"in e?t.addListener(e,\"wheel\",function(e){var t=.35;switch(e.deltaMode){case e.DOM_DELTA_PIXEL:e.wheelX=e.deltaX*t||0,e.wheelY=e.deltaY*t||0;break;case e.DOM_DELTA_LINE:case e.DOM_DELTA_PAGE:e.wheelX=5*(e.deltaX||0),e.wheelY=5*(e.deltaY||0);break}n(e)}):t.addListener(e,\"DOMMouseScroll\",function(e){e.axis&&e.axis==e.HORIZONTAL_AXIS?(e.wheelX=5*(e.detail||0),e.wheelY=0):(e.wheelX=0,e.wheelY=5*(e.detail||0)),n(e)})},t.addMultiMouseDownListener=function(e,n,r,o){var a,s,l,c=0,u={2:\"dblclick\",3:\"tripleclick\",4:\"quadclick\"};function d(e){if(0!==t.getButton(e)?c=0:e.detail>1?(c++,c>4&&(c=1)):c=1,i.isIE){var d=Math.abs(e.clientX-a)>5||Math.abs(e.clientY-s)>5;l&&!d||(c=1),l&&clearTimeout(l),l=setTimeout(function(){l=null},n[c-1]||600),1==c&&(a=e.clientX,s=e.clientY)}if(e._clicks=c,r[o](\"mousedown\",e),c>4)c=0;else if(c>1)return r[o](u[c],e)}function h(e){c=2,l&&clearTimeout(l),l=setTimeout(function(){l=null},n[c-1]||600),r[o](\"mousedown\",e),r[o](u[c],e)}Array.isArray(e)||(e=[e]),e.forEach(function(e){t.addListener(e,\"mousedown\",d),i.isOldIE&&t.addListener(e,\"dblclick\",h)})};var s=!i.isMac||!i.isOpera||\"KeyboardEvent\"in window?function(e){return 0|(e.ctrlKey?1:0)|(e.altKey?2:0)|(e.shiftKey?4:0)|(e.metaKey?8:0)}:function(e){return 0|(e.metaKey?1:0)|(e.altKey?2:0)|(e.shiftKey?4:0)|(e.ctrlKey?8:0)};function l(e,t,n){var l=s(t);if(!i.isMac&&o){if(t.getModifierState&&(t.getModifierState(\"OS\")||t.getModifierState(\"Win\"))&&(l|=8),o.altGr){if(3==(3&l))return;o.altGr=0}if(18===n||17===n){var c=\"location\"in t?t.location:t.keyLocation;if(17===n&&1===c)1==o[n]&&(a=t.timeStamp);else if(18===n&&3===l&&2===c){var u=t.timeStamp-a;u<50&&(o.altGr=!0)}}}if(n in r.MODIFIER_KEYS&&(n=-1),8&l&&n>=91&&n<=93&&(n=-1),!l&&13===n){c=\"location\"in t?t.location:t.keyLocation;if(3===c&&(e(t,l,-n),t.defaultPrevented))return}if(i.isChromeOS&&8&l){if(e(t,l,n),t.defaultPrevented)return;l&=-9}return!!(l||n in r.FUNCTION_KEYS||n in r.PRINTABLE_KEYS)&&e(t,l,n)}function c(){o=Object.create(null)}if(t.getModifierString=function(e){return r.KEY_MODS[s(e)]},t.addCommandKeyListener=function(e,n){var r=t.addListener;if(i.isOldGecko||i.isOpera&&!(\"KeyboardEvent\"in window)){var a=null;r(e,\"keydown\",function(e){a=e.keyCode}),r(e,\"keypress\",function(e){return l(n,e,a)})}else{var s=null;r(e,\"keydown\",function(e){o[e.keyCode]=(o[e.keyCode]||0)+1;var t=l(n,e,e.keyCode);return s=e.defaultPrevented,t}),r(e,\"keypress\",function(e){s&&(e.ctrlKey||e.altKey||e.shiftKey||e.metaKey)&&(t.stopEvent(e),s=null)}),r(e,\"keyup\",function(e){o[e.keyCode]=null}),o||(c(),r(window,\"focus\",c))}},\"object\"==typeof window&&window.postMessage&&!i.isOldIE){var u=1;t.nextTick=function(e,n){n=n||window;var r=\"zero-timeout-message-\"+u;t.addListener(n,\"message\",function i(o){o.data==r&&(t.stopPropagation(o),t.removeListener(n,\"message\",i),e())}),n.postMessage(r,\"*\")}}t.nextFrame=\"object\"==typeof window&&(window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame||window.oRequestAnimationFrame),t.nextFrame?t.nextFrame=t.nextFrame.bind(window):t.nextFrame=function(e){setTimeout(e,17)}}),ace.define(\"ace/lib/lang\",[\"require\",\"exports\",\"module\"],function(e,t,n){\"use strict\";t.last=function(e){return e[e.length-1]},t.stringReverse=function(e){return e.split(\"\").reverse().join(\"\")},t.stringRepeat=function(e,t){var n=\"\";while(t>0)1&t&&(n+=e),(t>>=1)&&(e+=e);return n};var r=/^\\s\\s*/,i=/\\s\\s*$/;t.stringTrimLeft=function(e){return e.replace(r,\"\")},t.stringTrimRight=function(e){return e.replace(i,\"\")},t.copyObject=function(e){var t={};for(var n in e)t[n]=e[n];return t},t.copyArray=function(e){for(var t=[],n=0,r=e.length;n<r;n++)e[n]&&\"object\"==typeof e[n]?t[n]=this.copyObject(e[n]):t[n]=e[n];return t},t.deepCopy=function e(t){if(\"object\"!==typeof t||!t)return t;var n;if(Array.isArray(t)){n=[];for(var r=0;r<t.length;r++)n[r]=e(t[r]);return n}if(\"[object Object]\"!==Object.prototype.toString.call(t))return t;for(var r in n={},t)n[r]=e(t[r]);return n},t.arrayToMap=function(e){for(var t={},n=0;n<e.length;n++)t[e[n]]=1;return t},t.createMap=function(e){var t=Object.create(null);for(var n in e)t[n]=e[n];return t},t.arrayRemove=function(e,t){for(var n=0;n<=e.length;n++)t===e[n]&&e.splice(n,1)},t.escapeRegExp=function(e){return e.replace(/([.*+?^${}()|[\\]\\/\\\\])/g,\"\\\\$1\")},t.escapeHTML=function(e){return e.replace(/&/g,\"&#38;\").replace(/\"/g,\"&#34;\").replace(/'/g,\"&#39;\").replace(/</g,\"&#60;\")},t.getMatchOffsets=function(e,t){var n=[];return e.replace(t,function(e){n.push({offset:arguments[arguments.length-2],length:e.length})}),n},t.deferredCall=function(e){var t=null,n=function(){t=null,e()},r=function(e){return r.cancel(),t=setTimeout(n,e||0),r};return r.schedule=r,r.call=function(){return this.cancel(),e(),r},r.cancel=function(){return clearTimeout(t),t=null,r},r.isPending=function(){return t},r},t.delayedCall=function(e,t){var n=null,r=function(){n=null,e()},i=function(e){null==n&&(n=setTimeout(r,e||t))};return i.delay=function(e){n&&clearTimeout(n),n=setTimeout(r,e||t)},i.schedule=i,i.call=function(){this.cancel(),e()},i.cancel=function(){n&&clearTimeout(n),n=null},i.isPending=function(){return n},i}}),ace.define(\"ace/keyboard/textinput_ios\",[\"require\",\"exports\",\"module\",\"ace/lib/event\",\"ace/lib/useragent\",\"ace/lib/dom\",\"ace/lib/lang\",\"ace/lib/keys\"],function(e,t,n){\"use strict\";var r=e(\"../lib/event\"),i=e(\"../lib/useragent\"),o=e(\"../lib/dom\"),a=e(\"../lib/lang\"),s=e(\"../lib/keys\"),l=s.KEY_MODS,c=i.isChrome<18,u=i.isIE,d=function(e,t){var n=o.createElement(\"textarea\");n.className=i.isIOS?\"ace_text-input ace_text-input-ios\":\"ace_text-input\",i.isTouchPad&&n.setAttribute(\"x-palm-disable-auto-cap\",!0),n.setAttribute(\"wrap\",\"off\"),n.setAttribute(\"autocorrect\",\"off\"),n.setAttribute(\"autocapitalize\",\"off\"),n.setAttribute(\"spellcheck\",!1),n.style.opacity=\"0\",e.insertBefore(n,e.firstChild);var d=\"\\n aaaa a\\n\",h=!1,p=!1,m=!1,f=!1,g=\"\",b=!0;try{var v=document.activeElement===n}catch(q){}r.addListener(n,\"blur\",function(e){t.onBlur(e),v=!1}),r.addListener(n,\"focus\",function(e){v=!0,t.onFocus(e),w()}),this.focus=function(){if(g)return n.focus();n.style.position=\"fixed\",n.focus()},this.blur=function(){n.blur()},this.isFocused=function(){return v};var k=a.delayedCall(function(){v&&w(b)}),y=a.delayedCall(function(){f||(n.value=d,v&&w())});function w(e){if(!f){if(f=!0,T)t=0,r=e?0:n.value.length-1;else var t=4,r=5;try{n.setSelectionRange(t,r)}catch(q){}f=!1}}function x(){f||(n.value=d,i.isWebKit&&y.schedule())}i.isWebKit||t.addEventListener(\"changeSelection\",function(){t.selection.isEmpty()!=b&&(b=!b,k.schedule())}),x(),v&&t.onFocus();var E=function(e){return 0===e.selectionStart&&e.selectionEnd===e.value.length},C=function(e){E(n)?(t.selectAll(),w()):T&&w(t.selection.isEmpty())},T=null;this.setInputHandler=function(e){T=e},this.getInputHandler=function(){return T};var A=!1,S=function(e){4===n.selectionStart&&5===n.selectionEnd||(T&&(e=T(e),T=null),m?(w(),e&&t.onPaste(e),m=!1):e==d.substr(0)&&4===n.selectionStart?A?t.execCommand(\"del\",{source:\"ace\"}):t.execCommand(\"backspace\",{source:\"ace\"}):h||(e.substring(0,9)==d&&e.length>d.length?e=e.substr(9):e.substr(0,4)==d.substr(0,4)?e=e.substr(4,e.length-d.length+1):e.charAt(e.length-1)==d.charAt(0)&&(e=e.slice(0,-1)),e==d.charAt(0)||e.charAt(e.length-1)==d.charAt(0)&&(e=e.slice(0,-1)),e&&t.onTextInput(e)),h&&(h=!1),A&&(A=!1))},_=function(e){if(!f){var t=n.value;S(t),x()}},F=function(e,t,n){var r=e.clipboardData||window.clipboardData;if(r&&!c){var i=u||n?\"Text\":\"text/plain\";try{return t?!1!==r.setData(i,t):r.getData(i)}catch(e){if(!n)return F(e,t,!0)}}},L=function(e,o){var a=t.getCopyText();if(!a)return r.preventDefault(e);F(e,a)?(i.isIOS&&(p=o,n.value=\"\\n aa\"+a+\"a a\\n\",n.setSelectionRange(4,4+a.length),h={value:a}),o?t.onCut():t.onCopy(),i.isIOS||r.preventDefault(e)):(h=!0,n.value=a,n.select(),setTimeout(function(){h=!1,x(),w(),o?t.onCut():t.onCopy()}))},R=function(e){L(e,!0)},$=function(e){L(e,!1)},B=function(e){var o=F(e);\"string\"==typeof o?(o&&t.onPaste(o,e),i.isIE&&setTimeout(w),r.preventDefault(e)):(n.value=\"\",m=!0)};r.addCommandKeyListener(n,t.onCommandKey.bind(t)),r.addListener(n,\"select\",C),r.addListener(n,\"input\",_),r.addListener(n,\"cut\",R),r.addListener(n,\"copy\",$),r.addListener(n,\"paste\",B);var D,M=function(e){f||!t.onCompositionStart||t.$readOnly||(f={},f.canUndo=t.session.$undoManager,t.onCompositionStart(),setTimeout(O,0),t.on(\"mousedown\",I),f.canUndo&&!t.selection.isEmpty()&&(t.insert(\"\"),t.session.markUndoGroup(),t.selection.clearSelection()),t.session.markUndoGroup())},O=function(){if(f&&t.onCompositionUpdate&&!t.$readOnly){var e=n.value.replace(/\\x01/g,\"\");if(f.lastValue!==e&&(t.onCompositionUpdate(e),f.lastValue&&t.undo(),f.canUndo&&(f.lastValue=e),f.lastValue)){var r=t.selection.getRange();t.insert(f.lastValue),t.session.markUndoGroup(),f.range=t.selection.getRange(),t.selection.setRange(r),t.selection.clearSelection()}}},I=function(e){if(t.onCompositionEnd&&!t.$readOnly){var r=f;f=!1;var o=setTimeout(function(){o=null;var e=n.value.replace(/\\x01/g,\"\");f||(e==r.lastValue?x():!r.lastValue&&e&&(x(),S(e)))});T=function(e){return o&&clearTimeout(o),e=e.replace(/\\x01/g,\"\"),e==r.lastValue?\"\":(r.lastValue&&o&&t.undo(),e)},t.onCompositionEnd(),t.removeListener(\"mousedown\",I),\"compositionend\"==e.type&&r.range&&t.selection.setRange(r.range);var a=!!i.isChrome&&i.isChrome>=53||!!i.isWebKit&&i.isWebKit>=603;a&&_()}},N=a.delayedCall(O,50);function P(){clearTimeout(D),D=setTimeout(function(){g&&(n.style.cssText=g,g=\"\"),null==t.renderer.$keepTextAreaAtCursor&&(t.renderer.$keepTextAreaAtCursor=!0,t.renderer.$moveTextAreaToCursor())},0)}r.addListener(n,\"compositionstart\",M),i.isGecko?r.addListener(n,\"text\",function(){N.schedule()}):(r.addListener(n,\"keyup\",function(){N.schedule()}),r.addListener(n,\"keydown\",function(){N.schedule()})),r.addListener(n,\"compositionend\",I),this.getElement=function(){return n},this.setReadOnly=function(e){n.readOnly=e},this.onContextMenu=function(e){A=!0,w(t.selection.isEmpty()),t._emit(\"nativecontextmenu\",{target:t,domEvent:e}),this.moveToMouse(e,!0)},this.moveToMouse=function(e,a){g||(g=n.style.cssText),n.style.cssText=(a?\"z-index:100000;\":\"\")+\"height:\"+n.style.height+\";\"+(i.isIE?\"opacity:0.1;\":\"\");var s=t.container.getBoundingClientRect(),l=o.computedStyle(t.container),c=s.top+(parseInt(l.borderTopWidth)||0),u=s.left+(parseInt(s.borderLeftWidth)||0),d=s.bottom-c-n.clientHeight-2,h=function(e){n.style.left=e.clientX-u-2+\"px\",n.style.top=Math.min(e.clientY-c-2,d)+\"px\"};h(e),\"mousedown\"==e.type&&(t.renderer.$keepTextAreaAtCursor&&(t.renderer.$keepTextAreaAtCursor=null),clearTimeout(D),i.isWin&&r.capture(t.container,h,P))},this.onContextMenuClose=P;var j=function(e){t.textInput.onContextMenu(e),P()};if(r.addListener(n,\"mouseup\",j),r.addListener(n,\"mousedown\",function(e){e.preventDefault(),P()}),r.addListener(t.renderer.scroller,\"contextmenu\",j),r.addListener(n,\"contextmenu\",j),i.isIOS){var z=null,W=!1;e.addEventListener(\"keydown\",function(e){z&&clearTimeout(z),W=!0}),e.addEventListener(\"keyup\",function(e){z=setTimeout(function(){W=!1},100)});var H=function(e){if(document.activeElement===n&&!W){if(p)return setTimeout(function(){p=!1},100);var r=n.selectionStart,i=n.selectionEnd;if(n.setSelectionRange(4,5),r==i)switch(r){case 0:t.onCommandKey(null,0,s.up);break;case 1:t.onCommandKey(null,0,s.home);break;case 2:t.onCommandKey(null,l.option,s.left);break;case 4:t.onCommandKey(null,0,s.left);break;case 5:t.onCommandKey(null,0,s.right);break;case 7:t.onCommandKey(null,l.option,s.right);break;case 8:t.onCommandKey(null,0,s.end);break;case 9:t.onCommandKey(null,0,s.down);break}else{switch(i){case 6:t.onCommandKey(null,l.shift,s.right);break;case 7:t.onCommandKey(null,l.shift|l.option,s.right);break;case 8:t.onCommandKey(null,l.shift,s.end);break;case 9:t.onCommandKey(null,l.shift,s.down);break}switch(r){case 0:t.onCommandKey(null,l.shift,s.up);break;case 1:t.onCommandKey(null,l.shift,s.home);break;case 2:t.onCommandKey(null,l.shift|l.option,s.left);break;case 3:t.onCommandKey(null,l.shift,s.left);break}}}};document.addEventListener(\"selectionchange\",H),t.on(\"destroy\",function(){document.removeEventListener(\"selectionchange\",H)})}};t.TextInput=d}),ace.define(\"ace/keyboard/textinput\",[\"require\",\"exports\",\"module\",\"ace/lib/event\",\"ace/lib/useragent\",\"ace/lib/dom\",\"ace/lib/lang\",\"ace/keyboard/textinput_ios\"],function(e,t,n){\"use strict\";var r=e(\"../lib/event\"),i=e(\"../lib/useragent\"),o=e(\"../lib/dom\"),a=e(\"../lib/lang\"),s=i.isChrome<18,l=i.isIE,c=e(\"./textinput_ios\").TextInput,u=function(e,t){if(i.isIOS)return c.call(this,e,t);var n=o.createElement(\"textarea\");n.className=\"ace_text-input\",n.setAttribute(\"wrap\",\"off\"),n.setAttribute(\"autocorrect\",\"off\"),n.setAttribute(\"autocapitalize\",\"off\"),n.setAttribute(\"spellcheck\",!1),n.style.opacity=\"0\",e.insertBefore(n,e.firstChild);var u=\"\\u2028\\u2028\",d=!1,h=!1,p=!1,m=\"\",f=!0;try{var g=document.activeElement===n}catch(P){}r.addListener(n,\"blur\",function(e){t.onBlur(e),g=!1}),r.addListener(n,\"focus\",function(e){g=!0,t.onFocus(e),k()}),this.focus=function(){if(m)return n.focus();var e=n.style.top;n.style.position=\"fixed\",n.style.top=\"0px\",n.focus(),setTimeout(function(){n.style.position=\"\",\"0px\"==n.style.top&&(n.style.top=e)},0)},this.blur=function(){n.blur()},this.isFocused=function(){return g};var b=a.delayedCall(function(){g&&k(f)}),v=a.delayedCall(function(){p||(n.value=u,g&&k())});function k(e){if(!p){if(p=!0,E)var t=0,r=e?0:n.value.length-1;else t=e?2:1,r=2;try{n.setSelectionRange(t,r)}catch(P){}p=!1}}function y(){p||(n.value=u,i.isWebKit&&v.schedule())}i.isWebKit||t.addEventListener(\"changeSelection\",function(){t.selection.isEmpty()!=f&&(f=!f,b.schedule())}),y(),g&&t.onFocus();var w=function(e){return 0===e.selectionStart&&e.selectionEnd===e.value.length},x=function(e){d?d=!1:w(n)?(t.selectAll(),k()):E&&k(t.selection.isEmpty())},E=null;this.setInputHandler=function(e){E=e},this.getInputHandler=function(){return E};var C=!1,T=function(e){E&&(e=E(e),E=null),h?(k(),e&&t.onPaste(e),h=!1):e==u.charAt(0)?C?t.execCommand(\"del\",{source:\"ace\"}):t.execCommand(\"backspace\",{source:\"ace\"}):(e.substring(0,2)==u?e=e.substr(2):e.charAt(0)==u.charAt(0)?e=e.substr(1):e.charAt(e.length-1)==u.charAt(0)&&(e=e.slice(0,-1)),e.charAt(e.length-1)==u.charAt(0)&&(e=e.slice(0,-1)),e&&t.onTextInput(e)),C&&(C=!1)},A=function(e){if(!p){var t=n.value;T(t),y()}},S=function(e,t,n){var r=e.clipboardData||window.clipboardData;if(r&&!s){var i=l||n?\"Text\":\"text/plain\";try{return t?!1!==r.setData(i,t):r.getData(i)}catch(e){if(!n)return S(e,t,!0)}}},_=function(e,i){var o=t.getCopyText();if(!o)return r.preventDefault(e);S(e,o)?(i?t.onCut():t.onCopy(),r.preventDefault(e)):(d=!0,n.value=o,n.select(),setTimeout(function(){d=!1,y(),k(),i?t.onCut():t.onCopy()}))},F=function(e){_(e,!0)},L=function(e){_(e,!1)},R=function(e){var o=S(e);\"string\"==typeof o?(o&&t.onPaste(o,e),i.isIE&&setTimeout(k),r.preventDefault(e)):(n.value=\"\",h=!0)};r.addCommandKeyListener(n,t.onCommandKey.bind(t)),r.addListener(n,\"select\",x),r.addListener(n,\"input\",A),r.addListener(n,\"cut\",F),r.addListener(n,\"copy\",L),r.addListener(n,\"paste\",R),\"oncut\"in n&&\"oncopy\"in n&&\"onpaste\"in n||r.addListener(e,\"keydown\",function(e){if((!i.isMac||e.metaKey)&&e.ctrlKey)switch(e.keyCode){case 67:L(e);break;case 86:R(e);break;case 88:F(e);break}});var $,B=function(e){p||!t.onCompositionStart||t.$readOnly||(p={},p.canUndo=t.session.$undoManager,t.onCompositionStart(),setTimeout(D,0),t.on(\"mousedown\",M),p.canUndo&&!t.selection.isEmpty()&&(t.insert(\"\"),t.session.markUndoGroup(),t.selection.clearSelection()),t.session.markUndoGroup())},D=function(){if(p&&t.onCompositionUpdate&&!t.$readOnly){var e=n.value.replace(/\\u2028/g,\"\");if(p.lastValue!==e&&(t.onCompositionUpdate(e),p.lastValue&&t.undo(),p.canUndo&&(p.lastValue=e),p.lastValue)){var r=t.selection.getRange();t.insert(p.lastValue),t.session.markUndoGroup(),p.range=t.selection.getRange(),t.selection.setRange(r),t.selection.clearSelection()}}},M=function(e){if(t.onCompositionEnd&&!t.$readOnly){var r=p;p=!1;var o=setTimeout(function(){o=null;var e=n.value.replace(/\\u2028/g,\"\");p||(e==r.lastValue?y():!r.lastValue&&e&&(y(),T(e)))});E=function(e){return o&&clearTimeout(o),e=e.replace(/\\u2028/g,\"\"),e==r.lastValue?\"\":(r.lastValue&&o&&t.undo(),e)},t.onCompositionEnd(),t.removeListener(\"mousedown\",M),\"compositionend\"==e.type&&r.range&&t.selection.setRange(r.range);var a=!!i.isChrome&&i.isChrome>=53||!!i.isWebKit&&i.isWebKit>=603;a&&A()}},O=a.delayedCall(D,50);function I(){clearTimeout($),$=setTimeout(function(){m&&(n.style.cssText=m,m=\"\"),null==t.renderer.$keepTextAreaAtCursor&&(t.renderer.$keepTextAreaAtCursor=!0,t.renderer.$moveTextAreaToCursor())},0)}r.addListener(n,\"compositionstart\",B),i.isGecko?r.addListener(n,\"text\",function(){O.schedule()}):(r.addListener(n,\"keyup\",function(){O.schedule()}),r.addListener(n,\"keydown\",function(){O.schedule()})),r.addListener(n,\"compositionend\",M),this.getElement=function(){return n},this.setReadOnly=function(e){n.readOnly=e},this.onContextMenu=function(e){C=!0,k(t.selection.isEmpty()),t._emit(\"nativecontextmenu\",{target:t,domEvent:e}),this.moveToMouse(e,!0)},this.moveToMouse=function(e,a){m||(m=n.style.cssText),n.style.cssText=(a?\"z-index:100000;\":\"\")+\"height:\"+n.style.height+\";\"+(i.isIE?\"opacity:0.1;\":\"\");var s=t.container.getBoundingClientRect(),l=o.computedStyle(t.container),c=s.top+(parseInt(l.borderTopWidth)||0),u=s.left+(parseInt(s.borderLeftWidth)||0),d=s.bottom-c-n.clientHeight-2,h=function(e){n.style.left=e.clientX-u-2+\"px\",n.style.top=Math.min(e.clientY-c-2,d)+\"px\"};h(e),\"mousedown\"==e.type&&(t.renderer.$keepTextAreaAtCursor&&(t.renderer.$keepTextAreaAtCursor=null),clearTimeout($),i.isWin&&r.capture(t.container,h,I))},this.onContextMenuClose=I;var N=function(e){t.textInput.onContextMenu(e),I()};r.addListener(n,\"mouseup\",N),r.addListener(n,\"mousedown\",function(e){e.preventDefault(),I()}),r.addListener(t.renderer.scroller,\"contextmenu\",N),r.addListener(n,\"contextmenu\",N)};t.TextInput=u}),ace.define(\"ace/mouse/default_handlers\",[\"require\",\"exports\",\"module\",\"ace/lib/dom\",\"ace/lib/event\",\"ace/lib/useragent\"],function(e,t,n){\"use strict\";e(\"../lib/dom\"),e(\"../lib/event\");var r=e(\"../lib/useragent\"),i=0,o=250;function a(e){e.$clickSelection=null;var t=e.editor;t.setDefaultHandler(\"mousedown\",this.onMouseDown.bind(e)),t.setDefaultHandler(\"dblclick\",this.onDoubleClick.bind(e)),t.setDefaultHandler(\"tripleclick\",this.onTripleClick.bind(e)),t.setDefaultHandler(\"quadclick\",this.onQuadClick.bind(e)),t.setDefaultHandler(\"mousewheel\",this.onMouseWheel.bind(e)),t.setDefaultHandler(\"touchmove\",this.onTouchMove.bind(e));var n=[\"select\",\"startSelect\",\"selectEnd\",\"selectAllEnd\",\"selectByWordsEnd\",\"selectByLinesEnd\",\"dragWait\",\"dragWaitEnd\",\"focusWait\"];n.forEach(function(t){e[t]=this[t]},this),e.selectByLines=this.extendSelectionBy.bind(e,\"getLineRange\"),e.selectByWords=this.extendSelectionBy.bind(e,\"getWordRange\")}function s(e,t,n,r){return Math.sqrt(Math.pow(n-e,2)+Math.pow(r-t,2))}function l(e,t){if(e.start.row==e.end.row)var n=2*t.column-e.start.column-e.end.column;else if(e.start.row!=e.end.row-1||e.start.column||e.end.column)n=2*t.row-e.start.row-e.end.row;else var n=t.column-4;return n<0?{cursor:e.start,anchor:e.end}:{cursor:e.end,anchor:e.start}}(function(){this.onMouseDown=function(e){var t=e.inSelection(),n=e.getDocumentPosition();this.mousedownEvent=e;var i=this.editor,o=e.getButton();if(0!==o){var a=i.getSelectionRange(),s=a.isEmpty();return i.$blockScrolling++,(s||1==o)&&i.selection.moveToPosition(n),i.$blockScrolling--,void(2==o&&(i.textInput.onContextMenu(e.domEvent),r.isMozilla||e.preventDefault()))}return this.mousedownEvent.time=Date.now(),!t||i.isFocused()||(i.focus(),!this.$focusTimout||this.$clickSelection||i.inMultiSelectMode)?(this.captureMouse(e),this.startSelect(n,e.domEvent._clicks>1),e.preventDefault()):(this.setState(\"focusWait\"),void this.captureMouse(e))},this.startSelect=function(e,t){e=e||this.editor.renderer.screenToTextCoordinates(this.x,this.y);var n=this.editor;n.$blockScrolling++,this.mousedownEvent.getShiftKey()?n.selection.selectToPosition(e):t||n.selection.moveToPosition(e),t||this.select(),n.renderer.scroller.setCapture&&n.renderer.scroller.setCapture(),n.setStyle(\"ace_selecting\"),this.setState(\"select\"),n.$blockScrolling--},this.select=function(){var e,t=this.editor,n=t.renderer.screenToTextCoordinates(this.x,this.y);if(t.$blockScrolling++,this.$clickSelection){var r=this.$clickSelection.comparePoint(n);if(-1==r)e=this.$clickSelection.end;else if(1==r)e=this.$clickSelection.start;else{var i=l(this.$clickSelection,n);n=i.cursor,e=i.anchor}t.selection.setSelectionAnchor(e.row,e.column)}t.selection.selectToPosition(n),t.$blockScrolling--,t.renderer.scrollCursorIntoView()},this.extendSelectionBy=function(e){var t,n=this.editor,r=n.renderer.screenToTextCoordinates(this.x,this.y),i=n.selection[e](r.row,r.column);if(n.$blockScrolling++,this.$clickSelection){var o=this.$clickSelection.comparePoint(i.start),a=this.$clickSelection.comparePoint(i.end);if(-1==o&&a<=0)t=this.$clickSelection.end,i.end.row==r.row&&i.end.column==r.column||(r=i.start);else if(1==a&&o>=0)t=this.$clickSelection.start,i.start.row==r.row&&i.start.column==r.column||(r=i.end);else if(-1==o&&1==a)r=i.end,t=i.start;else{var s=l(this.$clickSelection,r);r=s.cursor,t=s.anchor}n.selection.setSelectionAnchor(t.row,t.column)}n.selection.selectToPosition(r),n.$blockScrolling--,n.renderer.scrollCursorIntoView()},this.selectEnd=this.selectAllEnd=this.selectByWordsEnd=this.selectByLinesEnd=function(){this.$clickSelection=null,this.editor.unsetStyle(\"ace_selecting\"),this.editor.renderer.scroller.releaseCapture&&this.editor.renderer.scroller.releaseCapture()},this.focusWait=function(){var e=s(this.mousedownEvent.x,this.mousedownEvent.y,this.x,this.y),t=Date.now();(e>i||t-this.mousedownEvent.time>this.$focusTimout)&&this.startSelect(this.mousedownEvent.getDocumentPosition())},this.onDoubleClick=function(e){var t=e.getDocumentPosition(),n=this.editor,r=n.session,i=r.getBracketRange(t);i?(i.isEmpty()&&(i.start.column--,i.end.column++),this.setState(\"select\")):(i=n.selection.getWordRange(t.row,t.column),this.setState(\"selectByWords\")),this.$clickSelection=i,this.select()},this.onTripleClick=function(e){var t=e.getDocumentPosition(),n=this.editor;this.setState(\"selectByLines\");var r=n.getSelectionRange();r.isMultiLine()&&r.contains(t.row,t.column)?(this.$clickSelection=n.selection.getLineRange(r.start.row),this.$clickSelection.end=n.selection.getLineRange(r.end.row).end):this.$clickSelection=n.selection.getLineRange(t.row),this.select()},this.onQuadClick=function(e){var t=this.editor;t.selectAll(),this.$clickSelection=t.getSelectionRange(),this.setState(\"selectAll\")},this.onMouseWheel=function(e){if(!e.getAccelKey()){e.getShiftKey()&&e.wheelY&&!e.wheelX&&(e.wheelX=e.wheelY,e.wheelY=0);var t=this.editor;this.$lastScroll||(this.$lastScroll={t:0,vx:0,vy:0,allowed:0});var n=this.$lastScroll,r=e.domEvent.timeStamp,i=r-n.t,a=e.wheelX/i,s=e.wheelY/i;i<o&&(a=(a+n.vx)/2,s=(s+n.vy)/2);var l=Math.abs(a/s),c=!1;if(l>=1&&t.renderer.isScrollableBy(e.wheelX*e.speed,0)&&(c=!0),l<=1&&t.renderer.isScrollableBy(0,e.wheelY*e.speed)&&(c=!0),c)n.allowed=r;else if(r-n.allowed<o){var u=Math.abs(a)<=1.1*Math.abs(n.vx)&&Math.abs(s)<=1.1*Math.abs(n.vy);u?(c=!0,n.allowed=r):n.allowed=0}return n.t=r,n.vx=a,n.vy=s,c?(t.renderer.scrollBy(e.wheelX*e.speed,e.wheelY*e.speed),e.stop()):void 0}},this.onTouchMove=function(e){this.editor._emit(\"mousewheel\",e)}}).call(a.prototype),t.DefaultHandlers=a}),ace.define(\"ace/tooltip\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/lib/dom\"],function(e,t,n){\"use strict\";e(\"./lib/oop\");var r=e(\"./lib/dom\");function i(e){this.isOpen=!1,this.$element=null,this.$parentNode=e}(function(){this.$init=function(){return this.$element=r.createElement(\"div\"),this.$element.className=\"ace_tooltip\",this.$element.style.display=\"none\",this.$parentNode.appendChild(this.$element),this.$element},this.getElement=function(){return this.$element||this.$init()},this.setText=function(e){r.setInnerText(this.getElement(),e)},this.setHtml=function(e){this.getElement().innerHTML=e},this.setPosition=function(e,t){this.getElement().style.left=e+\"px\",this.getElement().style.top=t+\"px\"},this.setClassName=function(e){r.addCssClass(this.getElement(),e)},this.show=function(e,t,n){null!=e&&this.setText(e),null!=t&&null!=n&&this.setPosition(t,n),this.isOpen||(this.getElement().style.display=\"block\",this.isOpen=!0)},this.hide=function(){this.isOpen&&(this.getElement().style.display=\"none\",this.isOpen=!1)},this.getHeight=function(){return this.getElement().offsetHeight},this.getWidth=function(){return this.getElement().offsetWidth},this.destroy=function(){this.isOpen=!1,this.$element&&this.$element.parentNode&&this.$element.parentNode.removeChild(this.$element)}}).call(i.prototype),t.Tooltip=i}),ace.define(\"ace/mouse/default_gutter_handler\",[\"require\",\"exports\",\"module\",\"ace/lib/dom\",\"ace/lib/oop\",\"ace/lib/event\",\"ace/tooltip\"],function(e,t,n){\"use strict\";var r=e(\"../lib/dom\"),i=e(\"../lib/oop\"),o=e(\"../lib/event\"),a=e(\"../tooltip\").Tooltip;function s(e){var t,n,i,a=e.editor,s=a.renderer.$gutterLayer,c=new l(a.container);function u(){var t=n.getDocumentPosition().row,r=s.$annotations[t];if(!r)return d();var o=a.session.getLength();if(t==o){var l=a.renderer.pixelToScreenCoordinates(0,n.y).row,u=n.$pos;if(l>a.session.documentToScreenRow(u.row,u.column))return d()}if(i!=r)if(i=r.text.join(\"<br/>\"),c.setHtml(i),c.show(),a._signal(\"showGutterTooltip\",c),a.on(\"mousewheel\",d),e.$tooltipFollowsMouse)h(n);else{var p=n.domEvent.target,m=p.getBoundingClientRect(),f=c.getElement().style;f.left=m.right+\"px\",f.top=m.bottom+\"px\"}}function d(){t&&(t=clearTimeout(t)),i&&(c.hide(),i=null,a._signal(\"hideGutterTooltip\",c),a.removeEventListener(\"mousewheel\",d))}function h(e){c.setPosition(e.x,e.y)}e.editor.setDefaultHandler(\"guttermousedown\",function(t){if(a.isFocused()&&0==t.getButton()){var n=s.getRegion(t);if(\"foldWidgets\"!=n){var r=t.getDocumentPosition().row,i=a.session.selection;if(t.getShiftKey())i.selectTo(r,0);else{if(2==t.domEvent.detail)return a.selectAll(),t.preventDefault();e.$clickSelection=a.selection.getLineRange(r)}return e.setState(\"selectByLines\"),e.captureMouse(t),t.preventDefault()}}}),e.editor.setDefaultHandler(\"guttermousemove\",function(o){var a=o.domEvent.target||o.domEvent.srcElement;if(r.hasCssClass(a,\"ace_fold-widget\"))return d();i&&e.$tooltipFollowsMouse&&h(o),n=o,t||(t=setTimeout(function(){t=null,n&&!e.isMousePressed?u():d()},50))}),o.addListener(a.renderer.$gutter,\"mouseout\",function(e){n=null,i&&!t&&(t=setTimeout(function(){t=null,d()},50))}),a.on(\"changeSession\",d)}function l(e){a.call(this,e)}i.inherits(l,a),function(){this.setPosition=function(e,t){var n=window.innerWidth||document.documentElement.clientWidth,r=window.innerHeight||document.documentElement.clientHeight,i=this.getWidth(),o=this.getHeight();e+=15,t+=15,e+i>n&&(e-=e+i-n),t+o>r&&(t-=20+o),a.prototype.setPosition.call(this,e,t)}}.call(l.prototype),t.GutterHandler=s}),ace.define(\"ace/mouse/mouse_event\",[\"require\",\"exports\",\"module\",\"ace/lib/event\",\"ace/lib/useragent\"],function(e,t,n){\"use strict\";var r=e(\"../lib/event\"),i=e(\"../lib/useragent\"),o=t.MouseEvent=function(e,t){this.domEvent=e,this.editor=t,this.x=this.clientX=e.clientX,this.y=this.clientY=e.clientY,this.$pos=null,this.$inSelection=null,this.propagationStopped=!1,this.defaultPrevented=!1};(function(){this.stopPropagation=function(){r.stopPropagation(this.domEvent),this.propagationStopped=!0},this.preventDefault=function(){r.preventDefault(this.domEvent),this.defaultPrevented=!0},this.stop=function(){this.stopPropagation(),this.preventDefault()},this.getDocumentPosition=function(){return this.$pos?this.$pos:(this.$pos=this.editor.renderer.screenToTextCoordinates(this.clientX,this.clientY),this.$pos)},this.inSelection=function(){if(null!==this.$inSelection)return this.$inSelection;var e=this.editor,t=e.getSelectionRange();if(t.isEmpty())this.$inSelection=!1;else{var n=this.getDocumentPosition();this.$inSelection=t.contains(n.row,n.column)}return this.$inSelection},this.getButton=function(){return r.getButton(this.domEvent)},this.getShiftKey=function(){return this.domEvent.shiftKey},this.getAccelKey=i.isMac?function(){return this.domEvent.metaKey}:function(){return this.domEvent.ctrlKey}}).call(o.prototype)}),ace.define(\"ace/mouse/dragdrop_handler\",[\"require\",\"exports\",\"module\",\"ace/lib/dom\",\"ace/lib/event\",\"ace/lib/useragent\"],function(e,t,n){\"use strict\";var r=e(\"../lib/dom\"),i=e(\"../lib/event\"),o=e(\"../lib/useragent\"),a=200,s=200,l=5;function c(e){var t=e.editor,n=r.createElement(\"img\");n.src=\"data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\",o.isOpera&&(n.style.cssText=\"width:1px;height:1px;position:fixed;top:0;left:0;z-index:2147483647;opacity:0;\");var c=[\"dragWait\",\"dragWaitEnd\",\"startDrag\",\"dragReadyEnd\",\"onMouseDrag\"];c.forEach(function(t){e[t]=this[t]},this),t.addEventListener(\"mousedown\",this.onMouseDown.bind(e));var d,h,p,m,f,g,b,v,k,y,w,x=t.container,E=0;function C(e,n){var r=Date.now(),i=!n||e.row!=n.row,o=!n||e.column!=n.column;if(!y||i||o)t.$blockScrolling+=1,t.moveCursorToPosition(e),t.$blockScrolling-=1,y=r,w={x:h,y:p};else{var a=u(w.x,w.y,h,p);a>l?y=null:r-y>=s&&(t.renderer.scrollCursorIntoView(),y=null)}}function T(e,n){var r=Date.now(),i=t.renderer.layerConfig.lineHeight,o=t.renderer.layerConfig.characterWidth,s=t.renderer.scroller.getBoundingClientRect(),l={x:{left:h-s.left,right:s.right-h},y:{top:p-s.top,bottom:s.bottom-p}},c=Math.min(l.x.left,l.x.right),u=Math.min(l.y.top,l.y.bottom),d={row:e.row,column:e.column};c/o<=2&&(d.column+=l.x.left<l.x.right?-3:2),u/i<=1&&(d.row+=l.y.top<l.y.bottom?-1:1);var m=e.row!=d.row,f=e.column!=d.column,g=!n||e.row!=n.row;m||f&&!g?k?r-k>=a&&t.renderer.scrollCursorIntoView(d):k=r:k=null}function A(){var e=g;g=t.renderer.screenToTextCoordinates(h,p),C(g,e),T(g,e)}function S(){f=t.selection.toOrientedRange(),d=t.session.addMarker(f,\"ace_selection\",t.getSelectionStyle()),t.clearSelection(),t.isFocused()&&t.renderer.$cursorLayer.setBlinking(!1),clearInterval(m),A(),m=setInterval(A,20),E=0,i.addListener(document,\"mousemove\",L)}function _(){clearInterval(m),t.session.removeMarker(d),d=null,t.$blockScrolling+=1,t.selection.fromOrientedRange(f),t.$blockScrolling-=1,t.isFocused()&&!v&&t.renderer.$cursorLayer.setBlinking(!t.getReadOnly()),f=null,g=null,E=0,k=null,y=null,i.removeListener(document,\"mousemove\",L)}this.onDragStart=function(e){if(this.cancelDrag||!x.draggable){var r=this;return setTimeout(function(){r.startSelect(),r.captureMouse(e)},0),e.preventDefault()}f=t.getSelectionRange();var i=e.dataTransfer;i.effectAllowed=t.getReadOnly()?\"copy\":\"copyMove\",o.isOpera&&(t.container.appendChild(n),n.scrollTop=0),i.setDragImage&&i.setDragImage(n,0,0),o.isOpera&&t.container.removeChild(n),i.clearData(),i.setData(\"Text\",t.session.getTextRange()),v=!0,this.setState(\"drag\")},this.onDragEnd=function(e){if(x.draggable=!1,v=!1,this.setState(null),!t.getReadOnly()){var n=e.dataTransfer.dropEffect;b||\"move\"!=n||t.session.remove(t.getSelectionRange()),t.renderer.$cursorLayer.setBlinking(!0)}this.editor.unsetStyle(\"ace_dragging\"),this.editor.renderer.setCursorStyle(\"\")},this.onDragEnter=function(e){if(!t.getReadOnly()&&R(e.dataTransfer))return h=e.clientX,p=e.clientY,d||S(),E++,e.dataTransfer.dropEffect=b=$(e),i.preventDefault(e)},this.onDragOver=function(e){if(!t.getReadOnly()&&R(e.dataTransfer))return h=e.clientX,p=e.clientY,d||(S(),E++),null!==F&&(F=null),e.dataTransfer.dropEffect=b=$(e),i.preventDefault(e)},this.onDragLeave=function(e){if(E--,E<=0&&d)return _(),b=null,i.preventDefault(e)},this.onDrop=function(e){if(g){var n=e.dataTransfer;if(v)switch(b){case\"move\":f=f.contains(g.row,g.column)?{start:g,end:g}:t.moveText(f,g);break;case\"copy\":f=t.moveText(f,g,!0);break}else{var r=n.getData(\"Text\");f={start:g,end:t.session.insert(g,r)},t.focus(),b=null}return _(),i.preventDefault(e)}},i.addListener(x,\"dragstart\",this.onDragStart.bind(e)),i.addListener(x,\"dragend\",this.onDragEnd.bind(e)),i.addListener(x,\"dragenter\",this.onDragEnter.bind(e)),i.addListener(x,\"dragover\",this.onDragOver.bind(e)),i.addListener(x,\"dragleave\",this.onDragLeave.bind(e)),i.addListener(x,\"drop\",this.onDrop.bind(e));var F=null;function L(){null==F&&(F=setTimeout(function(){null!=F&&d&&_()},20))}function R(e){var t=e.types;return!t||Array.prototype.some.call(t,function(e){return\"text/plain\"==e||\"Text\"==e})}function $(e){var t=[\"copy\",\"copymove\",\"all\",\"uninitialized\"],n=[\"move\",\"copymove\",\"linkmove\",\"all\",\"uninitialized\"],r=o.isMac?e.altKey:e.ctrlKey,i=\"uninitialized\";try{i=e.dataTransfer.effectAllowed.toLowerCase()}catch(e){}var a=\"none\";return r&&t.indexOf(i)>=0?a=\"copy\":n.indexOf(i)>=0?a=\"move\":t.indexOf(i)>=0&&(a=\"copy\"),a}}function u(e,t,n,r){return Math.sqrt(Math.pow(n-e,2)+Math.pow(r-t,2))}(function(){this.dragWait=function(){var e=Date.now()-this.mousedownEvent.time;e>this.editor.getDragDelay()&&this.startDrag()},this.dragWaitEnd=function(){var e=this.editor.container;e.draggable=!1,this.startSelect(this.mousedownEvent.getDocumentPosition()),this.selectEnd()},this.dragReadyEnd=function(e){this.editor.renderer.$cursorLayer.setBlinking(!this.editor.getReadOnly()),this.editor.unsetStyle(\"ace_dragging\"),this.editor.renderer.setCursorStyle(\"\"),this.dragWaitEnd()},this.startDrag=function(){this.cancelDrag=!1;var e=this.editor,t=e.container;t.draggable=!0,e.renderer.$cursorLayer.setBlinking(!1),e.setStyle(\"ace_dragging\");var n=o.isWin?\"default\":\"move\";e.renderer.setCursorStyle(n),this.setState(\"dragReady\")},this.onMouseDrag=function(e){var t=this.editor.container;if(o.isIE&&\"dragReady\"==this.state){var n=u(this.mousedownEvent.x,this.mousedownEvent.y,this.x,this.y);n>3&&t.dragDrop()}if(\"dragWait\"===this.state){n=u(this.mousedownEvent.x,this.mousedownEvent.y,this.x,this.y);n>0&&(t.draggable=!1,this.startSelect(this.mousedownEvent.getDocumentPosition()))}},this.onMouseDown=function(e){if(this.$dragEnabled){this.mousedownEvent=e;var t=this.editor,n=e.inSelection(),r=e.getButton(),i=e.domEvent.detail||1;if(1===i&&0===r&&n){if(e.editor.inMultiSelectMode&&(e.getAccelKey()||e.getShiftKey()))return;this.mousedownEvent.time=Date.now();var a=e.domEvent.target||e.domEvent.srcElement;if(\"unselectable\"in a&&(a.unselectable=\"on\"),t.getDragDelay()){if(o.isWebKit){this.cancelDrag=!0;var s=t.container;s.draggable=!0}this.setState(\"dragWait\")}else this.startDrag();this.captureMouse(e,this.onMouseDrag.bind(this)),e.defaultPrevented=!0}}}}).call(c.prototype),t.DragdropHandler=c}),ace.define(\"ace/lib/net\",[\"require\",\"exports\",\"module\",\"ace/lib/dom\"],function(e,t,n){\"use strict\";var r=e(\"./dom\");t.get=function(e,t){var n=new XMLHttpRequest;n.open(\"GET\",e,!0),n.onreadystatechange=function(){4===n.readyState&&t(n.responseText)},n.send(null)},t.loadScript=function(e,t){var n=r.getDocumentHead(),i=document.createElement(\"script\");i.src=e,n.appendChild(i),i.onload=i.onreadystatechange=function(e,n){!n&&i.readyState&&\"loaded\"!=i.readyState&&\"complete\"!=i.readyState||(i=i.onload=i.onreadystatechange=null,n||t())}},t.qualifyURL=function(e){var t=document.createElement(\"a\");return t.href=e,t.href}}),ace.define(\"ace/lib/event_emitter\",[\"require\",\"exports\",\"module\"],function(e,t,n){\"use strict\";var r={},i=function(){this.propagationStopped=!0},o=function(){this.defaultPrevented=!0};r._emit=r._dispatchEvent=function(e,t){this._eventRegistry||(this._eventRegistry={}),this._defaultHandlers||(this._defaultHandlers={});var n=this._eventRegistry[e]||[],r=this._defaultHandlers[e];if(n.length||r){\"object\"==typeof t&&t||(t={}),t.type||(t.type=e),t.stopPropagation||(t.stopPropagation=i),t.preventDefault||(t.preventDefault=o),n=n.slice();for(var a=0;a<n.length;a++)if(n[a](t,this),t.propagationStopped)break;return r&&!t.defaultPrevented?r(t,this):void 0}},r._signal=function(e,t){var n=(this._eventRegistry||{})[e];if(n){n=n.slice();for(var r=0;r<n.length;r++)n[r](t,this)}},r.once=function(e,t){var n=this;t&&this.addEventListener(e,function r(){n.removeEventListener(e,r),t.apply(null,arguments)})},r.setDefaultHandler=function(e,t){var n=this._defaultHandlers;if(n||(n=this._defaultHandlers={_disabled_:{}}),n[e]){var r=n[e],i=n._disabled_[e];i||(n._disabled_[e]=i=[]),i.push(r);var o=i.indexOf(t);-1!=o&&i.splice(o,1)}n[e]=t},r.removeDefaultHandler=function(e,t){var n=this._defaultHandlers;if(n){var r=n._disabled_[e];if(n[e]==t){n[e];r&&this.setDefaultHandler(e,r.pop())}else if(r){var i=r.indexOf(t);-1!=i&&r.splice(i,1)}}},r.on=r.addEventListener=function(e,t,n){this._eventRegistry=this._eventRegistry||{};var r=this._eventRegistry[e];return r||(r=this._eventRegistry[e]=[]),-1==r.indexOf(t)&&r[n?\"unshift\":\"push\"](t),t},r.off=r.removeListener=r.removeEventListener=function(e,t){this._eventRegistry=this._eventRegistry||{};var n=this._eventRegistry[e];if(n){var r=n.indexOf(t);-1!==r&&n.splice(r,1)}},r.removeAllListeners=function(e){this._eventRegistry&&(this._eventRegistry[e]=[])},t.EventEmitter=r}),ace.define(\"ace/lib/app_config\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/lib/event_emitter\"],function(e,t,n){var r=e(\"./oop\"),i=e(\"./event_emitter\").EventEmitter,o={setOptions:function(e){Object.keys(e).forEach(function(t){this.setOption(t,e[t])},this)},getOptions:function(e){var t={};return e?Array.isArray(e)||(t=e,e=Object.keys(t)):e=Object.keys(this.$options),e.forEach(function(e){t[e]=this.getOption(e)},this),t},setOption:function(e,t){if(this[\"$\"+e]!==t){var n=this.$options[e];if(!n)return a('misspelled option \"'+e+'\"');if(n.forwardTo)return this[n.forwardTo]&&this[n.forwardTo].setOption(e,t);n.handlesSet||(this[\"$\"+e]=t),n&&n.set&&n.set.call(this,t)}},getOption:function(e){var t=this.$options[e];return t?t.forwardTo?this[t.forwardTo]&&this[t.forwardTo].getOption(e):t&&t.get?t.get.call(this):this[\"$\"+e]:a('misspelled option \"'+e+'\"')}};function a(e){\"undefined\"!=typeof console&&console.warn&&console.warn.apply(console,arguments)}function s(e,t){var n=new Error(e);n.data=t,\"object\"==typeof console&&console.error&&console.error(n),setTimeout(function(){throw n})}var l=function(){this.$defaultOptions={}};(function(){r.implement(this,i),this.defineOptions=function(e,t,n){return e.$options||(this.$defaultOptions[t]=e.$options={}),Object.keys(n).forEach(function(t){var r=n[t];\"string\"==typeof r&&(r={forwardTo:r}),r.name||(r.name=t),e.$options[r.name]=r,\"initialValue\"in r&&(e[\"$\"+r.name]=r.initialValue)}),r.implement(e,o),this},this.resetOptions=function(e){Object.keys(e.$options).forEach(function(t){var n=e.$options[t];\"value\"in n&&e.setOption(t,n.value)})},this.setDefaultValue=function(e,t,n){var r=this.$defaultOptions[e]||(this.$defaultOptions[e]={});r[t]&&(r.forwardTo?this.setDefaultValue(r.forwardTo,t,n):r[t].value=n)},this.setDefaultValues=function(e,t){Object.keys(t).forEach(function(n){this.setDefaultValue(e,n,t[n])},this)},this.warn=a,this.reportError=s}).call(l.prototype),t.AppConfig=l}),ace.define(\"ace/config\",[\"require\",\"exports\",\"module\",\"ace/lib/lang\",\"ace/lib/oop\",\"ace/lib/net\",\"ace/lib/app_config\"],function(e,t,r){var i=e(\"./lib/lang\"),o=(e(\"./lib/oop\"),e(\"./lib/net\")),a=e(\"./lib/app_config\").AppConfig;r.exports=t=new a;var s=function(){return this||\"undefined\"!=typeof window&&window}(),l={packaged:!1,workerPath:null,modePath:null,themePath:null,basePath:\"\",suffix:\".js\",$moduleUrls:{}};function c(i){if(s&&s.document){l.packaged=i||e.packaged||r.packaged||s.define&&n(\"07d6\").packaged;for(var o={},a=\"\",c=document.currentScript||document._currentScript,d=c&&c.ownerDocument||document,h=d.getElementsByTagName(\"script\"),p=0;p<h.length;p++){var m=h[p],f=m.src||m.getAttribute(\"src\");if(f){for(var g=m.attributes,b=0,v=g.length;b<v;b++){var k=g[b];0===k.name.indexOf(\"data-ace-\")&&(o[u(k.name.replace(/^data-ace-/,\"\"))]=k.value)}var y=f.match(/^(.*)\\/ace(\\-\\w+)?\\.js(\\?|$)/);y&&(a=y[1])}}for(var w in a&&(o.base=o.base||a,o.packaged=!0),o.basePath=o.base,o.workerPath=o.workerPath||o.base,o.modePath=o.modePath||o.base,o.themePath=o.themePath||o.base,delete o.base,o)\"undefined\"!==typeof o[w]&&t.set(w,o[w])}}function u(e){return e.replace(/-(.)/g,function(e,t){return t.toUpperCase()})}t.get=function(e){if(!l.hasOwnProperty(e))throw new Error(\"Unknown config key: \"+e);return l[e]},t.set=function(e,t){if(!l.hasOwnProperty(e))throw new Error(\"Unknown config key: \"+e);l[e]=t},t.all=function(){return i.copyObject(l)},t.moduleUrl=function(e,t){if(l.$moduleUrls[e])return l.$moduleUrls[e];var n=e.split(\"/\");t=t||n[n.length-2]||\"\";var r=\"snippets\"==t?\"/\":\"-\",i=n[n.length-1];if(\"worker\"==t&&\"-\"==r){var o=new RegExp(\"^\"+t+\"[\\\\-_]|[\\\\-_]\"+t+\"$\",\"g\");i=i.replace(o,\"\")}(!i||i==t)&&n.length>1&&(i=n[n.length-2]);var a=l[t+\"Path\"];return null==a?a=l.basePath:\"/\"==r&&(t=r=\"\"),a&&\"/\"!=a.slice(-1)&&(a+=\"/\"),a+t+r+i+this.get(\"suffix\")},t.setModuleUrl=function(e,t){return l.$moduleUrls[e]=t},t.$loading={},t.loadModule=function(n,r){var i,a;Array.isArray(n)&&(a=n[0],n=n[1]);try{i=e(n)}catch(l){}if(i&&!t.$loading[n])return r&&r(i);if(t.$loading[n]||(t.$loading[n]=[]),t.$loading[n].push(r),!(t.$loading[n].length>1)){var s=function(){e([n],function(e){t._emit(\"load.module\",{name:n,module:e});var r=t.$loading[n];t.$loading[n]=null,r.forEach(function(t){t&&t(e)})})};if(!t.get(\"packaged\"))return s();o.loadScript(t.moduleUrl(n,a),s)}},c(!0),t.init=c}),ace.define(\"ace/mouse/mouse_handler\",[\"require\",\"exports\",\"module\",\"ace/lib/event\",\"ace/lib/useragent\",\"ace/mouse/default_handlers\",\"ace/mouse/default_gutter_handler\",\"ace/mouse/mouse_event\",\"ace/mouse/dragdrop_handler\",\"ace/config\"],function(e,t,n){\"use strict\";var r=e(\"../lib/event\"),i=e(\"../lib/useragent\"),o=e(\"./default_handlers\").DefaultHandlers,a=e(\"./default_gutter_handler\").GutterHandler,s=e(\"./mouse_event\").MouseEvent,l=e(\"./dragdrop_handler\").DragdropHandler,c=e(\"../config\"),u=function(e){var t=this;this.editor=e,new o(this),new a(this),new l(this);var n=function(t){var n=!document.hasFocus||!document.hasFocus()||!e.isFocused()&&document.activeElement==(e.textInput&&e.textInput.getElement());n&&window.focus(),e.focus()},s=e.renderer.getMouseEventTarget();r.addListener(s,\"click\",this.onMouseEvent.bind(this,\"click\")),r.addListener(s,\"mousemove\",this.onMouseMove.bind(this,\"mousemove\")),r.addMultiMouseDownListener([s,e.renderer.scrollBarV&&e.renderer.scrollBarV.inner,e.renderer.scrollBarH&&e.renderer.scrollBarH.inner,e.textInput&&e.textInput.getElement()].filter(Boolean),[400,300,250],this,\"onMouseEvent\"),r.addMouseWheelListener(e.container,this.onMouseWheel.bind(this,\"mousewheel\")),r.addTouchMoveListener(e.container,this.onTouchMove.bind(this,\"touchmove\"));var c=e.renderer.$gutter;r.addListener(c,\"mousedown\",this.onMouseEvent.bind(this,\"guttermousedown\")),r.addListener(c,\"click\",this.onMouseEvent.bind(this,\"gutterclick\")),r.addListener(c,\"dblclick\",this.onMouseEvent.bind(this,\"gutterdblclick\")),r.addListener(c,\"mousemove\",this.onMouseEvent.bind(this,\"guttermousemove\")),r.addListener(s,\"mousedown\",n),r.addListener(c,\"mousedown\",n),i.isIE&&e.renderer.scrollBarV&&(r.addListener(e.renderer.scrollBarV.element,\"mousedown\",n),r.addListener(e.renderer.scrollBarH.element,\"mousedown\",n)),e.on(\"mousemove\",function(n){if(!t.state&&!t.$dragDelay&&t.$dragEnabled){var r=e.renderer.screenToTextCoordinates(n.x,n.y),i=e.session.selection.getRange(),o=e.renderer;!i.isEmpty()&&i.insideStart(r.row,r.column)?o.setCursorStyle(\"default\"):o.setCursorStyle(\"\")}})};(function(){this.onMouseEvent=function(e,t){this.editor._emit(e,new s(t,this.editor))},this.onMouseMove=function(e,t){var n=this.editor._eventRegistry&&this.editor._eventRegistry.mousemove;n&&n.length&&this.editor._emit(e,new s(t,this.editor))},this.onMouseWheel=function(e,t){var n=new s(t,this.editor);n.speed=2*this.$scrollSpeed,n.wheelX=t.wheelX,n.wheelY=t.wheelY,this.editor._emit(e,n)},this.onTouchMove=function(e,t){var n=new s(t,this.editor);n.speed=1,n.wheelX=t.wheelX,n.wheelY=t.wheelY,this.editor._emit(e,n)},this.setState=function(e){this.state=e},this.captureMouse=function(e,t){this.x=e.x,this.y=e.y,this.isMousePressed=!0;var n=this.editor.renderer;n.$keepTextAreaAtCursor&&(n.$keepTextAreaAtCursor=null);var o=this,a=function(e){if(e){if(i.isWebKit&&!e.which&&o.releaseMouse)return o.releaseMouse();o.x=e.clientX,o.y=e.clientY,t&&t(e),o.mouseEvent=new s(e,o.editor),o.$mouseMoved=!0}},l=function(e){clearInterval(u),c(),o[o.state+\"End\"]&&o[o.state+\"End\"](e),o.state=\"\",null==n.$keepTextAreaAtCursor&&(n.$keepTextAreaAtCursor=!0,n.$moveTextAreaToCursor()),o.isMousePressed=!1,o.$onCaptureMouseMove=o.releaseMouse=null,e&&o.onMouseEvent(\"mouseup\",e)},c=function(){o[o.state]&&o[o.state](),o.$mouseMoved=!1};if(i.isOldIE&&\"dblclick\"==e.domEvent.type)return setTimeout(function(){l(e)});o.$onCaptureMouseMove=a,o.releaseMouse=r.capture(this.editor.container,a,l);var u=setInterval(c,20)},this.releaseMouse=null,this.cancelContextMenu=function(){var e=function(t){t&&t.domEvent&&\"contextmenu\"!=t.domEvent.type||(this.editor.off(\"nativecontextmenu\",e),t&&t.domEvent&&r.stopEvent(t.domEvent))}.bind(this);setTimeout(e,10),this.editor.on(\"nativecontextmenu\",e)}}).call(u.prototype),c.defineOptions(u.prototype,\"mouseHandler\",{scrollSpeed:{initialValue:2},dragDelay:{initialValue:i.isMac?150:0},dragEnabled:{initialValue:!0},focusTimout:{initialValue:0},tooltipFollowsMouse:{initialValue:!0}}),t.MouseHandler=u}),ace.define(\"ace/mouse/fold_handler\",[\"require\",\"exports\",\"module\"],function(e,t,n){\"use strict\";function r(e){e.on(\"click\",function(t){var n=t.getDocumentPosition(),r=e.session,i=r.getFoldAt(n.row,n.column,1);i&&(t.getAccelKey()?r.removeFold(i):r.expandFold(i),t.stop())}),e.on(\"gutterclick\",function(t){var n=e.renderer.$gutterLayer.getRegion(t);if(\"foldWidgets\"==n){var r=t.getDocumentPosition().row,i=e.session;i.foldWidgets&&i.foldWidgets[r]&&e.session.onFoldWidgetClick(r,t),e.isFocused()||e.focus(),t.stop()}}),e.on(\"gutterdblclick\",function(t){var n=e.renderer.$gutterLayer.getRegion(t);if(\"foldWidgets\"==n){var r=t.getDocumentPosition().row,i=e.session,o=i.getParentFoldRangeData(r,!0),a=o.range||o.firstRange;if(a){r=a.start.row;var s=i.getFoldAt(r,i.getLine(r).length,1);s?i.removeFold(s):(i.addFold(\"...\",a),e.renderer.scrollCursorIntoView({row:a.start.row,column:0}))}t.stop()}})}t.FoldHandler=r}),ace.define(\"ace/keyboard/keybinding\",[\"require\",\"exports\",\"module\",\"ace/lib/keys\",\"ace/lib/event\"],function(e,t,n){\"use strict\";var r=e(\"../lib/keys\"),i=e(\"../lib/event\"),o=function(e){this.$editor=e,this.$data={editor:e},this.$handlers=[],this.setDefaultHandler(e.commands)};(function(){this.setDefaultHandler=function(e){this.removeKeyboardHandler(this.$defaultHandler),this.$defaultHandler=e,this.addKeyboardHandler(e,0)},this.setKeyboardHandler=function(e){var t=this.$handlers;if(t[t.length-1]!=e){while(t[t.length-1]&&t[t.length-1]!=this.$defaultHandler)this.removeKeyboardHandler(t[t.length-1]);this.addKeyboardHandler(e,1)}},this.addKeyboardHandler=function(e,t){if(e){\"function\"!=typeof e||e.handleKeyboard||(e.handleKeyboard=e);var n=this.$handlers.indexOf(e);-1!=n&&this.$handlers.splice(n,1),void 0==t?this.$handlers.push(e):this.$handlers.splice(t,0,e),-1==n&&e.attach&&e.attach(this.$editor)}},this.removeKeyboardHandler=function(e){var t=this.$handlers.indexOf(e);return-1!=t&&(this.$handlers.splice(t,1),e.detach&&e.detach(this.$editor),!0)},this.getKeyboardHandler=function(){return this.$handlers[this.$handlers.length-1]},this.getStatusText=function(){var e=this.$data,t=e.editor;return this.$handlers.map(function(n){return n.getStatusText&&n.getStatusText(t,e)||\"\"}).filter(Boolean).join(\" \")},this.$callKeyboardHandlers=function(e,t,n,r){for(var o,a=!1,s=this.$editor.commands,l=this.$handlers.length;l--;)if(o=this.$handlers[l].handleKeyboard(this.$data,e,t,n,r),o&&o.command&&(a=\"null\"==o.command||s.exec(o.command,this.$editor,o.args,r),a&&r&&-1!=e&&1!=o.passEvent&&1!=o.command.passEvent&&i.stopEvent(r),a))break;return a||-1!=e||(o={command:\"insertstring\"},a=s.exec(\"insertstring\",this.$editor,t)),a&&this.$editor._signal&&this.$editor._signal(\"keyboardActivity\",o),a},this.onCommandKey=function(e,t,n){var i=r.keyCodeToString(n);this.$callKeyboardHandlers(t,i,n,e)},this.onTextInput=function(e){this.$callKeyboardHandlers(-1,e)}}).call(o.prototype),t.KeyBinding=o}),ace.define(\"ace/lib/bidiutil\",[\"require\",\"exports\",\"module\"],function(e,t,n){\"use strict\";var r=0,i=0,o=!1,a=!1,s=!1,l=[[0,3,0,1,0,0,0],[0,3,0,1,2,2,0],[0,3,0,17,2,0,1],[0,3,5,5,4,1,0],[0,3,21,21,4,0,1],[0,3,5,5,4,2,0]],c=[[2,0,1,1,0,1,0],[2,0,1,1,0,2,0],[2,0,2,1,3,2,0],[2,0,2,33,3,1,1]],u=0,d=1,h=0,p=1,m=2,f=3,g=4,b=5,v=6,k=7,y=8,w=9,x=10,E=11,C=12,T=13,A=14,S=15,_=16,F=17,L=18,R=[L,L,L,L,L,L,L,L,L,v,b,v,y,b,L,L,L,L,L,L,L,L,L,L,L,L,L,L,b,b,b,v,y,g,g,E,E,E,g,g,g,g,g,x,w,x,w,w,m,m,m,m,m,m,m,m,m,m,w,g,g,g,g,g,g,h,h,h,h,h,h,h,h,h,h,h,h,h,h,h,h,h,h,h,h,h,h,h,h,h,h,g,g,g,g,g,g,h,h,h,h,h,h,h,h,h,h,h,h,h,h,h,h,h,h,h,h,h,h,h,h,h,h,g,g,g,g,L,L,L,L,L,L,b,L,L,L,L,L,L,L,L,L,L,L,L,L,L,L,L,L,L,L,L,L,L,L,L,L,L,w,g,E,E,E,E,g,g,g,g,h,g,g,L,g,g,E,E,m,m,g,h,g,g,g,m,h,g,g,g,g,g],$=[y,y,y,y,y,y,y,y,y,y,y,L,L,L,h,p,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,y,b,T,A,S,_,F,w,E,E,E,E,E,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,w,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,y];function B(e,t,n,u){var d=r?c:l,h=null,p=null,m=null,f=0,g=null,k=null,w=-1,x=null,E=null,C=[];if(!u)for(x=0,u=[];x<n;x++)u[x]=O(e[x]);for(i=r,o=!1,!1,a=!1,s=!1,E=0;E<n;E++){if(h=f,C[E]=p=M(e,u,C,E),f=d[h][p],g=240&f,f&=15,t[E]=m=d[f][5],g>0)if(16==g){for(x=w;x<E;x++)t[x]=1;w=-1}else w=-1;if(k=d[f][6],k)-1==w&&(w=E);else if(w>-1){for(x=w;x<E;x++)t[x]=m;w=-1}u[E]==b&&(t[E]=0),i|=m}if(s)for(x=0;x<n;x++)if(u[x]==v){t[x]=r;for(var T=x-1;T>=0;T--){if(u[T]!=y)break;t[T]=r}}}function D(e,t,n){if(!(i<e))if(1!=e||r!=d||a){var o,s,l,c,u=n.length,h=0;while(h<u){if(t[h]>=e){o=h+1;while(o<u&&t[o]>=e)o++;for(s=h,l=o-1;s<l;s++,l--)c=n[s],n[s]=n[l],n[l]=c;h=o}h++}}else n.reverse()}function M(e,t,n,i){var l,c,u,d,R=t[i];switch(R){case h:case p:o=!1;case g:case f:return R;case m:return o?f:m;case k:return o=!0,!0,p;case y:return g;case w:return i<1||i+1>=t.length||(l=n[i-1])!=m&&l!=f||(c=t[i+1])!=m&&c!=f?g:(o&&(c=f),c==l?c:g);case x:return l=i>0?n[i-1]:b,l==m&&i+1<t.length&&t[i+1]==m?m:g;case E:if(i>0&&n[i-1]==m)return m;if(o)return g;d=i+1,u=t.length;while(d<u&&t[d]==E)d++;return d<u&&t[d]==m?m:g;case C:u=t.length,d=i+1;while(d<u&&t[d]==C)d++;if(d<u){var $=e[i],B=$>=1425&&$<=2303||64286==$;if(l=t[d],B&&(l==p||l==k))return p}return i<1||(l=t[i-1])==b?g:n[i-1];case b:return o=!1,a=!0,r;case v:return s=!0,g;case T:case A:case _:case F:case S:o=!1;case L:return g}}function O(e){var t=e.charCodeAt(0),n=t>>8;return 0==n?t>191?h:R[t]:5==n?/[\\u0591-\\u05f4]/.test(e)?p:h:6==n?/[\\u0610-\\u061a\\u064b-\\u065f\\u06d6-\\u06e4\\u06e7-\\u06ed]/.test(e)?C:/[\\u0660-\\u0669\\u066b-\\u066c]/.test(e)?f:1642==t?E:/[\\u06f0-\\u06f9]/.test(e)?m:k:32==n&&t<=8287?$[255&t]:254==n&&t>=65136?k:g}t.L=h,t.R=p,t.EN=m,t.ON_R=3,t.AN=4,t.R_H=5,t.B=6,t.DOT=\"·\",t.doBidiReorder=function(e,n,i){if(e.length<2)return{};var o=e.split(\"\"),a=new Array(o.length),s=new Array(o.length),l=[];r=i?d:u,B(o,l,o.length,n);for(var c=0;c<a.length;a[c]=c,c++);D(2,l,a),D(1,l,a);for(c=0;c<a.length-1;c++)n[c]===f?l[c]=t.AN:l[c]===p&&(n[c]>k&&n[c]<T||n[c]===g||n[c]===L)?l[c]=t.ON_R:c>0&&\"ل\"===o[c-1]&&/\\u0622|\\u0623|\\u0625|\\u0627/.test(o[c])&&(l[c-1]=l[c]=t.R_H,c++);o[o.length-1]===t.DOT&&(l[o.length-1]=t.B);for(c=0;c<a.length;c++)s[c]=l[a[c]];return{logicalFromVisual:a,bidiLevels:s}},t.hasBidiCharacters=function(e,t){for(var n=!1,r=0;r<e.length;r++)t[r]=O(e.charAt(r)),n||t[r]!=p&&t[r]!=k||(n=!0);return n},t.getVisualFromLogicalIdx=function(e,t){for(var n=0;n<t.logicalFromVisual.length;n++)if(t.logicalFromVisual[n]==e)return n;return 0}}),ace.define(\"ace/bidihandler\",[\"require\",\"exports\",\"module\",\"ace/lib/bidiutil\",\"ace/lib/lang\",\"ace/lib/useragent\"],function(e,t,n){\"use strict\";var r=e(\"./lib/bidiutil\"),i=e(\"./lib/lang\"),o=e(\"./lib/useragent\"),a=/[\\u0590-\\u05f4\\u0600-\\u06ff\\u0700-\\u08ac]/,s=function(e){this.session=e,this.bidiMap={},this.currentRow=null,this.bidiUtil=r,this.charWidths=[],this.EOL=\"¬\",this.showInvisibles=!0,this.isRtlDir=!1,this.line=\"\",this.wrapIndent=0,this.isLastRow=!1,this.EOF=\"¶\",this.seenBidi=!1};(function(){this.isBidiRow=function(e,t,n){return!!this.seenBidi&&(e!==this.currentRow&&(this.currentRow=e,this.updateRowLine(t,n),this.updateBidiMap()),this.bidiMap.bidiLevels)},this.onChange=function(e){this.seenBidi?this.currentRow=null:\"insert\"==e.action&&a.test(e.lines.join(\"\\n\"))&&(this.seenBidi=!0,this.currentRow=null)},this.getDocumentRow=function(){var e=0,t=this.session.$screenRowCache;if(t.length){var n=this.session.$getRowCacheIndex(t,this.currentRow);n>=0&&(e=this.session.$docRowCache[n])}return e},this.getSplitIndex=function(){var e=0,t=this.session.$screenRowCache;if(t.length){var n,r=this.session.$getRowCacheIndex(t,this.currentRow);while(this.currentRow-e>0){if(n=this.session.$getRowCacheIndex(t,this.currentRow-e-1),n!==r)break;r=n,e++}}return e},this.updateRowLine=function(e,t){if(void 0===e&&(e=this.getDocumentRow()),this.wrapIndent=0,this.isLastRow=e===this.session.getLength()-1,this.line=this.session.getLine(e),this.session.$useWrapMode){var n=this.session.$wrapData[e];n&&(void 0===t&&(t=this.getSplitIndex()),t>0&&n.length?(this.wrapIndent=n.indent,this.line=t<n.length?this.line.substring(n[t-1],n[n.length-1]):this.line.substring(n[n.length-1])):this.line=this.line.substring(0,n[t]))}var o,a=this.session,s=0;this.line=this.line.replace(/\\t|[\\u1100-\\u2029, \\u202F-\\uFFE6]/g,function(e,t){return\"\\t\"===e||a.isFullWidth(e.charCodeAt(0))?(o=\"\\t\"===e?a.getScreenTabSize(t+s):2,s+=o-1,i.stringRepeat(r.DOT,o)):e})},this.updateBidiMap=function(){var e=[],t=this.isLastRow?this.EOF:this.EOL,n=this.line+(this.showInvisibles?t:r.DOT);r.hasBidiCharacters(n,e)?this.bidiMap=r.doBidiReorder(n,e,this.isRtlDir):this.bidiMap={}},this.markAsDirty=function(){this.currentRow=null},this.updateCharacterWidths=function(e){if(this.seenBidi&&this.characterWidth!==e.$characterSize.width){var t=this.characterWidth=e.$characterSize.width,n=e.$measureCharWidth(\"ה\");this.charWidths[r.L]=this.charWidths[r.EN]=this.charWidths[r.ON_R]=t,this.charWidths[r.R]=this.charWidths[r.AN]=n,this.charWidths[r.R_H]=o.isChrome?n:.45*n,this.charWidths[r.B]=0,this.currentRow=null}},this.getShowInvisibles=function(){return this.showInvisibles},this.setShowInvisibles=function(e){this.showInvisibles=e,this.currentRow=null},this.setEolChar=function(e){this.EOL=e},this.setTextDir=function(e){this.isRtlDir=e},this.getPosLeft=function(e){e-=this.wrapIndent;var t=r.getVisualFromLogicalIdx(e>0?e-1:0,this.bidiMap),n=this.bidiMap.bidiLevels,i=0;0===e&&n[t]%2!==0&&t++;for(var o=0;o<t;o++)i+=this.charWidths[n[o]];return 0!==e&&n[t]%2===0&&(i+=this.charWidths[n[t]]),this.wrapIndent&&(i+=this.wrapIndent*this.charWidths[r.L]),i},this.getSelections=function(e,t){for(var n,i,o=this.bidiMap,a=o.bidiLevels,s=this.wrapIndent*this.charWidths[r.L],l=[],c=Math.min(e,t)-this.wrapIndent,u=Math.max(e,t)-this.wrapIndent,d=!1,h=!1,p=0,m=0;m<a.length;m++)i=o.logicalFromVisual[m],n=a[m],d=i>=c&&i<u,d&&!h?p=s:!d&&h&&l.push({left:p,width:s-p}),s+=this.charWidths[n],h=d;return d&&m===a.length&&l.push({left:p,width:s-p}),l},this.offsetToCol=function(e){var t=0,n=(e=Math.max(e,0),0),i=0,o=this.bidiMap.bidiLevels,a=this.charWidths[o[i]];this.wrapIndent&&(e-=this.wrapIndent*this.charWidths[r.L]);while(e>n+a/2){if(n+=a,i===o.length-1){a=0;break}a=this.charWidths[o[++i]]}return i>0&&o[i-1]%2!==0&&o[i]%2===0?(e<n&&i--,t=this.bidiMap.logicalFromVisual[i]):i>0&&o[i-1]%2===0&&o[i]%2!==0?t=1+(e>n?this.bidiMap.logicalFromVisual[i]:this.bidiMap.logicalFromVisual[i-1]):this.isRtlDir&&i===o.length-1&&0===a&&o[i-1]%2===0||!this.isRtlDir&&0===i&&o[i]%2!==0?t=1+this.bidiMap.logicalFromVisual[i]:(i>0&&o[i-1]%2!==0&&0!==a&&i--,t=this.bidiMap.logicalFromVisual[i]),t+this.wrapIndent}}).call(s.prototype),t.BidiHandler=s}),ace.define(\"ace/range\",[\"require\",\"exports\",\"module\"],function(e,t,n){\"use strict\";var r=function(e,t){return e.row-t.row||e.column-t.column},i=function(e,t,n,r){this.start={row:e,column:t},this.end={row:n,column:r}};(function(){this.isEqual=function(e){return this.start.row===e.start.row&&this.end.row===e.end.row&&this.start.column===e.start.column&&this.end.column===e.end.column},this.toString=function(){return\"Range: [\"+this.start.row+\"/\"+this.start.column+\"] -> [\"+this.end.row+\"/\"+this.end.column+\"]\"},this.contains=function(e,t){return 0==this.compare(e,t)},this.compareRange=function(e){var t,n=e.end,r=e.start;return t=this.compare(n.row,n.column),1==t?(t=this.compare(r.row,r.column),1==t?2:0==t?1:0):-1==t?-2:(t=this.compare(r.row,r.column),-1==t?-1:1==t?42:0)},this.comparePoint=function(e){return this.compare(e.row,e.column)},this.containsRange=function(e){return 0==this.comparePoint(e.start)&&0==this.comparePoint(e.end)},this.intersects=function(e){var t=this.compareRange(e);return-1==t||0==t||1==t},this.isEnd=function(e,t){return this.end.row==e&&this.end.column==t},this.isStart=function(e,t){return this.start.row==e&&this.start.column==t},this.setStart=function(e,t){\"object\"==typeof e?(this.start.column=e.column,this.start.row=e.row):(this.start.row=e,this.start.column=t)},this.setEnd=function(e,t){\"object\"==typeof e?(this.end.column=e.column,this.end.row=e.row):(this.end.row=e,this.end.column=t)},this.inside=function(e,t){return 0==this.compare(e,t)&&(!this.isEnd(e,t)&&!this.isStart(e,t))},this.insideStart=function(e,t){return 0==this.compare(e,t)&&!this.isEnd(e,t)},this.insideEnd=function(e,t){return 0==this.compare(e,t)&&!this.isStart(e,t)},this.compare=function(e,t){return this.isMultiLine()||e!==this.start.row?e<this.start.row?-1:e>this.end.row?1:this.start.row===e?t>=this.start.column?0:-1:this.end.row===e?t<=this.end.column?0:1:0:t<this.start.column?-1:t>this.end.column?1:0},this.compareStart=function(e,t){return this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.compareEnd=function(e,t){return this.end.row==e&&this.end.column==t?1:this.compare(e,t)},this.compareInside=function(e,t){return this.end.row==e&&this.end.column==t?1:this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.clipRows=function(e,t){if(this.end.row>t)var n={row:t+1,column:0};else if(this.end.row<e)n={row:e,column:0};if(this.start.row>t)var r={row:t+1,column:0};else if(this.start.row<e)r={row:e,column:0};return i.fromPoints(r||this.start,n||this.end)},this.extend=function(e,t){var n=this.compare(e,t);if(0==n)return this;if(-1==n)var r={row:e,column:t};else var o={row:e,column:t};return i.fromPoints(r||this.start,o||this.end)},this.isEmpty=function(){return this.start.row===this.end.row&&this.start.column===this.end.column},this.isMultiLine=function(){return this.start.row!==this.end.row},this.clone=function(){return i.fromPoints(this.start,this.end)},this.collapseRows=function(){return 0==this.end.column?new i(this.start.row,0,Math.max(this.start.row,this.end.row-1),0):new i(this.start.row,0,this.end.row,0)},this.toScreenRange=function(e){var t=e.documentToScreenPosition(this.start),n=e.documentToScreenPosition(this.end);return new i(t.row,t.column,n.row,n.column)},this.moveBy=function(e,t){this.start.row+=e,this.start.column+=t,this.end.row+=e,this.end.column+=t}}).call(i.prototype),i.fromPoints=function(e,t){return new i(e.row,e.column,t.row,t.column)},i.comparePoints=r,i.comparePoints=function(e,t){return e.row-t.row||e.column-t.column},t.Range=i}),ace.define(\"ace/selection\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/lib/lang\",\"ace/lib/event_emitter\",\"ace/range\"],function(e,t,n){\"use strict\";var r=e(\"./lib/oop\"),i=e(\"./lib/lang\"),o=e(\"./lib/event_emitter\").EventEmitter,a=e(\"./range\").Range,s=function(e){this.session=e,this.doc=e.getDocument(),this.clearSelection(),this.lead=this.selectionLead=this.doc.createAnchor(0,0),this.anchor=this.selectionAnchor=this.doc.createAnchor(0,0);var t=this;this.lead.on(\"change\",function(e){t._emit(\"changeCursor\"),t.$isEmpty||t._emit(\"changeSelection\"),t.$keepDesiredColumnOnChange||e.old.column==e.value.column||(t.$desiredColumn=null)}),this.selectionAnchor.on(\"change\",function(){t.$isEmpty||t._emit(\"changeSelection\")})};(function(){r.implement(this,o),this.isEmpty=function(){return this.$isEmpty||this.anchor.row==this.lead.row&&this.anchor.column==this.lead.column},this.isMultiLine=function(){return!this.isEmpty()&&this.getRange().isMultiLine()},this.getCursor=function(){return this.lead.getPosition()},this.setSelectionAnchor=function(e,t){this.anchor.setPosition(e,t),this.$isEmpty&&(this.$isEmpty=!1,this._emit(\"changeSelection\"))},this.getSelectionAnchor=function(){return this.$isEmpty?this.getSelectionLead():this.anchor.getPosition()},this.getSelectionLead=function(){return this.lead.getPosition()},this.shiftSelection=function(e){if(this.$isEmpty)this.moveCursorTo(this.lead.row,this.lead.column+e);else{var t=this.getSelectionAnchor(),n=this.getSelectionLead(),r=this.isBackwards();r&&0===t.column||this.setSelectionAnchor(t.row,t.column+e),(r||0!==n.column)&&this.$moveSelection(function(){this.moveCursorTo(n.row,n.column+e)})}},this.isBackwards=function(){var e=this.anchor,t=this.lead;return e.row>t.row||e.row==t.row&&e.column>t.column},this.getRange=function(){var e=this.anchor,t=this.lead;return this.isEmpty()?a.fromPoints(t,t):this.isBackwards()?a.fromPoints(t,e):a.fromPoints(e,t)},this.clearSelection=function(){this.$isEmpty||(this.$isEmpty=!0,this._emit(\"changeSelection\"))},this.selectAll=function(){var e=this.doc.getLength()-1;this.setSelectionAnchor(0,0),this.moveCursorTo(e,this.doc.getLine(e).length)},this.setRange=this.setSelectionRange=function(e,t){t?(this.setSelectionAnchor(e.end.row,e.end.column),this.selectTo(e.start.row,e.start.column)):(this.setSelectionAnchor(e.start.row,e.start.column),this.selectTo(e.end.row,e.end.column)),this.getRange().isEmpty()&&(this.$isEmpty=!0),this.$desiredColumn=null},this.$moveSelection=function(e){var t=this.lead;this.$isEmpty&&this.setSelectionAnchor(t.row,t.column),e.call(this)},this.selectTo=function(e,t){this.$moveSelection(function(){this.moveCursorTo(e,t)})},this.selectToPosition=function(e){this.$moveSelection(function(){this.moveCursorToPosition(e)})},this.moveTo=function(e,t){this.clearSelection(),this.moveCursorTo(e,t)},this.moveToPosition=function(e){this.clearSelection(),this.moveCursorToPosition(e)},this.selectUp=function(){this.$moveSelection(this.moveCursorUp)},this.selectDown=function(){this.$moveSelection(this.moveCursorDown)},this.selectRight=function(){this.$moveSelection(this.moveCursorRight)},this.selectLeft=function(){this.$moveSelection(this.moveCursorLeft)},this.selectLineStart=function(){this.$moveSelection(this.moveCursorLineStart)},this.selectLineEnd=function(){this.$moveSelection(this.moveCursorLineEnd)},this.selectFileEnd=function(){this.$moveSelection(this.moveCursorFileEnd)},this.selectFileStart=function(){this.$moveSelection(this.moveCursorFileStart)},this.selectWordRight=function(){this.$moveSelection(this.moveCursorWordRight)},this.selectWordLeft=function(){this.$moveSelection(this.moveCursorWordLeft)},this.getWordRange=function(e,t){if(\"undefined\"==typeof t){var n=e||this.lead;e=n.row,t=n.column}return this.session.getWordRange(e,t)},this.selectWord=function(){this.setSelectionRange(this.getWordRange())},this.selectAWord=function(){var e=this.getCursor(),t=this.session.getAWordRange(e.row,e.column);this.setSelectionRange(t)},this.getLineRange=function(e,t){var n,r=\"number\"==typeof e?e:this.lead.row,i=this.session.getFoldLine(r);return i?(r=i.start.row,n=i.end.row):n=r,!0===t?new a(r,0,n,this.session.getLine(n).length):new a(r,0,n+1,0)},this.selectLine=function(){this.setSelectionRange(this.getLineRange())},this.moveCursorUp=function(){this.moveCursorBy(-1,0)},this.moveCursorDown=function(){this.moveCursorBy(1,0)},this.wouldMoveIntoSoftTab=function(e,t,n){var r=e.column,i=e.column+t;return n<0&&(r=e.column-t,i=e.column),this.session.isTabStop(e)&&this.doc.getLine(e.row).slice(r,i).split(\" \").length-1==t},this.moveCursorLeft=function(){var e,t=this.lead.getPosition();if(e=this.session.getFoldAt(t.row,t.column,-1))this.moveCursorTo(e.start.row,e.start.column);else if(0===t.column)t.row>0&&this.moveCursorTo(t.row-1,this.doc.getLine(t.row-1).length);else{var n=this.session.getTabSize();this.wouldMoveIntoSoftTab(t,n,-1)&&!this.session.getNavigateWithinSoftTabs()?this.moveCursorBy(0,-n):this.moveCursorBy(0,-1)}},this.moveCursorRight=function(){var e,t=this.lead.getPosition();if(e=this.session.getFoldAt(t.row,t.column,1))this.moveCursorTo(e.end.row,e.end.column);else if(this.lead.column==this.doc.getLine(this.lead.row).length)this.lead.row<this.doc.getLength()-1&&this.moveCursorTo(this.lead.row+1,0);else{var n=this.session.getTabSize();t=this.lead;this.wouldMoveIntoSoftTab(t,n,1)&&!this.session.getNavigateWithinSoftTabs()?this.moveCursorBy(0,n):this.moveCursorBy(0,1)}},this.moveCursorLineStart=function(){var e=this.lead.row,t=this.lead.column,n=this.session.documentToScreenRow(e,t),r=this.session.screenToDocumentPosition(n,0),i=this.session.getDisplayLine(e,null,r.row,r.column),o=i.match(/^\\s*/);o[0].length==t||this.session.$useEmacsStyleLineStart||(r.column+=o[0].length),this.moveCursorToPosition(r)},this.moveCursorLineEnd=function(){var e=this.lead,t=this.session.getDocumentLastRowColumnPosition(e.row,e.column);if(this.lead.column==t.column){var n=this.session.getLine(t.row);if(t.column==n.length){var r=n.search(/\\s+$/);r>0&&(t.column=r)}}this.moveCursorTo(t.row,t.column)},this.moveCursorFileEnd=function(){var e=this.doc.getLength()-1,t=this.doc.getLine(e).length;this.moveCursorTo(e,t)},this.moveCursorFileStart=function(){this.moveCursorTo(0,0)},this.moveCursorLongWordRight=function(){var e=this.lead.row,t=this.lead.column,n=this.doc.getLine(e),r=n.substring(t);this.session.nonTokenRe.lastIndex=0,this.session.tokenRe.lastIndex=0;var i=this.session.getFoldAt(e,t,1);if(i)this.moveCursorTo(i.end.row,i.end.column);else{if(this.session.nonTokenRe.exec(r)&&(t+=this.session.nonTokenRe.lastIndex,this.session.nonTokenRe.lastIndex=0,r=n.substring(t)),t>=n.length)return this.moveCursorTo(e,n.length),this.moveCursorRight(),void(e<this.doc.getLength()-1&&this.moveCursorWordRight());this.session.tokenRe.exec(r)&&(t+=this.session.tokenRe.lastIndex,this.session.tokenRe.lastIndex=0),this.moveCursorTo(e,t)}},this.moveCursorLongWordLeft=function(){var e,t=this.lead.row,n=this.lead.column;if(e=this.session.getFoldAt(t,n,-1))this.moveCursorTo(e.start.row,e.start.column);else{var r=this.session.getFoldStringAt(t,n,-1);null==r&&(r=this.doc.getLine(t).substring(0,n));var o=i.stringReverse(r);if(this.session.nonTokenRe.lastIndex=0,this.session.tokenRe.lastIndex=0,this.session.nonTokenRe.exec(o)&&(n-=this.session.nonTokenRe.lastIndex,o=o.slice(this.session.nonTokenRe.lastIndex),this.session.nonTokenRe.lastIndex=0),n<=0)return this.moveCursorTo(t,0),this.moveCursorLeft(),void(t>0&&this.moveCursorWordLeft());this.session.tokenRe.exec(o)&&(n-=this.session.tokenRe.lastIndex,this.session.tokenRe.lastIndex=0),this.moveCursorTo(t,n)}},this.$shortWordEndIndex=function(e){var t,n=0,r=/\\s/,i=this.session.tokenRe;if(i.lastIndex=0,this.session.tokenRe.exec(e))n=this.session.tokenRe.lastIndex;else{while((t=e[n])&&r.test(t))n++;if(n<1){i.lastIndex=0;while((t=e[n])&&!i.test(t))if(i.lastIndex=0,n++,r.test(t)){if(n>2){n--;break}while((t=e[n])&&r.test(t))n++;if(n>2)break}}}return i.lastIndex=0,n},this.moveCursorShortWordRight=function(){var e=this.lead.row,t=this.lead.column,n=this.doc.getLine(e),r=n.substring(t),i=this.session.getFoldAt(e,t,1);if(i)return this.moveCursorTo(i.end.row,i.end.column);if(t==n.length){var o=this.doc.getLength();do{e++,r=this.doc.getLine(e)}while(e<o&&/^\\s*$/.test(r));/^\\s+/.test(r)||(r=\"\"),t=0}var a=this.$shortWordEndIndex(r);this.moveCursorTo(e,t+a)},this.moveCursorShortWordLeft=function(){var e,t=this.lead.row,n=this.lead.column;if(e=this.session.getFoldAt(t,n,-1))return this.moveCursorTo(e.start.row,e.start.column);var r=this.session.getLine(t).substring(0,n);if(0===n){do{t--,r=this.doc.getLine(t)}while(t>0&&/^\\s*$/.test(r));n=r.length,/\\s+$/.test(r)||(r=\"\")}var o=i.stringReverse(r),a=this.$shortWordEndIndex(o);return this.moveCursorTo(t,n-a)},this.moveCursorWordRight=function(){this.session.$selectLongWords?this.moveCursorLongWordRight():this.moveCursorShortWordRight()},this.moveCursorWordLeft=function(){this.session.$selectLongWords?this.moveCursorLongWordLeft():this.moveCursorShortWordLeft()},this.moveCursorBy=function(e,t){var n,r=this.session.documentToScreenPosition(this.lead.row,this.lead.column);0===t&&(0!==e&&(this.session.$bidiHandler.isBidiRow(r.row,this.lead.row)?(n=this.session.$bidiHandler.getPosLeft(r.column),r.column=Math.round(n/this.session.$bidiHandler.charWidths[0])):n=r.column*this.session.$bidiHandler.charWidths[0]),this.$desiredColumn?r.column=this.$desiredColumn:this.$desiredColumn=r.column);var i=this.session.screenToDocumentPosition(r.row+e,r.column,n);0!==e&&0===t&&i.row===this.lead.row&&i.column===this.lead.column&&this.session.lineWidgets&&this.session.lineWidgets[i.row]&&(i.row>0||e>0)&&i.row++,this.moveCursorTo(i.row,i.column+t,0===t)},this.moveCursorToPosition=function(e){this.moveCursorTo(e.row,e.column)},this.moveCursorTo=function(e,t,n){var r=this.session.getFoldAt(e,t,1);r&&(e=r.start.row,t=r.start.column),this.$keepDesiredColumnOnChange=!0;var i=this.session.getLine(e);/[\\uDC00-\\uDFFF]/.test(i.charAt(t))&&i.charAt(t-1)&&(this.lead.row==e&&this.lead.column==t+1?t-=1:t+=1),this.lead.setPosition(e,t),this.$keepDesiredColumnOnChange=!1,n||(this.$desiredColumn=null)},this.moveCursorToScreen=function(e,t,n){var r=this.session.screenToDocumentPosition(e,t);this.moveCursorTo(r.row,r.column,n)},this.detach=function(){this.lead.detach(),this.anchor.detach(),this.session=this.doc=null},this.fromOrientedRange=function(e){this.setSelectionRange(e,e.cursor==e.start),this.$desiredColumn=e.desiredColumn||this.$desiredColumn},this.toOrientedRange=function(e){var t=this.getRange();return e?(e.start.column=t.start.column,e.start.row=t.start.row,e.end.column=t.end.column,e.end.row=t.end.row):e=t,e.cursor=this.isBackwards()?e.start:e.end,e.desiredColumn=this.$desiredColumn,e},this.getRangeOfMovements=function(e){var t=this.getCursor();try{e(this);var n=this.getCursor();return a.fromPoints(t,n)}catch(r){return a.fromPoints(t,t)}finally{this.moveCursorToPosition(t)}},this.toJSON=function(){if(this.rangeCount)var e=this.ranges.map(function(e){var t=e.clone();return t.isBackwards=e.cursor==e.start,t});else{e=this.getRange();e.isBackwards=this.isBackwards()}return e},this.fromJSON=function(e){if(void 0==e.start){if(this.rangeList){this.toSingleRange(e[0]);for(var t=e.length;t--;){var n=a.fromPoints(e[t].start,e[t].end);e[t].isBackwards&&(n.cursor=n.start),this.addRange(n,!0)}return}e=e[0]}this.rangeList&&this.toSingleRange(e),this.setSelectionRange(e,e.isBackwards)},this.isEqual=function(e){if((e.length||this.rangeCount)&&e.length!=this.rangeCount)return!1;if(!e.length||!this.ranges)return this.getRange().isEqual(e);for(var t=this.ranges.length;t--;)if(!this.ranges[t].isEqual(e[t]))return!1;return!0}}).call(s.prototype),t.Selection=s}),ace.define(\"ace/tokenizer\",[\"require\",\"exports\",\"module\",\"ace/config\"],function(e,t,n){\"use strict\";var r=e(\"./config\"),i=2e3,o=function(e){for(var t in this.states=e,this.regExps={},this.matchMappings={},this.states){for(var n=this.states[t],r=[],i=0,o=this.matchMappings[t]={defaultToken:\"text\"},a=\"g\",s=[],l=0;l<n.length;l++){var c=n[l];if(c.defaultToken&&(o.defaultToken=c.defaultToken),c.caseInsensitive&&(a=\"gi\"),null!=c.regex){c.regex instanceof RegExp&&(c.regex=c.regex.toString().slice(1,-1));var u=c.regex,d=new RegExp(\"(?:(\"+u+\")|(.))\").exec(\"a\").length-2;Array.isArray(c.token)?1==c.token.length||1==d?c.token=c.token[0]:d-1!=c.token.length?(this.reportError(\"number of classes and regexp groups doesn't match\",{rule:c,groupCount:d-1}),c.token=c.token[0]):(c.tokenArray=c.token,c.token=null,c.onMatch=this.$arrayTokens):\"function\"!=typeof c.token||c.onMatch||(c.onMatch=d>1?this.$applyToken:c.token),d>1&&(/\\\\\\d/.test(c.regex)?u=c.regex.replace(/\\\\([0-9]+)/g,function(e,t){return\"\\\\\"+(parseInt(t,10)+i+1)}):(d=1,u=this.removeCapturingGroups(c.regex)),c.splitRegex||\"string\"==typeof c.token||s.push(c)),o[i]=l,i+=d,r.push(u),c.onMatch||(c.onMatch=null)}}r.length||(o[0]=0,r.push(\"$\")),s.forEach(function(e){e.splitRegex=this.createSplitterRegexp(e.regex,a)},this),this.regExps[t]=new RegExp(\"(\"+r.join(\")|(\")+\")|($)\",a)}};(function(){this.$setMaxTokenCount=function(e){i=0|e},this.$applyToken=function(e){var t=this.splitRegex.exec(e).slice(1),n=this.token.apply(this,t);if(\"string\"===typeof n)return[{type:n,value:e}];for(var r=[],i=0,o=n.length;i<o;i++)t[i]&&(r[r.length]={type:n[i],value:t[i]});return r},this.$arrayTokens=function(e){if(!e)return[];var t=this.splitRegex.exec(e);if(!t)return\"text\";for(var n=[],r=this.tokenArray,i=0,o=r.length;i<o;i++)t[i+1]&&(n[n.length]={type:r[i],value:t[i+1]});return n},this.removeCapturingGroups=function(e){var t=e.replace(/\\[(?:\\\\.|[^\\]])*?\\]|\\\\.|\\(\\?[:=!]|(\\()/g,function(e,t){return t?\"(?:\":e});return t},this.createSplitterRegexp=function(e,t){if(-1!=e.indexOf(\"(?=\")){var n=0,r=!1,i={};e.replace(/(\\\\.)|(\\((?:\\?[=!])?)|(\\))|([\\[\\]])/g,function(e,t,o,a,s,l){return r?r=\"]\"!=s:s?r=!0:a?(n==i.stack&&(i.end=l+1,i.stack=-1),n--):o&&(n++,1!=o.length&&(i.stack=n,i.start=l)),e}),null!=i.end&&/^\\)*$/.test(e.substr(i.end))&&(e=e.substring(0,i.start)+e.substr(i.end))}return\"^\"!=e.charAt(0)&&(e=\"^\"+e),\"$\"!=e.charAt(e.length-1)&&(e+=\"$\"),new RegExp(e,(t||\"\").replace(\"g\",\"\"))},this.getLineTokens=function(e,t){if(t&&\"string\"!=typeof t){var n=t.slice(0);t=n[0],\"#tmp\"===t&&(n.shift(),t=n.shift())}else n=[];var r=t||\"start\",o=this.states[r];o||(r=\"start\",o=this.states[r]);var a=this.matchMappings[r],s=this.regExps[r];s.lastIndex=0;var l,c=[],u=0,d=0,h={type:null,value:\"\"};while(l=s.exec(e)){var p=a.defaultToken,m=null,f=l[0],g=s.lastIndex;if(g-f.length>u){var b=e.substring(u,g-f.length);h.type==p?h.value+=b:(h.type&&c.push(h),h={type:p,value:b})}for(var v=0;v<l.length-2;v++)if(void 0!==l[v+1]){m=o[a[v]],p=m.onMatch?m.onMatch(f,r,n,e):m.token,m.next&&(r=\"string\"==typeof m.next?m.next:m.next(r,n),o=this.states[r],o||(this.reportError(\"state doesn't exist\",r),r=\"start\",o=this.states[r]),a=this.matchMappings[r],u=g,s=this.regExps[r],s.lastIndex=g),m.consumeLineEnd&&(u=g);break}if(f)if(\"string\"===typeof p)m&&!1===m.merge||h.type!==p?(h.type&&c.push(h),h={type:p,value:f}):h.value+=f;else if(p){h.type&&c.push(h),h={type:null,value:\"\"};for(v=0;v<p.length;v++)c.push(p[v])}if(u==e.length)break;if(u=g,d++>i){d>2*e.length&&this.reportError(\"infinite loop with in ace tokenizer\",{startState:t,line:e});while(u<e.length)h.type&&c.push(h),h={value:e.substring(u,u+=2e3),type:\"overflow\"};r=\"start\",n=[];break}}return h.type&&c.push(h),n.length>1&&n[0]!==r&&n.unshift(\"#tmp\",r),{tokens:c,state:n.length?n:r}},this.reportError=r.reportError}).call(o.prototype),t.Tokenizer=o}),ace.define(\"ace/mode/text_highlight_rules\",[\"require\",\"exports\",\"module\",\"ace/lib/lang\"],function(e,t,n){\"use strict\";var r=e(\"../lib/lang\"),i=function(){this.$rules={start:[{token:\"empty_line\",regex:\"^$\"},{defaultToken:\"text\"}]}};(function(){this.addRules=function(e,t){if(t)for(var n in e){for(var r=e[n],i=0;i<r.length;i++){var o=r[i];(o.next||o.onMatch)&&(\"string\"==typeof o.next&&0!==o.next.indexOf(t)&&(o.next=t+o.next),o.nextState&&0!==o.nextState.indexOf(t)&&(o.nextState=t+o.nextState))}this.$rules[t+n]=r}else for(var n in e)this.$rules[n]=e[n]},this.getRules=function(){return this.$rules},this.embedRules=function(e,t,n,i,o){var a=\"function\"==typeof e?(new e).getRules():e;if(i)for(var s=0;s<i.length;s++)i[s]=t+i[s];else for(var l in i=[],a)i.push(t+l);if(this.addRules(a,t),n){var c=Array.prototype[o?\"push\":\"unshift\"];for(s=0;s<i.length;s++)c.apply(this.$rules[i[s]],r.deepCopy(n))}this.$embeds||(this.$embeds=[]),this.$embeds.push(t)},this.getEmbeds=function(){return this.$embeds};var e=function(e,t){return(\"start\"!=e||t.length)&&t.unshift(this.nextState,e),this.nextState},t=function(e,t){return t.shift(),t.shift()||\"start\"};this.normalizeRules=function(){var n=0,r=this.$rules;function i(o){var a=r[o];a.processed=!0;for(var s=0;s<a.length;s++){var l=a[s],c=null;Array.isArray(l)&&(c=l,l={}),!l.regex&&l.start&&(l.regex=l.start,l.next||(l.next=[]),l.next.push({defaultToken:l.token},{token:l.token+\".end\",regex:l.end||l.start,next:\"pop\"}),l.token=l.token+\".start\",l.push=!0);var u=l.next||l.push;if(u&&Array.isArray(u)){var d=l.stateName;d||(d=l.token,\"string\"!=typeof d&&(d=d[0]||\"\"),r[d]&&(d+=n++)),r[d]=u,l.next=d,i(d)}else\"pop\"==u&&(l.next=t);if(l.push&&(l.nextState=l.next||l.push,l.next=e,delete l.push),l.rules)for(var h in l.rules)r[h]?r[h].push&&r[h].push.apply(r[h],l.rules[h]):r[h]=l.rules[h];var p=\"string\"==typeof l?l:l.include;if(p&&(c=Array.isArray(p)?p.map(function(e){return r[e]}):r[p]),c){var m=[s,1].concat(c);l.noEscape&&(m=m.filter(function(e){return!e.next})),a.splice.apply(a,m),s--}l.keywordMap&&(l.token=this.createKeywordMapper(l.keywordMap,l.defaultToken||\"text\",l.caseInsensitive),delete l.defaultToken)}}Object.keys(r).forEach(i,this)},this.createKeywordMapper=function(e,t,n,r){var i=Object.create(null);return Object.keys(e).forEach(function(t){var o=e[t];n&&(o=o.toLowerCase());for(var a=o.split(r||\"|\"),s=a.length;s--;)i[a[s]]=t}),Object.getPrototypeOf(i)&&(i.__proto__=null),this.$keywordList=Object.keys(i),e=null,n?function(e){return i[e.toLowerCase()]||t}:function(e){return i[e]||t}},this.getKeywords=function(){return this.$keywords}}).call(i.prototype),t.TextHighlightRules=i}),ace.define(\"ace/mode/behaviour\",[\"require\",\"exports\",\"module\"],function(e,t,n){\"use strict\";var r=function(){this.$behaviours={}};(function(){this.add=function(e,t,n){switch(void 0){case this.$behaviours:this.$behaviours={};case this.$behaviours[e]:this.$behaviours[e]={}}this.$behaviours[e][t]=n},this.addBehaviours=function(e){for(var t in e)for(var n in e[t])this.add(t,n,e[t][n])},this.remove=function(e){this.$behaviours&&this.$behaviours[e]&&delete this.$behaviours[e]},this.inherit=function(e,t){if(\"function\"===typeof e)var n=(new e).getBehaviours(t);else n=e.getBehaviours(t);this.addBehaviours(n)},this.getBehaviours=function(e){if(e){for(var t={},n=0;n<e.length;n++)this.$behaviours[e[n]]&&(t[e[n]]=this.$behaviours[e[n]]);return t}return this.$behaviours}}).call(r.prototype),t.Behaviour=r}),ace.define(\"ace/token_iterator\",[\"require\",\"exports\",\"module\",\"ace/range\"],function(e,t,n){\"use strict\";var r=e(\"./range\").Range,i=function(e,t,n){this.$session=e,this.$row=t,this.$rowTokens=e.getTokens(t);var r=e.getTokenAt(t,n);this.$tokenIndex=r?r.index:-1};(function(){this.stepBackward=function(){this.$tokenIndex-=1;while(this.$tokenIndex<0){if(this.$row-=1,this.$row<0)return this.$row=0,null;this.$rowTokens=this.$session.getTokens(this.$row),this.$tokenIndex=this.$rowTokens.length-1}return this.$rowTokens[this.$tokenIndex]},this.stepForward=function(){var e;this.$tokenIndex+=1;while(this.$tokenIndex>=this.$rowTokens.length){if(this.$row+=1,e||(e=this.$session.getLength()),this.$row>=e)return this.$row=e-1,null;this.$rowTokens=this.$session.getTokens(this.$row),this.$tokenIndex=0}return this.$rowTokens[this.$tokenIndex]},this.getCurrentToken=function(){return this.$rowTokens[this.$tokenIndex]},this.getCurrentTokenRow=function(){return this.$row},this.getCurrentTokenColumn=function(){var e=this.$rowTokens,t=this.$tokenIndex,n=e[t].start;if(void 0!==n)return n;n=0;while(t>0)t-=1,n+=e[t].value.length;return n},this.getCurrentTokenPosition=function(){return{row:this.$row,column:this.getCurrentTokenColumn()}},this.getCurrentTokenRange=function(){var e=this.$rowTokens[this.$tokenIndex],t=this.getCurrentTokenColumn();return new r(this.$row,t,this.$row,t+e.value.length)}}).call(i.prototype),t.TokenIterator=i}),ace.define(\"ace/mode/behaviour/cstyle\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/mode/behaviour\",\"ace/token_iterator\",\"ace/lib/lang\"],function(e,t,n){\"use strict\";var r,i=e(\"../../lib/oop\"),o=e(\"../behaviour\").Behaviour,a=e(\"../../token_iterator\").TokenIterator,s=e(\"../../lib/lang\"),l=[\"text\",\"paren.rparen\",\"punctuation.operator\"],c=[\"text\",\"paren.rparen\",\"punctuation.operator\",\"comment\"],u={},d={'\"':'\"',\"'\":\"'\"},h=function(e){var t=-1;if(e.multiSelect&&(t=e.selection.index,u.rangeCount!=e.multiSelect.rangeCount&&(u={rangeCount:e.multiSelect.rangeCount})),u[t])return r=u[t];r=u[t]={autoInsertedBrackets:0,autoInsertedRow:-1,autoInsertedLineEnd:\"\",maybeInsertedBrackets:0,maybeInsertedRow:-1,maybeInsertedLineStart:\"\",maybeInsertedLineEnd:\"\"}},p=function(e,t,n,r){var i=e.end.row-e.start.row;return{text:n+t+r,selection:[0,e.start.column+1,i,e.end.column+(i?0:1)]}},m=function(e){this.add(\"braces\",\"insertion\",function(t,n,i,o,a){var l=i.getCursorPosition(),c=o.doc.getLine(l.row);if(\"{\"==a){h(i);var u=i.getSelectionRange(),d=o.doc.getTextRange(u);if(\"\"!==d&&\"{\"!==d&&i.getWrapBehavioursEnabled())return p(u,d,\"{\",\"}\");if(m.isSaneInsertion(i,o))return/[\\]\\}\\)]/.test(c[l.column])||i.inMultiSelectMode||e&&e.braces?(m.recordAutoInsert(i,o,\"}\"),{text:\"{}\",selection:[1,1]}):(m.recordMaybeInsert(i,o,\"{\"),{text:\"{\",selection:[1,1]})}else if(\"}\"==a){h(i);var f=c.substring(l.column,l.column+1);if(\"}\"==f){var g=o.$findOpeningBracket(\"}\",{column:l.column+1,row:l.row});if(null!==g&&m.isAutoInsertedClosing(l,c,a))return m.popAutoInsertedClosing(),{text:\"\",selection:[1,1]}}}else{if(\"\\n\"==a||\"\\r\\n\"==a){h(i);var b=\"\";m.isMaybeInsertedClosing(l,c)&&(b=s.stringRepeat(\"}\",r.maybeInsertedBrackets),m.clearMaybeInsertedClosing());f=c.substring(l.column,l.column+1);if(\"}\"===f){var v=o.findMatchingBracket({row:l.row,column:l.column+1},\"}\");if(!v)return null;var k=this.$getIndent(o.getLine(v.row))}else{if(!b)return void m.clearMaybeInsertedClosing();k=this.$getIndent(c)}var y=k+o.getTabString();return{text:\"\\n\"+y+\"\\n\"+k+b,selection:[1,y.length,1,y.length]}}m.clearMaybeInsertedClosing()}}),this.add(\"braces\",\"deletion\",function(e,t,n,i,o){var a=i.doc.getTextRange(o);if(!o.isMultiLine()&&\"{\"==a){h(n);var s=i.doc.getLine(o.start.row),l=s.substring(o.end.column,o.end.column+1);if(\"}\"==l)return o.end.column++,o;r.maybeInsertedBrackets--}}),this.add(\"parens\",\"insertion\",function(e,t,n,r,i){if(\"(\"==i){h(n);var o=n.getSelectionRange(),a=r.doc.getTextRange(o);if(\"\"!==a&&n.getWrapBehavioursEnabled())return p(o,a,\"(\",\")\");if(m.isSaneInsertion(n,r))return m.recordAutoInsert(n,r,\")\"),{text:\"()\",selection:[1,1]}}else if(\")\"==i){h(n);var s=n.getCursorPosition(),l=r.doc.getLine(s.row),c=l.substring(s.column,s.column+1);if(\")\"==c){var u=r.$findOpeningBracket(\")\",{column:s.column+1,row:s.row});if(null!==u&&m.isAutoInsertedClosing(s,l,i))return m.popAutoInsertedClosing(),{text:\"\",selection:[1,1]}}}}),this.add(\"parens\",\"deletion\",function(e,t,n,r,i){var o=r.doc.getTextRange(i);if(!i.isMultiLine()&&\"(\"==o){h(n);var a=r.doc.getLine(i.start.row),s=a.substring(i.start.column+1,i.start.column+2);if(\")\"==s)return i.end.column++,i}}),this.add(\"brackets\",\"insertion\",function(e,t,n,r,i){if(\"[\"==i){h(n);var o=n.getSelectionRange(),a=r.doc.getTextRange(o);if(\"\"!==a&&n.getWrapBehavioursEnabled())return p(o,a,\"[\",\"]\");if(m.isSaneInsertion(n,r))return m.recordAutoInsert(n,r,\"]\"),{text:\"[]\",selection:[1,1]}}else if(\"]\"==i){h(n);var s=n.getCursorPosition(),l=r.doc.getLine(s.row),c=l.substring(s.column,s.column+1);if(\"]\"==c){var u=r.$findOpeningBracket(\"]\",{column:s.column+1,row:s.row});if(null!==u&&m.isAutoInsertedClosing(s,l,i))return m.popAutoInsertedClosing(),{text:\"\",selection:[1,1]}}}}),this.add(\"brackets\",\"deletion\",function(e,t,n,r,i){var o=r.doc.getTextRange(i);if(!i.isMultiLine()&&\"[\"==o){h(n);var a=r.doc.getLine(i.start.row),s=a.substring(i.start.column+1,i.start.column+2);if(\"]\"==s)return i.end.column++,i}}),this.add(\"string_dquotes\",\"insertion\",function(e,t,n,r,i){var o=r.$mode.$quotes||d;if(1==i.length&&o[i]){if(this.lineCommentStart&&-1!=this.lineCommentStart.indexOf(i))return;h(n);var a=i,s=n.getSelectionRange(),l=r.doc.getTextRange(s);if(!(\"\"===l||1==l.length&&o[l])&&n.getWrapBehavioursEnabled())return p(s,l,a,a);if(!l){var c=n.getCursorPosition(),u=r.doc.getLine(c.row),m=u.substring(c.column-1,c.column),f=u.substring(c.column,c.column+1),g=r.getTokenAt(c.row,c.column),b=r.getTokenAt(c.row,c.column+1);if(\"\\\\\"==m&&g&&/escape/.test(g.type))return null;var v,k=g&&/string|escape/.test(g.type),y=!b||/string|escape/.test(b.type);if(f==a)v=k!==y,v&&/string\\.end/.test(b.type)&&(v=!1);else{if(k&&!y)return null;if(k&&y)return null;var w=r.$mode.tokenRe;w.lastIndex=0;var x=w.test(m);w.lastIndex=0;var E=w.test(m);if(x||E)return null;if(f&&!/[\\s;,.})\\]\\\\]/.test(f))return null;v=!0}return{text:v?a+a:\"\",selection:[1,1]}}}}),this.add(\"string_dquotes\",\"deletion\",function(e,t,n,r,i){var o=r.doc.getTextRange(i);if(!i.isMultiLine()&&('\"'==o||\"'\"==o)){h(n);var a=r.doc.getLine(i.start.row),s=a.substring(i.start.column+1,i.start.column+2);if(s==o)return i.end.column++,i}})};m.isSaneInsertion=function(e,t){var n=e.getCursorPosition(),r=new a(t,n.row,n.column);if(!this.$matchTokenType(r.getCurrentToken()||\"text\",l)){var i=new a(t,n.row,n.column+1);if(!this.$matchTokenType(i.getCurrentToken()||\"text\",l))return!1}return r.stepForward(),r.getCurrentTokenRow()!==n.row||this.$matchTokenType(r.getCurrentToken()||\"text\",c)},m.$matchTokenType=function(e,t){return t.indexOf(e.type||e)>-1},m.recordAutoInsert=function(e,t,n){var i=e.getCursorPosition(),o=t.doc.getLine(i.row);this.isAutoInsertedClosing(i,o,r.autoInsertedLineEnd[0])||(r.autoInsertedBrackets=0),r.autoInsertedRow=i.row,r.autoInsertedLineEnd=n+o.substr(i.column),r.autoInsertedBrackets++},m.recordMaybeInsert=function(e,t,n){var i=e.getCursorPosition(),o=t.doc.getLine(i.row);this.isMaybeInsertedClosing(i,o)||(r.maybeInsertedBrackets=0),r.maybeInsertedRow=i.row,r.maybeInsertedLineStart=o.substr(0,i.column)+n,r.maybeInsertedLineEnd=o.substr(i.column),r.maybeInsertedBrackets++},m.isAutoInsertedClosing=function(e,t,n){return r.autoInsertedBrackets>0&&e.row===r.autoInsertedRow&&n===r.autoInsertedLineEnd[0]&&t.substr(e.column)===r.autoInsertedLineEnd},m.isMaybeInsertedClosing=function(e,t){return r.maybeInsertedBrackets>0&&e.row===r.maybeInsertedRow&&t.substr(e.column)===r.maybeInsertedLineEnd&&t.substr(0,e.column)==r.maybeInsertedLineStart},m.popAutoInsertedClosing=function(){r.autoInsertedLineEnd=r.autoInsertedLineEnd.substr(1),r.autoInsertedBrackets--},m.clearMaybeInsertedClosing=function(){r&&(r.maybeInsertedBrackets=0,r.maybeInsertedRow=-1)},i.inherits(m,o),t.CstyleBehaviour=m}),ace.define(\"ace/unicode\",[\"require\",\"exports\",\"module\"],function(e,t,n){\"use strict\";function r(e){var n=/\\w{4}/g;for(var r in e)t.packages[r]=e[r].replace(n,\"\\\\u$&\")}t.packages={},r({L:\"0041-005A0061-007A00AA00B500BA00C0-00D600D8-00F600F8-02C102C6-02D102E0-02E402EC02EE0370-037403760377037A-037D03860388-038A038C038E-03A103A3-03F503F7-0481048A-05250531-055605590561-058705D0-05EA05F0-05F20621-064A066E066F0671-06D306D506E506E606EE06EF06FA-06FC06FF07100712-072F074D-07A507B107CA-07EA07F407F507FA0800-0815081A082408280904-0939093D09500958-0961097109720979-097F0985-098C098F09900993-09A809AA-09B009B209B6-09B909BD09CE09DC09DD09DF-09E109F009F10A05-0A0A0A0F0A100A13-0A280A2A-0A300A320A330A350A360A380A390A59-0A5C0A5E0A72-0A740A85-0A8D0A8F-0A910A93-0AA80AAA-0AB00AB20AB30AB5-0AB90ABD0AD00AE00AE10B05-0B0C0B0F0B100B13-0B280B2A-0B300B320B330B35-0B390B3D0B5C0B5D0B5F-0B610B710B830B85-0B8A0B8E-0B900B92-0B950B990B9A0B9C0B9E0B9F0BA30BA40BA8-0BAA0BAE-0BB90BD00C05-0C0C0C0E-0C100C12-0C280C2A-0C330C35-0C390C3D0C580C590C600C610C85-0C8C0C8E-0C900C92-0CA80CAA-0CB30CB5-0CB90CBD0CDE0CE00CE10D05-0D0C0D0E-0D100D12-0D280D2A-0D390D3D0D600D610D7A-0D7F0D85-0D960D9A-0DB10DB3-0DBB0DBD0DC0-0DC60E01-0E300E320E330E40-0E460E810E820E840E870E880E8A0E8D0E94-0E970E99-0E9F0EA1-0EA30EA50EA70EAA0EAB0EAD-0EB00EB20EB30EBD0EC0-0EC40EC60EDC0EDD0F000F40-0F470F49-0F6C0F88-0F8B1000-102A103F1050-1055105A-105D106110651066106E-10701075-1081108E10A0-10C510D0-10FA10FC1100-1248124A-124D1250-12561258125A-125D1260-1288128A-128D1290-12B012B2-12B512B8-12BE12C012C2-12C512C8-12D612D8-13101312-13151318-135A1380-138F13A0-13F41401-166C166F-167F1681-169A16A0-16EA1700-170C170E-17111720-17311740-17511760-176C176E-17701780-17B317D717DC1820-18771880-18A818AA18B0-18F51900-191C1950-196D1970-19741980-19AB19C1-19C71A00-1A161A20-1A541AA71B05-1B331B45-1B4B1B83-1BA01BAE1BAF1C00-1C231C4D-1C4F1C5A-1C7D1CE9-1CEC1CEE-1CF11D00-1DBF1E00-1F151F18-1F1D1F20-1F451F48-1F4D1F50-1F571F591F5B1F5D1F5F-1F7D1F80-1FB41FB6-1FBC1FBE1FC2-1FC41FC6-1FCC1FD0-1FD31FD6-1FDB1FE0-1FEC1FF2-1FF41FF6-1FFC2071207F2090-209421022107210A-211321152119-211D212421262128212A-212D212F-2139213C-213F2145-2149214E218321842C00-2C2E2C30-2C5E2C60-2CE42CEB-2CEE2D00-2D252D30-2D652D6F2D80-2D962DA0-2DA62DA8-2DAE2DB0-2DB62DB8-2DBE2DC0-2DC62DC8-2DCE2DD0-2DD62DD8-2DDE2E2F300530063031-3035303B303C3041-3096309D-309F30A1-30FA30FC-30FF3105-312D3131-318E31A0-31B731F0-31FF3400-4DB54E00-9FCBA000-A48CA4D0-A4FDA500-A60CA610-A61FA62AA62BA640-A65FA662-A66EA67F-A697A6A0-A6E5A717-A71FA722-A788A78BA78CA7FB-A801A803-A805A807-A80AA80C-A822A840-A873A882-A8B3A8F2-A8F7A8FBA90A-A925A930-A946A960-A97CA984-A9B2A9CFAA00-AA28AA40-AA42AA44-AA4BAA60-AA76AA7AAA80-AAAFAAB1AAB5AAB6AAB9-AABDAAC0AAC2AADB-AADDABC0-ABE2AC00-D7A3D7B0-D7C6D7CB-D7FBF900-FA2DFA30-FA6DFA70-FAD9FB00-FB06FB13-FB17FB1DFB1F-FB28FB2A-FB36FB38-FB3CFB3EFB40FB41FB43FB44FB46-FBB1FBD3-FD3DFD50-FD8FFD92-FDC7FDF0-FDFBFE70-FE74FE76-FEFCFF21-FF3AFF41-FF5AFF66-FFBEFFC2-FFC7FFCA-FFCFFFD2-FFD7FFDA-FFDC\",Ll:\"0061-007A00AA00B500BA00DF-00F600F8-00FF01010103010501070109010B010D010F01110113011501170119011B011D011F01210123012501270129012B012D012F01310133013501370138013A013C013E014001420144014601480149014B014D014F01510153015501570159015B015D015F01610163016501670169016B016D016F0171017301750177017A017C017E-0180018301850188018C018D019201950199-019B019E01A101A301A501A801AA01AB01AD01B001B401B601B901BA01BD-01BF01C601C901CC01CE01D001D201D401D601D801DA01DC01DD01DF01E101E301E501E701E901EB01ED01EF01F001F301F501F901FB01FD01FF02010203020502070209020B020D020F02110213021502170219021B021D021F02210223022502270229022B022D022F02310233-0239023C023F0240024202470249024B024D024F-02930295-02AF037103730377037B-037D039003AC-03CE03D003D103D5-03D703D903DB03DD03DF03E103E303E503E703E903EB03ED03EF-03F303F503F803FB03FC0430-045F04610463046504670469046B046D046F04710473047504770479047B047D047F0481048B048D048F04910493049504970499049B049D049F04A104A304A504A704A904AB04AD04AF04B104B304B504B704B904BB04BD04BF04C204C404C604C804CA04CC04CE04CF04D104D304D504D704D904DB04DD04DF04E104E304E504E704E904EB04ED04EF04F104F304F504F704F904FB04FD04FF05010503050505070509050B050D050F05110513051505170519051B051D051F0521052305250561-05871D00-1D2B1D62-1D771D79-1D9A1E011E031E051E071E091E0B1E0D1E0F1E111E131E151E171E191E1B1E1D1E1F1E211E231E251E271E291E2B1E2D1E2F1E311E331E351E371E391E3B1E3D1E3F1E411E431E451E471E491E4B1E4D1E4F1E511E531E551E571E591E5B1E5D1E5F1E611E631E651E671E691E6B1E6D1E6F1E711E731E751E771E791E7B1E7D1E7F1E811E831E851E871E891E8B1E8D1E8F1E911E931E95-1E9D1E9F1EA11EA31EA51EA71EA91EAB1EAD1EAF1EB11EB31EB51EB71EB91EBB1EBD1EBF1EC11EC31EC51EC71EC91ECB1ECD1ECF1ED11ED31ED51ED71ED91EDB1EDD1EDF1EE11EE31EE51EE71EE91EEB1EED1EEF1EF11EF31EF51EF71EF91EFB1EFD1EFF-1F071F10-1F151F20-1F271F30-1F371F40-1F451F50-1F571F60-1F671F70-1F7D1F80-1F871F90-1F971FA0-1FA71FB0-1FB41FB61FB71FBE1FC2-1FC41FC61FC71FD0-1FD31FD61FD71FE0-1FE71FF2-1FF41FF61FF7210A210E210F2113212F21342139213C213D2146-2149214E21842C30-2C5E2C612C652C662C682C6A2C6C2C712C732C742C76-2C7C2C812C832C852C872C892C8B2C8D2C8F2C912C932C952C972C992C9B2C9D2C9F2CA12CA32CA52CA72CA92CAB2CAD2CAF2CB12CB32CB52CB72CB92CBB2CBD2CBF2CC12CC32CC52CC72CC92CCB2CCD2CCF2CD12CD32CD52CD72CD92CDB2CDD2CDF2CE12CE32CE42CEC2CEE2D00-2D25A641A643A645A647A649A64BA64DA64FA651A653A655A657A659A65BA65DA65FA663A665A667A669A66BA66DA681A683A685A687A689A68BA68DA68FA691A693A695A697A723A725A727A729A72BA72DA72F-A731A733A735A737A739A73BA73DA73FA741A743A745A747A749A74BA74DA74FA751A753A755A757A759A75BA75DA75FA761A763A765A767A769A76BA76DA76FA771-A778A77AA77CA77FA781A783A785A787A78CFB00-FB06FB13-FB17FF41-FF5A\",Lu:\"0041-005A00C0-00D600D8-00DE01000102010401060108010A010C010E01100112011401160118011A011C011E01200122012401260128012A012C012E01300132013401360139013B013D013F0141014301450147014A014C014E01500152015401560158015A015C015E01600162016401660168016A016C016E017001720174017601780179017B017D018101820184018601870189-018B018E-0191019301940196-0198019C019D019F01A001A201A401A601A701A901AC01AE01AF01B1-01B301B501B701B801BC01C401C701CA01CD01CF01D101D301D501D701D901DB01DE01E001E201E401E601E801EA01EC01EE01F101F401F6-01F801FA01FC01FE02000202020402060208020A020C020E02100212021402160218021A021C021E02200222022402260228022A022C022E02300232023A023B023D023E02410243-02460248024A024C024E03700372037603860388-038A038C038E038F0391-03A103A3-03AB03CF03D2-03D403D803DA03DC03DE03E003E203E403E603E803EA03EC03EE03F403F703F903FA03FD-042F04600462046404660468046A046C046E04700472047404760478047A047C047E0480048A048C048E04900492049404960498049A049C049E04A004A204A404A604A804AA04AC04AE04B004B204B404B604B804BA04BC04BE04C004C104C304C504C704C904CB04CD04D004D204D404D604D804DA04DC04DE04E004E204E404E604E804EA04EC04EE04F004F204F404F604F804FA04FC04FE05000502050405060508050A050C050E05100512051405160518051A051C051E0520052205240531-055610A0-10C51E001E021E041E061E081E0A1E0C1E0E1E101E121E141E161E181E1A1E1C1E1E1E201E221E241E261E281E2A1E2C1E2E1E301E321E341E361E381E3A1E3C1E3E1E401E421E441E461E481E4A1E4C1E4E1E501E521E541E561E581E5A1E5C1E5E1E601E621E641E661E681E6A1E6C1E6E1E701E721E741E761E781E7A1E7C1E7E1E801E821E841E861E881E8A1E8C1E8E1E901E921E941E9E1EA01EA21EA41EA61EA81EAA1EAC1EAE1EB01EB21EB41EB61EB81EBA1EBC1EBE1EC01EC21EC41EC61EC81ECA1ECC1ECE1ED01ED21ED41ED61ED81EDA1EDC1EDE1EE01EE21EE41EE61EE81EEA1EEC1EEE1EF01EF21EF41EF61EF81EFA1EFC1EFE1F08-1F0F1F18-1F1D1F28-1F2F1F38-1F3F1F48-1F4D1F591F5B1F5D1F5F1F68-1F6F1FB8-1FBB1FC8-1FCB1FD8-1FDB1FE8-1FEC1FF8-1FFB21022107210B-210D2110-211221152119-211D212421262128212A-212D2130-2133213E213F214521832C00-2C2E2C602C62-2C642C672C692C6B2C6D-2C702C722C752C7E-2C802C822C842C862C882C8A2C8C2C8E2C902C922C942C962C982C9A2C9C2C9E2CA02CA22CA42CA62CA82CAA2CAC2CAE2CB02CB22CB42CB62CB82CBA2CBC2CBE2CC02CC22CC42CC62CC82CCA2CCC2CCE2CD02CD22CD42CD62CD82CDA2CDC2CDE2CE02CE22CEB2CEDA640A642A644A646A648A64AA64CA64EA650A652A654A656A658A65AA65CA65EA662A664A666A668A66AA66CA680A682A684A686A688A68AA68CA68EA690A692A694A696A722A724A726A728A72AA72CA72EA732A734A736A738A73AA73CA73EA740A742A744A746A748A74AA74CA74EA750A752A754A756A758A75AA75CA75EA760A762A764A766A768A76AA76CA76EA779A77BA77DA77EA780A782A784A786A78BFF21-FF3A\",Lt:\"01C501C801CB01F21F88-1F8F1F98-1F9F1FA8-1FAF1FBC1FCC1FFC\",Lm:\"02B0-02C102C6-02D102E0-02E402EC02EE0374037A0559064006E506E607F407F507FA081A0824082809710E460EC610FC17D718431AA71C78-1C7D1D2C-1D611D781D9B-1DBF2071207F2090-20942C7D2D6F2E2F30053031-3035303B309D309E30FC-30FEA015A4F8-A4FDA60CA67FA717-A71FA770A788A9CFAA70AADDFF70FF9EFF9F\",Lo:\"01BB01C0-01C3029405D0-05EA05F0-05F20621-063F0641-064A066E066F0671-06D306D506EE06EF06FA-06FC06FF07100712-072F074D-07A507B107CA-07EA0800-08150904-0939093D09500958-096109720979-097F0985-098C098F09900993-09A809AA-09B009B209B6-09B909BD09CE09DC09DD09DF-09E109F009F10A05-0A0A0A0F0A100A13-0A280A2A-0A300A320A330A350A360A380A390A59-0A5C0A5E0A72-0A740A85-0A8D0A8F-0A910A93-0AA80AAA-0AB00AB20AB30AB5-0AB90ABD0AD00AE00AE10B05-0B0C0B0F0B100B13-0B280B2A-0B300B320B330B35-0B390B3D0B5C0B5D0B5F-0B610B710B830B85-0B8A0B8E-0B900B92-0B950B990B9A0B9C0B9E0B9F0BA30BA40BA8-0BAA0BAE-0BB90BD00C05-0C0C0C0E-0C100C12-0C280C2A-0C330C35-0C390C3D0C580C590C600C610C85-0C8C0C8E-0C900C92-0CA80CAA-0CB30CB5-0CB90CBD0CDE0CE00CE10D05-0D0C0D0E-0D100D12-0D280D2A-0D390D3D0D600D610D7A-0D7F0D85-0D960D9A-0DB10DB3-0DBB0DBD0DC0-0DC60E01-0E300E320E330E40-0E450E810E820E840E870E880E8A0E8D0E94-0E970E99-0E9F0EA1-0EA30EA50EA70EAA0EAB0EAD-0EB00EB20EB30EBD0EC0-0EC40EDC0EDD0F000F40-0F470F49-0F6C0F88-0F8B1000-102A103F1050-1055105A-105D106110651066106E-10701075-1081108E10D0-10FA1100-1248124A-124D1250-12561258125A-125D1260-1288128A-128D1290-12B012B2-12B512B8-12BE12C012C2-12C512C8-12D612D8-13101312-13151318-135A1380-138F13A0-13F41401-166C166F-167F1681-169A16A0-16EA1700-170C170E-17111720-17311740-17511760-176C176E-17701780-17B317DC1820-18421844-18771880-18A818AA18B0-18F51900-191C1950-196D1970-19741980-19AB19C1-19C71A00-1A161A20-1A541B05-1B331B45-1B4B1B83-1BA01BAE1BAF1C00-1C231C4D-1C4F1C5A-1C771CE9-1CEC1CEE-1CF12135-21382D30-2D652D80-2D962DA0-2DA62DA8-2DAE2DB0-2DB62DB8-2DBE2DC0-2DC62DC8-2DCE2DD0-2DD62DD8-2DDE3006303C3041-3096309F30A1-30FA30FF3105-312D3131-318E31A0-31B731F0-31FF3400-4DB54E00-9FCBA000-A014A016-A48CA4D0-A4F7A500-A60BA610-A61FA62AA62BA66EA6A0-A6E5A7FB-A801A803-A805A807-A80AA80C-A822A840-A873A882-A8B3A8F2-A8F7A8FBA90A-A925A930-A946A960-A97CA984-A9B2AA00-AA28AA40-AA42AA44-AA4BAA60-AA6FAA71-AA76AA7AAA80-AAAFAAB1AAB5AAB6AAB9-AABDAAC0AAC2AADBAADCABC0-ABE2AC00-D7A3D7B0-D7C6D7CB-D7FBF900-FA2DFA30-FA6DFA70-FAD9FB1DFB1F-FB28FB2A-FB36FB38-FB3CFB3EFB40FB41FB43FB44FB46-FBB1FBD3-FD3DFD50-FD8FFD92-FDC7FDF0-FDFBFE70-FE74FE76-FEFCFF66-FF6FFF71-FF9DFFA0-FFBEFFC2-FFC7FFCA-FFCFFFD2-FFD7FFDA-FFDC\",M:\"0300-036F0483-04890591-05BD05BF05C105C205C405C505C70610-061A064B-065E067006D6-06DC06DE-06E406E706E806EA-06ED07110730-074A07A6-07B007EB-07F30816-0819081B-08230825-08270829-082D0900-0903093C093E-094E0951-0955096209630981-098309BC09BE-09C409C709C809CB-09CD09D709E209E30A01-0A030A3C0A3E-0A420A470A480A4B-0A4D0A510A700A710A750A81-0A830ABC0ABE-0AC50AC7-0AC90ACB-0ACD0AE20AE30B01-0B030B3C0B3E-0B440B470B480B4B-0B4D0B560B570B620B630B820BBE-0BC20BC6-0BC80BCA-0BCD0BD70C01-0C030C3E-0C440C46-0C480C4A-0C4D0C550C560C620C630C820C830CBC0CBE-0CC40CC6-0CC80CCA-0CCD0CD50CD60CE20CE30D020D030D3E-0D440D46-0D480D4A-0D4D0D570D620D630D820D830DCA0DCF-0DD40DD60DD8-0DDF0DF20DF30E310E34-0E3A0E47-0E4E0EB10EB4-0EB90EBB0EBC0EC8-0ECD0F180F190F350F370F390F3E0F3F0F71-0F840F860F870F90-0F970F99-0FBC0FC6102B-103E1056-1059105E-10601062-10641067-106D1071-10741082-108D108F109A-109D135F1712-17141732-1734175217531772177317B6-17D317DD180B-180D18A91920-192B1930-193B19B0-19C019C819C91A17-1A1B1A55-1A5E1A60-1A7C1A7F1B00-1B041B34-1B441B6B-1B731B80-1B821BA1-1BAA1C24-1C371CD0-1CD21CD4-1CE81CED1CF21DC0-1DE61DFD-1DFF20D0-20F02CEF-2CF12DE0-2DFF302A-302F3099309AA66F-A672A67CA67DA6F0A6F1A802A806A80BA823-A827A880A881A8B4-A8C4A8E0-A8F1A926-A92DA947-A953A980-A983A9B3-A9C0AA29-AA36AA43AA4CAA4DAA7BAAB0AAB2-AAB4AAB7AAB8AABEAABFAAC1ABE3-ABEAABECABEDFB1EFE00-FE0FFE20-FE26\",Mn:\"0300-036F0483-04870591-05BD05BF05C105C205C405C505C70610-061A064B-065E067006D6-06DC06DF-06E406E706E806EA-06ED07110730-074A07A6-07B007EB-07F30816-0819081B-08230825-08270829-082D0900-0902093C0941-0948094D0951-095509620963098109BC09C1-09C409CD09E209E30A010A020A3C0A410A420A470A480A4B-0A4D0A510A700A710A750A810A820ABC0AC1-0AC50AC70AC80ACD0AE20AE30B010B3C0B3F0B41-0B440B4D0B560B620B630B820BC00BCD0C3E-0C400C46-0C480C4A-0C4D0C550C560C620C630CBC0CBF0CC60CCC0CCD0CE20CE30D41-0D440D4D0D620D630DCA0DD2-0DD40DD60E310E34-0E3A0E47-0E4E0EB10EB4-0EB90EBB0EBC0EC8-0ECD0F180F190F350F370F390F71-0F7E0F80-0F840F860F870F90-0F970F99-0FBC0FC6102D-10301032-10371039103A103D103E10581059105E-10601071-1074108210851086108D109D135F1712-17141732-1734175217531772177317B7-17BD17C617C9-17D317DD180B-180D18A91920-19221927192819321939-193B1A171A181A561A58-1A5E1A601A621A65-1A6C1A73-1A7C1A7F1B00-1B031B341B36-1B3A1B3C1B421B6B-1B731B801B811BA2-1BA51BA81BA91C2C-1C331C361C371CD0-1CD21CD4-1CE01CE2-1CE81CED1DC0-1DE61DFD-1DFF20D0-20DC20E120E5-20F02CEF-2CF12DE0-2DFF302A-302F3099309AA66FA67CA67DA6F0A6F1A802A806A80BA825A826A8C4A8E0-A8F1A926-A92DA947-A951A980-A982A9B3A9B6-A9B9A9BCAA29-AA2EAA31AA32AA35AA36AA43AA4CAAB0AAB2-AAB4AAB7AAB8AABEAABFAAC1ABE5ABE8ABEDFB1EFE00-FE0FFE20-FE26\",Mc:\"0903093E-09400949-094C094E0982098309BE-09C009C709C809CB09CC09D70A030A3E-0A400A830ABE-0AC00AC90ACB0ACC0B020B030B3E0B400B470B480B4B0B4C0B570BBE0BBF0BC10BC20BC6-0BC80BCA-0BCC0BD70C01-0C030C41-0C440C820C830CBE0CC0-0CC40CC70CC80CCA0CCB0CD50CD60D020D030D3E-0D400D46-0D480D4A-0D4C0D570D820D830DCF-0DD10DD8-0DDF0DF20DF30F3E0F3F0F7F102B102C10311038103B103C105610571062-10641067-106D108310841087-108C108F109A-109C17B617BE-17C517C717C81923-19261929-192B193019311933-193819B0-19C019C819C91A19-1A1B1A551A571A611A631A641A6D-1A721B041B351B3B1B3D-1B411B431B441B821BA11BA61BA71BAA1C24-1C2B1C341C351CE11CF2A823A824A827A880A881A8B4-A8C3A952A953A983A9B4A9B5A9BAA9BBA9BD-A9C0AA2FAA30AA33AA34AA4DAA7BABE3ABE4ABE6ABE7ABE9ABEAABEC\",Me:\"0488048906DE20DD-20E020E2-20E4A670-A672\",N:\"0030-003900B200B300B900BC-00BE0660-066906F0-06F907C0-07C90966-096F09E6-09EF09F4-09F90A66-0A6F0AE6-0AEF0B66-0B6F0BE6-0BF20C66-0C6F0C78-0C7E0CE6-0CEF0D66-0D750E50-0E590ED0-0ED90F20-0F331040-10491090-10991369-137C16EE-16F017E0-17E917F0-17F91810-18191946-194F19D0-19DA1A80-1A891A90-1A991B50-1B591BB0-1BB91C40-1C491C50-1C5920702074-20792080-20892150-21822185-21892460-249B24EA-24FF2776-27932CFD30073021-30293038-303A3192-31953220-32293251-325F3280-328932B1-32BFA620-A629A6E6-A6EFA830-A835A8D0-A8D9A900-A909A9D0-A9D9AA50-AA59ABF0-ABF9FF10-FF19\",Nd:\"0030-00390660-066906F0-06F907C0-07C90966-096F09E6-09EF0A66-0A6F0AE6-0AEF0B66-0B6F0BE6-0BEF0C66-0C6F0CE6-0CEF0D66-0D6F0E50-0E590ED0-0ED90F20-0F291040-10491090-109917E0-17E91810-18191946-194F19D0-19DA1A80-1A891A90-1A991B50-1B591BB0-1BB91C40-1C491C50-1C59A620-A629A8D0-A8D9A900-A909A9D0-A9D9AA50-AA59ABF0-ABF9FF10-FF19\",Nl:\"16EE-16F02160-21822185-218830073021-30293038-303AA6E6-A6EF\",No:\"00B200B300B900BC-00BE09F4-09F90BF0-0BF20C78-0C7E0D70-0D750F2A-0F331369-137C17F0-17F920702074-20792080-20892150-215F21892460-249B24EA-24FF2776-27932CFD3192-31953220-32293251-325F3280-328932B1-32BFA830-A835\",P:\"0021-00230025-002A002C-002F003A003B003F0040005B-005D005F007B007D00A100AB00B700BB00BF037E0387055A-055F0589058A05BE05C005C305C605F305F40609060A060C060D061B061E061F066A-066D06D40700-070D07F7-07F90830-083E0964096509700DF40E4F0E5A0E5B0F04-0F120F3A-0F3D0F850FD0-0FD4104A-104F10FB1361-13681400166D166E169B169C16EB-16ED1735173617D4-17D617D8-17DA1800-180A1944194519DE19DF1A1E1A1F1AA0-1AA61AA8-1AAD1B5A-1B601C3B-1C3F1C7E1C7F1CD32010-20272030-20432045-20512053-205E207D207E208D208E2329232A2768-277527C527C627E6-27EF2983-299829D8-29DB29FC29FD2CF9-2CFC2CFE2CFF2E00-2E2E2E302E313001-30033008-30113014-301F3030303D30A030FBA4FEA4FFA60D-A60FA673A67EA6F2-A6F7A874-A877A8CEA8CFA8F8-A8FAA92EA92FA95FA9C1-A9CDA9DEA9DFAA5C-AA5FAADEAADFABEBFD3EFD3FFE10-FE19FE30-FE52FE54-FE61FE63FE68FE6AFE6BFF01-FF03FF05-FF0AFF0C-FF0FFF1AFF1BFF1FFF20FF3B-FF3DFF3FFF5BFF5DFF5F-FF65\",Pd:\"002D058A05BE140018062010-20152E172E1A301C303030A0FE31FE32FE58FE63FF0D\",Ps:\"0028005B007B0F3A0F3C169B201A201E2045207D208D23292768276A276C276E27702772277427C527E627E827EA27EC27EE2983298529872989298B298D298F299129932995299729D829DA29FC2E222E242E262E283008300A300C300E3010301430163018301A301DFD3EFE17FE35FE37FE39FE3BFE3DFE3FFE41FE43FE47FE59FE5BFE5DFF08FF3BFF5BFF5FFF62\",Pe:\"0029005D007D0F3B0F3D169C2046207E208E232A2769276B276D276F27712773277527C627E727E927EB27ED27EF298429862988298A298C298E2990299229942996299829D929DB29FD2E232E252E272E293009300B300D300F3011301530173019301B301E301FFD3FFE18FE36FE38FE3AFE3CFE3EFE40FE42FE44FE48FE5AFE5CFE5EFF09FF3DFF5DFF60FF63\",Pi:\"00AB2018201B201C201F20392E022E042E092E0C2E1C2E20\",Pf:\"00BB2019201D203A2E032E052E0A2E0D2E1D2E21\",Pc:\"005F203F20402054FE33FE34FE4D-FE4FFF3F\",Po:\"0021-00230025-0027002A002C002E002F003A003B003F0040005C00A100B700BF037E0387055A-055F058905C005C305C605F305F40609060A060C060D061B061E061F066A-066D06D40700-070D07F7-07F90830-083E0964096509700DF40E4F0E5A0E5B0F04-0F120F850FD0-0FD4104A-104F10FB1361-1368166D166E16EB-16ED1735173617D4-17D617D8-17DA1800-18051807-180A1944194519DE19DF1A1E1A1F1AA0-1AA61AA8-1AAD1B5A-1B601C3B-1C3F1C7E1C7F1CD3201620172020-20272030-2038203B-203E2041-20432047-205120532055-205E2CF9-2CFC2CFE2CFF2E002E012E06-2E082E0B2E0E-2E162E182E192E1B2E1E2E1F2E2A-2E2E2E302E313001-3003303D30FBA4FEA4FFA60D-A60FA673A67EA6F2-A6F7A874-A877A8CEA8CFA8F8-A8FAA92EA92FA95FA9C1-A9CDA9DEA9DFAA5C-AA5FAADEAADFABEBFE10-FE16FE19FE30FE45FE46FE49-FE4CFE50-FE52FE54-FE57FE5F-FE61FE68FE6AFE6BFF01-FF03FF05-FF07FF0AFF0CFF0EFF0FFF1AFF1BFF1FFF20FF3CFF61FF64FF65\",S:\"0024002B003C-003E005E0060007C007E00A2-00A900AC00AE-00B100B400B600B800D700F702C2-02C502D2-02DF02E5-02EB02ED02EF-02FF03750384038503F604820606-0608060B060E060F06E906FD06FE07F609F209F309FA09FB0AF10B700BF3-0BFA0C7F0CF10CF20D790E3F0F01-0F030F13-0F170F1A-0F1F0F340F360F380FBE-0FC50FC7-0FCC0FCE0FCF0FD5-0FD8109E109F13601390-139917DB194019E0-19FF1B61-1B6A1B74-1B7C1FBD1FBF-1FC11FCD-1FCF1FDD-1FDF1FED-1FEF1FFD1FFE20442052207A-207C208A-208C20A0-20B8210021012103-21062108210921142116-2118211E-2123212521272129212E213A213B2140-2144214A-214D214F2190-2328232B-23E82400-24262440-244A249C-24E92500-26CD26CF-26E126E326E8-26FF2701-27042706-2709270C-27272729-274B274D274F-27522756-275E2761-276727942798-27AF27B1-27BE27C0-27C427C7-27CA27CC27D0-27E527F0-29822999-29D729DC-29FB29FE-2B4C2B50-2B592CE5-2CEA2E80-2E992E9B-2EF32F00-2FD52FF0-2FFB300430123013302030363037303E303F309B309C319031913196-319F31C0-31E33200-321E322A-32503260-327F328A-32B032C0-32FE3300-33FF4DC0-4DFFA490-A4C6A700-A716A720A721A789A78AA828-A82BA836-A839AA77-AA79FB29FDFCFDFDFE62FE64-FE66FE69FF04FF0BFF1C-FF1EFF3EFF40FF5CFF5EFFE0-FFE6FFE8-FFEEFFFCFFFD\",Sm:\"002B003C-003E007C007E00AC00B100D700F703F60606-060820442052207A-207C208A-208C2140-2144214B2190-2194219A219B21A021A321A621AE21CE21CF21D221D421F4-22FF2308-230B23202321237C239B-23B323DC-23E125B725C125F8-25FF266F27C0-27C427C7-27CA27CC27D0-27E527F0-27FF2900-29822999-29D729DC-29FB29FE-2AFF2B30-2B442B47-2B4CFB29FE62FE64-FE66FF0BFF1C-FF1EFF5CFF5EFFE2FFE9-FFEC\",Sc:\"002400A2-00A5060B09F209F309FB0AF10BF90E3F17DB20A0-20B8A838FDFCFE69FF04FFE0FFE1FFE5FFE6\",Sk:\"005E006000A800AF00B400B802C2-02C502D2-02DF02E5-02EB02ED02EF-02FF0375038403851FBD1FBF-1FC11FCD-1FCF1FDD-1FDF1FED-1FEF1FFD1FFE309B309CA700-A716A720A721A789A78AFF3EFF40FFE3\",So:\"00A600A700A900AE00B000B60482060E060F06E906FD06FE07F609FA0B700BF3-0BF80BFA0C7F0CF10CF20D790F01-0F030F13-0F170F1A-0F1F0F340F360F380FBE-0FC50FC7-0FCC0FCE0FCF0FD5-0FD8109E109F13601390-1399194019E0-19FF1B61-1B6A1B74-1B7C210021012103-21062108210921142116-2118211E-2123212521272129212E213A213B214A214C214D214F2195-2199219C-219F21A121A221A421A521A7-21AD21AF-21CD21D021D121D321D5-21F32300-2307230C-231F2322-2328232B-237B237D-239A23B4-23DB23E2-23E82400-24262440-244A249C-24E92500-25B625B8-25C025C2-25F72600-266E2670-26CD26CF-26E126E326E8-26FF2701-27042706-2709270C-27272729-274B274D274F-27522756-275E2761-276727942798-27AF27B1-27BE2800-28FF2B00-2B2F2B452B462B50-2B592CE5-2CEA2E80-2E992E9B-2EF32F00-2FD52FF0-2FFB300430123013302030363037303E303F319031913196-319F31C0-31E33200-321E322A-32503260-327F328A-32B032C0-32FE3300-33FF4DC0-4DFFA490-A4C6A828-A82BA836A837A839AA77-AA79FDFDFFE4FFE8FFEDFFEEFFFCFFFD\",Z:\"002000A01680180E2000-200A20282029202F205F3000\",Zs:\"002000A01680180E2000-200A202F205F3000\",Zl:\"2028\",Zp:\"2029\",C:\"0000-001F007F-009F00AD03780379037F-0383038B038D03A20526-05300557055805600588058B-059005C8-05CF05EB-05EF05F5-0605061C061D0620065F06DD070E070F074B074C07B2-07BF07FB-07FF082E082F083F-08FF093A093B094F095609570973-097809800984098D098E0991099209A909B109B3-09B509BA09BB09C509C609C909CA09CF-09D609D8-09DB09DE09E409E509FC-0A000A040A0B-0A0E0A110A120A290A310A340A370A3A0A3B0A3D0A43-0A460A490A4A0A4E-0A500A52-0A580A5D0A5F-0A650A76-0A800A840A8E0A920AA90AB10AB40ABA0ABB0AC60ACA0ACE0ACF0AD1-0ADF0AE40AE50AF00AF2-0B000B040B0D0B0E0B110B120B290B310B340B3A0B3B0B450B460B490B4A0B4E-0B550B58-0B5B0B5E0B640B650B72-0B810B840B8B-0B8D0B910B96-0B980B9B0B9D0BA0-0BA20BA5-0BA70BAB-0BAD0BBA-0BBD0BC3-0BC50BC90BCE0BCF0BD1-0BD60BD8-0BE50BFB-0C000C040C0D0C110C290C340C3A-0C3C0C450C490C4E-0C540C570C5A-0C5F0C640C650C70-0C770C800C810C840C8D0C910CA90CB40CBA0CBB0CC50CC90CCE-0CD40CD7-0CDD0CDF0CE40CE50CF00CF3-0D010D040D0D0D110D290D3A-0D3C0D450D490D4E-0D560D58-0D5F0D640D650D76-0D780D800D810D840D97-0D990DB20DBC0DBE0DBF0DC7-0DC90DCB-0DCE0DD50DD70DE0-0DF10DF5-0E000E3B-0E3E0E5C-0E800E830E850E860E890E8B0E8C0E8E-0E930E980EA00EA40EA60EA80EA90EAC0EBA0EBE0EBF0EC50EC70ECE0ECF0EDA0EDB0EDE-0EFF0F480F6D-0F700F8C-0F8F0F980FBD0FCD0FD9-0FFF10C6-10CF10FD-10FF1249124E124F12571259125E125F1289128E128F12B112B612B712BF12C112C612C712D7131113161317135B-135E137D-137F139A-139F13F5-13FF169D-169F16F1-16FF170D1715-171F1737-173F1754-175F176D17711774-177F17B417B517DE17DF17EA-17EF17FA-17FF180F181A-181F1878-187F18AB-18AF18F6-18FF191D-191F192C-192F193C-193F1941-1943196E196F1975-197F19AC-19AF19CA-19CF19DB-19DD1A1C1A1D1A5F1A7D1A7E1A8A-1A8F1A9A-1A9F1AAE-1AFF1B4C-1B4F1B7D-1B7F1BAB-1BAD1BBA-1BFF1C38-1C3A1C4A-1C4C1C80-1CCF1CF3-1CFF1DE7-1DFC1F161F171F1E1F1F1F461F471F4E1F4F1F581F5A1F5C1F5E1F7E1F7F1FB51FC51FD41FD51FDC1FF01FF11FF51FFF200B-200F202A-202E2060-206F20722073208F2095-209F20B9-20CF20F1-20FF218A-218F23E9-23FF2427-243F244B-245F26CE26E226E4-26E727002705270A270B2728274C274E2753-2755275F27602795-279727B027BF27CB27CD-27CF2B4D-2B4F2B5A-2BFF2C2F2C5F2CF2-2CF82D26-2D2F2D66-2D6E2D70-2D7F2D97-2D9F2DA72DAF2DB72DBF2DC72DCF2DD72DDF2E32-2E7F2E9A2EF4-2EFF2FD6-2FEF2FFC-2FFF3040309730983100-3104312E-3130318F31B8-31BF31E4-31EF321F32FF4DB6-4DBF9FCC-9FFFA48D-A48FA4C7-A4CFA62C-A63FA660A661A674-A67BA698-A69FA6F8-A6FFA78D-A7FAA82C-A82FA83A-A83FA878-A87FA8C5-A8CDA8DA-A8DFA8FC-A8FFA954-A95EA97D-A97FA9CEA9DA-A9DDA9E0-A9FFAA37-AA3FAA4EAA4FAA5AAA5BAA7C-AA7FAAC3-AADAAAE0-ABBFABEEABEFABFA-ABFFD7A4-D7AFD7C7-D7CAD7FC-F8FFFA2EFA2FFA6EFA6FFADA-FAFFFB07-FB12FB18-FB1CFB37FB3DFB3FFB42FB45FBB2-FBD2FD40-FD4FFD90FD91FDC8-FDEFFDFEFDFFFE1A-FE1FFE27-FE2FFE53FE67FE6C-FE6FFE75FEFD-FF00FFBF-FFC1FFC8FFC9FFD0FFD1FFD8FFD9FFDD-FFDFFFE7FFEF-FFFBFFFEFFFF\",Cc:\"0000-001F007F-009F\",Cf:\"00AD0600-060306DD070F17B417B5200B-200F202A-202E2060-2064206A-206FFEFFFFF9-FFFB\",Co:\"E000-F8FF\",Cs:\"D800-DFFF\",Cn:\"03780379037F-0383038B038D03A20526-05300557055805600588058B-059005C8-05CF05EB-05EF05F5-05FF06040605061C061D0620065F070E074B074C07B2-07BF07FB-07FF082E082F083F-08FF093A093B094F095609570973-097809800984098D098E0991099209A909B109B3-09B509BA09BB09C509C609C909CA09CF-09D609D8-09DB09DE09E409E509FC-0A000A040A0B-0A0E0A110A120A290A310A340A370A3A0A3B0A3D0A43-0A460A490A4A0A4E-0A500A52-0A580A5D0A5F-0A650A76-0A800A840A8E0A920AA90AB10AB40ABA0ABB0AC60ACA0ACE0ACF0AD1-0ADF0AE40AE50AF00AF2-0B000B040B0D0B0E0B110B120B290B310B340B3A0B3B0B450B460B490B4A0B4E-0B550B58-0B5B0B5E0B640B650B72-0B810B840B8B-0B8D0B910B96-0B980B9B0B9D0BA0-0BA20BA5-0BA70BAB-0BAD0BBA-0BBD0BC3-0BC50BC90BCE0BCF0BD1-0BD60BD8-0BE50BFB-0C000C040C0D0C110C290C340C3A-0C3C0C450C490C4E-0C540C570C5A-0C5F0C640C650C70-0C770C800C810C840C8D0C910CA90CB40CBA0CBB0CC50CC90CCE-0CD40CD7-0CDD0CDF0CE40CE50CF00CF3-0D010D040D0D0D110D290D3A-0D3C0D450D490D4E-0D560D58-0D5F0D640D650D76-0D780D800D810D840D97-0D990DB20DBC0DBE0DBF0DC7-0DC90DCB-0DCE0DD50DD70DE0-0DF10DF5-0E000E3B-0E3E0E5C-0E800E830E850E860E890E8B0E8C0E8E-0E930E980EA00EA40EA60EA80EA90EAC0EBA0EBE0EBF0EC50EC70ECE0ECF0EDA0EDB0EDE-0EFF0F480F6D-0F700F8C-0F8F0F980FBD0FCD0FD9-0FFF10C6-10CF10FD-10FF1249124E124F12571259125E125F1289128E128F12B112B612B712BF12C112C612C712D7131113161317135B-135E137D-137F139A-139F13F5-13FF169D-169F16F1-16FF170D1715-171F1737-173F1754-175F176D17711774-177F17DE17DF17EA-17EF17FA-17FF180F181A-181F1878-187F18AB-18AF18F6-18FF191D-191F192C-192F193C-193F1941-1943196E196F1975-197F19AC-19AF19CA-19CF19DB-19DD1A1C1A1D1A5F1A7D1A7E1A8A-1A8F1A9A-1A9F1AAE-1AFF1B4C-1B4F1B7D-1B7F1BAB-1BAD1BBA-1BFF1C38-1C3A1C4A-1C4C1C80-1CCF1CF3-1CFF1DE7-1DFC1F161F171F1E1F1F1F461F471F4E1F4F1F581F5A1F5C1F5E1F7E1F7F1FB51FC51FD41FD51FDC1FF01FF11FF51FFF2065-206920722073208F2095-209F20B9-20CF20F1-20FF218A-218F23E9-23FF2427-243F244B-245F26CE26E226E4-26E727002705270A270B2728274C274E2753-2755275F27602795-279727B027BF27CB27CD-27CF2B4D-2B4F2B5A-2BFF2C2F2C5F2CF2-2CF82D26-2D2F2D66-2D6E2D70-2D7F2D97-2D9F2DA72DAF2DB72DBF2DC72DCF2DD72DDF2E32-2E7F2E9A2EF4-2EFF2FD6-2FEF2FFC-2FFF3040309730983100-3104312E-3130318F31B8-31BF31E4-31EF321F32FF4DB6-4DBF9FCC-9FFFA48D-A48FA4C7-A4CFA62C-A63FA660A661A674-A67BA698-A69FA6F8-A6FFA78D-A7FAA82C-A82FA83A-A83FA878-A87FA8C5-A8CDA8DA-A8DFA8FC-A8FFA954-A95EA97D-A97FA9CEA9DA-A9DDA9E0-A9FFAA37-AA3FAA4EAA4FAA5AAA5BAA7C-AA7FAAC3-AADAAAE0-ABBFABEEABEFABFA-ABFFD7A4-D7AFD7C7-D7CAD7FC-D7FFFA2EFA2FFA6EFA6FFADA-FAFFFB07-FB12FB18-FB1CFB37FB3DFB3FFB42FB45FBB2-FBD2FD40-FD4FFD90FD91FDC8-FDEFFDFEFDFFFE1A-FE1FFE27-FE2FFE53FE67FE6C-FE6FFE75FEFDFEFEFF00FFBF-FFC1FFC8FFC9FFD0FFD1FFD8FFD9FFDD-FFDFFFE7FFEF-FFF8FFFEFFFF\"})}),ace.define(\"ace/mode/text\",[\"require\",\"exports\",\"module\",\"ace/tokenizer\",\"ace/mode/text_highlight_rules\",\"ace/mode/behaviour/cstyle\",\"ace/unicode\",\"ace/lib/lang\",\"ace/token_iterator\",\"ace/range\"],function(e,t,n){\"use strict\";var r=e(\"../tokenizer\").Tokenizer,i=e(\"./text_highlight_rules\").TextHighlightRules,o=e(\"./behaviour/cstyle\").CstyleBehaviour,a=e(\"../unicode\"),s=e(\"../lib/lang\"),l=e(\"../token_iterator\").TokenIterator,c=e(\"../range\").Range,u=function(){this.HighlightRules=i};(function(){this.$defaultBehaviour=new o,this.tokenRe=new RegExp(\"^[\"+a.packages.L+a.packages.Mn+a.packages.Mc+a.packages.Nd+a.packages.Pc+\"\\\\$_]+\",\"g\"),this.nonTokenRe=new RegExp(\"^(?:[^\"+a.packages.L+a.packages.Mn+a.packages.Mc+a.packages.Nd+a.packages.Pc+\"\\\\$_]|\\\\s])+\",\"g\"),this.getTokenizer=function(){return this.$tokenizer||(this.$highlightRules=this.$highlightRules||new this.HighlightRules(this.$highlightRuleConfig),this.$tokenizer=new r(this.$highlightRules.getRules())),this.$tokenizer},this.lineCommentStart=\"\",this.blockComment=\"\",this.toggleCommentLines=function(e,t,n,r){var i=t.doc,o=!0,a=!0,l=1/0,c=t.getTabSize(),u=!1;if(this.lineCommentStart){if(Array.isArray(this.lineCommentStart))f=this.lineCommentStart.map(s.escapeRegExp).join(\"|\"),p=this.lineCommentStart[0];else f=s.escapeRegExp(this.lineCommentStart),p=this.lineCommentStart;f=new RegExp(\"^(\\\\s*)(?:\"+f+\") ?\"),u=t.getUseSoftTabs();v=function(e,t){var n=e.match(f);if(n){var r=n[1].length,o=n[0].length;h(e,r,o)||\" \"!=n[0][o-1]||o--,i.removeInLine(t,r,o)}};var d=p+\" \",h=(b=function(e,t){o&&!/\\S/.test(e)||(h(e,l,l)?i.insertInLine({row:t,column:l},d):i.insertInLine({row:t,column:l},p))},k=function(e,t){return f.test(e)},function(e,t,n){var r=0;while(t--&&\" \"==e.charAt(t))r++;if(r%c!=0)return!1;r=0;while(\" \"==e.charAt(n++))r++;return c>2?r%c!=c-1:r%c==0})}else{if(!this.blockComment)return!1;var p=this.blockComment.start,m=this.blockComment.end,f=new RegExp(\"^(\\\\s*)(?:\"+s.escapeRegExp(p)+\")\"),g=new RegExp(\"(?:\"+s.escapeRegExp(m)+\")\\\\s*$\"),b=function(e,t){k(e,t)||o&&!/\\S/.test(e)||(i.insertInLine({row:t,column:e.length},m),i.insertInLine({row:t,column:l},p))},v=function(e,t){var n;(n=e.match(g))&&i.removeInLine(t,e.length-n[0].length,e.length),(n=e.match(f))&&i.removeInLine(t,n[1].length,n[0].length)},k=function(e,n){if(f.test(e))return!0;for(var r=t.getTokens(n),i=0;i<r.length;i++)if(\"comment\"===r[i].type)return!0}}function y(e){for(var t=n;t<=r;t++)e(i.getLine(t),t)}var w=1/0;y(function(e,t){var n=e.search(/\\S/);-1!==n?(n<l&&(l=n),a&&!k(e,t)&&(a=!1)):w>e.length&&(w=e.length)}),l==1/0&&(l=w,o=!1,a=!1),u&&l%c!=0&&(l=Math.floor(l/c)*c),y(a?v:b)},this.toggleBlockComment=function(e,t,n,r){var i=this.blockComment;if(i){!i.start&&i[0]&&(i=i[0]);var o,a,s=new l(t,r.row,r.column),u=s.getCurrentToken(),d=(t.selection,t.selection.toOrientedRange());if(u&&/comment/.test(u.type)){var h,p;while(u&&/comment/.test(u.type)){var m=u.value.indexOf(i.start);if(-1!=m){var f=s.getCurrentTokenRow(),g=s.getCurrentTokenColumn()+m;h=new c(f,g,f,g+i.start.length);break}u=s.stepBackward()}s=new l(t,r.row,r.column),u=s.getCurrentToken();while(u&&/comment/.test(u.type)){m=u.value.indexOf(i.end);if(-1!=m){f=s.getCurrentTokenRow(),g=s.getCurrentTokenColumn()+m;p=new c(f,g,f,g+i.end.length);break}u=s.stepForward()}p&&t.remove(p),h&&(t.remove(h),o=h.start.row,a=-i.start.length)}else a=i.start.length,o=n.start.row,t.insert(n.end,i.end),t.insert(n.start,i.start);d.start.row==o&&(d.start.column+=a),d.end.row==o&&(d.end.column+=a),t.selection.fromOrientedRange(d)}},this.getNextLineIndent=function(e,t,n){return this.$getIndent(t)},this.checkOutdent=function(e,t,n){return!1},this.autoOutdent=function(e,t,n){},this.$getIndent=function(e){return e.match(/^\\s*/)[0]},this.createWorker=function(e){return null},this.createModeDelegates=function(e){for(var t in this.$embeds=[],this.$modes={},e)e[t]&&(this.$embeds.push(t),this.$modes[t]=new e[t]);var n=[\"toggleBlockComment\",\"toggleCommentLines\",\"getNextLineIndent\",\"checkOutdent\",\"autoOutdent\",\"transformAction\",\"getCompletions\"];for(t=0;t<n.length;t++)(function(e){var r=n[t],i=e[r];e[n[t]]=function(){return this.$delegator(r,arguments,i)}})(this)},this.$delegator=function(e,t,n){var r=t[0];\"string\"!=typeof r&&(r=r[0]);for(var i=0;i<this.$embeds.length;i++)if(this.$modes[this.$embeds[i]]){var o=r.split(this.$embeds[i]);if(!o[0]&&o[1]){t[0]=o[1];var a=this.$modes[this.$embeds[i]];return a[e].apply(a,t)}}var s=n.apply(this,t);return n?s:void 0},this.transformAction=function(e,t,n,r,i){if(this.$behaviour){var o=this.$behaviour.getBehaviours();for(var a in o)if(o[a][t]){var s=o[a][t].apply(this,arguments);if(s)return s}}},this.getKeywords=function(e){if(!this.completionKeywords){var t=this.$tokenizer.rules,n=[];for(var r in t)for(var i=t[r],o=0,a=i.length;o<a;o++)if(\"string\"===typeof i[o].token)/keyword|support|storage/.test(i[o].token)&&n.push(i[o].regex);else if(\"object\"===typeof i[o].token)for(var s=0,l=i[o].token.length;s<l;s++)if(/keyword|support|storage/.test(i[o].token[s])){r=i[o].regex.match(/\\(.+?\\)/g)[s];n.push(r.substr(1,r.length-2))}this.completionKeywords=n}return e?n.concat(this.$keywordList||[]):this.$keywordList},this.$createKeywordList=function(){return this.$highlightRules||this.getTokenizer(),this.$keywordList=this.$highlightRules.$keywordList||[]},this.getCompletions=function(e,t,n,r){var i=this.$keywordList||this.$createKeywordList();return i.map(function(e){return{name:e,value:e,score:0,meta:\"keyword\"}})},this.$id=\"ace/mode/text\"}).call(u.prototype),t.Mode=u}),ace.define(\"ace/apply_delta\",[\"require\",\"exports\",\"module\"],function(e,t,n){\"use strict\";t.applyDelta=function(e,t,n){var r=t.start.row,i=t.start.column,o=e[r]||\"\";switch(t.action){case\"insert\":var a=t.lines;if(1===a.length)e[r]=o.substring(0,i)+t.lines[0]+o.substring(i);else{var s=[r,1].concat(t.lines);e.splice.apply(e,s),e[r]=o.substring(0,i)+e[r],e[r+t.lines.length-1]+=o.substring(i)}break;case\"remove\":var l=t.end.column,c=t.end.row;r===c?e[r]=o.substring(0,i)+o.substring(l):e.splice(r,c-r+1,o.substring(0,i)+e[c].substring(l));break}}}),ace.define(\"ace/anchor\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/lib/event_emitter\"],function(e,t,n){\"use strict\";var r=e(\"./lib/oop\"),i=e(\"./lib/event_emitter\").EventEmitter,o=t.Anchor=function(e,t,n){this.$onChange=this.onChange.bind(this),this.attach(e),\"undefined\"==typeof n?this.setPosition(t.row,t.column):this.setPosition(t,n)};(function(){function e(e,t,n){var r=n?e.column<=t.column:e.column<t.column;return e.row<t.row||e.row==t.row&&r}function t(t,n,r){var i=\"insert\"==t.action,o=(i?1:-1)*(t.end.row-t.start.row),a=(i?1:-1)*(t.end.column-t.start.column),s=t.start,l=i?s:t.end;return e(n,s,r)?{row:n.row,column:n.column}:e(l,n,!r)?{row:n.row+o,column:n.column+(n.row==l.row?a:0)}:{row:s.row,column:s.column}}r.implement(this,i),this.getPosition=function(){return this.$clipPositionToDocument(this.row,this.column)},this.getDocument=function(){return this.document},this.$insertRight=!1,this.onChange=function(e){if((e.start.row!=e.end.row||e.start.row==this.row)&&!(e.start.row>this.row)){var n=t(e,{row:this.row,column:this.column},this.$insertRight);this.setPosition(n.row,n.column,!0)}},this.setPosition=function(e,t,n){var r;if(r=n?{row:e,column:t}:this.$clipPositionToDocument(e,t),this.row!=r.row||this.column!=r.column){var i={row:this.row,column:this.column};this.row=r.row,this.column=r.column,this._signal(\"change\",{old:i,value:r})}},this.detach=function(){this.document.removeEventListener(\"change\",this.$onChange)},this.attach=function(e){this.document=e||this.document,this.document.on(\"change\",this.$onChange)},this.$clipPositionToDocument=function(e,t){var n={};return e>=this.document.getLength()?(n.row=Math.max(0,this.document.getLength()-1),n.column=this.document.getLine(n.row).length):e<0?(n.row=0,n.column=0):(n.row=e,n.column=Math.min(this.document.getLine(n.row).length,Math.max(0,t))),t<0&&(n.column=0),n}}).call(o.prototype)}),ace.define(\"ace/document\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/apply_delta\",\"ace/lib/event_emitter\",\"ace/range\",\"ace/anchor\"],function(e,t,n){\"use strict\";var r=e(\"./lib/oop\"),i=e(\"./apply_delta\").applyDelta,o=e(\"./lib/event_emitter\").EventEmitter,a=e(\"./range\").Range,s=e(\"./anchor\").Anchor,l=function(e){this.$lines=[\"\"],0===e.length?this.$lines=[\"\"]:Array.isArray(e)?this.insertMergedLines({row:0,column:0},e):this.insert({row:0,column:0},e)};(function(){r.implement(this,o),this.setValue=function(e){var t=this.getLength()-1;this.remove(new a(0,0,t,this.getLine(t).length)),this.insert({row:0,column:0},e)},this.getValue=function(){return this.getAllLines().join(this.getNewLineCharacter())},this.createAnchor=function(e,t){return new s(this,e,t)},0===\"aaa\".split(/a/).length?this.$split=function(e){return e.replace(/\\r\\n|\\r/g,\"\\n\").split(\"\\n\")}:this.$split=function(e){return e.split(/\\r\\n|\\r|\\n/)},this.$detectNewLine=function(e){var t=e.match(/^.*?(\\r\\n|\\r|\\n)/m);this.$autoNewLine=t?t[1]:\"\\n\",this._signal(\"changeNewLineMode\")},this.getNewLineCharacter=function(){switch(this.$newLineMode){case\"windows\":return\"\\r\\n\";case\"unix\":return\"\\n\";default:return this.$autoNewLine||\"\\n\"}},this.$autoNewLine=\"\",this.$newLineMode=\"auto\",this.setNewLineMode=function(e){this.$newLineMode!==e&&(this.$newLineMode=e,this._signal(\"changeNewLineMode\"))},this.getNewLineMode=function(){return this.$newLineMode},this.isNewLine=function(e){return\"\\r\\n\"==e||\"\\r\"==e||\"\\n\"==e},this.getLine=function(e){return this.$lines[e]||\"\"},this.getLines=function(e,t){return this.$lines.slice(e,t+1)},this.getAllLines=function(){return this.getLines(0,this.getLength())},this.getLength=function(){return this.$lines.length},this.getTextRange=function(e){return this.getLinesForRange(e).join(this.getNewLineCharacter())},this.getLinesForRange=function(e){var t;if(e.start.row===e.end.row)t=[this.getLine(e.start.row).substring(e.start.column,e.end.column)];else{t=this.getLines(e.start.row,e.end.row),t[0]=(t[0]||\"\").substring(e.start.column);var n=t.length-1;e.end.row-e.start.row==n&&(t[n]=t[n].substring(0,e.end.column))}return t},this.insertLines=function(e,t){return console.warn(\"Use of document.insertLines is deprecated. Use the insertFullLines method instead.\"),this.insertFullLines(e,t)},this.removeLines=function(e,t){return console.warn(\"Use of document.removeLines is deprecated. Use the removeFullLines method instead.\"),this.removeFullLines(e,t)},this.insertNewLine=function(e){return console.warn(\"Use of document.insertNewLine is deprecated. Use insertMergedLines(position, ['', '']) instead.\"),this.insertMergedLines(e,[\"\",\"\"])},this.insert=function(e,t){return this.getLength()<=1&&this.$detectNewLine(t),this.insertMergedLines(e,this.$split(t))},this.insertInLine=function(e,t){var n=this.clippedPos(e.row,e.column),r=this.pos(e.row,e.column+t.length);return this.applyDelta({start:n,end:r,action:\"insert\",lines:[t]},!0),this.clonePos(r)},this.clippedPos=function(e,t){var n=this.getLength();void 0===e?e=n:e<0?e=0:e>=n&&(e=n-1,t=void 0);var r=this.getLine(e);return void 0==t&&(t=r.length),t=Math.min(Math.max(t,0),r.length),{row:e,column:t}},this.clonePos=function(e){return{row:e.row,column:e.column}},this.pos=function(e,t){return{row:e,column:t}},this.$clipPosition=function(e){var t=this.getLength();return e.row>=t?(e.row=Math.max(0,t-1),e.column=this.getLine(t-1).length):(e.row=Math.max(0,e.row),e.column=Math.min(Math.max(e.column,0),this.getLine(e.row).length)),e},this.insertFullLines=function(e,t){e=Math.min(Math.max(e,0),this.getLength());var n=0;e<this.getLength()?(t=t.concat([\"\"]),n=0):(t=[\"\"].concat(t),e--,n=this.$lines[e].length),this.insertMergedLines({row:e,column:n},t)},this.insertMergedLines=function(e,t){var n=this.clippedPos(e.row,e.column),r={row:n.row+t.length-1,column:(1==t.length?n.column:0)+t[t.length-1].length};return this.applyDelta({start:n,end:r,action:\"insert\",lines:t}),this.clonePos(r)},this.remove=function(e){var t=this.clippedPos(e.start.row,e.start.column),n=this.clippedPos(e.end.row,e.end.column);return this.applyDelta({start:t,end:n,action:\"remove\",lines:this.getLinesForRange({start:t,end:n})}),this.clonePos(t)},this.removeInLine=function(e,t,n){var r=this.clippedPos(e,t),i=this.clippedPos(e,n);return this.applyDelta({start:r,end:i,action:\"remove\",lines:this.getLinesForRange({start:r,end:i})},!0),this.clonePos(r)},this.removeFullLines=function(e,t){e=Math.min(Math.max(0,e),this.getLength()-1),t=Math.min(Math.max(0,t),this.getLength()-1);var n=t==this.getLength()-1&&e>0,r=t<this.getLength()-1,i=n?e-1:e,o=n?this.getLine(i).length:0,s=r?t+1:t,l=r?0:this.getLine(s).length,c=new a(i,o,s,l),u=this.$lines.slice(e,t+1);return this.applyDelta({start:c.start,end:c.end,action:\"remove\",lines:this.getLinesForRange(c)}),u},this.removeNewLine=function(e){e<this.getLength()-1&&e>=0&&this.applyDelta({start:this.pos(e,this.getLine(e).length),end:this.pos(e+1,0),action:\"remove\",lines:[\"\",\"\"]})},this.replace=function(e,t){return e instanceof a||(e=a.fromPoints(e.start,e.end)),0===t.length&&e.isEmpty()?e.start:t==this.getTextRange(e)?e.end:(this.remove(e),n=t?this.insert(e.start,t):e.start,n);var n},this.applyDeltas=function(e){for(var t=0;t<e.length;t++)this.applyDelta(e[t])},this.revertDeltas=function(e){for(var t=e.length-1;t>=0;t--)this.revertDelta(e[t])},this.applyDelta=function(e,t){var n=\"insert\"==e.action;(n?e.lines.length<=1&&!e.lines[0]:!a.comparePoints(e.start,e.end))||(n&&e.lines.length>2e4&&this.$splitAndapplyLargeDelta(e,2e4),i(this.$lines,e,t),this._signal(\"change\",e))},this.$splitAndapplyLargeDelta=function(e,t){var n=e.lines,r=n.length,i=e.start.row,o=e.start.column,a=0,s=0;do{a=s,s+=t-1;var l=n.slice(a,s);if(s>r){e.lines=l,e.start.row=i+a,e.start.column=o;break}l.push(\"\"),this.applyDelta({start:this.pos(i+a,o),end:this.pos(i+s,o=0),action:e.action,lines:l},!0)}while(1)},this.revertDelta=function(e){this.applyDelta({start:this.clonePos(e.start),end:this.clonePos(e.end),action:\"insert\"==e.action?\"remove\":\"insert\",lines:e.lines.slice()})},this.indexToPosition=function(e,t){for(var n=this.$lines||this.getAllLines(),r=this.getNewLineCharacter().length,i=t||0,o=n.length;i<o;i++)if(e-=n[i].length+r,e<0)return{row:i,column:e+n[i].length+r};return{row:o-1,column:n[o-1].length}},this.positionToIndex=function(e,t){for(var n=this.$lines||this.getAllLines(),r=this.getNewLineCharacter().length,i=0,o=Math.min(e.row,n.length),a=t||0;a<o;++a)i+=n[a].length+r;return i+e.column}}).call(l.prototype),t.Document=l}),ace.define(\"ace/background_tokenizer\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/lib/event_emitter\"],function(e,t,n){\"use strict\";var r=e(\"./lib/oop\"),i=e(\"./lib/event_emitter\").EventEmitter,o=function(e,t){this.running=!1,this.lines=[],this.states=[],this.currentLine=0,this.tokenizer=e;var n=this;this.$worker=function(){if(n.running){var e=new Date,t=n.currentLine,r=-1,i=n.doc,o=t;while(n.lines[t])t++;var a=i.getLength(),s=0;n.running=!1;while(t<a){n.$tokenizeRow(t),r=t;do{t++}while(n.lines[t]);if(s++,s%5===0&&new Date-e>20){n.running=setTimeout(n.$worker,20);break}}n.currentLine=t,-1==r&&(r=t),o<=r&&n.fireUpdateEvent(o,r)}}};(function(){r.implement(this,i),this.setTokenizer=function(e){this.tokenizer=e,this.lines=[],this.states=[],this.start(0)},this.setDocument=function(e){this.doc=e,this.lines=[],this.states=[],this.stop()},this.fireUpdateEvent=function(e,t){var n={first:e,last:t};this._signal(\"update\",{data:n})},this.start=function(e){this.currentLine=Math.min(e||0,this.currentLine,this.doc.getLength()),this.lines.splice(this.currentLine,this.lines.length),this.states.splice(this.currentLine,this.states.length),this.stop(),this.running=setTimeout(this.$worker,700)},this.scheduleStart=function(){this.running||(this.running=setTimeout(this.$worker,700))},this.$updateOnChange=function(e){var t=e.start.row,n=e.end.row-t;if(0===n)this.lines[t]=null;else if(\"remove\"==e.action)this.lines.splice(t,n+1,null),this.states.splice(t,n+1,null);else{var r=Array(n+1);r.unshift(t,1),this.lines.splice.apply(this.lines,r),this.states.splice.apply(this.states,r)}this.currentLine=Math.min(t,this.currentLine,this.doc.getLength()),this.stop()},this.stop=function(){this.running&&clearTimeout(this.running),this.running=!1},this.getTokens=function(e){return this.lines[e]||this.$tokenizeRow(e)},this.getState=function(e){return this.currentLine==e&&this.$tokenizeRow(e),this.states[e]||\"start\"},this.$tokenizeRow=function(e){var t=this.doc.getLine(e),n=this.states[e-1],r=this.tokenizer.getLineTokens(t,n,e);return this.states[e]+\"\"!==r.state+\"\"?(this.states[e]=r.state,this.lines[e+1]=null,this.currentLine>e+1&&(this.currentLine=e+1)):this.currentLine==e&&(this.currentLine=e+1),this.lines[e]=r.tokens}}).call(o.prototype),t.BackgroundTokenizer=o}),ace.define(\"ace/search_highlight\",[\"require\",\"exports\",\"module\",\"ace/lib/lang\",\"ace/lib/oop\",\"ace/range\"],function(e,t,n){\"use strict\";var r=e(\"./lib/lang\"),i=(e(\"./lib/oop\"),e(\"./range\").Range),o=function(e,t,n){this.setRegexp(e),this.clazz=t,this.type=n||\"text\"};(function(){this.MAX_RANGES=500,this.setRegexp=function(e){this.regExp+\"\"!=e+\"\"&&(this.regExp=e,this.cache=[])},this.update=function(e,t,n,o){if(this.regExp)for(var a=o.firstRow,s=o.lastRow,l=a;l<=s;l++){var c=this.cache[l];null==c&&(c=r.getMatchOffsets(n.getLine(l),this.regExp),c.length>this.MAX_RANGES&&(c=c.slice(0,this.MAX_RANGES)),c=c.map(function(e){return new i(l,e.offset,l,e.offset+e.length)}),this.cache[l]=c.length?c:\"\");for(var u=c.length;u--;)t.drawSingleLineMarker(e,c[u].toScreenRange(n),this.clazz,o)}}}).call(o.prototype),t.SearchHighlight=o}),ace.define(\"ace/edit_session/fold_line\",[\"require\",\"exports\",\"module\",\"ace/range\"],function(e,t,n){\"use strict\";var r=e(\"../range\").Range;function i(e,t){this.foldData=e,Array.isArray(t)?this.folds=t:t=this.folds=[t];var n=t[t.length-1];this.range=new r(t[0].start.row,t[0].start.column,n.end.row,n.end.column),this.start=this.range.start,this.end=this.range.end,this.folds.forEach(function(e){e.setFoldLine(this)},this)}(function(){this.shiftRow=function(e){this.start.row+=e,this.end.row+=e,this.folds.forEach(function(t){t.start.row+=e,t.end.row+=e})},this.addFold=function(e){if(e.sameRow){if(e.start.row<this.startRow||e.endRow>this.endRow)throw new Error(\"Can't add a fold to this FoldLine as it has no connection\");this.folds.push(e),this.folds.sort(function(e,t){return-e.range.compareEnd(t.start.row,t.start.column)}),this.range.compareEnd(e.start.row,e.start.column)>0?(this.end.row=e.end.row,this.end.column=e.end.column):this.range.compareStart(e.end.row,e.end.column)<0&&(this.start.row=e.start.row,this.start.column=e.start.column)}else if(e.start.row==this.end.row)this.folds.push(e),this.end.row=e.end.row,this.end.column=e.end.column;else{if(e.end.row!=this.start.row)throw new Error(\"Trying to add fold to FoldRow that doesn't have a matching row\");this.folds.unshift(e),this.start.row=e.start.row,this.start.column=e.start.column}e.foldLine=this},this.containsRow=function(e){return e>=this.start.row&&e<=this.end.row},this.walk=function(e,t,n){var r,i,o,a=0,s=this.folds,l=!0;null==t&&(t=this.end.row,n=this.end.column);for(var c=0;c<s.length;c++){if(r=s[c],i=r.range.compareStart(t,n),-1==i)return void e(null,t,n,a,l);if(o=e(null,r.start.row,r.start.column,a,l),o=!o&&e(r.placeholder,r.start.row,r.start.column,a),o||0===i)return;l=!r.sameRow,a=r.end.column}e(null,t,n,a,l)},this.getNextFoldTo=function(e,t){for(var n,r,i=0;i<this.folds.length;i++){if(n=this.folds[i],r=n.range.compareEnd(e,t),-1==r)return{fold:n,kind:\"after\"};if(0===r)return{fold:n,kind:\"inside\"}}return null},this.addRemoveChars=function(e,t,n){var r,i,o=this.getNextFoldTo(e,t);if(o)if(r=o.fold,\"inside\"==o.kind&&r.start.column!=t&&r.start.row!=e)window.console&&window.console.log(e,t,r);else if(r.start.row==e){i=this.folds;var a=i.indexOf(r);for(0===a&&(this.start.column+=n),a;a<i.length;a++){if(r=i[a],r.start.column+=n,!r.sameRow)return;r.end.column+=n}this.end.column+=n}},this.split=function(e,t){var n=this.getNextFoldTo(e,t);if(!n||\"inside\"==n.kind)return null;var r=n.fold,o=this.folds,a=this.foldData,s=o.indexOf(r),l=o[s-1];this.end.row=l.end.row,this.end.column=l.end.column,o=o.splice(s,o.length-s);var c=new i(a,o);return a.splice(a.indexOf(this)+1,0,c),c},this.merge=function(e){for(var t=e.folds,n=0;n<t.length;n++)this.addFold(t[n]);var r=this.foldData;r.splice(r.indexOf(e),1)},this.toString=function(){var e=[this.range.toString()+\": [\"];return this.folds.forEach(function(t){e.push(\"  \"+t.toString())}),e.push(\"]\"),e.join(\"\\n\")},this.idxToPosition=function(e){for(var t=0,n=0;n<this.folds.length;n++){var r=this.folds[n];if(e-=r.start.column-t,e<0)return{row:r.start.row,column:r.start.column+e};if(e-=r.placeholder.length,e<0)return r.start;t=r.end.column}return{row:this.end.row,column:this.end.column+e}}}).call(i.prototype),t.FoldLine=i}),ace.define(\"ace/range_list\",[\"require\",\"exports\",\"module\",\"ace/range\"],function(e,t,n){\"use strict\";var r=e(\"./range\").Range,i=r.comparePoints,o=function(){this.ranges=[]};(function(){this.comparePoints=i,this.pointIndex=function(e,t,n){for(var r=this.ranges,o=n||0;o<r.length;o++){var a=r[o],s=i(e,a.end);if(!(s>0)){var l=i(e,a.start);return 0===s?t&&0!==l?-o-2:o:l>0||0===l&&!t?o:-o-1}}return-o-1},this.add=function(e){var t=!e.isEmpty(),n=this.pointIndex(e.start,t);n<0&&(n=-n-1);var r=this.pointIndex(e.end,t,n);return r<0?r=-r-1:r++,this.ranges.splice(n,r-n,e)},this.addList=function(e){for(var t=[],n=e.length;n--;)t.push.apply(t,this.add(e[n]));return t},this.substractPoint=function(e){var t=this.pointIndex(e);if(t>=0)return this.ranges.splice(t,1)},this.merge=function(){var e=[],t=this.ranges;t=t.sort(function(e,t){return i(e.start,t.start)});for(var n,r=t[0],o=1;o<t.length;o++){n=r,r=t[o];var a=i(n.end,r.start);a<0||(0!=a||n.isEmpty()||r.isEmpty())&&(i(n.end,r.end)<0&&(n.end.row=r.end.row,n.end.column=r.end.column),t.splice(o,1),e.push(r),r=n,o--)}return this.ranges=t,e},this.contains=function(e,t){return this.pointIndex({row:e,column:t})>=0},this.containsPoint=function(e){return this.pointIndex(e)>=0},this.rangeAtPoint=function(e){var t=this.pointIndex(e);if(t>=0)return this.ranges[t]},this.clipRows=function(e,t){var n=this.ranges;if(n[0].start.row>t||n[n.length-1].start.row<e)return[];var r=this.pointIndex({row:e,column:0});r<0&&(r=-r-1);var i=this.pointIndex({row:t,column:0},r);i<0&&(i=-i-1);for(var o=[],a=r;a<i;a++)o.push(n[a]);return o},this.removeAll=function(){return this.ranges.splice(0,this.ranges.length)},this.attach=function(e){this.session&&this.detach(),this.session=e,this.onChange=this.$onChange.bind(this),this.session.on(\"change\",this.onChange)},this.detach=function(){this.session&&(this.session.removeListener(\"change\",this.onChange),this.session=null)},this.$onChange=function(e){if(\"insert\"==e.action)var t=e.start,n=e.end;else n=e.start,t=e.end;for(var r=t.row,i=n.row,o=i-r,a=-t.column+n.column,s=this.ranges,l=0,c=s.length;l<c;l++){var u=s[l];if(!(u.end.row<r)){if(u.start.row>r)break;if(u.start.row==r&&u.start.column>=t.column&&(u.start.column==t.column&&this.$insertRight||(u.start.column+=a,u.start.row+=o)),u.end.row==r&&u.end.column>=t.column){if(u.end.column==t.column&&this.$insertRight)continue;u.end.column==t.column&&a>0&&l<c-1&&u.end.column>u.start.column&&u.end.column==s[l+1].start.column&&(u.end.column-=a),u.end.column+=a,u.end.row+=o}}}if(0!=o&&l<c)for(;l<c;l++){u=s[l];u.start.row+=o,u.end.row+=o}}}).call(o.prototype),t.RangeList=o}),ace.define(\"ace/edit_session/fold\",[\"require\",\"exports\",\"module\",\"ace/range\",\"ace/range_list\",\"ace/lib/oop\"],function(e,t,n){\"use strict\";e(\"../range\").Range;var r=e(\"../range_list\").RangeList,i=e(\"../lib/oop\"),o=t.Fold=function(e,t){this.foldLine=null,this.placeholder=t,this.range=e,this.start=e.start,this.end=e.end,this.sameRow=e.start.row==e.end.row,this.subFolds=this.ranges=[]};function a(e,t){e.row-=t.row,0==e.row&&(e.column-=t.column)}function s(e,t){a(e.start,t),a(e.end,t)}function l(e,t){0==e.row&&(e.column+=t.column),e.row+=t.row}function c(e,t){l(e.start,t),l(e.end,t)}i.inherits(o,r),function(){this.toString=function(){return'\"'+this.placeholder+'\" '+this.range.toString()},this.setFoldLine=function(e){this.foldLine=e,this.subFolds.forEach(function(t){t.setFoldLine(e)})},this.clone=function(){var e=this.range.clone(),t=new o(e,this.placeholder);return this.subFolds.forEach(function(e){t.subFolds.push(e.clone())}),t.collapseChildren=this.collapseChildren,t},this.addSubFold=function(e){if(!this.range.isEqual(e)){if(!this.range.containsRange(e))throw new Error(\"A fold can't intersect already existing fold\"+e.range+this.range);s(e,this.start);for(var t=e.start.row,n=e.start.column,r=0,i=-1;r<this.subFolds.length;r++)if(i=this.subFolds[r].range.compare(t,n),1!=i)break;var o=this.subFolds[r];if(0==i)return o.addSubFold(e);t=e.range.end.row,n=e.range.end.column;var a=r;for(i=-1;a<this.subFolds.length;a++)if(i=this.subFolds[a].range.compare(t,n),1!=i)break;this.subFolds[a];if(0==i)throw new Error(\"A fold can't intersect already existing fold\"+e.range+this.range);this.subFolds.splice(r,a-r,e);return e.setFoldLine(this.foldLine),e}},this.restoreRange=function(e){return c(e,this.start)}}.call(o.prototype)}),ace.define(\"ace/edit_session/folding\",[\"require\",\"exports\",\"module\",\"ace/range\",\"ace/edit_session/fold_line\",\"ace/edit_session/fold\",\"ace/token_iterator\"],function(e,t,n){\"use strict\";var r=e(\"../range\").Range,i=e(\"./fold_line\").FoldLine,o=e(\"./fold\").Fold,a=e(\"../token_iterator\").TokenIterator;function s(){this.getFoldAt=function(e,t,n){var r=this.getFoldLine(e);if(!r)return null;for(var i=r.folds,o=0;o<i.length;o++){var a=i[o];if(a.range.contains(e,t)){if(1==n&&a.range.isEnd(e,t))continue;if(-1==n&&a.range.isStart(e,t))continue;return a}}},this.getFoldsInRange=function(e){var t=e.start,n=e.end,r=this.$foldData,i=[];t.column+=1,n.column-=1;for(var o=0;o<r.length;o++){var a=r[o].range.compareRange(e);if(2!=a){if(-2==a)break;for(var s=r[o].folds,l=0;l<s.length;l++){var c=s[l];if(a=c.range.compareRange(e),-2==a)break;if(2!=a){if(42==a)break;i.push(c)}}}}return t.column-=1,n.column+=1,i},this.getFoldsInRangeList=function(e){if(Array.isArray(e)){var t=[];e.forEach(function(e){t=t.concat(this.getFoldsInRange(e))},this)}else t=this.getFoldsInRange(e);return t},this.getAllFolds=function(){for(var e=[],t=this.$foldData,n=0;n<t.length;n++)for(var r=0;r<t[n].folds.length;r++)e.push(t[n].folds[r]);return e},this.getFoldStringAt=function(e,t,n,r){if(r=r||this.getFoldLine(e),!r)return null;for(var i,o,a={end:{column:0}},s=0;s<r.folds.length;s++){o=r.folds[s];var l=o.range.compareEnd(e,t);if(-1==l){i=this.getLine(o.start.row).substring(a.end.column,o.start.column);break}if(0===l)return null;a=o}return i||(i=this.getLine(o.start.row).substring(a.end.column)),-1==n?i.substring(0,t-a.end.column):1==n?i.substring(t-a.end.column):i},this.getFoldLine=function(e,t){var n=this.$foldData,r=0;for(t&&(r=n.indexOf(t)),-1==r&&(r=0),r;r<n.length;r++){var i=n[r];if(i.start.row<=e&&i.end.row>=e)return i;if(i.end.row>e)return null}return null},this.getNextFoldLine=function(e,t){var n=this.$foldData,r=0;for(t&&(r=n.indexOf(t)),-1==r&&(r=0),r;r<n.length;r++){var i=n[r];if(i.end.row>=e)return i}return null},this.getFoldedRowCount=function(e,t){for(var n=this.$foldData,r=t-e+1,i=0;i<n.length;i++){var o=n[i],a=o.end.row,s=o.start.row;if(a>=t){s<t&&(s>=e?r-=t-s:r=0);break}a>=e&&(r-=s>=e?a-s:a-e+1)}return r},this.$addFoldLine=function(e){return this.$foldData.push(e),this.$foldData.sort(function(e,t){return e.start.row-t.start.row}),e},this.addFold=function(e,t){var n,r=this.$foldData,a=!1;e instanceof o?n=e:(n=new o(t,e),n.collapseChildren=t.collapseChildren),this.$clipRangeToDocument(n.range);var s=n.start.row,l=n.start.column,c=n.end.row,u=n.end.column;if(!(s<c||s==c&&l<=u-2))throw new Error(\"The range has to be at least 2 characters width\");var d=this.getFoldAt(s,l,1),h=this.getFoldAt(c,u,-1);if(d&&h==d)return d.addSubFold(n);d&&!d.range.isStart(s,l)&&this.removeFold(d),h&&!h.range.isEnd(c,u)&&this.removeFold(h);var p=this.getFoldsInRange(n.range);p.length>0&&(this.removeFolds(p),p.forEach(function(e){n.addSubFold(e)}));for(var m=0;m<r.length;m++){var f=r[m];if(c==f.start.row){f.addFold(n),a=!0;break}if(s==f.end.row){if(f.addFold(n),a=!0,!n.sameRow){var g=r[m+1];if(g&&g.start.row==c){f.merge(g);break}}break}if(c<=f.start.row)break}return a||(f=this.$addFoldLine(new i(this.$foldData,n))),this.$useWrapMode?this.$updateWrapData(f.start.row,f.start.row):this.$updateRowLengthCache(f.start.row,f.start.row),this.$modified=!0,this._signal(\"changeFold\",{data:n,action:\"add\"}),n},this.addFolds=function(e){e.forEach(function(e){this.addFold(e)},this)},this.removeFold=function(e){var t=e.foldLine,n=t.start.row,r=t.end.row,i=this.$foldData,o=t.folds;if(1==o.length)i.splice(i.indexOf(t),1);else if(t.range.isEnd(e.end.row,e.end.column))o.pop(),t.end.row=o[o.length-1].end.row,t.end.column=o[o.length-1].end.column;else if(t.range.isStart(e.start.row,e.start.column))o.shift(),t.start.row=o[0].start.row,t.start.column=o[0].start.column;else if(e.sameRow)o.splice(o.indexOf(e),1);else{var a=t.split(e.start.row,e.start.column);o=a.folds,o.shift(),a.start.row=o[0].start.row,a.start.column=o[0].start.column}this.$updating||(this.$useWrapMode?this.$updateWrapData(n,r):this.$updateRowLengthCache(n,r)),this.$modified=!0,this._signal(\"changeFold\",{data:e,action:\"remove\"})},this.removeFolds=function(e){for(var t=[],n=0;n<e.length;n++)t.push(e[n]);t.forEach(function(e){this.removeFold(e)},this),this.$modified=!0},this.expandFold=function(e){this.removeFold(e),e.subFolds.forEach(function(t){e.restoreRange(t),this.addFold(t)},this),e.collapseChildren>0&&this.foldAll(e.start.row+1,e.end.row,e.collapseChildren-1),e.subFolds=[]},this.expandFolds=function(e){e.forEach(function(e){this.expandFold(e)},this)},this.unfold=function(e,t){var n,i;if(null==e?(n=new r(0,0,this.getLength(),0),t=!0):n=\"number\"==typeof e?new r(e,0,e,this.getLine(e).length):\"row\"in e?r.fromPoints(e,e):e,i=this.getFoldsInRangeList(n),t)this.removeFolds(i);else{var o=i;while(o.length)this.expandFolds(o),o=this.getFoldsInRangeList(n)}if(i.length)return i},this.isRowFolded=function(e,t){return!!this.getFoldLine(e,t)},this.getRowFoldEnd=function(e,t){var n=this.getFoldLine(e,t);return n?n.end.row:e},this.getRowFoldStart=function(e,t){var n=this.getFoldLine(e,t);return n?n.start.row:e},this.getFoldDisplayLine=function(e,t,n,r,i){null==r&&(r=e.start.row),null==i&&(i=0),null==t&&(t=e.end.row),null==n&&(n=this.getLine(t).length);var o=this.doc,a=\"\";return e.walk(function(e,t,n,s){if(!(t<r)){if(t==r){if(n<i)return;s=Math.max(i,s)}a+=null!=e?e:o.getLine(t).substring(s,n)}},t,n),a},this.getDisplayLine=function(e,t,n,r){var i,o=this.getFoldLine(e);return o?this.getFoldDisplayLine(o,e,t,n,r):(i=this.doc.getLine(e),i.substring(r||0,t||i.length))},this.$cloneFoldData=function(){var e=[];return e=this.$foldData.map(function(t){var n=t.folds.map(function(e){return e.clone()});return new i(e,n)}),e},this.toggleFold=function(e){var t,n,r=this.selection,i=r.getRange();if(i.isEmpty()){var o=i.start;if(t=this.getFoldAt(o.row,o.column),t)return void this.expandFold(t);(n=this.findMatchingBracket(o))?1==i.comparePoint(n)?i.end=n:(i.start=n,i.start.column++,i.end.column--):(n=this.findMatchingBracket({row:o.row,column:o.column+1}))?(1==i.comparePoint(n)?i.end=n:i.start=n,i.start.column++):i=this.getCommentFoldRange(o.row,o.column)||i}else{var a=this.getFoldsInRange(i);if(e&&a.length)return void this.expandFolds(a);1==a.length&&(t=a[0])}if(t||(t=this.getFoldAt(i.start.row,i.start.column)),t&&t.range.toString()==i.toString())this.expandFold(t);else{var s=\"...\";if(!i.isMultiLine()){if(s=this.getTextRange(i),s.length<4)return;s=s.trim().substring(0,2)+\"..\"}this.addFold(s,i)}},this.getCommentFoldRange=function(e,t,n){var i=new a(this,e,t),o=i.getCurrentToken(),s=o.type;if(o&&/^comment|string/.test(s)){s=s.match(/comment|string/)[0],\"comment\"==s&&(s+=\"|doc-start\");var l=new RegExp(s),c=new r;if(1!=n){do{o=i.stepBackward()}while(o&&l.test(o.type));i.stepForward()}if(c.start.row=i.getCurrentTokenRow(),c.start.column=i.getCurrentTokenColumn()+2,i=new a(this,e,t),-1!=n){var u=-1;do{if(o=i.stepForward(),-1==u){var d=this.getState(i.$row);l.test(d)||(u=i.$row)}else if(i.$row>u)break}while(o&&l.test(o.type));o=i.stepBackward()}else o=i.getCurrentToken();return c.end.row=i.getCurrentTokenRow(),c.end.column=i.getCurrentTokenColumn()+o.value.length-2,c}},this.foldAll=function(e,t,n){void 0==n&&(n=1e5);var r=this.foldWidgets;if(r){t=t||this.getLength(),e=e||0;for(var i=e;i<t;i++)if(null==r[i]&&(r[i]=this.getFoldWidget(i)),\"start\"==r[i]){var o=this.getFoldWidgetRange(i);if(o&&o.isMultiLine()&&o.end.row<=t&&o.start.row>=e){i=o.end.row;try{var a=this.addFold(\"...\",o);a&&(a.collapseChildren=n)}catch(s){}}}}},this.$foldStyles={manual:1,markbegin:1,markbeginend:1},this.$foldStyle=\"markbegin\",this.setFoldStyle=function(e){if(!this.$foldStyles[e])throw new Error(\"invalid fold style: \"+e+\"[\"+Object.keys(this.$foldStyles).join(\", \")+\"]\");if(this.$foldStyle!=e){this.$foldStyle=e,\"manual\"==e&&this.unfold();var t=this.$foldMode;this.$setFolding(null),this.$setFolding(t)}},this.$setFolding=function(e){this.$foldMode!=e&&(this.$foldMode=e,this.off(\"change\",this.$updateFoldWidgets),this.off(\"tokenizerUpdate\",this.$tokenizerUpdateFoldWidgets),this._signal(\"changeAnnotation\"),e&&\"manual\"!=this.$foldStyle?(this.foldWidgets=[],this.getFoldWidget=e.getFoldWidget.bind(e,this,this.$foldStyle),this.getFoldWidgetRange=e.getFoldWidgetRange.bind(e,this,this.$foldStyle),this.$updateFoldWidgets=this.updateFoldWidgets.bind(this),this.$tokenizerUpdateFoldWidgets=this.tokenizerUpdateFoldWidgets.bind(this),this.on(\"change\",this.$updateFoldWidgets),this.on(\"tokenizerUpdate\",this.$tokenizerUpdateFoldWidgets)):this.foldWidgets=null)},this.getParentFoldRangeData=function(e,t){var n=this.foldWidgets;if(!n||t&&n[e])return{};var r,i=e-1;while(i>=0){var o=n[i];if(null==o&&(o=n[i]=this.getFoldWidget(i)),\"start\"==o){var a=this.getFoldWidgetRange(i);if(r||(r=a),a&&a.end.row>=e)break}i--}return{range:-1!==i&&a,firstRange:r}},this.onFoldWidgetClick=function(e,t){t=t.domEvent;var n={children:t.shiftKey,all:t.ctrlKey||t.metaKey,siblings:t.altKey},r=this.$toggleFoldWidget(e,n);if(!r){var i=t.target||t.srcElement;i&&/ace_fold-widget/.test(i.className)&&(i.className+=\" ace_invalid\")}},this.$toggleFoldWidget=function(e,t){if(this.getFoldWidget){var n=this.getFoldWidget(e),r=this.getLine(e),i=\"end\"===n?-1:1,o=this.getFoldAt(e,-1===i?0:r.length,i);if(o)return t.children||t.all?this.removeFold(o):this.expandFold(o),o;var a=this.getFoldWidgetRange(e,!0);if(a&&!a.isMultiLine()&&(o=this.getFoldAt(a.start.row,a.start.column,1),o&&a.isEqual(o.range)))return this.removeFold(o),o;if(t.siblings){var s=this.getParentFoldRangeData(e);if(s.range)var l=s.range.start.row+1,c=s.range.end.row;this.foldAll(l,c,t.all?1e4:0)}else t.children?(c=a?a.end.row:this.getLength(),this.foldAll(e+1,c,t.all?1e4:0)):a&&(t.all&&(a.collapseChildren=1e4),this.addFold(\"...\",a));return a}},this.toggleFoldWidget=function(e){var t=this.selection.getCursor().row;t=this.getRowFoldStart(t);var n=this.$toggleFoldWidget(t,{});if(!n){var r=this.getParentFoldRangeData(t,!0);if(n=r.range||r.firstRange,n){t=n.start.row;var i=this.getFoldAt(t,this.getLine(t).length,1);i?this.removeFold(i):this.addFold(\"...\",n)}}},this.updateFoldWidgets=function(e){var t=e.start.row,n=e.end.row-t;if(0===n)this.foldWidgets[t]=null;else if(\"remove\"==e.action)this.foldWidgets.splice(t,n+1,null);else{var r=Array(n+1);r.unshift(t,1),this.foldWidgets.splice.apply(this.foldWidgets,r)}},this.tokenizerUpdateFoldWidgets=function(e){var t=e.data;t.first!=t.last&&this.foldWidgets.length>t.first&&this.foldWidgets.splice(t.first,this.foldWidgets.length)}}t.Folding=s}),ace.define(\"ace/edit_session/bracket_match\",[\"require\",\"exports\",\"module\",\"ace/token_iterator\",\"ace/range\"],function(e,t,n){\"use strict\";var r=e(\"../token_iterator\").TokenIterator,i=e(\"../range\").Range;function o(){this.findMatchingBracket=function(e,t){if(0==e.column)return null;var n=t||this.getLine(e.row).charAt(e.column-1);if(\"\"==n)return null;var r=n.match(/([\\(\\[\\{])|([\\)\\]\\}])/);return r?r[1]?this.$findClosingBracket(r[1],e):this.$findOpeningBracket(r[2],e):null},this.getBracketRange=function(e){var t,n=this.getLine(e.row),r=!0,o=n.charAt(e.column-1),a=o&&o.match(/([\\(\\[\\{])|([\\)\\]\\}])/);if(a||(o=n.charAt(e.column),e={row:e.row,column:e.column+1},a=o&&o.match(/([\\(\\[\\{])|([\\)\\]\\}])/),r=!1),!a)return null;if(a[1]){var s=this.$findClosingBracket(a[1],e);if(!s)return null;t=i.fromPoints(e,s),r||(t.end.column++,t.start.column--),t.cursor=t.end}else{s=this.$findOpeningBracket(a[2],e);if(!s)return null;t=i.fromPoints(s,e),r||(t.start.column++,t.end.column--),t.cursor=t.start}return t},this.$brackets={\")\":\"(\",\"(\":\")\",\"]\":\"[\",\"[\":\"]\",\"{\":\"}\",\"}\":\"{\"},this.$findOpeningBracket=function(e,t,n){var i=this.$brackets[e],o=1,a=new r(this,t.row,t.column),s=a.getCurrentToken();if(s||(s=a.stepForward()),s){n||(n=new RegExp(\"(\\\\.?\"+s.type.replace(\".\",\"\\\\.\").replace(\"rparen\",\".paren\").replace(/\\b(?:end)\\b/,\"(?:start|begin|end)\")+\")+\"));var l=t.column-a.getCurrentTokenColumn()-2,c=s.value;while(1){while(l>=0){var u=c.charAt(l);if(u==i){if(o-=1,0==o)return{row:a.getCurrentTokenRow(),column:l+a.getCurrentTokenColumn()}}else u==e&&(o+=1);l-=1}do{s=a.stepBackward()}while(s&&!n.test(s.type));if(null==s)break;c=s.value,l=c.length-1}return null}},this.$findClosingBracket=function(e,t,n){var i=this.$brackets[e],o=1,a=new r(this,t.row,t.column),s=a.getCurrentToken();if(s||(s=a.stepForward()),s){n||(n=new RegExp(\"(\\\\.?\"+s.type.replace(\".\",\"\\\\.\").replace(\"lparen\",\".paren\").replace(/\\b(?:start|begin)\\b/,\"(?:start|begin|end)\")+\")+\"));var l=t.column-a.getCurrentTokenColumn();while(1){var c=s.value,u=c.length;while(l<u){var d=c.charAt(l);if(d==i){if(o-=1,0==o)return{row:a.getCurrentTokenRow(),column:l+a.getCurrentTokenColumn()}}else d==e&&(o+=1);l+=1}do{s=a.stepForward()}while(s&&!n.test(s.type));if(null==s)break;l=0}return null}}}t.BracketMatch=o}),ace.define(\"ace/edit_session\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/lib/lang\",\"ace/bidihandler\",\"ace/config\",\"ace/lib/event_emitter\",\"ace/selection\",\"ace/mode/text\",\"ace/range\",\"ace/document\",\"ace/background_tokenizer\",\"ace/search_highlight\",\"ace/edit_session/folding\",\"ace/edit_session/bracket_match\"],function(e,t,n){\"use strict\";var r=e(\"./lib/oop\"),i=e(\"./lib/lang\"),o=e(\"./bidihandler\").BidiHandler,a=e(\"./config\"),s=e(\"./lib/event_emitter\").EventEmitter,l=e(\"./selection\").Selection,c=e(\"./mode/text\").Mode,u=e(\"./range\").Range,d=e(\"./document\").Document,h=e(\"./background_tokenizer\").BackgroundTokenizer,p=e(\"./search_highlight\").SearchHighlight,m=function(e,t){this.$breakpoints=[],this.$decorations=[],this.$frontMarkers={},this.$backMarkers={},this.$markerId=1,this.$undoSelect=!0,this.$foldData=[],this.id=\"session\"+ ++m.$uid,this.$foldData.toString=function(){return this.join(\"\\n\")},this.on(\"changeFold\",this.onChangeFold.bind(this)),this.$onChange=this.onChange.bind(this),\"object\"==typeof e&&e.getLine||(e=new d(e)),this.$bidiHandler=new o(this),this.setDocument(e),this.selection=new l(this),a.resetOptions(this),this.setMode(t),a._signal(\"session\",this)};m.$uid=0,function(){r.implement(this,s),this.setDocument=function(e){this.doc&&this.doc.removeListener(\"change\",this.$onChange),this.doc=e,e.on(\"change\",this.$onChange),this.bgTokenizer&&this.bgTokenizer.setDocument(this.getDocument()),this.resetCaches()},this.getDocument=function(){return this.doc},this.$resetRowCache=function(e){if(!e)return this.$docRowCache=[],void(this.$screenRowCache=[]);var t=this.$docRowCache.length,n=this.$getRowCacheIndex(this.$docRowCache,e)+1;t>n&&(this.$docRowCache.splice(n,t),this.$screenRowCache.splice(n,t))},this.$getRowCacheIndex=function(e,t){var n=0,r=e.length-1;while(n<=r){var i=n+r>>1,o=e[i];if(t>o)n=i+1;else{if(!(t<o))return i;r=i-1}}return n-1},this.resetCaches=function(){this.$modified=!0,this.$wrapData=[],this.$rowLengthCache=[],this.$resetRowCache(0),this.bgTokenizer&&this.bgTokenizer.start(0)},this.onChangeFold=function(e){var t=e.data;this.$resetRowCache(t.start.row)},this.onChange=function(e){this.$modified=!0,this.$bidiHandler.onChange(e),this.$resetRowCache(e.start.row);var t=this.$updateInternalDataOnChange(e);this.$fromUndo||!this.$undoManager||e.ignore||(this.$deltasDoc.push(e),t&&0!=t.length&&this.$deltasFold.push({action:\"removeFolds\",folds:t}),this.$informUndoManager.schedule()),this.bgTokenizer&&this.bgTokenizer.$updateOnChange(e),this._signal(\"change\",e)},this.setValue=function(e){this.doc.setValue(e),this.selection.moveTo(0,0),this.$resetRowCache(0),this.$deltas=[],this.$deltasDoc=[],this.$deltasFold=[],this.setUndoManager(this.$undoManager),this.getUndoManager().reset()},this.getValue=this.toString=function(){return this.doc.getValue()},this.getSelection=function(){return this.selection},this.getState=function(e){return this.bgTokenizer.getState(e)},this.getTokens=function(e){return this.bgTokenizer.getTokens(e)},this.getTokenAt=function(e,t){var n,r=this.bgTokenizer.getTokens(e),i=0;if(null==t){var o=r.length-1;i=this.getLine(e).length}else for(o=0;o<r.length;o++)if(i+=r[o].value.length,i>=t)break;return n=r[o],n?(n.index=o,n.start=i-n.value.length,n):null},this.setUndoManager=function(e){if(this.$undoManager=e,this.$deltas=[],this.$deltasDoc=[],this.$deltasFold=[],this.$informUndoManager&&this.$informUndoManager.cancel(),e){var t=this;this.$syncInformUndoManager=function(){t.$informUndoManager.cancel(),t.$deltasFold.length&&(t.$deltas.push({group:\"fold\",deltas:t.$deltasFold}),t.$deltasFold=[]),t.$deltasDoc.length&&(t.$deltas.push({group:\"doc\",deltas:t.$deltasDoc}),t.$deltasDoc=[]),t.$deltas.length>0&&e.execute({action:\"aceupdate\",args:[t.$deltas,t],merge:t.mergeUndoDeltas}),t.mergeUndoDeltas=!1,t.$deltas=[]},this.$informUndoManager=i.delayedCall(this.$syncInformUndoManager)}},this.markUndoGroup=function(){this.$syncInformUndoManager&&this.$syncInformUndoManager()},this.$defaultUndoManager={undo:function(){},redo:function(){},reset:function(){}},this.getUndoManager=function(){return this.$undoManager||this.$defaultUndoManager},this.getTabString=function(){return this.getUseSoftTabs()?i.stringRepeat(\" \",this.getTabSize()):\"\\t\"},this.setUseSoftTabs=function(e){this.setOption(\"useSoftTabs\",e)},this.getUseSoftTabs=function(){return this.$useSoftTabs&&!this.$mode.$indentWithTabs},this.setTabSize=function(e){this.setOption(\"tabSize\",e)},this.getTabSize=function(){return this.$tabSize},this.isTabStop=function(e){return this.$useSoftTabs&&e.column%this.$tabSize===0},this.setNavigateWithinSoftTabs=function(e){this.setOption(\"navigateWithinSoftTabs\",e)},this.getNavigateWithinSoftTabs=function(){return this.$navigateWithinSoftTabs},this.$overwrite=!1,this.setOverwrite=function(e){this.setOption(\"overwrite\",e)},this.getOverwrite=function(){return this.$overwrite},this.toggleOverwrite=function(){this.setOverwrite(!this.$overwrite)},this.addGutterDecoration=function(e,t){this.$decorations[e]||(this.$decorations[e]=\"\"),this.$decorations[e]+=\" \"+t,this._signal(\"changeBreakpoint\",{})},this.removeGutterDecoration=function(e,t){this.$decorations[e]=(this.$decorations[e]||\"\").replace(\" \"+t,\"\"),this._signal(\"changeBreakpoint\",{})},this.getBreakpoints=function(){return this.$breakpoints},this.setBreakpoints=function(e){this.$breakpoints=[];for(var t=0;t<e.length;t++)this.$breakpoints[e[t]]=\"ace_breakpoint\";this._signal(\"changeBreakpoint\",{})},this.clearBreakpoints=function(){this.$breakpoints=[],this._signal(\"changeBreakpoint\",{})},this.setBreakpoint=function(e,t){void 0===t&&(t=\"ace_breakpoint\"),t?this.$breakpoints[e]=t:delete this.$breakpoints[e],this._signal(\"changeBreakpoint\",{})},this.clearBreakpoint=function(e){delete this.$breakpoints[e],this._signal(\"changeBreakpoint\",{})},this.addMarker=function(e,t,n,r){var i=this.$markerId++,o={range:e,type:n||\"line\",renderer:\"function\"==typeof n?n:null,clazz:t,inFront:!!r,id:i};return r?(this.$frontMarkers[i]=o,this._signal(\"changeFrontMarker\")):(this.$backMarkers[i]=o,this._signal(\"changeBackMarker\")),i},this.addDynamicMarker=function(e,t){if(e.update){var n=this.$markerId++;return e.id=n,e.inFront=!!t,t?(this.$frontMarkers[n]=e,this._signal(\"changeFrontMarker\")):(this.$backMarkers[n]=e,this._signal(\"changeBackMarker\")),e}},this.removeMarker=function(e){var t=this.$frontMarkers[e]||this.$backMarkers[e];if(t){var n=t.inFront?this.$frontMarkers:this.$backMarkers;t&&(delete n[e],this._signal(t.inFront?\"changeFrontMarker\":\"changeBackMarker\"))}},this.getMarkers=function(e){return e?this.$frontMarkers:this.$backMarkers},this.highlight=function(e){if(!this.$searchHighlight){var t=new p(null,\"ace_selected-word\",\"text\");this.$searchHighlight=this.addDynamicMarker(t)}this.$searchHighlight.setRegexp(e)},this.highlightLines=function(e,t,n,r){\"number\"!=typeof t&&(n=t,t=e),n||(n=\"ace_step\");var i=new u(e,0,t,1/0);return i.id=this.addMarker(i,n,\"fullLine\",r),i},this.setAnnotations=function(e){this.$annotations=e,this._signal(\"changeAnnotation\",{})},this.getAnnotations=function(){return this.$annotations||[]},this.clearAnnotations=function(){this.setAnnotations([])},this.$detectNewLine=function(e){var t=e.match(/^.*?(\\r?\\n)/m);this.$autoNewLine=t?t[1]:\"\\n\"},this.getWordRange=function(e,t){var n=this.getLine(e),r=!1;if(t>0&&(r=!!n.charAt(t-1).match(this.tokenRe)),r||(r=!!n.charAt(t).match(this.tokenRe)),r)var i=this.tokenRe;else if(/^\\s+$/.test(n.slice(t-1,t+1)))i=/\\s/;else i=this.nonTokenRe;var o=t;if(o>0){do{o--}while(o>=0&&n.charAt(o).match(i));o++}var a=t;while(a<n.length&&n.charAt(a).match(i))a++;return new u(e,o,e,a)},this.getAWordRange=function(e,t){var n=this.getWordRange(e,t),r=this.getLine(n.end.row);while(r.charAt(n.end.column).match(/[ \\t]/))n.end.column+=1;return n},this.setNewLineMode=function(e){this.doc.setNewLineMode(e)},this.getNewLineMode=function(){return this.doc.getNewLineMode()},this.setUseWorker=function(e){this.setOption(\"useWorker\",e)},this.getUseWorker=function(){return this.$useWorker},this.onReloadTokenizer=function(e){var t=e.data;this.bgTokenizer.start(t.first),this._signal(\"tokenizerUpdate\",e)},this.$modes={},this.$mode=null,this.$modeId=null,this.setMode=function(e,t){if(e&&\"object\"===typeof e){if(e.getTokenizer)return this.$onChangeMode(e);var n=e,r=n.path}else r=e||\"ace/mode/text\";if(this.$modes[\"ace/mode/text\"]||(this.$modes[\"ace/mode/text\"]=new c),this.$modes[r]&&!n)return this.$onChangeMode(this.$modes[r]),void(t&&t());this.$modeId=r,a.loadModule([\"mode\",r],function(e){if(this.$modeId!==r)return t&&t();this.$modes[r]&&!n?this.$onChangeMode(this.$modes[r]):e&&e.Mode&&(e=new e.Mode(n),n||(this.$modes[r]=e,e.$id=r),this.$onChangeMode(e)),t&&t()}.bind(this)),this.$mode||this.$onChangeMode(this.$modes[\"ace/mode/text\"],!0)},this.$onChangeMode=function(e,t){if(t||(this.$modeId=e.$id),this.$mode!==e){this.$mode=e,this.$stopWorker(),this.$useWorker&&this.$startWorker();var n=e.getTokenizer();if(void 0!==n.addEventListener){var r=this.onReloadTokenizer.bind(this);n.addEventListener(\"update\",r)}if(this.bgTokenizer)this.bgTokenizer.setTokenizer(n);else{this.bgTokenizer=new h(n);var i=this;this.bgTokenizer.addEventListener(\"update\",function(e){i._signal(\"tokenizerUpdate\",e)})}this.bgTokenizer.setDocument(this.getDocument()),this.tokenRe=e.tokenRe,this.nonTokenRe=e.nonTokenRe,t||(e.attachToSession&&e.attachToSession(this),this.$options.wrapMethod.set.call(this,this.$wrapMethod),this.$setFolding(e.foldingRules),this.bgTokenizer.start(0),this._emit(\"changeMode\"))}},this.$stopWorker=function(){this.$worker&&(this.$worker.terminate(),this.$worker=null)},this.$startWorker=function(){try{this.$worker=this.$mode.createWorker(this)}catch(e){a.warn(\"Could not load worker\",e),this.$worker=null}},this.getMode=function(){return this.$mode},this.$scrollTop=0,this.setScrollTop=function(e){this.$scrollTop===e||isNaN(e)||(this.$scrollTop=e,this._signal(\"changeScrollTop\",e))},this.getScrollTop=function(){return this.$scrollTop},this.$scrollLeft=0,this.setScrollLeft=function(e){this.$scrollLeft===e||isNaN(e)||(this.$scrollLeft=e,this._signal(\"changeScrollLeft\",e))},this.getScrollLeft=function(){return this.$scrollLeft},this.getScreenWidth=function(){return this.$computeWidth(),this.lineWidgets?Math.max(this.getLineWidgetMaxWidth(),this.screenWidth):this.screenWidth},this.getLineWidgetMaxWidth=function(){if(null!=this.lineWidgetsWidth)return this.lineWidgetsWidth;var e=0;return this.lineWidgets.forEach(function(t){t&&t.screenWidth>e&&(e=t.screenWidth)}),this.lineWidgetWidth=e},this.$computeWidth=function(e){if(this.$modified||e){if(this.$modified=!1,this.$useWrapMode)return this.screenWidth=this.$wrapLimit;for(var t=this.doc.getAllLines(),n=this.$rowLengthCache,r=0,i=0,o=this.$foldData[i],a=o?o.start.row:1/0,s=t.length,l=0;l<s;l++){if(l>a){if(l=o.end.row+1,l>=s)break;o=this.$foldData[i++],a=o?o.start.row:1/0}null==n[l]&&(n[l]=this.$getStringScreenWidth(t[l])[0]),n[l]>r&&(r=n[l])}this.screenWidth=r}},this.getLine=function(e){return this.doc.getLine(e)},this.getLines=function(e,t){return this.doc.getLines(e,t)},this.getLength=function(){return this.doc.getLength()},this.getTextRange=function(e){return this.doc.getTextRange(e||this.selection.getRange())},this.insert=function(e,t){return this.doc.insert(e,t)},this.remove=function(e){return this.doc.remove(e)},this.removeFullLines=function(e,t){return this.doc.removeFullLines(e,t)},this.undoChanges=function(e,t){if(e.length){this.$fromUndo=!0;for(var n=null,r=e.length-1;-1!=r;r--){var i=e[r];\"doc\"==i.group?(this.doc.revertDeltas(i.deltas),n=this.$getUndoSelection(i.deltas,!0,n)):i.deltas.forEach(function(e){this.addFolds(e.folds)},this)}return this.$fromUndo=!1,n&&this.$undoSelect&&!t&&this.selection.setSelectionRange(n),n}},this.redoChanges=function(e,t){if(e.length){this.$fromUndo=!0;for(var n=null,r=0;r<e.length;r++){var i=e[r];\"doc\"==i.group&&(this.doc.applyDeltas(i.deltas),n=this.$getUndoSelection(i.deltas,!1,n))}return this.$fromUndo=!1,n&&this.$undoSelect&&!t&&this.selection.setSelectionRange(n),n}},this.setUndoSelect=function(e){this.$undoSelect=e},this.$getUndoSelection=function(e,t,n){function r(e){return t?\"insert\"!==e.action:\"insert\"===e.action}var i,o,a=e[0];r(a)?i=u.fromPoints(a.start,a.end):i=u.fromPoints(a.start,a.start);for(var s=1;s<e.length;s++)a=e[s],r(a)?(o=a.start,-1==i.compare(o.row,o.column)&&i.setStart(o),o=a.end,1==i.compare(o.row,o.column)&&i.setEnd(o),!0):(o=a.start,-1==i.compare(o.row,o.column)&&(i=u.fromPoints(a.start,a.start)),!1);if(null!=n){0===u.comparePoints(n.start,i.start)&&(n.start.column+=i.end.column-i.start.column,n.end.column+=i.end.column-i.start.column);var l=n.compareRange(i);1==l?i.setStart(n.start):-1==l&&i.setEnd(n.end)}return i},this.replace=function(e,t){return this.doc.replace(e,t)},this.moveText=function(e,t,n){var r=this.getTextRange(e),i=this.getFoldsInRange(e),o=u.fromPoints(t,t);if(!n){this.remove(e);var a=e.start.row-e.end.row,s=a?-e.end.column:e.start.column-e.end.column;s&&(o.start.row==e.end.row&&o.start.column>e.end.column&&(o.start.column+=s),o.end.row==e.end.row&&o.end.column>e.end.column&&(o.end.column+=s)),a&&o.start.row>=e.end.row&&(o.start.row+=a,o.end.row+=a)}if(o.end=this.insert(o.start,r),i.length){var l=e.start,c=o.start;a=c.row-l.row,s=c.column-l.column;this.addFolds(i.map(function(e){return e=e.clone(),e.start.row==l.row&&(e.start.column+=s),e.end.row==l.row&&(e.end.column+=s),e.start.row+=a,e.end.row+=a,e}))}return o},this.indentRows=function(e,t,n){n=n.replace(/\\t/g,this.getTabString());for(var r=e;r<=t;r++)this.doc.insertInLine({row:r,column:0},n)},this.outdentRows=function(e){for(var t=e.collapseRows(),n=new u(0,0,0,0),r=this.getTabSize(),i=t.start.row;i<=t.end.row;++i){var o=this.getLine(i);n.start.row=i,n.end.row=i;for(var a=0;a<r;++a)if(\" \"!=o.charAt(a))break;a<r&&\"\\t\"==o.charAt(a)?(n.start.column=a,n.end.column=a+1):(n.start.column=0,n.end.column=a),this.remove(n)}},this.$moveLines=function(e,t,n){if(e=this.getRowFoldStart(e),t=this.getRowFoldEnd(t),n<0){var r=this.getRowFoldStart(e+n);if(r<0)return 0;var i=r-e}else if(n>0){r=this.getRowFoldEnd(t+n);if(r>this.doc.getLength()-1)return 0;i=r-t}else{e=this.$clipRowToDocument(e),t=this.$clipRowToDocument(t);i=t-e+1}var o=new u(e,0,t,Number.MAX_VALUE),a=this.getFoldsInRange(o).map(function(e){return e=e.clone(),e.start.row+=i,e.end.row+=i,e}),s=0==n?this.doc.getLines(e,t):this.doc.removeFullLines(e,t);return this.doc.insertFullLines(e+i,s),a.length&&this.addFolds(a),i},this.moveLinesUp=function(e,t){return this.$moveLines(e,t,-1)},this.moveLinesDown=function(e,t){return this.$moveLines(e,t,1)},this.duplicateLines=function(e,t){return this.$moveLines(e,t,0)},this.$clipRowToDocument=function(e){return Math.max(0,Math.min(e,this.doc.getLength()-1))},this.$clipColumnToRow=function(e,t){return t<0?0:Math.min(this.doc.getLine(e).length,t)},this.$clipPositionToDocument=function(e,t){if(t=Math.max(0,t),e<0)e=0,t=0;else{var n=this.doc.getLength();e>=n?(e=n-1,t=this.doc.getLine(n-1).length):t=Math.min(this.doc.getLine(e).length,t)}return{row:e,column:t}},this.$clipRangeToDocument=function(e){e.start.row<0?(e.start.row=0,e.start.column=0):e.start.column=this.$clipColumnToRow(e.start.row,e.start.column);var t=this.doc.getLength()-1;return e.end.row>t?(e.end.row=t,e.end.column=this.doc.getLine(t).length):e.end.column=this.$clipColumnToRow(e.end.row,e.end.column),e},this.$wrapLimit=80,this.$useWrapMode=!1,this.$wrapLimitRange={min:null,max:null},this.setUseWrapMode=function(e){if(e!=this.$useWrapMode){if(this.$useWrapMode=e,this.$modified=!0,this.$resetRowCache(0),e){var t=this.getLength();this.$wrapData=Array(t),this.$updateWrapData(0,t-1)}this._signal(\"changeWrapMode\")}},this.getUseWrapMode=function(){return this.$useWrapMode},this.setWrapLimitRange=function(e,t){this.$wrapLimitRange.min===e&&this.$wrapLimitRange.max===t||(this.$wrapLimitRange={min:e,max:t},this.$modified=!0,this.$bidiHandler.markAsDirty(),this.$useWrapMode&&this._signal(\"changeWrapMode\"))},this.adjustWrapLimit=function(e,t){var n=this.$wrapLimitRange;n.max<0&&(n={min:t,max:t});var r=this.$constrainWrapLimit(e,n.min,n.max);return r!=this.$wrapLimit&&r>1&&(this.$wrapLimit=r,this.$modified=!0,this.$useWrapMode&&(this.$updateWrapData(0,this.getLength()-1),this.$resetRowCache(0),this._signal(\"changeWrapLimit\")),!0)},this.$constrainWrapLimit=function(e,t,n){return t&&(e=Math.max(t,e)),n&&(e=Math.min(n,e)),e},this.getWrapLimit=function(){return this.$wrapLimit},this.setWrapLimit=function(e){this.setWrapLimitRange(e,e)},this.getWrapLimitRange=function(){return{min:this.$wrapLimitRange.min,max:this.$wrapLimitRange.max}},this.$updateInternalDataOnChange=function(e){var t=this.$useWrapMode,n=e.action,r=e.start,i=e.end,o=r.row,a=i.row,s=a-o,l=null;if(this.$updating=!0,0!=s)if(\"remove\"===n){this[t?\"$wrapData\":\"$rowLengthCache\"].splice(o,s);var c=this.$foldData;l=this.getFoldsInRange(e),this.removeFolds(l);var u=this.getFoldLine(i.row),d=0;if(u){u.addRemoveChars(i.row,i.column,r.column-i.column),u.shiftRow(-s);var h=this.getFoldLine(o);h&&h!==u&&(h.merge(u),u=h),d=c.indexOf(u)+1}for(d;d<c.length;d++){u=c[d];u.start.row>=i.row&&u.shiftRow(-s)}a=o}else{var p=Array(s);p.unshift(o,0);var m=t?this.$wrapData:this.$rowLengthCache;m.splice.apply(m,p);c=this.$foldData,u=this.getFoldLine(o),d=0;if(u){var f=u.range.compareInside(r.row,r.column);0==f?(u=u.split(r.row,r.column),u&&(u.shiftRow(s),u.addRemoveChars(a,0,i.column-r.column))):-1==f&&(u.addRemoveChars(o,0,i.column-r.column),u.shiftRow(s)),d=c.indexOf(u)+1}for(d;d<c.length;d++){u=c[d];u.start.row>=o&&u.shiftRow(s)}}else{s=Math.abs(e.start.column-e.end.column),\"remove\"===n&&(l=this.getFoldsInRange(e),this.removeFolds(l),s=-s);u=this.getFoldLine(o);u&&u.addRemoveChars(o,r.column,s)}return t&&this.$wrapData.length!=this.doc.getLength()&&console.error(\"doc.getLength() and $wrapData.length have to be the same!\"),this.$updating=!1,t?this.$updateWrapData(o,a):this.$updateRowLengthCache(o,a),l},this.$updateRowLengthCache=function(e,t,n){this.$rowLengthCache[e]=null,this.$rowLengthCache[t]=null},this.$updateWrapData=function(e,t){var r,i,a=this.doc.getAllLines(),s=this.getTabSize(),l=this.$wrapData,c=this.$wrapLimit,u=e;t=Math.min(t,a.length-1);while(u<=t)i=this.getFoldLine(u,i),i?(r=[],i.walk(function(e,t,i,s){var l;if(null!=e){l=this.$getDisplayTokens(e,r.length),l[0]=n;for(var c=1;c<l.length;c++)l[c]=o}else l=this.$getDisplayTokens(a[t].substring(s,i),r.length);r=r.concat(l)}.bind(this),i.end.row,a[i.end.row].length+1),l[i.start.row]=this.$computeWrapSplits(r,c,s),u=i.end.row+1):(r=this.$getDisplayTokens(a[u]),l[u]=this.$computeWrapSplits(r,c,s),u++)};var e=1,t=2,n=3,o=4,l=9,d=10,m=11,f=12;function g(e){return!(e<4352)&&(e>=4352&&e<=4447||e>=4515&&e<=4519||e>=4602&&e<=4607||e>=9001&&e<=9002||e>=11904&&e<=11929||e>=11931&&e<=12019||e>=12032&&e<=12245||e>=12272&&e<=12283||e>=12288&&e<=12350||e>=12353&&e<=12438||e>=12441&&e<=12543||e>=12549&&e<=12589||e>=12593&&e<=12686||e>=12688&&e<=12730||e>=12736&&e<=12771||e>=12784&&e<=12830||e>=12832&&e<=12871||e>=12880&&e<=13054||e>=13056&&e<=19903||e>=19968&&e<=42124||e>=42128&&e<=42182||e>=43360&&e<=43388||e>=44032&&e<=55203||e>=55216&&e<=55238||e>=55243&&e<=55291||e>=63744&&e<=64255||e>=65040&&e<=65049||e>=65072&&e<=65106||e>=65108&&e<=65126||e>=65128&&e<=65131||e>=65281&&e<=65376||e>=65504&&e<=65510)}this.$computeWrapSplits=function(e,r,i){if(0==e.length)return[];var a=[],s=e.length,c=0,u=0,h=this.$wrapAsCode,p=this.$indentedSoftWrap,g=r<=Math.max(2*i,8)||!1===p?0:Math.floor(r/2);function b(){var t=0;if(0===g)return t;if(p)for(var n=0;n<e.length;n++){var r=e[n];if(r==d)t+=1;else{if(r!=m){if(r==f)continue;break}t+=i}}return h&&!1!==p&&(t+=i),Math.min(t,g)}function v(t){var n=e.slice(c,t),r=n.length;n.join(\"\").replace(/12/g,function(){r-=1}).replace(/2/g,function(){r-=1}),a.length||(k=b(),a.indent=k),u+=r,a.push(u),c=t}var k=0;while(s-c>r-k){var y=c+r-k;if(e[y-1]>=d&&e[y]>=d)v(y);else if(e[y]!=n&&e[y]!=o){var w=Math.max(y-(r-(r>>2)),c-1);while(y>w&&e[y]<n)y--;if(h){while(y>w&&e[y]<n)y--;while(y>w&&e[y]==l)y--}else while(y>w&&e[y]<d)y--;y>w?v(++y):(y=c+r,e[y]==t&&y--,v(y-k))}else{for(y;y!=c-1;y--)if(e[y]==n)break;if(y>c){v(y);continue}for(y=c+r,y;y<e.length;y++)if(e[y]!=o)break;if(y==e.length)break;v(y)}}return a},this.$getDisplayTokens=function(n,r){var i,o=[];r=r||0;for(var a=0;a<n.length;a++){var s=n.charCodeAt(a);if(9==s){i=this.getScreenTabSize(o.length+r),o.push(m);for(var c=1;c<i;c++)o.push(f)}else 32==s?o.push(d):s>39&&s<48||s>57&&s<64?o.push(l):s>=4352&&g(s)?o.push(e,t):o.push(e)}return o},this.$getStringScreenWidth=function(e,t,n){if(0==t)return[0,0];var r,i;for(null==t&&(t=1/0),n=n||0,i=0;i<e.length;i++)if(r=e.charCodeAt(i),9==r?n+=this.getScreenTabSize(n):r>=4352&&g(r)?n+=2:n+=1,n>t)break;return[n,i]},this.lineWidgets=null,this.getRowLength=function(e){if(this.lineWidgets)var t=this.lineWidgets[e]&&this.lineWidgets[e].rowCount||0;else t=0;return this.$useWrapMode&&this.$wrapData[e]?this.$wrapData[e].length+1+t:1+t},this.getRowLineCount=function(e){return this.$useWrapMode&&this.$wrapData[e]?this.$wrapData[e].length+1:1},this.getRowWrapIndent=function(e){if(this.$useWrapMode){var t=this.screenToDocumentPosition(e,Number.MAX_VALUE),n=this.$wrapData[t.row];return n.length&&n[0]<t.column?n.indent:0}return 0},this.getScreenLastRowColumn=function(e){var t=this.screenToDocumentPosition(e,Number.MAX_VALUE);return this.documentToScreenColumn(t.row,t.column)},this.getDocumentLastRowColumn=function(e,t){var n=this.documentToScreenRow(e,t);return this.getScreenLastRowColumn(n)},this.getDocumentLastRowColumnPosition=function(e,t){var n=this.documentToScreenRow(e,t);return this.screenToDocumentPosition(n,Number.MAX_VALUE/10)},this.getRowSplitData=function(e){return this.$useWrapMode?this.$wrapData[e]:void 0},this.getScreenTabSize=function(e){return this.$tabSize-e%this.$tabSize},this.screenToDocumentRow=function(e,t){return this.screenToDocumentPosition(e,t).row},this.screenToDocumentColumn=function(e,t){return this.screenToDocumentPosition(e,t).column},this.screenToDocumentPosition=function(e,t,n){if(e<0)return{row:0,column:0};var r,i,o=0,a=0,s=0,l=0,c=this.$screenRowCache,u=this.$getRowCacheIndex(c,e),d=c.length;if(d&&u>=0){s=c[u],o=this.$docRowCache[u];var h=e>c[d-1]}else h=!d;var p=this.getLength()-1,m=this.getNextFoldLine(o),f=m?m.start.row:1/0;while(s<=e){if(l=this.getRowLength(o),s+l>e||o>=p)break;s+=l,o++,o>f&&(o=m.end.row+1,m=this.getNextFoldLine(o,m),f=m?m.start.row:1/0),h&&(this.$docRowCache.push(o),this.$screenRowCache.push(s))}if(m&&m.start.row<=o)r=this.getFoldDisplayLine(m),o=m.start.row;else{if(s+l<=e||o>p)return{row:p,column:this.getLine(p).length};r=this.getLine(o),m=null}var g=0,b=Math.floor(e-s);if(this.$useWrapMode){var v=this.$wrapData[o];v&&(i=v[b],b>0&&v.length&&(g=v.indent,a=v[b-1]||v[v.length-1],r=r.substring(a)))}return void 0!==n&&this.$bidiHandler.isBidiRow(s+b,o,b)&&(t=this.$bidiHandler.offsetToCol(n)),a+=this.$getStringScreenWidth(r,t-g)[1],this.$useWrapMode&&a>=i&&(a=i-1),m?m.idxToPosition(a):{row:o,column:a}},this.documentToScreenPosition=function(e,t){if(\"undefined\"===typeof t)var n=this.$clipPositionToDocument(e.row,e.column);else n=this.$clipPositionToDocument(e,t);e=n.row,t=n.column;var r=0,i=null,o=null;o=this.getFoldAt(e,t,1),o&&(e=o.start.row,t=o.start.column);var a,s=0,l=this.$docRowCache,c=this.$getRowCacheIndex(l,e),u=l.length;if(u&&c>=0){s=l[c],r=this.$screenRowCache[c];var d=e>l[u-1]}else d=!u;var h=this.getNextFoldLine(s),p=h?h.start.row:1/0;while(s<e){if(s>=p){if(a=h.end.row+1,a>e)break;h=this.getNextFoldLine(a,h),p=h?h.start.row:1/0}else a=s+1;r+=this.getRowLength(s),s=a,d&&(this.$docRowCache.push(s),this.$screenRowCache.push(r))}var m=\"\";h&&s>=p?(m=this.getFoldDisplayLine(h,e,t),i=h.start.row):(m=this.getLine(e).substring(0,t),i=e);var f=0;if(this.$useWrapMode){var g=this.$wrapData[i];if(g){var b=0;while(m.length>=g[b])r++,b++;m=m.substring(g[b-1]||0,m.length),f=b>0?g.indent:0}}return{row:r,column:f+this.$getStringScreenWidth(m)[0]}},this.documentToScreenColumn=function(e,t){return this.documentToScreenPosition(e,t).column},this.documentToScreenRow=function(e,t){return this.documentToScreenPosition(e,t).row},this.getScreenLength=function(){var e=0,t=null;if(this.$useWrapMode){var n=this.$wrapData.length,r=0,i=(s=0,t=this.$foldData[s++],t?t.start.row:1/0);while(r<n){var o=this.$wrapData[r];e+=o?o.length+1:1,r++,r>i&&(r=t.end.row+1,t=this.$foldData[s++],i=t?t.start.row:1/0)}}else{e=this.getLength();for(var a=this.$foldData,s=0;s<a.length;s++)t=a[s],e-=t.end.row-t.start.row}return this.lineWidgets&&(e+=this.$getWidgetScreenLength()),e},this.$setFontMetrics=function(e){this.$enableVarChar&&(this.$getStringScreenWidth=function(t,n,r){if(0===n)return[0,0];var i,o;for(n||(n=1/0),r=r||0,o=0;o<t.length;o++)if(i=t.charAt(o),r+=\"\\t\"===i?this.getScreenTabSize(r):e.getCharacterWidth(i),r>n)break;return[r,o]})},this.destroy=function(){this.bgTokenizer&&(this.bgTokenizer.setDocument(null),this.bgTokenizer=null),this.$stopWorker()},this.isFullWidth=g}.call(m.prototype),e(\"./edit_session/folding\").Folding.call(m.prototype),e(\"./edit_session/bracket_match\").BracketMatch.call(m.prototype),a.defineOptions(m.prototype,\"session\",{wrap:{set:function(e){if(e&&\"off\"!=e?\"free\"==e?e=!0:\"printMargin\"==e?e=-1:\"string\"==typeof e&&(e=parseInt(e,10)||!1):e=!1,this.$wrap!=e)if(this.$wrap=e,e){var t=\"number\"==typeof e?e:null;this.setWrapLimitRange(t,t),this.setUseWrapMode(!0)}else this.setUseWrapMode(!1)},get:function(){return this.getUseWrapMode()?-1==this.$wrap?\"printMargin\":this.getWrapLimitRange().min?this.$wrap:\"free\":\"off\"},handlesSet:!0},wrapMethod:{set:function(e){e=\"auto\"==e?\"text\"!=this.$mode.type:\"text\"!=e,e!=this.$wrapAsCode&&(this.$wrapAsCode=e,this.$useWrapMode&&(this.$modified=!0,this.$resetRowCache(0),this.$updateWrapData(0,this.getLength()-1)))},initialValue:\"auto\"},indentedSoftWrap:{initialValue:!0},firstLineNumber:{set:function(){this._signal(\"changeBreakpoint\")},initialValue:1},useWorker:{set:function(e){this.$useWorker=e,this.$stopWorker(),e&&this.$startWorker()},initialValue:!0},useSoftTabs:{initialValue:!0},tabSize:{set:function(e){isNaN(e)||this.$tabSize===e||(this.$modified=!0,this.$rowLengthCache=[],this.$tabSize=e,this._signal(\"changeTabSize\"))},initialValue:4,handlesSet:!0},navigateWithinSoftTabs:{initialValue:!1},overwrite:{set:function(e){this._signal(\"changeOverwrite\")},initialValue:!1},newLineMode:{set:function(e){this.doc.setNewLineMode(e)},get:function(){return this.doc.getNewLineMode()},handlesSet:!0},mode:{set:function(e){this.setMode(e)},get:function(){return this.$modeId}}}),t.EditSession=m}),ace.define(\"ace/search\",[\"require\",\"exports\",\"module\",\"ace/lib/lang\",\"ace/lib/oop\",\"ace/range\"],function(e,t,n){\"use strict\";var r=e(\"./lib/lang\"),i=e(\"./lib/oop\"),o=e(\"./range\").Range,a=function(){this.$options={}};function s(e,t){function n(e){return/\\w/.test(e)||t.regExp?\"\\\\b\":\"\"}return n(e[0])+e+n(e[e.length-1])}(function(){this.set=function(e){return i.mixin(this.$options,e),this},this.getOptions=function(){return r.copyObject(this.$options)},this.setOptions=function(e){this.$options=e},this.find=function(e){var t=this.$options,n=this.$matchIterator(e,t);if(!n)return!1;var r=null;return n.forEach(function(e,n,i,a){return r=new o(e,n,i,a),!(n==a&&t.start&&t.start.start&&0!=t.skipCurrent&&r.isEqual(t.start))||(r=null,!1)}),r},this.findAll=function(e){var t=this.$options;if(!t.needle)return[];this.$assembleRegExp(t);var n=t.range,i=n?e.getLines(n.start.row,n.end.row):e.doc.getAllLines(),a=[],s=t.re;if(t.$isMultiLine){var l,c=s.length,u=i.length-c;e:for(var d=s.offset||0;d<=u;d++){for(var h=0;h<c;h++)if(-1==i[d+h].search(s[h]))continue e;var p=i[d],m=i[d+c-1],f=p.length-p.match(s[0])[0].length,g=m.match(s[c-1])[0].length;l&&l.end.row===d&&l.end.column>f||(a.push(l=new o(d,f,d+c-1,g)),c>2&&(d=d+c-2))}}else for(var b=0;b<i.length;b++){var v=r.getMatchOffsets(i[b],s);for(h=0;h<v.length;h++){var k=v[h];a.push(new o(b,k.offset,b,k.offset+k.length))}}if(n){var y=n.start.column,w=n.start.column;b=0,h=a.length-1;while(b<h&&a[b].start.column<y&&a[b].start.row==n.start.row)b++;while(b<h&&a[h].end.column>w&&a[h].end.row==n.end.row)h--;for(a=a.slice(b,h+1),b=0,h=a.length;b<h;b++)a[b].start.row+=n.start.row,a[b].end.row+=n.start.row}return a},this.replace=function(e,t){var n=this.$options,r=this.$assembleRegExp(n);if(n.$isMultiLine)return t;if(r){var i=r.exec(e);if(!i||i[0].length!=e.length)return null;if(t=e.replace(r,t),n.preserveCase){t=t.split(\"\");for(var o=Math.min(e.length,e.length);o--;){var a=e[o];a&&a.toLowerCase()!=a?t[o]=t[o].toUpperCase():t[o]=t[o].toLowerCase()}t=t.join(\"\")}return t}},this.$assembleRegExp=function(e,t){if(e.needle instanceof RegExp)return e.re=e.needle;var n=e.needle;if(!e.needle)return e.re=!1;e.regExp||(n=r.escapeRegExp(n)),e.wholeWord&&(n=s(n,e));var i=e.caseSensitive?\"gm\":\"gmi\";if(e.$isMultiLine=!t&&/[\\n\\r]/.test(n),e.$isMultiLine)return e.re=this.$assembleMultilineRegExp(n,i);try{var o=new RegExp(n,i)}catch(a){o=!1}return e.re=o},this.$assembleMultilineRegExp=function(e,t){for(var n=e.replace(/\\r\\n|\\r|\\n/g,\"$\\n^\").split(\"\\n\"),r=[],i=0;i<n.length;i++)try{r.push(new RegExp(n[i],t))}catch(o){return!1}return r},this.$matchIterator=function(e,t){var n=this.$assembleRegExp(t);if(!n)return!1;var r=1==t.backwards,i=0!=t.skipCurrent,o=t.range,a=t.start;a||(a=o?o[r?\"end\":\"start\"]:e.selection.getRange()),a.start&&(a=a[i!=r?\"end\":\"start\"]);var s=o?o.start.row:0,l=o?o.end.row:e.getLength()-1;if(r)var c=function(e){var n=a.row;if(!d(n,a.column,e)){for(n--;n>=s;n--)if(d(n,Number.MAX_VALUE,e))return;if(0!=t.wrap)for(n=l,s=a.row;n>=s;n--)if(d(n,Number.MAX_VALUE,e))return}};else c=function(e){var n=a.row;if(!d(n,a.column,e)){for(n+=1;n<=l;n++)if(d(n,0,e))return;if(0!=t.wrap)for(n=s,l=a.row;n<=l;n++)if(d(n,0,e))return}};if(t.$isMultiLine)var u=n.length,d=function(t,i,o){var a=r?t-u+1:t;if(!(a<0)){var s=e.getLine(a),l=s.search(n[0]);if(!(!r&&l<i||-1===l)){for(var c=1;c<u;c++)if(s=e.getLine(a+c),-1==s.search(n[c]))return;var d=s.match(n[u-1])[0].length;if(!(r&&d>i))return!!o(a,l,a+u-1,d)||void 0}}};else if(r)d=function(t,r,i){var o,a=e.getLine(t),s=[],l=0;n.lastIndex=0;while(o=n.exec(a)){var c=o[0].length;if(l=o.index,!c){if(l>=a.length)break;n.lastIndex=l+=1}if(o.index+c>r)break;s.push(o.index,c)}for(var u=s.length-1;u>=0;u-=2){var d=s[u-1];c=s[u];if(i(t,d,t,d+c))return!0}};else d=function(t,r,i){var o,a=e.getLine(t),s=r;n.lastIndex=r;while(o=n.exec(a)){var l=o[0].length;if(s=o.index,i(t,s,t,s+l))return!0;if(!l&&(n.lastIndex=s+=1,s>=a.length))return!1}};return{forEach:c}}}).call(a.prototype),t.Search=a}),ace.define(\"ace/keyboard/hash_handler\",[\"require\",\"exports\",\"module\",\"ace/lib/keys\",\"ace/lib/useragent\"],function(e,t,n){\"use strict\";var r=e(\"../lib/keys\"),i=e(\"../lib/useragent\"),o=r.KEY_MODS;function a(e,t){this.platform=t||(i.isMac?\"mac\":\"win\"),this.commands={},this.commandKeyBinding={},this.addCommands(e),this.$singleCommand=!0}function s(e,t){a.call(this,e,t),this.$singleCommand=!1}s.prototype=a.prototype,function(){function e(e){return\"object\"==typeof e&&e.bindKey&&e.bindKey.position||(e.isDefault?-100:0)}this.addCommand=function(e){this.commands[e.name]&&this.removeCommand(e),this.commands[e.name]=e,e.bindKey&&this._buildKeyHash(e)},this.removeCommand=function(e,t){var n=e&&(\"string\"===typeof e?e:e.name);e=this.commands[n],t||delete this.commands[n];var r=this.commandKeyBinding;for(var i in r){var o=r[i];if(o==e)delete r[i];else if(Array.isArray(o)){var a=o.indexOf(e);-1!=a&&(o.splice(a,1),1==o.length&&(r[i]=o[0]))}}},this.bindKey=function(e,t,n){if(\"object\"==typeof e&&e&&(void 0==n&&(n=e.position),e=e[this.platform]),e)return\"function\"==typeof t?this.addCommand({exec:t,bindKey:e,name:t.name||e}):void e.split(\"|\").forEach(function(e){var r=\"\";if(-1!=e.indexOf(\" \")){var i=e.split(/\\s+/);e=i.pop(),i.forEach(function(e){var t=this.parseKeys(e),n=o[t.hashId]+t.key;r+=(r?\" \":\"\")+n,this._addCommandToBinding(r,\"chainKeys\")},this),r+=\" \"}var a=this.parseKeys(e),s=o[a.hashId]+a.key;this._addCommandToBinding(r+s,t,n)},this)},this._addCommandToBinding=function(t,n,r){var i,o=this.commandKeyBinding;if(n)if(!o[t]||this.$singleCommand)o[t]=n;else{Array.isArray(o[t])?-1!=(i=o[t].indexOf(n))&&o[t].splice(i,1):o[t]=[o[t]],\"number\"!=typeof r&&(r=e(n));var a=o[t];for(i=0;i<a.length;i++){var s=a[i],l=e(s);if(l>r)break}a.splice(i,0,n)}else delete o[t]},this.addCommands=function(e){e&&Object.keys(e).forEach(function(t){var n=e[t];if(n){if(\"string\"===typeof n)return this.bindKey(n,t);\"function\"===typeof n&&(n={exec:n}),\"object\"===typeof n&&(n.name||(n.name=t),this.addCommand(n))}},this)},this.removeCommands=function(e){Object.keys(e).forEach(function(t){this.removeCommand(e[t])},this)},this.bindKeys=function(e){Object.keys(e).forEach(function(t){this.bindKey(t,e[t])},this)},this._buildKeyHash=function(e){this.bindKey(e.bindKey,e)},this.parseKeys=function(e){var t=e.toLowerCase().split(/[\\-\\+]([\\-\\+])?/).filter(function(e){return e}),n=t.pop(),i=r[n];if(r.FUNCTION_KEYS[i])n=r.FUNCTION_KEYS[i].toLowerCase();else{if(!t.length)return{key:n,hashId:-1};if(1==t.length&&\"shift\"==t[0])return{key:n.toUpperCase(),hashId:-1}}for(var o=0,a=t.length;a--;){var s=r.KEY_MODS[t[a]];if(null==s)return\"undefined\"!=typeof console&&console.error(\"invalid modifier \"+t[a]+\" in \"+e),!1;o|=s}return{key:n,hashId:o}},this.findKeyCommand=function(e,t){var n=o[e]+t;return this.commandKeyBinding[n]},this.handleKeyboard=function(e,t,n,r){if(!(r<0)){var i=o[t]+n,a=this.commandKeyBinding[i];return e.$keyChain&&(e.$keyChain+=\" \"+i,a=this.commandKeyBinding[e.$keyChain]||a),!a||\"chainKeys\"!=a&&\"chainKeys\"!=a[a.length-1]?(e.$keyChain&&(t&&4!=t||1!=n.length?(-1==t||r>0)&&(e.$keyChain=\"\"):e.$keyChain=e.$keyChain.slice(0,-i.length-1)),{command:a}):(e.$keyChain=e.$keyChain||i,{command:\"null\"})}},this.getStatusText=function(e,t){return t.$keyChain||\"\"}}.call(a.prototype),t.HashHandler=a,t.MultiHashHandler=s}),ace.define(\"ace/commands/command_manager\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/keyboard/hash_handler\",\"ace/lib/event_emitter\"],function(e,t,n){\"use strict\";var r=e(\"../lib/oop\"),i=e(\"../keyboard/hash_handler\").MultiHashHandler,o=e(\"../lib/event_emitter\").EventEmitter,a=function(e,t){i.call(this,t,e),this.byName=this.commands,this.setDefaultHandler(\"exec\",function(e){return e.command.exec(e.editor,e.args||{})})};r.inherits(a,i),function(){r.implement(this,o),this.exec=function(e,t,n){if(Array.isArray(e)){for(var r=e.length;r--;)if(this.exec(e[r],t,n))return!0;return!1}if(\"string\"===typeof e&&(e=this.commands[e]),!e)return!1;if(t&&t.$readOnly&&!e.readOnly)return!1;if(e.isAvailable&&!e.isAvailable(t))return!1;var i={editor:t,command:e,args:n};return i.returnValue=this._emit(\"exec\",i),this._signal(\"afterExec\",i),!1!==i.returnValue},this.toggleRecording=function(e){if(!this.$inReplay)return e&&e._emit(\"changeStatus\"),this.recording?(this.macro.pop(),this.removeEventListener(\"exec\",this.$addCommandToMacro),this.macro.length||(this.macro=this.oldMacro),this.recording=!1):(this.$addCommandToMacro||(this.$addCommandToMacro=function(e){this.macro.push([e.command,e.args])}.bind(this)),this.oldMacro=this.macro,this.macro=[],this.on(\"exec\",this.$addCommandToMacro),this.recording=!0)},this.replay=function(e){if(!this.$inReplay&&this.macro){if(this.recording)return this.toggleRecording(e);try{this.$inReplay=!0,this.macro.forEach(function(t){\"string\"==typeof t?this.exec(t,e):this.exec(t[0],e,t[1])},this)}finally{this.$inReplay=!1}}},this.trimMacro=function(e){return e.map(function(e){return\"string\"!=typeof e[0]&&(e[0]=e[0].name),e[1]||(e=e[0]),e})}}.call(a.prototype),t.CommandManager=a}),ace.define(\"ace/commands/default_commands\",[\"require\",\"exports\",\"module\",\"ace/lib/lang\",\"ace/config\",\"ace/range\"],function(e,t,n){\"use strict\";var r=e(\"../lib/lang\"),i=e(\"../config\"),o=e(\"../range\").Range;function a(e,t){return{win:e,mac:t}}t.commands=[{name:\"showSettingsMenu\",bindKey:a(\"Ctrl-,\",\"Command-,\"),exec:function(e){i.loadModule(\"ace/ext/settings_menu\",function(t){t.init(e),e.showSettingsMenu()})},readOnly:!0},{name:\"goToNextError\",bindKey:a(\"Alt-E\",\"F4\"),exec:function(e){i.loadModule(\"ace/ext/error_marker\",function(t){t.showErrorMarker(e,1)})},scrollIntoView:\"animate\",readOnly:!0},{name:\"goToPreviousError\",bindKey:a(\"Alt-Shift-E\",\"Shift-F4\"),exec:function(e){i.loadModule(\"ace/ext/error_marker\",function(t){t.showErrorMarker(e,-1)})},scrollIntoView:\"animate\",readOnly:!0},{name:\"selectall\",bindKey:a(\"Ctrl-A\",\"Command-A\"),exec:function(e){e.selectAll()},readOnly:!0},{name:\"centerselection\",bindKey:a(null,\"Ctrl-L\"),exec:function(e){e.centerSelection()},readOnly:!0},{name:\"gotoline\",bindKey:a(\"Ctrl-L\",\"Command-L\"),exec:function(e){var t=parseInt(prompt(\"Enter line number:\"),10);isNaN(t)||e.gotoLine(t)},readOnly:!0},{name:\"fold\",bindKey:a(\"Alt-L|Ctrl-F1\",\"Command-Alt-L|Command-F1\"),exec:function(e){e.session.toggleFold(!1)},multiSelectAction:\"forEach\",scrollIntoView:\"center\",readOnly:!0},{name:\"unfold\",bindKey:a(\"Alt-Shift-L|Ctrl-Shift-F1\",\"Command-Alt-Shift-L|Command-Shift-F1\"),exec:function(e){e.session.toggleFold(!0)},multiSelectAction:\"forEach\",scrollIntoView:\"center\",readOnly:!0},{name:\"toggleFoldWidget\",bindKey:a(\"F2\",\"F2\"),exec:function(e){e.session.toggleFoldWidget()},multiSelectAction:\"forEach\",scrollIntoView:\"center\",readOnly:!0},{name:\"toggleParentFoldWidget\",bindKey:a(\"Alt-F2\",\"Alt-F2\"),exec:function(e){e.session.toggleFoldWidget(!0)},multiSelectAction:\"forEach\",scrollIntoView:\"center\",readOnly:!0},{name:\"foldall\",bindKey:a(null,\"Ctrl-Command-Option-0\"),exec:function(e){e.session.foldAll()},scrollIntoView:\"center\",readOnly:!0},{name:\"foldOther\",bindKey:a(\"Alt-0\",\"Command-Option-0\"),exec:function(e){e.session.foldAll(),e.session.unfold(e.selection.getAllRanges())},scrollIntoView:\"center\",readOnly:!0},{name:\"unfoldall\",bindKey:a(\"Alt-Shift-0\",\"Command-Option-Shift-0\"),exec:function(e){e.session.unfold()},scrollIntoView:\"center\",readOnly:!0},{name:\"findnext\",bindKey:a(\"Ctrl-K\",\"Command-G\"),exec:function(e){e.findNext()},multiSelectAction:\"forEach\",scrollIntoView:\"center\",readOnly:!0},{name:\"findprevious\",bindKey:a(\"Ctrl-Shift-K\",\"Command-Shift-G\"),exec:function(e){e.findPrevious()},multiSelectAction:\"forEach\",scrollIntoView:\"center\",readOnly:!0},{name:\"selectOrFindNext\",bindKey:a(\"Alt-K\",\"Ctrl-G\"),exec:function(e){e.selection.isEmpty()?e.selection.selectWord():e.findNext()},readOnly:!0},{name:\"selectOrFindPrevious\",bindKey:a(\"Alt-Shift-K\",\"Ctrl-Shift-G\"),exec:function(e){e.selection.isEmpty()?e.selection.selectWord():e.findPrevious()},readOnly:!0},{name:\"find\",bindKey:a(\"Ctrl-F\",\"Command-F\"),exec:function(e){i.loadModule(\"ace/ext/searchbox\",function(t){t.Search(e)})},readOnly:!0},{name:\"overwrite\",bindKey:\"Insert\",exec:function(e){e.toggleOverwrite()},readOnly:!0},{name:\"selecttostart\",bindKey:a(\"Ctrl-Shift-Home\",\"Command-Shift-Home|Command-Shift-Up\"),exec:function(e){e.getSelection().selectFileStart()},multiSelectAction:\"forEach\",readOnly:!0,scrollIntoView:\"animate\",aceCommandGroup:\"fileJump\"},{name:\"gotostart\",bindKey:a(\"Ctrl-Home\",\"Command-Home|Command-Up\"),exec:function(e){e.navigateFileStart()},multiSelectAction:\"forEach\",readOnly:!0,scrollIntoView:\"animate\",aceCommandGroup:\"fileJump\"},{name:\"selectup\",bindKey:a(\"Shift-Up\",\"Shift-Up|Ctrl-Shift-P\"),exec:function(e){e.getSelection().selectUp()},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\",readOnly:!0},{name:\"golineup\",bindKey:a(\"Up\",\"Up|Ctrl-P\"),exec:function(e,t){e.navigateUp(t.times)},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\",readOnly:!0},{name:\"selecttoend\",bindKey:a(\"Ctrl-Shift-End\",\"Command-Shift-End|Command-Shift-Down\"),exec:function(e){e.getSelection().selectFileEnd()},multiSelectAction:\"forEach\",readOnly:!0,scrollIntoView:\"animate\",aceCommandGroup:\"fileJump\"},{name:\"gotoend\",bindKey:a(\"Ctrl-End\",\"Command-End|Command-Down\"),exec:function(e){e.navigateFileEnd()},multiSelectAction:\"forEach\",readOnly:!0,scrollIntoView:\"animate\",aceCommandGroup:\"fileJump\"},{name:\"selectdown\",bindKey:a(\"Shift-Down\",\"Shift-Down|Ctrl-Shift-N\"),exec:function(e){e.getSelection().selectDown()},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\",readOnly:!0},{name:\"golinedown\",bindKey:a(\"Down\",\"Down|Ctrl-N\"),exec:function(e,t){e.navigateDown(t.times)},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\",readOnly:!0},{name:\"selectwordleft\",bindKey:a(\"Ctrl-Shift-Left\",\"Option-Shift-Left\"),exec:function(e){e.getSelection().selectWordLeft()},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\",readOnly:!0},{name:\"gotowordleft\",bindKey:a(\"Ctrl-Left\",\"Option-Left\"),exec:function(e){e.navigateWordLeft()},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\",readOnly:!0},{name:\"selecttolinestart\",bindKey:a(\"Alt-Shift-Left\",\"Command-Shift-Left|Ctrl-Shift-A\"),exec:function(e){e.getSelection().selectLineStart()},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\",readOnly:!0},{name:\"gotolinestart\",bindKey:a(\"Alt-Left|Home\",\"Command-Left|Home|Ctrl-A\"),exec:function(e){e.navigateLineStart()},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\",readOnly:!0},{name:\"selectleft\",bindKey:a(\"Shift-Left\",\"Shift-Left|Ctrl-Shift-B\"),exec:function(e){e.getSelection().selectLeft()},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\",readOnly:!0},{name:\"gotoleft\",bindKey:a(\"Left\",\"Left|Ctrl-B\"),exec:function(e,t){e.navigateLeft(t.times)},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\",readOnly:!0},{name:\"selectwordright\",bindKey:a(\"Ctrl-Shift-Right\",\"Option-Shift-Right\"),exec:function(e){e.getSelection().selectWordRight()},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\",readOnly:!0},{name:\"gotowordright\",bindKey:a(\"Ctrl-Right\",\"Option-Right\"),exec:function(e){e.navigateWordRight()},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\",readOnly:!0},{name:\"selecttolineend\",bindKey:a(\"Alt-Shift-Right\",\"Command-Shift-Right|Shift-End|Ctrl-Shift-E\"),exec:function(e){e.getSelection().selectLineEnd()},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\",readOnly:!0},{name:\"gotolineend\",bindKey:a(\"Alt-Right|End\",\"Command-Right|End|Ctrl-E\"),exec:function(e){e.navigateLineEnd()},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\",readOnly:!0},{name:\"selectright\",bindKey:a(\"Shift-Right\",\"Shift-Right\"),exec:function(e){e.getSelection().selectRight()},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\",readOnly:!0},{name:\"gotoright\",bindKey:a(\"Right\",\"Right|Ctrl-F\"),exec:function(e,t){e.navigateRight(t.times)},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\",readOnly:!0},{name:\"selectpagedown\",bindKey:\"Shift-PageDown\",exec:function(e){e.selectPageDown()},readOnly:!0},{name:\"pagedown\",bindKey:a(null,\"Option-PageDown\"),exec:function(e){e.scrollPageDown()},readOnly:!0},{name:\"gotopagedown\",bindKey:a(\"PageDown\",\"PageDown|Ctrl-V\"),exec:function(e){e.gotoPageDown()},readOnly:!0},{name:\"selectpageup\",bindKey:\"Shift-PageUp\",exec:function(e){e.selectPageUp()},readOnly:!0},{name:\"pageup\",bindKey:a(null,\"Option-PageUp\"),exec:function(e){e.scrollPageUp()},readOnly:!0},{name:\"gotopageup\",bindKey:\"PageUp\",exec:function(e){e.gotoPageUp()},readOnly:!0},{name:\"scrollup\",bindKey:a(\"Ctrl-Up\",null),exec:function(e){e.renderer.scrollBy(0,-2*e.renderer.layerConfig.lineHeight)},readOnly:!0},{name:\"scrolldown\",bindKey:a(\"Ctrl-Down\",null),exec:function(e){e.renderer.scrollBy(0,2*e.renderer.layerConfig.lineHeight)},readOnly:!0},{name:\"selectlinestart\",bindKey:\"Shift-Home\",exec:function(e){e.getSelection().selectLineStart()},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\",readOnly:!0},{name:\"selectlineend\",bindKey:\"Shift-End\",exec:function(e){e.getSelection().selectLineEnd()},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\",readOnly:!0},{name:\"togglerecording\",bindKey:a(\"Ctrl-Alt-E\",\"Command-Option-E\"),exec:function(e){e.commands.toggleRecording(e)},readOnly:!0},{name:\"replaymacro\",bindKey:a(\"Ctrl-Shift-E\",\"Command-Shift-E\"),exec:function(e){e.commands.replay(e)},readOnly:!0},{name:\"jumptomatching\",bindKey:a(\"Ctrl-P\",\"Ctrl-P\"),exec:function(e){e.jumpToMatching()},multiSelectAction:\"forEach\",scrollIntoView:\"animate\",readOnly:!0},{name:\"selecttomatching\",bindKey:a(\"Ctrl-Shift-P\",\"Ctrl-Shift-P\"),exec:function(e){e.jumpToMatching(!0)},multiSelectAction:\"forEach\",scrollIntoView:\"animate\",readOnly:!0},{name:\"expandToMatching\",bindKey:a(\"Ctrl-Shift-M\",\"Ctrl-Shift-M\"),exec:function(e){e.jumpToMatching(!0,!0)},multiSelectAction:\"forEach\",scrollIntoView:\"animate\",readOnly:!0},{name:\"passKeysToBrowser\",bindKey:a(null,null),exec:function(){},passEvent:!0,readOnly:!0},{name:\"copy\",exec:function(e){},readOnly:!0},{name:\"cut\",exec:function(e){var t=e.getSelectionRange();e._emit(\"cut\",t),e.selection.isEmpty()||(e.session.remove(t),e.clearSelection())},scrollIntoView:\"cursor\",multiSelectAction:\"forEach\"},{name:\"paste\",exec:function(e,t){e.$handlePaste(t)},scrollIntoView:\"cursor\"},{name:\"removeline\",bindKey:a(\"Ctrl-D\",\"Command-D\"),exec:function(e){e.removeLines()},scrollIntoView:\"cursor\",multiSelectAction:\"forEachLine\"},{name:\"duplicateSelection\",bindKey:a(\"Ctrl-Shift-D\",\"Command-Shift-D\"),exec:function(e){e.duplicateSelection()},scrollIntoView:\"cursor\",multiSelectAction:\"forEach\"},{name:\"sortlines\",bindKey:a(\"Ctrl-Alt-S\",\"Command-Alt-S\"),exec:function(e){e.sortLines()},scrollIntoView:\"selection\",multiSelectAction:\"forEachLine\"},{name:\"togglecomment\",bindKey:a(\"Ctrl-/\",\"Command-/\"),exec:function(e){e.toggleCommentLines()},multiSelectAction:\"forEachLine\",scrollIntoView:\"selectionPart\"},{name:\"toggleBlockComment\",bindKey:a(\"Ctrl-Shift-/\",\"Command-Shift-/\"),exec:function(e){e.toggleBlockComment()},multiSelectAction:\"forEach\",scrollIntoView:\"selectionPart\"},{name:\"modifyNumberUp\",bindKey:a(\"Ctrl-Shift-Up\",\"Alt-Shift-Up\"),exec:function(e){e.modifyNumber(1)},scrollIntoView:\"cursor\",multiSelectAction:\"forEach\"},{name:\"modifyNumberDown\",bindKey:a(\"Ctrl-Shift-Down\",\"Alt-Shift-Down\"),exec:function(e){e.modifyNumber(-1)},scrollIntoView:\"cursor\",multiSelectAction:\"forEach\"},{name:\"replace\",bindKey:a(\"Ctrl-H\",\"Command-Option-F\"),exec:function(e){i.loadModule(\"ace/ext/searchbox\",function(t){t.Search(e,!0)})}},{name:\"undo\",bindKey:a(\"Ctrl-Z\",\"Command-Z\"),exec:function(e){e.undo()}},{name:\"redo\",bindKey:a(\"Ctrl-Shift-Z|Ctrl-Y\",\"Command-Shift-Z|Command-Y\"),exec:function(e){e.redo()}},{name:\"copylinesup\",bindKey:a(\"Alt-Shift-Up\",\"Command-Option-Up\"),exec:function(e){e.copyLinesUp()},scrollIntoView:\"cursor\"},{name:\"movelinesup\",bindKey:a(\"Alt-Up\",\"Option-Up\"),exec:function(e){e.moveLinesUp()},scrollIntoView:\"cursor\"},{name:\"copylinesdown\",bindKey:a(\"Alt-Shift-Down\",\"Command-Option-Down\"),exec:function(e){e.copyLinesDown()},scrollIntoView:\"cursor\"},{name:\"movelinesdown\",bindKey:a(\"Alt-Down\",\"Option-Down\"),exec:function(e){e.moveLinesDown()},scrollIntoView:\"cursor\"},{name:\"del\",bindKey:a(\"Delete\",\"Delete|Ctrl-D|Shift-Delete\"),exec:function(e){e.remove(\"right\")},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\"},{name:\"backspace\",bindKey:a(\"Shift-Backspace|Backspace\",\"Ctrl-Backspace|Shift-Backspace|Backspace|Ctrl-H\"),exec:function(e){e.remove(\"left\")},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\"},{name:\"cut_or_delete\",bindKey:a(\"Shift-Delete\",null),exec:function(e){if(!e.selection.isEmpty())return!1;e.remove(\"left\")},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\"},{name:\"removetolinestart\",bindKey:a(\"Alt-Backspace\",\"Command-Backspace\"),exec:function(e){e.removeToLineStart()},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\"},{name:\"removetolineend\",bindKey:a(\"Alt-Delete\",\"Ctrl-K|Command-Delete\"),exec:function(e){e.removeToLineEnd()},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\"},{name:\"removetolinestarthard\",bindKey:a(\"Ctrl-Shift-Backspace\",null),exec:function(e){var t=e.selection.getRange();t.start.column=0,e.session.remove(t)},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\"},{name:\"removetolineendhard\",bindKey:a(\"Ctrl-Shift-Delete\",null),exec:function(e){var t=e.selection.getRange();t.end.column=Number.MAX_VALUE,e.session.remove(t)},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\"},{name:\"removewordleft\",bindKey:a(\"Ctrl-Backspace\",\"Alt-Backspace|Ctrl-Alt-Backspace\"),exec:function(e){e.removeWordLeft()},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\"},{name:\"removewordright\",bindKey:a(\"Ctrl-Delete\",\"Alt-Delete\"),exec:function(e){e.removeWordRight()},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\"},{name:\"outdent\",bindKey:a(\"Shift-Tab\",\"Shift-Tab\"),exec:function(e){e.blockOutdent()},multiSelectAction:\"forEach\",scrollIntoView:\"selectionPart\"},{name:\"indent\",bindKey:a(\"Tab\",\"Tab\"),exec:function(e){e.indent()},multiSelectAction:\"forEach\",scrollIntoView:\"selectionPart\"},{name:\"blockoutdent\",bindKey:a(\"Ctrl-[\",\"Ctrl-[\"),exec:function(e){e.blockOutdent()},multiSelectAction:\"forEachLine\",scrollIntoView:\"selectionPart\"},{name:\"blockindent\",bindKey:a(\"Ctrl-]\",\"Ctrl-]\"),exec:function(e){e.blockIndent()},multiSelectAction:\"forEachLine\",scrollIntoView:\"selectionPart\"},{name:\"insertstring\",exec:function(e,t){e.insert(t)},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\"},{name:\"inserttext\",exec:function(e,t){e.insert(r.stringRepeat(t.text||\"\",t.times||1))},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\"},{name:\"splitline\",bindKey:a(null,\"Ctrl-O\"),exec:function(e){e.splitLine()},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\"},{name:\"transposeletters\",bindKey:a(\"Alt-Shift-X\",\"Ctrl-T\"),exec:function(e){e.transposeLetters()},multiSelectAction:function(e){e.transposeSelections(1)},scrollIntoView:\"cursor\"},{name:\"touppercase\",bindKey:a(\"Ctrl-U\",\"Ctrl-U\"),exec:function(e){e.toUpperCase()},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\"},{name:\"tolowercase\",bindKey:a(\"Ctrl-Shift-U\",\"Ctrl-Shift-U\"),exec:function(e){e.toLowerCase()},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\"},{name:\"expandtoline\",bindKey:a(\"Ctrl-Shift-L\",\"Command-Shift-L\"),exec:function(e){var t=e.selection.getRange();t.start.column=t.end.column=0,t.end.row++,e.selection.setRange(t,!1)},multiSelectAction:\"forEach\",scrollIntoView:\"cursor\",readOnly:!0},{name:\"joinlines\",bindKey:a(null,null),exec:function(e){for(var t=e.selection.isBackwards(),n=t?e.selection.getSelectionLead():e.selection.getSelectionAnchor(),i=t?e.selection.getSelectionAnchor():e.selection.getSelectionLead(),a=e.session.doc.getLine(n.row).length,s=e.session.doc.getTextRange(e.selection.getRange()),l=s.replace(/\\n\\s*/,\" \").length,c=e.session.doc.getLine(n.row),u=n.row+1;u<=i.row+1;u++){var d=r.stringTrimLeft(r.stringTrimRight(e.session.doc.getLine(u)));0!==d.length&&(d=\" \"+d),c+=d}i.row+1<e.session.doc.getLength()-1&&(c+=e.session.doc.getNewLineCharacter()),e.clearSelection(),e.session.doc.replace(new o(n.row,0,i.row+2,0),c),l>0?(e.selection.moveCursorTo(n.row,n.column),e.selection.selectTo(n.row,n.column+l)):(a=e.session.doc.getLine(n.row).length>a?a+1:a,e.selection.moveCursorTo(n.row,a))},multiSelectAction:\"forEach\",readOnly:!0},{name:\"invertSelection\",bindKey:a(null,null),exec:function(e){var t=e.session.doc.getLength()-1,n=e.session.doc.getLine(t).length,r=e.selection.rangeList.ranges,i=[];r.length<1&&(r=[e.selection.getRange()]);for(var a=0;a<r.length;a++)a==r.length-1&&(r[a].end.row===t&&r[a].end.column===n||i.push(new o(r[a].end.row,r[a].end.column,t,n))),0===a?0===r[a].start.row&&0===r[a].start.column||i.push(new o(0,0,r[a].start.row,r[a].start.column)):i.push(new o(r[a-1].end.row,r[a-1].end.column,r[a].start.row,r[a].start.column));e.exitMultiSelectMode(),e.clearSelection();for(a=0;a<i.length;a++)e.selection.addRange(i[a],!1)},readOnly:!0,scrollIntoView:\"none\"}]}),ace.define(\"ace/editor\",[\"require\",\"exports\",\"module\",\"ace/lib/fixoldbrowsers\",\"ace/lib/oop\",\"ace/lib/dom\",\"ace/lib/lang\",\"ace/lib/useragent\",\"ace/keyboard/textinput\",\"ace/mouse/mouse_handler\",\"ace/mouse/fold_handler\",\"ace/keyboard/keybinding\",\"ace/edit_session\",\"ace/search\",\"ace/range\",\"ace/lib/event_emitter\",\"ace/commands/command_manager\",\"ace/commands/default_commands\",\"ace/config\",\"ace/token_iterator\"],function(e,t,n){\"use strict\";e(\"./lib/fixoldbrowsers\");var r=e(\"./lib/oop\"),i=e(\"./lib/dom\"),o=e(\"./lib/lang\"),a=e(\"./lib/useragent\"),s=e(\"./keyboard/textinput\").TextInput,l=e(\"./mouse/mouse_handler\").MouseHandler,c=e(\"./mouse/fold_handler\").FoldHandler,u=e(\"./keyboard/keybinding\").KeyBinding,d=e(\"./edit_session\").EditSession,h=e(\"./search\").Search,p=e(\"./range\").Range,m=e(\"./lib/event_emitter\").EventEmitter,f=e(\"./commands/command_manager\").CommandManager,g=e(\"./commands/default_commands\").commands,b=e(\"./config\"),v=e(\"./token_iterator\").TokenIterator,k=function(e,t){var n=e.getContainerElement();this.container=n,this.renderer=e,this.id=\"editor\"+ ++k.$uid,this.commands=new f(a.isMac?\"mac\":\"win\",g),\"object\"==typeof document&&(this.textInput=new s(e.getTextAreaContainer(),this),this.renderer.textarea=this.textInput.getElement(),this.$mouseHandler=new l(this),new c(this)),this.keyBinding=new u(this),this.$blockScrolling=0,this.$search=(new h).set({wrap:!0}),this.$historyTracker=this.$historyTracker.bind(this),this.commands.on(\"exec\",this.$historyTracker),this.$initOperationListeners(),this._$emitInputEvent=o.delayedCall(function(){this._signal(\"input\",{}),this.session&&this.session.bgTokenizer&&this.session.bgTokenizer.scheduleStart()}.bind(this)),this.on(\"change\",function(e,t){t._$emitInputEvent.schedule(31)}),this.setSession(t||new d(\"\")),b.resetOptions(this),b._signal(\"editor\",this)};k.$uid=0,function(){r.implement(this,m),this.$initOperationListeners=function(){this.selections=[],this.commands.on(\"exec\",this.startOperation.bind(this),!0),this.commands.on(\"afterExec\",this.endOperation.bind(this),!0),this.$opResetTimer=o.delayedCall(this.endOperation.bind(this)),this.on(\"change\",function(){this.curOp||this.startOperation(),this.curOp.docChanged=!0}.bind(this),!0),this.on(\"changeSelection\",function(){this.curOp||this.startOperation(),this.curOp.selectionChanged=!0}.bind(this),!0)},this.curOp=null,this.prevOp={},this.startOperation=function(e){if(this.curOp){if(!e||this.curOp.command)return;this.prevOp=this.curOp}e||(this.previousCommand=null,e={}),this.$opResetTimer.schedule(),this.curOp={command:e.command||{},args:e.args,scrollTop:this.renderer.scrollTop},this.curOp.command.name&&void 0!==this.curOp.command.scrollIntoView&&this.$blockScrolling++},this.endOperation=function(e){if(this.curOp){if(e&&!1===e.returnValue)return this.curOp=null;this._signal(\"beforeEndOperation\");var t=this.curOp.command;t.name&&this.$blockScrolling>0&&this.$blockScrolling--;var n=t&&t.scrollIntoView;if(n){switch(n){case\"center-animate\":n=\"animate\";case\"center\":this.renderer.scrollCursorIntoView(null,.5);break;case\"animate\":case\"cursor\":this.renderer.scrollCursorIntoView();break;case\"selectionPart\":var r=this.selection.getRange(),i=this.renderer.layerConfig;(r.start.row>=i.lastRow||r.end.row<=i.firstRow)&&this.renderer.scrollSelectionIntoView(this.selection.anchor,this.selection.lead);break;default:break}\"animate\"==n&&this.renderer.animateScrolling(this.curOp.scrollTop)}this.prevOp=this.curOp,this.curOp=null}},this.$mergeableCommands=[\"backspace\",\"del\",\"insertstring\"],this.$historyTracker=function(e){if(this.$mergeUndoDeltas){var t=this.prevOp,n=this.$mergeableCommands,r=t.command&&e.command.name==t.command.name;if(\"insertstring\"==e.command.name){var i=e.args;void 0===this.mergeNextCommand&&(this.mergeNextCommand=!0),r=r&&this.mergeNextCommand&&(!/\\s/.test(i)||/\\s/.test(t.args)),this.mergeNextCommand=!0}else r=r&&-1!==n.indexOf(e.command.name);\"always\"!=this.$mergeUndoDeltas&&Date.now()-this.sequenceStartTime>2e3&&(r=!1),r?this.session.mergeUndoDeltas=!0:-1!==n.indexOf(e.command.name)&&(this.sequenceStartTime=Date.now())}},this.setKeyboardHandler=function(e,t){if(e&&\"string\"===typeof e){this.$keybindingId=e;var n=this;b.loadModule([\"keybinding\",e],function(r){n.$keybindingId==e&&n.keyBinding.setKeyboardHandler(r&&r.handler),t&&t()})}else this.$keybindingId=null,this.keyBinding.setKeyboardHandler(e),t&&t()},this.getKeyboardHandler=function(){return this.keyBinding.getKeyboardHandler()},this.setSession=function(e){if(this.session!=e){this.curOp&&this.endOperation(),this.curOp={};var t=this.session;if(t){this.session.off(\"change\",this.$onDocumentChange),this.session.off(\"changeMode\",this.$onChangeMode),this.session.off(\"tokenizerUpdate\",this.$onTokenizerUpdate),this.session.off(\"changeTabSize\",this.$onChangeTabSize),this.session.off(\"changeWrapLimit\",this.$onChangeWrapLimit),this.session.off(\"changeWrapMode\",this.$onChangeWrapMode),this.session.off(\"changeFold\",this.$onChangeFold),this.session.off(\"changeFrontMarker\",this.$onChangeFrontMarker),this.session.off(\"changeBackMarker\",this.$onChangeBackMarker),this.session.off(\"changeBreakpoint\",this.$onChangeBreakpoint),this.session.off(\"changeAnnotation\",this.$onChangeAnnotation),this.session.off(\"changeOverwrite\",this.$onCursorChange),this.session.off(\"changeScrollTop\",this.$onScrollTopChange),this.session.off(\"changeScrollLeft\",this.$onScrollLeftChange);var n=this.session.getSelection();n.off(\"changeCursor\",this.$onCursorChange),n.off(\"changeSelection\",this.$onSelectionChange)}this.session=e,e?(this.$onDocumentChange=this.onDocumentChange.bind(this),e.on(\"change\",this.$onDocumentChange),this.renderer.setSession(e),this.$onChangeMode=this.onChangeMode.bind(this),e.on(\"changeMode\",this.$onChangeMode),this.$onTokenizerUpdate=this.onTokenizerUpdate.bind(this),e.on(\"tokenizerUpdate\",this.$onTokenizerUpdate),this.$onChangeTabSize=this.renderer.onChangeTabSize.bind(this.renderer),e.on(\"changeTabSize\",this.$onChangeTabSize),this.$onChangeWrapLimit=this.onChangeWrapLimit.bind(this),e.on(\"changeWrapLimit\",this.$onChangeWrapLimit),this.$onChangeWrapMode=this.onChangeWrapMode.bind(this),e.on(\"changeWrapMode\",this.$onChangeWrapMode),this.$onChangeFold=this.onChangeFold.bind(this),e.on(\"changeFold\",this.$onChangeFold),this.$onChangeFrontMarker=this.onChangeFrontMarker.bind(this),this.session.on(\"changeFrontMarker\",this.$onChangeFrontMarker),this.$onChangeBackMarker=this.onChangeBackMarker.bind(this),this.session.on(\"changeBackMarker\",this.$onChangeBackMarker),this.$onChangeBreakpoint=this.onChangeBreakpoint.bind(this),this.session.on(\"changeBreakpoint\",this.$onChangeBreakpoint),this.$onChangeAnnotation=this.onChangeAnnotation.bind(this),this.session.on(\"changeAnnotation\",this.$onChangeAnnotation),this.$onCursorChange=this.onCursorChange.bind(this),this.session.on(\"changeOverwrite\",this.$onCursorChange),this.$onScrollTopChange=this.onScrollTopChange.bind(this),this.session.on(\"changeScrollTop\",this.$onScrollTopChange),this.$onScrollLeftChange=this.onScrollLeftChange.bind(this),this.session.on(\"changeScrollLeft\",this.$onScrollLeftChange),this.selection=e.getSelection(),this.selection.on(\"changeCursor\",this.$onCursorChange),this.$onSelectionChange=this.onSelectionChange.bind(this),this.selection.on(\"changeSelection\",this.$onSelectionChange),this.onChangeMode(),this.$blockScrolling+=1,this.onCursorChange(),this.$blockScrolling-=1,this.onScrollTopChange(),this.onScrollLeftChange(),this.onSelectionChange(),this.onChangeFrontMarker(),this.onChangeBackMarker(),this.onChangeBreakpoint(),this.onChangeAnnotation(),this.session.getUseWrapMode()&&this.renderer.adjustWrapLimit(),this.renderer.updateFull()):(this.selection=null,this.renderer.setSession(e)),this._signal(\"changeSession\",{session:e,oldSession:t}),this.curOp=null,t&&t._signal(\"changeEditor\",{oldEditor:this}),e&&e._signal(\"changeEditor\",{editor:this}),e&&e.bgTokenizer&&e.bgTokenizer.scheduleStart()}},this.getSession=function(){return this.session},this.setValue=function(e,t){return this.session.doc.setValue(e),t?1==t?this.navigateFileEnd():-1==t&&this.navigateFileStart():this.selectAll(),e},this.getValue=function(){return this.session.getValue()},this.getSelection=function(){return this.selection},this.resize=function(e){this.renderer.onResize(e)},this.setTheme=function(e,t){this.renderer.setTheme(e,t)},this.getTheme=function(){return this.renderer.getTheme()},this.setStyle=function(e){this.renderer.setStyle(e)},this.unsetStyle=function(e){this.renderer.unsetStyle(e)},this.getFontSize=function(){return this.getOption(\"fontSize\")||i.computedStyle(this.container,\"fontSize\")},this.setFontSize=function(e){this.setOption(\"fontSize\",e)},this.$highlightBrackets=function(){if(this.session.$bracketHighlight&&(this.session.removeMarker(this.session.$bracketHighlight),this.session.$bracketHighlight=null),!this.$highlightPending){var e=this;this.$highlightPending=!0,setTimeout(function(){e.$highlightPending=!1;var t=e.session;if(t&&t.bgTokenizer){var n=t.findMatchingBracket(e.getCursorPosition());if(n)var r=new p(n.row,n.column,n.row,n.column+1);else if(t.$mode.getMatching)r=t.$mode.getMatching(e.session);r&&(t.$bracketHighlight=t.addMarker(r,\"ace_bracket\",\"text\"))}},50)}},this.$highlightTags=function(){if(!this.$highlightTagPending){var e=this;this.$highlightTagPending=!0,setTimeout(function(){e.$highlightTagPending=!1;var t=e.session;if(t&&t.bgTokenizer){var n=e.getCursorPosition(),r=new v(e.session,n.row,n.column),i=r.getCurrentToken();if(!i||!/\\b(?:tag-open|tag-name)/.test(i.type))return t.removeMarker(t.$tagHighlight),void(t.$tagHighlight=null);if(-1==i.type.indexOf(\"tag-open\")||(i=r.stepForward(),i)){var o=i.value,a=0,s=r.stepBackward();if(\"<\"==s.value)do{s=i,i=r.stepForward(),i&&i.value===o&&-1!==i.type.indexOf(\"tag-name\")&&(\"<\"===s.value?a++:\"</\"===s.value&&a--)}while(i&&a>=0);else{do{i=s,s=r.stepBackward(),i&&i.value===o&&-1!==i.type.indexOf(\"tag-name\")&&(\"<\"===s.value?a++:\"</\"===s.value&&a--)}while(s&&a<=0);r.stepForward()}if(!i)return t.removeMarker(t.$tagHighlight),void(t.$tagHighlight=null);var l=r.getCurrentTokenRow(),c=r.getCurrentTokenColumn(),u=new p(l,c,l,c+i.value.length),d=t.$backMarkers[t.$tagHighlight];t.$tagHighlight&&void 0!=d&&0!==u.compareRange(d.range)&&(t.removeMarker(t.$tagHighlight),t.$tagHighlight=null),u&&!t.$tagHighlight&&(t.$tagHighlight=t.addMarker(u,\"ace_bracket\",\"text\"))}}},50)}},this.focus=function(){var e=this;setTimeout(function(){e.textInput.focus()}),this.textInput.focus()},this.isFocused=function(){return this.textInput.isFocused()},this.blur=function(){this.textInput.blur()},this.onFocus=function(e){this.$isFocused||(this.$isFocused=!0,this.renderer.showCursor(),this.renderer.visualizeFocus(),this._emit(\"focus\",e))},this.onBlur=function(e){this.$isFocused&&(this.$isFocused=!1,this.renderer.hideCursor(),this.renderer.visualizeBlur(),this._emit(\"blur\",e))},this.$cursorChange=function(){this.renderer.updateCursor()},this.onDocumentChange=function(e){var t=this.session.$useWrapMode,n=e.start.row==e.end.row?e.end.row:1/0;this.renderer.updateLines(e.start.row,n,t),this._signal(\"change\",e),this.$cursorChange(),this.$updateHighlightActiveLine()},this.onTokenizerUpdate=function(e){var t=e.data;this.renderer.updateLines(t.first,t.last)},this.onScrollTopChange=function(){this.renderer.scrollToY(this.session.getScrollTop())},this.onScrollLeftChange=function(){this.renderer.scrollToX(this.session.getScrollLeft())},this.onCursorChange=function(){this.$cursorChange(),this.$blockScrolling||(b.warn(\"Automatically scrolling cursor into view after selection change\",\"this will be disabled in the next version\",\"set editor.$blockScrolling = Infinity to disable this message\"),this.renderer.scrollCursorIntoView()),this.$highlightBrackets(),this.$highlightTags(),this.$updateHighlightActiveLine(),this._signal(\"changeSelection\")},this.$updateHighlightActiveLine=function(){var e,t=this.getSession();if(this.$highlightActiveLine&&(\"line\"==this.$selectionStyle&&this.selection.isMultiLine()||(e=this.getCursorPosition()),!this.renderer.$maxLines||1!==this.session.getLength()||this.renderer.$minLines>1||(e=!1)),t.$highlightLineMarker&&!e)t.removeMarker(t.$highlightLineMarker.id),t.$highlightLineMarker=null;else if(!t.$highlightLineMarker&&e){var n=new p(e.row,e.column,e.row,1/0);n.id=t.addMarker(n,\"ace_active-line\",\"screenLine\"),t.$highlightLineMarker=n}else e&&(t.$highlightLineMarker.start.row=e.row,t.$highlightLineMarker.end.row=e.row,t.$highlightLineMarker.start.column=e.column,t._signal(\"changeBackMarker\"))},this.onSelectionChange=function(e){var t=this.session;if(t.$selectionMarker&&t.removeMarker(t.$selectionMarker),t.$selectionMarker=null,this.selection.isEmpty())this.$updateHighlightActiveLine();else{var n=this.selection.getRange(),r=this.getSelectionStyle();t.$selectionMarker=t.addMarker(n,\"ace_selection\",r)}var i=this.$highlightSelectedWord&&this.$getSelectionHighLightRegexp();this.session.highlight(i),this._signal(\"changeSelection\")},this.$getSelectionHighLightRegexp=function(){var e=this.session,t=this.getSelectionRange();if(!t.isEmpty()&&!t.isMultiLine()){var n=t.start.column-1,r=t.end.column+1,i=e.getLine(t.start.row),o=i.length,a=i.substring(Math.max(n,0),Math.min(r,o));if(!(n>=0&&/^[\\w\\d]/.test(a)||r<=o&&/[\\w\\d]$/.test(a))&&(a=i.substring(t.start.column,t.end.column),/^[\\w\\d]+$/.test(a))){var s=this.$search.$assembleRegExp({wholeWord:!0,caseSensitive:!0,needle:a});return s}}},this.onChangeFrontMarker=function(){this.renderer.updateFrontMarkers()},this.onChangeBackMarker=function(){this.renderer.updateBackMarkers()},this.onChangeBreakpoint=function(){this.renderer.updateBreakpoints()},this.onChangeAnnotation=function(){this.renderer.setAnnotations(this.session.getAnnotations())},this.onChangeMode=function(e){this.renderer.updateText(),this._emit(\"changeMode\",e)},this.onChangeWrapLimit=function(){this.renderer.updateFull()},this.onChangeWrapMode=function(){this.renderer.onResize(!0)},this.onChangeFold=function(){this.$updateHighlightActiveLine(),this.renderer.updateFull()},this.getSelectedText=function(){return this.session.getTextRange(this.getSelectionRange())},this.getCopyText=function(){var e=this.getSelectedText();return this._signal(\"copy\",e),e},this.onCopy=function(){this.commands.exec(\"copy\",this)},this.onCut=function(){this.commands.exec(\"cut\",this)},this.onPaste=function(e,t){var n={text:e,event:t};this.commands.exec(\"paste\",this,n)},this.$handlePaste=function(e){\"string\"==typeof e&&(e={text:e}),this._signal(\"paste\",e);var t=e.text;if(!this.inMultiSelectMode||this.inVirtualSelectionMode)this.insert(t);else{var n=t.split(/\\r\\n|\\r|\\n/),r=this.selection.rangeList.ranges;if(n.length>r.length||n.length<2||!n[1])return this.commands.exec(\"insertstring\",this,t);for(var i=r.length;i--;){var o=r[i];o.isEmpty()||this.session.remove(o),this.session.insert(o.start,n[i])}}},this.execCommand=function(e,t){return this.commands.exec(e,this,t)},this.insert=function(e,t){var n=this.session,r=n.getMode(),i=this.getCursorPosition();if(this.getBehavioursEnabled()&&!t){var o=r.transformAction(n.getState(i.row),\"insertion\",this,n,e);o&&(e!==o.text&&(this.session.mergeUndoDeltas=!1,this.$mergeNextCommand=!1),e=o.text)}if(\"\\t\"==e&&(e=this.session.getTabString()),this.selection.isEmpty()){if(this.session.getOverwrite()&&-1==e.indexOf(\"\\n\")){a=new p.fromPoints(i,i);a.end.column+=e.length,this.session.remove(a)}}else{var a=this.getSelectionRange();i=this.session.remove(a),this.clearSelection()}if(\"\\n\"==e||\"\\r\\n\"==e){var s=n.getLine(i.row);if(i.column>s.search(/\\S|$/)){var l=s.substr(i.column).search(/\\S|$/);n.doc.removeInLine(i.row,i.column,i.column+l)}}this.clearSelection();var c=i.column,u=n.getState(i.row),d=(s=n.getLine(i.row),r.checkOutdent(u,s,e));n.insert(i,e);if(o&&o.selection&&(2==o.selection.length?this.selection.setSelectionRange(new p(i.row,c+o.selection[0],i.row,c+o.selection[1])):this.selection.setSelectionRange(new p(i.row+o.selection[0],o.selection[1],i.row+o.selection[2],o.selection[3]))),n.getDocument().isNewLine(e)){var h=r.getNextLineIndent(u,s.slice(0,i.column),n.getTabString());n.insert({row:i.row+1,column:0},h)}d&&r.autoOutdent(u,n,i.row)},this.onTextInput=function(e){this.keyBinding.onTextInput(e)},this.onCommandKey=function(e,t,n){this.keyBinding.onCommandKey(e,t,n)},this.setOverwrite=function(e){this.session.setOverwrite(e)},this.getOverwrite=function(){return this.session.getOverwrite()},this.toggleOverwrite=function(){this.session.toggleOverwrite()},this.setScrollSpeed=function(e){this.setOption(\"scrollSpeed\",e)},this.getScrollSpeed=function(){return this.getOption(\"scrollSpeed\")},this.setDragDelay=function(e){this.setOption(\"dragDelay\",e)},this.getDragDelay=function(){return this.getOption(\"dragDelay\")},this.setSelectionStyle=function(e){this.setOption(\"selectionStyle\",e)},this.getSelectionStyle=function(){return this.getOption(\"selectionStyle\")},this.setHighlightActiveLine=function(e){this.setOption(\"highlightActiveLine\",e)},this.getHighlightActiveLine=function(){return this.getOption(\"highlightActiveLine\")},this.setHighlightGutterLine=function(e){this.setOption(\"highlightGutterLine\",e)},this.getHighlightGutterLine=function(){return this.getOption(\"highlightGutterLine\")},this.setHighlightSelectedWord=function(e){this.setOption(\"highlightSelectedWord\",e)},this.getHighlightSelectedWord=function(){return this.$highlightSelectedWord},this.setAnimatedScroll=function(e){this.renderer.setAnimatedScroll(e)},this.getAnimatedScroll=function(){return this.renderer.getAnimatedScroll()},this.setShowInvisibles=function(e){this.renderer.setShowInvisibles(e)},this.getShowInvisibles=function(){return this.renderer.getShowInvisibles()},this.setDisplayIndentGuides=function(e){this.renderer.setDisplayIndentGuides(e)},this.getDisplayIndentGuides=function(){return this.renderer.getDisplayIndentGuides()},this.setShowPrintMargin=function(e){this.renderer.setShowPrintMargin(e)},this.getShowPrintMargin=function(){return this.renderer.getShowPrintMargin()},this.setPrintMarginColumn=function(e){this.renderer.setPrintMarginColumn(e)},this.getPrintMarginColumn=function(){return this.renderer.getPrintMarginColumn()},this.setReadOnly=function(e){this.setOption(\"readOnly\",e)},this.getReadOnly=function(){return this.getOption(\"readOnly\")},this.setBehavioursEnabled=function(e){this.setOption(\"behavioursEnabled\",e)},this.getBehavioursEnabled=function(){return this.getOption(\"behavioursEnabled\")},this.setWrapBehavioursEnabled=function(e){this.setOption(\"wrapBehavioursEnabled\",e)},this.getWrapBehavioursEnabled=function(){return this.getOption(\"wrapBehavioursEnabled\")},this.setShowFoldWidgets=function(e){this.setOption(\"showFoldWidgets\",e)},this.getShowFoldWidgets=function(){return this.getOption(\"showFoldWidgets\")},this.setFadeFoldWidgets=function(e){this.setOption(\"fadeFoldWidgets\",e)},this.getFadeFoldWidgets=function(){return this.getOption(\"fadeFoldWidgets\")},this.remove=function(e){this.selection.isEmpty()&&(\"left\"==e?this.selection.selectLeft():this.selection.selectRight());var t=this.getSelectionRange();if(this.getBehavioursEnabled()){var n=this.session,r=n.getState(t.start.row),i=n.getMode().transformAction(r,\"deletion\",this,n,t);if(0===t.end.column){var o=n.getTextRange(t);if(\"\\n\"==o[o.length-1]){var a=n.getLine(t.end.row);/^\\s+$/.test(a)&&(t.end.column=a.length)}}i&&(t=i)}this.session.remove(t),this.clearSelection()},this.removeWordRight=function(){this.selection.isEmpty()&&this.selection.selectWordRight(),this.session.remove(this.getSelectionRange()),this.clearSelection()},this.removeWordLeft=function(){this.selection.isEmpty()&&this.selection.selectWordLeft(),this.session.remove(this.getSelectionRange()),this.clearSelection()},this.removeToLineStart=function(){this.selection.isEmpty()&&this.selection.selectLineStart(),this.session.remove(this.getSelectionRange()),this.clearSelection()},this.removeToLineEnd=function(){this.selection.isEmpty()&&this.selection.selectLineEnd();var e=this.getSelectionRange();e.start.column==e.end.column&&e.start.row==e.end.row&&(e.end.column=0,e.end.row++),this.session.remove(e),this.clearSelection()},this.splitLine=function(){this.selection.isEmpty()||(this.session.remove(this.getSelectionRange()),this.clearSelection());var e=this.getCursorPosition();this.insert(\"\\n\"),this.moveCursorToPosition(e)},this.transposeLetters=function(){if(this.selection.isEmpty()){var e=this.getCursorPosition(),t=e.column;if(0!==t){var n,r,i=this.session.getLine(e.row);t<i.length?(n=i.charAt(t)+i.charAt(t-1),r=new p(e.row,t-1,e.row,t+1)):(n=i.charAt(t-1)+i.charAt(t-2),r=new p(e.row,t-2,e.row,t)),this.session.replace(r,n),this.session.selection.moveToPosition(r.end)}}},this.toLowerCase=function(){var e=this.getSelectionRange();this.selection.isEmpty()&&this.selection.selectWord();var t=this.getSelectionRange(),n=this.session.getTextRange(t);this.session.replace(t,n.toLowerCase()),this.selection.setSelectionRange(e)},this.toUpperCase=function(){var e=this.getSelectionRange();this.selection.isEmpty()&&this.selection.selectWord();var t=this.getSelectionRange(),n=this.session.getTextRange(t);this.session.replace(t,n.toUpperCase()),this.selection.setSelectionRange(e)},this.indent=function(){var e=this.session,t=this.getSelectionRange();if(!(t.start.row<t.end.row)){if(t.start.column<t.end.column){var n=e.getTextRange(t);if(!/^\\s+$/.test(n)){u=this.$getSelectedRows();return void e.indentRows(u.first,u.last,\"\\t\")}}var r=e.getLine(t.start.row),i=t.start,a=e.getTabSize(),s=e.documentToScreenColumn(i.row,i.column);if(this.session.getUseSoftTabs())var l=a-s%a,c=o.stringRepeat(\" \",l);else{l=s%a;while(\" \"==r[t.start.column-1]&&l)t.start.column--,l--;this.selection.setSelectionRange(t),c=\"\\t\"}return this.insert(c)}var u=this.$getSelectedRows();e.indentRows(u.first,u.last,\"\\t\")},this.blockIndent=function(){var e=this.$getSelectedRows();this.session.indentRows(e.first,e.last,\"\\t\")},this.blockOutdent=function(){var e=this.session.getSelection();this.session.outdentRows(e.getRange())},this.sortLines=function(){for(var e=this.$getSelectedRows(),t=this.session,n=[],r=e.first;r<=e.last;r++)n.push(t.getLine(r));n.sort(function(e,t){return e.toLowerCase()<t.toLowerCase()?-1:e.toLowerCase()>t.toLowerCase()?1:0});var i=new p(0,0,0,0);for(r=e.first;r<=e.last;r++){var o=t.getLine(r);i.start.row=r,i.end.row=r,i.end.column=o.length,t.replace(i,n[r-e.first])}},this.toggleCommentLines=function(){var e=this.session.getState(this.getCursorPosition().row),t=this.$getSelectedRows();this.session.getMode().toggleCommentLines(e,this.session,t.first,t.last)},this.toggleBlockComment=function(){var e=this.getCursorPosition(),t=this.session.getState(e.row),n=this.getSelectionRange();this.session.getMode().toggleBlockComment(t,this.session,n,e)},this.getNumberAt=function(e,t){var n=/[\\-]?[0-9]+(?:\\.[0-9]+)?/g;n.lastIndex=0;var r=this.session.getLine(e);while(n.lastIndex<t){var i=n.exec(r);if(i.index<=t&&i.index+i[0].length>=t){var o={value:i[0],start:i.index,end:i.index+i[0].length};return o}}return null},this.modifyNumber=function(e){var t=this.selection.getCursor().row,n=this.selection.getCursor().column,r=new p(t,n-1,t,n),i=this.session.getTextRange(r);if(!isNaN(parseFloat(i))&&isFinite(i)){var o=this.getNumberAt(t,n);if(o){var a=o.value.indexOf(\".\")>=0?o.start+o.value.indexOf(\".\")+1:o.end,s=o.start+o.value.length-a,l=parseFloat(o.value);l*=Math.pow(10,s),a!==o.end&&n<a?e*=Math.pow(10,o.end-n-1):e*=Math.pow(10,o.end-n),l+=e,l/=Math.pow(10,s);var c=l.toFixed(s),u=new p(t,o.start,t,o.end);this.session.replace(u,c),this.moveCursorTo(t,Math.max(o.start+1,n+c.length-o.value.length))}}},this.removeLines=function(){var e=this.$getSelectedRows();this.session.removeFullLines(e.first,e.last),this.clearSelection()},this.duplicateSelection=function(){var e=this.selection,t=this.session,n=e.getRange(),r=e.isBackwards();if(n.isEmpty()){var i=n.start.row;t.duplicateLines(i,i)}else{var o=r?n.start:n.end,a=t.insert(o,t.getTextRange(n),!1);n.start=o,n.end=a,e.setSelectionRange(n,r)}},this.moveLinesDown=function(){this.$moveLines(1,!1)},this.moveLinesUp=function(){this.$moveLines(-1,!1)},this.moveText=function(e,t,n){return this.session.moveText(e,t,n)},this.copyLinesUp=function(){this.$moveLines(-1,!0)},this.copyLinesDown=function(){this.$moveLines(1,!0)},this.$moveLines=function(e,t){var n,r,i=this.selection;if(!i.inMultiSelectMode||this.inVirtualSelectionMode){var o=i.toOrientedRange();n=this.$getSelectedRows(o),r=this.session.$moveLines(n.first,n.last,t?0:e),t&&-1==e&&(r=0),o.moveBy(r,0),i.fromOrientedRange(o)}else{var a=i.rangeList.ranges;i.rangeList.detach(this.session),this.inVirtualSelectionMode=!0;for(var s=0,l=0,c=a.length,u=0;u<c;u++){var d=u;a[u].moveBy(s,0),n=this.$getSelectedRows(a[u]);var h=n.first,p=n.last;while(++u<c){l&&a[u].moveBy(l,0);var m=this.$getSelectedRows(a[u]);if(t&&m.first!=p)break;if(!t&&m.first>p+1)break;p=m.last}u--,s=this.session.$moveLines(h,p,t?0:e),t&&-1==e&&(d=u+1);while(d<=u)a[d].moveBy(s,0),d++;t||(s=0),l+=s}i.fromOrientedRange(i.ranges[0]),i.rangeList.attach(this.session),this.inVirtualSelectionMode=!1}},this.$getSelectedRows=function(e){return e=(e||this.getSelectionRange()).collapseRows(),{first:this.session.getRowFoldStart(e.start.row),last:this.session.getRowFoldEnd(e.end.row)}},this.onCompositionStart=function(e){this.renderer.showComposition(this.getCursorPosition())},this.onCompositionUpdate=function(e){this.renderer.setCompositionText(e)},this.onCompositionEnd=function(){this.renderer.hideComposition()},this.getFirstVisibleRow=function(){return this.renderer.getFirstVisibleRow()},this.getLastVisibleRow=function(){return this.renderer.getLastVisibleRow()},this.isRowVisible=function(e){return e>=this.getFirstVisibleRow()&&e<=this.getLastVisibleRow()},this.isRowFullyVisible=function(e){return e>=this.renderer.getFirstFullyVisibleRow()&&e<=this.renderer.getLastFullyVisibleRow()},this.$getVisibleRowCount=function(){return this.renderer.getScrollBottomRow()-this.renderer.getScrollTopRow()+1},this.$moveByPage=function(e,t){var n=this.renderer,r=this.renderer.layerConfig,i=e*Math.floor(r.height/r.lineHeight);this.$blockScrolling++,!0===t?this.selection.$moveSelection(function(){this.moveCursorBy(i,0)}):!1===t&&(this.selection.moveCursorBy(i,0),this.selection.clearSelection()),this.$blockScrolling--;var o=n.scrollTop;n.scrollBy(0,i*r.lineHeight),null!=t&&n.scrollCursorIntoView(null,.5),n.animateScrolling(o)},this.selectPageDown=function(){this.$moveByPage(1,!0)},this.selectPageUp=function(){this.$moveByPage(-1,!0)},this.gotoPageDown=function(){this.$moveByPage(1,!1)},this.gotoPageUp=function(){this.$moveByPage(-1,!1)},this.scrollPageDown=function(){this.$moveByPage(1)},this.scrollPageUp=function(){this.$moveByPage(-1)},this.scrollToRow=function(e){this.renderer.scrollToRow(e)},this.scrollToLine=function(e,t,n,r){this.renderer.scrollToLine(e,t,n,r)},this.centerSelection=function(){var e=this.getSelectionRange(),t={row:Math.floor(e.start.row+(e.end.row-e.start.row)/2),column:Math.floor(e.start.column+(e.end.column-e.start.column)/2)};this.renderer.alignCursor(t,.5)},this.getCursorPosition=function(){return this.selection.getCursor()},this.getCursorPositionScreen=function(){return this.session.documentToScreenPosition(this.getCursorPosition())},this.getSelectionRange=function(){return this.selection.getRange()},this.selectAll=function(){this.$blockScrolling+=1,this.selection.selectAll(),this.$blockScrolling-=1},this.clearSelection=function(){this.selection.clearSelection()},this.moveCursorTo=function(e,t){this.selection.moveCursorTo(e,t)},this.moveCursorToPosition=function(e){this.selection.moveCursorToPosition(e)},this.jumpToMatching=function(e,t){var n=this.getCursorPosition(),r=new v(this.session,n.row,n.column),i=r.getCurrentToken(),o=i||r.stepForward();if(o){var a,s,l=!1,c={},u=n.column-o.start,d={\")\":\"(\",\"(\":\"(\",\"]\":\"[\",\"[\":\"[\",\"{\":\"{\",\"}\":\"{\"};do{if(o.value.match(/[{}()\\[\\]]/g)){for(;u<o.value.length&&!l;u++)if(d[o.value[u]])switch(s=d[o.value[u]]+\".\"+o.type.replace(\"rparen\",\"lparen\"),isNaN(c[s])&&(c[s]=0),o.value[u]){case\"(\":case\"[\":case\"{\":c[s]++;break;case\")\":case\"]\":case\"}\":c[s]--,-1===c[s]&&(a=\"bracket\",l=!0);break}}else o&&-1!==o.type.indexOf(\"tag-name\")&&(isNaN(c[o.value])&&(c[o.value]=0),\"<\"===i.value?c[o.value]++:\"</\"===i.value&&c[o.value]--,-1===c[o.value]&&(a=\"tag\",l=!0));l||(i=o,o=r.stepForward(),u=0)}while(o&&!l);if(a){var h,m;if(\"bracket\"===a)h=this.session.getBracketRange(n),h||(h=new p(r.getCurrentTokenRow(),r.getCurrentTokenColumn()+u-1,r.getCurrentTokenRow(),r.getCurrentTokenColumn()+u-1),m=h.start,(t||m.row===n.row&&Math.abs(m.column-n.column)<2)&&(h=this.session.getBracketRange(m)));else if(\"tag\"===a){if(!o||-1===o.type.indexOf(\"tag-name\"))return;var f=o.value;if(h=new p(r.getCurrentTokenRow(),r.getCurrentTokenColumn()-2,r.getCurrentTokenRow(),r.getCurrentTokenColumn()-2),0===h.compare(n.row,n.column)){l=!1;do{o=i,i=r.stepBackward(),i&&(-1!==i.type.indexOf(\"tag-close\")&&h.setEnd(r.getCurrentTokenRow(),r.getCurrentTokenColumn()+1),o.value===f&&-1!==o.type.indexOf(\"tag-name\")&&(\"<\"===i.value?c[f]++:\"</\"===i.value&&c[f]--,0===c[f]&&(l=!0)))}while(i&&!l)}o&&o.type.indexOf(\"tag-name\")&&(m=h.start,m.row==n.row&&Math.abs(m.column-n.column)<2&&(m=h.end))}m=h&&h.cursor||m,m&&(e?h&&t?this.selection.setRange(h):h&&h.isEqual(this.getSelectionRange())?this.clearSelection():this.selection.selectTo(m.row,m.column):this.selection.moveTo(m.row,m.column))}}},this.gotoLine=function(e,t,n){this.selection.clearSelection(),this.session.unfold({row:e-1,column:t||0}),this.$blockScrolling+=1,this.exitMultiSelectMode&&this.exitMultiSelectMode(),this.moveCursorTo(e-1,t||0),this.$blockScrolling-=1,this.isRowFullyVisible(e-1)||this.scrollToLine(e-1,!0,n)},this.navigateTo=function(e,t){this.selection.moveTo(e,t)},this.navigateUp=function(e){if(this.selection.isMultiLine()&&!this.selection.isBackwards()){var t=this.selection.anchor.getPosition();return this.moveCursorToPosition(t)}this.selection.clearSelection(),this.selection.moveCursorBy(-e||-1,0)},this.navigateDown=function(e){if(this.selection.isMultiLine()&&this.selection.isBackwards()){var t=this.selection.anchor.getPosition();return this.moveCursorToPosition(t)}this.selection.clearSelection(),this.selection.moveCursorBy(e||1,0)},this.navigateLeft=function(e){if(this.selection.isEmpty()){e=e||1;while(e--)this.selection.moveCursorLeft()}else{var t=this.getSelectionRange().start;this.moveCursorToPosition(t)}this.clearSelection()},this.navigateRight=function(e){if(this.selection.isEmpty()){e=e||1;while(e--)this.selection.moveCursorRight()}else{var t=this.getSelectionRange().end;this.moveCursorToPosition(t)}this.clearSelection()},this.navigateLineStart=function(){this.selection.moveCursorLineStart(),this.clearSelection()},this.navigateLineEnd=function(){this.selection.moveCursorLineEnd(),this.clearSelection()},this.navigateFileEnd=function(){this.selection.moveCursorFileEnd(),this.clearSelection()},this.navigateFileStart=function(){this.selection.moveCursorFileStart(),this.clearSelection()},this.navigateWordRight=function(){this.selection.moveCursorWordRight(),this.clearSelection()},this.navigateWordLeft=function(){this.selection.moveCursorWordLeft(),this.clearSelection()},this.replace=function(e,t){t&&this.$search.set(t);var n=this.$search.find(this.session),r=0;return n?(this.$tryReplace(n,e)&&(r=1),null!==n&&(this.selection.setSelectionRange(n),this.renderer.scrollSelectionIntoView(n.start,n.end)),r):r},this.replaceAll=function(e,t){t&&this.$search.set(t);var n=this.$search.findAll(this.session),r=0;if(!n.length)return r;this.$blockScrolling+=1;var i=this.getSelectionRange();this.selection.moveTo(0,0);for(var o=n.length-1;o>=0;--o)this.$tryReplace(n[o],e)&&r++;return this.selection.setSelectionRange(i),this.$blockScrolling-=1,r},this.$tryReplace=function(e,t){var n=this.session.getTextRange(e);return t=this.$search.replace(n,t),null!==t?(e.end=this.session.replace(e,t),e):null},this.getLastSearchOptions=function(){return this.$search.getOptions()},this.find=function(e,t,n){t||(t={}),\"string\"==typeof e||e instanceof RegExp?t.needle=e:\"object\"==typeof e&&r.mixin(t,e);var i=this.selection.getRange();null==t.needle&&(e=this.session.getTextRange(i)||this.$search.$options.needle,e||(i=this.session.getWordRange(i.start.row,i.start.column),e=this.session.getTextRange(i)),this.$search.set({needle:e})),this.$search.set(t),t.start||this.$search.set({start:i});var o=this.$search.find(this.session);return t.preventScroll?o:o?(this.revealRange(o,n),o):(t.backwards?i.start=i.end:i.end=i.start,void this.selection.setRange(i))},this.findNext=function(e,t){this.find({skipCurrent:!0,backwards:!1},e,t)},this.findPrevious=function(e,t){this.find(e,{skipCurrent:!0,backwards:!0},t)},this.revealRange=function(e,t){this.$blockScrolling+=1,this.session.unfold(e),this.selection.setSelectionRange(e),this.$blockScrolling-=1;var n=this.renderer.scrollTop;this.renderer.scrollSelectionIntoView(e.start,e.end,.5),!1!==t&&this.renderer.animateScrolling(n)},this.undo=function(){this.$blockScrolling++,this.session.getUndoManager().undo(),this.$blockScrolling--,this.renderer.scrollCursorIntoView(null,.5)},this.redo=function(){this.$blockScrolling++,this.session.getUndoManager().redo(),this.$blockScrolling--,this.renderer.scrollCursorIntoView(null,.5)},this.destroy=function(){this.renderer.destroy(),this._signal(\"destroy\",this),this.session&&this.session.destroy()},this.setAutoScrollEditorIntoView=function(e){if(e){var t,n=this,r=!1;this.$scrollAnchor||(this.$scrollAnchor=document.createElement(\"div\"));var i=this.$scrollAnchor;i.style.cssText=\"position:absolute\",this.container.insertBefore(i,this.container.firstChild);var o=this.on(\"changeSelection\",function(){r=!0}),a=this.renderer.on(\"beforeRender\",function(){r&&(t=n.renderer.container.getBoundingClientRect())}),s=this.renderer.on(\"afterRender\",function(){if(r&&t&&(n.isFocused()||n.searchBox&&n.searchBox.isFocused())){var e=n.renderer,o=e.$cursorLayer.$pixelPos,a=e.layerConfig,s=o.top-a.offset;r=o.top>=0&&s+t.top<0||!(o.top<a.height&&o.top+t.top+a.lineHeight>window.innerHeight)&&null,null!=r&&(i.style.top=s+\"px\",i.style.left=o.left+\"px\",i.style.height=a.lineHeight+\"px\",i.scrollIntoView(r)),r=t=null}});this.setAutoScrollEditorIntoView=function(e){e||(delete this.setAutoScrollEditorIntoView,this.off(\"changeSelection\",o),this.renderer.off(\"afterRender\",s),this.renderer.off(\"beforeRender\",a))}}},this.$resetCursorStyle=function(){var e=this.$cursorStyle||\"ace\",t=this.renderer.$cursorLayer;t&&(t.setSmoothBlinking(/smooth/.test(e)),t.isBlinking=!this.$readOnly&&\"wide\"!=e,i.setCssClass(t.element,\"ace_slim-cursors\",/slim/.test(e)))}}.call(k.prototype),b.defineOptions(k.prototype,\"editor\",{selectionStyle:{set:function(e){this.onSelectionChange(),this._signal(\"changeSelectionStyle\",{data:e})},initialValue:\"line\"},highlightActiveLine:{set:function(){this.$updateHighlightActiveLine()},initialValue:!0},highlightSelectedWord:{set:function(e){this.$onSelectionChange()},initialValue:!0},readOnly:{set:function(e){this.$resetCursorStyle()},initialValue:!1},cursorStyle:{set:function(e){this.$resetCursorStyle()},values:[\"ace\",\"slim\",\"smooth\",\"wide\"],initialValue:\"ace\"},mergeUndoDeltas:{values:[!1,!0,\"always\"],initialValue:!0},behavioursEnabled:{initialValue:!0},wrapBehavioursEnabled:{initialValue:!0},autoScrollEditorIntoView:{set:function(e){this.setAutoScrollEditorIntoView(e)}},keyboardHandler:{set:function(e){this.setKeyboardHandler(e)},get:function(){return this.keybindingId},handlesSet:!0},hScrollBarAlwaysVisible:\"renderer\",vScrollBarAlwaysVisible:\"renderer\",highlightGutterLine:\"renderer\",animatedScroll:\"renderer\",showInvisibles:\"renderer\",showPrintMargin:\"renderer\",printMarginColumn:\"renderer\",printMargin:\"renderer\",fadeFoldWidgets:\"renderer\",showFoldWidgets:\"renderer\",showLineNumbers:\"renderer\",showGutter:\"renderer\",displayIndentGuides:\"renderer\",fontSize:\"renderer\",fontFamily:\"renderer\",maxLines:\"renderer\",minLines:\"renderer\",scrollPastEnd:\"renderer\",fixedWidthGutter:\"renderer\",theme:\"renderer\",scrollSpeed:\"$mouseHandler\",dragDelay:\"$mouseHandler\",dragEnabled:\"$mouseHandler\",focusTimout:\"$mouseHandler\",tooltipFollowsMouse:\"$mouseHandler\",firstLineNumber:\"session\",overwrite:\"session\",newLineMode:\"session\",useWorker:\"session\",useSoftTabs:\"session\",tabSize:\"session\",wrap:\"session\",indentedSoftWrap:\"session\",foldStyle:\"session\",mode:\"session\"}),t.Editor=k}),ace.define(\"ace/undomanager\",[\"require\",\"exports\",\"module\"],function(e,t,n){\"use strict\";var r=function(){this.reset()};(function(){function e(e){return{action:e.action,start:e.start,end:e.end,lines:1==e.lines.length?null:e.lines,text:1==e.lines.length?e.lines[0]:null}}function t(e){return{action:e.action,start:e.start,end:e.end,lines:e.lines||[e.text]}}function n(e,t){for(var n=new Array(e.length),r=0;r<e.length;r++){for(var i=e[r],o={group:i.group,deltas:new Array(i.length)},a=0;a<i.deltas.length;a++){var s=i.deltas[a];o.deltas[a]=t(s)}n[r]=o}return n}this.execute=function(e){var t=e.args[0];this.$doc=e.args[1],e.merge&&this.hasUndo()&&(this.dirtyCounter--,t=this.$undoStack.pop().concat(t)),this.$undoStack.push(t),this.$redoStack=[],this.dirtyCounter<0&&(this.dirtyCounter=NaN),this.dirtyCounter++},this.undo=function(e){var t=this.$undoStack.pop(),n=null;return t&&(n=this.$doc.undoChanges(t,e),this.$redoStack.push(t),this.dirtyCounter--),n},this.redo=function(e){var t=this.$redoStack.pop(),n=null;return t&&(n=this.$doc.redoChanges(this.$deserializeDeltas(t),e),this.$undoStack.push(t),this.dirtyCounter++),n},this.reset=function(){this.$undoStack=[],this.$redoStack=[],this.dirtyCounter=0},this.hasUndo=function(){return this.$undoStack.length>0},this.hasRedo=function(){return this.$redoStack.length>0},this.markClean=function(){this.dirtyCounter=0},this.isClean=function(){return 0===this.dirtyCounter},this.$serializeDeltas=function(t){return n(t,e)},this.$deserializeDeltas=function(e){return n(e,t)}}).call(r.prototype),t.UndoManager=r}),ace.define(\"ace/layer/gutter\",[\"require\",\"exports\",\"module\",\"ace/lib/dom\",\"ace/lib/oop\",\"ace/lib/lang\",\"ace/lib/event_emitter\"],function(e,t,n){\"use strict\";var r=e(\"../lib/dom\"),i=e(\"../lib/oop\"),o=e(\"../lib/lang\"),a=e(\"../lib/event_emitter\").EventEmitter,s=function(e){this.element=r.createElement(\"div\"),this.element.className=\"ace_layer ace_gutter-layer\",e.appendChild(this.element),this.setShowFoldWidgets(this.$showFoldWidgets),this.gutterWidth=0,this.$annotations=[],this.$updateAnnotations=this.$updateAnnotations.bind(this),this.$cells=[]};(function(){i.implement(this,a),this.setSession=function(e){this.session&&this.session.removeEventListener(\"change\",this.$updateAnnotations),this.session=e,e&&e.on(\"change\",this.$updateAnnotations)},this.addGutterDecoration=function(e,t){window.console&&console.warn&&console.warn(\"deprecated use session.addGutterDecoration\"),this.session.addGutterDecoration(e,t)},this.removeGutterDecoration=function(e,t){window.console&&console.warn&&console.warn(\"deprecated use session.removeGutterDecoration\"),this.session.removeGutterDecoration(e,t)},this.setAnnotations=function(e){this.$annotations=[];for(var t=0;t<e.length;t++){var n=e[t],r=n.row,i=this.$annotations[r];i||(i=this.$annotations[r]={text:[]});var a=n.text;a=a?o.escapeHTML(a):n.html||\"\",-1===i.text.indexOf(a)&&i.text.push(a);var s=n.type;\"error\"==s?i.className=\" ace_error\":\"warning\"==s&&\" ace_error\"!=i.className?i.className=\" ace_warning\":\"info\"!=s||i.className||(i.className=\" ace_info\")}},this.$updateAnnotations=function(e){if(this.$annotations.length){var t=e.start.row,n=e.end.row-t;if(0===n);else if(\"remove\"==e.action)this.$annotations.splice(t,n+1,null);else{var r=new Array(n+1);r.unshift(t,1),this.$annotations.splice.apply(this.$annotations,r)}}},this.update=function(e){var t=this.session,n=e.firstRow,i=Math.min(e.lastRow+e.gutterOffset,t.getLength()-1),o=t.getNextFoldLine(n),a=o?o.start.row:1/0,s=this.$showFoldWidgets&&t.foldWidgets,l=t.$breakpoints,c=t.$decorations,u=t.$firstLineNumber,d=0,h=t.gutterRenderer||this.$renderer,p=null,m=-1,f=n;while(1){if(f>a&&(f=o.end.row+1,o=t.getNextFoldLine(f,o),a=o?o.start.row:1/0),f>i){while(this.$cells.length>m+1)p=this.$cells.pop(),this.element.removeChild(p.element);break}p=this.$cells[++m],p||(p={element:null,textNode:null,foldWidget:null},p.element=r.createElement(\"div\"),p.textNode=document.createTextNode(\"\"),p.element.appendChild(p.textNode),this.element.appendChild(p.element),this.$cells[m]=p);var g=\"ace_gutter-cell \";l[f]&&(g+=l[f]),c[f]&&(g+=c[f]),this.$annotations[f]&&(g+=this.$annotations[f].className),p.element.className!=g&&(p.element.className=g);var b=t.getRowLength(f)*e.lineHeight+\"px\";if(b!=p.element.style.height&&(p.element.style.height=b),s){var v=s[f];null==v&&(v=s[f]=t.getFoldWidget(f))}if(v){p.foldWidget||(p.foldWidget=r.createElement(\"span\"),p.element.appendChild(p.foldWidget));g=\"ace_fold-widget ace_\"+v;\"start\"==v&&f==a&&f<o.end.row?g+=\" ace_closed\":g+=\" ace_open\",p.foldWidget.className!=g&&(p.foldWidget.className=g);b=e.lineHeight+\"px\";p.foldWidget.style.height!=b&&(p.foldWidget.style.height=b)}else p.foldWidget&&(p.element.removeChild(p.foldWidget),p.foldWidget=null);var k=d=h?h.getText(t,f):f+u;k!==p.textNode.data&&(p.textNode.data=k),f++}this.element.style.height=e.minHeight+\"px\",(this.$fixedWidth||t.$useWrapMode)&&(d=t.getLength()+u);var y=h?h.getWidth(t,d,e):d.toString().length*e.characterWidth,w=this.$padding||this.$computePadding();y+=w.left+w.right,y===this.gutterWidth||isNaN(y)||(this.gutterWidth=y,this.element.style.width=Math.ceil(this.gutterWidth)+\"px\",this._emit(\"changeGutterWidth\",y))},this.$fixedWidth=!1,this.$showLineNumbers=!0,this.$renderer=\"\",this.setShowLineNumbers=function(e){this.$renderer=!e&&{getWidth:function(){return\"\"},getText:function(){return\"\"}}},this.getShowLineNumbers=function(){return this.$showLineNumbers},this.$showFoldWidgets=!0,this.setShowFoldWidgets=function(e){e?r.addCssClass(this.element,\"ace_folding-enabled\"):r.removeCssClass(this.element,\"ace_folding-enabled\"),this.$showFoldWidgets=e,this.$padding=null},this.getShowFoldWidgets=function(){return this.$showFoldWidgets},this.$computePadding=function(){if(!this.element.firstChild)return{left:0,right:0};var e=r.computedStyle(this.element.firstChild);return this.$padding={},this.$padding.left=parseInt(e.paddingLeft)+1||0,this.$padding.right=parseInt(e.paddingRight)||0,this.$padding},this.getRegion=function(e){var t=this.$padding||this.$computePadding(),n=this.element.getBoundingClientRect();return e.x<t.left+n.left?\"markers\":this.$showFoldWidgets&&e.x>n.right-t.right?\"foldWidgets\":void 0}}).call(s.prototype),t.Gutter=s}),ace.define(\"ace/layer/marker\",[\"require\",\"exports\",\"module\",\"ace/range\",\"ace/lib/dom\"],function(e,t,n){\"use strict\";var r=e(\"../range\").Range,i=e(\"../lib/dom\"),o=function(e){this.element=i.createElement(\"div\"),this.element.className=\"ace_layer ace_marker-layer\",e.appendChild(this.element)};(function(){function e(e,t,n,r){return(e?1:0)|(t?2:0)|(n?4:0)|(r?8:0)}this.$padding=0,this.setPadding=function(e){this.$padding=e},this.setSession=function(e){this.session=e},this.setMarkers=function(e){this.markers=e},this.update=function(e){if(e){this.config=e;var t=[];for(var n in this.markers){var r=this.markers[n];if(r.range){var i=r.range.clipRows(e.firstRow,e.lastRow);if(!i.isEmpty())if(i=i.toScreenRange(this.session),r.renderer){var o=this.$getTop(i.start.row,e),a=this.$padding+(this.session.$bidiHandler.isBidiRow(i.start.row)?this.session.$bidiHandler.getPosLeft(i.start.column):i.start.column*e.characterWidth);r.renderer(t,i,a,o,e)}else\"fullLine\"==r.type?this.drawFullLineMarker(t,i,r.clazz,e):\"screenLine\"==r.type?this.drawScreenLineMarker(t,i,r.clazz,e):i.isMultiLine()?\"text\"==r.type?this.drawTextMarker(t,i,r.clazz,e):this.drawMultiLineMarker(t,i,r.clazz,e):this.session.$bidiHandler.isBidiRow(i.start.row)?this.drawBidiSingleLineMarker(t,i,r.clazz+\" ace_start ace_br15\",e):this.drawSingleLineMarker(t,i,r.clazz+\" ace_start ace_br15\",e)}else r.update(t,this,this.session,e)}this.element.innerHTML=t.join(\"\")}},this.$getTop=function(e,t){return(e-t.firstRowScreen)*t.lineHeight},this.drawTextMarker=function(t,n,i,o,a){for(var s=this.session,l=n.start.row,c=n.end.row,u=l,d=0,h=0,p=s.getScreenLastRowColumn(u),m=null,f=new r(u,n.start.column,u,h);u<=c;u++)f.start.row=f.end.row=u,f.start.column=u==l?n.start.column:s.getRowWrapIndent(u),f.end.column=p,d=h,h=p,p=u+1<c?s.getScreenLastRowColumn(u+1):u==c?0:n.end.column,m=i+(u==l?\" ace_start\":\"\")+\" ace_br\"+e(u==l||u==l+1&&n.start.column,d<h,h>p,u==c),this.session.$bidiHandler.isBidiRow(u)?this.drawBidiSingleLineMarker(t,f,m,o,u==c?0:1,a):this.drawSingleLineMarker(t,f,m,o,u==c?0:1,a)},this.drawMultiLineMarker=function(e,t,n,r,i){var o,a,s,l=this.$padding;if(i=i||\"\",this.session.$bidiHandler.isBidiRow(t.start.row)){var c=t.clone();c.end.row=c.start.row,c.end.column=this.session.getLine(c.start.row).length,this.drawBidiSingleLineMarker(e,c,n+\" ace_br1 ace_start\",r,null,i)}else o=r.lineHeight,a=this.$getTop(t.start.row,r),s=l+t.start.column*r.characterWidth,e.push(\"<div class='\",n,\" ace_br1 ace_start' style='\",\"height:\",o,\"px;\",\"right:0;\",\"top:\",a,\"px;\",\"left:\",s,\"px;\",i,\"'></div>\");if(this.session.$bidiHandler.isBidiRow(t.end.row)){c=t.clone();c.start.row=c.end.row,c.start.column=0,this.drawBidiSingleLineMarker(e,c,n+\" ace_br12\",r,null,i)}else{var u=t.end.column*r.characterWidth;o=r.lineHeight,a=this.$getTop(t.end.row,r),e.push(\"<div class='\",n,\" ace_br12' style='\",\"height:\",o,\"px;\",\"width:\",u,\"px;\",\"top:\",a,\"px;\",\"left:\",l,\"px;\",i,\"'></div>\")}if(o=(t.end.row-t.start.row-1)*r.lineHeight,!(o<=0)){a=this.$getTop(t.start.row+1,r);var d=(t.start.column?1:0)|(t.end.column?0:8);e.push(\"<div class='\",n,d?\" ace_br\"+d:\"\",\"' style='\",\"height:\",o,\"px;\",\"right:0;\",\"top:\",a,\"px;\",\"left:\",l,\"px;\",i,\"'></div>\")}},this.drawSingleLineMarker=function(e,t,n,r,i,o){var a=r.lineHeight,s=(t.end.column+(i||0)-t.start.column)*r.characterWidth,l=this.$getTop(t.start.row,r),c=this.$padding+t.start.column*r.characterWidth;e.push(\"<div class='\",n,\"' style='\",\"height:\",a,\"px;\",\"width:\",s,\"px;\",\"top:\",l,\"px;\",\"left:\",c,\"px;\",o||\"\",\"'></div>\")},this.drawBidiSingleLineMarker=function(e,t,n,r,i,o){var a=r.lineHeight,s=this.$getTop(t.start.row,r),l=this.$padding,c=this.session.$bidiHandler.getSelections(t.start.column,t.end.column);c.forEach(function(t){e.push(\"<div class='\",n,\"' style='\",\"height:\",a,\"px;\",\"width:\",t.width+(i||0),\"px;\",\"top:\",s,\"px;\",\"left:\",l+t.left,\"px;\",o||\"\",\"'></div>\")})},this.drawFullLineMarker=function(e,t,n,r,i){var o=this.$getTop(t.start.row,r),a=r.lineHeight;t.start.row!=t.end.row&&(a+=this.$getTop(t.end.row,r)-o),e.push(\"<div class='\",n,\"' style='\",\"height:\",a,\"px;\",\"top:\",o,\"px;\",\"left:0;right:0;\",i||\"\",\"'></div>\")},this.drawScreenLineMarker=function(e,t,n,r,i){var o=this.$getTop(t.start.row,r),a=r.lineHeight;e.push(\"<div class='\",n,\"' style='\",\"height:\",a,\"px;\",\"top:\",o,\"px;\",\"left:0;right:0;\",i||\"\",\"'></div>\")}}).call(o.prototype),t.Marker=o}),ace.define(\"ace/layer/text\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/lib/dom\",\"ace/lib/lang\",\"ace/lib/useragent\",\"ace/lib/event_emitter\"],function(e,t,n){\"use strict\";var r=e(\"../lib/oop\"),i=e(\"../lib/dom\"),o=e(\"../lib/lang\"),a=(e(\"../lib/useragent\"),e(\"../lib/event_emitter\").EventEmitter),s=function(e){this.element=i.createElement(\"div\"),this.element.className=\"ace_layer ace_text-layer\",e.appendChild(this.element),this.$updateEolChar=this.$updateEolChar.bind(this)};(function(){r.implement(this,a),this.EOF_CHAR=\"¶\",this.EOL_CHAR_LF=\"¬\",this.EOL_CHAR_CRLF=\"¤\",this.EOL_CHAR=this.EOL_CHAR_LF,this.TAB_CHAR=\"—\",this.SPACE_CHAR=\"·\",this.$padding=0,this.$updateEolChar=function(){var e=\"\\n\"==this.session.doc.getNewLineCharacter()?this.EOL_CHAR_LF:this.EOL_CHAR_CRLF;if(this.EOL_CHAR!=e)return this.EOL_CHAR=e,!0},this.setPadding=function(e){this.$padding=e,this.element.style.padding=\"0 \"+e+\"px\"},this.getLineHeight=function(){return this.$fontMetrics.$characterSize.height||0},this.getCharacterWidth=function(){return this.$fontMetrics.$characterSize.width||0},this.$setFontMetrics=function(e){this.$fontMetrics=e,this.$fontMetrics.on(\"changeCharacterSize\",function(e){this._signal(\"changeCharacterSize\",e)}.bind(this)),this.$pollSizeChanges()},this.checkForSizeChanges=function(){this.$fontMetrics.checkForSizeChanges()},this.$pollSizeChanges=function(){return this.$pollSizeChangesTimer=this.$fontMetrics.$pollSizeChanges()},this.setSession=function(e){this.session=e,e&&this.$computeTabString()},this.showInvisibles=!1,this.setShowInvisibles=function(e){return this.showInvisibles!=e&&(this.showInvisibles=e,this.$computeTabString(),!0)},this.displayIndentGuides=!0,this.setDisplayIndentGuides=function(e){return this.displayIndentGuides!=e&&(this.displayIndentGuides=e,this.$computeTabString(),!0)},this.$tabStrings=[],this.onChangeTabSize=this.$computeTabString=function(){var e=this.session.getTabSize();this.tabSize=e;for(var t=this.$tabStrings=[0],n=1;n<e+1;n++)this.showInvisibles?t.push(\"<span class='ace_invisible ace_invisible_tab'>\"+o.stringRepeat(this.TAB_CHAR,n)+\"</span>\"):t.push(o.stringRepeat(\" \",n));if(this.displayIndentGuides){this.$indentGuideRe=/\\s\\S| \\t|\\t |\\s$/;var r=\"ace_indent-guide\",i=\"\",a=\"\";if(this.showInvisibles){r+=\" ace_invisible\",i=\" ace_invisible_space\",a=\" ace_invisible_tab\";var s=o.stringRepeat(this.SPACE_CHAR,this.tabSize),l=o.stringRepeat(this.TAB_CHAR,this.tabSize)}else s=o.stringRepeat(\" \",this.tabSize),l=s;this.$tabStrings[\" \"]=\"<span class='\"+r+i+\"'>\"+s+\"</span>\",this.$tabStrings[\"\\t\"]=\"<span class='\"+r+a+\"'>\"+l+\"</span>\"}},this.updateLines=function(e,t,n){this.config.lastRow==e.lastRow&&this.config.firstRow==e.firstRow||this.scrollLines(e),this.config=e;for(var r=Math.max(t,e.firstRow),i=Math.min(n,e.lastRow),o=this.element.childNodes,a=0,s=e.firstRow;s<r;s++){var l=this.session.getFoldLine(s);if(l){if(l.containsRow(r)){r=l.start.row;break}s=l.end.row}a++}s=r,l=this.session.getNextFoldLine(s);var c=l?l.start.row:1/0;while(1){if(s>c&&(s=l.end.row+1,l=this.session.getNextFoldLine(s,l),c=l?l.start.row:1/0),s>i)break;var u=o[a++];if(u){var d=[];this.$renderLine(d,s,!this.$useLineGroups(),s==c&&l),u.style.height=e.lineHeight*this.session.getRowLength(s)+\"px\",u.innerHTML=d.join(\"\")}s++}},this.scrollLines=function(e){var t=this.config;if(this.config=e,!t||t.lastRow<e.firstRow)return this.update(e);if(e.lastRow<t.firstRow)return this.update(e);var n=this.element;if(t.firstRow<e.firstRow)for(var r=this.session.getFoldedRowCount(t.firstRow,e.firstRow-1);r>0;r--)n.removeChild(n.firstChild);if(t.lastRow>e.lastRow)for(r=this.session.getFoldedRowCount(e.lastRow+1,t.lastRow);r>0;r--)n.removeChild(n.lastChild);if(e.firstRow<t.firstRow){var i=this.$renderLinesFragment(e,e.firstRow,t.firstRow-1);n.firstChild?n.insertBefore(i,n.firstChild):n.appendChild(i)}if(e.lastRow>t.lastRow){i=this.$renderLinesFragment(e,t.lastRow+1,e.lastRow);n.appendChild(i)}},this.$renderLinesFragment=function(e,t,n){var r=this.element.ownerDocument.createDocumentFragment(),o=t,a=this.session.getNextFoldLine(o),s=a?a.start.row:1/0;while(1){if(o>s&&(o=a.end.row+1,a=this.session.getNextFoldLine(o,a),s=a?a.start.row:1/0),o>n)break;var l=i.createElement(\"div\"),c=[];if(this.$renderLine(c,o,!1,o==s&&a),l.innerHTML=c.join(\"\"),this.$useLineGroups())l.className=\"ace_line_group\",r.appendChild(l),l.style.height=e.lineHeight*this.session.getRowLength(o)+\"px\";else while(l.firstChild)r.appendChild(l.firstChild);o++}return r},this.update=function(e){this.config=e;var t=[],n=e.firstRow,r=e.lastRow,i=n,o=this.session.getNextFoldLine(i),a=o?o.start.row:1/0;while(1){if(i>a&&(i=o.end.row+1,o=this.session.getNextFoldLine(i,o),a=o?o.start.row:1/0),i>r)break;this.$useLineGroups()&&t.push(\"<div class='ace_line_group' style='height:\",e.lineHeight*this.session.getRowLength(i),\"px'>\"),this.$renderLine(t,i,!1,i==a&&o),this.$useLineGroups()&&t.push(\"</div>\"),i++}this.element.innerHTML=t.join(\"\")},this.$textToken={text:!0,rparen:!0,lparen:!0},this.$renderToken=function(e,t,n,r){var i=this,a=/\\t|&|<|>|( +)|([\\x00-\\x1f\\x80-\\xa0\\xad\\u1680\\u180E\\u2000-\\u200f\\u2028\\u2029\\u202F\\u205F\\u3000\\uFEFF\\uFFF9-\\uFFFC])|[\\u1100-\\u115F\\u11A3-\\u11A7\\u11FA-\\u11FF\\u2329-\\u232A\\u2E80-\\u2E99\\u2E9B-\\u2EF3\\u2F00-\\u2FD5\\u2FF0-\\u2FFB\\u3000-\\u303E\\u3041-\\u3096\\u3099-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u3190-\\u31BA\\u31C0-\\u31E3\\u31F0-\\u321E\\u3220-\\u3247\\u3250-\\u32FE\\u3300-\\u4DBF\\u4E00-\\uA48C\\uA490-\\uA4C6\\uA960-\\uA97C\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFAFF\\uFE10-\\uFE19\\uFE30-\\uFE52\\uFE54-\\uFE66\\uFE68-\\uFE6B\\uFF01-\\uFF60\\uFFE0-\\uFFE6]|[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]/g,s=function(e,n,r,a,s){if(n)return i.showInvisibles?\"<span class='ace_invisible ace_invisible_space'>\"+o.stringRepeat(i.SPACE_CHAR,e.length)+\"</span>\":e;if(\"&\"==e)return\"&#38;\";if(\"<\"==e)return\"&#60;\";if(\">\"==e)return\"&#62;\";if(\"\\t\"==e){var l=i.session.getScreenTabSize(t+a);return t+=l-1,i.$tabStrings[l]}if(\"　\"==e){var c=i.showInvisibles?\"ace_cjk ace_invisible ace_invisible_space\":\"ace_cjk\",u=i.showInvisibles?i.SPACE_CHAR:\"\";return t+=1,\"<span class='\"+c+\"' style='width:\"+2*i.config.characterWidth+\"px'>\"+u+\"</span>\"}return r?\"<span class='ace_invisible ace_invisible_space ace_invalid'>\"+i.SPACE_CHAR+\"</span>\":(t+=1,\"<span class='ace_cjk' style='width:\"+2*i.config.characterWidth+\"px'>\"+e+\"</span>\")},l=r.replace(a,s);if(this.$textToken[n.type])e.push(l);else{var c=\"ace_\"+n.type.replace(/\\./g,\" ace_\"),u=\"\";\"fold\"==n.type&&(u=\" style='width:\"+n.value.length*this.config.characterWidth+\"px;' \"),e.push(\"<span class='\",c,\"'\",u,\">\",l,\"</span>\")}return t+r.length},this.renderIndentGuide=function(e,t,n){var r=t.search(this.$indentGuideRe);return r<=0||r>=n?t:\" \"==t[0]?(r-=r%this.tabSize,e.push(o.stringRepeat(this.$tabStrings[\" \"],r/this.tabSize)),t.substr(r)):\"\\t\"==t[0]?(e.push(o.stringRepeat(this.$tabStrings[\"\\t\"],r)),t.substr(r)):t},this.$renderWrappedLine=function(e,t,n,r){for(var i=0,a=0,s=n[0],l=0,c=0;c<t.length;c++){var u=t[c],d=u.value;if(0==c&&this.displayIndentGuides){if(i=d.length,d=this.renderIndentGuide(e,d,s),!d)continue;i-=d.length}if(i+d.length<s)l=this.$renderToken(e,l,u,d),i+=d.length;else{while(i+d.length>=s)l=this.$renderToken(e,l,u,d.substring(0,s-i)),d=d.substring(s-i),i=s,r||e.push(\"</div>\",\"<div class='ace_line' style='height:\",this.config.lineHeight,\"px'>\"),e.push(o.stringRepeat(\" \",n.indent)),a++,l=0,s=n[a]||Number.MAX_VALUE;0!=d.length&&(i+=d.length,l=this.$renderToken(e,l,u,d))}}},this.$renderSimpleLine=function(e,t){var n=0,r=t[0],i=r.value;this.displayIndentGuides&&(i=this.renderIndentGuide(e,i)),i&&(n=this.$renderToken(e,n,r,i));for(var o=1;o<t.length;o++)r=t[o],i=r.value,n=this.$renderToken(e,n,r,i)},this.$renderLine=function(e,t,n,r){if(r||0==r||(r=this.session.getFoldLine(t)),r)var i=this.$getFoldLineTokens(t,r);else i=this.session.getTokens(t);if(n||e.push(\"<div class='ace_line' style='height:\",this.config.lineHeight*(this.$useLineGroups()?1:this.session.getRowLength(t)),\"px'>\"),i.length){var o=this.session.getRowSplitData(t);o&&o.length?this.$renderWrappedLine(e,i,o,n):this.$renderSimpleLine(e,i)}this.showInvisibles&&(r&&(t=r.end.row),e.push(\"<span class='ace_invisible ace_invisible_eol'>\",t==this.session.getLength()-1?this.EOF_CHAR:this.EOL_CHAR,\"</span>\")),n||e.push(\"</div>\")},this.$getFoldLineTokens=function(e,t){var n=this.session,r=[];function i(e,t,n){var i=0,o=0;while(o+e[i].value.length<t)if(o+=e[i].value.length,i++,i==e.length)return;if(o!=t){var a=e[i].value.substring(t-o);a.length>n-t&&(a=a.substring(0,n-t)),r.push({type:e[i].type,value:a}),o=t+a.length,i+=1}while(o<n&&i<e.length){a=e[i].value;a.length+o>n?r.push({type:e[i].type,value:a.substring(0,n-o)}):r.push(e[i]),o+=a.length,i+=1}}var o=n.getTokens(e);return t.walk(function(e,t,a,s,l){null!=e?r.push({type:\"fold\",value:e}):(l&&(o=n.getTokens(t)),o.length&&i(o,s,a))},t.end.row,this.session.getLine(t.end.row).length),r},this.$useLineGroups=function(){return this.session.getUseWrapMode()},this.destroy=function(){clearInterval(this.$pollSizeChangesTimer),this.$measureNode&&this.$measureNode.parentNode.removeChild(this.$measureNode),delete this.$measureNode}}).call(s.prototype),t.Text=s}),ace.define(\"ace/layer/cursor\",[\"require\",\"exports\",\"module\",\"ace/lib/dom\"],function(e,t,n){\"use strict\";var r,i=e(\"../lib/dom\"),o=function(e){this.element=i.createElement(\"div\"),this.element.className=\"ace_layer ace_cursor-layer\",e.appendChild(this.element),void 0===r&&(r=!(\"opacity\"in this.element.style)),this.isVisible=!1,this.isBlinking=!0,this.blinkInterval=1e3,this.smoothBlinking=!1,this.cursors=[],this.cursor=this.addCursor(),i.addCssClass(this.element,\"ace_hidden-cursors\"),this.$updateCursors=(r?this.$updateVisibility:this.$updateOpacity).bind(this)};(function(){this.$updateVisibility=function(e){for(var t=this.cursors,n=t.length;n--;)t[n].style.visibility=e?\"\":\"hidden\"},this.$updateOpacity=function(e){for(var t=this.cursors,n=t.length;n--;)t[n].style.opacity=e?\"\":\"0\"},this.$padding=0,this.setPadding=function(e){this.$padding=e},this.setSession=function(e){this.session=e},this.setBlinking=function(e){e!=this.isBlinking&&(this.isBlinking=e,this.restartTimer())},this.setBlinkInterval=function(e){e!=this.blinkInterval&&(this.blinkInterval=e,this.restartTimer())},this.setSmoothBlinking=function(e){e==this.smoothBlinking||r||(this.smoothBlinking=e,i.setCssClass(this.element,\"ace_smooth-blinking\",e),this.$updateCursors(!0),this.$updateCursors=this.$updateOpacity.bind(this),this.restartTimer())},this.addCursor=function(){var e=i.createElement(\"div\");return e.className=\"ace_cursor\",this.element.appendChild(e),this.cursors.push(e),e},this.removeCursor=function(){if(this.cursors.length>1){var e=this.cursors.pop();return e.parentNode.removeChild(e),e}},this.hideCursor=function(){this.isVisible=!1,i.addCssClass(this.element,\"ace_hidden-cursors\"),this.restartTimer()},this.showCursor=function(){this.isVisible=!0,i.removeCssClass(this.element,\"ace_hidden-cursors\"),this.restartTimer()},this.restartTimer=function(){var e=this.$updateCursors;if(clearInterval(this.intervalId),clearTimeout(this.timeoutId),this.smoothBlinking&&i.removeCssClass(this.element,\"ace_smooth-blinking\"),e(!0),this.isBlinking&&this.blinkInterval&&this.isVisible){this.smoothBlinking&&setTimeout(function(){i.addCssClass(this.element,\"ace_smooth-blinking\")}.bind(this));var t=function(){this.timeoutId=setTimeout(function(){e(!1)},.6*this.blinkInterval)}.bind(this);this.intervalId=setInterval(function(){e(!0),t()},this.blinkInterval),t()}},this.getPixelPosition=function(e,t){if(!this.config||!this.session)return{left:0,top:0};e||(e=this.session.selection.getCursor());var n=this.session.documentToScreenPosition(e),r=this.$padding+(this.session.$bidiHandler.isBidiRow(n.row,e.row)?this.session.$bidiHandler.getPosLeft(n.column):n.column*this.config.characterWidth),i=(n.row-(t?this.config.firstRowScreen:0))*this.config.lineHeight;return{left:r,top:i}},this.update=function(e){this.config=e;var t=this.session.$selectionMarkers,n=0,r=0;void 0!==t&&0!==t.length||(t=[{cursor:null}]);n=0;for(var i=t.length;n<i;n++){var o=this.getPixelPosition(t[n].cursor,!0);if(!((o.top>e.height+e.offset||o.top<0)&&n>1)){var a=(this.cursors[r++]||this.addCursor()).style;this.drawCursor?this.drawCursor(a,o,e,t[n],this.session):(a.left=o.left+\"px\",a.top=o.top+\"px\",a.width=e.characterWidth+\"px\",a.height=e.lineHeight+\"px\")}}while(this.cursors.length>r)this.removeCursor();var s=this.session.getOverwrite();this.$setOverwrite(s),this.$pixelPos=o,this.restartTimer()},this.drawCursor=null,this.$setOverwrite=function(e){e!=this.overwrite&&(this.overwrite=e,e?i.addCssClass(this.element,\"ace_overwrite-cursors\"):i.removeCssClass(this.element,\"ace_overwrite-cursors\"))},this.destroy=function(){clearInterval(this.intervalId),clearTimeout(this.timeoutId)}}).call(o.prototype),t.Cursor=o}),ace.define(\"ace/scrollbar\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/lib/dom\",\"ace/lib/event\",\"ace/lib/event_emitter\"],function(e,t,n){\"use strict\";var r=e(\"./lib/oop\"),i=e(\"./lib/dom\"),o=e(\"./lib/event\"),a=e(\"./lib/event_emitter\").EventEmitter,s=32768,l=function(e){this.element=i.createElement(\"div\"),this.element.className=\"ace_scrollbar ace_scrollbar\"+this.classSuffix,this.inner=i.createElement(\"div\"),this.inner.className=\"ace_scrollbar-inner\",this.element.appendChild(this.inner),e.appendChild(this.element),this.setVisible(!1),this.skipEvent=!1,o.addListener(this.element,\"scroll\",this.onScroll.bind(this)),o.addListener(this.element,\"mousedown\",o.preventDefault)};(function(){r.implement(this,a),this.setVisible=function(e){this.element.style.display=e?\"\":\"none\",this.isVisible=e,this.coeff=1}}).call(l.prototype);var c=function(e,t){l.call(this,e),this.scrollTop=0,this.scrollHeight=0,t.$scrollbarWidth=this.width=i.scrollbarWidth(e.ownerDocument),this.inner.style.width=this.element.style.width=(this.width||15)+5+\"px\",this.$minWidth=0};r.inherits(c,l),function(){this.classSuffix=\"-v\",this.onScroll=function(){if(!this.skipEvent){if(this.scrollTop=this.element.scrollTop,1!=this.coeff){var e=this.element.clientHeight/this.scrollHeight;this.scrollTop=this.scrollTop*(1-e)/(this.coeff-e)}this._emit(\"scroll\",{data:this.scrollTop})}this.skipEvent=!1},this.getWidth=function(){return Math.max(this.isVisible?this.width:0,this.$minWidth||0)},this.setHeight=function(e){this.element.style.height=e+\"px\"},this.setInnerHeight=this.setScrollHeight=function(e){this.scrollHeight=e,e>s?(this.coeff=s/e,e=s):1!=this.coeff&&(this.coeff=1),this.inner.style.height=e+\"px\"},this.setScrollTop=function(e){this.scrollTop!=e&&(this.skipEvent=!0,this.scrollTop=e,this.element.scrollTop=e*this.coeff)}}.call(c.prototype);var u=function(e,t){l.call(this,e),this.scrollLeft=0,this.height=t.$scrollbarWidth,this.inner.style.height=this.element.style.height=(this.height||15)+5+\"px\"};r.inherits(u,l),function(){this.classSuffix=\"-h\",this.onScroll=function(){this.skipEvent||(this.scrollLeft=this.element.scrollLeft,this._emit(\"scroll\",{data:this.scrollLeft})),this.skipEvent=!1},this.getHeight=function(){return this.isVisible?this.height:0},this.setWidth=function(e){this.element.style.width=e+\"px\"},this.setInnerWidth=function(e){this.inner.style.width=e+\"px\"},this.setScrollWidth=function(e){this.inner.style.width=e+\"px\"},this.setScrollLeft=function(e){this.scrollLeft!=e&&(this.skipEvent=!0,this.scrollLeft=this.element.scrollLeft=e)}}.call(u.prototype),t.ScrollBar=c,t.ScrollBarV=c,t.ScrollBarH=u,t.VScrollBar=c,t.HScrollBar=u}),ace.define(\"ace/renderloop\",[\"require\",\"exports\",\"module\",\"ace/lib/event\"],function(e,t,n){\"use strict\";var r=e(\"./lib/event\"),i=function(e,t){this.onRender=e,this.pending=!1,this.changes=0,this.window=t||window};(function(){this.schedule=function(e){if(this.changes=this.changes|e,!this.pending&&this.changes){this.pending=!0;var t=this;r.nextFrame(function(){var e;t.pending=!1;while(e=t.changes)t.changes=0,t.onRender(e)},this.window)}}}).call(i.prototype),t.RenderLoop=i}),ace.define(\"ace/layer/font_metrics\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/lib/dom\",\"ace/lib/lang\",\"ace/lib/useragent\",\"ace/lib/event_emitter\"],function(e,t,n){var r=e(\"../lib/oop\"),i=e(\"../lib/dom\"),o=e(\"../lib/lang\"),a=e(\"../lib/useragent\"),s=e(\"../lib/event_emitter\").EventEmitter,l=0,c=t.FontMetrics=function(e){this.el=i.createElement(\"div\"),this.$setMeasureNodeStyles(this.el.style,!0),this.$main=i.createElement(\"div\"),this.$setMeasureNodeStyles(this.$main.style),this.$measureNode=i.createElement(\"div\"),this.$setMeasureNodeStyles(this.$measureNode.style),this.el.appendChild(this.$main),this.el.appendChild(this.$measureNode),e.appendChild(this.el),l||this.$testFractionalRect(),this.$measureNode.innerHTML=o.stringRepeat(\"X\",l),this.$characterSize={width:0,height:0},this.checkForSizeChanges()};(function(){r.implement(this,s),this.$characterSize={width:0,height:0},this.$testFractionalRect=function(){var e=i.createElement(\"div\");this.$setMeasureNodeStyles(e.style),e.style.width=\"0.2px\",document.documentElement.appendChild(e);var t=e.getBoundingClientRect().width;l=t>0&&t<1?50:100,e.parentNode.removeChild(e)},this.$setMeasureNodeStyles=function(e,t){e.width=e.height=\"auto\",e.left=e.top=\"0px\",e.visibility=\"hidden\",e.position=\"absolute\",e.whiteSpace=\"pre\",a.isIE<8?e[\"font-family\"]=\"inherit\":e.font=\"inherit\",e.overflow=t?\"hidden\":\"visible\"},this.checkForSizeChanges=function(){var e=this.$measureSizes();if(e&&(this.$characterSize.width!==e.width||this.$characterSize.height!==e.height)){this.$measureNode.style.fontWeight=\"bold\";var t=this.$measureSizes();this.$measureNode.style.fontWeight=\"\",this.$characterSize=e,this.charSizes=Object.create(null),this.allowBoldFonts=t&&t.width===e.width&&t.height===e.height,this._emit(\"changeCharacterSize\",{data:e})}},this.$pollSizeChanges=function(){if(this.$pollSizeChangesTimer)return this.$pollSizeChangesTimer;var e=this;return this.$pollSizeChangesTimer=setInterval(function(){e.checkForSizeChanges()},500)},this.setPolling=function(e){e?this.$pollSizeChanges():this.$pollSizeChangesTimer&&(clearInterval(this.$pollSizeChangesTimer),this.$pollSizeChangesTimer=0)},this.$measureSizes=function(){if(50===l){var e=null;try{e=this.$measureNode.getBoundingClientRect()}catch(n){e={width:0,height:0}}var t={height:e.height,width:e.width/l}}else t={height:this.$measureNode.clientHeight,width:this.$measureNode.clientWidth/l};return 0===t.width||0===t.height?null:t},this.$measureCharWidth=function(e){this.$main.innerHTML=o.stringRepeat(e,l);var t=this.$main.getBoundingClientRect();return t.width/l},this.getCharacterWidth=function(e){var t=this.charSizes[e];return void 0===t&&(t=this.charSizes[e]=this.$measureCharWidth(e)/this.$characterSize.width),t},this.destroy=function(){clearInterval(this.$pollSizeChangesTimer),this.el&&this.el.parentNode&&this.el.parentNode.removeChild(this.el)}}).call(c.prototype)}),ace.define(\"ace/virtual_renderer\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/lib/dom\",\"ace/config\",\"ace/lib/useragent\",\"ace/layer/gutter\",\"ace/layer/marker\",\"ace/layer/text\",\"ace/layer/cursor\",\"ace/scrollbar\",\"ace/scrollbar\",\"ace/renderloop\",\"ace/layer/font_metrics\",\"ace/lib/event_emitter\"],function(e,t,n){\"use strict\";var r=e(\"./lib/oop\"),i=e(\"./lib/dom\"),o=e(\"./config\"),a=e(\"./lib/useragent\"),s=e(\"./layer/gutter\").Gutter,l=e(\"./layer/marker\").Marker,c=e(\"./layer/text\").Text,u=e(\"./layer/cursor\").Cursor,d=e(\"./scrollbar\").HScrollBar,h=e(\"./scrollbar\").VScrollBar,p=e(\"./renderloop\").RenderLoop,m=e(\"./layer/font_metrics\").FontMetrics,f=e(\"./lib/event_emitter\").EventEmitter,g='.ace_editor {position: relative;overflow: hidden;font: 12px/normal \\'Monaco\\', \\'Menlo\\', \\'Ubuntu Mono\\', \\'Consolas\\', \\'source-code-pro\\', monospace;direction: ltr;text-align: left;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);}.ace_scroller {position: absolute;overflow: hidden;top: 0;bottom: 0;background-color: inherit;-ms-user-select: none;-moz-user-select: none;-webkit-user-select: none;user-select: none;cursor: text;}.ace_content {position: absolute;-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;min-width: 100%;}.ace_dragging .ace_scroller:before{position: absolute;top: 0;left: 0;right: 0;bottom: 0;content: \\'\\';background: rgba(250, 250, 250, 0.01);z-index: 1000;}.ace_dragging.ace_dark .ace_scroller:before{background: rgba(0, 0, 0, 0.01);}.ace_selecting, .ace_selecting * {cursor: text !important;}.ace_gutter {position: absolute;overflow : hidden;width: auto;top: 0;bottom: 0;left: 0;cursor: default;z-index: 4;-ms-user-select: none;-moz-user-select: none;-webkit-user-select: none;user-select: none;}.ace_gutter-active-line {position: absolute;left: 0;right: 0;}.ace_scroller.ace_scroll-left {box-shadow: 17px 0 16px -16px rgba(0, 0, 0, 0.4) inset;}.ace_gutter-cell {padding-left: 19px;padding-right: 6px;background-repeat: no-repeat;}.ace_gutter-cell.ace_error {background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABOFBMVEX/////////QRswFAb/Ui4wFAYwFAYwFAaWGAfDRymzOSH/PxswFAb/SiUwFAYwFAbUPRvjQiDllog5HhHdRybsTi3/Tyv9Tir+Syj/UC3////XurebMBIwFAb/RSHbPx/gUzfdwL3kzMivKBAwFAbbvbnhPx66NhowFAYwFAaZJg8wFAaxKBDZurf/RB6mMxb/SCMwFAYwFAbxQB3+RB4wFAb/Qhy4Oh+4QifbNRcwFAYwFAYwFAb/QRzdNhgwFAYwFAbav7v/Uy7oaE68MBK5LxLewr/r2NXewLswFAaxJw4wFAbkPRy2PyYwFAaxKhLm1tMwFAazPiQwFAaUGAb/QBrfOx3bvrv/VC/maE4wFAbRPBq6MRO8Qynew8Dp2tjfwb0wFAbx6eju5+by6uns4uH9/f36+vr/GkHjAAAAYnRSTlMAGt+64rnWu/bo8eAA4InH3+DwoN7j4eLi4xP99Nfg4+b+/u9B/eDs1MD1mO7+4PHg2MXa347g7vDizMLN4eG+Pv7i5evs/v79yu7S3/DV7/498Yv24eH+4ufQ3Ozu/v7+y13sRqwAAADLSURBVHjaZc/XDsFgGIBhtDrshlitmk2IrbHFqL2pvXf/+78DPokj7+Fz9qpU/9UXJIlhmPaTaQ6QPaz0mm+5gwkgovcV6GZzd5JtCQwgsxoHOvJO15kleRLAnMgHFIESUEPmawB9ngmelTtipwwfASilxOLyiV5UVUyVAfbG0cCPHig+GBkzAENHS0AstVF6bacZIOzgLmxsHbt2OecNgJC83JERmePUYq8ARGkJx6XtFsdddBQgZE2nPR6CICZhawjA4Fb/chv+399kfR+MMMDGOQAAAABJRU5ErkJggg==\");background-repeat: no-repeat;background-position: 2px center;}.ace_gutter-cell.ace_warning {background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAmVBMVEX///8AAAD///8AAAAAAABPSzb/5sAAAAB/blH/73z/ulkAAAAAAAD85pkAAAAAAAACAgP/vGz/rkDerGbGrV7/pkQICAf////e0IsAAAD/oED/qTvhrnUAAAD/yHD/njcAAADuv2r/nz//oTj/p064oGf/zHAAAAA9Nir/tFIAAAD/tlTiuWf/tkIAAACynXEAAAAAAAAtIRW7zBpBAAAAM3RSTlMAABR1m7RXO8Ln31Z36zT+neXe5OzooRDfn+TZ4p3h2hTf4t3k3ucyrN1K5+Xaks52Sfs9CXgrAAAAjklEQVR42o3PbQ+CIBQFYEwboPhSYgoYunIqqLn6/z8uYdH8Vmdnu9vz4WwXgN/xTPRD2+sgOcZjsge/whXZgUaYYvT8QnuJaUrjrHUQreGczuEafQCO/SJTufTbroWsPgsllVhq3wJEk2jUSzX3CUEDJC84707djRc5MTAQxoLgupWRwW6UB5fS++NV8AbOZgnsC7BpEAAAAABJRU5ErkJggg==\");background-position: 2px center;}.ace_gutter-cell.ace_info {background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAJ0Uk5TAAB2k804AAAAPklEQVQY02NgIB68QuO3tiLznjAwpKTgNyDbMegwisCHZUETUZV0ZqOquBpXj2rtnpSJT1AEnnRmL2OgGgAAIKkRQap2htgAAAAASUVORK5CYII=\");background-position: 2px center;}.ace_dark .ace_gutter-cell.ace_info {background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAChoaGAgIAqKiq+vr6tra1ZWVmUlJSbm5s8PDxubm56enrdgzg3AAAAAXRSTlMAQObYZgAAAClJREFUeNpjYMAPdsMYHegyJZFQBlsUlMFVCWUYKkAZMxZAGdxlDMQBAG+TBP4B6RyJAAAAAElFTkSuQmCC\");}.ace_scrollbar {position: absolute;right: 0;bottom: 0;z-index: 6;}.ace_scrollbar-inner {position: absolute;cursor: text;left: 0;top: 0;}.ace_scrollbar-v{overflow-x: hidden;overflow-y: scroll;top: 0;}.ace_scrollbar-h {overflow-x: scroll;overflow-y: hidden;left: 0;}.ace_print-margin {position: absolute;height: 100%;}.ace_text-input {position: absolute;z-index: 0;width: 0.5em;height: 1em;opacity: 0;background: transparent;-moz-appearance: none;appearance: none;border: none;resize: none;outline: none;overflow: hidden;font: inherit;padding: 0 1px;margin: 0 -1px;text-indent: -1em;-ms-user-select: text;-moz-user-select: text;-webkit-user-select: text;user-select: text;white-space: pre!important;}.ace_text-input.ace_composition {background: inherit;color: inherit;z-index: 1000;opacity: 1;text-indent: 0;}.ace_layer {z-index: 1;position: absolute;overflow: hidden;word-wrap: normal;white-space: pre;height: 100%;width: 100%;-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;pointer-events: none;}.ace_gutter-layer {position: relative;width: auto;text-align: right;pointer-events: auto;}.ace_text-layer {font: inherit !important;}.ace_cjk {display: inline-block;text-align: center;}.ace_cursor-layer {z-index: 4;}.ace_cursor {z-index: 4;position: absolute;-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;border-left: 2px solid;transform: translatez(0);}.ace_multiselect .ace_cursor {border-left-width: 1px;}.ace_slim-cursors .ace_cursor {border-left-width: 1px;}.ace_overwrite-cursors .ace_cursor {border-left-width: 0;border-bottom: 1px solid;}.ace_hidden-cursors .ace_cursor {opacity: 0.2;}.ace_smooth-blinking .ace_cursor {-webkit-transition: opacity 0.18s;transition: opacity 0.18s;}.ace_marker-layer .ace_step, .ace_marker-layer .ace_stack {position: absolute;z-index: 3;}.ace_marker-layer .ace_selection {position: absolute;z-index: 5;}.ace_marker-layer .ace_bracket {position: absolute;z-index: 6;}.ace_marker-layer .ace_active-line {position: absolute;z-index: 2;}.ace_marker-layer .ace_selected-word {position: absolute;z-index: 4;-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;}.ace_line .ace_fold {-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;display: inline-block;height: 11px;margin-top: -2px;vertical-align: middle;background-image:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII=\"),url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACJJREFUeNpi+P//fxgTAwPDBxDxD078RSX+YeEyDFMCIMAAI3INmXiwf2YAAAAASUVORK5CYII=\");background-repeat: no-repeat, repeat-x;background-position: center center, top left;color: transparent;border: 1px solid black;border-radius: 2px;cursor: pointer;pointer-events: auto;}.ace_dark .ace_fold {}.ace_fold:hover{background-image:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII=\"),url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACBJREFUeNpi+P//fz4TAwPDZxDxD5X4i5fLMEwJgAADAEPVDbjNw87ZAAAAAElFTkSuQmCC\");}.ace_tooltip {background-color: #FFF;background-image: -webkit-linear-gradient(top, transparent, rgba(0, 0, 0, 0.1));background-image: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.1));border: 1px solid gray;border-radius: 1px;box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);color: black;max-width: 100%;padding: 3px 4px;position: fixed;z-index: 999999;-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;cursor: default;white-space: pre;word-wrap: break-word;line-height: normal;font-style: normal;font-weight: normal;letter-spacing: normal;pointer-events: none;}.ace_folding-enabled > .ace_gutter-cell {padding-right: 13px;}.ace_fold-widget {-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;margin: 0 -12px 0 1px;display: none;width: 11px;vertical-align: top;background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42mWKsQ0AMAzC8ixLlrzQjzmBiEjp0A6WwBCSPgKAXoLkqSot7nN3yMwR7pZ32NzpKkVoDBUxKAAAAABJRU5ErkJggg==\");background-repeat: no-repeat;background-position: center;border-radius: 3px;border: 1px solid transparent;cursor: pointer;}.ace_folding-enabled .ace_fold-widget {display: inline-block;   }.ace_fold-widget.ace_end {background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42m3HwQkAMAhD0YzsRchFKI7sAikeWkrxwScEB0nh5e7KTPWimZki4tYfVbX+MNl4pyZXejUO1QAAAABJRU5ErkJggg==\");}.ace_fold-widget.ace_closed {background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAGCAYAAAAG5SQMAAAAOUlEQVR42jXKwQkAMAgDwKwqKD4EwQ26sSOkVWjgIIHAzPiCgaqiqnJHZnKICBERHN194O5b9vbLuAVRL+l0YWnZAAAAAElFTkSuQmCCXA==\");}.ace_fold-widget:hover {border: 1px solid rgba(0, 0, 0, 0.3);background-color: rgba(255, 255, 255, 0.2);box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7);}.ace_fold-widget:active {border: 1px solid rgba(0, 0, 0, 0.4);background-color: rgba(0, 0, 0, 0.05);box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);}.ace_dark .ace_fold-widget {background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHklEQVQIW2P4//8/AzoGEQ7oGCaLLAhWiSwB146BAQCSTPYocqT0AAAAAElFTkSuQmCC\");}.ace_dark .ace_fold-widget.ace_end {background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAH0lEQVQIW2P4//8/AxQ7wNjIAjDMgC4AxjCVKBirIAAF0kz2rlhxpAAAAABJRU5ErkJggg==\");}.ace_dark .ace_fold-widget.ace_closed {background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAHElEQVQIW2P4//+/AxAzgDADlOOAznHAKgPWAwARji8UIDTfQQAAAABJRU5ErkJggg==\");}.ace_dark .ace_fold-widget:hover {box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);background-color: rgba(255, 255, 255, 0.1);}.ace_dark .ace_fold-widget:active {box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);}.ace_fold-widget.ace_invalid {background-color: #FFB4B4;border-color: #DE5555;}.ace_fade-fold-widgets .ace_fold-widget {-webkit-transition: opacity 0.4s ease 0.05s;transition: opacity 0.4s ease 0.05s;opacity: 0;}.ace_fade-fold-widgets:hover .ace_fold-widget {-webkit-transition: opacity 0.05s ease 0.05s;transition: opacity 0.05s ease 0.05s;opacity:1;}.ace_underline {text-decoration: underline;}.ace_bold {font-weight: bold;}.ace_nobold .ace_bold {font-weight: normal;}.ace_italic {font-style: italic;}.ace_error-marker {background-color: rgba(255, 0, 0,0.2);position: absolute;z-index: 9;}.ace_highlight-marker {background-color: rgba(255, 255, 0,0.2);position: absolute;z-index: 8;}.ace_br1 {border-top-left-radius    : 3px;}.ace_br2 {border-top-right-radius   : 3px;}.ace_br3 {border-top-left-radius    : 3px; border-top-right-radius:    3px;}.ace_br4 {border-bottom-right-radius: 3px;}.ace_br5 {border-top-left-radius    : 3px; border-bottom-right-radius: 3px;}.ace_br6 {border-top-right-radius   : 3px; border-bottom-right-radius: 3px;}.ace_br7 {border-top-left-radius    : 3px; border-top-right-radius:    3px; border-bottom-right-radius: 3px;}.ace_br8 {border-bottom-left-radius : 3px;}.ace_br9 {border-top-left-radius    : 3px; border-bottom-left-radius:  3px;}.ace_br10{border-top-right-radius   : 3px; border-bottom-left-radius:  3px;}.ace_br11{border-top-left-radius    : 3px; border-top-right-radius:    3px; border-bottom-left-radius:  3px;}.ace_br12{border-bottom-right-radius: 3px; border-bottom-left-radius:  3px;}.ace_br13{border-top-left-radius    : 3px; border-bottom-right-radius: 3px; border-bottom-left-radius:  3px;}.ace_br14{border-top-right-radius   : 3px; border-bottom-right-radius: 3px; border-bottom-left-radius:  3px;}.ace_br15{border-top-left-radius    : 3px; border-top-right-radius:    3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_text-input-ios {position: absolute !important;top: -100000px !important;left: -100000px !important;}';i.importCssString(g,\"ace_editor.css\");var b=function(e,t){var n=this;this.container=e||i.createElement(\"div\"),this.$keepTextAreaAtCursor=!a.isOldIE,i.addCssClass(this.container,\"ace_editor\"),this.setTheme(t),this.$gutter=i.createElement(\"div\"),this.$gutter.className=\"ace_gutter\",this.container.appendChild(this.$gutter),this.$gutter.setAttribute(\"aria-hidden\",!0),this.scroller=i.createElement(\"div\"),this.scroller.className=\"ace_scroller\",this.container.appendChild(this.scroller),this.content=i.createElement(\"div\"),this.content.className=\"ace_content\",this.scroller.appendChild(this.content),this.$gutterLayer=new s(this.$gutter),this.$gutterLayer.on(\"changeGutterWidth\",this.onGutterResize.bind(this)),this.$markerBack=new l(this.content);var r=this.$textLayer=new c(this.content);this.canvas=r.element,this.$markerFront=new l(this.content),this.$cursorLayer=new u(this.content),this.$horizScroll=!1,this.$vScroll=!1,this.scrollBar=this.scrollBarV=new h(this.container,this),this.scrollBarH=new d(this.container,this),this.scrollBarV.addEventListener(\"scroll\",function(e){n.$scrollAnimation||n.session.setScrollTop(e.data-n.scrollMargin.top)}),this.scrollBarH.addEventListener(\"scroll\",function(e){n.$scrollAnimation||n.session.setScrollLeft(e.data-n.scrollMargin.left)}),this.scrollTop=0,this.scrollLeft=0,this.cursorPos={row:0,column:0},this.$fontMetrics=new m(this.container),this.$textLayer.$setFontMetrics(this.$fontMetrics),this.$textLayer.addEventListener(\"changeCharacterSize\",function(e){n.updateCharacterSize(),n.onResize(!0,n.gutterWidth,n.$size.width,n.$size.height),n._signal(\"changeCharacterSize\",e)}),this.$size={width:0,height:0,scrollerHeight:0,scrollerWidth:0,$dirty:!0},this.layerConfig={width:1,padding:0,firstRow:0,firstRowScreen:0,lastRow:0,lineHeight:0,characterWidth:0,minHeight:1,maxHeight:1,offset:0,height:1,gutterOffset:1},this.scrollMargin={left:0,right:0,top:0,bottom:0,v:0,h:0},this.$loop=new p(this.$renderChanges.bind(this),this.container.ownerDocument.defaultView),this.$loop.schedule(this.CHANGE_FULL),this.updateCharacterSize(),this.setPadding(4),o.resetOptions(this),o._emit(\"renderer\",this)};(function(){this.CHANGE_CURSOR=1,this.CHANGE_MARKER=2,this.CHANGE_GUTTER=4,this.CHANGE_SCROLL=8,this.CHANGE_LINES=16,this.CHANGE_TEXT=32,this.CHANGE_SIZE=64,this.CHANGE_MARKER_BACK=128,this.CHANGE_MARKER_FRONT=256,this.CHANGE_FULL=512,this.CHANGE_H_SCROLL=1024,r.implement(this,f),this.updateCharacterSize=function(){this.$textLayer.allowBoldFonts!=this.$allowBoldFonts&&(this.$allowBoldFonts=this.$textLayer.allowBoldFonts,this.setStyle(\"ace_nobold\",!this.$allowBoldFonts)),this.layerConfig.characterWidth=this.characterWidth=this.$textLayer.getCharacterWidth(),this.layerConfig.lineHeight=this.lineHeight=this.$textLayer.getLineHeight(),this.$updatePrintMargin()},this.setSession=function(e){this.session&&this.session.doc.off(\"changeNewLineMode\",this.onChangeNewLineMode),this.session=e,e&&this.scrollMargin.top&&e.getScrollTop()<=0&&e.setScrollTop(-this.scrollMargin.top),this.$cursorLayer.setSession(e),this.$markerBack.setSession(e),this.$markerFront.setSession(e),this.$gutterLayer.setSession(e),this.$textLayer.setSession(e),e&&(this.$loop.schedule(this.CHANGE_FULL),this.session.$setFontMetrics(this.$fontMetrics),this.scrollBarH.scrollLeft=this.scrollBarV.scrollTop=null,this.onChangeNewLineMode=this.onChangeNewLineMode.bind(this),this.onChangeNewLineMode(),this.session.doc.on(\"changeNewLineMode\",this.onChangeNewLineMode))},this.updateLines=function(e,t,n){if(void 0===t&&(t=1/0),this.$changedLines?(this.$changedLines.firstRow>e&&(this.$changedLines.firstRow=e),this.$changedLines.lastRow<t&&(this.$changedLines.lastRow=t)):this.$changedLines={firstRow:e,lastRow:t},this.$changedLines.lastRow<this.layerConfig.firstRow){if(!n)return;this.$changedLines.lastRow=this.layerConfig.lastRow}this.$changedLines.firstRow>this.layerConfig.lastRow||this.$loop.schedule(this.CHANGE_LINES)},this.onChangeNewLineMode=function(){this.$loop.schedule(this.CHANGE_TEXT),this.$textLayer.$updateEolChar(),this.session.$bidiHandler.setEolChar(this.$textLayer.EOL_CHAR)},this.onChangeTabSize=function(){this.$loop.schedule(this.CHANGE_TEXT|this.CHANGE_MARKER),this.$textLayer.onChangeTabSize()},this.updateText=function(){this.$loop.schedule(this.CHANGE_TEXT)},this.updateFull=function(e){e?this.$renderChanges(this.CHANGE_FULL,!0):this.$loop.schedule(this.CHANGE_FULL)},this.updateFontSize=function(){this.$textLayer.checkForSizeChanges()},this.$changes=0,this.$updateSizeAsync=function(){this.$loop.pending?this.$size.$dirty=!0:this.onResize()},this.onResize=function(e,t,n,r){if(!(this.resizing>2)){this.resizing>0?this.resizing++:this.resizing=e?1:0;var i=this.container;r||(r=i.clientHeight||i.scrollHeight),n||(n=i.clientWidth||i.scrollWidth);var o=this.$updateCachedSize(e,t,n,r);if(!this.$size.scrollerHeight||!n&&!r)return this.resizing=0;e&&(this.$gutterLayer.$padding=null),e?this.$renderChanges(o|this.$changes,!0):this.$loop.schedule(o|this.$changes),this.resizing&&(this.resizing=0),this.scrollBarV.scrollLeft=this.scrollBarV.scrollTop=null}},this.$updateCachedSize=function(e,t,n,r){r-=this.$extraHeight||0;var i=0,o=this.$size,a={width:o.width,height:o.height,scrollerHeight:o.scrollerHeight,scrollerWidth:o.scrollerWidth};return r&&(e||o.height!=r)&&(o.height=r,i|=this.CHANGE_SIZE,o.scrollerHeight=o.height,this.$horizScroll&&(o.scrollerHeight-=this.scrollBarH.getHeight()),this.scrollBarV.element.style.bottom=this.scrollBarH.getHeight()+\"px\",i|=this.CHANGE_SCROLL),n&&(e||o.width!=n)&&(i|=this.CHANGE_SIZE,o.width=n,null==t&&(t=this.$showGutter?this.$gutter.offsetWidth:0),this.gutterWidth=t,this.scrollBarH.element.style.left=this.scroller.style.left=t+\"px\",o.scrollerWidth=Math.max(0,n-t-this.scrollBarV.getWidth()),this.scrollBarH.element.style.right=this.scroller.style.right=this.scrollBarV.getWidth()+\"px\",this.scroller.style.bottom=this.scrollBarH.getHeight()+\"px\",(this.session&&this.session.getUseWrapMode()&&this.adjustWrapLimit()||e)&&(i|=this.CHANGE_FULL)),o.$dirty=!n||!r,i&&this._signal(\"resize\",a),i},this.onGutterResize=function(){var e=this.$showGutter?this.$gutter.offsetWidth:0;e!=this.gutterWidth&&(this.$changes|=this.$updateCachedSize(!0,e,this.$size.width,this.$size.height)),this.session.getUseWrapMode()&&this.adjustWrapLimit()?this.$loop.schedule(this.CHANGE_FULL):this.$size.$dirty?this.$loop.schedule(this.CHANGE_FULL):(this.$computeLayerConfig(),this.$loop.schedule(this.CHANGE_MARKER))},this.adjustWrapLimit=function(){var e=this.$size.scrollerWidth-2*this.$padding,t=Math.floor(e/this.characterWidth);return this.session.adjustWrapLimit(t,this.$showPrintMargin&&this.$printMarginColumn)},this.setAnimatedScroll=function(e){this.setOption(\"animatedScroll\",e)},this.getAnimatedScroll=function(){return this.$animatedScroll},this.setShowInvisibles=function(e){this.setOption(\"showInvisibles\",e),this.session.$bidiHandler.setShowInvisibles(e)},this.getShowInvisibles=function(){return this.getOption(\"showInvisibles\")},this.getDisplayIndentGuides=function(){return this.getOption(\"displayIndentGuides\")},this.setDisplayIndentGuides=function(e){this.setOption(\"displayIndentGuides\",e)},this.setShowPrintMargin=function(e){this.setOption(\"showPrintMargin\",e)},this.getShowPrintMargin=function(){return this.getOption(\"showPrintMargin\")},this.setPrintMarginColumn=function(e){this.setOption(\"printMarginColumn\",e)},this.getPrintMarginColumn=function(){return this.getOption(\"printMarginColumn\")},this.getShowGutter=function(){return this.getOption(\"showGutter\")},this.setShowGutter=function(e){return this.setOption(\"showGutter\",e)},this.getFadeFoldWidgets=function(){return this.getOption(\"fadeFoldWidgets\")},this.setFadeFoldWidgets=function(e){this.setOption(\"fadeFoldWidgets\",e)},this.setHighlightGutterLine=function(e){this.setOption(\"highlightGutterLine\",e)},this.getHighlightGutterLine=function(){return this.getOption(\"highlightGutterLine\")},this.$updateGutterLineHighlight=function(){var e=this.$cursorLayer.$pixelPos,t=this.layerConfig.lineHeight;if(this.session.getUseWrapMode()){var n=this.session.selection.getCursor();n.column=0,e=this.$cursorLayer.getPixelPosition(n,!0),t*=this.session.getRowLength(n.row)}this.$gutterLineHighlight.style.top=e.top-this.layerConfig.offset+\"px\",this.$gutterLineHighlight.style.height=t+\"px\"},this.$updatePrintMargin=function(){if(this.$showPrintMargin||this.$printMarginEl){if(!this.$printMarginEl){var e=i.createElement(\"div\");e.className=\"ace_layer ace_print-margin-layer\",this.$printMarginEl=i.createElement(\"div\"),this.$printMarginEl.className=\"ace_print-margin\",e.appendChild(this.$printMarginEl),this.content.insertBefore(e,this.content.firstChild)}var t=this.$printMarginEl.style;t.left=this.characterWidth*this.$printMarginColumn+this.$padding+\"px\",t.visibility=this.$showPrintMargin?\"visible\":\"hidden\",this.session&&-1==this.session.$wrap&&this.adjustWrapLimit()}},this.getContainerElement=function(){return this.container},this.getMouseEventTarget=function(){return this.scroller},this.getTextAreaContainer=function(){return this.container},this.$moveTextAreaToCursor=function(){if(this.$keepTextAreaAtCursor){var e=this.layerConfig,t=this.$cursorLayer.$pixelPos.top,n=this.$cursorLayer.$pixelPos.left;t-=e.offset;var r=this.textarea.style,i=this.lineHeight;if(t<0||t>e.height-i)r.top=r.left=\"0\";else{var o=this.characterWidth;if(this.$composition){var a=this.textarea.value.replace(/^\\x01+/,\"\");o*=this.session.$getStringScreenWidth(a)[0]+2,i+=2}n-=this.scrollLeft,n>this.$size.scrollerWidth-o&&(n=this.$size.scrollerWidth-o),n+=this.gutterWidth,r.height=i+\"px\",r.width=o+\"px\",r.left=Math.min(n,this.$size.scrollerWidth-o)+\"px\",r.top=Math.min(t,this.$size.height-i)+\"px\"}}},this.getFirstVisibleRow=function(){return this.layerConfig.firstRow},this.getFirstFullyVisibleRow=function(){return this.layerConfig.firstRow+(0===this.layerConfig.offset?0:1)},this.getLastFullyVisibleRow=function(){var e=this.layerConfig,t=e.lastRow,n=this.session.documentToScreenRow(t,0)*e.lineHeight;return n-this.session.getScrollTop()>e.height-e.lineHeight?t-1:t},this.getLastVisibleRow=function(){return this.layerConfig.lastRow},this.$padding=null,this.setPadding=function(e){this.$padding=e,this.$textLayer.setPadding(e),this.$cursorLayer.setPadding(e),this.$markerFront.setPadding(e),this.$markerBack.setPadding(e),this.$loop.schedule(this.CHANGE_FULL),this.$updatePrintMargin()},this.setScrollMargin=function(e,t,n,r){var i=this.scrollMargin;i.top=0|e,i.bottom=0|t,i.right=0|r,i.left=0|n,i.v=i.top+i.bottom,i.h=i.left+i.right,i.top&&this.scrollTop<=0&&this.session&&this.session.setScrollTop(-i.top),this.updateFull()},this.getHScrollBarAlwaysVisible=function(){return this.$hScrollBarAlwaysVisible},this.setHScrollBarAlwaysVisible=function(e){this.setOption(\"hScrollBarAlwaysVisible\",e)},this.getVScrollBarAlwaysVisible=function(){return this.$vScrollBarAlwaysVisible},this.setVScrollBarAlwaysVisible=function(e){this.setOption(\"vScrollBarAlwaysVisible\",e)},this.$updateScrollBarV=function(){var e=this.layerConfig.maxHeight,t=this.$size.scrollerHeight;!this.$maxLines&&this.$scrollPastEnd&&(e-=(t-this.lineHeight)*this.$scrollPastEnd,this.scrollTop>e-t&&(e=this.scrollTop+t,this.scrollBarV.scrollTop=null)),this.scrollBarV.setScrollHeight(e+this.scrollMargin.v),this.scrollBarV.setScrollTop(this.scrollTop+this.scrollMargin.top)},this.$updateScrollBarH=function(){this.scrollBarH.setScrollWidth(this.layerConfig.width+2*this.$padding+this.scrollMargin.h),this.scrollBarH.setScrollLeft(this.scrollLeft+this.scrollMargin.left)},this.$frozen=!1,this.freeze=function(){this.$frozen=!0},this.unfreeze=function(){this.$frozen=!1},this.$renderChanges=function(e,t){if(this.$changes&&(e|=this.$changes,this.$changes=0),this.session&&this.container.offsetWidth&&!this.$frozen&&(e||t)){if(this.$size.$dirty)return this.$changes|=e,this.onResize(!0);this.lineHeight||this.$textLayer.checkForSizeChanges(),this._signal(\"beforeRender\"),this.session&&this.session.$bidiHandler&&this.session.$bidiHandler.updateCharacterWidths(this.$fontMetrics);var n=this.layerConfig;if(e&this.CHANGE_FULL||e&this.CHANGE_SIZE||e&this.CHANGE_TEXT||e&this.CHANGE_LINES||e&this.CHANGE_SCROLL||e&this.CHANGE_H_SCROLL){if(e|=this.$computeLayerConfig(),n.firstRow!=this.layerConfig.firstRow&&n.firstRowScreen==this.layerConfig.firstRowScreen){var r=this.scrollTop+(n.firstRow-this.layerConfig.firstRow)*this.lineHeight;r>0&&(this.scrollTop=r,e|=this.CHANGE_SCROLL,e|=this.$computeLayerConfig())}n=this.layerConfig,this.$updateScrollBarV(),e&this.CHANGE_H_SCROLL&&this.$updateScrollBarH(),this.$gutterLayer.element.style.marginTop=-n.offset+\"px\",this.content.style.marginTop=-n.offset+\"px\",this.content.style.width=n.width+2*this.$padding+\"px\",this.content.style.height=n.minHeight+\"px\"}if(e&this.CHANGE_H_SCROLL&&(this.content.style.marginLeft=-this.scrollLeft+\"px\",this.scroller.className=this.scrollLeft<=0?\"ace_scroller\":\"ace_scroller ace_scroll-left\"),e&this.CHANGE_FULL)return this.$textLayer.update(n),this.$showGutter&&this.$gutterLayer.update(n),this.$markerBack.update(n),this.$markerFront.update(n),this.$cursorLayer.update(n),this.$moveTextAreaToCursor(),this.$highlightGutterLine&&this.$updateGutterLineHighlight(),void this._signal(\"afterRender\");if(e&this.CHANGE_SCROLL)return e&this.CHANGE_TEXT||e&this.CHANGE_LINES?this.$textLayer.update(n):this.$textLayer.scrollLines(n),this.$showGutter&&this.$gutterLayer.update(n),this.$markerBack.update(n),this.$markerFront.update(n),this.$cursorLayer.update(n),this.$highlightGutterLine&&this.$updateGutterLineHighlight(),this.$moveTextAreaToCursor(),void this._signal(\"afterRender\");e&this.CHANGE_TEXT?(this.$textLayer.update(n),this.$showGutter&&this.$gutterLayer.update(n)):e&this.CHANGE_LINES?(this.$updateLines()||e&this.CHANGE_GUTTER&&this.$showGutter)&&this.$gutterLayer.update(n):(e&this.CHANGE_TEXT||e&this.CHANGE_GUTTER)&&this.$showGutter&&this.$gutterLayer.update(n),e&this.CHANGE_CURSOR&&(this.$cursorLayer.update(n),this.$moveTextAreaToCursor(),this.$highlightGutterLine&&this.$updateGutterLineHighlight()),e&(this.CHANGE_MARKER|this.CHANGE_MARKER_FRONT)&&this.$markerFront.update(n),e&(this.CHANGE_MARKER|this.CHANGE_MARKER_BACK)&&this.$markerBack.update(n),this._signal(\"afterRender\")}else this.$changes|=e},this.$autosize=function(){var e=this.session.getScreenLength()*this.lineHeight,t=this.$maxLines*this.lineHeight,n=Math.min(t,Math.max((this.$minLines||1)*this.lineHeight,e))+this.scrollMargin.v+(this.$extraHeight||0);this.$horizScroll&&(n+=this.scrollBarH.getHeight()),this.$maxPixelHeight&&n>this.$maxPixelHeight&&(n=this.$maxPixelHeight);var r=e>t;if(n!=this.desiredHeight||this.$size.height!=this.desiredHeight||r!=this.$vScroll){r!=this.$vScroll&&(this.$vScroll=r,this.scrollBarV.setVisible(r));var i=this.container.clientWidth;this.container.style.height=n+\"px\",this.$updateCachedSize(!0,this.$gutterWidth,i,n),this.desiredHeight=n,this._signal(\"autosize\")}},this.$computeLayerConfig=function(){var e=this.session,t=this.$size,n=t.height<=2*this.lineHeight,r=this.session.getScreenLength(),i=r*this.lineHeight,o=this.$getLongestLine(),a=!n&&(this.$hScrollBarAlwaysVisible||t.scrollerWidth-o-2*this.$padding<0),s=this.$horizScroll!==a;s&&(this.$horizScroll=a,this.scrollBarH.setVisible(a));var l=this.$vScroll;this.$maxLines&&this.lineHeight>1&&this.$autosize();var c=this.scrollTop%this.lineHeight,u=t.scrollerHeight+this.lineHeight,d=!this.$maxLines&&this.$scrollPastEnd?(t.scrollerHeight-this.lineHeight)*this.$scrollPastEnd:0;i+=d;var h=this.scrollMargin;this.session.setScrollTop(Math.max(-h.top,Math.min(this.scrollTop,i-t.scrollerHeight+h.bottom))),this.session.setScrollLeft(Math.max(-h.left,Math.min(this.scrollLeft,o+2*this.$padding-t.scrollerWidth+h.right)));var p=!n&&(this.$vScrollBarAlwaysVisible||t.scrollerHeight-i+d<0||this.scrollTop>h.top),m=l!==p;m&&(this.$vScroll=p,this.scrollBarV.setVisible(p));var f,g,b=Math.ceil(u/this.lineHeight)-1,v=Math.max(0,Math.round((this.scrollTop-c)/this.lineHeight)),k=v+b,y=this.lineHeight;v=e.screenToDocumentRow(v,0);var w=e.getFoldLine(v);w&&(v=w.start.row),f=e.documentToScreenRow(v,0),g=e.getRowLength(v)*y,k=Math.min(e.screenToDocumentRow(k,0),e.getLength()-1),u=t.scrollerHeight+e.getRowLength(k)*y+g,c=this.scrollTop-f*y;var x=0;return this.layerConfig.width!=o&&(x=this.CHANGE_H_SCROLL),(s||m)&&(x=this.$updateCachedSize(!0,this.gutterWidth,t.width,t.height),this._signal(\"scrollbarVisibilityChanged\"),m&&(o=this.$getLongestLine())),this.layerConfig={width:o,padding:this.$padding,firstRow:v,firstRowScreen:f,lastRow:k,lineHeight:y,characterWidth:this.characterWidth,minHeight:u,maxHeight:i,offset:c,gutterOffset:y?Math.max(0,Math.ceil((c+t.height-t.scrollerHeight)/y)):0,height:this.$size.scrollerHeight},x},this.$updateLines=function(){if(this.$changedLines){var e=this.$changedLines.firstRow,t=this.$changedLines.lastRow;this.$changedLines=null;var n=this.layerConfig;if(!(e>n.lastRow+1)&&!(t<n.firstRow))return t===1/0?(this.$showGutter&&this.$gutterLayer.update(n),void this.$textLayer.update(n)):(this.$textLayer.updateLines(n,e,t),!0)}},this.$getLongestLine=function(){var e=this.session.getScreenWidth();return this.showInvisibles&&!this.session.$useWrapMode&&(e+=1),Math.max(this.$size.scrollerWidth-2*this.$padding,Math.round(e*this.characterWidth))},this.updateFrontMarkers=function(){this.$markerFront.setMarkers(this.session.getMarkers(!0)),this.$loop.schedule(this.CHANGE_MARKER_FRONT)},this.updateBackMarkers=function(){this.$markerBack.setMarkers(this.session.getMarkers()),this.$loop.schedule(this.CHANGE_MARKER_BACK)},this.addGutterDecoration=function(e,t){this.$gutterLayer.addGutterDecoration(e,t)},this.removeGutterDecoration=function(e,t){this.$gutterLayer.removeGutterDecoration(e,t)},this.updateBreakpoints=function(e){this.$loop.schedule(this.CHANGE_GUTTER)},this.setAnnotations=function(e){this.$gutterLayer.setAnnotations(e),this.$loop.schedule(this.CHANGE_GUTTER)},this.updateCursor=function(){this.$loop.schedule(this.CHANGE_CURSOR)},this.hideCursor=function(){this.$cursorLayer.hideCursor()},this.showCursor=function(){this.$cursorLayer.showCursor()},this.scrollSelectionIntoView=function(e,t,n){this.scrollCursorIntoView(e,n),this.scrollCursorIntoView(t,n)},this.scrollCursorIntoView=function(e,t,n){if(0!==this.$size.scrollerHeight){var r=this.$cursorLayer.getPixelPosition(e),i=r.left,o=r.top,a=n&&n.top||0,s=n&&n.bottom||0,l=this.$scrollAnimation?this.session.getScrollTop():this.scrollTop;l+a>o?(t&&l+a>o+this.lineHeight&&(o-=t*this.$size.scrollerHeight),0===o&&(o=-this.scrollMargin.top),this.session.setScrollTop(o)):l+this.$size.scrollerHeight-s<o+this.lineHeight&&(t&&l+this.$size.scrollerHeight-s<o-this.lineHeight&&(o+=t*this.$size.scrollerHeight),this.session.setScrollTop(o+this.lineHeight-this.$size.scrollerHeight));var c=this.scrollLeft;c>i?(i<this.$padding+2*this.layerConfig.characterWidth&&(i=-this.scrollMargin.left),this.session.setScrollLeft(i)):c+this.$size.scrollerWidth<i+this.characterWidth?this.session.setScrollLeft(Math.round(i+this.characterWidth-this.$size.scrollerWidth)):c<=this.$padding&&i-c<this.characterWidth&&this.session.setScrollLeft(0)}},this.getScrollTop=function(){return this.session.getScrollTop()},this.getScrollLeft=function(){return this.session.getScrollLeft()},this.getScrollTopRow=function(){return this.scrollTop/this.lineHeight},this.getScrollBottomRow=function(){return Math.max(0,Math.floor((this.scrollTop+this.$size.scrollerHeight)/this.lineHeight)-1)},this.scrollToRow=function(e){this.session.setScrollTop(e*this.lineHeight)},this.alignCursor=function(e,t){\"number\"==typeof e&&(e={row:e,column:0});var n=this.$cursorLayer.getPixelPosition(e),r=this.$size.scrollerHeight-this.lineHeight,i=n.top-r*(t||0);return this.session.setScrollTop(i),i},this.STEPS=8,this.$calcSteps=function(e,t){var n=0,r=this.STEPS,i=[],o=function(e,t,n){return n*(Math.pow(e-1,3)+1)+t};for(n=0;n<r;++n)i.push(o(n/this.STEPS,e,t-e));return i},this.scrollToLine=function(e,t,n,r){var i=this.$cursorLayer.getPixelPosition({row:e,column:0}),o=i.top;t&&(o-=this.$size.scrollerHeight/2);var a=this.scrollTop;this.session.setScrollTop(o),!1!==n&&this.animateScrolling(a,r)},this.animateScrolling=function(e,t){var n=this.scrollTop;if(this.$animatedScroll){var r=this;if(e!=n){if(this.$scrollAnimation){var i=this.$scrollAnimation.steps;if(i.length&&(e=i[0],e==n))return}var o=r.$calcSteps(e,n);this.$scrollAnimation={from:e,to:n,steps:o},clearInterval(this.$timer),r.session.setScrollTop(o.shift()),r.session.$scrollTop=n,this.$timer=setInterval(function(){o.length?(r.session.setScrollTop(o.shift()),r.session.$scrollTop=n):null!=n?(r.session.$scrollTop=-1,r.session.setScrollTop(n),n=null):(r.$timer=clearInterval(r.$timer),r.$scrollAnimation=null,t&&t())},10)}}},this.scrollToY=function(e){this.scrollTop!==e&&(this.$loop.schedule(this.CHANGE_SCROLL),this.scrollTop=e)},this.scrollToX=function(e){this.scrollLeft!==e&&(this.scrollLeft=e),this.$loop.schedule(this.CHANGE_H_SCROLL)},this.scrollTo=function(e,t){this.session.setScrollTop(t),this.session.setScrollLeft(t)},this.scrollBy=function(e,t){t&&this.session.setScrollTop(this.session.getScrollTop()+t),e&&this.session.setScrollLeft(this.session.getScrollLeft()+e)},this.isScrollableBy=function(e,t){return t<0&&this.session.getScrollTop()>=1-this.scrollMargin.top||(t>0&&this.session.getScrollTop()+this.$size.scrollerHeight-this.layerConfig.maxHeight<-1+this.scrollMargin.bottom||(e<0&&this.session.getScrollLeft()>=1-this.scrollMargin.left||(e>0&&this.session.getScrollLeft()+this.$size.scrollerWidth-this.layerConfig.width<-1+this.scrollMargin.right||void 0)))},this.pixelToScreenCoordinates=function(e,t){var n=this.scroller.getBoundingClientRect(),r=e+this.scrollLeft-n.left-this.$padding,i=r/this.characterWidth,o=Math.floor((t+this.scrollTop-n.top)/this.lineHeight),a=Math.round(i);return{row:o,column:a,side:i-a>0?1:-1,offsetX:r}},this.screenToTextCoordinates=function(e,t){var n=this.scroller.getBoundingClientRect(),r=e+this.scrollLeft-n.left-this.$padding,i=Math.round(r/this.characterWidth),o=(t+this.scrollTop-n.top)/this.lineHeight;return this.session.screenToDocumentPosition(o,Math.max(i,0),r)},this.textToScreenCoordinates=function(e,t){var n=this.scroller.getBoundingClientRect(),r=this.session.documentToScreenPosition(e,t),i=this.$padding+(this.session.$bidiHandler.isBidiRow(r.row,e)?this.session.$bidiHandler.getPosLeft(r.column):Math.round(r.column*this.characterWidth)),o=r.row*this.lineHeight;return{pageX:n.left+i-this.scrollLeft,pageY:n.top+o-this.scrollTop}},this.visualizeFocus=function(){i.addCssClass(this.container,\"ace_focus\")},this.visualizeBlur=function(){i.removeCssClass(this.container,\"ace_focus\")},this.showComposition=function(e){this.$composition||(this.$composition={keepTextAreaAtCursor:this.$keepTextAreaAtCursor,cssText:this.textarea.style.cssText}),this.$keepTextAreaAtCursor=!0,i.addCssClass(this.textarea,\"ace_composition\"),this.textarea.style.cssText=\"\",this.$moveTextAreaToCursor()},this.setCompositionText=function(e){this.$moveTextAreaToCursor()},this.hideComposition=function(){this.$composition&&(i.removeCssClass(this.textarea,\"ace_composition\"),this.$keepTextAreaAtCursor=this.$composition.keepTextAreaAtCursor,this.textarea.style.cssText=this.$composition.cssText,this.$composition=null)},this.setTheme=function(e,t){var n=this;if(this.$themeId=e,n._dispatchEvent(\"themeChange\",{theme:e}),e&&\"string\"!=typeof e)a(e);else{var r=e||this.$options.theme.initialValue;o.loadModule([\"theme\",r],a)}function a(r){if(n.$themeId!=e)return t&&t();if(!r||!r.cssClass)throw new Error(\"couldn't load module \"+e+\" or it didn't call define\");i.importCssString(r.cssText,r.cssClass,n.container.ownerDocument),n.theme&&i.removeCssClass(n.container,n.theme.cssClass);var o=\"padding\"in r?r.padding:\"padding\"in(n.theme||{})?4:n.$padding;n.$padding&&o!=n.$padding&&n.setPadding(o),n.$theme=r.cssClass,n.theme=r,i.addCssClass(n.container,r.cssClass),i.setCssClass(n.container,\"ace_dark\",r.isDark),n.$size&&(n.$size.width=0,n.$updateSizeAsync()),n._dispatchEvent(\"themeLoaded\",{theme:r}),t&&t()}},this.getTheme=function(){return this.$themeId},this.setStyle=function(e,t){i.setCssClass(this.container,e,!1!==t)},this.unsetStyle=function(e){i.removeCssClass(this.container,e)},this.setCursorStyle=function(e){this.scroller.style.cursor!=e&&(this.scroller.style.cursor=e)},this.setMouseCursor=function(e){this.scroller.style.cursor=e},this.destroy=function(){this.$textLayer.destroy(),this.$cursorLayer.destroy()}}).call(b.prototype),o.defineOptions(b.prototype,\"renderer\",{animatedScroll:{initialValue:!1},showInvisibles:{set:function(e){this.$textLayer.setShowInvisibles(e)&&this.$loop.schedule(this.CHANGE_TEXT)},initialValue:!1},showPrintMargin:{set:function(){this.$updatePrintMargin()},initialValue:!0},printMarginColumn:{set:function(){this.$updatePrintMargin()},initialValue:80},printMargin:{set:function(e){\"number\"==typeof e&&(this.$printMarginColumn=e),this.$showPrintMargin=!!e,this.$updatePrintMargin()},get:function(){return this.$showPrintMargin&&this.$printMarginColumn}},showGutter:{set:function(e){this.$gutter.style.display=e?\"block\":\"none\",this.$loop.schedule(this.CHANGE_FULL),this.onGutterResize()},initialValue:!0},fadeFoldWidgets:{set:function(e){i.setCssClass(this.$gutter,\"ace_fade-fold-widgets\",e)},initialValue:!1},showFoldWidgets:{set:function(e){this.$gutterLayer.setShowFoldWidgets(e)},initialValue:!0},showLineNumbers:{set:function(e){this.$gutterLayer.setShowLineNumbers(e),this.$loop.schedule(this.CHANGE_GUTTER)},initialValue:!0},displayIndentGuides:{set:function(e){this.$textLayer.setDisplayIndentGuides(e)&&this.$loop.schedule(this.CHANGE_TEXT)},initialValue:!0},highlightGutterLine:{set:function(e){if(!this.$gutterLineHighlight)return this.$gutterLineHighlight=i.createElement(\"div\"),this.$gutterLineHighlight.className=\"ace_gutter-active-line\",void this.$gutter.appendChild(this.$gutterLineHighlight);this.$gutterLineHighlight.style.display=e?\"\":\"none\",this.$cursorLayer.$pixelPos&&this.$updateGutterLineHighlight()},initialValue:!1,value:!0},hScrollBarAlwaysVisible:{set:function(e){this.$hScrollBarAlwaysVisible&&this.$horizScroll||this.$loop.schedule(this.CHANGE_SCROLL)},initialValue:!1},vScrollBarAlwaysVisible:{set:function(e){this.$vScrollBarAlwaysVisible&&this.$vScroll||this.$loop.schedule(this.CHANGE_SCROLL)},initialValue:!1},fontSize:{set:function(e){\"number\"==typeof e&&(e+=\"px\"),this.container.style.fontSize=e,this.updateFontSize()},initialValue:12},fontFamily:{set:function(e){this.container.style.fontFamily=e,this.updateFontSize()}},maxLines:{set:function(e){this.updateFull()}},minLines:{set:function(e){this.updateFull()}},maxPixelHeight:{set:function(e){this.updateFull()},initialValue:0},scrollPastEnd:{set:function(e){e=+e||0,this.$scrollPastEnd!=e&&(this.$scrollPastEnd=e,this.$loop.schedule(this.CHANGE_SCROLL))},initialValue:0,handlesSet:!0},fixedWidthGutter:{set:function(e){this.$gutterLayer.$fixedWidth=!!e,this.$loop.schedule(this.CHANGE_GUTTER)}},theme:{set:function(e){this.setTheme(e)},get:function(){return this.$themeId||this.theme},initialValue:\"./theme/textmate\",handlesSet:!0}}),t.VirtualRenderer=b}),ace.define(\"ace/worker/worker_client\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/lib/net\",\"ace/lib/event_emitter\",\"ace/config\"],function(e,t,n){\"use strict\";var r=e(\"../lib/oop\"),i=e(\"../lib/net\"),o=e(\"../lib/event_emitter\").EventEmitter,a=e(\"../config\");function s(e,t){var n=t.src;i.qualifyURL(e);try{return new Blob([n],{type:\"application/javascript\"})}catch(a){var r=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder,o=new r;return o.append(n),o.getBlob(\"application/javascript\")}}function l(e,t){var n=s(e,t),r=window.URL||window.webkitURL,i=r.createObjectURL(n);return new Worker(i)}var c=function(t,n,r,i,o){if(this.$sendDeltaQueue=this.$sendDeltaQueue.bind(this),this.changeListener=this.changeListener.bind(this),this.onMessage=this.onMessage.bind(this),e.nameToUrl&&!e.toUrl&&(e.toUrl=e.nameToUrl),a.get(\"packaged\")||!e.toUrl)i=i||a.moduleUrl(n.id,\"worker\");else{var s=this.$normalizePath;i=i||s(e.toUrl(\"ace/worker/worker.js\",null,\"_\"));var c={};t.forEach(function(t){c[t]=s(e.toUrl(t,null,\"_\").replace(/(\\.js)?(\\?.*)?$/,\"\"))})}this.$worker=l(i,n),o&&this.send(\"importScripts\",o),this.$worker.postMessage({init:!0,tlns:c,module:n.id,classname:r}),this.callbackId=1,this.callbacks={},this.$worker.onmessage=this.onMessage};(function(){r.implement(this,o),this.onMessage=function(e){var t=e.data;switch(t.type){case\"event\":this._signal(t.name,{data:t.data});break;case\"call\":var n=this.callbacks[t.id];n&&(n(t.data),delete this.callbacks[t.id]);break;case\"error\":this.reportError(t.data);break;case\"log\":window.console&&console.log&&console.log.apply(console,t.data);break}},this.reportError=function(e){window.console&&console.error&&console.error(e)},this.$normalizePath=function(e){return i.qualifyURL(e)},this.terminate=function(){this._signal(\"terminate\",{}),this.deltaQueue=null,this.$worker.terminate(),this.$worker=null,this.$doc&&this.$doc.off(\"change\",this.changeListener),this.$doc=null},this.send=function(e,t){this.$worker.postMessage({command:e,args:t})},this.call=function(e,t,n){if(n){var r=this.callbackId++;this.callbacks[r]=n,t.push(r)}this.send(e,t)},this.emit=function(e,t){try{this.$worker.postMessage({event:e,data:{data:t.data}})}catch(n){console.error(n.stack)}},this.attachToDocument=function(e){this.$doc&&this.terminate(),this.$doc=e,this.call(\"setValue\",[e.getValue()]),e.on(\"change\",this.changeListener)},this.changeListener=function(e){this.deltaQueue||(this.deltaQueue=[],setTimeout(this.$sendDeltaQueue,0)),\"insert\"==e.action?this.deltaQueue.push(e.start,e.lines):this.deltaQueue.push(e.start,e.end)},this.$sendDeltaQueue=function(){var e=this.deltaQueue;e&&(this.deltaQueue=null,e.length>50&&e.length>this.$doc.getLength()>>1?this.call(\"setValue\",[this.$doc.getValue()]):this.emit(\"change\",{data:e}))}}).call(c.prototype);var u=function(e,t,n){this.$sendDeltaQueue=this.$sendDeltaQueue.bind(this),this.changeListener=this.changeListener.bind(this),this.callbackId=1,this.callbacks={},this.messageBuffer=[];var r=null,i=!1,s=Object.create(o),l=this;this.$worker={},this.$worker.terminate=function(){},this.$worker.postMessage=function(e){l.messageBuffer.push(e),r&&(i?setTimeout(c):c())},this.setEmitSync=function(e){i=e};var c=function(){var e=l.messageBuffer.shift();e.command?r[e.command].apply(r,e.args):e.event&&s._signal(e.event,e.data)};s.postMessage=function(e){l.onMessage({data:e})},s.callback=function(e,t){this.postMessage({type:\"call\",id:t,data:e})},s.emit=function(e,t){this.postMessage({type:\"event\",name:e,data:t})},a.loadModule([\"worker\",t],function(e){r=new e[n](s);while(l.messageBuffer.length)c()})};u.prototype=c.prototype,t.UIWorkerClient=u,t.WorkerClient=c,t.createWorker=l}),ace.define(\"ace/placeholder\",[\"require\",\"exports\",\"module\",\"ace/range\",\"ace/lib/event_emitter\",\"ace/lib/oop\"],function(e,t,n){\"use strict\";var r=e(\"./range\").Range,i=e(\"./lib/event_emitter\").EventEmitter,o=e(\"./lib/oop\"),a=function(e,t,n,r,i,o){var a=this;this.length=t,this.session=e,this.doc=e.getDocument(),this.mainClass=i,this.othersClass=o,this.$onUpdate=this.onUpdate.bind(this),this.doc.on(\"change\",this.$onUpdate),this.$others=r,this.$onCursorChange=function(){setTimeout(function(){a.onCursorChange()})},this.$pos=n;var s=e.getUndoManager().$undoStack||e.getUndoManager().$undostack||{length:-1};this.$undoStackDepth=s.length,this.setup(),e.selection.on(\"changeCursor\",this.$onCursorChange)};(function(){o.implement(this,i),this.setup=function(){var e=this,t=this.doc,n=this.session;this.selectionBefore=n.selection.toJSON(),n.selection.inMultiSelectMode&&n.selection.toSingleRange(),this.pos=t.createAnchor(this.$pos.row,this.$pos.column);var i=this.pos;i.$insertRight=!0,i.detach(),i.markerId=n.addMarker(new r(i.row,i.column,i.row,i.column+this.length),this.mainClass,null,!1),this.others=[],this.$others.forEach(function(n){var r=t.createAnchor(n.row,n.column);r.$insertRight=!0,r.detach(),e.others.push(r)}),n.setUndoSelect(!1)},this.showOtherMarkers=function(){if(!this.othersActive){var e=this.session,t=this;this.othersActive=!0,this.others.forEach(function(n){n.markerId=e.addMarker(new r(n.row,n.column,n.row,n.column+t.length),t.othersClass,null,!1)})}},this.hideOtherMarkers=function(){if(this.othersActive){this.othersActive=!1;for(var e=0;e<this.others.length;e++)this.session.removeMarker(this.others[e].markerId)}},this.onUpdate=function(e){if(this.$updating)return this.updateAnchors(e);var t=e;if(t.start.row===t.end.row&&t.start.row===this.pos.row){this.$updating=!0;var n=\"insert\"===e.action?t.end.column-t.start.column:t.start.column-t.end.column,i=t.start.column>=this.pos.column&&t.start.column<=this.pos.column+this.length+1,o=t.start.column-this.pos.column;if(this.updateAnchors(e),i&&(this.length+=n),i&&!this.session.$fromUndo)if(\"insert\"===e.action)for(var a=this.others.length-1;a>=0;a--){var s=this.others[a],l={row:s.row,column:s.column+o};this.doc.insertMergedLines(l,e.lines)}else if(\"remove\"===e.action)for(a=this.others.length-1;a>=0;a--){s=this.others[a],l={row:s.row,column:s.column+o};this.doc.remove(new r(l.row,l.column,l.row,l.column-n))}this.$updating=!1,this.updateMarkers()}},this.updateAnchors=function(e){this.pos.onChange(e);for(var t=this.others.length;t--;)this.others[t].onChange(e);this.updateMarkers()},this.updateMarkers=function(){if(!this.$updating){var e=this,t=this.session,n=function(n,i){t.removeMarker(n.markerId),n.markerId=t.addMarker(new r(n.row,n.column,n.row,n.column+e.length),i,null,!1)};n(this.pos,this.mainClass);for(var i=this.others.length;i--;)n(this.others[i],this.othersClass)}},this.onCursorChange=function(e){if(!this.$updating&&this.session){var t=this.session.selection.getCursor();t.row===this.pos.row&&t.column>=this.pos.column&&t.column<=this.pos.column+this.length?(this.showOtherMarkers(),this._emit(\"cursorEnter\",e)):(this.hideOtherMarkers(),this._emit(\"cursorLeave\",e))}},this.detach=function(){this.session.removeMarker(this.pos&&this.pos.markerId),this.hideOtherMarkers(),this.doc.removeEventListener(\"change\",this.$onUpdate),this.session.selection.removeEventListener(\"changeCursor\",this.$onCursorChange),this.session.setUndoSelect(!0),this.session=null},this.cancel=function(){if(-1!==this.$undoStackDepth){for(var e=this.session.getUndoManager(),t=(e.$undoStack||e.$undostack).length-this.$undoStackDepth,n=0;n<t;n++)e.undo(!0);this.selectionBefore&&this.session.selection.fromJSON(this.selectionBefore)}}}).call(a.prototype),t.PlaceHolder=a}),ace.define(\"ace/mouse/multi_select_handler\",[\"require\",\"exports\",\"module\",\"ace/lib/event\",\"ace/lib/useragent\"],function(e,t,n){var r=e(\"../lib/event\"),i=e(\"../lib/useragent\");function o(e,t){return e.row==t.row&&e.column==t.column}function a(e){var t=e.domEvent,n=t.altKey,a=t.shiftKey,s=t.ctrlKey,l=e.getAccelKey(),c=e.getButton();if(s&&i.isMac&&(c=t.button),e.editor.inMultiSelectMode&&2==c)e.editor.textInput.onContextMenu(e.domEvent);else if(s||n||l){if(0===c){var u,d=e.editor,h=d.selection,p=d.inMultiSelectMode,m=e.getDocumentPosition(),f=h.getCursor(),g=e.inSelection()||h.isEmpty()&&o(m,f),b=e.x,v=e.y,k=function(e){b=e.clientX,v=e.clientY},y=d.session,w=d.renderer.pixelToScreenCoordinates(b,v),x=w;if(d.$mouseHandler.$enableJumpToDef)s&&n||l&&n?u=a?\"block\":\"add\":n&&d.$blockSelectEnabled&&(u=\"block\");else if(l&&!n){if(u=\"add\",!p&&a)return}else n&&d.$blockSelectEnabled&&(u=\"block\");if(u&&i.isMac&&t.ctrlKey&&d.$mouseHandler.cancelContextMenu(),\"add\"==u){if(!p&&g)return;if(!p){var E=h.toOrientedRange();d.addSelectionMarker(E)}var C=h.rangeList.rangeAtPoint(m);d.$blockScrolling++,d.inVirtualSelectionMode=!0,a&&(C=null,E=h.ranges[0]||E,d.removeSelectionMarker(E)),d.once(\"mouseup\",function(){var e=h.toOrientedRange();C&&e.isEmpty()&&o(C.cursor,e.cursor)?h.substractPoint(e.cursor):(a?h.substractPoint(E.cursor):E&&(d.removeSelectionMarker(E),h.addRange(E)),h.addRange(e)),d.$blockScrolling--,d.inVirtualSelectionMode=!1})}else if(\"block\"==u){var T;e.stop(),d.inVirtualSelectionMode=!0;var A=[],S=function(){var e=d.renderer.pixelToScreenCoordinates(b,v),t=y.screenToDocumentPosition(e.row,e.column,e.offsetX);o(x,e)&&o(t,h.lead)||(x=e,d.$blockScrolling++,d.selection.moveToPosition(t),d.renderer.scrollCursorIntoView(),d.removeSelectionMarkers(A),A=h.rectangularRangeBlock(x,w),d.$mouseHandler.$clickSelection&&1==A.length&&A[0].isEmpty()&&(A[0]=d.$mouseHandler.$clickSelection.clone()),A.forEach(d.addSelectionMarker,d),d.updateSelectionMarkers(),d.$blockScrolling--)};d.$blockScrolling++,p&&!l?h.toSingleRange():!p&&l&&(T=h.toOrientedRange(),d.addSelectionMarker(T)),a?w=y.documentToScreenPosition(h.lead):h.moveToPosition(m),d.$blockScrolling--,x={row:-1,column:-1};var _=function(e){clearInterval(L),d.removeSelectionMarkers(A),A.length||(A=[h.toOrientedRange()]),d.$blockScrolling++,T&&(d.removeSelectionMarker(T),h.toSingleRange(T));for(var t=0;t<A.length;t++)h.addRange(A[t]);d.inVirtualSelectionMode=!1,d.$mouseHandler.$clickSelection=null,d.$blockScrolling--},F=S;r.capture(d.container,k,_);var L=setInterval(function(){F()},20);return e.preventDefault()}}}else 0===c&&e.editor.inMultiSelectMode&&e.editor.exitMultiSelectMode()}t.onMouseDown=a}),ace.define(\"ace/commands/multi_select_commands\",[\"require\",\"exports\",\"module\",\"ace/keyboard/hash_handler\"],function(e,t,n){t.defaultCommands=[{name:\"addCursorAbove\",exec:function(e){e.selectMoreLines(-1)},bindKey:{win:\"Ctrl-Alt-Up\",mac:\"Ctrl-Alt-Up\"},scrollIntoView:\"cursor\",readOnly:!0},{name:\"addCursorBelow\",exec:function(e){e.selectMoreLines(1)},bindKey:{win:\"Ctrl-Alt-Down\",mac:\"Ctrl-Alt-Down\"},scrollIntoView:\"cursor\",readOnly:!0},{name:\"addCursorAboveSkipCurrent\",exec:function(e){e.selectMoreLines(-1,!0)},bindKey:{win:\"Ctrl-Alt-Shift-Up\",mac:\"Ctrl-Alt-Shift-Up\"},scrollIntoView:\"cursor\",readOnly:!0},{name:\"addCursorBelowSkipCurrent\",exec:function(e){e.selectMoreLines(1,!0)},bindKey:{win:\"Ctrl-Alt-Shift-Down\",mac:\"Ctrl-Alt-Shift-Down\"},scrollIntoView:\"cursor\",readOnly:!0},{name:\"selectMoreBefore\",exec:function(e){e.selectMore(-1)},bindKey:{win:\"Ctrl-Alt-Left\",mac:\"Ctrl-Alt-Left\"},scrollIntoView:\"cursor\",readOnly:!0},{name:\"selectMoreAfter\",exec:function(e){e.selectMore(1)},bindKey:{win:\"Ctrl-Alt-Right\",mac:\"Ctrl-Alt-Right\"},scrollIntoView:\"cursor\",readOnly:!0},{name:\"selectNextBefore\",exec:function(e){e.selectMore(-1,!0)},bindKey:{win:\"Ctrl-Alt-Shift-Left\",mac:\"Ctrl-Alt-Shift-Left\"},scrollIntoView:\"cursor\",readOnly:!0},{name:\"selectNextAfter\",exec:function(e){e.selectMore(1,!0)},bindKey:{win:\"Ctrl-Alt-Shift-Right\",mac:\"Ctrl-Alt-Shift-Right\"},scrollIntoView:\"cursor\",readOnly:!0},{name:\"splitIntoLines\",exec:function(e){e.multiSelect.splitIntoLines()},bindKey:{win:\"Ctrl-Alt-L\",mac:\"Ctrl-Alt-L\"},readOnly:!0},{name:\"alignCursors\",exec:function(e){e.alignCursors()},bindKey:{win:\"Ctrl-Alt-A\",mac:\"Ctrl-Alt-A\"},scrollIntoView:\"cursor\"},{name:\"findAll\",exec:function(e){e.findAll()},bindKey:{win:\"Ctrl-Alt-K\",mac:\"Ctrl-Alt-G\"},scrollIntoView:\"cursor\",readOnly:!0}],t.multiSelectCommands=[{name:\"singleSelection\",bindKey:\"esc\",exec:function(e){e.exitMultiSelectMode()},scrollIntoView:\"cursor\",readOnly:!0,isAvailable:function(e){return e&&e.inMultiSelectMode}}];var r=e(\"../keyboard/hash_handler\").HashHandler;t.keyboardHandler=new r(t.multiSelectCommands)}),ace.define(\"ace/multi_select\",[\"require\",\"exports\",\"module\",\"ace/range_list\",\"ace/range\",\"ace/selection\",\"ace/mouse/multi_select_handler\",\"ace/lib/event\",\"ace/lib/lang\",\"ace/commands/multi_select_commands\",\"ace/search\",\"ace/edit_session\",\"ace/editor\",\"ace/config\"],function(e,t,n){var r=e(\"./range_list\").RangeList,i=e(\"./range\").Range,o=e(\"./selection\").Selection,a=e(\"./mouse/multi_select_handler\").onMouseDown,s=e(\"./lib/event\"),l=e(\"./lib/lang\"),c=e(\"./commands/multi_select_commands\");t.commands=c.defaultCommands.concat(c.multiSelectCommands);var u=e(\"./search\").Search,d=new u;function h(e,t,n){return d.$options.wrap=!0,d.$options.needle=t,d.$options.backwards=-1==n,d.find(e)}var p=e(\"./edit_session\").EditSession;(function(){this.getSelectionMarkers=function(){return this.$selectionMarkers}}).call(p.prototype),function(){this.ranges=null,this.rangeList=null,this.addRange=function(e,t){if(e){if(!this.inMultiSelectMode&&0===this.rangeCount){var n=this.toOrientedRange();if(this.rangeList.add(n),this.rangeList.add(e),2!=this.rangeList.ranges.length)return this.rangeList.removeAll(),t||this.fromOrientedRange(e);this.rangeList.removeAll(),this.rangeList.add(n),this.$onAddRange(n)}e.cursor||(e.cursor=e.end);var r=this.rangeList.add(e);return this.$onAddRange(e),r.length&&this.$onRemoveRange(r),this.rangeCount>1&&!this.inMultiSelectMode&&(this._signal(\"multiSelect\"),this.inMultiSelectMode=!0,this.session.$undoSelect=!1,this.rangeList.attach(this.session)),t||this.fromOrientedRange(e)}},this.toSingleRange=function(e){e=e||this.ranges[0];var t=this.rangeList.removeAll();t.length&&this.$onRemoveRange(t),e&&this.fromOrientedRange(e)},this.substractPoint=function(e){var t=this.rangeList.substractPoint(e);if(t)return this.$onRemoveRange(t),t[0]},this.mergeOverlappingRanges=function(){var e=this.rangeList.merge();e.length?this.$onRemoveRange(e):this.ranges[0]&&this.fromOrientedRange(this.ranges[0])},this.$onAddRange=function(e){this.rangeCount=this.rangeList.ranges.length,this.ranges.unshift(e),this._signal(\"addRange\",{range:e})},this.$onRemoveRange=function(e){if(this.rangeCount=this.rangeList.ranges.length,1==this.rangeCount&&this.inMultiSelectMode){var t=this.rangeList.ranges.pop();e.push(t),this.rangeCount=0}for(var n=e.length;n--;){var r=this.ranges.indexOf(e[n]);this.ranges.splice(r,1)}this._signal(\"removeRange\",{ranges:e}),0===this.rangeCount&&this.inMultiSelectMode&&(this.inMultiSelectMode=!1,this._signal(\"singleSelect\"),this.session.$undoSelect=!0,this.rangeList.detach(this.session)),t=t||this.ranges[0],t&&!t.isEqual(this.getRange())&&this.fromOrientedRange(t)},this.$initRangeList=function(){this.rangeList||(this.rangeList=new r,this.ranges=[],this.rangeCount=0)},this.getAllRanges=function(){return this.rangeCount?this.rangeList.ranges.concat():[this.getRange()]},this.splitIntoLines=function(){if(this.rangeCount>1){var e=this.rangeList.ranges,t=e[e.length-1],n=i.fromPoints(e[0].start,t.end);this.toSingleRange(),this.setSelectionRange(n,t.cursor==t.start)}else{n=this.getRange();var r=this.isBackwards(),o=n.start.row,a=n.end.row;if(o==a){if(r)var s=n.end,l=n.start;else s=n.start,l=n.end;return this.addRange(i.fromPoints(l,l)),void this.addRange(i.fromPoints(s,s))}var c=[],u=this.getLineRange(o,!0);u.start.column=n.start.column,c.push(u);for(var d=o+1;d<a;d++)c.push(this.getLineRange(d,!0));u=this.getLineRange(a,!0),u.end.column=n.end.column,c.push(u),c.forEach(this.addRange,this)}},this.toggleBlockSelection=function(){if(this.rangeCount>1){var e=this.rangeList.ranges,t=e[e.length-1],n=i.fromPoints(e[0].start,t.end);this.toSingleRange(),this.setSelectionRange(n,t.cursor==t.start)}else{var r=this.session.documentToScreenPosition(this.selectionLead),o=this.session.documentToScreenPosition(this.selectionAnchor),a=this.rectangularRangeBlock(r,o);a.forEach(this.addRange,this)}},this.rectangularRangeBlock=function(e,t,n){var r=[],o=e.column<t.column;if(o)var a=e.column,s=t.column,l=e.offsetX,c=t.offsetX;else a=t.column,s=e.column,l=t.offsetX,c=e.offsetX;var u=e.row<t.row;if(u)var d=e.row,h=t.row;else d=t.row,h=e.row;a<0&&(a=0),d<0&&(d=0),d==h&&(n=!0);for(var p=d;p<=h;p++){var m=i.fromPoints(this.session.screenToDocumentPosition(p,a,l),this.session.screenToDocumentPosition(p,s,c));if(m.isEmpty()){if(g&&f(m.end,g))break;var g=m.end}m.cursor=o?m.start:m.end,r.push(m)}if(u&&r.reverse(),!n){var b=r.length-1;while(r[b].isEmpty()&&b>0)b--;if(b>0){var v=0;while(r[v].isEmpty())v++}for(var k=b;k>=v;k--)r[k].isEmpty()&&r.splice(k,1)}return r}}.call(o.prototype);var m=e(\"./editor\").Editor;function f(e,t){return e.row==t.row&&e.column==t.column}function g(e){e.$multiselectOnSessionChange||(e.$onAddRange=e.$onAddRange.bind(e),e.$onRemoveRange=e.$onRemoveRange.bind(e),e.$onMultiSelect=e.$onMultiSelect.bind(e),e.$onSingleSelect=e.$onSingleSelect.bind(e),e.$multiselectOnSessionChange=t.onSessionChange.bind(e),e.$checkMultiselectChange=e.$checkMultiselectChange.bind(e),e.$multiselectOnSessionChange(e),e.on(\"changeSession\",e.$multiselectOnSessionChange),e.on(\"mousedown\",a),e.commands.addCommands(c.defaultCommands),b(e))}function b(e){var t=e.textInput.getElement(),n=!1;function r(t){n&&(e.renderer.setMouseCursor(\"\"),n=!1)}s.addListener(t,\"keydown\",function(t){var i=18==t.keyCode&&!(t.ctrlKey||t.shiftKey||t.metaKey);e.$blockSelectEnabled&&i?n||(e.renderer.setMouseCursor(\"crosshair\"),n=!0):n&&r()}),s.addListener(t,\"keyup\",r),s.addListener(t,\"blur\",r)}(function(){this.updateSelectionMarkers=function(){this.renderer.updateCursor(),this.renderer.updateBackMarkers()},this.addSelectionMarker=function(e){e.cursor||(e.cursor=e.end);var t=this.getSelectionStyle();return e.marker=this.session.addMarker(e,\"ace_selection\",t),this.session.$selectionMarkers.push(e),this.session.selectionMarkerCount=this.session.$selectionMarkers.length,e},this.removeSelectionMarker=function(e){if(e.marker){this.session.removeMarker(e.marker);var t=this.session.$selectionMarkers.indexOf(e);-1!=t&&this.session.$selectionMarkers.splice(t,1),this.session.selectionMarkerCount=this.session.$selectionMarkers.length}},this.removeSelectionMarkers=function(e){for(var t=this.session.$selectionMarkers,n=e.length;n--;){var r=e[n];if(r.marker){this.session.removeMarker(r.marker);var i=t.indexOf(r);-1!=i&&t.splice(i,1)}}this.session.selectionMarkerCount=t.length},this.$onAddRange=function(e){this.addSelectionMarker(e.range),this.renderer.updateCursor(),this.renderer.updateBackMarkers()},this.$onRemoveRange=function(e){this.removeSelectionMarkers(e.ranges),this.renderer.updateCursor(),this.renderer.updateBackMarkers()},this.$onMultiSelect=function(e){this.inMultiSelectMode||(this.inMultiSelectMode=!0,this.setStyle(\"ace_multiselect\"),this.keyBinding.addKeyboardHandler(c.keyboardHandler),this.commands.setDefaultHandler(\"exec\",this.$onMultiSelectExec),this.renderer.updateCursor(),this.renderer.updateBackMarkers())},this.$onSingleSelect=function(e){this.session.multiSelect.inVirtualMode||(this.inMultiSelectMode=!1,this.unsetStyle(\"ace_multiselect\"),this.keyBinding.removeKeyboardHandler(c.keyboardHandler),this.commands.removeDefaultHandler(\"exec\",this.$onMultiSelectExec),this.renderer.updateCursor(),this.renderer.updateBackMarkers(),this._emit(\"changeSelection\"))},this.$onMultiSelectExec=function(e){var t=e.command,n=e.editor;if(n.multiSelect){if(t.multiSelectAction)\"forEach\"==t.multiSelectAction?r=n.forEachSelection(t,e.args):\"forEachLine\"==t.multiSelectAction?r=n.forEachSelection(t,e.args,!0):\"single\"==t.multiSelectAction?(n.exitMultiSelectMode(),r=t.exec(n,e.args||{})):r=t.multiSelectAction(n,e.args||{});else{var r=t.exec(n,e.args||{});n.multiSelect.addRange(n.multiSelect.toOrientedRange()),n.multiSelect.mergeOverlappingRanges()}return r}},this.forEachSelection=function(e,t,n){if(!this.inVirtualSelectionMode){var r,i=n&&n.keepOrder,a=1==n||n&&n.$byLines,s=this.session,l=this.selection,c=l.rangeList,u=(i?l:c).ranges;if(!u.length)return e.exec?e.exec(this,t||{}):e(this,t||{});var d=l._eventRegistry;l._eventRegistry={};var h=new o(s);this.inVirtualSelectionMode=!0;for(var p=u.length;p--;){if(a)while(p>0&&u[p].start.row==u[p-1].end.row)p--;h.fromOrientedRange(u[p]),h.index=p,this.selection=s.selection=h;var m=e.exec?e.exec(this,t||{}):e(this,t||{});r||void 0===m||(r=m),h.toOrientedRange(u[p])}h.detach(),this.selection=s.selection=l,this.inVirtualSelectionMode=!1,l._eventRegistry=d,l.mergeOverlappingRanges();var f=this.renderer.$scrollAnimation;return this.onCursorChange(),this.onSelectionChange(),f&&f.from==f.to&&this.renderer.animateScrolling(f.from),r}},this.exitMultiSelectMode=function(){this.inMultiSelectMode&&!this.inVirtualSelectionMode&&this.multiSelect.toSingleRange()},this.getSelectedText=function(){var e=\"\";if(this.inMultiSelectMode&&!this.inVirtualSelectionMode){for(var t=this.multiSelect.rangeList.ranges,n=[],r=0;r<t.length;r++)n.push(this.session.getTextRange(t[r]));var i=this.session.getDocument().getNewLineCharacter();e=n.join(i),e.length==(n.length-1)*i.length&&(e=\"\")}else this.selection.isEmpty()||(e=this.session.getTextRange(this.getSelectionRange()));return e},this.$checkMultiselectChange=function(e,t){if(this.inMultiSelectMode&&!this.inVirtualSelectionMode){var n=this.multiSelect.ranges[0];if(this.multiSelect.isEmpty()&&t==this.multiSelect.anchor)return;var r=t==this.multiSelect.anchor?n.cursor==n.start?n.end:n.start:n.cursor;r.row==t.row&&this.session.$clipPositionToDocument(r.row,r.column).column==t.column||this.multiSelect.toSingleRange(this.multiSelect.toOrientedRange())}},this.findAll=function(e,t,n){if(t=t||{},t.needle=e||t.needle,void 0==t.needle){var r=this.selection.isEmpty()?this.selection.getWordRange():this.selection.getRange();t.needle=this.session.getTextRange(r)}this.$search.set(t);var i=this.$search.findAll(this.session);if(!i.length)return 0;this.$blockScrolling+=1;var o=this.multiSelect;n||o.toSingleRange(i[0]);for(var a=i.length;a--;)o.addRange(i[a],!0);return r&&o.rangeList.rangeAtPoint(r.start)&&o.addRange(r,!0),this.$blockScrolling-=1,i.length},this.selectMoreLines=function(e,t){var n=this.selection.toOrientedRange(),r=n.cursor==n.end,o=this.session.documentToScreenPosition(n.cursor);this.selection.$desiredColumn&&(o.column=this.selection.$desiredColumn);var a=this.session.screenToDocumentPosition(o.row+e,o.column);if(n.isEmpty())l=a;else var s=this.session.documentToScreenPosition(r?n.end:n.start),l=this.session.screenToDocumentPosition(s.row+e,s.column);if(r){var c=i.fromPoints(a,l);c.cursor=c.start}else{c=i.fromPoints(l,a);c.cursor=c.end}if(c.desiredColumn=o.column,this.selection.inMultiSelectMode){if(t)var u=n.cursor}else this.selection.addRange(n);this.selection.addRange(c),u&&this.selection.substractPoint(u)},this.transposeSelections=function(e){for(var t=this.session,n=t.multiSelect,r=n.ranges,i=r.length;i--;){var o=r[i];if(o.isEmpty()){var a=t.getWordRange(o.start.row,o.start.column);o.start.row=a.start.row,o.start.column=a.start.column,o.end.row=a.end.row,o.end.column=a.end.column}}n.mergeOverlappingRanges();var s=[];for(i=r.length;i--;){o=r[i];s.unshift(t.getTextRange(o))}e<0?s.unshift(s.pop()):s.push(s.shift());for(i=r.length;i--;){o=r[i],a=o.clone();t.replace(o,s[i]),o.start.row=a.start.row,o.start.column=a.start.column}},this.selectMore=function(e,t,n){var r=this.session,i=r.multiSelect,o=i.toOrientedRange();if(!o.isEmpty()||(o=r.getWordRange(o.start.row,o.start.column),o.cursor=-1==e?o.start:o.end,this.multiSelect.addRange(o),!n)){var a=r.getTextRange(o),s=h(r,a,e);s&&(s.cursor=-1==e?s.start:s.end,this.$blockScrolling+=1,this.session.unfold(s),this.multiSelect.addRange(s),this.$blockScrolling-=1,this.renderer.scrollCursorIntoView(null,.5)),t&&this.multiSelect.substractPoint(o.cursor)}},this.alignCursors=function(){var e=this.session,t=e.multiSelect,n=t.ranges,r=-1,o=n.filter(function(e){if(e.cursor.row==r)return!0;r=e.cursor.row});if(n.length&&o.length!=n.length-1){o.forEach(function(e){t.substractPoint(e.cursor)});var a=0,s=1/0,c=n.map(function(t){var n=t.cursor,r=e.getLine(n.row),i=r.substr(n.column).search(/\\S/g);return-1==i&&(i=0),n.column>a&&(a=n.column),i<s&&(s=i),i});n.forEach(function(t,n){var r=t.cursor,o=a-r.column,u=c[n]-s;o>u?e.insert(r,l.stringRepeat(\" \",o-u)):e.remove(new i(r.row,r.column,r.row,r.column-o+u)),t.start.column=t.end.column=a,t.start.row=t.end.row=r.row,t.cursor=t.end}),t.fromOrientedRange(n[0]),this.renderer.updateCursor(),this.renderer.updateBackMarkers()}else{var u=this.selection.getRange(),d=u.start.row,h=u.end.row,p=d==h;if(p){var m,f=this.session.getLength();do{m=this.session.getLine(h)}while(/[=:]/.test(m)&&++h<f);do{m=this.session.getLine(d)}while(/[=:]/.test(m)&&--d>0);d<0&&(d=0),h>=f&&(h=f-1)}var g=this.session.removeFullLines(d,h);g=this.$reAlignText(g,p),this.session.insert({row:d,column:0},g.join(\"\\n\")+\"\\n\"),p||(u.start.column=0,u.end.column=g[g.length-1].length),this.selection.setRange(u)}},this.$reAlignText=function(e,t){var n,r,i,o=!0,a=!0;return e.map(function(e){var t=e.match(/(\\s*)(.*?)(\\s*)([=:].*)/);return t?null==n?(n=t[1].length,r=t[2].length,i=t[3].length,t):(n+r+i!=t[1].length+t[2].length+t[3].length&&(a=!1),n!=t[1].length&&(o=!1),n>t[1].length&&(n=t[1].length),r<t[2].length&&(r=t[2].length),i>t[3].length&&(i=t[3].length),t):[e]}).map(t?c:o?a?u:c:d);function s(e){return l.stringRepeat(\" \",e)}function c(e){return e[2]?s(n)+e[2]+s(r-e[2].length+i)+e[4].replace(/^([=:])\\s+/,\"$1 \"):e[0]}function u(e){return e[2]?s(n+r-e[2].length)+e[2]+s(i,\" \")+e[4].replace(/^([=:])\\s+/,\"$1 \"):e[0]}function d(e){return e[2]?s(n)+e[2]+s(i)+e[4].replace(/^([=:])\\s+/,\"$1 \"):e[0]}}}).call(m.prototype),t.onSessionChange=function(e){var t=e.session;t&&!t.multiSelect&&(t.$selectionMarkers=[],t.selection.$initRangeList(),t.multiSelect=t.selection),this.multiSelect=t&&t.multiSelect;var n=e.oldSession;n&&(n.multiSelect.off(\"addRange\",this.$onAddRange),n.multiSelect.off(\"removeRange\",this.$onRemoveRange),n.multiSelect.off(\"multiSelect\",this.$onMultiSelect),n.multiSelect.off(\"singleSelect\",this.$onSingleSelect),n.multiSelect.lead.off(\"change\",this.$checkMultiselectChange),n.multiSelect.anchor.off(\"change\",this.$checkMultiselectChange)),t&&(t.multiSelect.on(\"addRange\",this.$onAddRange),t.multiSelect.on(\"removeRange\",this.$onRemoveRange),t.multiSelect.on(\"multiSelect\",this.$onMultiSelect),t.multiSelect.on(\"singleSelect\",this.$onSingleSelect),t.multiSelect.lead.on(\"change\",this.$checkMultiselectChange),t.multiSelect.anchor.on(\"change\",this.$checkMultiselectChange)),t&&this.inMultiSelectMode!=t.selection.inMultiSelectMode&&(t.selection.inMultiSelectMode?this.$onMultiSelect():this.$onSingleSelect())},t.MultiSelect=g,e(\"./config\").defineOptions(m.prototype,\"editor\",{enableMultiselect:{set:function(e){g(this),e?(this.on(\"changeSession\",this.$multiselectOnSessionChange),this.on(\"mousedown\",a)):(this.off(\"changeSession\",this.$multiselectOnSessionChange),this.off(\"mousedown\",a))},value:!0},enableBlockSelect:{set:function(e){this.$blockSelectEnabled=e},value:!0}})}),ace.define(\"ace/mode/folding/fold_mode\",[\"require\",\"exports\",\"module\",\"ace/range\"],function(e,t,n){\"use strict\";var r=e(\"../../range\").Range,i=t.FoldMode=function(){};(function(){this.foldingStartMarker=null,this.foldingStopMarker=null,this.getFoldWidget=function(e,t,n){var r=e.getLine(n);return this.foldingStartMarker.test(r)?\"start\":\"markbeginend\"==t&&this.foldingStopMarker&&this.foldingStopMarker.test(r)?\"end\":\"\"},this.getFoldWidgetRange=function(e,t,n){return null},this.indentationBlock=function(e,t,n){var i=/\\S/,o=e.getLine(t),a=o.search(i);if(-1!=a){var s=n||o.length,l=e.getLength(),c=t,u=t;while(++t<l){var d=e.getLine(t).search(i);if(-1!=d){if(d<=a)break;u=t}}if(u>c){var h=e.getLine(u).length;return new r(c,s,u,h)}}},this.openingBracketBlock=function(e,t,n,i,o){var a={row:n,column:i+1},s=e.$findClosingBracket(t,a,o);if(s){var l=e.foldWidgets[s.row];return null==l&&(l=e.getFoldWidget(s.row)),\"start\"==l&&s.row>a.row&&(s.row--,s.column=e.getLine(s.row).length),r.fromPoints(a,s)}},this.closingBracketBlock=function(e,t,n,i,o){var a={row:n,column:i},s=e.$findOpeningBracket(t,a);if(s)return s.column++,a.column--,r.fromPoints(s,a)}}).call(i.prototype)}),ace.define(\"ace/theme/textmate\",[\"require\",\"exports\",\"module\",\"ace/lib/dom\"],function(e,t,n){\"use strict\";t.isDark=!1,t.cssClass=\"ace-tm\",t.cssText='.ace-tm .ace_gutter {background: #f0f0f0;color: #333;}.ace-tm .ace_print-margin {width: 1px;background: #e8e8e8;}.ace-tm .ace_fold {background-color: #6B72E6;}.ace-tm {background-color: #FFFFFF;color: black;}.ace-tm .ace_cursor {color: black;}.ace-tm .ace_invisible {color: rgb(191, 191, 191);}.ace-tm .ace_storage,.ace-tm .ace_keyword {color: blue;}.ace-tm .ace_constant {color: rgb(197, 6, 11);}.ace-tm .ace_constant.ace_buildin {color: rgb(88, 72, 246);}.ace-tm .ace_constant.ace_language {color: rgb(88, 92, 246);}.ace-tm .ace_constant.ace_library {color: rgb(6, 150, 14);}.ace-tm .ace_invalid {background-color: rgba(255, 0, 0, 0.1);color: red;}.ace-tm .ace_support.ace_function {color: rgb(60, 76, 114);}.ace-tm .ace_support.ace_constant {color: rgb(6, 150, 14);}.ace-tm .ace_support.ace_type,.ace-tm .ace_support.ace_class {color: rgb(109, 121, 222);}.ace-tm .ace_keyword.ace_operator {color: rgb(104, 118, 135);}.ace-tm .ace_string {color: rgb(3, 106, 7);}.ace-tm .ace_comment {color: rgb(76, 136, 107);}.ace-tm .ace_comment.ace_doc {color: rgb(0, 102, 255);}.ace-tm .ace_comment.ace_doc.ace_tag {color: rgb(128, 159, 191);}.ace-tm .ace_constant.ace_numeric {color: rgb(0, 0, 205);}.ace-tm .ace_variable {color: rgb(49, 132, 149);}.ace-tm .ace_xml-pe {color: rgb(104, 104, 91);}.ace-tm .ace_entity.ace_name.ace_function {color: #0000A2;}.ace-tm .ace_heading {color: rgb(12, 7, 255);}.ace-tm .ace_list {color:rgb(185, 6, 144);}.ace-tm .ace_meta.ace_tag {color:rgb(0, 22, 142);}.ace-tm .ace_string.ace_regex {color: rgb(255, 0, 0)}.ace-tm .ace_marker-layer .ace_selection {background: rgb(181, 213, 255);}.ace-tm.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px white;}.ace-tm .ace_marker-layer .ace_step {background: rgb(252, 255, 0);}.ace-tm .ace_marker-layer .ace_stack {background: rgb(164, 229, 101);}.ace-tm .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid rgb(192, 192, 192);}.ace-tm .ace_marker-layer .ace_active-line {background: rgba(0, 0, 0, 0.07);}.ace-tm .ace_gutter-active-line {background-color : #dcdcdc;}.ace-tm .ace_marker-layer .ace_selected-word {background: rgb(250, 250, 255);border: 1px solid rgb(200, 200, 250);}.ace-tm .ace_indent-guide {background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==\") right repeat-y;}';var r=e(\"../lib/dom\");r.importCssString(t.cssText,t.cssClass)}),ace.define(\"ace/line_widgets\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/lib/dom\",\"ace/range\"],function(e,t,n){\"use strict\";e(\"./lib/oop\");var r=e(\"./lib/dom\");e(\"./range\").Range;function i(e){this.session=e,this.session.widgetManager=this,this.session.getRowLength=this.getRowLength,this.session.$getWidgetScreenLength=this.$getWidgetScreenLength,this.updateOnChange=this.updateOnChange.bind(this),this.renderWidgets=this.renderWidgets.bind(this),this.measureWidgets=this.measureWidgets.bind(this),this.session._changedWidgets=[],this.$onChangeEditor=this.$onChangeEditor.bind(this),this.session.on(\"change\",this.updateOnChange),this.session.on(\"changeFold\",this.updateOnFold),this.session.on(\"changeEditor\",this.$onChangeEditor)}(function(){this.getRowLength=function(e){var t;return t=this.lineWidgets&&this.lineWidgets[e]&&this.lineWidgets[e].rowCount||0,this.$useWrapMode&&this.$wrapData[e]?this.$wrapData[e].length+1+t:1+t},this.$getWidgetScreenLength=function(){var e=0;return this.lineWidgets.forEach(function(t){t&&t.rowCount&&!t.hidden&&(e+=t.rowCount)}),e},this.$onChangeEditor=function(e){this.attach(e.editor)},this.attach=function(e){e&&e.widgetManager&&e.widgetManager!=this&&e.widgetManager.detach(),this.editor!=e&&(this.detach(),this.editor=e,e&&(e.widgetManager=this,e.renderer.on(\"beforeRender\",this.measureWidgets),e.renderer.on(\"afterRender\",this.renderWidgets)))},this.detach=function(e){var t=this.editor;if(t){this.editor=null,t.widgetManager=null,t.renderer.off(\"beforeRender\",this.measureWidgets),t.renderer.off(\"afterRender\",this.renderWidgets);var n=this.session.lineWidgets;n&&n.forEach(function(e){e&&e.el&&e.el.parentNode&&(e._inDocument=!1,e.el.parentNode.removeChild(e.el))})}},this.updateOnFold=function(e,t){var n=t.lineWidgets;if(n&&e.action){for(var r=e.data,i=r.start.row,o=r.end.row,a=\"add\"==e.action,s=i+1;s<o;s++)n[s]&&(n[s].hidden=a);n[o]&&(a?n[i]?n[o].hidden=a:n[i]=n[o]:(n[i]==n[o]&&(n[i]=void 0),n[o].hidden=a))}},this.updateOnChange=function(e){var t=this.session.lineWidgets;if(t){var n=e.start.row,r=e.end.row-n;if(0===r);else if(\"remove\"==e.action){var i=t.splice(n+1,r);i.forEach(function(e){e&&this.removeLineWidget(e)},this),this.$updateRows()}else{var o=new Array(r);o.unshift(n,0),t.splice.apply(t,o),this.$updateRows()}}},this.$updateRows=function(){var e=this.session.lineWidgets;if(e){var t=!0;e.forEach(function(e,n){if(e){t=!1,e.row=n;while(e.$oldWidget)e.$oldWidget.row=n,e=e.$oldWidget}}),t&&(this.session.lineWidgets=null)}},this.addLineWidget=function(e){this.session.lineWidgets||(this.session.lineWidgets=new Array(this.session.getLength()));var t=this.session.lineWidgets[e.row];t&&(e.$oldWidget=t,t.el&&t.el.parentNode&&(t.el.parentNode.removeChild(t.el),t._inDocument=!1)),this.session.lineWidgets[e.row]=e,e.session=this.session;var n=this.editor.renderer;e.html&&!e.el&&(e.el=r.createElement(\"div\"),e.el.innerHTML=e.html),e.el&&(r.addCssClass(e.el,\"ace_lineWidgetContainer\"),e.el.style.position=\"absolute\",e.el.style.zIndex=5,n.container.appendChild(e.el),e._inDocument=!0),e.coverGutter||(e.el.style.zIndex=3),null==e.pixelHeight&&(e.pixelHeight=e.el.offsetHeight),null==e.rowCount&&(e.rowCount=e.pixelHeight/n.layerConfig.lineHeight);var i=this.session.getFoldAt(e.row,0);if(e.$fold=i,i){var o=this.session.lineWidgets;e.row!=i.end.row||o[i.start.row]?e.hidden=!0:o[i.start.row]=e}return this.session._emit(\"changeFold\",{data:{start:{row:e.row}}}),this.$updateRows(),this.renderWidgets(null,n),this.onWidgetChanged(e),e},this.removeLineWidget=function(e){if(e._inDocument=!1,e.session=null,e.el&&e.el.parentNode&&e.el.parentNode.removeChild(e.el),e.editor&&e.editor.destroy)try{e.editor.destroy()}catch(n){}if(this.session.lineWidgets){var t=this.session.lineWidgets[e.row];if(t==e)this.session.lineWidgets[e.row]=e.$oldWidget,e.$oldWidget&&this.onWidgetChanged(e.$oldWidget);else while(t){if(t.$oldWidget==e){t.$oldWidget=e.$oldWidget;break}t=t.$oldWidget}}this.session._emit(\"changeFold\",{data:{start:{row:e.row}}}),this.$updateRows()},this.getWidgetsAtRow=function(e){var t=this.session.lineWidgets,n=t&&t[e],r=[];while(n)r.push(n),n=n.$oldWidget;return r},this.onWidgetChanged=function(e){this.session._changedWidgets.push(e),this.editor&&this.editor.renderer.updateFull()},this.measureWidgets=function(e,t){var n=this.session._changedWidgets,r=t.layerConfig;if(n&&n.length){for(var i=1/0,o=0;o<n.length;o++){var a=n[o];if(a&&a.el&&a.session==this.session){if(!a._inDocument){if(this.session.lineWidgets[a.row]!=a)continue;a._inDocument=!0,t.container.appendChild(a.el)}a.h=a.el.offsetHeight,a.fixedWidth||(a.w=a.el.offsetWidth,a.screenWidth=Math.ceil(a.w/r.characterWidth));var s=a.h/r.lineHeight;a.coverLine&&(s-=this.session.getRowLineCount(a.row),s<0&&(s=0)),a.rowCount!=s&&(a.rowCount=s,a.row<i&&(i=a.row))}}i!=1/0&&(this.session._emit(\"changeFold\",{data:{start:{row:i}}}),this.session.lineWidgetWidth=null),this.session._changedWidgets=[]}},this.renderWidgets=function(e,t){var n=t.layerConfig,r=this.session.lineWidgets;if(r){var i=Math.min(this.firstRow,n.firstRow),o=Math.max(this.lastRow,n.lastRow,r.length);while(i>0&&!r[i])i--;this.firstRow=n.firstRow,this.lastRow=n.lastRow,t.$cursorLayer.config=n;for(var a=i;a<=o;a++){var s=r[a];if(s&&s.el)if(s.hidden)s.el.style.top=-100-(s.pixelHeight||0)+\"px\";else{s._inDocument||(s._inDocument=!0,t.container.appendChild(s.el));var l=t.$cursorLayer.getPixelPosition({row:a,column:0},!0).top;s.coverLine||(l+=n.lineHeight*this.session.getRowLineCount(s.row)),s.el.style.top=l-n.offset+\"px\";var c=s.coverGutter?0:t.gutterWidth;s.fixedWidth||(c-=t.scrollLeft),s.el.style.left=c+\"px\",s.fullWidth&&s.screenWidth&&(s.el.style.minWidth=n.width+2*n.padding+\"px\"),s.fixedWidth?s.el.style.right=t.scrollBar.getWidth()+\"px\":s.el.style.right=\"\"}}}}}).call(i.prototype),t.LineWidgets=i}),ace.define(\"ace/ext/error_marker\",[\"require\",\"exports\",\"module\",\"ace/line_widgets\",\"ace/lib/dom\",\"ace/range\"],function(e,t,n){\"use strict\";var r=e(\"../line_widgets\").LineWidgets,i=e(\"../lib/dom\"),o=e(\"../range\").Range;function a(e,t,n){var r=0,i=e.length-1;while(r<=i){var o=r+i>>1,a=n(t,e[o]);if(a>0)r=o+1;else{if(!(a<0))return o;i=o-1}}return-(r+1)}function s(e,t,n){var r=e.getAnnotations().sort(o.comparePoints);if(r.length){var i=a(r,{row:t,column:-1},o.comparePoints);i<0&&(i=-i-1),i>=r.length?i=n>0?0:r.length-1:0===i&&n<0&&(i=r.length-1);var s=r[i];if(s&&n){if(s.row===t){do{s=r[i+=n]}while(s&&s.row===t);if(!s)return r.slice()}var l=[];t=s.row;do{l[n<0?\"unshift\":\"push\"](s),s=r[i+=n]}while(s&&s.row==t);return l.length&&l}}}t.showErrorMarker=function(e,t){var n=e.session;n.widgetManager||(n.widgetManager=new r(n),n.widgetManager.attach(e));var o=e.getCursorPosition(),a=o.row,l=n.widgetManager.getWidgetsAtRow(a).filter(function(e){return\"errorMarker\"==e.type})[0];l?l.destroy():a-=t;var c,u=s(n,a,t);if(u){var d=u[0];o.column=(d.pos&&\"number\"!=typeof d.column?d.pos.sc:d.column)||0,o.row=d.row,c=e.renderer.$gutterLayer.$annotations[o.row]}else{if(l)return;c={text:[\"Looks good!\"],className:\"ace_ok\"}}e.session.unfold(o.row),e.selection.moveToPosition(o);var h={row:o.row,fixedWidth:!0,coverGutter:!0,el:i.createElement(\"div\"),type:\"errorMarker\"},p=h.el.appendChild(i.createElement(\"div\")),m=h.el.appendChild(i.createElement(\"div\"));m.className=\"error_widget_arrow \"+c.className;var f=e.renderer.$cursorLayer.getPixelPosition(o).left;m.style.left=f+e.renderer.gutterWidth-5+\"px\",h.el.className=\"error_widget_wrapper\",p.className=\"error_widget \"+c.className,p.innerHTML=c.text.join(\"<br>\"),p.appendChild(i.createElement(\"div\"));var g=function(e,t,n){if(0===t&&(\"esc\"===n||\"return\"===n))return h.destroy(),{command:\"null\"}};h.destroy=function(){e.$mouseHandler.isMousePressed||(e.keyBinding.removeKeyboardHandler(g),n.widgetManager.removeLineWidget(h),e.off(\"changeSelection\",h.destroy),e.off(\"changeSession\",h.destroy),e.off(\"mouseup\",h.destroy),e.off(\"change\",h.destroy))},e.keyBinding.addKeyboardHandler(g),e.on(\"changeSelection\",h.destroy),e.on(\"changeSession\",h.destroy),e.on(\"mouseup\",h.destroy),e.on(\"change\",h.destroy),e.session.widgetManager.addLineWidget(h),h.el.onmousedown=e.focus.bind(e),e.renderer.scrollCursorIntoView(null,.5,{bottom:h.el.offsetHeight})},i.importCssString(\"    .error_widget_wrapper {        background: inherit;        color: inherit;        border:none    }    .error_widget {        border-top: solid 2px;        border-bottom: solid 2px;        margin: 5px 0;        padding: 10px 40px;        white-space: pre-wrap;    }    .error_widget.ace_error, .error_widget_arrow.ace_error{        border-color: #ff5a5a    }    .error_widget.ace_warning, .error_widget_arrow.ace_warning{        border-color: #F1D817    }    .error_widget.ace_info, .error_widget_arrow.ace_info{        border-color: #5a5a5a    }    .error_widget.ace_ok, .error_widget_arrow.ace_ok{        border-color: #5aaa5a    }    .error_widget_arrow {        position: absolute;        border: solid 5px;        border-top-color: transparent!important;        border-right-color: transparent!important;        border-left-color: transparent!important;        top: -5px;    }\",\"\")}),ace.define(\"ace/ace\",[\"require\",\"exports\",\"module\",\"ace/lib/fixoldbrowsers\",\"ace/lib/dom\",\"ace/lib/event\",\"ace/editor\",\"ace/edit_session\",\"ace/undomanager\",\"ace/virtual_renderer\",\"ace/worker/worker_client\",\"ace/keyboard/hash_handler\",\"ace/placeholder\",\"ace/multi_select\",\"ace/mode/folding/fold_mode\",\"ace/theme/textmate\",\"ace/ext/error_marker\",\"ace/config\"],function(e,t,r){\"use strict\";e(\"./lib/fixoldbrowsers\");var i=e(\"./lib/dom\"),o=e(\"./lib/event\"),a=e(\"./editor\").Editor,s=e(\"./edit_session\").EditSession,l=e(\"./undomanager\").UndoManager,c=e(\"./virtual_renderer\").VirtualRenderer;e(\"./worker/worker_client\"),e(\"./keyboard/hash_handler\"),e(\"./placeholder\"),e(\"./multi_select\"),e(\"./mode/folding/fold_mode\"),e(\"./theme/textmate\"),e(\"./ext/error_marker\"),t.config=e(\"./config\"),t.acequire=e,t.define=n(\"07d6\"),t.edit=function(e){if(\"string\"==typeof e){var n=e;if(e=document.getElementById(n),!e)throw new Error(\"ace.edit can't find div #\"+n)}if(e&&e.env&&e.env.editor instanceof a)return e.env.editor;var r=\"\";if(e&&/input|textarea/i.test(e.tagName)){var s=e;r=s.value,e=i.createElement(\"pre\"),s.parentNode.replaceChild(e,s)}else e&&(r=i.getInnerText(e),e.innerHTML=\"\");var l=t.createEditSession(r),u=new a(new c(e));u.setSession(l);var d={document:l,editor:u,onResize:u.resize.bind(u,null)};return s&&(d.textarea=s),o.addListener(window,\"resize\",d.onResize),u.on(\"destroy\",function(){o.removeListener(window,\"resize\",d.onResize),d.editor.container.env=null}),u.container.env=u.env=d,u},t.createEditSession=function(e,t){var n=new s(e,t);return n.setUndoManager(new l),n},t.EditSession=s,t.UndoManager=l,t.version=\"1.2.9\"}),function(){ace.acequire([\"ace/ace\"],function(e){for(var t in e&&(e.config.init(!0),e.define=ace.define),window.ace||(window.ace=e),e)e.hasOwnProperty(t)&&(window.ace[t]=e[t])})}(),e.exports=window.ace.acequire(\"ace/ace\")},\"07d6\":function(e,t){e.exports=function(){throw new Error(\"define cannot be used indirect\")}},2099:function(e,t){ace.define(\"ace/snippets\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/lib/event_emitter\",\"ace/lib/lang\",\"ace/range\",\"ace/anchor\",\"ace/keyboard/hash_handler\",\"ace/tokenizer\",\"ace/lib/dom\",\"ace/editor\"],function(e,t,n){\"use strict\";var r=e(\"./lib/oop\"),i=e(\"./lib/event_emitter\").EventEmitter,o=e(\"./lib/lang\"),a=e(\"./range\").Range,s=e(\"./anchor\").Anchor,l=e(\"./keyboard/hash_handler\").HashHandler,c=e(\"./tokenizer\").Tokenizer,u=a.comparePoints,d=function(){this.snippetMap={},this.snippetNameMap={}};(function(){r.implement(this,i),this.getTokenizer=function(){function e(e,t,n){return e=e.substr(1),/^\\d+$/.test(e)&&!n.inFormatString?[{tabstopId:parseInt(e,10)}]:[{text:e}]}function t(e){return\"(?:[^\\\\\\\\\"+e+\"]|\\\\\\\\.)\"}return d.$tokenizer=new c({start:[{regex:/:/,onMatch:function(e,t,n){return n.length&&n[0].expectIf?(n[0].expectIf=!1,n[0].elseBranch=n[0],[n[0]]):\":\"}},{regex:/\\\\./,onMatch:function(e,t,n){var r=e[1];return\"}\"==r&&n.length?e=r:-1!=\"`$\\\\\".indexOf(r)?e=r:n.inFormatString&&(\"n\"==r?e=\"\\n\":\"t\"==r?e=\"\\n\":-1!=\"ulULE\".indexOf(r)&&(e={changeCase:r,local:r>\"a\"})),[e]}},{regex:/}/,onMatch:function(e,t,n){return[n.length?n.shift():e]}},{regex:/\\$(?:\\d+|\\w+)/,onMatch:e},{regex:/\\$\\{[\\dA-Z_a-z]+/,onMatch:function(t,n,r){var i=e(t.substr(1),n,r);return r.unshift(i[0]),i},next:\"snippetVar\"},{regex:/\\n/,token:\"newline\",merge:!1}],snippetVar:[{regex:\"\\\\|\"+t(\"\\\\|\")+\"*\\\\|\",onMatch:function(e,t,n){n[0].choices=e.slice(1,-1).split(\",\")},next:\"start\"},{regex:\"/(\"+t(\"/\")+\"+)/(?:(\"+t(\"/\")+\"*)/)(\\\\w*):?\",onMatch:function(e,t,n){var r=n[0];return r.fmtString=e,e=this.splitRegex.exec(e),r.guard=e[1],r.fmt=e[2],r.flag=e[3],\"\"},next:\"start\"},{regex:\"`\"+t(\"`\")+\"*`\",onMatch:function(e,t,n){return n[0].code=e.splice(1,-1),\"\"},next:\"start\"},{regex:\"\\\\?\",onMatch:function(e,t,n){n[0]&&(n[0].expectIf=!0)},next:\"start\"},{regex:\"([^:}\\\\\\\\]|\\\\\\\\.)*:?\",token:\"\",next:\"start\"}],formatString:[{regex:\"/(\"+t(\"/\")+\"+)/\",token:\"regex\"},{regex:\"\",onMatch:function(e,t,n){n.inFormatString=!0},next:\"start\"}]}),d.prototype.getTokenizer=function(){return d.$tokenizer},d.$tokenizer},this.tokenizeTmSnippet=function(e,t){return this.getTokenizer().getLineTokens(e,t).tokens.map(function(e){return e.value||e})},this.$getDefaultValue=function(e,t){if(/^[A-Z]\\d+$/.test(t)){var n=t.substr(1);return(this.variables[t[0]+\"__\"]||{})[n]}if(/^\\d+$/.test(t))return(this.variables.__||{})[t];if(t=t.replace(/^TM_/,\"\"),e){var r=e.session;switch(t){case\"CURRENT_WORD\":var i=r.getWordRange();case\"SELECTION\":case\"SELECTED_TEXT\":return r.getTextRange(i);case\"CURRENT_LINE\":return r.getLine(e.getCursorPosition().row);case\"PREV_LINE\":return r.getLine(e.getCursorPosition().row-1);case\"LINE_INDEX\":return e.getCursorPosition().column;case\"LINE_NUMBER\":return e.getCursorPosition().row+1;case\"SOFT_TABS\":return r.getUseSoftTabs()?\"YES\":\"NO\";case\"TAB_SIZE\":return r.getTabSize();case\"FILENAME\":case\"FILEPATH\":return\"\";case\"FULLNAME\":return\"Ace\"}}},this.variables={},this.getVariableValue=function(e,t){return this.variables.hasOwnProperty(t)?this.variables[t](e,t)||\"\":this.$getDefaultValue(e,t)||\"\"},this.tmStrFormat=function(e,t,n){var r=t.flag||\"\",i=t.guard;i=new RegExp(i,r.replace(/[^gi]/,\"\"));var o=this.tokenizeTmSnippet(t.fmt,\"formatString\"),a=this,s=e.replace(i,function(){a.variables.__=arguments;for(var e=a.resolveVariables(o,n),t=\"E\",r=0;r<e.length;r++){var i=e[r];if(\"object\"==typeof i)if(e[r]=\"\",i.changeCase&&i.local){var s=e[r+1];s&&\"string\"==typeof s&&(\"u\"==i.changeCase?e[r]=s[0].toUpperCase():e[r]=s[0].toLowerCase(),e[r+1]=s.substr(1))}else i.changeCase&&(t=i.changeCase);else\"U\"==t?e[r]=i.toUpperCase():\"L\"==t&&(e[r]=i.toLowerCase())}return e.join(\"\")});return this.variables.__=null,s},this.resolveVariables=function(e,t){for(var n=[],r=0;r<e.length;r++){var i=e[r];if(\"string\"==typeof i)n.push(i);else{if(\"object\"!=typeof i)continue;if(i.skip)a(i);else{if(i.processed<r)continue;if(i.text){var o=this.getVariableValue(t,i.text);o&&i.fmtString&&(o=this.tmStrFormat(o,i)),i.processed=r,null==i.expectIf?o&&(n.push(o),a(i)):o?i.skip=i.elseBranch:a(i)}else null!=i.tabstopId?n.push(i):null!=i.changeCase&&n.push(i)}}}function a(t){var n=e.indexOf(t,r+1);-1!=n&&(r=n)}return n},this.insertSnippetForSelection=function(e,t){var n=e.getCursorPosition(),r=e.session.getLine(n.row),i=e.session.getTabString(),o=r.match(/^\\s*/)[0];n.column<o.length&&(o=o.slice(0,n.column)),t=t.replace(/\\r/g,\"\");var a=this.tokenizeTmSnippet(t);a=this.resolveVariables(a,e),a=a.map(function(e){return\"\\n\"==e?e+o:\"string\"==typeof e?e.replace(/\\t/g,i):e});var s=[];a.forEach(function(e,t){if(\"object\"==typeof e){var n=e.tabstopId,r=s[n];if(r||(r=s[n]=[],r.index=n,r.value=\"\"),-1===r.indexOf(e)){r.push(e);var i=a.indexOf(e,t+1);if(-1!==i){var o=a.slice(t+1,i),l=o.some(function(e){return\"object\"===typeof e});l&&!r.value?r.value=o:!o.length||r.value&&\"string\"===typeof r.value||(r.value=o.join(\"\"))}}}}),s.forEach(function(e){e.length=0});var l={};function c(e){for(var t=[],n=0;n<e.length;n++){var r=e[n];if(\"object\"==typeof r){if(l[r.tabstopId])continue;var i=e.lastIndexOf(r,n-1);r=t[i]||{tabstopId:r.tabstopId}}t[n]=r}return t}for(var u=0;u<a.length;u++){var d=a[u];if(\"object\"==typeof d){var p=d.tabstopId,m=a.indexOf(d,u+1);if(l[p])l[p]===d&&(l[p]=null);else{var f=s[p],g=\"string\"==typeof f.value?[f.value]:c(f.value);g.unshift(u+1,Math.max(0,m-u)),g.push(d),l[p]=d,a.splice.apply(a,g),-1===f.indexOf(d)&&f.push(d)}}}var b=0,v=0,k=\"\";a.forEach(function(e){if(\"string\"===typeof e){var t=e.split(\"\\n\");t.length>1?(v=t[t.length-1].length,b+=t.length-1):v+=e.length,k+=e}else e.start?e.end={row:b,column:v}:e.start={row:b,column:v}});var y=e.getSelectionRange(),w=e.session.replace(y,k),x=new h(e),E=e.inVirtualSelectionMode&&e.selection.index;x.addTabstops(s,y.start,w,E)},this.insertSnippet=function(e,t){var n=this;if(e.inVirtualSelectionMode)return n.insertSnippetForSelection(e,t);e.forEachSelection(function(){n.insertSnippetForSelection(e,t)},null,{keepOrder:!0}),e.tabstopManager&&e.tabstopManager.tabNext()},this.$getScope=function(e){var t=e.session.$mode.$id||\"\";if(t=t.split(\"/\").pop(),\"html\"===t||\"php\"===t){\"php\"!==t||e.session.$mode.inlinePhp||(t=\"html\");var n=e.getCursorPosition(),r=e.session.getState(n.row);\"object\"===typeof r&&(r=r[0]),r.substring&&(\"js-\"==r.substring(0,3)?t=\"javascript\":\"css-\"==r.substring(0,4)?t=\"css\":\"php-\"==r.substring(0,4)&&(t=\"php\"))}return t},this.getActiveScopes=function(e){var t=this.$getScope(e),n=[t],r=this.snippetMap;return r[t]&&r[t].includeScopes&&n.push.apply(n,r[t].includeScopes),n.push(\"_\"),n},this.expandWithTab=function(e,t){var n=this,r=e.forEachSelection(function(){return n.expandSnippetForSelection(e,t)},null,{keepOrder:!0});return r&&e.tabstopManager&&e.tabstopManager.tabNext(),r},this.expandSnippetForSelection=function(e,t){var n,r=e.getCursorPosition(),i=e.session.getLine(r.row),o=i.substring(0,r.column),a=i.substr(r.column),s=this.snippetMap;return this.getActiveScopes(e).some(function(e){var t=s[e];return t&&(n=this.findMatchingSnippet(t,o,a)),!!n},this),!!n&&(!(!t||!t.dryRun)||(e.session.doc.removeInLine(r.row,r.column-n.replaceBefore.length,r.column+n.replaceAfter.length),this.variables.M__=n.matchBefore,this.variables.T__=n.matchAfter,this.insertSnippetForSelection(e,n.content),this.variables.M__=this.variables.T__=null,!0))},this.findMatchingSnippet=function(e,t,n){for(var r=e.length;r--;){var i=e[r];if((!i.startRe||i.startRe.test(t))&&((!i.endRe||i.endRe.test(n))&&(i.startRe||i.endRe)))return i.matchBefore=i.startRe?i.startRe.exec(t):[\"\"],i.matchAfter=i.endRe?i.endRe.exec(n):[\"\"],i.replaceBefore=i.triggerRe?i.triggerRe.exec(t)[0]:\"\",i.replaceAfter=i.endTriggerRe?i.endTriggerRe.exec(n)[0]:\"\",i}},this.snippetMap={},this.snippetNameMap={},this.register=function(e,t){var n=this.snippetMap,r=this.snippetNameMap,i=this;function a(e){return e&&!/^\\^?\\(.*\\)\\$?$|^\\\\b$/.test(e)&&(e=\"(?:\"+e+\")\"),e||\"\"}function s(e,t,n){return e=a(e),t=a(t),n?(e=t+e,e&&\"$\"!=e[e.length-1]&&(e+=\"$\")):(e+=t,e&&\"^\"!=e[0]&&(e=\"^\"+e)),new RegExp(e)}function l(e){e.scope||(e.scope=t||\"_\"),t=e.scope,n[t]||(n[t]=[],r[t]={});var a=r[t];if(e.name){var l=a[e.name];l&&i.unregister(l),a[e.name]=e}n[t].push(e),e.tabTrigger&&!e.trigger&&(!e.guard&&/^\\w/.test(e.tabTrigger)&&(e.guard=\"\\\\b\"),e.trigger=o.escapeRegExp(e.tabTrigger)),(e.trigger||e.guard||e.endTrigger||e.endGuard)&&(e.startRe=s(e.trigger,e.guard,!0),e.triggerRe=new RegExp(e.trigger,\"\",!0),e.endRe=s(e.endTrigger,e.endGuard,!0),e.endTriggerRe=new RegExp(e.endTrigger,\"\",!0))}e||(e=[]),e&&e.content?l(e):Array.isArray(e)&&e.forEach(l),this._signal(\"registerSnippets\",{scope:t})},this.unregister=function(e,t){var n=this.snippetMap,r=this.snippetNameMap;function i(e){var i=r[e.scope||t];if(i&&i[e.name]){delete i[e.name];var o=n[e.scope||t],a=o&&o.indexOf(e);a>=0&&o.splice(a,1)}}e.content?i(e):Array.isArray(e)&&e.forEach(i)},this.parseSnippetFile=function(e){e=e.replace(/\\r/g,\"\");var t,n=[],r={},i=/^#.*|^({[\\s\\S]*})\\s*$|^(\\S+) (.*)$|^((?:\\n*\\t.*)+)/gm;while(t=i.exec(e)){if(t[1])try{r=JSON.parse(t[1]),n.push(r)}catch(l){}if(t[4])r.content=t[4].replace(/^\\t/gm,\"\"),n.push(r),r={};else{var o=t[2],a=t[3];if(\"regex\"==o){var s=/\\/((?:[^\\/\\\\]|\\\\.)*)|$/g;r.guard=s.exec(a)[1],r.trigger=s.exec(a)[1],r.endTrigger=s.exec(a)[1],r.endGuard=s.exec(a)[1]}else\"snippet\"==o?(r.tabTrigger=a.match(/^\\S*/)[0],r.name||(r.name=a)):r[o]=a}}return n},this.getSnippetByName=function(e,t){var n,r=this.snippetNameMap;return this.getActiveScopes(t).some(function(t){var i=r[t];return i&&(n=i[e]),!!n},this),n}}).call(d.prototype);var h=function(e){if(e.tabstopManager)return e.tabstopManager;e.tabstopManager=this,this.$onChange=this.onChange.bind(this),this.$onChangeSelection=o.delayedCall(this.onChangeSelection.bind(this)).schedule,this.$onChangeSession=this.onChangeSession.bind(this),this.$onAfterExec=this.onAfterExec.bind(this),this.attach(e)};(function(){this.attach=function(e){this.index=0,this.ranges=[],this.tabstops=[],this.$openTabstops=null,this.selectedTabstop=null,this.editor=e,this.editor.on(\"change\",this.$onChange),this.editor.on(\"changeSelection\",this.$onChangeSelection),this.editor.on(\"changeSession\",this.$onChangeSession),this.editor.commands.on(\"afterExec\",this.$onAfterExec),this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler)},this.detach=function(){this.tabstops.forEach(this.removeTabstopMarkers,this),this.ranges=null,this.tabstops=null,this.selectedTabstop=null,this.editor.removeListener(\"change\",this.$onChange),this.editor.removeListener(\"changeSelection\",this.$onChangeSelection),this.editor.removeListener(\"changeSession\",this.$onChangeSession),this.editor.commands.removeListener(\"afterExec\",this.$onAfterExec),this.editor.keyBinding.removeKeyboardHandler(this.keyboardHandler),this.editor.tabstopManager=null,this.editor=null},this.onChange=function(e){var t=\"r\"==e.action[0],n=e.start,r=e.end,i=n.row,o=r.row,a=o-i,s=r.column-n.column;if(t&&(a=-a,s=-s),!this.$inChange&&t){var l=this.selectedTabstop,c=l&&!l.some(function(e){return u(e.start,n)<=0&&u(e.end,r)>=0});if(c)return this.detach()}for(var d=this.ranges,h=0;h<d.length;h++){var p=d[h];p.end.row<n.row||(t&&u(n,p.start)<0&&u(r,p.end)>0?(this.removeRange(p),h--):(p.start.row==i&&p.start.column>n.column&&(p.start.column+=s),p.end.row==i&&p.end.column>=n.column&&(p.end.column+=s),p.start.row>=i&&(p.start.row+=a),p.end.row>=i&&(p.end.row+=a),u(p.start,p.end)>0&&this.removeRange(p)))}d.length||this.detach()},this.updateLinkedFields=function(){var e=this.selectedTabstop;if(e&&e.hasLinkedRanges){this.$inChange=!0;for(var n=this.editor.session,r=n.getTextRange(e.firstNonLinked),i=e.length;i--;){var o=e[i];if(o.linked){var a=t.snippetManager.tmStrFormat(r,o.original);n.replace(o,a)}}this.$inChange=!1}},this.onAfterExec=function(e){e.command&&!e.command.readOnly&&this.updateLinkedFields()},this.onChangeSelection=function(){if(this.editor){for(var e=this.editor.selection.lead,t=this.editor.selection.anchor,n=this.editor.selection.isEmpty(),r=this.ranges.length;r--;)if(!this.ranges[r].linked){var i=this.ranges[r].contains(e.row,e.column),o=n||this.ranges[r].contains(t.row,t.column);if(i&&o)return}this.detach()}},this.onChangeSession=function(){this.detach()},this.tabNext=function(e){var t=this.tabstops.length,n=this.index+(e||1);n=Math.min(Math.max(n,1),t),n==t&&(n=0),this.selectTabstop(n),0===n&&this.detach()},this.selectTabstop=function(e){this.$openTabstops=null;var t=this.tabstops[this.index];if(t&&this.addTabstopMarkers(t),this.index=e,t=this.tabstops[this.index],t&&t.length){if(this.selectedTabstop=t,this.editor.inVirtualSelectionMode)this.editor.selection.setRange(t.firstNonLinked);else{var n=this.editor.multiSelect;n.toSingleRange(t.firstNonLinked.clone());for(var r=t.length;r--;)t.hasLinkedRanges&&t[r].linked||n.addRange(t[r].clone(),!0);n.ranges[0]&&n.addRange(n.ranges[0].clone())}this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler)}},this.addTabstops=function(e,t,n){if(this.$openTabstops||(this.$openTabstops=[]),!e[0]){var r=a.fromPoints(n,n);f(r.start,t),f(r.end,t),e[0]=[r],e[0].index=0}var i=this.index,o=[i+1,0],s=this.ranges;e.forEach(function(e,n){for(var r=this.$openTabstops[n]||e,i=e.length;i--;){var l=e[i],c=a.fromPoints(l.start,l.end||l.start);m(c.start,t),m(c.end,t),c.original=l,c.tabstop=r,s.push(c),r!=e?r.unshift(c):r[i]=c,l.fmtString?(c.linked=!0,r.hasLinkedRanges=!0):r.firstNonLinked||(r.firstNonLinked=c)}r.firstNonLinked||(r.hasLinkedRanges=!1),r===e&&(o.push(r),this.$openTabstops[n]=r),this.addTabstopMarkers(r)},this),o.length>2&&(this.tabstops.length&&o.push(o.splice(2,1)[0]),this.tabstops.splice.apply(this.tabstops,o))},this.addTabstopMarkers=function(e){var t=this.editor.session;e.forEach(function(e){e.markerId||(e.markerId=t.addMarker(e,\"ace_snippet-marker\",\"text\"))})},this.removeTabstopMarkers=function(e){var t=this.editor.session;e.forEach(function(e){t.removeMarker(e.markerId),e.markerId=null})},this.removeRange=function(e){var t=e.tabstop.indexOf(e);e.tabstop.splice(t,1),t=this.ranges.indexOf(e),this.ranges.splice(t,1),this.editor.session.removeMarker(e.markerId),e.tabstop.length||(t=this.tabstops.indexOf(e.tabstop),-1!=t&&this.tabstops.splice(t,1),this.tabstops.length||this.detach())},this.keyboardHandler=new l,this.keyboardHandler.bindKeys({Tab:function(e){t.snippetManager&&t.snippetManager.expandWithTab(e)||e.tabstopManager.tabNext(1)},\"Shift-Tab\":function(e){e.tabstopManager.tabNext(-1)},Esc:function(e){e.tabstopManager.detach()},Return:function(e){return!1}})}).call(h.prototype);var p={};p.onChange=s.prototype.onChange,p.setPosition=function(e,t){this.pos.row=e,this.pos.column=t},p.update=function(e,t,n){this.$insertRight=n,this.pos=e,this.onChange(t)};var m=function(e,t){0==e.row&&(e.column+=t.column),e.row+=t.row},f=function(e,t){e.row==t.row&&(e.column-=t.column),e.row-=t.row};e(\"./lib/dom\").importCssString(\".ace_snippet-marker {    -moz-box-sizing: border-box;    box-sizing: border-box;    background: rgba(194, 193, 208, 0.09);    border: 1px dotted rgba(211, 208, 235, 0.62);    position: absolute;}\"),t.snippetManager=new d;var g=e(\"./editor\").Editor;(function(){this.insertSnippet=function(e,n){return t.snippetManager.insertSnippet(this,e,n)},this.expandSnippet=function(e){return t.snippetManager.expandWithTab(this,e)}}).call(g.prototype)}),ace.define(\"ace/autocomplete/popup\",[\"require\",\"exports\",\"module\",\"ace/virtual_renderer\",\"ace/editor\",\"ace/range\",\"ace/lib/event\",\"ace/lib/lang\",\"ace/lib/dom\"],function(e,t,n){\"use strict\";var r=e(\"../virtual_renderer\").VirtualRenderer,i=e(\"../editor\").Editor,o=e(\"../range\").Range,a=e(\"../lib/event\"),s=e(\"../lib/lang\"),l=e(\"../lib/dom\"),c=function(e){var t=new r(e);t.$maxLines=4;var n=new i(t);return n.setHighlightActiveLine(!1),n.setShowPrintMargin(!1),n.renderer.setShowGutter(!1),n.renderer.setHighlightGutterLine(!1),n.$mouseHandler.$focusWaitTimout=0,n.$highlightTagPending=!0,n},u=function(e){var t=l.createElement(\"div\"),n=new c(t);e&&e.appendChild(t),t.style.display=\"none\",n.renderer.content.style.cursor=\"default\",n.renderer.setStyle(\"ace_autocomplete\"),n.setOption(\"displayIndentGuides\",!1),n.setOption(\"dragDelay\",150);var r,i=function(){};n.focus=i,n.$isFocused=!0,n.renderer.$cursorLayer.restartTimer=i,n.renderer.$cursorLayer.element.style.opacity=0,n.renderer.$maxLines=8,n.renderer.$keepTextAreaAtCursor=!1,n.setHighlightActiveLine(!1),n.session.highlight(\"\"),n.session.$searchHighlight.clazz=\"ace_highlight-marker\",n.on(\"mousedown\",function(e){var t=e.getDocumentPosition();n.selection.moveToPosition(t),d.start.row=d.end.row=t.row,e.stop()});var u=new o(-1,0,-1,1/0),d=new o(-1,0,-1,1/0);d.id=n.session.addMarker(d,\"ace_active-line\",\"fullLine\"),n.setSelectOnHover=function(e){e?u.id&&(n.session.removeMarker(u.id),u.id=null):u.id=n.session.addMarker(u,\"ace_line-hover\",\"fullLine\")},n.setSelectOnHover(!1),n.on(\"mousemove\",function(e){if(r){if(r.x!=e.x||r.y!=e.y){r=e,r.scrollTop=n.renderer.scrollTop;var t=r.getDocumentPosition().row;u.start.row!=t&&(u.id||n.setRow(t),p(t))}}else r=e}),n.renderer.on(\"beforeRender\",function(){if(r&&-1!=u.start.row){r.$pos=null;var e=r.getDocumentPosition().row;u.id||n.setRow(e),p(e,!0)}}),n.renderer.on(\"afterRender\",function(){var e=n.getRow(),t=n.renderer.$textLayer,r=t.element.childNodes[e-t.config.firstRow];r!=t.selectedNode&&(t.selectedNode&&l.removeCssClass(t.selectedNode,\"ace_selected\"),t.selectedNode=r,r&&l.addCssClass(r,\"ace_selected\"))});var h=function(){p(-1)},p=function(e,t){e!==u.start.row&&(u.start.row=u.end.row=e,t||n.session._emit(\"changeBackMarker\"),n._emit(\"changeHoverMarker\"))};n.getHoveredRow=function(){return u.start.row},a.addListener(n.container,\"mouseout\",h),n.on(\"hide\",h),n.on(\"changeSelection\",h),n.session.doc.getLength=function(){return n.data.length},n.session.doc.getLine=function(e){var t=n.data[e];return\"string\"==typeof t?t:t&&t.value||\"\"};var m=n.session.bgTokenizer;return m.$tokenizeRow=function(e){var t=n.data[e],r=[];if(!t)return r;\"string\"==typeof t&&(t={value:t}),t.caption||(t.caption=t.value||t.name);for(var i,o,a=-1,s=0;s<t.caption.length;s++)o=t.caption[s],i=t.matchMask&1<<s?1:0,a!==i?(r.push({type:t.className||(i?\"completion-highlight\":\"\"),value:o}),a=i):r[r.length-1].value+=o;if(t.meta){var l=n.renderer.$size.scrollerWidth/n.renderer.layerConfig.characterWidth,c=t.meta;c.length+t.caption.length>l-2&&(c=c.substr(0,l-t.caption.length-3)+\"…\"),r.push({type:\"rightAlignedText\",value:c})}return r},m.$updateOnChange=i,m.start=i,n.session.$computeWidth=function(){return this.screenWidth=0},n.$blockScrolling=1/0,n.isOpen=!1,n.isTopdown=!1,n.autoSelect=!0,n.data=[],n.setData=function(e){n.setValue(s.stringRepeat(\"\\n\",e.length),-1),n.data=e||[],n.setRow(0)},n.getData=function(e){return n.data[e]},n.getRow=function(){return d.start.row},n.setRow=function(e){e=Math.max(this.autoSelect?0:-1,Math.min(this.data.length,e)),d.start.row!=e&&(n.selection.clearSelection(),d.start.row=d.end.row=e||0,n.session._emit(\"changeBackMarker\"),n.moveCursorTo(e||0,0),n.isOpen&&n._signal(\"select\"))},n.on(\"changeSelection\",function(){n.isOpen&&n.setRow(n.selection.lead.row),n.renderer.scrollCursorIntoView()}),n.hide=function(){this.container.style.display=\"none\",this._signal(\"hide\"),n.isOpen=!1},n.show=function(e,t,i){var o=this.container,a=window.innerHeight,s=window.innerWidth,l=this.renderer,c=l.$maxLines*t*1.4,u=e.top+this.$borderSize,d=u>a/2&&!i;d&&u+t+c>a?(l.$maxPixelHeight=u-2*this.$borderSize,o.style.top=\"\",o.style.bottom=a-u+\"px\",n.isTopdown=!1):(u+=t,l.$maxPixelHeight=a-u-.2*t,o.style.top=u+\"px\",o.style.bottom=\"\",n.isTopdown=!0),o.style.display=\"\",this.renderer.$textLayer.checkForSizeChanges();var h=e.left;h+o.offsetWidth>s&&(h=s-o.offsetWidth),o.style.left=h+\"px\",this._signal(\"show\"),r=null,n.isOpen=!0},n.getTextLeftOffset=function(){return this.$borderSize+this.renderer.$padding+this.$imageSize},n.$imageSize=0,n.$borderSize=1,n};l.importCssString(\".ace_editor.ace_autocomplete .ace_marker-layer .ace_active-line {    background-color: #CAD6FA;    z-index: 1;}.ace_editor.ace_autocomplete .ace_line-hover {    border: 1px solid #abbffe;    margin-top: -1px;    background: rgba(233,233,253,0.4);}.ace_editor.ace_autocomplete .ace_line-hover {    position: absolute;    z-index: 2;}.ace_editor.ace_autocomplete .ace_scroller {   background: none;   border: none;   box-shadow: none;}.ace_rightAlignedText {    color: gray;    display: inline-block;    position: absolute;    right: 4px;    text-align: right;    z-index: -1;}.ace_editor.ace_autocomplete .ace_completion-highlight{    color: #000;    text-shadow: 0 0 0.01em;}.ace_editor.ace_autocomplete {    width: 280px;    z-index: 200000;    background: #fbfbfb;    color: #444;    border: 1px lightgray solid;    position: fixed;    box-shadow: 2px 3px 5px rgba(0,0,0,.2);    line-height: 1.4;}\"),t.AcePopup=u}),ace.define(\"ace/autocomplete/util\",[\"require\",\"exports\",\"module\"],function(e,t,n){\"use strict\";t.parForEach=function(e,t,n){var r=0,i=e.length;0===i&&n();for(var o=0;o<i;o++)t(e[o],function(e,t){r++,r===i&&n(e,t)})};var r=/[a-zA-Z_0-9\\$\\-\\u00A2-\\uFFFF]/;t.retrievePrecedingIdentifier=function(e,t,n){n=n||r;for(var i=[],o=t-1;o>=0;o--){if(!n.test(e[o]))break;i.push(e[o])}return i.reverse().join(\"\")},t.retrieveFollowingIdentifier=function(e,t,n){n=n||r;for(var i=[],o=t;o<e.length;o++){if(!n.test(e[o]))break;i.push(e[o])}return i},t.getCompletionPrefix=function(e){var t,n=e.getCursorPosition(),r=e.session.getLine(n.row);return e.completers.forEach(function(e){e.identifierRegexps&&e.identifierRegexps.forEach(function(e){!t&&e&&(t=this.retrievePrecedingIdentifier(r,n.column,e))}.bind(this))}.bind(this)),t||this.retrievePrecedingIdentifier(r,n.column)}}),ace.define(\"ace/autocomplete\",[\"require\",\"exports\",\"module\",\"ace/keyboard/hash_handler\",\"ace/autocomplete/popup\",\"ace/autocomplete/util\",\"ace/lib/event\",\"ace/lib/lang\",\"ace/lib/dom\",\"ace/snippets\"],function(e,t,n){\"use strict\";var r=e(\"./keyboard/hash_handler\").HashHandler,i=e(\"./autocomplete/popup\").AcePopup,o=e(\"./autocomplete/util\"),a=(e(\"./lib/event\"),e(\"./lib/lang\")),s=e(\"./lib/dom\"),l=e(\"./snippets\").snippetManager,c=function(){this.autoInsert=!1,this.autoSelect=!0,this.exactMatch=!1,this.gatherCompletionsId=0,this.keyboardHandler=new r,this.keyboardHandler.bindKeys(this.commands),this.blurListener=this.blurListener.bind(this),this.changeListener=this.changeListener.bind(this),this.mousedownListener=this.mousedownListener.bind(this),this.mousewheelListener=this.mousewheelListener.bind(this),this.changeTimer=a.delayedCall(function(){this.updateCompletions(!0)}.bind(this)),this.tooltipTimer=a.delayedCall(this.updateDocTooltip.bind(this),50)};(function(){this.$init=function(){return this.popup=new i(document.body||document.documentElement),this.popup.on(\"click\",function(e){this.insertMatch(),e.stop()}.bind(this)),this.popup.focus=this.editor.focus.bind(this.editor),this.popup.on(\"show\",this.tooltipTimer.bind(null,null)),this.popup.on(\"select\",this.tooltipTimer.bind(null,null)),this.popup.on(\"changeHoverMarker\",this.tooltipTimer.bind(null,null)),this.popup},this.getPopup=function(){return this.popup||this.$init()},this.openPopup=function(e,t,n){this.popup||this.$init(),this.popup.autoSelect=this.autoSelect,this.popup.setData(this.completions.filtered),e.keyBinding.addKeyboardHandler(this.keyboardHandler);var r=e.renderer;if(this.popup.setRow(this.autoSelect?0:-1),n)n&&!t&&this.detach();else{this.popup.setTheme(e.getTheme()),this.popup.setFontSize(e.getFontSize());var i=r.layerConfig.lineHeight,o=r.$cursorLayer.getPixelPosition(this.base,!0);o.left-=this.popup.getTextLeftOffset();var a=e.container.getBoundingClientRect();o.top+=a.top-r.layerConfig.offset,o.left+=a.left-e.renderer.scrollLeft,o.left+=r.gutterWidth,this.popup.show(o,i)}},this.detach=function(){this.editor.keyBinding.removeKeyboardHandler(this.keyboardHandler),this.editor.off(\"changeSelection\",this.changeListener),this.editor.off(\"blur\",this.blurListener),this.editor.off(\"mousedown\",this.mousedownListener),this.editor.off(\"mousewheel\",this.mousewheelListener),this.changeTimer.cancel(),this.hideDocTooltip(),this.gatherCompletionsId+=1,this.popup&&this.popup.isOpen&&this.popup.hide(),this.base&&this.base.detach(),this.activated=!1,this.completions=this.base=null},this.changeListener=function(e){var t=this.editor.selection.lead;(t.row!=this.base.row||t.column<this.base.column)&&this.detach(),this.activated?this.changeTimer.schedule():this.detach()},this.blurListener=function(e){var t=document.activeElement,n=this.editor.textInput.getElement(),r=e.relatedTarget&&this.tooltipNode&&this.tooltipNode.contains(e.relatedTarget),i=this.popup&&this.popup.container;t==n||t.parentNode==i||r||t==this.tooltipNode||e.relatedTarget==n||this.detach()},this.mousedownListener=function(e){this.detach()},this.mousewheelListener=function(e){this.detach()},this.goTo=function(e){var t=this.popup.getRow(),n=this.popup.session.getLength()-1;switch(e){case\"up\":t=t<=0?n:t-1;break;case\"down\":t=t>=n?-1:t+1;break;case\"start\":t=0;break;case\"end\":t=n;break}this.popup.setRow(t)},this.insertMatch=function(e,t){if(e||(e=this.popup.getData(this.popup.getRow())),!e)return!1;if(e.completer&&e.completer.insertMatch)e.completer.insertMatch(this.editor,e);else{if(this.completions.filterText)for(var n,r=this.editor.selection.getAllRanges(),i=0;n=r[i];i++)n.start.column-=this.completions.filterText.length,this.editor.session.remove(n);e.snippet?l.insertSnippet(this.editor,e.snippet):this.editor.execCommand(\"insertstring\",e.value||e)}this.detach()},this.commands={Up:function(e){e.completer.goTo(\"up\")},Down:function(e){e.completer.goTo(\"down\")},\"Ctrl-Up|Ctrl-Home\":function(e){e.completer.goTo(\"start\")},\"Ctrl-Down|Ctrl-End\":function(e){e.completer.goTo(\"end\")},Esc:function(e){e.completer.detach()},Return:function(e){return e.completer.insertMatch()},\"Shift-Return\":function(e){e.completer.insertMatch(null,{deleteSuffix:!0})},Tab:function(e){var t=e.completer.insertMatch();if(t||e.tabstopManager)return t;e.completer.goTo(\"down\")},PageUp:function(e){e.completer.popup.gotoPageUp()},PageDown:function(e){e.completer.popup.gotoPageDown()}},this.gatherCompletions=function(e,t){var n=e.getSession(),r=e.getCursorPosition(),i=o.getCompletionPrefix(e);this.base=n.doc.createAnchor(r.row,r.column-i.length),this.base.$insertRight=!0;var a=[],s=e.completers.length;return e.completers.forEach(function(l,c){l.getCompletions(e,n,r,i,function(n,r){!n&&r&&(a=a.concat(r)),t(null,{prefix:o.getCompletionPrefix(e),matches:a,finished:0===--s})})}),!0},this.showPopup=function(e){this.editor&&this.detach(),this.activated=!0,this.editor=e,e.completer!=this&&(e.completer&&e.completer.detach(),e.completer=this),e.on(\"changeSelection\",this.changeListener),e.on(\"blur\",this.blurListener),e.on(\"mousedown\",this.mousedownListener),e.on(\"mousewheel\",this.mousewheelListener),this.updateCompletions()},this.updateCompletions=function(e){if(e&&this.base&&this.completions){var t=this.editor.getCursorPosition(),n=this.editor.session.getTextRange({start:this.base,end:t});if(n==this.completions.filterText)return;return this.completions.setFilter(n),this.completions.filtered.length?1!=this.completions.filtered.length||this.completions.filtered[0].value!=n||this.completions.filtered[0].snippet?void this.openPopup(this.editor,n,e):this.detach():this.detach()}var r=this.gatherCompletionsId;this.gatherCompletions(this.editor,function(t,n){var i=function(){if(n.finished)return this.detach()}.bind(this),o=n.prefix,a=n&&n.matches;if(!a||!a.length)return i();if(0===o.indexOf(n.prefix)&&r==this.gatherCompletionsId){this.completions=new u(a),this.exactMatch&&(this.completions.exactMatch=!0),this.completions.setFilter(o);var s=this.completions.filtered;return s.length&&(1!=s.length||s[0].value!=o||s[0].snippet)?this.autoInsert&&1==s.length&&n.finished?this.insertMatch(s[0]):void this.openPopup(this.editor,o,e):i()}}.bind(this))},this.cancelContextMenu=function(){this.editor.$mouseHandler.cancelContextMenu()},this.updateDocTooltip=function(){var e=this.popup,t=e.data,n=t&&(t[e.getHoveredRow()]||t[e.getRow()]),r=null;return n&&this.editor&&this.popup.isOpen?(this.editor.completers.some(function(e){return e.getDocTooltip&&(r=e.getDocTooltip(n)),r}),r||(r=n),\"string\"==typeof r&&(r={docText:r}),r&&(r.docHTML||r.docText)?void this.showDocTooltip(r):this.hideDocTooltip()):this.hideDocTooltip()},this.showDocTooltip=function(e){this.tooltipNode||(this.tooltipNode=s.createElement(\"div\"),this.tooltipNode.className=\"ace_tooltip ace_doc-tooltip\",this.tooltipNode.style.margin=0,this.tooltipNode.style.pointerEvents=\"auto\",this.tooltipNode.tabIndex=-1,this.tooltipNode.onblur=this.blurListener.bind(this),this.tooltipNode.onclick=this.onTooltipClick.bind(this));var t=this.tooltipNode;e.docHTML?t.innerHTML=e.docHTML:e.docText&&(t.textContent=e.docText),t.parentNode||document.body.appendChild(t);var n=this.popup,r=n.container.getBoundingClientRect();t.style.top=n.container.style.top,t.style.bottom=n.container.style.bottom,window.innerWidth-r.right<320?(t.style.right=window.innerWidth-r.left+\"px\",t.style.left=\"\"):(t.style.left=r.right+1+\"px\",t.style.right=\"\"),t.style.display=\"block\"},this.hideDocTooltip=function(){if(this.tooltipTimer.cancel(),this.tooltipNode){var e=this.tooltipNode;this.editor.isFocused()||document.activeElement!=e||this.editor.focus(),this.tooltipNode=null,e.parentNode&&e.parentNode.removeChild(e)}},this.onTooltipClick=function(e){var t=e.target;while(t&&t!=this.tooltipNode){if(\"A\"==t.nodeName&&t.href){t.rel=\"noreferrer\",t.target=\"_blank\";break}t=t.parentNode}}}).call(c.prototype),c.startCommand={name:\"startAutocomplete\",exec:function(e){e.completer||(e.completer=new c),e.completer.autoInsert=!1,e.completer.autoSelect=!0,e.completer.showPopup(e),e.completer.cancelContextMenu()},bindKey:\"Ctrl-Space|Ctrl-Shift-Space|Alt-Space\"};var u=function(e,t){this.all=e,this.filtered=e,this.filterText=t||\"\",this.exactMatch=!1};(function(){this.setFilter=function(e){if(e.length>this.filterText&&0===e.lastIndexOf(this.filterText,0))var t=this.filtered;else t=this.all;this.filterText=e,t=this.filterCompletions(t,this.filterText),t=t.sort(function(e,t){return t.exactMatch-e.exactMatch||t.score-e.score});var n=null;t=t.filter(function(e){var t=e.snippet||e.caption||e.value;return t!==n&&(n=t,!0)}),this.filtered=t},this.filterCompletions=function(e,t){var n=[],r=t.toUpperCase(),i=t.toLowerCase();e:for(var o,a=0;o=e[a];a++){var s=o.value||o.caption||o.snippet;if(s){var l,c,u=-1,d=0,h=0;if(this.exactMatch){if(t!==s.substr(0,t.length))continue e}else for(var p=0;p<t.length;p++){var m=s.indexOf(i[p],u+1),f=s.indexOf(r[p],u+1);if(l=m>=0&&(f<0||m<f)?m:f,l<0)continue e;c=l-u-1,c>0&&(-1===u&&(h+=10),h+=c),d|=1<<l,u=l}o.matchMask=d,o.exactMatch=h?0:1,o.score=(o.score||0)-h,n.push(o)}}return n}}).call(u.prototype),t.Autocomplete=c,t.FilteredList=u}),ace.define(\"ace/autocomplete/text_completer\",[\"require\",\"exports\",\"module\",\"ace/range\"],function(e,t,n){var r=e(\"../range\").Range,i=/[^a-zA-Z_0-9\\$\\-\\u00C0-\\u1FFF\\u2C00-\\uD7FF\\w]+/;function o(e,t){var n=e.getTextRange(r.fromPoints({row:0,column:0},t));return n.split(i).length-1}function a(e,t){var n=o(e,t),r=e.getValue().split(i),a=Object.create(null),s=r[n];return r.forEach(function(e,t){if(e&&e!==s){var i=Math.abs(n-t),o=r.length-i;a[e]?a[e]=Math.max(o,a[e]):a[e]=o}}),a}t.getCompletions=function(e,t,n,r,i){var o=a(t,n,r),s=Object.keys(o);i(null,s.map(function(e){return{caption:e,value:e,score:o[e],meta:\"local\"}}))}}),ace.define(\"ace/ext/language_tools\",[\"require\",\"exports\",\"module\",\"ace/snippets\",\"ace/autocomplete\",\"ace/config\",\"ace/lib/lang\",\"ace/autocomplete/util\",\"ace/autocomplete/text_completer\",\"ace/editor\",\"ace/config\"],function(e,t,n){\"use strict\";var r=e(\"../snippets\").snippetManager,i=e(\"../autocomplete\").Autocomplete,o=e(\"../config\"),a=e(\"../lib/lang\"),s=e(\"../autocomplete/util\"),l=e(\"../autocomplete/text_completer\"),c={getCompletions:function(e,t,n,r,i){if(t.$mode.completer)return t.$mode.completer.getCompletions(e,t,n,r,i);var o=e.session.getState(n.row),a=t.$mode.getCompletions(o,t,n,r);i(null,a)}},u={getCompletions:function(e,t,n,i,o){var a=r.snippetMap,s=[];r.getActiveScopes(e).forEach(function(e){for(var t=a[e]||[],n=t.length;n--;){var r=t[n],i=r.name||r.tabTrigger;i&&s.push({caption:i,snippet:r.content,meta:r.tabTrigger&&!r.name?r.tabTrigger+\"⇥ \":\"snippet\",type:\"snippet\"})}},this),o(null,s)},getDocTooltip:function(e){\"snippet\"!=e.type||e.docHTML||(e.docHTML=[\"<b>\",a.escapeHTML(e.caption),\"</b>\",\"<hr></hr>\",a.escapeHTML(e.snippet)].join(\"\"))}},d=[u,l,c];t.setCompleters=function(e){d.length=0,e&&d.push.apply(d,e)},t.addCompleter=function(e){d.push(e)},t.textCompleter=l,t.keyWordCompleter=c,t.snippetCompleter=u;var h={name:\"expandSnippet\",exec:function(e){return r.expandWithTab(e)},bindKey:\"Tab\"},p=function(e,t){m(t.session.$mode)},m=function(e){var t=e.$id;r.files||(r.files={}),f(t),e.modes&&e.modes.forEach(m)},f=function(e){if(e&&!r.files[e]){var t=e.replace(\"mode\",\"snippets\");r.files[e]={},o.loadModule(t,function(t){t&&(r.files[e]=t,!t.snippets&&t.snippetText&&(t.snippets=r.parseSnippetFile(t.snippetText)),r.register(t.snippets||[],t.scope),t.includeScopes&&(r.snippetMap[t.scope].includeScopes=t.includeScopes,t.includeScopes.forEach(function(e){f(\"ace/mode/\"+e)})))})}},g=function(e){var t=e.editor,n=t.completer&&t.completer.activated;if(\"backspace\"===e.command.name)n&&!s.getCompletionPrefix(t)&&t.completer.detach();else if(\"insertstring\"===e.command.name){var r=s.getCompletionPrefix(t);r&&!n&&(t.completer||(t.completer=new i),t.completer.autoInsert=!1,t.completer.showPopup(t))}},b=e(\"../editor\").Editor;e(\"../config\").defineOptions(b.prototype,\"editor\",{enableBasicAutocompletion:{set:function(e){e?(this.completers||(this.completers=Array.isArray(e)?e:d),this.commands.addCommand(i.startCommand)):this.commands.removeCommand(i.startCommand)},value:!1},enableLiveAutocompletion:{set:function(e){e?(this.completers||(this.completers=Array.isArray(e)?e:d),this.commands.on(\"afterExec\",g)):this.commands.removeListener(\"afterExec\",g)},value:!1},enableSnippets:{set:function(e){e?(this.commands.addCommand(h),this.on(\"changeMode\",p),p(null,this)):(this.commands.removeCommand(h),this.off(\"changeMode\",p))},value:!1}})}),function(){ace.acequire([\"ace/ext/language_tools\"],function(){})}()},2968:function(e,t){ace.define(\"ace/mode/yaml_highlight_rules\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/mode/text_highlight_rules\"],function(e,t,n){\"use strict\";var r=e(\"../lib/oop\"),i=e(\"./text_highlight_rules\").TextHighlightRules,o=function(){this.$rules={start:[{token:\"comment\",regex:\"#.*$\"},{token:\"list.markup\",regex:/^(?:-{3}|\\.{3})\\s*(?=#|$)/},{token:\"list.markup\",regex:/^\\s*[\\-?](?:$|\\s)/},{token:\"constant\",regex:\"!![\\\\w//]+\"},{token:\"constant.language\",regex:\"[&\\\\*][a-zA-Z0-9-_]+\"},{token:[\"meta.tag\",\"keyword\"],regex:/^(\\s*\\w.*?)(:(?=\\s|$))/},{token:[\"meta.tag\",\"keyword\"],regex:/(\\w+?)(\\s*:(?=\\s|$))/},{token:\"keyword.operator\",regex:\"<<\\\\w*:\\\\w*\"},{token:\"keyword.operator\",regex:\"-\\\\s*(?=[{])\"},{token:\"string\",regex:'[\"](?:(?:\\\\\\\\.)|(?:[^\"\\\\\\\\]))*?[\"]'},{token:\"string\",regex:/[|>][-+\\d\\s]*$/,onMatch:function(e,t,n,r){var i=/^\\s*/.exec(r)[0];return n.length<1?n.push(this.next):n[0]=\"mlString\",n.length<2?n.push(i.length):n[1]=i.length,this.token},next:\"mlString\"},{token:\"string\",regex:\"['](?:(?:\\\\\\\\.)|(?:[^'\\\\\\\\]))*?[']\"},{token:\"constant.numeric\",regex:/(\\b|[+\\-\\.])[\\d_]+(?:(?:\\.[\\d_]*)?(?:[eE][+\\-]?[\\d_]+)?)(?=[^\\d-\\w]|$)/},{token:\"constant.numeric\",regex:/[+\\-]?\\.inf\\b|NaN\\b|0x[\\dA-Fa-f_]+|0b[10_]+/},{token:\"constant.language.boolean\",regex:\"\\\\b(?:true|false|TRUE|FALSE|True|False|yes|no)\\\\b\"},{token:\"paren.lparen\",regex:\"[[({]\"},{token:\"paren.rparen\",regex:\"[\\\\])}]\"},{token:\"text\",regex:/[^\\s,:\\[\\]\\{\\}]+/}],mlString:[{token:\"indent\",regex:/^\\s*$/},{token:\"indent\",regex:/^\\s*/,onMatch:function(e,t,n){var r=n[1];return r>=e.length?(this.next=\"start\",n.splice(0)):this.next=\"mlString\",this.token},next:\"mlString\"},{token:\"string\",regex:\".+\"}]},this.normalizeRules()};r.inherits(o,i),t.YamlHighlightRules=o}),ace.define(\"ace/mode/matching_brace_outdent\",[\"require\",\"exports\",\"module\",\"ace/range\"],function(e,t,n){\"use strict\";var r=e(\"../range\").Range,i=function(){};(function(){this.checkOutdent=function(e,t){return!!/^\\s+$/.test(e)&&/^\\s*\\}/.test(t)},this.autoOutdent=function(e,t){var n=e.getLine(t),i=n.match(/^(\\s*\\})/);if(!i)return 0;var o=i[1].length,a=e.findMatchingBracket({row:t,column:o});if(!a||a.row==t)return 0;var s=this.$getIndent(e.getLine(a.row));e.replace(new r(t,0,t,o-1),s)},this.$getIndent=function(e){return e.match(/^\\s*/)[0]}}).call(i.prototype),t.MatchingBraceOutdent=i}),ace.define(\"ace/mode/folding/coffee\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/mode/folding/fold_mode\",\"ace/range\"],function(e,t,n){\"use strict\";var r=e(\"../../lib/oop\"),i=e(\"./fold_mode\").FoldMode,o=e(\"../../range\").Range,a=t.FoldMode=function(){};r.inherits(a,i),function(){this.getFoldWidgetRange=function(e,t,n){var r=this.indentationBlock(e,n);if(r)return r;var i=/\\S/,a=e.getLine(n),s=a.search(i);if(-1!=s&&\"#\"==a[s]){var l=a.length,c=e.getLength(),u=n,d=n;while(++n<c){a=e.getLine(n);var h=a.search(i);if(-1!=h){if(\"#\"!=a[h])break;d=n}}if(d>u){var p=e.getLine(d).length;return new o(u,l,d,p)}}},this.getFoldWidget=function(e,t,n){var r=e.getLine(n),i=r.search(/\\S/),o=e.getLine(n+1),a=e.getLine(n-1),s=a.search(/\\S/),l=o.search(/\\S/);if(-1==i)return e.foldWidgets[n-1]=-1!=s&&s<l?\"start\":\"\",\"\";if(-1==s){if(i==l&&\"#\"==r[i]&&\"#\"==o[i])return e.foldWidgets[n-1]=\"\",e.foldWidgets[n+1]=\"\",\"start\"}else if(s==i&&\"#\"==r[i]&&\"#\"==a[i]&&-1==e.getLine(n-2).search(/\\S/))return e.foldWidgets[n-1]=\"start\",e.foldWidgets[n+1]=\"\",\"\";return e.foldWidgets[n-1]=-1!=s&&s<i?\"start\":\"\",i<l?\"start\":\"\"}}.call(a.prototype)}),ace.define(\"ace/mode/yaml\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/mode/text\",\"ace/mode/yaml_highlight_rules\",\"ace/mode/matching_brace_outdent\",\"ace/mode/folding/coffee\"],function(e,t,n){\"use strict\";var r=e(\"../lib/oop\"),i=e(\"./text\").Mode,o=e(\"./yaml_highlight_rules\").YamlHighlightRules,a=e(\"./matching_brace_outdent\").MatchingBraceOutdent,s=e(\"./folding/coffee\").FoldMode,l=function(){this.HighlightRules=o,this.$outdent=new a,this.foldingRules=new s,this.$behaviour=this.$defaultBehaviour};r.inherits(l,i),function(){this.lineCommentStart=[\"#\",\"//\"],this.getNextLineIndent=function(e,t,n){var r=this.$getIndent(t);if(\"start\"==e){var i=t.match(/^.*[\\{\\(\\[]\\s*$/);i&&(r+=n)}return r},this.checkOutdent=function(e,t,n){return this.$outdent.checkOutdent(t,n)},this.autoOutdent=function(e,t,n){this.$outdent.autoOutdent(t,n)},this.$id=\"ace/mode/yaml\"}.call(l.prototype),t.Mode=l})},\"6a21\":function(e,t){ace.define(\"ace/snippets/javascript\",[\"require\",\"exports\",\"module\"],function(e,t,n){\"use strict\";t.snippetText='# Prototype\\nsnippet proto\\n\\t${1:class_name}.prototype.${2:method_name} = function(${3:first_argument}) {\\n\\t\\t${4:// body...}\\n\\t};\\n# Function\\nsnippet fun\\n\\tfunction ${1?:function_name}(${2:argument}) {\\n\\t\\t${3:// body...}\\n\\t}\\n# Anonymous Function\\nregex /((=)\\\\s*|(:)\\\\s*|(\\\\()|\\\\b)/f/(\\\\))?/\\nsnippet f\\n\\tfunction${M1?: ${1:functionName}}($2) {\\n\\t\\t${0:$TM_SELECTED_TEXT}\\n\\t}${M2?;}${M3?,}${M4?)}\\n# Immediate function\\ntrigger \\\\(?f\\\\(\\nendTrigger \\\\)?\\nsnippet f(\\n\\t(function(${1}) {\\n\\t\\t${0:${TM_SELECTED_TEXT:/* code */}}\\n\\t}(${1}));\\n# if\\nsnippet if\\n\\tif (${1:true}) {\\n\\t\\t${0}\\n\\t}\\n# if ... else\\nsnippet ife\\n\\tif (${1:true}) {\\n\\t\\t${2}\\n\\t} else {\\n\\t\\t${0}\\n\\t}\\n# tertiary conditional\\nsnippet ter\\n\\t${1:/* condition */} ? ${2:a} : ${3:b}\\n# switch\\nsnippet switch\\n\\tswitch (${1:expression}) {\\n\\t\\tcase \\'${3:case}\\':\\n\\t\\t\\t${4:// code}\\n\\t\\t\\tbreak;\\n\\t\\t${5}\\n\\t\\tdefault:\\n\\t\\t\\t${2:// code}\\n\\t}\\n# case\\nsnippet case\\n\\tcase \\'${1:case}\\':\\n\\t\\t${2:// code}\\n\\t\\tbreak;\\n\\t${3}\\n\\n# while (...) {...}\\nsnippet wh\\n\\twhile (${1:/* condition */}) {\\n\\t\\t${0:/* code */}\\n\\t}\\n# try\\nsnippet try\\n\\ttry {\\n\\t\\t${0:/* code */}\\n\\t} catch (e) {}\\n# do...while\\nsnippet do\\n\\tdo {\\n\\t\\t${2:/* code */}\\n\\t} while (${1:/* condition */});\\n# Object Method\\nsnippet :f\\nregex /([,{[])|^\\\\s*/:f/\\n\\t${1:method_name}: function(${2:attribute}) {\\n\\t\\t${0}\\n\\t}${3:,}\\n# setTimeout function\\nsnippet setTimeout\\nregex /\\\\b/st|timeout|setTimeo?u?t?/\\n\\tsetTimeout(function() {${3:$TM_SELECTED_TEXT}}, ${1:10});\\n# Get Elements\\nsnippet gett\\n\\tgetElementsBy${1:TagName}(\\'${2}\\')${3}\\n# Get Element\\nsnippet get\\n\\tgetElementBy${1:Id}(\\'${2}\\')${3}\\n# console.log (Firebug)\\nsnippet cl\\n\\tconsole.log(${1});\\n# return\\nsnippet ret\\n\\treturn ${1:result}\\n# for (property in object ) { ... }\\nsnippet fori\\n\\tfor (var ${1:prop} in ${2:Things}) {\\n\\t\\t${0:$2[$1]}\\n\\t}\\n# hasOwnProperty\\nsnippet has\\n\\thasOwnProperty(${1})\\n# docstring\\nsnippet /**\\n\\t/**\\n\\t * ${1:description}\\n\\t *\\n\\t */\\nsnippet @par\\nregex /^\\\\s*\\\\*\\\\s*/@(para?m?)?/\\n\\t@param {${1:type}} ${2:name} ${3:description}\\nsnippet @ret\\n\\t@return {${1:type}} ${2:description}\\n# JSON.parse\\nsnippet jsonp\\n\\tJSON.parse(${1:jstr});\\n# JSON.stringify\\nsnippet jsons\\n\\tJSON.stringify(${1:object});\\n# self-defining function\\nsnippet sdf\\n\\tvar ${1:function_name} = function(${2:argument}) {\\n\\t\\t${3:// initial code ...}\\n\\n\\t\\t$1 = function($2) {\\n\\t\\t\\t${4:// main code}\\n\\t\\t};\\n\\t}\\n# singleton\\nsnippet sing\\n\\tfunction ${1:Singleton} (${2:argument}) {\\n\\t\\t// the cached instance\\n\\t\\tvar instance;\\n\\n\\t\\t// rewrite the constructor\\n\\t\\t$1 = function $1($2) {\\n\\t\\t\\treturn instance;\\n\\t\\t};\\n\\t\\t\\n\\t\\t// carry over the prototype properties\\n\\t\\t$1.prototype = this;\\n\\n\\t\\t// the instance\\n\\t\\tinstance = new $1();\\n\\n\\t\\t// reset the constructor pointer\\n\\t\\tinstance.constructor = $1;\\n\\n\\t\\t${3:// code ...}\\n\\n\\t\\treturn instance;\\n\\t}\\n# class\\nsnippet class\\nregex /^\\\\s*/clas{0,2}/\\n\\tvar ${1:class} = function(${20}) {\\n\\t\\t$40$0\\n\\t};\\n\\t\\n\\t(function() {\\n\\t\\t${60:this.prop = \"\"}\\n\\t}).call(${1:class}.prototype);\\n\\t\\n\\texports.${1:class} = ${1:class};\\n# \\nsnippet for-\\n\\tfor (var ${1:i} = ${2:Things}.length; ${1:i}--; ) {\\n\\t\\t${0:${2:Things}[${1:i}];}\\n\\t}\\n# for (...) {...}\\nsnippet for\\n\\tfor (var ${1:i} = 0; $1 < ${2:Things}.length; $1++) {\\n\\t\\t${3:$2[$1]}$0\\n\\t}\\n# for (...) {...} (Improved Native For-Loop)\\nsnippet forr\\n\\tfor (var ${1:i} = ${2:Things}.length - 1; $1 >= 0; $1--) {\\n\\t\\t${3:$2[$1]}$0\\n\\t}\\n\\n\\n#modules\\nsnippet def\\n\\tdefine(function(require, exports, module) {\\n\\t\"use strict\";\\n\\tvar ${1/.*\\\\///} = require(\"${1}\");\\n\\t\\n\\t$TM_SELECTED_TEXT\\n\\t});\\nsnippet req\\nguard ^\\\\s*\\n\\tvar ${1/.*\\\\///} = require(\"${1}\");\\n\\t$0\\nsnippet requ\\nguard ^\\\\s*\\n\\tvar ${1/.*\\\\/(.)/\\\\u$1/} = require(\"${1}\").${1/.*\\\\/(.)/\\\\u$1/};\\n\\t$0\\n',t.scope=\"javascript\"})},\"6d68\":function(e,t){e.exports.id=\"ace/mode/javascript_worker\",e.exports.src='\"no use strict\";!function(window){function resolveModuleId(id,paths){for(var testPath=id,tail=\"\";testPath;){var alias=paths[testPath];if(\"string\"==typeof alias)return alias+tail;if(alias)return alias.location.replace(/\\\\/*$/,\"/\")+(tail||alias.main||alias.name);if(alias===!1)return\"\";var i=testPath.lastIndexOf(\"/\");if(-1===i)break;tail=testPath.substr(i)+tail,testPath=testPath.slice(0,i)}return id}if(!(void 0!==window.window&&window.document||window.acequire&&window.define)){window.console||(window.console=function(){var msgs=Array.prototype.slice.call(arguments,0);postMessage({type:\"log\",data:msgs})},window.console.error=window.console.warn=window.console.log=window.console.trace=window.console),window.window=window,window.ace=window,window.onerror=function(message,file,line,col,err){postMessage({type:\"error\",data:{message:message,data:err.data,file:file,line:line,col:col,stack:err.stack}})},window.normalizeModule=function(parentId,moduleName){if(-1!==moduleName.indexOf(\"!\")){var chunks=moduleName.split(\"!\");return window.normalizeModule(parentId,chunks[0])+\"!\"+window.normalizeModule(parentId,chunks[1])}if(\".\"==moduleName.charAt(0)){var base=parentId.split(\"/\").slice(0,-1).join(\"/\");for(moduleName=(base?base+\"/\":\"\")+moduleName;-1!==moduleName.indexOf(\".\")&&previous!=moduleName;){var previous=moduleName;moduleName=moduleName.replace(/^\\\\.\\\\//,\"\").replace(/\\\\/\\\\.\\\\//,\"/\").replace(/[^\\\\/]+\\\\/\\\\.\\\\.\\\\//,\"\")}}return moduleName},window.acequire=function acequire(parentId,id){if(id||(id=parentId,parentId=null),!id.charAt)throw Error(\"worker.js acequire() accepts only (parentId, id) as arguments\");id=window.normalizeModule(parentId,id);var module=window.acequire.modules[id];if(module)return module.initialized||(module.initialized=!0,module.exports=module.factory().exports),module.exports;if(!window.acequire.tlns)return console.log(\"unable to load \"+id);var path=resolveModuleId(id,window.acequire.tlns);return\".js\"!=path.slice(-3)&&(path+=\".js\"),window.acequire.id=id,window.acequire.modules[id]={},importScripts(path),window.acequire(parentId,id)},window.acequire.modules={},window.acequire.tlns={},window.define=function(id,deps,factory){if(2==arguments.length?(factory=deps,\"string\"!=typeof id&&(deps=id,id=window.acequire.id)):1==arguments.length&&(factory=id,deps=[],id=window.acequire.id),\"function\"!=typeof factory)return window.acequire.modules[id]={exports:factory,initialized:!0},void 0;deps.length||(deps=[\"require\",\"exports\",\"module\"]);var req=function(childId){return window.acequire(id,childId)};window.acequire.modules[id]={exports:{},factory:function(){var module=this,returnExports=factory.apply(this,deps.map(function(dep){switch(dep){case\"require\":return req;case\"exports\":return module.exports;case\"module\":return module;default:return req(dep)}}));return returnExports&&(module.exports=returnExports),module}}},window.define.amd={},acequire.tlns={},window.initBaseUrls=function(topLevelNamespaces){for(var i in topLevelNamespaces)acequire.tlns[i]=topLevelNamespaces[i]},window.initSender=function(){var EventEmitter=window.acequire(\"ace/lib/event_emitter\").EventEmitter,oop=window.acequire(\"ace/lib/oop\"),Sender=function(){};return function(){oop.implement(this,EventEmitter),this.callback=function(data,callbackId){postMessage({type:\"call\",id:callbackId,data:data})},this.emit=function(name,data){postMessage({type:\"event\",name:name,data:data})}}.call(Sender.prototype),new Sender};var main=window.main=null,sender=window.sender=null;window.onmessage=function(e){var msg=e.data;if(msg.event&&sender)sender._signal(msg.event,msg.data);else if(msg.command)if(main[msg.command])main[msg.command].apply(main,msg.args);else{if(!window[msg.command])throw Error(\"Unknown command:\"+msg.command);window[msg.command].apply(window,msg.args)}else if(msg.init){window.initBaseUrls(msg.tlns),acequire(\"ace/lib/es5-shim\"),sender=window.sender=window.initSender();var clazz=acequire(msg.module)[msg.classname];main=window.main=new clazz(sender)}}}}(this),ace.define(\"ace/lib/oop\",[\"require\",\"exports\",\"module\"],function(acequire,exports){\"use strict\";exports.inherits=function(ctor,superCtor){ctor.super_=superCtor,ctor.prototype=Object.create(superCtor.prototype,{constructor:{value:ctor,enumerable:!1,writable:!0,configurable:!0}})},exports.mixin=function(obj,mixin){for(var key in mixin)obj[key]=mixin[key];return obj},exports.implement=function(proto,mixin){exports.mixin(proto,mixin)}}),ace.define(\"ace/range\",[\"require\",\"exports\",\"module\"],function(acequire,exports){\"use strict\";var comparePoints=function(p1,p2){return p1.row-p2.row||p1.column-p2.column},Range=function(startRow,startColumn,endRow,endColumn){this.start={row:startRow,column:startColumn},this.end={row:endRow,column:endColumn}};(function(){this.isEqual=function(range){return this.start.row===range.start.row&&this.end.row===range.end.row&&this.start.column===range.start.column&&this.end.column===range.end.column},this.toString=function(){return\"Range: [\"+this.start.row+\"/\"+this.start.column+\"] -> [\"+this.end.row+\"/\"+this.end.column+\"]\"},this.contains=function(row,column){return 0==this.compare(row,column)},this.compareRange=function(range){var cmp,end=range.end,start=range.start;return cmp=this.compare(end.row,end.column),1==cmp?(cmp=this.compare(start.row,start.column),1==cmp?2:0==cmp?1:0):-1==cmp?-2:(cmp=this.compare(start.row,start.column),-1==cmp?-1:1==cmp?42:0)},this.comparePoint=function(p){return this.compare(p.row,p.column)},this.containsRange=function(range){return 0==this.comparePoint(range.start)&&0==this.comparePoint(range.end)},this.intersects=function(range){var cmp=this.compareRange(range);return-1==cmp||0==cmp||1==cmp},this.isEnd=function(row,column){return this.end.row==row&&this.end.column==column},this.isStart=function(row,column){return this.start.row==row&&this.start.column==column},this.setStart=function(row,column){\"object\"==typeof row?(this.start.column=row.column,this.start.row=row.row):(this.start.row=row,this.start.column=column)},this.setEnd=function(row,column){\"object\"==typeof row?(this.end.column=row.column,this.end.row=row.row):(this.end.row=row,this.end.column=column)},this.inside=function(row,column){return 0==this.compare(row,column)?this.isEnd(row,column)||this.isStart(row,column)?!1:!0:!1},this.insideStart=function(row,column){return 0==this.compare(row,column)?this.isEnd(row,column)?!1:!0:!1},this.insideEnd=function(row,column){return 0==this.compare(row,column)?this.isStart(row,column)?!1:!0:!1},this.compare=function(row,column){return this.isMultiLine()||row!==this.start.row?this.start.row>row?-1:row>this.end.row?1:this.start.row===row?column>=this.start.column?0:-1:this.end.row===row?this.end.column>=column?0:1:0:this.start.column>column?-1:column>this.end.column?1:0},this.compareStart=function(row,column){return this.start.row==row&&this.start.column==column?-1:this.compare(row,column)},this.compareEnd=function(row,column){return this.end.row==row&&this.end.column==column?1:this.compare(row,column)},this.compareInside=function(row,column){return this.end.row==row&&this.end.column==column?1:this.start.row==row&&this.start.column==column?-1:this.compare(row,column)},this.clipRows=function(firstRow,lastRow){if(this.end.row>lastRow)var end={row:lastRow+1,column:0};else if(firstRow>this.end.row)var end={row:firstRow,column:0};if(this.start.row>lastRow)var start={row:lastRow+1,column:0};else if(firstRow>this.start.row)var start={row:firstRow,column:0};return Range.fromPoints(start||this.start,end||this.end)},this.extend=function(row,column){var cmp=this.compare(row,column);if(0==cmp)return this;if(-1==cmp)var start={row:row,column:column};else var end={row:row,column:column};return Range.fromPoints(start||this.start,end||this.end)},this.isEmpty=function(){return this.start.row===this.end.row&&this.start.column===this.end.column},this.isMultiLine=function(){return this.start.row!==this.end.row},this.clone=function(){return Range.fromPoints(this.start,this.end)},this.collapseRows=function(){return 0==this.end.column?new Range(this.start.row,0,Math.max(this.start.row,this.end.row-1),0):new Range(this.start.row,0,this.end.row,0)},this.toScreenRange=function(session){var screenPosStart=session.documentToScreenPosition(this.start),screenPosEnd=session.documentToScreenPosition(this.end);return new Range(screenPosStart.row,screenPosStart.column,screenPosEnd.row,screenPosEnd.column)},this.moveBy=function(row,column){this.start.row+=row,this.start.column+=column,this.end.row+=row,this.end.column+=column}}).call(Range.prototype),Range.fromPoints=function(start,end){return new Range(start.row,start.column,end.row,end.column)},Range.comparePoints=comparePoints,Range.comparePoints=function(p1,p2){return p1.row-p2.row||p1.column-p2.column},exports.Range=Range}),ace.define(\"ace/apply_delta\",[\"require\",\"exports\",\"module\"],function(acequire,exports){\"use strict\";exports.applyDelta=function(docLines,delta){var row=delta.start.row,startColumn=delta.start.column,line=docLines[row]||\"\";switch(delta.action){case\"insert\":var lines=delta.lines;if(1===lines.length)docLines[row]=line.substring(0,startColumn)+delta.lines[0]+line.substring(startColumn);else{var args=[row,1].concat(delta.lines);docLines.splice.apply(docLines,args),docLines[row]=line.substring(0,startColumn)+docLines[row],docLines[row+delta.lines.length-1]+=line.substring(startColumn)}break;case\"remove\":var endColumn=delta.end.column,endRow=delta.end.row;row===endRow?docLines[row]=line.substring(0,startColumn)+line.substring(endColumn):docLines.splice(row,endRow-row+1,line.substring(0,startColumn)+docLines[endRow].substring(endColumn))}}}),ace.define(\"ace/lib/event_emitter\",[\"require\",\"exports\",\"module\"],function(acequire,exports){\"use strict\";var EventEmitter={},stopPropagation=function(){this.propagationStopped=!0},preventDefault=function(){this.defaultPrevented=!0};EventEmitter._emit=EventEmitter._dispatchEvent=function(eventName,e){this._eventRegistry||(this._eventRegistry={}),this._defaultHandlers||(this._defaultHandlers={});var listeners=this._eventRegistry[eventName]||[],defaultHandler=this._defaultHandlers[eventName];if(listeners.length||defaultHandler){\"object\"==typeof e&&e||(e={}),e.type||(e.type=eventName),e.stopPropagation||(e.stopPropagation=stopPropagation),e.preventDefault||(e.preventDefault=preventDefault),listeners=listeners.slice();for(var i=0;listeners.length>i&&(listeners[i](e,this),!e.propagationStopped);i++);return defaultHandler&&!e.defaultPrevented?defaultHandler(e,this):void 0}},EventEmitter._signal=function(eventName,e){var listeners=(this._eventRegistry||{})[eventName];if(listeners){listeners=listeners.slice();for(var i=0;listeners.length>i;i++)listeners[i](e,this)}},EventEmitter.once=function(eventName,callback){var _self=this;callback&&this.addEventListener(eventName,function newCallback(){_self.removeEventListener(eventName,newCallback),callback.apply(null,arguments)})},EventEmitter.setDefaultHandler=function(eventName,callback){var handlers=this._defaultHandlers;if(handlers||(handlers=this._defaultHandlers={_disabled_:{}}),handlers[eventName]){var old=handlers[eventName],disabled=handlers._disabled_[eventName];disabled||(handlers._disabled_[eventName]=disabled=[]),disabled.push(old);var i=disabled.indexOf(callback);-1!=i&&disabled.splice(i,1)}handlers[eventName]=callback},EventEmitter.removeDefaultHandler=function(eventName,callback){var handlers=this._defaultHandlers;if(handlers){var disabled=handlers._disabled_[eventName];if(handlers[eventName]==callback)handlers[eventName],disabled&&this.setDefaultHandler(eventName,disabled.pop());else if(disabled){var i=disabled.indexOf(callback);-1!=i&&disabled.splice(i,1)}}},EventEmitter.on=EventEmitter.addEventListener=function(eventName,callback,capturing){this._eventRegistry=this._eventRegistry||{};var listeners=this._eventRegistry[eventName];return listeners||(listeners=this._eventRegistry[eventName]=[]),-1==listeners.indexOf(callback)&&listeners[capturing?\"unshift\":\"push\"](callback),callback},EventEmitter.off=EventEmitter.removeListener=EventEmitter.removeEventListener=function(eventName,callback){this._eventRegistry=this._eventRegistry||{};var listeners=this._eventRegistry[eventName];if(listeners){var index=listeners.indexOf(callback);-1!==index&&listeners.splice(index,1)}},EventEmitter.removeAllListeners=function(eventName){this._eventRegistry&&(this._eventRegistry[eventName]=[])},exports.EventEmitter=EventEmitter}),ace.define(\"ace/anchor\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/lib/event_emitter\"],function(acequire,exports){\"use strict\";var oop=acequire(\"./lib/oop\"),EventEmitter=acequire(\"./lib/event_emitter\").EventEmitter,Anchor=exports.Anchor=function(doc,row,column){this.$onChange=this.onChange.bind(this),this.attach(doc),column===void 0?this.setPosition(row.row,row.column):this.setPosition(row,column)};(function(){function $pointsInOrder(point1,point2,equalPointsInOrder){var bColIsAfter=equalPointsInOrder?point1.column<=point2.column:point1.column<point2.column;return point1.row<point2.row||point1.row==point2.row&&bColIsAfter}function $getTransformedPoint(delta,point,moveIfEqual){var deltaIsInsert=\"insert\"==delta.action,deltaRowShift=(deltaIsInsert?1:-1)*(delta.end.row-delta.start.row),deltaColShift=(deltaIsInsert?1:-1)*(delta.end.column-delta.start.column),deltaStart=delta.start,deltaEnd=deltaIsInsert?deltaStart:delta.end;return $pointsInOrder(point,deltaStart,moveIfEqual)?{row:point.row,column:point.column}:$pointsInOrder(deltaEnd,point,!moveIfEqual)?{row:point.row+deltaRowShift,column:point.column+(point.row==deltaEnd.row?deltaColShift:0)}:{row:deltaStart.row,column:deltaStart.column}}oop.implement(this,EventEmitter),this.getPosition=function(){return this.$clipPositionToDocument(this.row,this.column)},this.getDocument=function(){return this.document},this.$insertRight=!1,this.onChange=function(delta){if(!(delta.start.row==delta.end.row&&delta.start.row!=this.row||delta.start.row>this.row)){var point=$getTransformedPoint(delta,{row:this.row,column:this.column},this.$insertRight);this.setPosition(point.row,point.column,!0)}},this.setPosition=function(row,column,noClip){var pos;if(pos=noClip?{row:row,column:column}:this.$clipPositionToDocument(row,column),this.row!=pos.row||this.column!=pos.column){var old={row:this.row,column:this.column};this.row=pos.row,this.column=pos.column,this._signal(\"change\",{old:old,value:pos})}},this.detach=function(){this.document.removeEventListener(\"change\",this.$onChange)},this.attach=function(doc){this.document=doc||this.document,this.document.on(\"change\",this.$onChange)},this.$clipPositionToDocument=function(row,column){var pos={};return row>=this.document.getLength()?(pos.row=Math.max(0,this.document.getLength()-1),pos.column=this.document.getLine(pos.row).length):0>row?(pos.row=0,pos.column=0):(pos.row=row,pos.column=Math.min(this.document.getLine(pos.row).length,Math.max(0,column))),0>column&&(pos.column=0),pos}}).call(Anchor.prototype)}),ace.define(\"ace/document\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/apply_delta\",\"ace/lib/event_emitter\",\"ace/range\",\"ace/anchor\"],function(acequire,exports){\"use strict\";var oop=acequire(\"./lib/oop\"),applyDelta=acequire(\"./apply_delta\").applyDelta,EventEmitter=acequire(\"./lib/event_emitter\").EventEmitter,Range=acequire(\"./range\").Range,Anchor=acequire(\"./anchor\").Anchor,Document=function(textOrLines){this.$lines=[\"\"],0===textOrLines.length?this.$lines=[\"\"]:Array.isArray(textOrLines)?this.insertMergedLines({row:0,column:0},textOrLines):this.insert({row:0,column:0},textOrLines)};(function(){oop.implement(this,EventEmitter),this.setValue=function(text){var len=this.getLength()-1;this.remove(new Range(0,0,len,this.getLine(len).length)),this.insert({row:0,column:0},text)},this.getValue=function(){return this.getAllLines().join(this.getNewLineCharacter())},this.createAnchor=function(row,column){return new Anchor(this,row,column)},this.$split=0===\"aaa\".split(/a/).length?function(text){return text.replace(/\\\\r\\\\n|\\\\r/g,\"\\\\n\").split(\"\\\\n\")}:function(text){return text.split(/\\\\r\\\\n|\\\\r|\\\\n/)},this.$detectNewLine=function(text){var match=text.match(/^.*?(\\\\r\\\\n|\\\\r|\\\\n)/m);this.$autoNewLine=match?match[1]:\"\\\\n\",this._signal(\"changeNewLineMode\")},this.getNewLineCharacter=function(){switch(this.$newLineMode){case\"windows\":return\"\\\\r\\\\n\";case\"unix\":return\"\\\\n\";default:return this.$autoNewLine||\"\\\\n\"}},this.$autoNewLine=\"\",this.$newLineMode=\"auto\",this.setNewLineMode=function(newLineMode){this.$newLineMode!==newLineMode&&(this.$newLineMode=newLineMode,this._signal(\"changeNewLineMode\"))},this.getNewLineMode=function(){return this.$newLineMode},this.isNewLine=function(text){return\"\\\\r\\\\n\"==text||\"\\\\r\"==text||\"\\\\n\"==text},this.getLine=function(row){return this.$lines[row]||\"\"},this.getLines=function(firstRow,lastRow){return this.$lines.slice(firstRow,lastRow+1)},this.getAllLines=function(){return this.getLines(0,this.getLength())},this.getLength=function(){return this.$lines.length},this.getTextRange=function(range){return this.getLinesForRange(range).join(this.getNewLineCharacter())},this.getLinesForRange=function(range){var lines;if(range.start.row===range.end.row)lines=[this.getLine(range.start.row).substring(range.start.column,range.end.column)];else{lines=this.getLines(range.start.row,range.end.row),lines[0]=(lines[0]||\"\").substring(range.start.column);var l=lines.length-1;range.end.row-range.start.row==l&&(lines[l]=lines[l].substring(0,range.end.column))}return lines},this.insertLines=function(row,lines){return console.warn(\"Use of document.insertLines is deprecated. Use the insertFullLines method instead.\"),this.insertFullLines(row,lines)},this.removeLines=function(firstRow,lastRow){return console.warn(\"Use of document.removeLines is deprecated. Use the removeFullLines method instead.\"),this.removeFullLines(firstRow,lastRow)},this.insertNewLine=function(position){return console.warn(\"Use of document.insertNewLine is deprecated. Use insertMergedLines(position, [\\'\\', \\'\\']) instead.\"),this.insertMergedLines(position,[\"\",\"\"])},this.insert=function(position,text){return 1>=this.getLength()&&this.$detectNewLine(text),this.insertMergedLines(position,this.$split(text))},this.insertInLine=function(position,text){var start=this.clippedPos(position.row,position.column),end=this.pos(position.row,position.column+text.length);return this.applyDelta({start:start,end:end,action:\"insert\",lines:[text]},!0),this.clonePos(end)},this.clippedPos=function(row,column){var length=this.getLength();void 0===row?row=length:0>row?row=0:row>=length&&(row=length-1,column=void 0);var line=this.getLine(row);return void 0==column&&(column=line.length),column=Math.min(Math.max(column,0),line.length),{row:row,column:column}},this.clonePos=function(pos){return{row:pos.row,column:pos.column}},this.pos=function(row,column){return{row:row,column:column}},this.$clipPosition=function(position){var length=this.getLength();return position.row>=length?(position.row=Math.max(0,length-1),position.column=this.getLine(length-1).length):(position.row=Math.max(0,position.row),position.column=Math.min(Math.max(position.column,0),this.getLine(position.row).length)),position},this.insertFullLines=function(row,lines){row=Math.min(Math.max(row,0),this.getLength());var column=0;this.getLength()>row?(lines=lines.concat([\"\"]),column=0):(lines=[\"\"].concat(lines),row--,column=this.$lines[row].length),this.insertMergedLines({row:row,column:column},lines)},this.insertMergedLines=function(position,lines){var start=this.clippedPos(position.row,position.column),end={row:start.row+lines.length-1,column:(1==lines.length?start.column:0)+lines[lines.length-1].length};return this.applyDelta({start:start,end:end,action:\"insert\",lines:lines}),this.clonePos(end)},this.remove=function(range){var start=this.clippedPos(range.start.row,range.start.column),end=this.clippedPos(range.end.row,range.end.column);return this.applyDelta({start:start,end:end,action:\"remove\",lines:this.getLinesForRange({start:start,end:end})}),this.clonePos(start)},this.removeInLine=function(row,startColumn,endColumn){var start=this.clippedPos(row,startColumn),end=this.clippedPos(row,endColumn);return this.applyDelta({start:start,end:end,action:\"remove\",lines:this.getLinesForRange({start:start,end:end})},!0),this.clonePos(start)},this.removeFullLines=function(firstRow,lastRow){firstRow=Math.min(Math.max(0,firstRow),this.getLength()-1),lastRow=Math.min(Math.max(0,lastRow),this.getLength()-1);var deleteFirstNewLine=lastRow==this.getLength()-1&&firstRow>0,deleteLastNewLine=this.getLength()-1>lastRow,startRow=deleteFirstNewLine?firstRow-1:firstRow,startCol=deleteFirstNewLine?this.getLine(startRow).length:0,endRow=deleteLastNewLine?lastRow+1:lastRow,endCol=deleteLastNewLine?0:this.getLine(endRow).length,range=new Range(startRow,startCol,endRow,endCol),deletedLines=this.$lines.slice(firstRow,lastRow+1);return this.applyDelta({start:range.start,end:range.end,action:\"remove\",lines:this.getLinesForRange(range)}),deletedLines},this.removeNewLine=function(row){this.getLength()-1>row&&row>=0&&this.applyDelta({start:this.pos(row,this.getLine(row).length),end:this.pos(row+1,0),action:\"remove\",lines:[\"\",\"\"]})},this.replace=function(range,text){if(range instanceof Range||(range=Range.fromPoints(range.start,range.end)),0===text.length&&range.isEmpty())return range.start;if(text==this.getTextRange(range))return range.end;this.remove(range);var end;return end=text?this.insert(range.start,text):range.start},this.applyDeltas=function(deltas){for(var i=0;deltas.length>i;i++)this.applyDelta(deltas[i])},this.revertDeltas=function(deltas){for(var i=deltas.length-1;i>=0;i--)this.revertDelta(deltas[i])},this.applyDelta=function(delta,doNotValidate){var isInsert=\"insert\"==delta.action;(isInsert?1>=delta.lines.length&&!delta.lines[0]:!Range.comparePoints(delta.start,delta.end))||(isInsert&&delta.lines.length>2e4&&this.$splitAndapplyLargeDelta(delta,2e4),applyDelta(this.$lines,delta,doNotValidate),this._signal(\"change\",delta))},this.$splitAndapplyLargeDelta=function(delta,MAX){for(var lines=delta.lines,l=lines.length,row=delta.start.row,column=delta.start.column,from=0,to=0;;){from=to,to+=MAX-1;var chunk=lines.slice(from,to);if(to>l){delta.lines=chunk,delta.start.row=row+from,delta.start.column=column;break}chunk.push(\"\"),this.applyDelta({start:this.pos(row+from,column),end:this.pos(row+to,column=0),action:delta.action,lines:chunk},!0)}},this.revertDelta=function(delta){this.applyDelta({start:this.clonePos(delta.start),end:this.clonePos(delta.end),action:\"insert\"==delta.action?\"remove\":\"insert\",lines:delta.lines.slice()})},this.indexToPosition=function(index,startRow){for(var lines=this.$lines||this.getAllLines(),newlineLength=this.getNewLineCharacter().length,i=startRow||0,l=lines.length;l>i;i++)if(index-=lines[i].length+newlineLength,0>index)return{row:i,column:index+lines[i].length+newlineLength};return{row:l-1,column:lines[l-1].length}},this.positionToIndex=function(pos,startRow){for(var lines=this.$lines||this.getAllLines(),newlineLength=this.getNewLineCharacter().length,index=0,row=Math.min(pos.row,lines.length),i=startRow||0;row>i;++i)index+=lines[i].length+newlineLength;return index+pos.column}}).call(Document.prototype),exports.Document=Document}),ace.define(\"ace/lib/lang\",[\"require\",\"exports\",\"module\"],function(acequire,exports){\"use strict\";exports.last=function(a){return a[a.length-1]},exports.stringReverse=function(string){return string.split(\"\").reverse().join(\"\")},exports.stringRepeat=function(string,count){for(var result=\"\";count>0;)1&count&&(result+=string),(count>>=1)&&(string+=string);return result};var trimBeginRegexp=/^\\\\s\\\\s*/,trimEndRegexp=/\\\\s\\\\s*$/;exports.stringTrimLeft=function(string){return string.replace(trimBeginRegexp,\"\")},exports.stringTrimRight=function(string){return string.replace(trimEndRegexp,\"\")},exports.copyObject=function(obj){var copy={};for(var key in obj)copy[key]=obj[key];return copy},exports.copyArray=function(array){for(var copy=[],i=0,l=array.length;l>i;i++)copy[i]=array[i]&&\"object\"==typeof array[i]?this.copyObject(array[i]):array[i];return copy},exports.deepCopy=function deepCopy(obj){if(\"object\"!=typeof obj||!obj)return obj;var copy;if(Array.isArray(obj)){copy=[];for(var key=0;obj.length>key;key++)copy[key]=deepCopy(obj[key]);return copy}if(\"[object Object]\"!==Object.prototype.toString.call(obj))return obj;copy={};for(var key in obj)copy[key]=deepCopy(obj[key]);return copy},exports.arrayToMap=function(arr){for(var map={},i=0;arr.length>i;i++)map[arr[i]]=1;return map},exports.createMap=function(props){var map=Object.create(null);for(var i in props)map[i]=props[i];return map},exports.arrayRemove=function(array,value){for(var i=0;array.length>=i;i++)value===array[i]&&array.splice(i,1)},exports.escapeRegExp=function(str){return str.replace(/([.*+?^${}()|[\\\\]\\\\/\\\\\\\\])/g,\"\\\\\\\\$1\")},exports.escapeHTML=function(str){return str.replace(/&/g,\"&#38;\").replace(/\"/g,\"&#34;\").replace(/\\'/g,\"&#39;\").replace(/</g,\"&#60;\")},exports.getMatchOffsets=function(string,regExp){var matches=[];return string.replace(regExp,function(str){matches.push({offset:arguments[arguments.length-2],length:str.length})}),matches},exports.deferredCall=function(fcn){var timer=null,callback=function(){timer=null,fcn()},deferred=function(timeout){return deferred.cancel(),timer=setTimeout(callback,timeout||0),deferred};return deferred.schedule=deferred,deferred.call=function(){return this.cancel(),fcn(),deferred},deferred.cancel=function(){return clearTimeout(timer),timer=null,deferred},deferred.isPending=function(){return timer},deferred},exports.delayedCall=function(fcn,defaultTimeout){var timer=null,callback=function(){timer=null,fcn()},_self=function(timeout){null==timer&&(timer=setTimeout(callback,timeout||defaultTimeout))};return _self.delay=function(timeout){timer&&clearTimeout(timer),timer=setTimeout(callback,timeout||defaultTimeout)},_self.schedule=_self,_self.call=function(){this.cancel(),fcn()},_self.cancel=function(){timer&&clearTimeout(timer),timer=null},_self.isPending=function(){return timer},_self}}),ace.define(\"ace/worker/mirror\",[\"require\",\"exports\",\"module\",\"ace/range\",\"ace/document\",\"ace/lib/lang\"],function(acequire,exports){\"use strict\";acequire(\"../range\").Range;var Document=acequire(\"../document\").Document,lang=acequire(\"../lib/lang\"),Mirror=exports.Mirror=function(sender){this.sender=sender;var doc=this.doc=new Document(\"\"),deferredUpdate=this.deferredUpdate=lang.delayedCall(this.onUpdate.bind(this)),_self=this;sender.on(\"change\",function(e){var data=e.data;if(data[0].start)doc.applyDeltas(data);else for(var i=0;data.length>i;i+=2){if(Array.isArray(data[i+1]))var d={action:\"insert\",start:data[i],lines:data[i+1]};else var d={action:\"remove\",start:data[i],end:data[i+1]};doc.applyDelta(d,!0)}return _self.$timeout?deferredUpdate.schedule(_self.$timeout):(_self.onUpdate(),void 0)})};(function(){this.$timeout=500,this.setTimeout=function(timeout){this.$timeout=timeout},this.setValue=function(value){this.doc.setValue(value),this.deferredUpdate.schedule(this.$timeout)},this.getValue=function(callbackId){this.sender.callback(this.doc.getValue(),callbackId)},this.onUpdate=function(){},this.isPending=function(){return this.deferredUpdate.isPending()}}).call(Mirror.prototype)}),ace.define(\"ace/mode/javascript/jshint\",[\"require\",\"exports\",\"module\"],function(acequire,exports,module){module.exports=function outer(modules,cache,entry){function newRequire(name,jumped){if(!cache[name]){if(!modules[name]){var currentRequire=\"function\"==typeof acequire&&acequire;if(!jumped&&currentRequire)return currentRequire(name,!0);if(previousRequire)return previousRequire(name,!0);var err=Error(\"Cannot find module \\'\"+name+\"\\'\");throw err.code=\"MODULE_NOT_FOUND\",err}var m=cache[name]={exports:{}};modules[name][0].call(m.exports,function(x){var id=modules[name][1][x];return newRequire(id?id:x)},m,m.exports,outer,modules,cache,entry)}return cache[name].exports}for(var previousRequire=\"function\"==typeof acequire&&acequire,i=0;entry.length>i;i++)newRequire(entry[i]);return newRequire(entry[0])}({\"/node_modules/browserify/node_modules/events/events.js\":[function(_dereq_,module){function EventEmitter(){this._events=this._events||{},this._maxListeners=this._maxListeners||void 0}function isFunction(arg){return\"function\"==typeof arg}function isNumber(arg){return\"number\"==typeof arg}function isObject(arg){return\"object\"==typeof arg&&null!==arg}function isUndefined(arg){return void 0===arg}module.exports=EventEmitter,EventEmitter.EventEmitter=EventEmitter,EventEmitter.prototype._events=void 0,EventEmitter.prototype._maxListeners=void 0,EventEmitter.defaultMaxListeners=10,EventEmitter.prototype.setMaxListeners=function(n){if(!isNumber(n)||0>n||isNaN(n))throw TypeError(\"n must be a positive number\");return this._maxListeners=n,this},EventEmitter.prototype.emit=function(type){var er,handler,len,args,i,listeners;if(this._events||(this._events={}),\"error\"===type&&(!this._events.error||isObject(this._events.error)&&!this._events.error.length)){if(er=arguments[1],er instanceof Error)throw er;throw TypeError(\\'Uncaught, unspecified \"error\" event.\\')}if(handler=this._events[type],isUndefined(handler))return!1;if(isFunction(handler))switch(arguments.length){case 1:handler.call(this);break;case 2:handler.call(this,arguments[1]);break;case 3:handler.call(this,arguments[1],arguments[2]);break;default:for(len=arguments.length,args=Array(len-1),i=1;len>i;i++)args[i-1]=arguments[i];handler.apply(this,args)}else if(isObject(handler)){for(len=arguments.length,args=Array(len-1),i=1;len>i;i++)args[i-1]=arguments[i];for(listeners=handler.slice(),len=listeners.length,i=0;len>i;i++)listeners[i].apply(this,args)}return!0},EventEmitter.prototype.addListener=function(type,listener){var m;if(!isFunction(listener))throw TypeError(\"listener must be a function\");if(this._events||(this._events={}),this._events.newListener&&this.emit(\"newListener\",type,isFunction(listener.listener)?listener.listener:listener),this._events[type]?isObject(this._events[type])?this._events[type].push(listener):this._events[type]=[this._events[type],listener]:this._events[type]=listener,isObject(this._events[type])&&!this._events[type].warned){var m;m=isUndefined(this._maxListeners)?EventEmitter.defaultMaxListeners:this._maxListeners,m&&m>0&&this._events[type].length>m&&(this._events[type].warned=!0,console.error(\"(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.\",this._events[type].length),\"function\"==typeof console.trace&&console.trace())}return this},EventEmitter.prototype.on=EventEmitter.prototype.addListener,EventEmitter.prototype.once=function(type,listener){function g(){this.removeListener(type,g),fired||(fired=!0,listener.apply(this,arguments))}if(!isFunction(listener))throw TypeError(\"listener must be a function\");var fired=!1;return g.listener=listener,this.on(type,g),this},EventEmitter.prototype.removeListener=function(type,listener){var list,position,length,i;if(!isFunction(listener))throw TypeError(\"listener must be a function\");if(!this._events||!this._events[type])return this;if(list=this._events[type],length=list.length,position=-1,list===listener||isFunction(list.listener)&&list.listener===listener)delete this._events[type],this._events.removeListener&&this.emit(\"removeListener\",type,listener);else if(isObject(list)){for(i=length;i--\\x3e0;)if(list[i]===listener||list[i].listener&&list[i].listener===listener){position=i;break}if(0>position)return this;1===list.length?(list.length=0,delete this._events[type]):list.splice(position,1),this._events.removeListener&&this.emit(\"removeListener\",type,listener)}return this},EventEmitter.prototype.removeAllListeners=function(type){var key,listeners;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[type]&&delete this._events[type],this;if(0===arguments.length){for(key in this._events)\"removeListener\"!==key&&this.removeAllListeners(key);return this.removeAllListeners(\"removeListener\"),this._events={},this\\n}if(listeners=this._events[type],isFunction(listeners))this.removeListener(type,listeners);else for(;listeners.length;)this.removeListener(type,listeners[listeners.length-1]);return delete this._events[type],this},EventEmitter.prototype.listeners=function(type){var ret;return ret=this._events&&this._events[type]?isFunction(this._events[type])?[this._events[type]]:this._events[type].slice():[]},EventEmitter.listenerCount=function(emitter,type){var ret;return ret=emitter._events&&emitter._events[type]?isFunction(emitter._events[type])?1:emitter._events[type].length:0}},{}],\"/node_modules/jshint/data/ascii-identifier-data.js\":[function(_dereq_,module){for(var identifierStartTable=[],i=0;128>i;i++)identifierStartTable[i]=36===i||i>=65&&90>=i||95===i||i>=97&&122>=i;for(var identifierPartTable=[],i=0;128>i;i++)identifierPartTable[i]=identifierStartTable[i]||i>=48&&57>=i;module.exports={asciiIdentifierStartTable:identifierStartTable,asciiIdentifierPartTable:identifierPartTable}},{}],\"/node_modules/jshint/lodash.js\":[function(_dereq_,module,exports){(function(global){(function(){function baseFindIndex(array,predicate,fromRight){for(var length=array.length,index=fromRight?length:-1;fromRight?index--:length>++index;)if(predicate(array[index],index,array))return index;return-1}function baseIndexOf(array,value,fromIndex){if(value!==value)return indexOfNaN(array,fromIndex);for(var index=fromIndex-1,length=array.length;length>++index;)if(array[index]===value)return index;return-1}function baseIsFunction(value){return\"function\"==typeof value||!1}function baseToString(value){return\"string\"==typeof value?value:null==value?\"\":value+\"\"}function indexOfNaN(array,fromIndex,fromRight){for(var length=array.length,index=fromIndex+(fromRight?0:-1);fromRight?index--:length>++index;){var other=array[index];if(other!==other)return index}return-1}function isObjectLike(value){return!!value&&\"object\"==typeof value}function lodash(){}function arrayCopy(source,array){var index=-1,length=source.length;for(array||(array=Array(length));length>++index;)array[index]=source[index];return array}function arrayEach(array,iteratee){for(var index=-1,length=array.length;length>++index&&iteratee(array[index],index,array)!==!1;);return array}function arrayFilter(array,predicate){for(var index=-1,length=array.length,resIndex=-1,result=[];length>++index;){var value=array[index];predicate(value,index,array)&&(result[++resIndex]=value)}return result}function arrayMap(array,iteratee){for(var index=-1,length=array.length,result=Array(length);length>++index;)result[index]=iteratee(array[index],index,array);return result}function arrayMax(array){for(var index=-1,length=array.length,result=NEGATIVE_INFINITY;length>++index;){var value=array[index];value>result&&(result=value)}return result}function arraySome(array,predicate){for(var index=-1,length=array.length;length>++index;)if(predicate(array[index],index,array))return!0;return!1}function assignWith(object,source,customizer){var props=keys(source);push.apply(props,getSymbols(source));for(var index=-1,length=props.length;length>++index;){var key=props[index],value=object[key],result=customizer(value,source[key],key,object,source);(result===result?result===value:value!==value)&&(value!==undefined||key in object)||(object[key]=result)}return object}function baseCopy(source,props,object){object||(object={});for(var index=-1,length=props.length;length>++index;){var key=props[index];object[key]=source[key]}return object}function baseCallback(func,thisArg,argCount){var type=typeof func;return\"function\"==type?thisArg===undefined?func:bindCallback(func,thisArg,argCount):null==func?identity:\"object\"==type?baseMatches(func):thisArg===undefined?property(func):baseMatchesProperty(func,thisArg)}function baseClone(value,isDeep,customizer,key,object,stackA,stackB){var result;if(customizer&&(result=object?customizer(value,key,object):customizer(value)),result!==undefined)return result;if(!isObject(value))return value;var isArr=isArray(value);if(isArr){if(result=initCloneArray(value),!isDeep)return arrayCopy(value,result)}else{var tag=objToString.call(value),isFunc=tag==funcTag;if(tag!=objectTag&&tag!=argsTag&&(!isFunc||object))return cloneableTags[tag]?initCloneByTag(value,tag,isDeep):object?value:{};if(result=initCloneObject(isFunc?{}:value),!isDeep)return baseAssign(result,value)}stackA||(stackA=[]),stackB||(stackB=[]);for(var length=stackA.length;length--;)if(stackA[length]==value)return stackB[length];return stackA.push(value),stackB.push(result),(isArr?arrayEach:baseForOwn)(value,function(subValue,key){result[key]=baseClone(subValue,isDeep,customizer,key,value,stackA,stackB)}),result}function baseFilter(collection,predicate){var result=[];return baseEach(collection,function(value,index,collection){predicate(value,index,collection)&&result.push(value)}),result}function baseForIn(object,iteratee){return baseFor(object,iteratee,keysIn)}function baseForOwn(object,iteratee){return baseFor(object,iteratee,keys)}function baseGet(object,path,pathKey){if(null!=object){pathKey!==undefined&&pathKey in toObject(object)&&(path=[pathKey]);for(var index=-1,length=path.length;null!=object&&length>++index;)var result=object=object[path[index]];return result}}function baseIsEqual(value,other,customizer,isLoose,stackA,stackB){if(value===other)return 0!==value||1/value==1/other;var valType=typeof value,othType=typeof other;return\"function\"!=valType&&\"object\"!=valType&&\"function\"!=othType&&\"object\"!=othType||null==value||null==other?value!==value&&other!==other:baseIsEqualDeep(value,other,baseIsEqual,customizer,isLoose,stackA,stackB)}function baseIsEqualDeep(object,other,equalFunc,customizer,isLoose,stackA,stackB){var objIsArr=isArray(object),othIsArr=isArray(other),objTag=arrayTag,othTag=arrayTag;objIsArr||(objTag=objToString.call(object),objTag==argsTag?objTag=objectTag:objTag!=objectTag&&(objIsArr=isTypedArray(object))),othIsArr||(othTag=objToString.call(other),othTag==argsTag?othTag=objectTag:othTag!=objectTag&&(othIsArr=isTypedArray(other)));var objIsObj=objTag==objectTag,othIsObj=othTag==objectTag,isSameTag=objTag==othTag;if(isSameTag&&!objIsArr&&!objIsObj)return equalByTag(object,other,objTag);if(!isLoose){var valWrapped=objIsObj&&hasOwnProperty.call(object,\"__wrapped__\"),othWrapped=othIsObj&&hasOwnProperty.call(other,\"__wrapped__\");if(valWrapped||othWrapped)return equalFunc(valWrapped?object.value():object,othWrapped?other.value():other,customizer,isLoose,stackA,stackB)}if(!isSameTag)return!1;stackA||(stackA=[]),stackB||(stackB=[]);for(var length=stackA.length;length--;)if(stackA[length]==object)return stackB[length]==other;stackA.push(object),stackB.push(other);var result=(objIsArr?equalArrays:equalObjects)(object,other,equalFunc,customizer,isLoose,stackA,stackB);return stackA.pop(),stackB.pop(),result}function baseIsMatch(object,props,values,strictCompareFlags,customizer){for(var index=-1,length=props.length,noCustomizer=!customizer;length>++index;)if(noCustomizer&&strictCompareFlags[index]?values[index]!==object[props[index]]:!(props[index]in object))return!1;for(index=-1;length>++index;){var key=props[index],objValue=object[key],srcValue=values[index];if(noCustomizer&&strictCompareFlags[index])var result=objValue!==undefined||key in object;else result=customizer?customizer(objValue,srcValue,key):undefined,result===undefined&&(result=baseIsEqual(srcValue,objValue,customizer,!0));if(!result)return!1}return!0}function baseMatches(source){var props=keys(source),length=props.length;if(!length)return constant(!0);if(1==length){var key=props[0],value=source[key];if(isStrictComparable(value))return function(object){return null==object?!1:object[key]===value&&(value!==undefined||key in toObject(object))}}for(var values=Array(length),strictCompareFlags=Array(length);length--;)value=source[props[length]],values[length]=value,strictCompareFlags[length]=isStrictComparable(value);return function(object){return null!=object&&baseIsMatch(toObject(object),props,values,strictCompareFlags)}}function baseMatchesProperty(path,value){var isArr=isArray(path),isCommon=isKey(path)&&isStrictComparable(value),pathKey=path+\"\";return path=toPath(path),function(object){if(null==object)return!1;var key=pathKey;if(object=toObject(object),!(!isArr&&isCommon||key in object)){if(object=1==path.length?object:baseGet(object,baseSlice(path,0,-1)),null==object)return!1;key=last(path),object=toObject(object)}return object[key]===value?value!==undefined||key in object:baseIsEqual(value,object[key],null,!0)}}function baseMerge(object,source,customizer,stackA,stackB){if(!isObject(object))return object;var isSrcArr=isLength(source.length)&&(isArray(source)||isTypedArray(source));if(!isSrcArr){var props=keys(source);push.apply(props,getSymbols(source))}return arrayEach(props||source,function(srcValue,key){if(props&&(key=srcValue,srcValue=source[key]),isObjectLike(srcValue))stackA||(stackA=[]),stackB||(stackB=[]),baseMergeDeep(object,source,key,baseMerge,customizer,stackA,stackB);else{var value=object[key],result=customizer?customizer(value,srcValue,key,object,source):undefined,isCommon=result===undefined;isCommon&&(result=srcValue),!isSrcArr&&result===undefined||!isCommon&&(result===result?result===value:value!==value)||(object[key]=result)}}),object}function baseMergeDeep(object,source,key,mergeFunc,customizer,stackA,stackB){for(var length=stackA.length,srcValue=source[key];length--;)if(stackA[length]==srcValue)return object[key]=stackB[length],undefined;var value=object[key],result=customizer?customizer(value,srcValue,key,object,source):undefined,isCommon=result===undefined;isCommon&&(result=srcValue,isLength(srcValue.length)&&(isArray(srcValue)||isTypedArray(srcValue))?result=isArray(value)?value:getLength(value)?arrayCopy(value):[]:isPlainObject(srcValue)||isArguments(srcValue)?result=isArguments(value)?toPlainObject(value):isPlainObject(value)?value:{}:isCommon=!1),stackA.push(srcValue),stackB.push(result),isCommon?object[key]=mergeFunc(result,srcValue,customizer,stackA,stackB):(result===result?result!==value:value===value)&&(object[key]=result)}function baseProperty(key){return function(object){return null==object?undefined:object[key]}}function basePropertyDeep(path){var pathKey=path+\"\";return path=toPath(path),function(object){return baseGet(object,path,pathKey)}}function baseSlice(array,start,end){var index=-1,length=array.length;start=null==start?0:+start||0,0>start&&(start=-start>length?0:length+start),end=end===undefined||end>length?length:+end||0,0>end&&(end+=length),length=start>end?0:end-start>>>0,start>>>=0;for(var result=Array(length);length>++index;)result[index]=array[index+start];return result}function baseSome(collection,predicate){var result;return baseEach(collection,function(value,index,collection){return result=predicate(value,index,collection),!result}),!!result}function baseValues(object,props){for(var index=-1,length=props.length,result=Array(length);length>++index;)result[index]=object[props[index]];return result}function binaryIndex(array,value,retHighest){var low=0,high=array?array.length:low;if(\"number\"==typeof value&&value===value&&HALF_MAX_ARRAY_LENGTH>=high){for(;high>low;){var mid=low+high>>>1,computed=array[mid];(retHighest?value>=computed:value>computed)?low=mid+1:high=mid}return high}return binaryIndexBy(array,value,identity,retHighest)}function binaryIndexBy(array,value,iteratee,retHighest){value=iteratee(value);for(var low=0,high=array?array.length:0,valIsNaN=value!==value,valIsUndef=value===undefined;high>low;){var mid=floor((low+high)/2),computed=iteratee(array[mid]),isReflexive=computed===computed;if(valIsNaN)var setLow=isReflexive||retHighest;else setLow=valIsUndef?isReflexive&&(retHighest||computed!==undefined):retHighest?value>=computed:value>computed;setLow?low=mid+1:high=mid}return nativeMin(high,MAX_ARRAY_INDEX)}function bindCallback(func,thisArg,argCount){if(\"function\"!=typeof func)return identity;if(thisArg===undefined)return func;switch(argCount){case 1:return function(value){return func.call(thisArg,value)};case 3:return function(value,index,collection){return func.call(thisArg,value,index,collection)};case 4:return function(accumulator,value,index,collection){return func.call(thisArg,accumulator,value,index,collection)};case 5:return function(value,other,key,object,source){return func.call(thisArg,value,other,key,object,source)}}return function(){return func.apply(thisArg,arguments)}}function bufferClone(buffer){return bufferSlice.call(buffer,0)}function createAssigner(assigner){return restParam(function(object,sources){var index=-1,length=null==object?0:sources.length,customizer=length>2&&sources[length-2],guard=length>2&&sources[2],thisArg=length>1&&sources[length-1];for(\"function\"==typeof customizer?(customizer=bindCallback(customizer,thisArg,5),length-=2):(customizer=\"function\"==typeof thisArg?thisArg:null,length-=customizer?1:0),guard&&isIterateeCall(sources[0],sources[1],guard)&&(customizer=3>length?null:customizer,length=1);length>++index;){var source=sources[index];source&&assigner(object,source,customizer)}return object})}function createBaseEach(eachFunc,fromRight){return function(collection,iteratee){var length=collection?getLength(collection):0;if(!isLength(length))return eachFunc(collection,iteratee);for(var index=fromRight?length:-1,iterable=toObject(collection);(fromRight?index--:length>++index)&&iteratee(iterable[index],index,iterable)!==!1;);return collection}}function createBaseFor(fromRight){return function(object,iteratee,keysFunc){for(var iterable=toObject(object),props=keysFunc(object),length=props.length,index=fromRight?length:-1;fromRight?index--:length>++index;){var key=props[index];if(iteratee(iterable[key],key,iterable)===!1)break}return object}}function createFindIndex(fromRight){return function(array,predicate,thisArg){return array&&array.length?(predicate=getCallback(predicate,thisArg,3),baseFindIndex(array,predicate,fromRight)):-1}}function createForEach(arrayFunc,eachFunc){return function(collection,iteratee,thisArg){return\"function\"==typeof iteratee&&thisArg===undefined&&isArray(collection)?arrayFunc(collection,iteratee):eachFunc(collection,bindCallback(iteratee,thisArg,3))}}function equalArrays(array,other,equalFunc,customizer,isLoose,stackA,stackB){var index=-1,arrLength=array.length,othLength=other.length,result=!0;if(arrLength!=othLength&&!(isLoose&&othLength>arrLength))return!1;for(;result&&arrLength>++index;){var arrValue=array[index],othValue=other[index];if(result=undefined,customizer&&(result=isLoose?customizer(othValue,arrValue,index):customizer(arrValue,othValue,index)),result===undefined)if(isLoose)for(var othIndex=othLength;othIndex--&&(othValue=other[othIndex],!(result=arrValue&&arrValue===othValue||equalFunc(arrValue,othValue,customizer,isLoose,stackA,stackB))););else result=arrValue&&arrValue===othValue||equalFunc(arrValue,othValue,customizer,isLoose,stackA,stackB)}return!!result}function equalByTag(object,other,tag){switch(tag){case boolTag:case dateTag:return+object==+other;case errorTag:return object.name==other.name&&object.message==other.message;case numberTag:return object!=+object?other!=+other:0==object?1/object==1/other:object==+other;case regexpTag:case stringTag:return object==other+\"\"}return!1}function equalObjects(object,other,equalFunc,customizer,isLoose,stackA,stackB){var objProps=keys(object),objLength=objProps.length,othProps=keys(other),othLength=othProps.length;if(objLength!=othLength&&!isLoose)return!1;for(var skipCtor=isLoose,index=-1;objLength>++index;){var key=objProps[index],result=isLoose?key in other:hasOwnProperty.call(other,key);if(result){var objValue=object[key],othValue=other[key];result=undefined,customizer&&(result=isLoose?customizer(othValue,objValue,key):customizer(objValue,othValue,key)),result===undefined&&(result=objValue&&objValue===othValue||equalFunc(objValue,othValue,customizer,isLoose,stackA,stackB))}if(!result)return!1;skipCtor||(skipCtor=\"constructor\"==key)}if(!skipCtor){var objCtor=object.constructor,othCtor=other.constructor;if(objCtor!=othCtor&&\"constructor\"in object&&\"constructor\"in other&&!(\"function\"==typeof objCtor&&objCtor instanceof objCtor&&\"function\"==typeof othCtor&&othCtor instanceof othCtor))return!1}return!0}function getCallback(func,thisArg,argCount){var result=lodash.callback||callback;return result=result===callback?baseCallback:result,argCount?result(func,thisArg,argCount):result}function getIndexOf(collection,target,fromIndex){var result=lodash.indexOf||indexOf;return result=result===indexOf?baseIndexOf:result,collection?result(collection,target,fromIndex):result}function initCloneArray(array){var length=array.length,result=new array.constructor(length);return length&&\"string\"==typeof array[0]&&hasOwnProperty.call(array,\"index\")&&(result.index=array.index,result.input=array.input),result}function initCloneObject(object){var Ctor=object.constructor;return\"function\"==typeof Ctor&&Ctor instanceof Ctor||(Ctor=Object),new Ctor}function initCloneByTag(object,tag,isDeep){var Ctor=object.constructor;switch(tag){case arrayBufferTag:return bufferClone(object);case boolTag:case dateTag:return new Ctor(+object);case float32Tag:case float64Tag:case int8Tag:case int16Tag:case int32Tag:case uint8Tag:case uint8ClampedTag:case uint16Tag:case uint32Tag:var buffer=object.buffer;return new Ctor(isDeep?bufferClone(buffer):buffer,object.byteOffset,object.length);case numberTag:case stringTag:return new Ctor(object);case regexpTag:var result=new Ctor(object.source,reFlags.exec(object));result.lastIndex=object.lastIndex}return result}function isIndex(value,length){return value=+value,length=null==length?MAX_SAFE_INTEGER:length,value>-1&&0==value%1&&length>value}function isIterateeCall(value,index,object){if(!isObject(object))return!1;var type=typeof index;if(\"number\"==type)var length=getLength(object),prereq=isLength(length)&&isIndex(index,length);else prereq=\"string\"==type&&index in object;if(prereq){var other=object[index];return value===value?value===other:other!==other}return!1}function isKey(value,object){var type=typeof value;if(\"string\"==type&&reIsPlainProp.test(value)||\"number\"==type)return!0;if(isArray(value))return!1;var result=!reIsDeepProp.test(value);return result||null!=object&&value in toObject(object)}function isLength(value){return\"number\"==typeof value&&value>-1&&0==value%1&&MAX_SAFE_INTEGER>=value}function isStrictComparable(value){return value===value&&(0===value?1/value>0:!isObject(value))}function shimIsPlainObject(value){var Ctor;if(lodash.support,!isObjectLike(value)||objToString.call(value)!=objectTag||!hasOwnProperty.call(value,\"constructor\")&&(Ctor=value.constructor,\"function\"==typeof Ctor&&!(Ctor instanceof Ctor)))return!1;var result;return baseForIn(value,function(subValue,key){result=key}),result===undefined||hasOwnProperty.call(value,result)}function shimKeys(object){for(var props=keysIn(object),propsLength=props.length,length=propsLength&&object.length,support=lodash.support,allowIndexes=length&&isLength(length)&&(isArray(object)||support.nonEnumArgs&&isArguments(object)),index=-1,result=[];propsLength>++index;){var key=props[index];(allowIndexes&&isIndex(key,length)||hasOwnProperty.call(object,key))&&result.push(key)}return result}function toObject(value){return isObject(value)?value:Object(value)}function toPath(value){if(isArray(value))return value;var result=[];return baseToString(value).replace(rePropName,function(match,number,quote,string){result.push(quote?string.replace(reEscapeChar,\"$1\"):number||match)}),result}function indexOf(array,value,fromIndex){var length=array?array.length:0;if(!length)return-1;if(\"number\"==typeof fromIndex)fromIndex=0>fromIndex?nativeMax(length+fromIndex,0):fromIndex;else if(fromIndex){var index=binaryIndex(array,value),other=array[index];return(value===value?value===other:other!==other)?index:-1}return baseIndexOf(array,value,fromIndex||0)}function last(array){var length=array?array.length:0;return length?array[length-1]:undefined}function slice(array,start,end){var length=array?array.length:0;return length?(end&&\"number\"!=typeof end&&isIterateeCall(array,start,end)&&(start=0,end=length),baseSlice(array,start,end)):[]}function unzip(array){for(var index=-1,length=(array&&array.length&&arrayMax(arrayMap(array,getLength)))>>>0,result=Array(length);length>++index;)result[index]=arrayMap(array,baseProperty(index));return result}function includes(collection,target,fromIndex,guard){var length=collection?getLength(collection):0;return isLength(length)||(collection=values(collection),length=collection.length),length?(fromIndex=\"number\"!=typeof fromIndex||guard&&isIterateeCall(target,fromIndex,guard)?0:0>fromIndex?nativeMax(length+fromIndex,0):fromIndex||0,\"string\"==typeof collection||!isArray(collection)&&isString(collection)?length>fromIndex&&collection.indexOf(target,fromIndex)>-1:getIndexOf(collection,target,fromIndex)>-1):!1}function reject(collection,predicate,thisArg){var func=isArray(collection)?arrayFilter:baseFilter;return predicate=getCallback(predicate,thisArg,3),func(collection,function(value,index,collection){return!predicate(value,index,collection)})}function some(collection,predicate,thisArg){var func=isArray(collection)?arraySome:baseSome;return thisArg&&isIterateeCall(collection,predicate,thisArg)&&(predicate=null),(\"function\"!=typeof predicate||thisArg!==undefined)&&(predicate=getCallback(predicate,thisArg,3)),func(collection,predicate)}function restParam(func,start){if(\"function\"!=typeof func)throw new TypeError(FUNC_ERROR_TEXT);return start=nativeMax(start===undefined?func.length-1:+start||0,0),function(){for(var args=arguments,index=-1,length=nativeMax(args.length-start,0),rest=Array(length);length>++index;)rest[index]=args[start+index];switch(start){case 0:return func.call(this,rest);case 1:return func.call(this,args[0],rest);case 2:return func.call(this,args[0],args[1],rest)}var otherArgs=Array(start+1);for(index=-1;start>++index;)otherArgs[index]=args[index];return otherArgs[start]=rest,func.apply(this,otherArgs)}}function clone(value,isDeep,customizer,thisArg){return isDeep&&\"boolean\"!=typeof isDeep&&isIterateeCall(value,isDeep,customizer)?isDeep=!1:\"function\"==typeof isDeep&&(thisArg=customizer,customizer=isDeep,isDeep=!1),customizer=\"function\"==typeof customizer&&bindCallback(customizer,thisArg,1),baseClone(value,isDeep,customizer)}function isArguments(value){var length=isObjectLike(value)?value.length:undefined;return isLength(length)&&objToString.call(value)==argsTag}function isEmpty(value){if(null==value)return!0;var length=getLength(value);return isLength(length)&&(isArray(value)||isString(value)||isArguments(value)||isObjectLike(value)&&isFunction(value.splice))?!length:!keys(value).length}function isObject(value){var type=typeof value;return\"function\"==type||!!value&&\"object\"==type}function isNative(value){return null==value?!1:objToString.call(value)==funcTag?reIsNative.test(fnToString.call(value)):isObjectLike(value)&&reIsHostCtor.test(value)}function isNumber(value){return\"number\"==typeof value||isObjectLike(value)&&objToString.call(value)==numberTag}function isString(value){return\"string\"==typeof value||isObjectLike(value)&&objToString.call(value)==stringTag}function isTypedArray(value){return isObjectLike(value)&&isLength(value.length)&&!!typedArrayTags[objToString.call(value)]}function toPlainObject(value){return baseCopy(value,keysIn(value))}function has(object,path){if(null==object)return!1;var result=hasOwnProperty.call(object,path);return result||isKey(path)||(path=toPath(path),object=1==path.length?object:baseGet(object,baseSlice(path,0,-1)),path=last(path),result=null!=object&&hasOwnProperty.call(object,path)),result}function keysIn(object){if(null==object)return[];isObject(object)||(object=Object(object));var length=object.length;length=length&&isLength(length)&&(isArray(object)||support.nonEnumArgs&&isArguments(object))&&length||0;for(var Ctor=object.constructor,index=-1,isProto=\"function\"==typeof Ctor&&Ctor.prototype===object,result=Array(length),skipIndexes=length>0;length>++index;)result[index]=index+\"\";for(var key in object)skipIndexes&&isIndex(key,length)||\"constructor\"==key&&(isProto||!hasOwnProperty.call(object,key))||result.push(key);return result}function values(object){return baseValues(object,keys(object))}function escapeRegExp(string){return string=baseToString(string),string&&reHasRegExpChars.test(string)?string.replace(reRegExpChars,\"\\\\\\\\$&\"):string}function callback(func,thisArg,guard){return guard&&isIterateeCall(func,thisArg,guard)&&(thisArg=null),baseCallback(func,thisArg)}function constant(value){return function(){return value}}function identity(value){return value}function property(path){return isKey(path)?baseProperty(path):basePropertyDeep(path)}var undefined,VERSION=\"3.7.0\",FUNC_ERROR_TEXT=\"Expected a function\",argsTag=\"[object Arguments]\",arrayTag=\"[object Array]\",boolTag=\"[object Boolean]\",dateTag=\"[object Date]\",errorTag=\"[object Error]\",funcTag=\"[object Function]\",mapTag=\"[object Map]\",numberTag=\"[object Number]\",objectTag=\"[object Object]\",regexpTag=\"[object RegExp]\",setTag=\"[object Set]\",stringTag=\"[object String]\",weakMapTag=\"[object WeakMap]\",arrayBufferTag=\"[object ArrayBuffer]\",float32Tag=\"[object Float32Array]\",float64Tag=\"[object Float64Array]\",int8Tag=\"[object Int8Array]\",int16Tag=\"[object Int16Array]\",int32Tag=\"[object Int32Array]\",uint8Tag=\"[object Uint8Array]\",uint8ClampedTag=\"[object Uint8ClampedArray]\",uint16Tag=\"[object Uint16Array]\",uint32Tag=\"[object Uint32Array]\",reIsDeepProp=/\\\\.|\\\\[(?:[^[\\\\]]+|([\"\\'])(?:(?!\\\\1)[^\\\\n\\\\\\\\]|\\\\\\\\.)*?)\\\\1\\\\]/,reIsPlainProp=/^\\\\w*$/,rePropName=/[^.[\\\\]]+|\\\\[(?:(-?\\\\d+(?:\\\\.\\\\d+)?)|([\"\\'])((?:(?!\\\\2)[^\\\\n\\\\\\\\]|\\\\\\\\.)*?)\\\\2)\\\\]/g,reRegExpChars=/[.*+?^${}()|[\\\\]\\\\/\\\\\\\\]/g,reHasRegExpChars=RegExp(reRegExpChars.source),reEscapeChar=/\\\\\\\\(\\\\\\\\)?/g,reFlags=/\\\\w*$/,reIsHostCtor=/^\\\\[object .+?Constructor\\\\]$/,typedArrayTags={};typedArrayTags[float32Tag]=typedArrayTags[float64Tag]=typedArrayTags[int8Tag]=typedArrayTags[int16Tag]=typedArrayTags[int32Tag]=typedArrayTags[uint8Tag]=typedArrayTags[uint8ClampedTag]=typedArrayTags[uint16Tag]=typedArrayTags[uint32Tag]=!0,typedArrayTags[argsTag]=typedArrayTags[arrayTag]=typedArrayTags[arrayBufferTag]=typedArrayTags[boolTag]=typedArrayTags[dateTag]=typedArrayTags[errorTag]=typedArrayTags[funcTag]=typedArrayTags[mapTag]=typedArrayTags[numberTag]=typedArrayTags[objectTag]=typedArrayTags[regexpTag]=typedArrayTags[setTag]=typedArrayTags[stringTag]=typedArrayTags[weakMapTag]=!1;var cloneableTags={};cloneableTags[argsTag]=cloneableTags[arrayTag]=cloneableTags[arrayBufferTag]=cloneableTags[boolTag]=cloneableTags[dateTag]=cloneableTags[float32Tag]=cloneableTags[float64Tag]=cloneableTags[int8Tag]=cloneableTags[int16Tag]=cloneableTags[int32Tag]=cloneableTags[numberTag]=cloneableTags[objectTag]=cloneableTags[regexpTag]=cloneableTags[stringTag]=cloneableTags[uint8Tag]=cloneableTags[uint8ClampedTag]=cloneableTags[uint16Tag]=cloneableTags[uint32Tag]=!0,cloneableTags[errorTag]=cloneableTags[funcTag]=cloneableTags[mapTag]=cloneableTags[setTag]=cloneableTags[weakMapTag]=!1;var objectTypes={\"function\":!0,object:!0},freeExports=objectTypes[typeof exports]&&exports&&!exports.nodeType&&exports,freeModule=objectTypes[typeof module]&&module&&!module.nodeType&&module,freeGlobal=freeExports&&freeModule&&\"object\"==typeof global&&global&&global.Object&&global,freeSelf=objectTypes[typeof self]&&self&&self.Object&&self,freeWindow=objectTypes[typeof window]&&window&&window.Object&&window,moduleExports=freeModule&&freeModule.exports===freeExports&&freeExports,root=freeGlobal||freeWindow!==(this&&this.window)&&freeWindow||freeSelf||this,arrayProto=Array.prototype,objectProto=Object.prototype,fnToString=Function.prototype.toString,hasOwnProperty=objectProto.hasOwnProperty,objToString=objectProto.toString,reIsNative=RegExp(\"^\"+escapeRegExp(objToString).replace(/toString|(function).*?(?=\\\\\\\\\\\\()| for .+?(?=\\\\\\\\\\\\])/g,\"$1.*?\")+\"$\"),ArrayBuffer=isNative(ArrayBuffer=root.ArrayBuffer)&&ArrayBuffer,bufferSlice=isNative(bufferSlice=ArrayBuffer&&new ArrayBuffer(0).slice)&&bufferSlice,floor=Math.floor,getOwnPropertySymbols=isNative(getOwnPropertySymbols=Object.getOwnPropertySymbols)&&getOwnPropertySymbols,getPrototypeOf=isNative(getPrototypeOf=Object.getPrototypeOf)&&getPrototypeOf,push=arrayProto.push,preventExtensions=isNative(Object.preventExtensions=Object.preventExtensions)&&preventExtensions,propertyIsEnumerable=objectProto.propertyIsEnumerable,Uint8Array=isNative(Uint8Array=root.Uint8Array)&&Uint8Array,Float64Array=function(){try{var func=isNative(func=root.Float64Array)&&func,result=new func(new ArrayBuffer(10),0,1)&&func}catch(e){}return result}(),nativeAssign=function(){var object={1:0},func=preventExtensions&&isNative(func=Object.assign)&&func;try{func(preventExtensions(object),\"xo\")}catch(e){}return!object[1]&&func}(),nativeIsArray=isNative(nativeIsArray=Array.isArray)&&nativeIsArray,nativeKeys=isNative(nativeKeys=Object.keys)&&nativeKeys,nativeMax=Math.max,nativeMin=Math.min,NEGATIVE_INFINITY=Number.NEGATIVE_INFINITY,MAX_ARRAY_LENGTH=Math.pow(2,32)-1,MAX_ARRAY_INDEX=MAX_ARRAY_LENGTH-1,HALF_MAX_ARRAY_LENGTH=MAX_ARRAY_LENGTH>>>1,FLOAT64_BYTES_PER_ELEMENT=Float64Array?Float64Array.BYTES_PER_ELEMENT:0,MAX_SAFE_INTEGER=Math.pow(2,53)-1,support=lodash.support={};(function(x){var Ctor=function(){this.x=x},props=[];Ctor.prototype={valueOf:x,y:x};for(var key in new Ctor)props.push(key);support.funcDecomp=/\\\\bthis\\\\b/.test(function(){return this}),support.funcNames=\"string\"==typeof Function.name;try{support.nonEnumArgs=!propertyIsEnumerable.call(arguments,1)}catch(e){support.nonEnumArgs=!0}})(1,0);var baseAssign=nativeAssign||function(object,source){return null==source?object:baseCopy(source,getSymbols(source),baseCopy(source,keys(source),object))},baseEach=createBaseEach(baseForOwn),baseFor=createBaseFor();bufferSlice||(bufferClone=ArrayBuffer&&Uint8Array?function(buffer){var byteLength=buffer.byteLength,floatLength=Float64Array?floor(byteLength/FLOAT64_BYTES_PER_ELEMENT):0,offset=floatLength*FLOAT64_BYTES_PER_ELEMENT,result=new ArrayBuffer(byteLength);if(floatLength){var view=new Float64Array(result,0,floatLength);view.set(new Float64Array(buffer,0,floatLength))}return byteLength!=offset&&(view=new Uint8Array(result,offset),view.set(new Uint8Array(buffer,offset))),result}:constant(null));var getLength=baseProperty(\"length\"),getSymbols=getOwnPropertySymbols?function(object){return getOwnPropertySymbols(toObject(object))}:constant([]),findLastIndex=createFindIndex(!0),zip=restParam(unzip),forEach=createForEach(arrayEach,baseEach),isArray=nativeIsArray||function(value){return isObjectLike(value)&&isLength(value.length)&&objToString.call(value)==arrayTag},isFunction=baseIsFunction(/x/)||Uint8Array&&!baseIsFunction(Uint8Array)?function(value){return objToString.call(value)==funcTag}:baseIsFunction,isPlainObject=getPrototypeOf?function(value){if(!value||objToString.call(value)!=objectTag)return!1;var valueOf=value.valueOf,objProto=isNative(valueOf)&&(objProto=getPrototypeOf(valueOf))&&getPrototypeOf(objProto);return objProto?value==objProto||getPrototypeOf(value)==objProto:shimIsPlainObject(value)}:shimIsPlainObject,assign=createAssigner(function(object,source,customizer){return customizer?assignWith(object,source,customizer):baseAssign(object,source)}),keys=nativeKeys?function(object){if(object)var Ctor=object.constructor,length=object.length;return\"function\"==typeof Ctor&&Ctor.prototype===object||\"function\"!=typeof object&&isLength(length)?shimKeys(object):isObject(object)?nativeKeys(object):[]}:shimKeys,merge=createAssigner(baseMerge);lodash.assign=assign,lodash.callback=callback,lodash.constant=constant,lodash.forEach=forEach,lodash.keys=keys,lodash.keysIn=keysIn,lodash.merge=merge,lodash.property=property,lodash.reject=reject,lodash.restParam=restParam,lodash.slice=slice,lodash.toPlainObject=toPlainObject,lodash.unzip=unzip,lodash.values=values,lodash.zip=zip,lodash.each=forEach,lodash.extend=assign,lodash.iteratee=callback,lodash.clone=clone,lodash.escapeRegExp=escapeRegExp,lodash.findLastIndex=findLastIndex,lodash.has=has,lodash.identity=identity,lodash.includes=includes,lodash.indexOf=indexOf,lodash.isArguments=isArguments,lodash.isArray=isArray,lodash.isEmpty=isEmpty,lodash.isFunction=isFunction,lodash.isNative=isNative,lodash.isNumber=isNumber,lodash.isObject=isObject,lodash.isPlainObject=isPlainObject,lodash.isString=isString,lodash.isTypedArray=isTypedArray,lodash.last=last,lodash.some=some,lodash.any=some,lodash.contains=includes,lodash.include=includes,lodash.VERSION=VERSION,freeExports&&freeModule?moduleExports?(freeModule.exports=lodash)._=lodash:freeExports._=lodash:root._=lodash\\n}).call(this)}).call(this,\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{})},{}],\"/node_modules/jshint/src/jshint.js\":[function(_dereq_,module,exports){var _=_dereq_(\"../lodash\"),events=_dereq_(\"events\"),vars=_dereq_(\"./vars.js\"),messages=_dereq_(\"./messages.js\"),Lexer=_dereq_(\"./lex.js\").Lexer,reg=_dereq_(\"./reg.js\"),state=_dereq_(\"./state.js\").state,style=_dereq_(\"./style.js\"),options=_dereq_(\"./options.js\"),scopeManager=_dereq_(\"./scope-manager.js\"),JSHINT=function(){\"use strict\";function checkOption(name,t){return name=name.trim(),/^[+-]W\\\\d{3}$/g.test(name)?!0:-1!==options.validNames.indexOf(name)||\"jslint\"===t.type||_.has(options.removed,name)?!0:(error(\"E001\",t,name),!1)}function isString(obj){return\"[object String]\"===Object.prototype.toString.call(obj)}function isIdentifier(tkn,value){return tkn?tkn.identifier&&tkn.value===value?!0:!1:!1}function isReserved(token){if(!token.reserved)return!1;var meta=token.meta;if(meta&&meta.isFutureReservedWord&&state.inES5()){if(!meta.es5)return!1;if(meta.strictOnly&&!state.option.strict&&!state.isStrict())return!1;if(token.isProperty)return!1}return!0}function supplant(str,data){return str.replace(/\\\\{([^{}]*)\\\\}/g,function(a,b){var r=data[b];return\"string\"==typeof r||\"number\"==typeof r?r:a})}function combine(dest,src){Object.keys(src).forEach(function(name){_.has(JSHINT.blacklist,name)||(dest[name]=src[name])})}function processenforceall(){if(state.option.enforceall){for(var enforceopt in options.bool.enforcing)void 0!==state.option[enforceopt]||options.noenforceall[enforceopt]||(state.option[enforceopt]=!0);for(var relaxopt in options.bool.relaxing)void 0===state.option[relaxopt]&&(state.option[relaxopt]=!1)}}function assume(){processenforceall(),state.option.esversion||state.option.moz||(state.option.esversion=state.option.es3?3:state.option.esnext?6:5),state.inES5()&&combine(predefined,vars.ecmaIdentifiers[5]),state.inES6()&&combine(predefined,vars.ecmaIdentifiers[6]),state.option.module&&(state.option.strict===!0&&(state.option.strict=\"global\"),state.inES6()||warning(\"W134\",state.tokens.next,\"module\",6)),state.option.couch&&combine(predefined,vars.couch),state.option.qunit&&combine(predefined,vars.qunit),state.option.rhino&&combine(predefined,vars.rhino),state.option.shelljs&&(combine(predefined,vars.shelljs),combine(predefined,vars.node)),state.option.typed&&combine(predefined,vars.typed),state.option.phantom&&(combine(predefined,vars.phantom),state.option.strict===!0&&(state.option.strict=\"global\")),state.option.prototypejs&&combine(predefined,vars.prototypejs),state.option.node&&(combine(predefined,vars.node),combine(predefined,vars.typed),state.option.strict===!0&&(state.option.strict=\"global\")),state.option.devel&&combine(predefined,vars.devel),state.option.dojo&&combine(predefined,vars.dojo),state.option.browser&&(combine(predefined,vars.browser),combine(predefined,vars.typed)),state.option.browserify&&(combine(predefined,vars.browser),combine(predefined,vars.typed),combine(predefined,vars.browserify),state.option.strict===!0&&(state.option.strict=\"global\")),state.option.nonstandard&&combine(predefined,vars.nonstandard),state.option.jasmine&&combine(predefined,vars.jasmine),state.option.jquery&&combine(predefined,vars.jquery),state.option.mootools&&combine(predefined,vars.mootools),state.option.worker&&combine(predefined,vars.worker),state.option.wsh&&combine(predefined,vars.wsh),state.option.globalstrict&&state.option.strict!==!1&&(state.option.strict=\"global\"),state.option.yui&&combine(predefined,vars.yui),state.option.mocha&&combine(predefined,vars.mocha)}function quit(code,line,chr){var percentage=Math.floor(100*(line/state.lines.length)),message=messages.errors[code].desc;throw{name:\"JSHintError\",line:line,character:chr,message:message+\" (\"+percentage+\"% scanned).\",raw:message,code:code}}function removeIgnoredMessages(){var ignored=state.ignoredLines;_.isEmpty(ignored)||(JSHINT.errors=_.reject(JSHINT.errors,function(err){return ignored[err.line]}))}function warning(code,t,a,b,c,d){var ch,l,w,msg;if(/^W\\\\d{3}$/.test(code)){if(state.ignored[code])return;msg=messages.warnings[code]}else/E\\\\d{3}/.test(code)?msg=messages.errors[code]:/I\\\\d{3}/.test(code)&&(msg=messages.info[code]);return t=t||state.tokens.next||{},\"(end)\"===t.id&&(t=state.tokens.curr),l=t.line||0,ch=t.from||0,w={id:\"(error)\",raw:msg.desc,code:msg.code,evidence:state.lines[l-1]||\"\",line:l,character:ch,scope:JSHINT.scope,a:a,b:b,c:c,d:d},w.reason=supplant(msg.desc,w),JSHINT.errors.push(w),removeIgnoredMessages(),JSHINT.errors.length>=state.option.maxerr&&quit(\"E043\",l,ch),w}function warningAt(m,l,ch,a,b,c,d){return warning(m,{line:l,from:ch},a,b,c,d)}function error(m,t,a,b,c,d){warning(m,t,a,b,c,d)}function errorAt(m,l,ch,a,b,c,d){return error(m,{line:l,from:ch},a,b,c,d)}function addInternalSrc(elem,src){var i;return i={id:\"(internal)\",elem:elem,value:src},JSHINT.internals.push(i),i}function doOption(){var nt=state.tokens.next,body=nt.body.match(/(-\\\\s+)?[^\\\\s,:]+(?:\\\\s*:\\\\s*(-\\\\s+)?[^\\\\s,]+)?/g)||[],predef={};if(\"globals\"===nt.type){body.forEach(function(g,idx){g=g.split(\":\");var key=(g[0]||\"\").trim(),val=(g[1]||\"\").trim();if(\"-\"===key||!key.length){if(idx>0&&idx===body.length-1)return;return error(\"E002\",nt),void 0}\"-\"===key.charAt(0)?(key=key.slice(1),val=!1,JSHINT.blacklist[key]=key,delete predefined[key]):predef[key]=\"true\"===val}),combine(predefined,predef);for(var key in predef)_.has(predef,key)&&(declared[key]=nt)}\"exported\"===nt.type&&body.forEach(function(e,idx){if(!e.length){if(idx>0&&idx===body.length-1)return;return error(\"E002\",nt),void 0}state.funct[\"(scope)\"].addExported(e)}),\"members\"===nt.type&&(membersOnly=membersOnly||{},body.forEach(function(m){var ch1=m.charAt(0),ch2=m.charAt(m.length-1);ch1!==ch2||\\'\"\\'!==ch1&&\"\\'\"!==ch1||(m=m.substr(1,m.length-2).replace(\\'\\\\\\\\\"\\',\\'\"\\')),membersOnly[m]=!1}));var numvals=[\"maxstatements\",\"maxparams\",\"maxdepth\",\"maxcomplexity\",\"maxerr\",\"maxlen\",\"indent\"];(\"jshint\"===nt.type||\"jslint\"===nt.type)&&(body.forEach(function(g){g=g.split(\":\");var key=(g[0]||\"\").trim(),val=(g[1]||\"\").trim();if(checkOption(key,nt))if(numvals.indexOf(key)>=0)if(\"false\"!==val){if(val=+val,\"number\"!=typeof val||!isFinite(val)||0>=val||Math.floor(val)!==val)return error(\"E032\",nt,g[1].trim()),void 0;state.option[key]=val}else state.option[key]=\"indent\"===key?4:!1;else{if(\"validthis\"===key)return state.funct[\"(global)\"]?void error(\"E009\"):\"true\"!==val&&\"false\"!==val?void error(\"E002\",nt):(state.option.validthis=\"true\"===val,void 0);if(\"quotmark\"!==key)if(\"shadow\"!==key)if(\"unused\"!==key)if(\"latedef\"!==key)if(\"ignore\"!==key)if(\"strict\"!==key){\"module\"===key&&(hasParsedCode(state.funct)||error(\"E055\",state.tokens.next,\"module\"));var esversions={es3:3,es5:5,esnext:6};if(!_.has(esversions,key)){if(\"esversion\"===key){switch(val){case\"5\":state.inES5(!0)&&warning(\"I003\");case\"3\":case\"6\":state.option.moz=!1,state.option.esversion=+val;break;case\"2015\":state.option.moz=!1,state.option.esversion=6;break;default:error(\"E002\",nt)}return hasParsedCode(state.funct)||error(\"E055\",state.tokens.next,\"esversion\"),void 0}var match=/^([+-])(W\\\\d{3})$/g.exec(key);if(match)return state.ignored[match[2]]=\"-\"===match[1],void 0;var tn;return\"true\"===val||\"false\"===val?(\"jslint\"===nt.type?(tn=options.renamed[key]||key,state.option[tn]=\"true\"===val,void 0!==options.inverted[tn]&&(state.option[tn]=!state.option[tn])):state.option[key]=\"true\"===val,\"newcap\"===key&&(state.option[\"(explicitNewcap)\"]=!0),void 0):(error(\"E002\",nt),void 0)}switch(val){case\"true\":state.option.moz=!1,state.option.esversion=esversions[key];break;case\"false\":state.option.moz||(state.option.esversion=5);break;default:error(\"E002\",nt)}}else switch(val){case\"true\":state.option.strict=!0;break;case\"false\":state.option.strict=!1;break;case\"func\":case\"global\":case\"implied\":state.option.strict=val;break;default:error(\"E002\",nt)}else switch(val){case\"line\":state.ignoredLines[nt.line]=!0,removeIgnoredMessages();break;default:error(\"E002\",nt)}else switch(val){case\"true\":state.option.latedef=!0;break;case\"false\":state.option.latedef=!1;break;case\"nofunc\":state.option.latedef=\"nofunc\";break;default:error(\"E002\",nt)}else switch(val){case\"true\":state.option.unused=!0;break;case\"false\":state.option.unused=!1;break;case\"vars\":case\"strict\":state.option.unused=val;break;default:error(\"E002\",nt)}else switch(val){case\"true\":state.option.shadow=!0;break;case\"outer\":state.option.shadow=\"outer\";break;case\"false\":case\"inner\":state.option.shadow=\"inner\";break;default:error(\"E002\",nt)}else switch(val){case\"true\":case\"false\":state.option.quotmark=\"true\"===val;break;case\"double\":case\"single\":state.option.quotmark=val;break;default:error(\"E002\",nt)}}}),assume())}function peek(p){var t,i=p||0,j=lookahead.length;if(j>i)return lookahead[i];for(;i>=j;)t=lookahead[j],t||(t=lookahead[j]=lex.token()),j+=1;return t||\"(end)\"!==state.tokens.next.id?t:state.tokens.next}function peekIgnoreEOL(){var t,i=0;do t=peek(i++);while(\"(endline)\"===t.id);return t}function advance(id,t){switch(state.tokens.curr.id){case\"(number)\":\".\"===state.tokens.next.id&&warning(\"W005\",state.tokens.curr);break;case\"-\":(\"-\"===state.tokens.next.id||\"--\"===state.tokens.next.id)&&warning(\"W006\");break;case\"+\":(\"+\"===state.tokens.next.id||\"++\"===state.tokens.next.id)&&warning(\"W007\")}for(id&&state.tokens.next.id!==id&&(t?\"(end)\"===state.tokens.next.id?error(\"E019\",t,t.id):error(\"E020\",state.tokens.next,id,t.id,t.line,state.tokens.next.value):(\"(identifier)\"!==state.tokens.next.type||state.tokens.next.value!==id)&&warning(\"W116\",state.tokens.next,id,state.tokens.next.value)),state.tokens.prev=state.tokens.curr,state.tokens.curr=state.tokens.next;;){if(state.tokens.next=lookahead.shift()||lex.token(),state.tokens.next||quit(\"E041\",state.tokens.curr.line),\"(end)\"===state.tokens.next.id||\"(error)\"===state.tokens.next.id)return;if(state.tokens.next.check&&state.tokens.next.check(),state.tokens.next.isSpecial)\"falls through\"===state.tokens.next.type?state.tokens.curr.caseFallsThrough=!0:doOption();else if(\"(endline)\"!==state.tokens.next.id)break}}function isInfix(token){return token.infix||!token.identifier&&!token.template&&!!token.led}function isEndOfExpr(){var curr=state.tokens.curr,next=state.tokens.next;return\";\"===next.id||\"}\"===next.id||\":\"===next.id?!0:isInfix(next)===isInfix(curr)||\"yield\"===curr.id&&state.inMoz()?curr.line!==startLine(next):!1}function isBeginOfExpr(prev){return!prev.left&&\"unary\"!==prev.arity}function expression(rbp,initial){var left,isArray=!1,isObject=!1,isLetExpr=!1;state.nameStack.push(),initial||\"let\"!==state.tokens.next.value||\"(\"!==peek(0).value||(state.inMoz()||warning(\"W118\",state.tokens.next,\"let expressions\"),isLetExpr=!0,state.funct[\"(scope)\"].stack(),advance(\"let\"),advance(\"(\"),state.tokens.prev.fud(),advance(\")\")),\"(end)\"===state.tokens.next.id&&error(\"E006\",state.tokens.curr);var isDangerous=state.option.asi&&state.tokens.prev.line!==startLine(state.tokens.curr)&&_.contains([\"]\",\")\"],state.tokens.prev.id)&&_.contains([\"[\",\"(\"],state.tokens.curr.id);if(isDangerous&&warning(\"W014\",state.tokens.curr,state.tokens.curr.id),advance(),initial&&(state.funct[\"(verb)\"]=state.tokens.curr.value,state.tokens.curr.beginsStmt=!0),initial===!0&&state.tokens.curr.fud)left=state.tokens.curr.fud();else for(state.tokens.curr.nud?left=state.tokens.curr.nud():error(\"E030\",state.tokens.curr,state.tokens.curr.id);(state.tokens.next.lbp>rbp||\"(template)\"===state.tokens.next.type)&&!isEndOfExpr();)isArray=\"Array\"===state.tokens.curr.value,isObject=\"Object\"===state.tokens.curr.value,left&&(left.value||left.first&&left.first.value)&&(\"new\"!==left.value||left.first&&left.first.value&&\".\"===left.first.value)&&(isArray=!1,left.value!==state.tokens.curr.value&&(isObject=!1)),advance(),isArray&&\"(\"===state.tokens.curr.id&&\")\"===state.tokens.next.id&&warning(\"W009\",state.tokens.curr),isObject&&\"(\"===state.tokens.curr.id&&\")\"===state.tokens.next.id&&warning(\"W010\",state.tokens.curr),left&&state.tokens.curr.led?left=state.tokens.curr.led(left):error(\"E033\",state.tokens.curr,state.tokens.curr.id);return isLetExpr&&state.funct[\"(scope)\"].unstack(),state.nameStack.pop(),left}function startLine(token){return token.startLine||token.line}function nobreaknonadjacent(left,right){left=left||state.tokens.curr,right=right||state.tokens.next,state.option.laxbreak||left.line===startLine(right)||warning(\"W014\",right,right.value)}function nolinebreak(t){t=t||state.tokens.curr,t.line!==startLine(state.tokens.next)&&warning(\"E022\",t,t.value)}function nobreakcomma(left,right){left.line!==startLine(right)&&(state.option.laxcomma||(comma.first&&(warning(\"I001\"),comma.first=!1),warning(\"W014\",left,right.value)))}function comma(opts){if(opts=opts||{},opts.peek?nobreakcomma(state.tokens.prev,state.tokens.curr):(nobreakcomma(state.tokens.curr,state.tokens.next),advance(\",\")),state.tokens.next.identifier&&(!opts.property||!state.inES5()))switch(state.tokens.next.value){case\"break\":case\"case\":case\"catch\":case\"continue\":case\"default\":case\"do\":case\"else\":case\"finally\":case\"for\":case\"if\":case\"in\":case\"instanceof\":case\"return\":case\"switch\":case\"throw\":case\"try\":case\"var\":case\"let\":case\"while\":case\"with\":return error(\"E024\",state.tokens.next,state.tokens.next.value),!1}if(\"(punctuator)\"===state.tokens.next.type)switch(state.tokens.next.value){case\"}\":case\"]\":case\",\":if(opts.allowTrailing)return!0;case\")\":return error(\"E024\",state.tokens.next,state.tokens.next.value),!1}return!0}function symbol(s,p){var x=state.syntax[s];return x&&\"object\"==typeof x||(state.syntax[s]=x={id:s,lbp:p,value:s}),x}function delim(s){var x=symbol(s,0);return x.delim=!0,x}function stmt(s,f){var x=delim(s);return x.identifier=x.reserved=!0,x.fud=f,x}function blockstmt(s,f){var x=stmt(s,f);return x.block=!0,x}function reserveName(x){var c=x.id.charAt(0);return(c>=\"a\"&&\"z\">=c||c>=\"A\"&&\"Z\">=c)&&(x.identifier=x.reserved=!0),x}function prefix(s,f){var x=symbol(s,150);return reserveName(x),x.nud=\"function\"==typeof f?f:function(){return this.arity=\"unary\",this.right=expression(150),(\"++\"===this.id||\"--\"===this.id)&&(state.option.plusplus?warning(\"W016\",this,this.id):!this.right||this.right.identifier&&!isReserved(this.right)||\".\"===this.right.id||\"[\"===this.right.id||warning(\"W017\",this),this.right&&this.right.isMetaProperty?error(\"E031\",this):this.right&&this.right.identifier&&state.funct[\"(scope)\"].block.modify(this.right.value,this)),this},x}function type(s,f){var x=delim(s);return x.type=s,x.nud=f,x}function reserve(name,func){var x=type(name,func);return x.identifier=!0,x.reserved=!0,x}function FutureReservedWord(name,meta){var x=type(name,meta&&meta.nud||function(){return this});return meta=meta||{},meta.isFutureReservedWord=!0,x.value=name,x.identifier=!0,x.reserved=!0,x.meta=meta,x}function reservevar(s,v){return reserve(s,function(){return\"function\"==typeof v&&v(this),this})}function infix(s,f,p,w){var x=symbol(s,p);return reserveName(x),x.infix=!0,x.led=function(left){return w||nobreaknonadjacent(state.tokens.prev,state.tokens.curr),\"in\"!==s&&\"instanceof\"!==s||\"!\"!==left.id||warning(\"W018\",left,\"!\"),\"function\"==typeof f?f(left,this):(this.left=left,this.right=expression(p),this)},x}function application(s){var x=symbol(s,42);return x.led=function(left){return nobreaknonadjacent(state.tokens.prev,state.tokens.curr),this.left=left,this.right=doFunction({type:\"arrow\",loneArg:left}),this},x}function relation(s,f){var x=symbol(s,100);return x.led=function(left){nobreaknonadjacent(state.tokens.prev,state.tokens.curr),this.left=left;var right=this.right=expression(100);return isIdentifier(left,\"NaN\")||isIdentifier(right,\"NaN\")?warning(\"W019\",this):f&&f.apply(this,[left,right]),left&&right||quit(\"E041\",state.tokens.curr.line),\"!\"===left.id&&warning(\"W018\",left,\"!\"),\"!\"===right.id&&warning(\"W018\",right,\"!\"),this},x}function isPoorRelation(node){return node&&(\"(number)\"===node.type&&0===+node.value||\"(string)\"===node.type&&\"\"===node.value||\"null\"===node.type&&!state.option.eqnull||\"true\"===node.type||\"false\"===node.type||\"undefined\"===node.type)}function isTypoTypeof(left,right,state){var values;return state.option.notypeof?!1:left&&right?(values=state.inES6()?typeofValues.es6:typeofValues.es3,\"(identifier)\"===right.type&&\"typeof\"===right.value&&\"(string)\"===left.type?!_.contains(values,left.value):!1):!1}function isGlobalEval(left,state){var isGlobal=!1;return\"this\"===left.type&&null===state.funct[\"(context)\"]?isGlobal=!0:\"(identifier)\"===left.type&&(state.option.node&&\"global\"===left.value?isGlobal=!0:!state.option.browser||\"window\"!==left.value&&\"document\"!==left.value||(isGlobal=!0)),isGlobal}function findNativePrototype(left){function walkPrototype(obj){return\"object\"==typeof obj?\"prototype\"===obj.right?obj:walkPrototype(obj.left):void 0}function walkNative(obj){for(;!obj.identifier&&\"object\"==typeof obj.left;)obj=obj.left;return obj.identifier&&natives.indexOf(obj.value)>=0?obj.value:void 0}var natives=[\"Array\",\"ArrayBuffer\",\"Boolean\",\"Collator\",\"DataView\",\"Date\",\"DateTimeFormat\",\"Error\",\"EvalError\",\"Float32Array\",\"Float64Array\",\"Function\",\"Infinity\",\"Intl\",\"Int16Array\",\"Int32Array\",\"Int8Array\",\"Iterator\",\"Number\",\"NumberFormat\",\"Object\",\"RangeError\",\"ReferenceError\",\"RegExp\",\"StopIteration\",\"String\",\"SyntaxError\",\"TypeError\",\"Uint16Array\",\"Uint32Array\",\"Uint8Array\",\"Uint8ClampedArray\",\"URIError\"],prototype=walkPrototype(left);return prototype?walkNative(prototype):void 0}function checkLeftSideAssign(left,assignToken,options){var allowDestructuring=options&&options.allowDestructuring;if(assignToken=assignToken||left,state.option.freeze){var nativeObject=findNativePrototype(left);nativeObject&&warning(\"W121\",left,nativeObject)}return left.identifier&&!left.isMetaProperty&&state.funct[\"(scope)\"].block.reassign(left.value,left),\".\"===left.id?((!left.left||\"arguments\"===left.left.value&&!state.isStrict())&&warning(\"E031\",assignToken),state.nameStack.set(state.tokens.prev),!0):\"{\"===left.id||\"[\"===left.id?(allowDestructuring&&state.tokens.curr.left.destructAssign?state.tokens.curr.left.destructAssign.forEach(function(t){t.id&&state.funct[\"(scope)\"].block.modify(t.id,t.token)}):\"{\"!==left.id&&left.left?\"arguments\"!==left.left.value||state.isStrict()||warning(\"E031\",assignToken):warning(\"E031\",assignToken),\"[\"===left.id&&state.nameStack.set(left.right),!0):left.isMetaProperty?(error(\"E031\",assignToken),!0):left.identifier&&!isReserved(left)?(\"exception\"===state.funct[\"(scope)\"].labeltype(left.value)&&warning(\"W022\",left),state.nameStack.set(left),!0):(left===state.syntax[\"function\"]&&warning(\"W023\",state.tokens.curr),!1)}function assignop(s,f,p){var x=infix(s,\"function\"==typeof f?f:function(left,that){return that.left=left,left&&checkLeftSideAssign(left,that,{allowDestructuring:!0})?(that.right=expression(10),that):(error(\"E031\",that),void 0)},p);return x.exps=!0,x.assign=!0,x}function bitwise(s,f,p){var x=symbol(s,p);return reserveName(x),x.led=\"function\"==typeof f?f:function(left){return state.option.bitwise&&warning(\"W016\",this,this.id),this.left=left,this.right=expression(p),this},x}function bitwiseassignop(s){return assignop(s,function(left,that){return state.option.bitwise&&warning(\"W016\",that,that.id),left&&checkLeftSideAssign(left,that)?(that.right=expression(10),that):(error(\"E031\",that),void 0)},20)}function suffix(s){var x=symbol(s,150);return x.led=function(left){return state.option.plusplus?warning(\"W016\",this,this.id):left.identifier&&!isReserved(left)||\".\"===left.id||\"[\"===left.id||warning(\"W017\",this),left.isMetaProperty?error(\"E031\",this):left&&left.identifier&&state.funct[\"(scope)\"].block.modify(left.value,left),this.left=left,this},x}function optionalidentifier(fnparam,prop,preserve){if(state.tokens.next.identifier){preserve||advance();var curr=state.tokens.curr,val=state.tokens.curr.value;return isReserved(curr)?prop&&state.inES5()?val:fnparam&&\"undefined\"===val?val:(warning(\"W024\",state.tokens.curr,state.tokens.curr.id),val):val}}function identifier(fnparam,prop){var i=optionalidentifier(fnparam,prop,!1);if(i)return i;if(\"...\"===state.tokens.next.value){if(state.inES6(!0)||warning(\"W119\",state.tokens.next,\"spread/rest operator\",\"6\"),advance(),checkPunctuator(state.tokens.next,\"...\"))for(warning(\"E024\",state.tokens.next,\"...\");checkPunctuator(state.tokens.next,\"...\");)advance();return state.tokens.next.identifier?identifier(fnparam,prop):(warning(\"E024\",state.tokens.curr,\"...\"),void 0)}error(\"E030\",state.tokens.next,state.tokens.next.value),\";\"!==state.tokens.next.id&&advance()}function reachable(controlToken){var t,i=0;if(\";\"===state.tokens.next.id&&!controlToken.inBracelessBlock)for(;;){do t=peek(i),i+=1;while(\"(end)\"!==t.id&&\"(comment)\"===t.id);if(t.reach)return;if(\"(endline)\"!==t.id){if(\"function\"===t.id){state.option.latedef===!0&&warning(\"W026\",t);break}warning(\"W027\",t,t.value,controlToken.value);break}}}function parseFinalSemicolon(){if(\";\"!==state.tokens.next.id){if(state.tokens.next.isUnclosed)return advance();var sameLine=startLine(state.tokens.next)===state.tokens.curr.line&&\"(end)\"!==state.tokens.next.id,blockEnd=checkPunctuator(state.tokens.next,\"}\");sameLine&&!blockEnd?errorAt(\"E058\",state.tokens.curr.line,state.tokens.curr.character):state.option.asi||(blockEnd&&!state.option.lastsemic||!sameLine)&&warningAt(\"W033\",state.tokens.curr.line,state.tokens.curr.character)}else advance(\";\")}function statement(){var r,i=indent,t=state.tokens.next,hasOwnScope=!1;if(\";\"===t.id)return advance(\";\"),void 0;var res=isReserved(t);if(res&&t.meta&&t.meta.isFutureReservedWord&&\":\"===peek().id&&(warning(\"W024\",t,t.id),res=!1),t.identifier&&!res&&\":\"===peek().id&&(advance(),advance(\":\"),hasOwnScope=!0,state.funct[\"(scope)\"].stack(),state.funct[\"(scope)\"].block.addBreakLabel(t.value,{token:state.tokens.curr}),state.tokens.next.labelled||\"{\"===state.tokens.next.value||warning(\"W028\",state.tokens.next,t.value,state.tokens.next.value),state.tokens.next.label=t.value,t=state.tokens.next),\"{\"===t.id){var iscase=\"case\"===state.funct[\"(verb)\"]&&\":\"===state.tokens.curr.value;return block(!0,!0,!1,!1,iscase),void 0}return r=expression(0,!0),!r||r.identifier&&\"function\"===r.value||\"(punctuator)\"===r.type&&r.left&&r.left.identifier&&\"function\"===r.left.value||state.isStrict()||\"global\"!==state.option.strict||warning(\"E007\"),t.block||(state.option.expr||r&&r.exps?state.option.nonew&&r&&r.left&&\"(\"===r.id&&\"new\"===r.left.id&&warning(\"W031\",t):warning(\"W030\",state.tokens.curr),parseFinalSemicolon()),indent=i,hasOwnScope&&state.funct[\"(scope)\"].unstack(),r}function statements(){for(var p,a=[];!state.tokens.next.reach&&\"(end)\"!==state.tokens.next.id;)\";\"===state.tokens.next.id?(p=peek(),(!p||\"(\"!==p.id&&\"[\"!==p.id)&&warning(\"W032\"),advance(\";\")):a.push(statement());return a}function directives(){for(var i,p,pn;\"(string)\"===state.tokens.next.id;){if(p=peek(0),\"(endline)\"===p.id){i=1;do pn=peek(i++);while(\"(endline)\"===pn.id);if(\";\"===pn.id)p=pn;else{if(\"[\"===pn.value||\".\"===pn.value)break;state.option.asi&&\"(\"!==pn.value||warning(\"W033\",state.tokens.next)}}else{if(\".\"===p.id||\"[\"===p.id)break;\";\"!==p.id&&warning(\"W033\",p)}advance();var directive=state.tokens.curr.value;(state.directive[directive]||\"use strict\"===directive&&\"implied\"===state.option.strict)&&warning(\"W034\",state.tokens.curr,directive),state.directive[directive]=!0,\";\"===p.id&&advance(\";\")}state.isStrict()&&(state.option[\"(explicitNewcap)\"]||(state.option.newcap=!0),state.option.undef=!0)}function block(ordinary,stmt,isfunc,isfatarrow,iscase){var a,m,t,line,d,b=inblock,old_indent=indent;inblock=ordinary,t=state.tokens.next;var metrics=state.funct[\"(metrics)\"];if(metrics.nestedBlockDepth+=1,metrics.verifyMaxNestedBlockDepthPerFunction(),\"{\"===state.tokens.next.id){if(advance(\"{\"),state.funct[\"(scope)\"].stack(),line=state.tokens.curr.line,\"}\"!==state.tokens.next.id){for(indent+=state.option.indent;!ordinary&&state.tokens.next.from>indent;)indent+=state.option.indent;if(isfunc){m={};for(d in state.directive)_.has(state.directive,d)&&(m[d]=state.directive[d]);directives(),state.option.strict&&state.funct[\"(context)\"][\"(global)\"]&&(m[\"use strict\"]||state.isStrict()||warning(\"E007\"))}a=statements(),metrics.statementCount+=a.length,indent-=state.option.indent}advance(\"}\",t),isfunc&&(state.funct[\"(scope)\"].validateParams(),m&&(state.directive=m)),state.funct[\"(scope)\"].unstack(),indent=old_indent}else if(ordinary)state.funct[\"(noblockscopedvar)\"]=\"for\"!==state.tokens.next.id,state.funct[\"(scope)\"].stack(),(!stmt||state.option.curly)&&warning(\"W116\",state.tokens.next,\"{\",state.tokens.next.value),state.tokens.next.inBracelessBlock=!0,indent+=state.option.indent,a=[statement()],indent-=state.option.indent,state.funct[\"(scope)\"].unstack(),delete state.funct[\"(noblockscopedvar)\"];else if(isfunc){if(state.funct[\"(scope)\"].stack(),m={},!stmt||isfatarrow||state.inMoz()||error(\"W118\",state.tokens.curr,\"function closure expressions\"),!stmt)for(d in state.directive)_.has(state.directive,d)&&(m[d]=state.directive[d]);expression(10),state.option.strict&&state.funct[\"(context)\"][\"(global)\"]&&(m[\"use strict\"]||state.isStrict()||warning(\"E007\")),state.funct[\"(scope)\"].unstack()}else error(\"E021\",state.tokens.next,\"{\",state.tokens.next.value);switch(state.funct[\"(verb)\"]){case\"break\":case\"continue\":case\"return\":case\"throw\":if(iscase)break;default:state.funct[\"(verb)\"]=null}return inblock=b,!ordinary||!state.option.noempty||a&&0!==a.length||warning(\"W035\",state.tokens.prev),metrics.nestedBlockDepth-=1,a}function countMember(m){membersOnly&&\"boolean\"!=typeof membersOnly[m]&&warning(\"W036\",state.tokens.curr,m),\"number\"==typeof member[m]?member[m]+=1:member[m]=1}function comprehensiveArrayExpression(){var res={};res.exps=!0,state.funct[\"(comparray)\"].stack();var reversed=!1;return\"for\"!==state.tokens.next.value&&(reversed=!0,state.inMoz()||warning(\"W116\",state.tokens.next,\"for\",state.tokens.next.value),state.funct[\"(comparray)\"].setState(\"use\"),res.right=expression(10)),advance(\"for\"),\"each\"===state.tokens.next.value&&(advance(\"each\"),state.inMoz()||warning(\"W118\",state.tokens.curr,\"for each\")),advance(\"(\"),state.funct[\"(comparray)\"].setState(\"define\"),res.left=expression(130),_.contains([\"in\",\"of\"],state.tokens.next.value)?advance():error(\"E045\",state.tokens.curr),state.funct[\"(comparray)\"].setState(\"generate\"),expression(10),advance(\")\"),\"if\"===state.tokens.next.value&&(advance(\"if\"),advance(\"(\"),state.funct[\"(comparray)\"].setState(\"filter\"),res.filter=expression(10),advance(\")\")),reversed||(state.funct[\"(comparray)\"].setState(\"use\"),res.right=expression(10)),advance(\"]\"),state.funct[\"(comparray)\"].unstack(),res}function isMethod(){return state.funct[\"(statement)\"]&&\"class\"===state.funct[\"(statement)\"].type||state.funct[\"(context)\"]&&\"class\"===state.funct[\"(context)\"][\"(verb)\"]}function isPropertyName(token){return token.identifier||\"(string)\"===token.id||\"(number)\"===token.id}function propertyName(preserveOrToken){var id,preserve=!0;return\"object\"==typeof preserveOrToken?id=preserveOrToken:(preserve=preserveOrToken,id=optionalidentifier(!1,!0,preserve)),id?\"object\"==typeof id&&(\"(string)\"===id.id||\"(identifier)\"===id.id?id=id.value:\"(number)\"===id.id&&(id=\"\"+id.value)):\"(string)\"===state.tokens.next.id?(id=state.tokens.next.value,preserve||advance()):\"(number)\"===state.tokens.next.id&&(id=\"\"+state.tokens.next.value,preserve||advance()),\"hasOwnProperty\"===id&&warning(\"W001\"),id}function functionparams(options){function addParam(addParamArgs){state.funct[\"(scope)\"].addParam.apply(state.funct[\"(scope)\"],addParamArgs)}var next,ident,t,paramsIds=[],tokens=[],pastDefault=!1,pastRest=!1,arity=0,loneArg=options&&options.loneArg;if(loneArg&&loneArg.identifier===!0)return state.funct[\"(scope)\"].addParam(loneArg.value,loneArg),{arity:1,params:[loneArg.value]};if(next=state.tokens.next,options&&options.parsedOpening||advance(\"(\"),\")\"===state.tokens.next.id)return advance(\")\"),void 0;for(;;){arity++;var currentParams=[];if(_.contains([\"{\",\"[\"],state.tokens.next.id)){tokens=destructuringPattern();for(t in tokens)t=tokens[t],t.id&&(paramsIds.push(t.id),currentParams.push([t.id,t.token]))}else if(checkPunctuator(state.tokens.next,\"...\")&&(pastRest=!0),ident=identifier(!0))paramsIds.push(ident),currentParams.push([ident,state.tokens.curr]);else for(;!checkPunctuators(state.tokens.next,[\",\",\")\"]);)advance();if(pastDefault&&\"=\"!==state.tokens.next.id&&error(\"W138\",state.tokens.current),\"=\"===state.tokens.next.id&&(state.inES6()||warning(\"W119\",state.tokens.next,\"default parameters\",\"6\"),advance(\"=\"),pastDefault=!0,expression(10)),currentParams.forEach(addParam),\",\"!==state.tokens.next.id)return advance(\")\",next),{arity:arity,params:paramsIds};pastRest&&warning(\"W131\",state.tokens.next),comma()}}function functor(name,token,overwrites){var funct={\"(name)\":name,\"(breakage)\":0,\"(loopage)\":0,\"(tokens)\":{},\"(properties)\":{},\"(catch)\":!1,\"(global)\":!1,\"(line)\":null,\"(character)\":null,\"(metrics)\":null,\"(statement)\":null,\"(context)\":null,\"(scope)\":null,\"(comparray)\":null,\"(generator)\":null,\"(arrow)\":null,\"(params)\":null};return token&&_.extend(funct,{\"(line)\":token.line,\"(character)\":token.character,\"(metrics)\":createMetrics(token)}),_.extend(funct,overwrites),funct[\"(context)\"]&&(funct[\"(scope)\"]=funct[\"(context)\"][\"(scope)\"],funct[\"(comparray)\"]=funct[\"(context)\"][\"(comparray)\"]),funct}function isFunctor(token){return\"(scope)\"in token}function hasParsedCode(funct){return funct[\"(global)\"]&&!funct[\"(verb)\"]}function doTemplateLiteral(left){function end(){if(state.tokens.curr.template&&state.tokens.curr.tail&&state.tokens.curr.context===ctx)return!0;var complete=state.tokens.next.template&&state.tokens.next.tail&&state.tokens.next.context===ctx;return complete&&advance(),complete||state.tokens.next.isUnclosed}var ctx=this.context,noSubst=this.noSubst,depth=this.depth;if(!noSubst)for(;!end();)!state.tokens.next.template||state.tokens.next.depth>depth?expression(0):advance();return{id:\"(template)\",type:\"(template)\",tag:left}}function doFunction(options){var f,token,name,statement,classExprBinding,isGenerator,isArrow,ignoreLoopFunc,oldOption=state.option,oldIgnored=state.ignored;options&&(name=options.name,statement=options.statement,classExprBinding=options.classExprBinding,isGenerator=\"generator\"===options.type,isArrow=\"arrow\"===options.type,ignoreLoopFunc=options.ignoreLoopFunc),state.option=Object.create(state.option),state.ignored=Object.create(state.ignored),state.funct=functor(name||state.nameStack.infer(),state.tokens.next,{\"(statement)\":statement,\"(context)\":state.funct,\"(arrow)\":isArrow,\"(generator)\":isGenerator}),f=state.funct,token=state.tokens.curr,token.funct=state.funct,functions.push(state.funct),state.funct[\"(scope)\"].stack(\"functionouter\");var internallyAccessibleName=name||classExprBinding;internallyAccessibleName&&state.funct[\"(scope)\"].block.add(internallyAccessibleName,classExprBinding?\"class\":\"function\",state.tokens.curr,!1),state.funct[\"(scope)\"].stack(\"functionparams\");var paramsInfo=functionparams(options);return paramsInfo?(state.funct[\"(params)\"]=paramsInfo.params,state.funct[\"(metrics)\"].arity=paramsInfo.arity,state.funct[\"(metrics)\"].verifyMaxParametersPerFunction()):state.funct[\"(metrics)\"].arity=0,isArrow&&(state.inES6(!0)||warning(\"W119\",state.tokens.curr,\"arrow function syntax (=>)\",\"6\"),options.loneArg||advance(\"=>\")),block(!1,!0,!0,isArrow),!state.option.noyield&&isGenerator&&\"yielded\"!==state.funct[\"(generator)\"]&&warning(\"W124\",state.tokens.curr),state.funct[\"(metrics)\"].verifyMaxStatementsPerFunction(),state.funct[\"(metrics)\"].verifyMaxComplexityPerFunction(),state.funct[\"(unusedOption)\"]=state.option.unused,state.option=oldOption,state.ignored=oldIgnored,state.funct[\"(last)\"]=state.tokens.curr.line,state.funct[\"(lastcharacter)\"]=state.tokens.curr.character,state.funct[\"(scope)\"].unstack(),state.funct[\"(scope)\"].unstack(),state.funct=state.funct[\"(context)\"],ignoreLoopFunc||state.option.loopfunc||!state.funct[\"(loopage)\"]||f[\"(isCapturing)\"]&&warning(\"W083\",token),f}function createMetrics(functionStartToken){return{statementCount:0,nestedBlockDepth:-1,ComplexityCount:1,arity:0,verifyMaxStatementsPerFunction:function(){state.option.maxstatements&&this.statementCount>state.option.maxstatements&&warning(\"W071\",functionStartToken,this.statementCount)\\n},verifyMaxParametersPerFunction:function(){_.isNumber(state.option.maxparams)&&this.arity>state.option.maxparams&&warning(\"W072\",functionStartToken,this.arity)},verifyMaxNestedBlockDepthPerFunction:function(){state.option.maxdepth&&this.nestedBlockDepth>0&&this.nestedBlockDepth===state.option.maxdepth+1&&warning(\"W073\",null,this.nestedBlockDepth)},verifyMaxComplexityPerFunction:function(){var max=state.option.maxcomplexity,cc=this.ComplexityCount;max&&cc>max&&warning(\"W074\",functionStartToken,cc)}}}function increaseComplexityCount(){state.funct[\"(metrics)\"].ComplexityCount+=1}function checkCondAssignment(expr){var id,paren;switch(expr&&(id=expr.id,paren=expr.paren,\",\"===id&&(expr=expr.exprs[expr.exprs.length-1])&&(id=expr.id,paren=paren||expr.paren)),id){case\"=\":case\"+=\":case\"-=\":case\"*=\":case\"%=\":case\"&=\":case\"|=\":case\"^=\":case\"/=\":paren||state.option.boss||warning(\"W084\")}}function checkProperties(props){if(state.inES5())for(var name in props)props[name]&&props[name].setterToken&&!props[name].getterToken&&warning(\"W078\",props[name].setterToken)}function metaProperty(name,c){if(checkPunctuator(state.tokens.next,\".\")){var left=state.tokens.curr.id;advance(\".\");var id=identifier();return state.tokens.curr.isMetaProperty=!0,name!==id?error(\"E057\",state.tokens.prev,left,id):c(),state.tokens.curr}}function destructuringPattern(options){var isAssignment=options&&options.assignment;return state.inES6()||warning(\"W104\",state.tokens.curr,isAssignment?\"destructuring assignment\":\"destructuring binding\",\"6\"),destructuringPatternRecursive(options)}function destructuringPatternRecursive(options){var ids,identifiers=[],openingParsed=options&&options.openingParsed,isAssignment=options&&options.assignment,recursiveOptions=isAssignment?{assignment:isAssignment}:null,firstToken=openingParsed?state.tokens.curr:state.tokens.next,nextInnerDE=function(){var ident;if(checkPunctuators(state.tokens.next,[\"[\",\"{\"])){ids=destructuringPatternRecursive(recursiveOptions);for(var id in ids)id=ids[id],identifiers.push({id:id.id,token:id.token})}else if(checkPunctuator(state.tokens.next,\",\"))identifiers.push({id:null,token:state.tokens.curr});else{if(!checkPunctuator(state.tokens.next,\"(\")){var is_rest=checkPunctuator(state.tokens.next,\"...\");if(isAssignment){var identifierToken=is_rest?peek(0):state.tokens.next;identifierToken.identifier||warning(\"E030\",identifierToken,identifierToken.value);var assignTarget=expression(155);assignTarget&&(checkLeftSideAssign(assignTarget),assignTarget.identifier&&(ident=assignTarget.value))}else ident=identifier();return ident&&identifiers.push({id:ident,token:state.tokens.curr}),is_rest}advance(\"(\"),nextInnerDE(),advance(\")\")}return!1},assignmentProperty=function(){var id;checkPunctuator(state.tokens.next,\"[\")?(advance(\"[\"),expression(10),advance(\"]\"),advance(\":\"),nextInnerDE()):\"(string)\"===state.tokens.next.id||\"(number)\"===state.tokens.next.id?(advance(),advance(\":\"),nextInnerDE()):(id=identifier(),checkPunctuator(state.tokens.next,\":\")?(advance(\":\"),nextInnerDE()):id&&(isAssignment&&checkLeftSideAssign(state.tokens.curr),identifiers.push({id:id,token:state.tokens.curr})))};if(checkPunctuator(firstToken,\"[\")){openingParsed||advance(\"[\"),checkPunctuator(state.tokens.next,\"]\")&&warning(\"W137\",state.tokens.curr);for(var element_after_rest=!1;!checkPunctuator(state.tokens.next,\"]\");)nextInnerDE()&&!element_after_rest&&checkPunctuator(state.tokens.next,\",\")&&(warning(\"W130\",state.tokens.next),element_after_rest=!0),checkPunctuator(state.tokens.next,\"=\")&&(checkPunctuator(state.tokens.prev,\"...\")?advance(\"]\"):advance(\"=\"),\"undefined\"===state.tokens.next.id&&warning(\"W080\",state.tokens.prev,state.tokens.prev.value),expression(10)),checkPunctuator(state.tokens.next,\"]\")||advance(\",\");advance(\"]\")}else if(checkPunctuator(firstToken,\"{\")){for(openingParsed||advance(\"{\"),checkPunctuator(state.tokens.next,\"}\")&&warning(\"W137\",state.tokens.curr);!checkPunctuator(state.tokens.next,\"}\")&&(assignmentProperty(),checkPunctuator(state.tokens.next,\"=\")&&(advance(\"=\"),\"undefined\"===state.tokens.next.id&&warning(\"W080\",state.tokens.prev,state.tokens.prev.value),expression(10)),checkPunctuator(state.tokens.next,\"}\")||(advance(\",\"),!checkPunctuator(state.tokens.next,\"}\"))););advance(\"}\")}return identifiers}function destructuringPatternMatch(tokens,value){var first=value.first;first&&_.zip(tokens,Array.isArray(first)?first:[first]).forEach(function(val){var token=val[0],value=val[1];token&&value?token.first=value:token&&token.first&&!value&&warning(\"W080\",token.first,token.first.value)})}function blockVariableStatement(type,statement,context){var tokens,lone,value,letblock,prefix=context&&context.prefix,inexport=context&&context.inexport,isLet=\"let\"===type,isConst=\"const\"===type;for(state.inES6()||warning(\"W104\",state.tokens.curr,type,\"6\"),isLet&&\"(\"===state.tokens.next.value?(state.inMoz()||warning(\"W118\",state.tokens.next,\"let block\"),advance(\"(\"),state.funct[\"(scope)\"].stack(),letblock=!0):state.funct[\"(noblockscopedvar)\"]&&error(\"E048\",state.tokens.curr,isConst?\"Const\":\"Let\"),statement.first=[];;){var names=[];_.contains([\"{\",\"[\"],state.tokens.next.value)?(tokens=destructuringPattern(),lone=!1):(tokens=[{id:identifier(),token:state.tokens.curr}],lone=!0),!prefix&&isConst&&\"=\"!==state.tokens.next.id&&warning(\"E012\",state.tokens.curr,state.tokens.curr.value);for(var t in tokens)tokens.hasOwnProperty(t)&&(t=tokens[t],state.funct[\"(scope)\"].block.isGlobal()&&predefined[t.id]===!1&&warning(\"W079\",t.token,t.id),t.id&&!state.funct[\"(noblockscopedvar)\"]&&(state.funct[\"(scope)\"].addlabel(t.id,{type:type,token:t.token}),names.push(t.token),lone&&inexport&&state.funct[\"(scope)\"].setExported(t.token.value,t.token)));if(\"=\"===state.tokens.next.id&&(advance(\"=\"),prefix||\"undefined\"!==state.tokens.next.id||warning(\"W080\",state.tokens.prev,state.tokens.prev.value),!prefix&&\"=\"===peek(0).id&&state.tokens.next.identifier&&warning(\"W120\",state.tokens.next,state.tokens.next.value),value=expression(prefix?120:10),lone?tokens[0].first=value:destructuringPatternMatch(names,value)),statement.first=statement.first.concat(names),\",\"!==state.tokens.next.id)break;comma()}return letblock&&(advance(\")\"),block(!0,!0),statement.block=!0,state.funct[\"(scope)\"].unstack()),statement}function classdef(isStatement){return state.inES6()||warning(\"W104\",state.tokens.curr,\"class\",\"6\"),isStatement?(this.name=identifier(),state.funct[\"(scope)\"].addlabel(this.name,{type:\"class\",token:state.tokens.curr})):state.tokens.next.identifier&&\"extends\"!==state.tokens.next.value?(this.name=identifier(),this.namedExpr=!0):this.name=state.nameStack.infer(),classtail(this),this}function classtail(c){var wasInClassBody=state.inClassBody;\"extends\"===state.tokens.next.value&&(advance(\"extends\"),c.heritage=expression(10)),state.inClassBody=!0,advance(\"{\"),c.body=classbody(c),advance(\"}\"),state.inClassBody=wasInClassBody}function classbody(c){for(var name,isStatic,isGenerator,getset,computed,props=Object.create(null),staticProps=Object.create(null),i=0;\"}\"!==state.tokens.next.id;++i)if(name=state.tokens.next,isStatic=!1,isGenerator=!1,getset=null,\";\"!==name.id){if(\"*\"===name.id&&(isGenerator=!0,advance(\"*\"),name=state.tokens.next),\"[\"===name.id)name=computedPropertyName(),computed=!0;else{if(!isPropertyName(name)){warning(\"W052\",state.tokens.next,state.tokens.next.value||state.tokens.next.type),advance();continue}advance(),computed=!1,name.identifier&&\"static\"===name.value&&(checkPunctuator(state.tokens.next,\"*\")&&(isGenerator=!0,advance(\"*\")),(isPropertyName(state.tokens.next)||\"[\"===state.tokens.next.id)&&(computed=\"[\"===state.tokens.next.id,isStatic=!0,name=state.tokens.next,\"[\"===state.tokens.next.id?name=computedPropertyName():advance())),!name.identifier||\"get\"!==name.value&&\"set\"!==name.value||(isPropertyName(state.tokens.next)||\"[\"===state.tokens.next.id)&&(computed=\"[\"===state.tokens.next.id,getset=name,name=state.tokens.next,\"[\"===state.tokens.next.id?name=computedPropertyName():advance())}if(!checkPunctuator(state.tokens.next,\"(\")){for(error(\"E054\",state.tokens.next,state.tokens.next.value);\"}\"!==state.tokens.next.id&&!checkPunctuator(state.tokens.next,\"(\");)advance();\"(\"!==state.tokens.next.value&&doFunction({statement:c})}if(computed||(getset?saveAccessor(getset.value,isStatic?staticProps:props,name.value,name,!0,isStatic):(\"constructor\"===name.value?state.nameStack.set(c):state.nameStack.set(name),saveProperty(isStatic?staticProps:props,name.value,name,!0,isStatic))),getset&&\"constructor\"===name.value){var propDesc=\"get\"===getset.value?\"class getter method\":\"class setter method\";error(\"E049\",name,propDesc,\"constructor\")}else\"prototype\"===name.value&&error(\"E049\",name,\"class method\",\"prototype\");propertyName(name),doFunction({statement:c,type:isGenerator?\"generator\":null,classExprBinding:c.namedExpr?c.name:null})}else warning(\"W032\"),advance(\";\");checkProperties(props)}function saveProperty(props,name,tkn,isClass,isStatic){var msg=[\"key\",\"class method\",\"static class method\"];msg=msg[(isClass||!1)+(isStatic||!1)],tkn.identifier&&(name=tkn.value),props[name]&&\"__proto__\"!==name?warning(\"W075\",state.tokens.next,msg,name):props[name]=Object.create(null),props[name].basic=!0,props[name].basictkn=tkn}function saveAccessor(accessorType,props,name,tkn,isClass,isStatic){var flagName=\"get\"===accessorType?\"getterToken\":\"setterToken\",msg=\"\";isClass?(isStatic&&(msg+=\"static \"),msg+=accessorType+\"ter method\"):msg=\"key\",state.tokens.curr.accessorType=accessorType,state.nameStack.set(tkn),props[name]?(props[name].basic||props[name][flagName])&&\"__proto__\"!==name&&warning(\"W075\",state.tokens.next,msg,name):props[name]=Object.create(null),props[name][flagName]=tkn}function computedPropertyName(){advance(\"[\"),state.inES6()||warning(\"W119\",state.tokens.curr,\"computed property names\",\"6\");var value=expression(10);return advance(\"]\"),value}function checkPunctuators(token,values){return\"(punctuator)\"===token.type?_.contains(values,token.value):!1}function checkPunctuator(token,value){return\"(punctuator)\"===token.type&&token.value===value}function destructuringAssignOrJsonValue(){var block=lookupBlockType();block.notJson?(!state.inES6()&&block.isDestAssign&&warning(\"W104\",state.tokens.curr,\"destructuring assignment\",\"6\"),statements()):(state.option.laxbreak=!0,state.jsonMode=!0,jsonValue())}function jsonValue(){function jsonObject(){var o={},t=state.tokens.next;if(advance(\"{\"),\"}\"!==state.tokens.next.id)for(;;){if(\"(end)\"===state.tokens.next.id)error(\"E026\",state.tokens.next,t.line);else{if(\"}\"===state.tokens.next.id){warning(\"W094\",state.tokens.curr);break}\",\"===state.tokens.next.id?error(\"E028\",state.tokens.next):\"(string)\"!==state.tokens.next.id&&warning(\"W095\",state.tokens.next,state.tokens.next.value)}if(o[state.tokens.next.value]===!0?warning(\"W075\",state.tokens.next,\"key\",state.tokens.next.value):\"__proto__\"===state.tokens.next.value&&!state.option.proto||\"__iterator__\"===state.tokens.next.value&&!state.option.iterator?warning(\"W096\",state.tokens.next,state.tokens.next.value):o[state.tokens.next.value]=!0,advance(),advance(\":\"),jsonValue(),\",\"!==state.tokens.next.id)break;advance(\",\")}advance(\"}\")}function jsonArray(){var t=state.tokens.next;if(advance(\"[\"),\"]\"!==state.tokens.next.id)for(;;){if(\"(end)\"===state.tokens.next.id)error(\"E027\",state.tokens.next,t.line);else{if(\"]\"===state.tokens.next.id){warning(\"W094\",state.tokens.curr);break}\",\"===state.tokens.next.id&&error(\"E028\",state.tokens.next)}if(jsonValue(),\",\"!==state.tokens.next.id)break;advance(\",\")}advance(\"]\")}switch(state.tokens.next.id){case\"{\":jsonObject();break;case\"[\":jsonArray();break;case\"true\":case\"false\":case\"null\":case\"(number)\":case\"(string)\":advance();break;case\"-\":advance(\"-\"),advance(\"(number)\");break;default:error(\"E003\",state.tokens.next)}}var api,declared,functions,inblock,indent,lookahead,lex,member,membersOnly,predefined,stack,urls,bang={\"<\":!0,\"<=\":!0,\"==\":!0,\"===\":!0,\"!==\":!0,\"!=\":!0,\">\":!0,\">=\":!0,\"+\":!0,\"-\":!0,\"*\":!0,\"/\":!0,\"%\":!0},functionicity=[\"closure\",\"exception\",\"global\",\"label\",\"outer\",\"unused\",\"var\"],extraModules=[],emitter=new events.EventEmitter,typeofValues={};typeofValues.legacy=[\"xml\",\"unknown\"],typeofValues.es3=[\"undefined\",\"boolean\",\"number\",\"string\",\"function\",\"object\"],typeofValues.es3=typeofValues.es3.concat(typeofValues.legacy),typeofValues.es6=typeofValues.es3.concat(\"symbol\"),type(\"(number)\",function(){return this}),type(\"(string)\",function(){return this}),state.syntax[\"(identifier)\"]={type:\"(identifier)\",lbp:0,identifier:!0,nud:function(){var v=this.value;return\"=>\"===state.tokens.next.id?this:(state.funct[\"(comparray)\"].check(v)||state.funct[\"(scope)\"].block.use(v,state.tokens.curr),this)},led:function(){error(\"E033\",state.tokens.next,state.tokens.next.value)}};var baseTemplateSyntax={lbp:0,identifier:!1,template:!0};state.syntax[\"(template)\"]=_.extend({type:\"(template)\",nud:doTemplateLiteral,led:doTemplateLiteral,noSubst:!1},baseTemplateSyntax),state.syntax[\"(template middle)\"]=_.extend({type:\"(template middle)\",middle:!0,noSubst:!1},baseTemplateSyntax),state.syntax[\"(template tail)\"]=_.extend({type:\"(template tail)\",tail:!0,noSubst:!1},baseTemplateSyntax),state.syntax[\"(no subst template)\"]=_.extend({type:\"(template)\",nud:doTemplateLiteral,led:doTemplateLiteral,noSubst:!0,tail:!0},baseTemplateSyntax),type(\"(regexp)\",function(){return this}),delim(\"(endline)\"),delim(\"(begin)\"),delim(\"(end)\").reach=!0,delim(\"(error)\").reach=!0,delim(\"}\").reach=!0,delim(\")\"),delim(\"]\"),delim(\\'\"\\').reach=!0,delim(\"\\'\").reach=!0,delim(\";\"),delim(\":\").reach=!0,delim(\"#\"),reserve(\"else\"),reserve(\"case\").reach=!0,reserve(\"catch\"),reserve(\"default\").reach=!0,reserve(\"finally\"),reservevar(\"arguments\",function(x){state.isStrict()&&state.funct[\"(global)\"]&&warning(\"E008\",x)}),reservevar(\"eval\"),reservevar(\"false\"),reservevar(\"Infinity\"),reservevar(\"null\"),reservevar(\"this\",function(x){state.isStrict()&&!isMethod()&&!state.option.validthis&&(state.funct[\"(statement)\"]&&state.funct[\"(name)\"].charAt(0)>\"Z\"||state.funct[\"(global)\"])&&warning(\"W040\",x)}),reservevar(\"true\"),reservevar(\"undefined\"),assignop(\"=\",\"assign\",20),assignop(\"+=\",\"assignadd\",20),assignop(\"-=\",\"assignsub\",20),assignop(\"*=\",\"assignmult\",20),assignop(\"/=\",\"assigndiv\",20).nud=function(){error(\"E014\")},assignop(\"%=\",\"assignmod\",20),bitwiseassignop(\"&=\"),bitwiseassignop(\"|=\"),bitwiseassignop(\"^=\"),bitwiseassignop(\"<<=\"),bitwiseassignop(\">>=\"),bitwiseassignop(\">>>=\"),infix(\",\",function(left,that){var expr;if(that.exprs=[left],state.option.nocomma&&warning(\"W127\"),!comma({peek:!0}))return that;for(;;){if(!(expr=expression(10)))break;if(that.exprs.push(expr),\",\"!==state.tokens.next.value||!comma())break}return that},10,!0),infix(\"?\",function(left,that){return increaseComplexityCount(),that.left=left,that.right=expression(10),advance(\":\"),that[\"else\"]=expression(10),that},30);var orPrecendence=40;infix(\"||\",function(left,that){return increaseComplexityCount(),that.left=left,that.right=expression(orPrecendence),that},orPrecendence),infix(\"&&\",\"and\",50),bitwise(\"|\",\"bitor\",70),bitwise(\"^\",\"bitxor\",80),bitwise(\"&\",\"bitand\",90),relation(\"==\",function(left,right){var eqnull=state.option.eqnull&&(\"null\"===(left&&left.value)||\"null\"===(right&&right.value));switch(!0){case!eqnull&&state.option.eqeqeq:this.from=this.character,warning(\"W116\",this,\"===\",\"==\");break;case isPoorRelation(left):warning(\"W041\",this,\"===\",left.value);break;case isPoorRelation(right):warning(\"W041\",this,\"===\",right.value);break;case isTypoTypeof(right,left,state):warning(\"W122\",this,right.value);break;case isTypoTypeof(left,right,state):warning(\"W122\",this,left.value)}return this}),relation(\"===\",function(left,right){return isTypoTypeof(right,left,state)?warning(\"W122\",this,right.value):isTypoTypeof(left,right,state)&&warning(\"W122\",this,left.value),this}),relation(\"!=\",function(left,right){var eqnull=state.option.eqnull&&(\"null\"===(left&&left.value)||\"null\"===(right&&right.value));return!eqnull&&state.option.eqeqeq?(this.from=this.character,warning(\"W116\",this,\"!==\",\"!=\")):isPoorRelation(left)?warning(\"W041\",this,\"!==\",left.value):isPoorRelation(right)?warning(\"W041\",this,\"!==\",right.value):isTypoTypeof(right,left,state)?warning(\"W122\",this,right.value):isTypoTypeof(left,right,state)&&warning(\"W122\",this,left.value),this}),relation(\"!==\",function(left,right){return isTypoTypeof(right,left,state)?warning(\"W122\",this,right.value):isTypoTypeof(left,right,state)&&warning(\"W122\",this,left.value),this}),relation(\"<\"),relation(\">\"),relation(\"<=\"),relation(\">=\"),bitwise(\"<<\",\"shiftleft\",120),bitwise(\">>\",\"shiftright\",120),bitwise(\">>>\",\"shiftrightunsigned\",120),infix(\"in\",\"in\",120),infix(\"instanceof\",\"instanceof\",120),infix(\"+\",function(left,that){var right;return that.left=left,that.right=right=expression(130),left&&right&&\"(string)\"===left.id&&\"(string)\"===right.id?(left.value+=right.value,left.character=right.character,!state.option.scripturl&&reg.javascriptURL.test(left.value)&&warning(\"W050\",left),left):that},130),prefix(\"+\",\"num\"),prefix(\"+++\",function(){return warning(\"W007\"),this.arity=\"unary\",this.right=expression(150),this}),infix(\"+++\",function(left){return warning(\"W007\"),this.left=left,this.right=expression(130),this},130),infix(\"-\",\"sub\",130),prefix(\"-\",\"neg\"),prefix(\"---\",function(){return warning(\"W006\"),this.arity=\"unary\",this.right=expression(150),this}),infix(\"---\",function(left){return warning(\"W006\"),this.left=left,this.right=expression(130),this},130),infix(\"*\",\"mult\",140),infix(\"/\",\"div\",140),infix(\"%\",\"mod\",140),suffix(\"++\"),prefix(\"++\",\"preinc\"),state.syntax[\"++\"].exps=!0,suffix(\"--\"),prefix(\"--\",\"predec\"),state.syntax[\"--\"].exps=!0,prefix(\"delete\",function(){var p=expression(10);return p?(\".\"!==p.id&&\"[\"!==p.id&&warning(\"W051\"),this.first=p,p.identifier&&!state.isStrict()&&(p.forgiveUndef=!0),this):this}).exps=!0,prefix(\"~\",function(){return state.option.bitwise&&warning(\"W016\",this,\"~\"),this.arity=\"unary\",this.right=expression(150),this}),prefix(\"...\",function(){return state.inES6(!0)||warning(\"W119\",this,\"spread/rest operator\",\"6\"),state.tokens.next.identifier||\"(string)\"===state.tokens.next.type||checkPunctuators(state.tokens.next,[\"[\",\"(\"])||error(\"E030\",state.tokens.next,state.tokens.next.value),expression(150),this}),prefix(\"!\",function(){return this.arity=\"unary\",this.right=expression(150),this.right||quit(\"E041\",this.line||0),bang[this.right.id]===!0&&warning(\"W018\",this,\"!\"),this}),prefix(\"typeof\",function(){var p=expression(150);return this.first=this.right=p,p||quit(\"E041\",this.line||0,this.character||0),p.identifier&&(p.forgiveUndef=!0),this}),prefix(\"new\",function(){var mp=metaProperty(\"target\",function(){state.inES6(!0)||warning(\"W119\",state.tokens.prev,\"new.target\",\"6\");for(var inFunction,c=state.funct;c&&(inFunction=!c[\"(global)\"],c[\"(arrow)\"]);)c=c[\"(context)\"];inFunction||warning(\"W136\",state.tokens.prev,\"new.target\")});if(mp)return mp;var i,c=expression(155);if(c&&\"function\"!==c.id)if(c.identifier)switch(c[\"new\"]=!0,c.value){case\"Number\":case\"String\":case\"Boolean\":case\"Math\":case\"JSON\":warning(\"W053\",state.tokens.prev,c.value);break;case\"Symbol\":state.inES6()&&warning(\"W053\",state.tokens.prev,c.value);break;case\"Function\":state.option.evil||warning(\"W054\");break;case\"Date\":case\"RegExp\":case\"this\":break;default:\"function\"!==c.id&&(i=c.value.substr(0,1),state.option.newcap&&(\"A\">i||i>\"Z\")&&!state.funct[\"(scope)\"].isPredefined(c.value)&&warning(\"W055\",state.tokens.curr))}else\".\"!==c.id&&\"[\"!==c.id&&\"(\"!==c.id&&warning(\"W056\",state.tokens.curr);else state.option.supernew||warning(\"W057\",this);return\"(\"===state.tokens.next.id||state.option.supernew||warning(\"W058\",state.tokens.curr,state.tokens.curr.value),this.first=this.right=c,this}),state.syntax[\"new\"].exps=!0,prefix(\"void\").exps=!0,infix(\".\",function(left,that){var m=identifier(!1,!0);return\"string\"==typeof m&&countMember(m),that.left=left,that.right=m,m&&\"hasOwnProperty\"===m&&\"=\"===state.tokens.next.value&&warning(\"W001\"),!left||\"arguments\"!==left.value||\"callee\"!==m&&\"caller\"!==m?state.option.evil||!left||\"document\"!==left.value||\"write\"!==m&&\"writeln\"!==m||warning(\"W060\",left):state.option.noarg?warning(\"W059\",left,m):state.isStrict()&&error(\"E008\"),state.option.evil||\"eval\"!==m&&\"execScript\"!==m||isGlobalEval(left,state)&&warning(\"W061\"),that},160,!0),infix(\"(\",function(left,that){state.option.immed&&left&&!left.immed&&\"function\"===left.id&&warning(\"W062\");var n=0,p=[];if(left&&\"(identifier)\"===left.type&&left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)&&-1===\"Array Number String Boolean Date Object Error Symbol\".indexOf(left.value)&&(\"Math\"===left.value?warning(\"W063\",left):state.option.newcap&&warning(\"W064\",left)),\")\"!==state.tokens.next.id)for(;p[p.length]=expression(10),n+=1,\",\"===state.tokens.next.id;)comma();return advance(\")\"),\"object\"==typeof left&&(state.inES5()||\"parseInt\"!==left.value||1!==n||warning(\"W065\",state.tokens.curr),state.option.evil||(\"eval\"===left.value||\"Function\"===left.value||\"execScript\"===left.value?(warning(\"W061\",left),p[0]&&\"(string)\"===[0].id&&addInternalSrc(left,p[0].value)):!p[0]||\"(string)\"!==p[0].id||\"setTimeout\"!==left.value&&\"setInterval\"!==left.value?!p[0]||\"(string)\"!==p[0].id||\".\"!==left.value||\"window\"!==left.left.value||\"setTimeout\"!==left.right&&\"setInterval\"!==left.right||(warning(\"W066\",left),addInternalSrc(left,p[0].value)):(warning(\"W066\",left),addInternalSrc(left,p[0].value))),left.identifier||\".\"===left.id||\"[\"===left.id||\"=>\"===left.id||\"(\"===left.id||\"&&\"===left.id||\"||\"===left.id||\"?\"===left.id||state.inES6()&&left[\"(name)\"]||warning(\"W067\",that)),that.left=left,that},155,!0).exps=!0,prefix(\"(\",function(){var pn1,ret,triggerFnExpr,first,last,pn=state.tokens.next,i=-1,parens=1,opening=state.tokens.curr,preceeding=state.tokens.prev,isNecessary=!state.option.singleGroups;do\"(\"===pn.value?parens+=1:\")\"===pn.value&&(parens-=1),i+=1,pn1=pn,pn=peek(i);while((0!==parens||\")\"!==pn1.value)&&\";\"!==pn.value&&\"(end)\"!==pn.type);if(\"function\"===state.tokens.next.id&&(triggerFnExpr=state.tokens.next.immed=!0),\"=>\"===pn.value)return doFunction({type:\"arrow\",parsedOpening:!0});var exprs=[];if(\")\"!==state.tokens.next.id)for(;exprs.push(expression(10)),\",\"===state.tokens.next.id;)state.option.nocomma&&warning(\"W127\"),comma();return advance(\")\",this),state.option.immed&&exprs[0]&&\"function\"===exprs[0].id&&\"(\"!==state.tokens.next.id&&\".\"!==state.tokens.next.id&&\"[\"!==state.tokens.next.id&&warning(\"W068\",this),exprs.length?(exprs.length>1?(ret=Object.create(state.syntax[\",\"]),ret.exprs=exprs,first=exprs[0],last=exprs[exprs.length-1],isNecessary||(isNecessary=preceeding.assign||preceeding.delim)):(ret=first=last=exprs[0],isNecessary||(isNecessary=opening.beginsStmt&&(\"{\"===ret.id||triggerFnExpr||isFunctor(ret))||triggerFnExpr&&(!isEndOfExpr()||\"}\"!==state.tokens.prev.id)||isFunctor(ret)&&!isEndOfExpr()||\"{\"===ret.id&&\"=>\"===preceeding.id||\"(number)\"===ret.type&&checkPunctuator(pn,\".\")&&/^\\\\d+$/.test(ret.value))),ret&&(!isNecessary&&(first.left||first.right||ret.exprs)&&(isNecessary=!isBeginOfExpr(preceeding)&&first.lbp<=preceeding.lbp||!isEndOfExpr()&&last.lbp<state.tokens.next.lbp),isNecessary||warning(\"W126\",opening),ret.paren=!0),ret):void 0}),application(\"=>\"),infix(\"[\",function(left,that){var s,e=expression(10);return e&&\"(string)\"===e.type&&(state.option.evil||\"eval\"!==e.value&&\"execScript\"!==e.value||isGlobalEval(left,state)&&warning(\"W061\"),countMember(e.value),!state.option.sub&&reg.identifier.test(e.value)&&(s=state.syntax[e.value],s&&isReserved(s)||warning(\"W069\",state.tokens.prev,e.value))),advance(\"]\",that),e&&\"hasOwnProperty\"===e.value&&\"=\"===state.tokens.next.value&&warning(\"W001\"),that.left=left,that.right=e,that},160,!0),prefix(\"[\",function(){var blocktype=lookupBlockType();if(blocktype.isCompArray)return state.option.esnext||state.inMoz()||warning(\"W118\",state.tokens.curr,\"array comprehension\"),comprehensiveArrayExpression();if(blocktype.isDestAssign)return this.destructAssign=destructuringPattern({openingParsed:!0,assignment:!0}),this;var b=state.tokens.curr.line!==startLine(state.tokens.next);for(this.first=[],b&&(indent+=state.option.indent,state.tokens.next.from===indent+state.option.indent&&(indent+=state.option.indent));\"(end)\"!==state.tokens.next.id;){for(;\",\"===state.tokens.next.id;){if(!state.option.elision){if(state.inES5()){warning(\"W128\");do advance(\",\");while(\",\"===state.tokens.next.id);continue}warning(\"W070\")}advance(\",\")}if(\"]\"===state.tokens.next.id)break;if(this.first.push(expression(10)),\",\"!==state.tokens.next.id)break;if(comma({allowTrailing:!0}),\"]\"===state.tokens.next.id&&!state.inES5()){warning(\"W070\",state.tokens.curr);break}}return b&&(indent-=state.option.indent),advance(\"]\",this),this}),function(x){x.nud=function(){var b,f,i,p,t,nextVal,isGeneratorMethod=!1,props=Object.create(null);b=state.tokens.curr.line!==startLine(state.tokens.next),b&&(indent+=state.option.indent,state.tokens.next.from===indent+state.option.indent&&(indent+=state.option.indent));var blocktype=lookupBlockType();if(blocktype.isDestAssign)return this.destructAssign=destructuringPattern({openingParsed:!0,assignment:!0}),this;for(;\"}\"!==state.tokens.next.id;){if(nextVal=state.tokens.next.value,!state.tokens.next.identifier||\",\"!==peekIgnoreEOL().id&&\"}\"!==peekIgnoreEOL().id)if(\":\"===peek().id||\"get\"!==nextVal&&\"set\"!==nextVal){if(\"*\"===state.tokens.next.value&&\"(punctuator)\"===state.tokens.next.type?(state.inES6()||warning(\"W104\",state.tokens.next,\"generator functions\",\"6\"),advance(\"*\"),isGeneratorMethod=!0):isGeneratorMethod=!1,\"[\"===state.tokens.next.id)i=computedPropertyName(),state.nameStack.set(i);else if(state.nameStack.set(state.tokens.next),i=propertyName(),saveProperty(props,i,state.tokens.next),\"string\"!=typeof i)break;\"(\"===state.tokens.next.value?(state.inES6()||warning(\"W104\",state.tokens.curr,\"concise methods\",\"6\"),doFunction({type:isGeneratorMethod?\"generator\":null})):(advance(\":\"),expression(10))}else advance(nextVal),state.inES5()||error(\"E034\"),i=propertyName(),i||state.inES6()||error(\"E035\"),i&&saveAccessor(nextVal,props,i,state.tokens.curr),t=state.tokens.next,f=doFunction(),p=f[\"(params)\"],\"get\"===nextVal&&i&&p?warning(\"W076\",t,p[0],i):\"set\"!==nextVal||!i||p&&1===p.length||warning(\"W077\",t,i);else state.inES6()||warning(\"W104\",state.tokens.next,\"object short notation\",\"6\"),i=propertyName(!0),saveProperty(props,i,state.tokens.next),expression(10);if(countMember(i),\",\"!==state.tokens.next.id)break;comma({allowTrailing:!0,property:!0}),\",\"===state.tokens.next.id?warning(\"W070\",state.tokens.curr):\"}\"!==state.tokens.next.id||state.inES5()||warning(\"W070\",state.tokens.curr)}return b&&(indent-=state.option.indent),advance(\"}\",this),checkProperties(props),this},x.fud=function(){error(\"E036\",state.tokens.curr)}}(delim(\"{\"));var conststatement=stmt(\"const\",function(context){return blockVariableStatement(\"const\",this,context)});conststatement.exps=!0;var letstatement=stmt(\"let\",function(context){return blockVariableStatement(\"let\",this,context)});letstatement.exps=!0;var varstatement=stmt(\"var\",function(context){var tokens,lone,value,prefix=context&&context.prefix,inexport=context&&context.inexport,implied=context&&context.implied,report=!(context&&context.ignore);for(this.first=[];;){var names=[];_.contains([\"{\",\"[\"],state.tokens.next.value)?(tokens=destructuringPattern(),lone=!1):(tokens=[{id:identifier(),token:state.tokens.curr}],lone=!0),prefix&&implied||!report||!state.option.varstmt||warning(\"W132\",this),this.first=this.first.concat(names);for(var t in tokens)tokens.hasOwnProperty(t)&&(t=tokens[t],!implied&&state.funct[\"(global)\"]&&(predefined[t.id]===!1?warning(\"W079\",t.token,t.id):state.option.futurehostile===!1&&(!state.inES5()&&vars.ecmaIdentifiers[5][t.id]===!1||!state.inES6()&&vars.ecmaIdentifiers[6][t.id]===!1)&&warning(\"W129\",t.token,t.id)),t.id&&(\"for\"===implied?(state.funct[\"(scope)\"].has(t.id)||report&&warning(\"W088\",t.token,t.id),state.funct[\"(scope)\"].block.use(t.id,t.token)):(state.funct[\"(scope)\"].addlabel(t.id,{type:\"var\",token:t.token}),lone&&inexport&&state.funct[\"(scope)\"].setExported(t.id,t.token)),names.push(t.token)));if(\"=\"===state.tokens.next.id&&(state.nameStack.set(state.tokens.curr),advance(\"=\"),prefix||!report||state.funct[\"(loopage)\"]||\"undefined\"!==state.tokens.next.id||warning(\"W080\",state.tokens.prev,state.tokens.prev.value),\"=\"===peek(0).id&&state.tokens.next.identifier&&(!prefix&&report&&!state.funct[\"(params)\"]||-1===state.funct[\"(params)\"].indexOf(state.tokens.next.value))&&warning(\"W120\",state.tokens.next,state.tokens.next.value),value=expression(prefix?120:10),lone?tokens[0].first=value:destructuringPatternMatch(names,value)),\",\"!==state.tokens.next.id)break;comma()}return this});varstatement.exps=!0,blockstmt(\"class\",function(){return classdef.call(this,!0)}),blockstmt(\"function\",function(context){var inexport=context&&context.inexport,generator=!1;\"*\"===state.tokens.next.value&&(advance(\"*\"),state.inES6({strict:!0})?generator=!0:warning(\"W119\",state.tokens.curr,\"function*\",\"6\")),inblock&&warning(\"W082\",state.tokens.curr);var i=optionalidentifier();return state.funct[\"(scope)\"].addlabel(i,{type:\"function\",token:state.tokens.curr}),void 0===i?warning(\"W025\"):inexport&&state.funct[\"(scope)\"].setExported(i,state.tokens.prev),doFunction({name:i,statement:this,type:generator?\"generator\":null,ignoreLoopFunc:inblock}),\"(\"===state.tokens.next.id&&state.tokens.next.line===state.tokens.curr.line&&error(\"E039\"),this}),prefix(\"function\",function(){var generator=!1;\"*\"===state.tokens.next.value&&(state.inES6()||warning(\"W119\",state.tokens.curr,\"function*\",\"6\"),advance(\"*\"),generator=!0);var i=optionalidentifier();return doFunction({name:i,type:generator?\"generator\":null}),this}),blockstmt(\"if\",function(){var t=state.tokens.next;increaseComplexityCount(),state.condition=!0,advance(\"(\");var expr=expression(0);checkCondAssignment(expr);var forinifcheck=null;state.option.forin&&state.forinifcheckneeded&&(state.forinifcheckneeded=!1,forinifcheck=state.forinifchecks[state.forinifchecks.length-1],forinifcheck.type=\"(punctuator)\"===expr.type&&\"!\"===expr.value?\"(negative)\":\"(positive)\"),advance(\")\",t),state.condition=!1;var s=block(!0,!0);return forinifcheck&&\"(negative)\"===forinifcheck.type&&s&&s[0]&&\"(identifier)\"===s[0].type&&\"continue\"===s[0].value&&(forinifcheck.type=\"(negative-with-continue)\"),\"else\"===state.tokens.next.id&&(advance(\"else\"),\"if\"===state.tokens.next.id||\"switch\"===state.tokens.next.id?statement():block(!0,!0)),this}),blockstmt(\"try\",function(){function doCatch(){if(advance(\"catch\"),advance(\"(\"),state.funct[\"(scope)\"].stack(\"catchparams\"),checkPunctuators(state.tokens.next,[\"[\",\"{\"])){var tokens=destructuringPattern();_.each(tokens,function(token){token.id&&state.funct[\"(scope)\"].addParam(token.id,token,\"exception\")})}else\"(identifier)\"!==state.tokens.next.type?warning(\"E030\",state.tokens.next,state.tokens.next.value):state.funct[\"(scope)\"].addParam(identifier(),state.tokens.curr,\"exception\");\"if\"===state.tokens.next.value&&(state.inMoz()||warning(\"W118\",state.tokens.curr,\"catch filter\"),advance(\"if\"),expression(0)),advance(\")\"),block(!1),state.funct[\"(scope)\"].unstack()}var b;for(block(!0);\"catch\"===state.tokens.next.id;)increaseComplexityCount(),b&&!state.inMoz()&&warning(\"W118\",state.tokens.next,\"multiple catch blocks\"),doCatch(),b=!0;return\"finally\"===state.tokens.next.id?(advance(\"finally\"),block(!0),void 0):(b||error(\"E021\",state.tokens.next,\"catch\",state.tokens.next.value),this)}),blockstmt(\"while\",function(){var t=state.tokens.next;return state.funct[\"(breakage)\"]+=1,state.funct[\"(loopage)\"]+=1,increaseComplexityCount(),advance(\"(\"),checkCondAssignment(expression(0)),advance(\")\",t),block(!0,!0),state.funct[\"(breakage)\"]-=1,state.funct[\"(loopage)\"]-=1,this}).labelled=!0,blockstmt(\"with\",function(){var t=state.tokens.next;return state.isStrict()?error(\"E010\",state.tokens.curr):state.option.withstmt||warning(\"W085\",state.tokens.curr),advance(\"(\"),expression(0),advance(\")\",t),block(!0,!0),this}),blockstmt(\"switch\",function(){var t=state.tokens.next,g=!1,noindent=!1;\\nfor(state.funct[\"(breakage)\"]+=1,advance(\"(\"),checkCondAssignment(expression(0)),advance(\")\",t),t=state.tokens.next,advance(\"{\"),state.tokens.next.from===indent&&(noindent=!0),noindent||(indent+=state.option.indent),this.cases=[];;)switch(state.tokens.next.id){case\"case\":switch(state.funct[\"(verb)\"]){case\"yield\":case\"break\":case\"case\":case\"continue\":case\"return\":case\"switch\":case\"throw\":break;default:state.tokens.curr.caseFallsThrough||warning(\"W086\",state.tokens.curr,\"case\")}advance(\"case\"),this.cases.push(expression(0)),increaseComplexityCount(),g=!0,advance(\":\"),state.funct[\"(verb)\"]=\"case\";break;case\"default\":switch(state.funct[\"(verb)\"]){case\"yield\":case\"break\":case\"continue\":case\"return\":case\"throw\":break;default:this.cases.length&&(state.tokens.curr.caseFallsThrough||warning(\"W086\",state.tokens.curr,\"default\"))}advance(\"default\"),g=!0,advance(\":\");break;case\"}\":return noindent||(indent-=state.option.indent),advance(\"}\",t),state.funct[\"(breakage)\"]-=1,state.funct[\"(verb)\"]=void 0,void 0;case\"(end)\":return error(\"E023\",state.tokens.next,\"}\"),void 0;default:if(indent+=state.option.indent,g)switch(state.tokens.curr.id){case\",\":return error(\"E040\"),void 0;case\":\":g=!1,statements();break;default:return error(\"E025\",state.tokens.curr),void 0}else{if(\":\"!==state.tokens.curr.id)return error(\"E021\",state.tokens.next,\"case\",state.tokens.next.value),void 0;advance(\":\"),error(\"E024\",state.tokens.curr,\":\"),statements()}indent-=state.option.indent}return this}).labelled=!0,stmt(\"debugger\",function(){return state.option.debug||warning(\"W087\",this),this}).exps=!0,function(){var x=stmt(\"do\",function(){state.funct[\"(breakage)\"]+=1,state.funct[\"(loopage)\"]+=1,increaseComplexityCount(),this.first=block(!0,!0),advance(\"while\");var t=state.tokens.next;return advance(\"(\"),checkCondAssignment(expression(0)),advance(\")\",t),state.funct[\"(breakage)\"]-=1,state.funct[\"(loopage)\"]-=1,this});x.labelled=!0,x.exps=!0}(),blockstmt(\"for\",function(){var s,t=state.tokens.next,letscope=!1,foreachtok=null;\"each\"===t.value&&(foreachtok=t,advance(\"each\"),state.inMoz()||warning(\"W118\",state.tokens.curr,\"for each\")),increaseComplexityCount(),advance(\"(\");var nextop,comma,initializer,i=0,inof=[\"in\",\"of\"],level=0;checkPunctuators(state.tokens.next,[\"{\",\"[\"])&&++level;do{if(nextop=peek(i),++i,checkPunctuators(nextop,[\"{\",\"[\"])?++level:checkPunctuators(nextop,[\"}\",\"]\"])&&--level,0>level)break;0===level&&(!comma&&checkPunctuator(nextop,\",\")?comma=nextop:!initializer&&checkPunctuator(nextop,\"=\")&&(initializer=nextop))}while(level>0||!_.contains(inof,nextop.value)&&\";\"!==nextop.value&&\"(end)\"!==nextop.type);if(_.contains(inof,nextop.value)){state.inES6()||\"of\"!==nextop.value||warning(\"W104\",nextop,\"for of\",\"6\");var ok=!(initializer||comma);if(initializer&&error(\"W133\",comma,nextop.value,\"initializer is forbidden\"),comma&&error(\"W133\",comma,nextop.value,\"more than one ForBinding\"),\"var\"===state.tokens.next.id?(advance(\"var\"),state.tokens.curr.fud({prefix:!0})):\"let\"===state.tokens.next.id||\"const\"===state.tokens.next.id?(advance(state.tokens.next.id),letscope=!0,state.funct[\"(scope)\"].stack(),state.tokens.curr.fud({prefix:!0})):Object.create(varstatement).fud({prefix:!0,implied:\"for\",ignore:!ok}),advance(nextop.value),expression(20),advance(\")\",t),\"in\"===nextop.value&&state.option.forin&&(state.forinifcheckneeded=!0,void 0===state.forinifchecks&&(state.forinifchecks=[]),state.forinifchecks.push({type:\"(none)\"})),state.funct[\"(breakage)\"]+=1,state.funct[\"(loopage)\"]+=1,s=block(!0,!0),\"in\"===nextop.value&&state.option.forin){if(state.forinifchecks&&state.forinifchecks.length>0){var check=state.forinifchecks.pop();(s&&s.length>0&&(\"object\"!=typeof s[0]||\"if\"!==s[0].value)||\"(positive)\"===check.type&&s.length>1||\"(negative)\"===check.type)&&warning(\"W089\",this)}state.forinifcheckneeded=!1}state.funct[\"(breakage)\"]-=1,state.funct[\"(loopage)\"]-=1}else{if(foreachtok&&error(\"E045\",foreachtok),\";\"!==state.tokens.next.id)if(\"var\"===state.tokens.next.id)advance(\"var\"),state.tokens.curr.fud();else if(\"let\"===state.tokens.next.id)advance(\"let\"),letscope=!0,state.funct[\"(scope)\"].stack(),state.tokens.curr.fud();else for(;expression(0,\"for\"),\",\"===state.tokens.next.id;)comma();if(nolinebreak(state.tokens.curr),advance(\";\"),state.funct[\"(loopage)\"]+=1,\";\"!==state.tokens.next.id&&checkCondAssignment(expression(0)),nolinebreak(state.tokens.curr),advance(\";\"),\";\"===state.tokens.next.id&&error(\"E021\",state.tokens.next,\")\",\";\"),\")\"!==state.tokens.next.id)for(;expression(0,\"for\"),\",\"===state.tokens.next.id;)comma();advance(\")\",t),state.funct[\"(breakage)\"]+=1,block(!0,!0),state.funct[\"(breakage)\"]-=1,state.funct[\"(loopage)\"]-=1}return letscope&&state.funct[\"(scope)\"].unstack(),this}).labelled=!0,stmt(\"break\",function(){var v=state.tokens.next.value;return state.option.asi||nolinebreak(this),\";\"===state.tokens.next.id||state.tokens.next.reach||state.tokens.curr.line!==startLine(state.tokens.next)?0===state.funct[\"(breakage)\"]&&warning(\"W052\",state.tokens.next,this.value):(state.funct[\"(scope)\"].funct.hasBreakLabel(v)||warning(\"W090\",state.tokens.next,v),this.first=state.tokens.next,advance()),reachable(this),this}).exps=!0,stmt(\"continue\",function(){var v=state.tokens.next.value;return 0===state.funct[\"(breakage)\"]&&warning(\"W052\",state.tokens.next,this.value),state.funct[\"(loopage)\"]||warning(\"W052\",state.tokens.next,this.value),state.option.asi||nolinebreak(this),\";\"===state.tokens.next.id||state.tokens.next.reach||state.tokens.curr.line===startLine(state.tokens.next)&&(state.funct[\"(scope)\"].funct.hasBreakLabel(v)||warning(\"W090\",state.tokens.next,v),this.first=state.tokens.next,advance()),reachable(this),this}).exps=!0,stmt(\"return\",function(){return this.line===startLine(state.tokens.next)?\";\"===state.tokens.next.id||state.tokens.next.reach||(this.first=expression(0),!this.first||\"(punctuator)\"!==this.first.type||\"=\"!==this.first.value||this.first.paren||state.option.boss||warningAt(\"W093\",this.first.line,this.first.character)):\"(punctuator)\"===state.tokens.next.type&&[\"[\",\"{\",\"+\",\"-\"].indexOf(state.tokens.next.value)>-1&&nolinebreak(this),reachable(this),this}).exps=!0,function(x){x.exps=!0,x.lbp=25}(prefix(\"yield\",function(){var prev=state.tokens.prev;state.inES6(!0)&&!state.funct[\"(generator)\"]?\"(catch)\"===state.funct[\"(name)\"]&&state.funct[\"(context)\"][\"(generator)\"]||error(\"E046\",state.tokens.curr,\"yield\"):state.inES6()||warning(\"W104\",state.tokens.curr,\"yield\",\"6\"),state.funct[\"(generator)\"]=\"yielded\";var delegatingYield=!1;return\"*\"===state.tokens.next.value&&(delegatingYield=!0,advance(\"*\")),this.line!==startLine(state.tokens.next)&&state.inMoz()?state.option.asi||nolinebreak(this):((delegatingYield||\";\"!==state.tokens.next.id&&!state.option.asi&&!state.tokens.next.reach&&state.tokens.next.nud)&&(nobreaknonadjacent(state.tokens.curr,state.tokens.next),this.first=expression(10),\"(punctuator)\"!==this.first.type||\"=\"!==this.first.value||this.first.paren||state.option.boss||warningAt(\"W093\",this.first.line,this.first.character)),state.inMoz()&&\")\"!==state.tokens.next.id&&(prev.lbp>30||!prev.assign&&!isEndOfExpr()||\"yield\"===prev.id)&&error(\"E050\",this)),this})),stmt(\"throw\",function(){return nolinebreak(this),this.first=expression(20),reachable(this),this}).exps=!0,stmt(\"import\",function(){if(state.inES6()||warning(\"W119\",state.tokens.curr,\"import\",\"6\"),\"(string)\"===state.tokens.next.type)return advance(\"(string)\"),this;if(state.tokens.next.identifier){if(this.name=identifier(),state.funct[\"(scope)\"].addlabel(this.name,{type:\"const\",token:state.tokens.curr}),\",\"!==state.tokens.next.value)return advance(\"from\"),advance(\"(string)\"),this;advance(\",\")}if(\"*\"===state.tokens.next.id)advance(\"*\"),advance(\"as\"),state.tokens.next.identifier&&(this.name=identifier(),state.funct[\"(scope)\"].addlabel(this.name,{type:\"const\",token:state.tokens.curr}));else for(advance(\"{\");;){if(\"}\"===state.tokens.next.value){advance(\"}\");break}var importName;if(\"default\"===state.tokens.next.type?(importName=\"default\",advance(\"default\")):importName=identifier(),\"as\"===state.tokens.next.value&&(advance(\"as\"),importName=identifier()),state.funct[\"(scope)\"].addlabel(importName,{type:\"const\",token:state.tokens.curr}),\",\"!==state.tokens.next.value){if(\"}\"===state.tokens.next.value){advance(\"}\");break}error(\"E024\",state.tokens.next,state.tokens.next.value);break}advance(\",\")}return advance(\"from\"),advance(\"(string)\"),this}).exps=!0,stmt(\"export\",function(){var token,identifier,ok=!0;if(state.inES6()||(warning(\"W119\",state.tokens.curr,\"export\",\"6\"),ok=!1),state.funct[\"(scope)\"].block.isGlobal()||(error(\"E053\",state.tokens.curr),ok=!1),\"*\"===state.tokens.next.value)return advance(\"*\"),advance(\"from\"),advance(\"(string)\"),this;if(\"default\"===state.tokens.next.type){state.nameStack.set(state.tokens.next),advance(\"default\");var exportType=state.tokens.next.id;return(\"function\"===exportType||\"class\"===exportType)&&(this.block=!0),token=peek(),expression(10),identifier=token.value,this.block&&(state.funct[\"(scope)\"].addlabel(identifier,{type:exportType,token:token}),state.funct[\"(scope)\"].setExported(identifier,token)),this}if(\"{\"===state.tokens.next.value){advance(\"{\");for(var exportedTokens=[];;){if(state.tokens.next.identifier||error(\"E030\",state.tokens.next,state.tokens.next.value),advance(),exportedTokens.push(state.tokens.curr),\"as\"===state.tokens.next.value&&(advance(\"as\"),state.tokens.next.identifier||error(\"E030\",state.tokens.next,state.tokens.next.value),advance()),\",\"!==state.tokens.next.value){if(\"}\"===state.tokens.next.value){advance(\"}\");break}error(\"E024\",state.tokens.next,state.tokens.next.value);break}advance(\",\")}return\"from\"===state.tokens.next.value?(advance(\"from\"),advance(\"(string)\")):ok&&exportedTokens.forEach(function(token){state.funct[\"(scope)\"].setExported(token.value,token)}),this}if(\"var\"===state.tokens.next.id)advance(\"var\"),state.tokens.curr.fud({inexport:!0});else if(\"let\"===state.tokens.next.id)advance(\"let\"),state.tokens.curr.fud({inexport:!0});else if(\"const\"===state.tokens.next.id)advance(\"const\"),state.tokens.curr.fud({inexport:!0});else if(\"function\"===state.tokens.next.id)this.block=!0,advance(\"function\"),state.syntax[\"function\"].fud({inexport:!0});else if(\"class\"===state.tokens.next.id){this.block=!0,advance(\"class\");var classNameToken=state.tokens.next;state.syntax[\"class\"].fud(),state.funct[\"(scope)\"].setExported(classNameToken.value,classNameToken)}else error(\"E024\",state.tokens.next,state.tokens.next.value);return this}).exps=!0,FutureReservedWord(\"abstract\"),FutureReservedWord(\"boolean\"),FutureReservedWord(\"byte\"),FutureReservedWord(\"char\"),FutureReservedWord(\"class\",{es5:!0,nud:classdef}),FutureReservedWord(\"double\"),FutureReservedWord(\"enum\",{es5:!0}),FutureReservedWord(\"export\",{es5:!0}),FutureReservedWord(\"extends\",{es5:!0}),FutureReservedWord(\"final\"),FutureReservedWord(\"float\"),FutureReservedWord(\"goto\"),FutureReservedWord(\"implements\",{es5:!0,strictOnly:!0}),FutureReservedWord(\"import\",{es5:!0}),FutureReservedWord(\"int\"),FutureReservedWord(\"interface\",{es5:!0,strictOnly:!0}),FutureReservedWord(\"long\"),FutureReservedWord(\"native\"),FutureReservedWord(\"package\",{es5:!0,strictOnly:!0}),FutureReservedWord(\"private\",{es5:!0,strictOnly:!0}),FutureReservedWord(\"protected\",{es5:!0,strictOnly:!0}),FutureReservedWord(\"public\",{es5:!0,strictOnly:!0}),FutureReservedWord(\"short\"),FutureReservedWord(\"static\",{es5:!0,strictOnly:!0}),FutureReservedWord(\"super\",{es5:!0}),FutureReservedWord(\"synchronized\"),FutureReservedWord(\"transient\"),FutureReservedWord(\"volatile\");var lookupBlockType=function(){var pn,pn1,prev,i=-1,bracketStack=0,ret={};checkPunctuators(state.tokens.curr,[\"[\",\"{\"])&&(bracketStack+=1);do{if(prev=-1===i?state.tokens.curr:pn,pn=-1===i?state.tokens.next:peek(i),pn1=peek(i+1),i+=1,checkPunctuators(pn,[\"[\",\"{\"])?bracketStack+=1:checkPunctuators(pn,[\"]\",\"}\"])&&(bracketStack-=1),1===bracketStack&&pn.identifier&&\"for\"===pn.value&&!checkPunctuator(prev,\".\")){ret.isCompArray=!0,ret.notJson=!0;break}if(0===bracketStack&&checkPunctuators(pn,[\"}\",\"]\"])){if(\"=\"===pn1.value){ret.isDestAssign=!0,ret.notJson=!0;break}if(\".\"===pn1.value){ret.notJson=!0;break}}checkPunctuator(pn,\";\")&&(ret.isBlock=!0,ret.notJson=!0)}while(bracketStack>0&&\"(end)\"!==pn.id);return ret},arrayComprehension=function(){function declare(v){var l=_current.variables.filter(function(elt){return elt.value===v?(elt.undef=!1,v):void 0}).length;return 0!==l}function use(v){var l=_current.variables.filter(function(elt){return elt.value!==v||elt.undef?void 0:(elt.unused===!0&&(elt.unused=!1),v)}).length;return 0===l}var _current,CompArray=function(){this.mode=\"use\",this.variables=[]},_carrays=[];return{stack:function(){_current=new CompArray,_carrays.push(_current)},unstack:function(){_current.variables.filter(function(v){v.unused&&warning(\"W098\",v.token,v.raw_text||v.value),v.undef&&state.funct[\"(scope)\"].block.use(v.value,v.token)}),_carrays.splice(-1,1),_current=_carrays[_carrays.length-1]},setState:function(s){_.contains([\"use\",\"define\",\"generate\",\"filter\"],s)&&(_current.mode=s)},check:function(v){return _current?_current&&\"use\"===_current.mode?(use(v)&&_current.variables.push({funct:state.funct,token:state.tokens.curr,value:v,undef:!0,unused:!1}),!0):_current&&\"define\"===_current.mode?(declare(v)||_current.variables.push({funct:state.funct,token:state.tokens.curr,value:v,undef:!1,unused:!0}),!0):_current&&\"generate\"===_current.mode?(state.funct[\"(scope)\"].block.use(v,state.tokens.curr),!0):_current&&\"filter\"===_current.mode?(use(v)&&state.funct[\"(scope)\"].block.use(v,state.tokens.curr),!0):!1:void 0}}},escapeRegex=function(str){return str.replace(/[-\\\\/\\\\\\\\^$*+?.()|[\\\\]{}]/g,\"\\\\\\\\$&\")},itself=function(s,o,g){function each(obj,cb){obj&&(Array.isArray(obj)||\"object\"!=typeof obj||(obj=Object.keys(obj)),obj.forEach(cb))}var i,k,x,reIgnoreStr,reIgnore,optionKeys,newOptionObj={},newIgnoredObj={};o=_.clone(o),state.reset(),o&&o.scope?JSHINT.scope=o.scope:(JSHINT.errors=[],JSHINT.undefs=[],JSHINT.internals=[],JSHINT.blacklist={},JSHINT.scope=\"(main)\"),predefined=Object.create(null),combine(predefined,vars.ecmaIdentifiers[3]),combine(predefined,vars.reservedVars),combine(predefined,g||{}),declared=Object.create(null);var exported=Object.create(null);if(o)for(each(o.predef||null,function(item){var slice,prop;\"-\"===item[0]?(slice=item.slice(1),JSHINT.blacklist[slice]=slice,delete predefined[slice]):(prop=Object.getOwnPropertyDescriptor(o.predef,item),predefined[item]=prop?prop.value:!1)}),each(o.exported||null,function(item){exported[item]=!0}),delete o.predef,delete o.exported,optionKeys=Object.keys(o),x=0;optionKeys.length>x;x++)if(/^-W\\\\d{3}$/g.test(optionKeys[x]))newIgnoredObj[optionKeys[x].slice(1)]=!0;else{var optionKey=optionKeys[x];newOptionObj[optionKey]=o[optionKey],(\"esversion\"===optionKey&&5===o[optionKey]||\"es5\"===optionKey&&o[optionKey])&&warning(\"I003\"),\"newcap\"===optionKeys[x]&&o[optionKey]===!1&&(newOptionObj[\"(explicitNewcap)\"]=!0)}state.option=newOptionObj,state.ignored=newIgnoredObj,state.option.indent=state.option.indent||4,state.option.maxerr=state.option.maxerr||50,indent=1;var scopeManagerInst=scopeManager(state,predefined,exported,declared);if(scopeManagerInst.on(\"warning\",function(ev){warning.apply(null,[ev.code,ev.token].concat(ev.data))}),scopeManagerInst.on(\"error\",function(ev){error.apply(null,[ev.code,ev.token].concat(ev.data))}),state.funct=functor(\"(global)\",null,{\"(global)\":!0,\"(scope)\":scopeManagerInst,\"(comparray)\":arrayComprehension(),\"(metrics)\":createMetrics(state.tokens.next)}),functions=[state.funct],urls=[],stack=null,member={},membersOnly=null,inblock=!1,lookahead=[],!isString(s)&&!Array.isArray(s))return errorAt(\"E004\",0),!1;api={get isJSON(){return state.jsonMode},getOption:function(name){return state.option[name]||null},getCache:function(name){return state.cache[name]},setCache:function(name,value){state.cache[name]=value},warn:function(code,data){warningAt.apply(null,[code,data.line,data.char].concat(data.data))},on:function(names,listener){names.split(\" \").forEach(function(name){emitter.on(name,listener)}.bind(this))}},emitter.removeAllListeners(),(extraModules||[]).forEach(function(func){func(api)}),state.tokens.prev=state.tokens.curr=state.tokens.next=state.syntax[\"(begin)\"],o&&o.ignoreDelimiters&&(Array.isArray(o.ignoreDelimiters)||(o.ignoreDelimiters=[o.ignoreDelimiters]),o.ignoreDelimiters.forEach(function(delimiterPair){delimiterPair.start&&delimiterPair.end&&(reIgnoreStr=escapeRegex(delimiterPair.start)+\"[\\\\\\\\s\\\\\\\\S]*?\"+escapeRegex(delimiterPair.end),reIgnore=RegExp(reIgnoreStr,\"ig\"),s=s.replace(reIgnore,function(match){return match.replace(/./g,\" \")}))})),lex=new Lexer(s),lex.on(\"warning\",function(ev){warningAt.apply(null,[ev.code,ev.line,ev.character].concat(ev.data))}),lex.on(\"error\",function(ev){errorAt.apply(null,[ev.code,ev.line,ev.character].concat(ev.data))}),lex.on(\"fatal\",function(ev){quit(\"E041\",ev.line,ev.from)}),lex.on(\"Identifier\",function(ev){emitter.emit(\"Identifier\",ev)}),lex.on(\"String\",function(ev){emitter.emit(\"String\",ev)}),lex.on(\"Number\",function(ev){emitter.emit(\"Number\",ev)}),lex.start();for(var name in o)_.has(o,name)&&checkOption(name,state.tokens.curr);assume(),combine(predefined,g||{}),comma.first=!0;try{switch(advance(),state.tokens.next.id){case\"{\":case\"[\":destructuringAssignOrJsonValue();break;default:directives(),state.directive[\"use strict\"]&&\"global\"!==state.option.strict&&warning(\"W097\",state.tokens.prev),statements()}\"(end)\"!==state.tokens.next.id&&quit(\"E041\",state.tokens.curr.line),state.funct[\"(scope)\"].unstack()}catch(err){if(!err||\"JSHintError\"!==err.name)throw err;var nt=state.tokens.next||{};JSHINT.errors.push({scope:\"(main)\",raw:err.raw,code:err.code,reason:err.message,line:err.line||nt.line,character:err.character||nt.from},null)}if(\"(main)\"===JSHINT.scope)for(o=o||{},i=0;JSHINT.internals.length>i;i+=1)k=JSHINT.internals[i],o.scope=k.elem,itself(k.value,o,g);return 0===JSHINT.errors.length};return itself.addModule=function(func){extraModules.push(func)},itself.addModule(style.register),itself.data=function(){var fu,f,i,j,n,globals,data={functions:[],options:state.option};itself.errors.length&&(data.errors=itself.errors),state.jsonMode&&(data.json=!0);var impliedGlobals=state.funct[\"(scope)\"].getImpliedGlobals();for(impliedGlobals.length>0&&(data.implieds=impliedGlobals),urls.length>0&&(data.urls=urls),globals=state.funct[\"(scope)\"].getUsedOrDefinedGlobals(),globals.length>0&&(data.globals=globals),i=1;functions.length>i;i+=1){for(f=functions[i],fu={},j=0;functionicity.length>j;j+=1)fu[functionicity[j]]=[];for(j=0;functionicity.length>j;j+=1)0===fu[functionicity[j]].length&&delete fu[functionicity[j]];fu.name=f[\"(name)\"],fu.param=f[\"(params)\"],fu.line=f[\"(line)\"],fu.character=f[\"(character)\"],fu.last=f[\"(last)\"],fu.lastcharacter=f[\"(lastcharacter)\"],fu.metrics={complexity:f[\"(metrics)\"].ComplexityCount,parameters:f[\"(metrics)\"].arity,statements:f[\"(metrics)\"].statementCount},data.functions.push(fu)}var unuseds=state.funct[\"(scope)\"].getUnuseds();unuseds.length>0&&(data.unused=unuseds);for(n in member)if(\"number\"==typeof member[n]){data.member=member;break}return data},itself.jshint=itself,itself}();\"object\"==typeof exports&&exports&&(exports.JSHINT=JSHINT)},{\"../lodash\":\"/node_modules/jshint/lodash.js\",\"./lex.js\":\"/node_modules/jshint/src/lex.js\",\"./messages.js\":\"/node_modules/jshint/src/messages.js\",\"./options.js\":\"/node_modules/jshint/src/options.js\",\"./reg.js\":\"/node_modules/jshint/src/reg.js\",\"./scope-manager.js\":\"/node_modules/jshint/src/scope-manager.js\",\"./state.js\":\"/node_modules/jshint/src/state.js\",\"./style.js\":\"/node_modules/jshint/src/style.js\",\"./vars.js\":\"/node_modules/jshint/src/vars.js\",events:\"/node_modules/browserify/node_modules/events/events.js\"}],\"/node_modules/jshint/src/lex.js\":[function(_dereq_,module,exports){\"use strict\";function asyncTrigger(){var _checks=[];return{push:function(fn){_checks.push(fn)},check:function(){for(var check=0;_checks.length>check;++check)_checks[check]();_checks.splice(0,_checks.length)}}}function Lexer(source){var lines=source;\"string\"==typeof lines&&(lines=lines.replace(/\\\\r\\\\n/g,\"\\\\n\").replace(/\\\\r/g,\"\\\\n\").split(\"\\\\n\")),lines[0]&&\"#!\"===lines[0].substr(0,2)&&(-1!==lines[0].indexOf(\"node\")&&(state.option.node=!0),lines[0]=\"\"),this.emitter=new events.EventEmitter,this.source=source,this.setLines(lines),this.prereg=!0,this.line=0,this.char=1,this.from=1,this.input=\"\",this.inComment=!1,this.context=[],this.templateStarts=[];for(var i=0;state.option.indent>i;i+=1)state.tab+=\" \";this.ignoreLinterErrors=!1}var _=_dereq_(\"../lodash\"),events=_dereq_(\"events\"),reg=_dereq_(\"./reg.js\"),state=_dereq_(\"./state.js\").state,unicodeData=_dereq_(\"../data/ascii-identifier-data.js\"),asciiIdentifierStartTable=unicodeData.asciiIdentifierStartTable,asciiIdentifierPartTable=unicodeData.asciiIdentifierPartTable,Token={Identifier:1,Punctuator:2,NumericLiteral:3,StringLiteral:4,Comment:5,Keyword:6,NullLiteral:7,BooleanLiteral:8,RegExp:9,TemplateHead:10,TemplateMiddle:11,TemplateTail:12,NoSubstTemplate:13},Context={Block:1,Template:2};Lexer.prototype={_lines:[],inContext:function(ctxType){return this.context.length>0&&this.context[this.context.length-1].type===ctxType},pushContext:function(ctxType){this.context.push({type:ctxType})},popContext:function(){return this.context.pop()},isContext:function(context){return this.context.length>0&&this.context[this.context.length-1]===context},currentContext:function(){return this.context.length>0&&this.context[this.context.length-1]},getLines:function(){return this._lines=state.lines,this._lines},setLines:function(val){this._lines=val,state.lines=this._lines},peek:function(i){return this.input.charAt(i||0)},skip:function(i){i=i||1,this.char+=i,this.input=this.input.slice(i)},on:function(names,listener){names.split(\" \").forEach(function(name){this.emitter.on(name,listener)}.bind(this))},trigger:function(){this.emitter.emit.apply(this.emitter,Array.prototype.slice.call(arguments))},triggerAsync:function(type,args,checks,fn){checks.push(function(){fn()&&this.trigger(type,args)}.bind(this))},scanPunctuator:function(){var ch2,ch3,ch4,ch1=this.peek();switch(ch1){case\".\":if(/^[0-9]$/.test(this.peek(1)))return null;if(\".\"===this.peek(1)&&\".\"===this.peek(2))return{type:Token.Punctuator,value:\"...\"};case\"(\":case\")\":case\";\":case\",\":case\"[\":case\"]\":case\":\":case\"~\":case\"?\":return{type:Token.Punctuator,value:ch1};case\"{\":return this.pushContext(Context.Block),{type:Token.Punctuator,value:ch1};case\"}\":return this.inContext(Context.Block)&&this.popContext(),{type:Token.Punctuator,value:ch1};case\"#\":return{type:Token.Punctuator,value:ch1};case\"\":return null}return ch2=this.peek(1),ch3=this.peek(2),ch4=this.peek(3),\">\"===ch1&&\">\"===ch2&&\">\"===ch3&&\"=\"===ch4?{type:Token.Punctuator,value:\">>>=\"}:\"=\"===ch1&&\"=\"===ch2&&\"=\"===ch3?{type:Token.Punctuator,value:\"===\"}:\"!\"===ch1&&\"=\"===ch2&&\"=\"===ch3?{type:Token.Punctuator,value:\"!==\"}:\">\"===ch1&&\">\"===ch2&&\">\"===ch3?{type:Token.Punctuator,value:\">>>\"}:\"<\"===ch1&&\"<\"===ch2&&\"=\"===ch3?{type:Token.Punctuator,value:\"<<=\"}:\">\"===ch1&&\">\"===ch2&&\"=\"===ch3?{type:Token.Punctuator,value:\">>=\"}:\"=\"===ch1&&\">\"===ch2?{type:Token.Punctuator,value:ch1+ch2}:ch1===ch2&&\"+-<>&|\".indexOf(ch1)>=0?{type:Token.Punctuator,value:ch1+ch2}:\"<>=!+-*%&|^\".indexOf(ch1)>=0?\"=\"===ch2?{type:Token.Punctuator,value:ch1+ch2}:{type:Token.Punctuator,value:ch1}:\"/\"===ch1?\"=\"===ch2?{type:Token.Punctuator,value:\"/=\"}:{type:Token.Punctuator,value:\"/\"}:null},scanComments:function(){function commentToken(label,body,opt){var special=[\"jshint\",\"jslint\",\"members\",\"member\",\"globals\",\"global\",\"exported\"],isSpecial=!1,value=label+body,commentType=\"plain\";return opt=opt||{},opt.isMultiline&&(value+=\"*/\"),body=body.replace(/\\\\n/g,\" \"),\"/*\"===label&&reg.fallsThrough.test(body)&&(isSpecial=!0,commentType=\"falls through\"),special.forEach(function(str){if(!isSpecial&&(\"//\"!==label||\"jshint\"===str)&&(\" \"===body.charAt(str.length)&&body.substr(0,str.length)===str&&(isSpecial=!0,label+=str,body=body.substr(str.length)),isSpecial||\" \"!==body.charAt(0)||\" \"!==body.charAt(str.length+1)||body.substr(1,str.length)!==str||(isSpecial=!0,label=label+\" \"+str,body=body.substr(str.length+1)),isSpecial))switch(str){case\"member\":commentType=\"members\";break;case\"global\":commentType=\"globals\";break;default:var options=body.split(\":\").map(function(v){return v.replace(/^\\\\s+/,\"\").replace(/\\\\s+$/,\"\")});if(2===options.length)switch(options[0]){case\"ignore\":switch(options[1]){case\"start\":self.ignoringLinterErrors=!0,isSpecial=!1;break;case\"end\":self.ignoringLinterErrors=!1,isSpecial=!1}}commentType=str}}),{type:Token.Comment,commentType:commentType,value:value,body:body,isSpecial:isSpecial,isMultiline:opt.isMultiline||!1,isMalformed:opt.isMalformed||!1}}var ch1=this.peek(),ch2=this.peek(1),rest=this.input.substr(2),startLine=this.line,startChar=this.char,self=this;if(\"*\"===ch1&&\"/\"===ch2)return this.trigger(\"error\",{code:\"E018\",line:startLine,character:startChar}),this.skip(2),null;if(\"/\"!==ch1||\"*\"!==ch2&&\"/\"!==ch2)return null;if(\"/\"===ch2)return this.skip(this.input.length),commentToken(\"//\",rest);var body=\"\";if(\"*\"===ch2){for(this.inComment=!0,this.skip(2);\"*\"!==this.peek()||\"/\"!==this.peek(1);)if(\"\"===this.peek()){if(body+=\"\\\\n\",!this.nextLine())return this.trigger(\"error\",{code:\"E017\",line:startLine,character:startChar}),this.inComment=!1,commentToken(\"/*\",body,{isMultiline:!0,isMalformed:!0})}else body+=this.peek(),this.skip();return this.skip(2),this.inComment=!1,commentToken(\"/*\",body,{isMultiline:!0})}},scanKeyword:function(){var result=/^[a-zA-Z_$][a-zA-Z0-9_$]*/.exec(this.input),keywords=[\"if\",\"in\",\"do\",\"var\",\"for\",\"new\",\"try\",\"let\",\"this\",\"else\",\"case\",\"void\",\"with\",\"enum\",\"while\",\"break\",\"catch\",\"throw\",\"const\",\"yield\",\"class\",\"super\",\"return\",\"typeof\",\"delete\",\"switch\",\"export\",\"import\",\"default\",\"finally\",\"extends\",\"function\",\"continue\",\"debugger\",\"instanceof\"];return result&&keywords.indexOf(result[0])>=0?{type:Token.Keyword,value:result[0]}:null},scanIdentifier:function(){function isNonAsciiIdentifierStart(code){return code>256}function isNonAsciiIdentifierPart(code){return code>256}function isHexDigit(str){return/^[0-9a-fA-F]$/.test(str)}function removeEscapeSequences(id){return id.replace(/\\\\\\\\u([0-9a-fA-F]{4})/g,function(m0,codepoint){return String.fromCharCode(parseInt(codepoint,16))})}var type,char,id=\"\",index=0,readUnicodeEscapeSequence=function(){if(index+=1,\"u\"!==this.peek(index))return null;var code,ch1=this.peek(index+1),ch2=this.peek(index+2),ch3=this.peek(index+3),ch4=this.peek(index+4);return isHexDigit(ch1)&&isHexDigit(ch2)&&isHexDigit(ch3)&&isHexDigit(ch4)?(code=parseInt(ch1+ch2+ch3+ch4,16),asciiIdentifierPartTable[code]||isNonAsciiIdentifierPart(code)?(index+=5,\"\\\\\\\\u\"+ch1+ch2+ch3+ch4):null):null}.bind(this),getIdentifierStart=function(){var chr=this.peek(index),code=chr.charCodeAt(0);return 92===code?readUnicodeEscapeSequence():128>code?asciiIdentifierStartTable[code]?(index+=1,chr):null:isNonAsciiIdentifierStart(code)?(index+=1,chr):null}.bind(this),getIdentifierPart=function(){var chr=this.peek(index),code=chr.charCodeAt(0);return 92===code?readUnicodeEscapeSequence():128>code?asciiIdentifierPartTable[code]?(index+=1,chr):null:isNonAsciiIdentifierPart(code)?(index+=1,chr):null}.bind(this);if(char=getIdentifierStart(),null===char)return null;for(id=char;char=getIdentifierPart(),null!==char;)id+=char;switch(id){case\"true\":case\"false\":type=Token.BooleanLiteral;break;case\"null\":type=Token.NullLiteral;break;default:type=Token.Identifier}return{type:type,value:removeEscapeSequences(id),text:id,tokenLength:id.length}},scanNumericLiteral:function(){function isDecimalDigit(str){return/^[0-9]$/.test(str)}function isOctalDigit(str){return/^[0-7]$/.test(str)}function isBinaryDigit(str){return/^[01]$/.test(str)}function isHexDigit(str){return/^[0-9a-fA-F]$/.test(str)}function isIdentifierStart(ch){return\"$\"===ch||\"_\"===ch||\"\\\\\\\\\"===ch||ch>=\"a\"&&\"z\">=ch||ch>=\"A\"&&\"Z\">=ch}var bad,index=0,value=\"\",length=this.input.length,char=this.peek(index),isAllowedDigit=isDecimalDigit,base=10,isLegacy=!1;if(\".\"!==char&&!isDecimalDigit(char))return null;if(\".\"!==char){for(value=this.peek(index),index+=1,char=this.peek(index),\"0\"===value&&((\"x\"===char||\"X\"===char)&&(isAllowedDigit=isHexDigit,base=16,index+=1,value+=char),(\"o\"===char||\"O\"===char)&&(isAllowedDigit=isOctalDigit,base=8,state.inES6(!0)||this.trigger(\"warning\",{code:\"W119\",line:this.line,character:this.char,data:[\"Octal integer literal\",\"6\"]}),index+=1,value+=char),(\"b\"===char||\"B\"===char)&&(isAllowedDigit=isBinaryDigit,base=2,state.inES6(!0)||this.trigger(\"warning\",{code:\"W119\",line:this.line,character:this.char,data:[\"Binary integer literal\",\"6\"]}),index+=1,value+=char),isOctalDigit(char)&&(isAllowedDigit=isOctalDigit,base=8,isLegacy=!0,bad=!1,index+=1,value+=char),!isOctalDigit(char)&&isDecimalDigit(char)&&(index+=1,value+=char));length>index;){if(char=this.peek(index),isLegacy&&isDecimalDigit(char))bad=!0;else if(!isAllowedDigit(char))break;value+=char,index+=1}if(isAllowedDigit!==isDecimalDigit)return!isLegacy&&2>=value.length?{type:Token.NumericLiteral,value:value,isMalformed:!0}:length>index&&(char=this.peek(index),isIdentifierStart(char))?null:{type:Token.NumericLiteral,value:value,base:base,isLegacy:isLegacy,isMalformed:!1}}if(\".\"===char)for(value+=char,index+=1;length>index&&(char=this.peek(index),isDecimalDigit(char));)value+=char,index+=1;if(\"e\"===char||\"E\"===char){if(value+=char,index+=1,char=this.peek(index),(\"+\"===char||\"-\"===char)&&(value+=this.peek(index),index+=1),char=this.peek(index),!isDecimalDigit(char))return null;for(value+=char,index+=1;length>index&&(char=this.peek(index),isDecimalDigit(char));)value+=char,index+=1}return length>index&&(char=this.peek(index),isIdentifierStart(char))?null:{type:Token.NumericLiteral,value:value,base:base,isMalformed:!isFinite(value)}},scanEscapeSequence:function(checks){var allowNewLine=!1,jump=1;this.skip();var char=this.peek();switch(char){case\"\\'\":this.triggerAsync(\"warning\",{code:\"W114\",line:this.line,character:this.char,data:[\"\\\\\\\\\\'\"]},checks,function(){return state.jsonMode});break;case\"b\":char=\"\\\\\\\\b\";break;case\"f\":char=\"\\\\\\\\f\";break;case\"n\":char=\"\\\\\\\\n\";break;case\"r\":char=\"\\\\\\\\r\";break;case\"t\":char=\"\\\\\\\\t\";break;case\"0\":char=\"\\\\\\\\0\";var n=parseInt(this.peek(1),10);this.triggerAsync(\"warning\",{code:\"W115\",line:this.line,character:this.char},checks,function(){return n>=0&&7>=n&&state.isStrict()});break;case\"u\":var hexCode=this.input.substr(1,4),code=parseInt(hexCode,16);isNaN(code)&&this.trigger(\"warning\",{code:\"W052\",line:this.line,character:this.char,data:[\"u\"+hexCode]}),char=String.fromCharCode(code),jump=5;break;case\"v\":this.triggerAsync(\"warning\",{code:\"W114\",line:this.line,character:this.char,data:[\"\\\\\\\\v\"]},checks,function(){return state.jsonMode}),char=\"\\v\";break;case\"x\":var x=parseInt(this.input.substr(1,2),16);this.triggerAsync(\"warning\",{code:\"W114\",line:this.line,character:this.char,data:[\"\\\\\\\\x-\"]},checks,function(){return state.jsonMode}),char=String.fromCharCode(x),jump=3;break;case\"\\\\\\\\\":char=\"\\\\\\\\\\\\\\\\\";break;case\\'\"\\':char=\\'\\\\\\\\\"\\';break;case\"/\":break;case\"\":allowNewLine=!0,char=\"\"}return{\"char\":char,jump:jump,allowNewLine:allowNewLine}},scanTemplateLiteral:function(checks){var tokenType,ch,value=\"\",startLine=this.line,startChar=this.char,depth=this.templateStarts.length;if(!state.inES6(!0))return null;if(\"`\"===this.peek())tokenType=Token.TemplateHead,this.templateStarts.push({line:this.line,\"char\":this.char}),depth=this.templateStarts.length,this.skip(1),this.pushContext(Context.Template);else{if(!this.inContext(Context.Template)||\"}\"!==this.peek())return null;tokenType=Token.TemplateMiddle}for(;\"`\"!==this.peek();){for(;\"\"===(ch=this.peek());)if(value+=\"\\\\n\",!this.nextLine()){var startPos=this.templateStarts.pop();return this.trigger(\"error\",{code:\"E052\",line:startPos.line,character:startPos.char}),{type:tokenType,value:value,startLine:startLine,startChar:startChar,isUnclosed:!0,depth:depth,context:this.popContext()}}if(\"$\"===ch&&\"{\"===this.peek(1))return value+=\"${\",this.skip(2),{type:tokenType,value:value,startLine:startLine,startChar:startChar,isUnclosed:!1,depth:depth,context:this.currentContext()};\\nif(\"\\\\\\\\\"===ch){var escape=this.scanEscapeSequence(checks);value+=escape.char,this.skip(escape.jump)}else\"`\"!==ch&&(value+=ch,this.skip(1))}return tokenType=tokenType===Token.TemplateHead?Token.NoSubstTemplate:Token.TemplateTail,this.skip(1),this.templateStarts.pop(),{type:tokenType,value:value,startLine:startLine,startChar:startChar,isUnclosed:!1,depth:depth,context:this.popContext()}},scanStringLiteral:function(checks){var quote=this.peek();if(\\'\"\\'!==quote&&\"\\'\"!==quote)return null;this.triggerAsync(\"warning\",{code:\"W108\",line:this.line,character:this.char},checks,function(){return state.jsonMode&&\\'\"\\'!==quote});var value=\"\",startLine=this.line,startChar=this.char,allowNewLine=!1;for(this.skip();this.peek()!==quote;)if(\"\"===this.peek()){if(allowNewLine?(allowNewLine=!1,this.triggerAsync(\"warning\",{code:\"W043\",line:this.line,character:this.char},checks,function(){return!state.option.multistr}),this.triggerAsync(\"warning\",{code:\"W042\",line:this.line,character:this.char},checks,function(){return state.jsonMode&&state.option.multistr})):this.trigger(\"warning\",{code:\"W112\",line:this.line,character:this.char}),!this.nextLine())return this.trigger(\"error\",{code:\"E029\",line:startLine,character:startChar}),{type:Token.StringLiteral,value:value,startLine:startLine,startChar:startChar,isUnclosed:!0,quote:quote}}else{allowNewLine=!1;var char=this.peek(),jump=1;if(\" \">char&&this.trigger(\"warning\",{code:\"W113\",line:this.line,character:this.char,data:[\"<non-printable>\"]}),\"\\\\\\\\\"===char){var parsed=this.scanEscapeSequence(checks);char=parsed.char,jump=parsed.jump,allowNewLine=parsed.allowNewLine}value+=char,this.skip(jump)}return this.skip(),{type:Token.StringLiteral,value:value,startLine:startLine,startChar:startChar,isUnclosed:!1,quote:quote}},scanRegExp:function(){var terminated,index=0,length=this.input.length,char=this.peek(),value=char,body=\"\",flags=[],malformed=!1,isCharSet=!1,scanUnexpectedChars=function(){\" \">char&&(malformed=!0,this.trigger(\"warning\",{code:\"W048\",line:this.line,character:this.char})),\"<\"===char&&(malformed=!0,this.trigger(\"warning\",{code:\"W049\",line:this.line,character:this.char,data:[char]}))}.bind(this);if(!this.prereg||\"/\"!==char)return null;for(index+=1,terminated=!1;length>index;)if(char=this.peek(index),value+=char,body+=char,isCharSet)\"]\"===char&&(\"\\\\\\\\\"!==this.peek(index-1)||\"\\\\\\\\\"===this.peek(index-2))&&(isCharSet=!1),\"\\\\\\\\\"===char&&(index+=1,char=this.peek(index),body+=char,value+=char,scanUnexpectedChars()),index+=1;else{if(\"\\\\\\\\\"===char){if(index+=1,char=this.peek(index),body+=char,value+=char,scanUnexpectedChars(),\"/\"===char){index+=1;continue}if(\"[\"===char){index+=1;continue}}if(\"[\"!==char){if(\"/\"===char){body=body.substr(0,body.length-1),terminated=!0,index+=1;break}index+=1}else isCharSet=!0,index+=1}if(!terminated)return this.trigger(\"error\",{code:\"E015\",line:this.line,character:this.from}),void this.trigger(\"fatal\",{line:this.line,from:this.from});for(;length>index&&(char=this.peek(index),/[gim]/.test(char));)flags.push(char),value+=char,index+=1;try{RegExp(body,flags.join(\"\"))}catch(err){malformed=!0,this.trigger(\"error\",{code:\"E016\",line:this.line,character:this.char,data:[err.message]})}return{type:Token.RegExp,value:value,flags:flags,isMalformed:malformed}},scanNonBreakingSpaces:function(){return state.option.nonbsp?this.input.search(/(\\\\u00A0)/):-1},scanUnsafeChars:function(){return this.input.search(reg.unsafeChars)},next:function(checks){this.from=this.char;var start;if(/\\\\s/.test(this.peek()))for(start=this.char;/\\\\s/.test(this.peek());)this.from+=1,this.skip();var match=this.scanComments()||this.scanStringLiteral(checks)||this.scanTemplateLiteral(checks);return match?match:(match=this.scanRegExp()||this.scanPunctuator()||this.scanKeyword()||this.scanIdentifier()||this.scanNumericLiteral(),match?(this.skip(match.tokenLength||match.value.length),match):null)},nextLine:function(){var char;if(this.line>=this.getLines().length)return!1;this.input=this.getLines()[this.line],this.line+=1,this.char=1,this.from=1;var inputTrimmed=this.input.trim(),startsWith=function(){return _.some(arguments,function(prefix){return 0===inputTrimmed.indexOf(prefix)})},endsWith=function(){return _.some(arguments,function(suffix){return-1!==inputTrimmed.indexOf(suffix,inputTrimmed.length-suffix.length)})};if(this.ignoringLinterErrors===!0&&(startsWith(\"/*\",\"//\")||this.inComment&&endsWith(\"*/\")||(this.input=\"\")),char=this.scanNonBreakingSpaces(),char>=0&&this.trigger(\"warning\",{code:\"W125\",line:this.line,character:char+1}),this.input=this.input.replace(/\\\\t/g,state.tab),char=this.scanUnsafeChars(),char>=0&&this.trigger(\"warning\",{code:\"W100\",line:this.line,character:char}),!this.ignoringLinterErrors&&state.option.maxlen&&state.option.maxlen<this.input.length){var inComment=this.inComment||startsWith.call(inputTrimmed,\"//\")||startsWith.call(inputTrimmed,\"/*\"),shouldTriggerError=!inComment||!reg.maxlenException.test(inputTrimmed);shouldTriggerError&&this.trigger(\"warning\",{code:\"W101\",line:this.line,character:this.input.length})}return!0},start:function(){this.nextLine()},token:function(){function isReserved(token,isProperty){if(!token.reserved)return!1;var meta=token.meta;if(meta&&meta.isFutureReservedWord&&state.inES5()){if(!meta.es5)return!1;if(meta.strictOnly&&!state.option.strict&&!state.isStrict())return!1;if(isProperty)return!1}return!0}for(var token,checks=asyncTrigger(),create=function(type,value,isProperty,token){var obj;if(\"(endline)\"!==type&&\"(end)\"!==type&&(this.prereg=!1),\"(punctuator)\"===type){switch(value){case\".\":case\")\":case\"~\":case\"#\":case\"]\":case\"++\":case\"--\":this.prereg=!1;break;default:this.prereg=!0}obj=Object.create(state.syntax[value]||state.syntax[\"(error)\"])}return\"(identifier)\"===type&&((\"return\"===value||\"case\"===value||\"typeof\"===value)&&(this.prereg=!0),_.has(state.syntax,value)&&(obj=Object.create(state.syntax[value]||state.syntax[\"(error)\"]),isReserved(obj,isProperty&&\"(identifier)\"===type)||(obj=null))),obj||(obj=Object.create(state.syntax[type])),obj.identifier=\"(identifier)\"===type,obj.type=obj.type||type,obj.value=value,obj.line=this.line,obj.character=this.char,obj.from=this.from,obj.identifier&&token&&(obj.raw_text=token.text||token.value),token&&token.startLine&&token.startLine!==this.line&&(obj.startLine=token.startLine),token&&token.context&&(obj.context=token.context),token&&token.depth&&(obj.depth=token.depth),token&&token.isUnclosed&&(obj.isUnclosed=token.isUnclosed),isProperty&&obj.identifier&&(obj.isProperty=isProperty),obj.check=checks.check,obj}.bind(this);;){if(!this.input.length)return this.nextLine()?create(\"(endline)\",\"\"):this.exhausted?null:(this.exhausted=!0,create(\"(end)\",\"\"));if(token=this.next(checks))switch(token.type){case Token.StringLiteral:return this.triggerAsync(\"String\",{line:this.line,\"char\":this.char,from:this.from,startLine:token.startLine,startChar:token.startChar,value:token.value,quote:token.quote},checks,function(){return!0}),create(\"(string)\",token.value,null,token);case Token.TemplateHead:return this.trigger(\"TemplateHead\",{line:this.line,\"char\":this.char,from:this.from,startLine:token.startLine,startChar:token.startChar,value:token.value}),create(\"(template)\",token.value,null,token);case Token.TemplateMiddle:return this.trigger(\"TemplateMiddle\",{line:this.line,\"char\":this.char,from:this.from,startLine:token.startLine,startChar:token.startChar,value:token.value}),create(\"(template middle)\",token.value,null,token);case Token.TemplateTail:return this.trigger(\"TemplateTail\",{line:this.line,\"char\":this.char,from:this.from,startLine:token.startLine,startChar:token.startChar,value:token.value}),create(\"(template tail)\",token.value,null,token);case Token.NoSubstTemplate:return this.trigger(\"NoSubstTemplate\",{line:this.line,\"char\":this.char,from:this.from,startLine:token.startLine,startChar:token.startChar,value:token.value}),create(\"(no subst template)\",token.value,null,token);case Token.Identifier:this.triggerAsync(\"Identifier\",{line:this.line,\"char\":this.char,from:this.form,name:token.value,raw_name:token.text,isProperty:\".\"===state.tokens.curr.id},checks,function(){return!0});case Token.Keyword:case Token.NullLiteral:case Token.BooleanLiteral:return create(\"(identifier)\",token.value,\".\"===state.tokens.curr.id,token);case Token.NumericLiteral:return token.isMalformed&&this.trigger(\"warning\",{code:\"W045\",line:this.line,character:this.char,data:[token.value]}),this.triggerAsync(\"warning\",{code:\"W114\",line:this.line,character:this.char,data:[\"0x-\"]},checks,function(){return 16===token.base&&state.jsonMode}),this.triggerAsync(\"warning\",{code:\"W115\",line:this.line,character:this.char},checks,function(){return state.isStrict()&&8===token.base&&token.isLegacy}),this.trigger(\"Number\",{line:this.line,\"char\":this.char,from:this.from,value:token.value,base:token.base,isMalformed:token.malformed}),create(\"(number)\",token.value);case Token.RegExp:return create(\"(regexp)\",token.value);case Token.Comment:if(state.tokens.curr.comment=!0,token.isSpecial)return{id:\"(comment)\",value:token.value,body:token.body,type:token.commentType,isSpecial:token.isSpecial,line:this.line,character:this.char,from:this.from};break;case\"\":break;default:return create(\"(punctuator)\",token.value)}else this.input.length&&(this.trigger(\"error\",{code:\"E024\",line:this.line,character:this.char,data:[this.peek()]}),this.input=\"\")}}},exports.Lexer=Lexer,exports.Context=Context},{\"../data/ascii-identifier-data.js\":\"/node_modules/jshint/data/ascii-identifier-data.js\",\"../lodash\":\"/node_modules/jshint/lodash.js\",\"./reg.js\":\"/node_modules/jshint/src/reg.js\",\"./state.js\":\"/node_modules/jshint/src/state.js\",events:\"/node_modules/browserify/node_modules/events/events.js\"}],\"/node_modules/jshint/src/messages.js\":[function(_dereq_,module,exports){\"use strict\";var _=_dereq_(\"../lodash\"),errors={E001:\"Bad option: \\'{a}\\'.\",E002:\"Bad option value.\",E003:\"Expected a JSON value.\",E004:\"Input is neither a string nor an array of strings.\",E005:\"Input is empty.\",E006:\"Unexpected early end of program.\",E007:\\'Missing \"use strict\" statement.\\',E008:\"Strict violation.\",E009:\"Option \\'validthis\\' can\\'t be used in a global scope.\",E010:\"\\'with\\' is not allowed in strict mode.\",E011:\"\\'{a}\\' has already been declared.\",E012:\"const \\'{a}\\' is initialized to \\'undefined\\'.\",E013:\"Attempting to override \\'{a}\\' which is a constant.\",E014:\"A regular expression literal can be confused with \\'/=\\'.\",E015:\"Unclosed regular expression.\",E016:\"Invalid regular expression.\",E017:\"Unclosed comment.\",E018:\"Unbegun comment.\",E019:\"Unmatched \\'{a}\\'.\",E020:\"Expected \\'{a}\\' to match \\'{b}\\' from line {c} and instead saw \\'{d}\\'.\",E021:\"Expected \\'{a}\\' and instead saw \\'{b}\\'.\",E022:\"Line breaking error \\'{a}\\'.\",E023:\"Missing \\'{a}\\'.\",E024:\"Unexpected \\'{a}\\'.\",E025:\"Missing \\':\\' on a case clause.\",E026:\"Missing \\'}\\' to match \\'{\\' from line {a}.\",E027:\"Missing \\']\\' to match \\'[\\' from line {a}.\",E028:\"Illegal comma.\",E029:\"Unclosed string.\",E030:\"Expected an identifier and instead saw \\'{a}\\'.\",E031:\"Bad assignment.\",E032:\"Expected a small integer or \\'false\\' and instead saw \\'{a}\\'.\",E033:\"Expected an operator and instead saw \\'{a}\\'.\",E034:\"get/set are ES5 features.\",E035:\"Missing property name.\",E036:\"Expected to see a statement and instead saw a block.\",E037:null,E038:null,E039:\"Function declarations are not invocable. Wrap the whole function invocation in parens.\",E040:\"Each value should have its own case label.\",E041:\"Unrecoverable syntax error.\",E042:\"Stopping.\",E043:\"Too many errors.\",E044:null,E045:\"Invalid for each loop.\",E046:\"A yield statement shall be within a generator function (with syntax: `function*`)\",E047:null,E048:\"{a} declaration not directly within block.\",E049:\"A {a} cannot be named \\'{b}\\'.\",E050:\"Mozilla acequires the yield expression to be parenthesized here.\",E051:null,E052:\"Unclosed template literal.\",E053:\"Export declaration must be in global scope.\",E054:\"Class properties must be methods. Expected \\'(\\' but instead saw \\'{a}\\'.\",E055:\"The \\'{a}\\' option cannot be set after any executable code.\",E056:\"\\'{a}\\' was used before it was declared, which is illegal for \\'{b}\\' variables.\",E057:\"Invalid meta property: \\'{a}.{b}\\'.\",E058:\"Missing semicolon.\"},warnings={W001:\"\\'hasOwnProperty\\' is a really bad name.\",W002:\"Value of \\'{a}\\' may be overwritten in IE 8 and earlier.\",W003:\"\\'{a}\\' was used before it was defined.\",W004:\"\\'{a}\\' is already defined.\",W005:\"A dot following a number can be confused with a decimal point.\",W006:\"Confusing minuses.\",W007:\"Confusing plusses.\",W008:\"A leading decimal point can be confused with a dot: \\'{a}\\'.\",W009:\"The array literal notation [] is preferable.\",W010:\"The object literal notation {} is preferable.\",W011:null,W012:null,W013:null,W014:\"Bad line breaking before \\'{a}\\'.\",W015:null,W016:\"Unexpected use of \\'{a}\\'.\",W017:\"Bad operand.\",W018:\"Confusing use of \\'{a}\\'.\",W019:\"Use the isNaN function to compare with NaN.\",W020:\"Read only.\",W021:\"Reassignment of \\'{a}\\', which is is a {b}. Use \\'var\\' or \\'let\\' to declare bindings that may change.\",W022:\"Do not assign to the exception parameter.\",W023:\"Expected an identifier in an assignment and instead saw a function invocation.\",W024:\"Expected an identifier and instead saw \\'{a}\\' (a reserved word).\",W025:\"Missing name in function declaration.\",W026:\"Inner functions should be listed at the top of the outer function.\",W027:\"Unreachable \\'{a}\\' after \\'{b}\\'.\",W028:\"Label \\'{a}\\' on {b} statement.\",W030:\"Expected an assignment or function call and instead saw an expression.\",W031:\"Do not use \\'new\\' for side effects.\",W032:\"Unnecessary semicolon.\",W033:\"Missing semicolon.\",W034:\\'Unnecessary directive \"{a}\".\\',W035:\"Empty block.\",W036:\"Unexpected /*member \\'{a}\\'.\",W037:\"\\'{a}\\' is a statement label.\",W038:\"\\'{a}\\' used out of scope.\",W039:\"\\'{a}\\' is not allowed.\",W040:\"Possible strict violation.\",W041:\"Use \\'{a}\\' to compare with \\'{b}\\'.\",W042:\"Avoid EOL escaping.\",W043:\"Bad escaping of EOL. Use option multistr if needed.\",W044:\"Bad or unnecessary escaping.\",W045:\"Bad number \\'{a}\\'.\",W046:\"Don\\'t use extra leading zeros \\'{a}\\'.\",W047:\"A trailing decimal point can be confused with a dot: \\'{a}\\'.\",W048:\"Unexpected control character in regular expression.\",W049:\"Unexpected escaped character \\'{a}\\' in regular expression.\",W050:\"JavaScript URL.\",W051:\"Variables should not be deleted.\",W052:\"Unexpected \\'{a}\\'.\",W053:\"Do not use {a} as a constructor.\",W054:\"The Function constructor is a form of eval.\",W055:\"A constructor name should start with an uppercase letter.\",W056:\"Bad constructor.\",W057:\"Weird construction. Is \\'new\\' necessary?\",W058:\"Missing \\'()\\' invoking a constructor.\",W059:\"Avoid arguments.{a}.\",W060:\"document.write can be a form of eval.\",W061:\"eval can be harmful.\",W062:\"Wrap an immediate function invocation in parens to assist the reader in understanding that the expression is the result of a function, and not the function itself.\",W063:\"Math is not a function.\",W064:\"Missing \\'new\\' prefix when invoking a constructor.\",W065:\"Missing radix parameter.\",W066:\"Implied eval. Consider passing a function instead of a string.\",W067:\"Bad invocation.\",W068:\"Wrapping non-IIFE function literals in parens is unnecessary.\",W069:\"[\\'{a}\\'] is better written in dot notation.\",W070:\"Extra comma. (it breaks older versions of IE)\",W071:\"This function has too many statements. ({a})\",W072:\"This function has too many parameters. ({a})\",W073:\"Blocks are nested too deeply. ({a})\",W074:\"This function\\'s cyclomatic complexity is too high. ({a})\",W075:\"Duplicate {a} \\'{b}\\'.\",W076:\"Unexpected parameter \\'{a}\\' in get {b} function.\",W077:\"Expected a single parameter in set {a} function.\",W078:\"Setter is defined without getter.\",W079:\"Redefinition of \\'{a}\\'.\",W080:\"It\\'s not necessary to initialize \\'{a}\\' to \\'undefined\\'.\",W081:null,W082:\"Function declarations should not be placed in blocks. Use a function expression or move the statement to the top of the outer function.\",W083:\"Don\\'t make functions within a loop.\",W084:\"Assignment in conditional expression\",W085:\"Don\\'t use \\'with\\'.\",W086:\"Expected a \\'break\\' statement before \\'{a}\\'.\",W087:\"Forgotten \\'debugger\\' statement?\",W088:\"Creating global \\'for\\' variable. Should be \\'for (var {a} ...\\'.\",W089:\"The body of a for in should be wrapped in an if statement to filter unwanted properties from the prototype.\",W090:\"\\'{a}\\' is not a statement label.\",W091:null,W093:\"Did you mean to return a conditional instead of an assignment?\",W094:\"Unexpected comma.\",W095:\"Expected a string and instead saw {a}.\",W096:\"The \\'{a}\\' key may produce unexpected results.\",W097:\\'Use the function form of \"use strict\".\\',W098:\"\\'{a}\\' is defined but never used.\",W099:null,W100:\"This character may get silently deleted by one or more browsers.\",W101:\"Line is too long.\",W102:null,W103:\"The \\'{a}\\' property is deprecated.\",W104:\"\\'{a}\\' is available in ES{b} (use \\'esversion: {b}\\') or Mozilla JS extensions (use moz).\",W105:\"Unexpected {a} in \\'{b}\\'.\",W106:\"Identifier \\'{a}\\' is not in camel case.\",W107:\"Script URL.\",W108:\"Strings must use doublequote.\",W109:\"Strings must use singlequote.\",W110:\"Mixed double and single quotes.\",W112:\"Unclosed string.\",W113:\"Control character in string: {a}.\",W114:\"Avoid {a}.\",W115:\"Octal literals are not allowed in strict mode.\",W116:\"Expected \\'{a}\\' and instead saw \\'{b}\\'.\",W117:\"\\'{a}\\' is not defined.\",W118:\"\\'{a}\\' is only available in Mozilla JavaScript extensions (use moz option).\",W119:\"\\'{a}\\' is only available in ES{b} (use \\'esversion: {b}\\').\",W120:\"You might be leaking a variable ({a}) here.\",W121:\"Extending prototype of native object: \\'{a}\\'.\",W122:\"Invalid typeof value \\'{a}\\'\",W123:\"\\'{a}\\' is already defined in outer scope.\",W124:\"A generator function shall contain a yield statement.\",W125:\"This line contains non-breaking spaces: http://jshint.com/doc/options/#nonbsp\",W126:\"Unnecessary grouping operator.\",W127:\"Unexpected use of a comma operator.\",W128:\"Empty array elements acequire elision=true.\",W129:\"\\'{a}\\' is defined in a future version of JavaScript. Use a different variable name to avoid migration issues.\",W130:\"Invalid element after rest element.\",W131:\"Invalid parameter after rest parameter.\",W132:\"`var` declarations are forbidden. Use `let` or `const` instead.\",W133:\"Invalid for-{a} loop left-hand-side: {b}.\",W134:\"The \\'{a}\\' option is only available when linting ECMAScript {b} code.\",W135:\"{a} may not be supported by non-browser environments.\",W136:\"\\'{a}\\' must be in function scope.\",W137:\"Empty destructuring.\",W138:\"Regular parameters should not come after default parameters.\"},info={I001:\"Comma warnings can be turned off with \\'laxcomma\\'.\",I002:null,I003:\"ES5 option is now set per default\"};exports.errors={},exports.warnings={},exports.info={},_.each(errors,function(desc,code){exports.errors[code]={code:code,desc:desc}}),_.each(warnings,function(desc,code){exports.warnings[code]={code:code,desc:desc}}),_.each(info,function(desc,code){exports.info[code]={code:code,desc:desc}})},{\"../lodash\":\"/node_modules/jshint/lodash.js\"}],\"/node_modules/jshint/src/name-stack.js\":[function(_dereq_,module){\"use strict\";function NameStack(){this._stack=[]}Object.defineProperty(NameStack.prototype,\"length\",{get:function(){return this._stack.length}}),NameStack.prototype.push=function(){this._stack.push(null)},NameStack.prototype.pop=function(){this._stack.pop()},NameStack.prototype.set=function(token){this._stack[this.length-1]=token},NameStack.prototype.infer=function(){var type,nameToken=this._stack[this.length-1],prefix=\"\";return nameToken&&\"class\"!==nameToken.type||(nameToken=this._stack[this.length-2]),nameToken?(type=nameToken.type,\"(string)\"!==type&&\"(number)\"!==type&&\"(identifier)\"!==type&&\"default\"!==type?\"(expression)\":(nameToken.accessorType&&(prefix=nameToken.accessorType+\" \"),prefix+nameToken.value)):\"(empty)\"},module.exports=NameStack},{}],\"/node_modules/jshint/src/options.js\":[function(_dereq_,module,exports){\"use strict\";exports.bool={enforcing:{bitwise:!0,freeze:!0,camelcase:!0,curly:!0,eqeqeq:!0,futurehostile:!0,notypeof:!0,es3:!0,es5:!0,forin:!0,funcscope:!0,immed:!0,iterator:!0,newcap:!0,noarg:!0,nocomma:!0,noempty:!0,nonbsp:!0,nonew:!0,undef:!0,singleGroups:!1,varstmt:!1,enforceall:!1},relaxing:{asi:!0,multistr:!0,debug:!0,boss:!0,evil:!0,globalstrict:!0,plusplus:!0,proto:!0,scripturl:!0,sub:!0,supernew:!0,laxbreak:!0,laxcomma:!0,validthis:!0,withstmt:!0,moz:!0,noyield:!0,eqnull:!0,lastsemic:!0,loopfunc:!0,expr:!0,esnext:!0,elision:!0},environments:{mootools:!0,couch:!0,jasmine:!0,jquery:!0,node:!0,qunit:!0,rhino:!0,shelljs:!0,prototypejs:!0,yui:!0,mocha:!0,module:!0,wsh:!0,worker:!0,nonstandard:!0,browser:!0,browserify:!0,devel:!0,dojo:!0,typed:!0,phantom:!0},obsolete:{onecase:!0,regexp:!0,regexdash:!0}},exports.val={maxlen:!1,indent:!1,maxerr:!1,predef:!1,globals:!1,quotmark:!1,scope:!1,maxstatements:!1,maxdepth:!1,maxparams:!1,maxcomplexity:!1,shadow:!1,strict:!0,unused:!0,latedef:!1,ignore:!1,ignoreDelimiters:!1,esversion:5},exports.inverted={bitwise:!0,forin:!0,newcap:!0,plusplus:!0,regexp:!0,undef:!0,eqeqeq:!0,strict:!0},exports.validNames=Object.keys(exports.val).concat(Object.keys(exports.bool.relaxing)).concat(Object.keys(exports.bool.enforcing)).concat(Object.keys(exports.bool.obsolete)).concat(Object.keys(exports.bool.environments)),exports.renamed={eqeq:\"eqeqeq\",windows:\"wsh\",sloppy:\"strict\"},exports.removed={nomen:!0,onevar:!0,passfail:!0,white:!0,gcl:!0,smarttabs:!0,trailing:!0},exports.noenforceall={varstmt:!0,strict:!0}},{}],\"/node_modules/jshint/src/reg.js\":[function(_dereq_,module,exports){\"use strict\";exports.unsafeString=/@cc|<\\\\/?|script|\\\\]\\\\s*\\\\]|<\\\\s*!|&lt/i,exports.unsafeChars=/[\\\\u0000-\\\\u001f\\\\u007f-\\\\u009f\\\\u00ad\\\\u0600-\\\\u0604\\\\u070f\\\\u17b4\\\\u17b5\\\\u200c-\\\\u200f\\\\u2028-\\\\u202f\\\\u2060-\\\\u206f\\\\ufeff\\\\ufff0-\\\\uffff]/,exports.needEsc=/[\\\\u0000-\\\\u001f&<\"\\\\/\\\\\\\\\\\\u007f-\\\\u009f\\\\u00ad\\\\u0600-\\\\u0604\\\\u070f\\\\u17b4\\\\u17b5\\\\u200c-\\\\u200f\\\\u2028-\\\\u202f\\\\u2060-\\\\u206f\\\\ufeff\\\\ufff0-\\\\uffff]/,exports.needEscGlobal=/[\\\\u0000-\\\\u001f&<\"\\\\/\\\\\\\\\\\\u007f-\\\\u009f\\\\u00ad\\\\u0600-\\\\u0604\\\\u070f\\\\u17b4\\\\u17b5\\\\u200c-\\\\u200f\\\\u2028-\\\\u202f\\\\u2060-\\\\u206f\\\\ufeff\\\\ufff0-\\\\uffff]/g,exports.starSlash=/\\\\*\\\\//,exports.identifier=/^([a-zA-Z_$][a-zA-Z0-9_$]*)$/,exports.javascriptURL=/^(?:javascript|jscript|ecmascript|vbscript|livescript)\\\\s*:/i,exports.fallsThrough=/^\\\\s*falls?\\\\sthrough\\\\s*$/,exports.maxlenException=/^(?:(?:\\\\/\\\\/|\\\\/\\\\*|\\\\*) ?)?[^ ]+$/},{}],\"/node_modules/jshint/src/scope-manager.js\":[function(_dereq_,module){\"use strict\";var _=_dereq_(\"../lodash\"),events=_dereq_(\"events\"),marker={},scopeManager=function(state,predefined,exported,declared){function _newScope(type){_current={\"(labels)\":Object.create(null),\"(usages)\":Object.create(null),\"(breakLabels)\":Object.create(null),\"(parent)\":_current,\"(type)\":type,\"(params)\":\"functionparams\"===type||\"catchparams\"===type?[]:null},_scopeStack.push(_current)}function warning(code,token){emitter.emit(\"warning\",{code:code,token:token,data:_.slice(arguments,2)})}function error(code,token){emitter.emit(\"warning\",{code:code,token:token,data:_.slice(arguments,2)})}function _setupUsages(labelName){_current[\"(usages)\"][labelName]||(_current[\"(usages)\"][labelName]={\"(modified)\":[],\"(reassigned)\":[],\"(tokens)\":[]})}function _checkForUnused(){if(\"functionparams\"===_current[\"(type)\"])return _checkParams(),void 0;var curentLabels=_current[\"(labels)\"];for(var labelName in curentLabels)curentLabels[labelName]&&\"exception\"!==curentLabels[labelName][\"(type)\"]&&curentLabels[labelName][\"(unused)\"]&&_warnUnused(labelName,curentLabels[labelName][\"(token)\"],\"var\")}function _checkParams(){var params=_current[\"(params)\"];if(params)for(var unused_opt,param=params.pop();param;){var label=_current[\"(labels)\"][param];if(unused_opt=_getUnusedOption(state.funct[\"(unusedOption)\"]),\"undefined\"===param)return;if(label[\"(unused)\"])_warnUnused(param,label[\"(token)\"],\"param\",state.funct[\"(unusedOption)\"]);else if(\"last-param\"===unused_opt)return;param=params.pop()}}function _getLabel(labelName){for(var i=_scopeStack.length-1;i>=0;--i){var scopeLabels=_scopeStack[i][\"(labels)\"];if(scopeLabels[labelName])return scopeLabels}}function usedSoFarInCurrentFunction(labelName){for(var i=_scopeStack.length-1;i>=0;i--){var current=_scopeStack[i];if(current[\"(usages)\"][labelName])return current[\"(usages)\"][labelName];if(current===_currentFunctBody)break}return!1}function _checkOuterShadow(labelName,token){if(\"outer\"===state.option.shadow)for(var isGlobal=\"global\"===_currentFunctBody[\"(type)\"],isNewFunction=\"functionparams\"===_current[\"(type)\"],outsideCurrentFunction=!isGlobal,i=0;_scopeStack.length>i;i++){var stackItem=_scopeStack[i];isNewFunction||_scopeStack[i+1]!==_currentFunctBody||(outsideCurrentFunction=!1),outsideCurrentFunction&&stackItem[\"(labels)\"][labelName]&&warning(\"W123\",token,labelName),stackItem[\"(breakLabels)\"][labelName]&&warning(\"W123\",token,labelName)}}function _latedefWarning(type,labelName,token){state.option.latedef&&(state.option.latedef===!0&&\"function\"===type||\"function\"!==type)&&warning(\"W003\",token,labelName)}var _current,_scopeStack=[];_newScope(\"global\"),_current[\"(predefined)\"]=predefined;var _currentFunctBody=_current,usedPredefinedAndGlobals=Object.create(null),impliedGlobals=Object.create(null),unuseds=[],emitter=new events.EventEmitter,_getUnusedOption=function(unused_opt){return void 0===unused_opt&&(unused_opt=state.option.unused),unused_opt===!0&&(unused_opt=\"last-param\"),unused_opt},_warnUnused=function(name,tkn,type,unused_opt){var line=tkn.line,chr=tkn.from,raw_name=tkn.raw_text||name;unused_opt=_getUnusedOption(unused_opt);var warnable_types={vars:[\"var\"],\"last-param\":[\"var\",\"param\"],strict:[\"var\",\"param\",\"last-param\"]};unused_opt&&warnable_types[unused_opt]&&-1!==warnable_types[unused_opt].indexOf(type)&&warning(\"W098\",{line:line,from:chr},raw_name),(unused_opt||\"var\"===type)&&unuseds.push({name:name,line:line,character:chr})},scopeManagerInst={on:function(names,listener){names.split(\" \").forEach(function(name){emitter.on(name,listener)})},isPredefined:function(labelName){return!this.has(labelName)&&_.has(_scopeStack[0][\"(predefined)\"],labelName)},stack:function(type){var previousScope=_current;_newScope(type),type||\"functionparams\"!==previousScope[\"(type)\"]||(_current[\"(isFuncBody)\"]=!0,_current[\"(context)\"]=_currentFunctBody,_currentFunctBody=_current)},unstack:function(){var i,j,subScope=_scopeStack.length>1?_scopeStack[_scopeStack.length-2]:null,isUnstackingFunctionBody=_current===_currentFunctBody,isUnstackingFunctionParams=\"functionparams\"===_current[\"(type)\"],isUnstackingFunctionOuter=\"functionouter\"===_current[\"(type)\"],currentUsages=_current[\"(usages)\"],currentLabels=_current[\"(labels)\"],usedLabelNameList=Object.keys(currentUsages);for(currentUsages.__proto__&&-1===usedLabelNameList.indexOf(\"__proto__\")&&usedLabelNameList.push(\"__proto__\"),i=0;usedLabelNameList.length>i;i++){var usedLabelName=usedLabelNameList[i],usage=currentUsages[usedLabelName],usedLabel=currentLabels[usedLabelName];if(usedLabel){var usedLabelType=usedLabel[\"(type)\"];if(usedLabel[\"(useOutsideOfScope)\"]&&!state.option.funcscope){var usedTokens=usage[\"(tokens)\"];if(usedTokens)for(j=0;usedTokens.length>j;j++)usedLabel[\"(function)\"]===usedTokens[j][\"(function)\"]&&error(\"W038\",usedTokens[j],usedLabelName)}if(_current[\"(labels)\"][usedLabelName][\"(unused)\"]=!1,\"const\"===usedLabelType&&usage[\"(modified)\"])for(j=0;usage[\"(modified)\"].length>j;j++)error(\"E013\",usage[\"(modified)\"][j],usedLabelName);if((\"function\"===usedLabelType||\"class\"===usedLabelType)&&usage[\"(reassigned)\"])for(j=0;usage[\"(reassigned)\"].length>j;j++)error(\"W021\",usage[\"(reassigned)\"][j],usedLabelName,usedLabelType)}else if(isUnstackingFunctionOuter&&(state.funct[\"(isCapturing)\"]=!0),subScope)if(subScope[\"(usages)\"][usedLabelName]){var subScopeUsage=subScope[\"(usages)\"][usedLabelName];subScopeUsage[\"(modified)\"]=subScopeUsage[\"(modified)\"].concat(usage[\"(modified)\"]),subScopeUsage[\"(tokens)\"]=subScopeUsage[\"(tokens)\"].concat(usage[\"(tokens)\"]),subScopeUsage[\"(reassigned)\"]=subScopeUsage[\"(reassigned)\"].concat(usage[\"(reassigned)\"]),subScopeUsage[\"(onlyUsedSubFunction)\"]=!1}else subScope[\"(usages)\"][usedLabelName]=usage,isUnstackingFunctionBody&&(subScope[\"(usages)\"][usedLabelName][\"(onlyUsedSubFunction)\"]=!0);else if(\"boolean\"==typeof _current[\"(predefined)\"][usedLabelName]){if(delete declared[usedLabelName],usedPredefinedAndGlobals[usedLabelName]=marker,_current[\"(predefined)\"][usedLabelName]===!1&&usage[\"(reassigned)\"])for(j=0;usage[\"(reassigned)\"].length>j;j++)warning(\"W020\",usage[\"(reassigned)\"][j])}else if(usage[\"(tokens)\"])for(j=0;usage[\"(tokens)\"].length>j;j++){var undefinedToken=usage[\"(tokens)\"][j];undefinedToken.forgiveUndef||(state.option.undef&&!undefinedToken.ignoreUndef&&warning(\"W117\",undefinedToken,usedLabelName),impliedGlobals[usedLabelName]?impliedGlobals[usedLabelName].line.push(undefinedToken.line):impliedGlobals[usedLabelName]={name:usedLabelName,line:[undefinedToken.line]})}}if(subScope||Object.keys(declared).forEach(function(labelNotUsed){_warnUnused(labelNotUsed,declared[labelNotUsed],\"var\")}),subScope&&!isUnstackingFunctionBody&&!isUnstackingFunctionParams&&!isUnstackingFunctionOuter){var labelNames=Object.keys(currentLabels);for(i=0;labelNames.length>i;i++){var defLabelName=labelNames[i];currentLabels[defLabelName][\"(blockscoped)\"]||\"exception\"===currentLabels[defLabelName][\"(type)\"]||this.funct.has(defLabelName,{excludeCurrent:!0})||(subScope[\"(labels)\"][defLabelName]=currentLabels[defLabelName],\"global\"!==_currentFunctBody[\"(type)\"]&&(subScope[\"(labels)\"][defLabelName][\"(useOutsideOfScope)\"]=!0),delete currentLabels[defLabelName])}}_checkForUnused(),_scopeStack.pop(),isUnstackingFunctionBody&&(_currentFunctBody=_scopeStack[_.findLastIndex(_scopeStack,function(scope){return scope[\"(isFuncBody)\"]||\"global\"===scope[\"(type)\"]})]),_current=subScope},addParam:function(labelName,token,type){if(type=type||\"param\",\"exception\"===type){var previouslyDefinedLabelType=this.funct.labeltype(labelName);previouslyDefinedLabelType&&\"exception\"!==previouslyDefinedLabelType&&(state.option.node||warning(\"W002\",state.tokens.next,labelName))}if(_.has(_current[\"(labels)\"],labelName)?_current[\"(labels)\"][labelName].duplicated=!0:(_checkOuterShadow(labelName,token,type),_current[\"(labels)\"][labelName]={\"(type)\":type,\"(token)\":token,\"(unused)\":!0},_current[\"(params)\"].push(labelName)),_.has(_current[\"(usages)\"],labelName)){var usage=_current[\"(usages)\"][labelName];usage[\"(onlyUsedSubFunction)\"]?_latedefWarning(type,labelName,token):warning(\"E056\",token,labelName,type)}},validateParams:function(){if(\"global\"!==_currentFunctBody[\"(type)\"]){var isStrict=state.isStrict(),currentFunctParamScope=_currentFunctBody[\"(parent)\"];currentFunctParamScope[\"(params)\"]&&currentFunctParamScope[\"(params)\"].forEach(function(labelName){var label=currentFunctParamScope[\"(labels)\"][labelName];label&&label.duplicated&&(isStrict?warning(\"E011\",label[\"(token)\"],labelName):state.option.shadow!==!0&&warning(\"W004\",label[\"(token)\"],labelName))})}},getUsedOrDefinedGlobals:function(){var list=Object.keys(usedPredefinedAndGlobals);return usedPredefinedAndGlobals.__proto__===marker&&-1===list.indexOf(\"__proto__\")&&list.push(\"__proto__\"),list},getImpliedGlobals:function(){var values=_.values(impliedGlobals),hasProto=!1;return impliedGlobals.__proto__&&(hasProto=values.some(function(value){return\"__proto__\"===value.name}),hasProto||values.push(impliedGlobals.__proto__)),values},getUnuseds:function(){return unuseds},has:function(labelName){return Boolean(_getLabel(labelName))},labeltype:function(labelName){var scopeLabels=_getLabel(labelName);return scopeLabels?scopeLabels[labelName][\"(type)\"]:null},addExported:function(labelName){var globalLabels=_scopeStack[0][\"(labels)\"];if(_.has(declared,labelName))delete declared[labelName];else if(_.has(globalLabels,labelName))globalLabels[labelName][\"(unused)\"]=!1;else{for(var i=1;_scopeStack.length>i;i++){var scope=_scopeStack[i];if(scope[\"(type)\"])break;if(_.has(scope[\"(labels)\"],labelName)&&!scope[\"(labels)\"][labelName][\"(blockscoped)\"])return scope[\"(labels)\"][labelName][\"(unused)\"]=!1,void 0}exported[labelName]=!0}},setExported:function(labelName,token){this.block.use(labelName,token)\\n},addlabel:function(labelName,opts){var type=opts.type,token=opts.token,isblockscoped=\"let\"===type||\"const\"===type||\"class\"===type,isexported=\"global\"===(isblockscoped?_current:_currentFunctBody)[\"(type)\"]&&_.has(exported,labelName);if(_checkOuterShadow(labelName,token,type),isblockscoped){var declaredInCurrentScope=_current[\"(labels)\"][labelName];if(declaredInCurrentScope||_current!==_currentFunctBody||\"global\"===_current[\"(type)\"]||(declaredInCurrentScope=!!_currentFunctBody[\"(parent)\"][\"(labels)\"][labelName]),!declaredInCurrentScope&&_current[\"(usages)\"][labelName]){var usage=_current[\"(usages)\"][labelName];usage[\"(onlyUsedSubFunction)\"]?_latedefWarning(type,labelName,token):warning(\"E056\",token,labelName,type)}declaredInCurrentScope?warning(\"E011\",token,labelName):\"outer\"===state.option.shadow&&scopeManagerInst.funct.has(labelName)&&warning(\"W004\",token,labelName),scopeManagerInst.block.add(labelName,type,token,!isexported)}else{var declaredInCurrentFunctionScope=scopeManagerInst.funct.has(labelName);!declaredInCurrentFunctionScope&&usedSoFarInCurrentFunction(labelName)&&_latedefWarning(type,labelName,token),scopeManagerInst.funct.has(labelName,{onlyBlockscoped:!0})?warning(\"E011\",token,labelName):state.option.shadow!==!0&&declaredInCurrentFunctionScope&&\"__proto__\"!==labelName&&\"global\"!==_currentFunctBody[\"(type)\"]&&warning(\"W004\",token,labelName),scopeManagerInst.funct.add(labelName,type,token,!isexported),\"global\"===_currentFunctBody[\"(type)\"]&&(usedPredefinedAndGlobals[labelName]=marker)}},funct:{labeltype:function(labelName,options){for(var onlyBlockscoped=options&&options.onlyBlockscoped,excludeParams=options&&options.excludeParams,currentScopeIndex=_scopeStack.length-(options&&options.excludeCurrent?2:1),i=currentScopeIndex;i>=0;i--){var current=_scopeStack[i];if(current[\"(labels)\"][labelName]&&(!onlyBlockscoped||current[\"(labels)\"][labelName][\"(blockscoped)\"]))return current[\"(labels)\"][labelName][\"(type)\"];var scopeCheck=excludeParams?_scopeStack[i-1]:current;if(scopeCheck&&\"functionparams\"===scopeCheck[\"(type)\"])return null}return null},hasBreakLabel:function(labelName){for(var i=_scopeStack.length-1;i>=0;i--){var current=_scopeStack[i];if(current[\"(breakLabels)\"][labelName])return!0;if(\"functionparams\"===current[\"(type)\"])return!1}return!1},has:function(labelName,options){return Boolean(this.labeltype(labelName,options))},add:function(labelName,type,tok,unused){_current[\"(labels)\"][labelName]={\"(type)\":type,\"(token)\":tok,\"(blockscoped)\":!1,\"(function)\":_currentFunctBody,\"(unused)\":unused}}},block:{isGlobal:function(){return\"global\"===_current[\"(type)\"]},use:function(labelName,token){var paramScope=_currentFunctBody[\"(parent)\"];paramScope&&paramScope[\"(labels)\"][labelName]&&\"param\"===paramScope[\"(labels)\"][labelName][\"(type)\"]&&(scopeManagerInst.funct.has(labelName,{excludeParams:!0,onlyBlockscoped:!0})||(paramScope[\"(labels)\"][labelName][\"(unused)\"]=!1)),token&&(state.ignored.W117||state.option.undef===!1)&&(token.ignoreUndef=!0),_setupUsages(labelName),token&&(token[\"(function)\"]=_currentFunctBody,_current[\"(usages)\"][labelName][\"(tokens)\"].push(token))},reassign:function(labelName,token){this.modify(labelName,token),_current[\"(usages)\"][labelName][\"(reassigned)\"].push(token)},modify:function(labelName,token){_setupUsages(labelName),_current[\"(usages)\"][labelName][\"(modified)\"].push(token)},add:function(labelName,type,tok,unused){_current[\"(labels)\"][labelName]={\"(type)\":type,\"(token)\":tok,\"(blockscoped)\":!0,\"(unused)\":unused}},addBreakLabel:function(labelName,opts){var token=opts.token;scopeManagerInst.funct.hasBreakLabel(labelName)?warning(\"E011\",token,labelName):\"outer\"===state.option.shadow&&(scopeManagerInst.funct.has(labelName)?warning(\"W004\",token,labelName):_checkOuterShadow(labelName,token)),_current[\"(breakLabels)\"][labelName]=token}}};return scopeManagerInst};module.exports=scopeManager},{\"../lodash\":\"/node_modules/jshint/lodash.js\",events:\"/node_modules/browserify/node_modules/events/events.js\"}],\"/node_modules/jshint/src/state.js\":[function(_dereq_,module,exports){\"use strict\";var NameStack=_dereq_(\"./name-stack.js\"),state={syntax:{},isStrict:function(){return this.directive[\"use strict\"]||this.inClassBody||this.option.module||\"implied\"===this.option.strict},inMoz:function(){return this.option.moz},inES6:function(){return this.option.moz||this.option.esversion>=6},inES5:function(strict){return strict?!(this.option.esversion&&5!==this.option.esversion||this.option.moz):!this.option.esversion||this.option.esversion>=5||this.option.moz},reset:function(){this.tokens={prev:null,next:null,curr:null},this.option={},this.funct=null,this.ignored={},this.directive={},this.jsonMode=!1,this.jsonWarnings=[],this.lines=[],this.tab=\"\",this.cache={},this.ignoredLines={},this.forinifcheckneeded=!1,this.nameStack=new NameStack,this.inClassBody=!1}};exports.state=state},{\"./name-stack.js\":\"/node_modules/jshint/src/name-stack.js\"}],\"/node_modules/jshint/src/style.js\":[function(_dereq_,module,exports){\"use strict\";exports.register=function(linter){linter.on(\"Identifier\",function(data){linter.getOption(\"proto\")||\"__proto__\"===data.name&&linter.warn(\"W103\",{line:data.line,\"char\":data.char,data:[data.name,\"6\"]})}),linter.on(\"Identifier\",function(data){linter.getOption(\"iterator\")||\"__iterator__\"===data.name&&linter.warn(\"W103\",{line:data.line,\"char\":data.char,data:[data.name]})}),linter.on(\"Identifier\",function(data){linter.getOption(\"camelcase\")&&data.name.replace(/^_+|_+$/g,\"\").indexOf(\"_\")>-1&&!data.name.match(/^[A-Z0-9_]*$/)&&linter.warn(\"W106\",{line:data.line,\"char\":data.from,data:[data.name]})}),linter.on(\"String\",function(data){var code,quotmark=linter.getOption(\"quotmark\");quotmark&&(\"single\"===quotmark&&\"\\'\"!==data.quote&&(code=\"W109\"),\"double\"===quotmark&&\\'\"\\'!==data.quote&&(code=\"W108\"),quotmark===!0&&(linter.getCache(\"quotmark\")||linter.setCache(\"quotmark\",data.quote),linter.getCache(\"quotmark\")!==data.quote&&(code=\"W110\")),code&&linter.warn(code,{line:data.line,\"char\":data.char}))}),linter.on(\"Number\",function(data){\".\"===data.value.charAt(0)&&linter.warn(\"W008\",{line:data.line,\"char\":data.char,data:[data.value]}),\".\"===data.value.substr(data.value.length-1)&&linter.warn(\"W047\",{line:data.line,\"char\":data.char,data:[data.value]}),/^00+/.test(data.value)&&linter.warn(\"W046\",{line:data.line,\"char\":data.char,data:[data.value]})}),linter.on(\"String\",function(data){var re=/^(?:javascript|jscript|ecmascript|vbscript|livescript)\\\\s*:/i;linter.getOption(\"scripturl\")||re.test(data.value)&&linter.warn(\"W107\",{line:data.line,\"char\":data.char})})}},{}],\"/node_modules/jshint/src/vars.js\":[function(_dereq_,module,exports){\"use strict\";exports.reservedVars={arguments:!1,NaN:!1},exports.ecmaIdentifiers={3:{Array:!1,Boolean:!1,Date:!1,decodeURI:!1,decodeURIComponent:!1,encodeURI:!1,encodeURIComponent:!1,Error:!1,eval:!1,EvalError:!1,Function:!1,hasOwnProperty:!1,isFinite:!1,isNaN:!1,Math:!1,Number:!1,Object:!1,parseInt:!1,parseFloat:!1,RangeError:!1,ReferenceError:!1,RegExp:!1,String:!1,SyntaxError:!1,TypeError:!1,URIError:!1},5:{JSON:!1},6:{Map:!1,Promise:!1,Proxy:!1,Reflect:!1,Set:!1,Symbol:!1,WeakMap:!1,WeakSet:!1}},exports.browser={Audio:!1,Blob:!1,addEventListener:!1,applicationCache:!1,atob:!1,blur:!1,btoa:!1,cancelAnimationFrame:!1,CanvasGradient:!1,CanvasPattern:!1,CanvasRenderingContext2D:!1,CSS:!1,clearInterval:!1,clearTimeout:!1,close:!1,closed:!1,Comment:!1,CustomEvent:!1,DOMParser:!1,defaultStatus:!1,Document:!1,document:!1,DocumentFragment:!1,Element:!1,ElementTimeControl:!1,Event:!1,event:!1,fetch:!1,FileReader:!1,FormData:!1,focus:!1,frames:!1,getComputedStyle:!1,HTMLElement:!1,HTMLAnchorElement:!1,HTMLBaseElement:!1,HTMLBlockquoteElement:!1,HTMLBodyElement:!1,HTMLBRElement:!1,HTMLButtonElement:!1,HTMLCanvasElement:!1,HTMLCollection:!1,HTMLDirectoryElement:!1,HTMLDivElement:!1,HTMLDListElement:!1,HTMLFieldSetElement:!1,HTMLFontElement:!1,HTMLFormElement:!1,HTMLFrameElement:!1,HTMLFrameSetElement:!1,HTMLHeadElement:!1,HTMLHeadingElement:!1,HTMLHRElement:!1,HTMLHtmlElement:!1,HTMLIFrameElement:!1,HTMLImageElement:!1,HTMLInputElement:!1,HTMLIsIndexElement:!1,HTMLLabelElement:!1,HTMLLayerElement:!1,HTMLLegendElement:!1,HTMLLIElement:!1,HTMLLinkElement:!1,HTMLMapElement:!1,HTMLMenuElement:!1,HTMLMetaElement:!1,HTMLModElement:!1,HTMLObjectElement:!1,HTMLOListElement:!1,HTMLOptGroupElement:!1,HTMLOptionElement:!1,HTMLParagraphElement:!1,HTMLParamElement:!1,HTMLPreElement:!1,HTMLQuoteElement:!1,HTMLScriptElement:!1,HTMLSelectElement:!1,HTMLStyleElement:!1,HTMLTableCaptionElement:!1,HTMLTableCellElement:!1,HTMLTableColElement:!1,HTMLTableElement:!1,HTMLTableRowElement:!1,HTMLTableSectionElement:!1,HTMLTemplateElement:!1,HTMLTextAreaElement:!1,HTMLTitleElement:!1,HTMLUListElement:!1,HTMLVideoElement:!1,history:!1,Image:!1,Intl:!1,length:!1,localStorage:!1,location:!1,matchMedia:!1,MessageChannel:!1,MessageEvent:!1,MessagePort:!1,MouseEvent:!1,moveBy:!1,moveTo:!1,MutationObserver:!1,name:!1,Node:!1,NodeFilter:!1,NodeList:!1,Notification:!1,navigator:!1,onbeforeunload:!0,onblur:!0,onerror:!0,onfocus:!0,onload:!0,onresize:!0,onunload:!0,open:!1,openDatabase:!1,opener:!1,Option:!1,parent:!1,performance:!1,print:!1,Range:!1,requestAnimationFrame:!1,removeEventListener:!1,resizeBy:!1,resizeTo:!1,screen:!1,scroll:!1,scrollBy:!1,scrollTo:!1,sessionStorage:!1,setInterval:!1,setTimeout:!1,SharedWorker:!1,status:!1,SVGAElement:!1,SVGAltGlyphDefElement:!1,SVGAltGlyphElement:!1,SVGAltGlyphItemElement:!1,SVGAngle:!1,SVGAnimateColorElement:!1,SVGAnimateElement:!1,SVGAnimateMotionElement:!1,SVGAnimateTransformElement:!1,SVGAnimatedAngle:!1,SVGAnimatedBoolean:!1,SVGAnimatedEnumeration:!1,SVGAnimatedInteger:!1,SVGAnimatedLength:!1,SVGAnimatedLengthList:!1,SVGAnimatedNumber:!1,SVGAnimatedNumberList:!1,SVGAnimatedPathData:!1,SVGAnimatedPoints:!1,SVGAnimatedPreserveAspectRatio:!1,SVGAnimatedRect:!1,SVGAnimatedString:!1,SVGAnimatedTransformList:!1,SVGAnimationElement:!1,SVGCSSRule:!1,SVGCircleElement:!1,SVGClipPathElement:!1,SVGColor:!1,SVGColorProfileElement:!1,SVGColorProfileRule:!1,SVGComponentTransferFunctionElement:!1,SVGCursorElement:!1,SVGDefsElement:!1,SVGDescElement:!1,SVGDocument:!1,SVGElement:!1,SVGElementInstance:!1,SVGElementInstanceList:!1,SVGEllipseElement:!1,SVGExternalResourcesRequired:!1,SVGFEBlendElement:!1,SVGFEColorMatrixElement:!1,SVGFEComponentTransferElement:!1,SVGFECompositeElement:!1,SVGFEConvolveMatrixElement:!1,SVGFEDiffuseLightingElement:!1,SVGFEDisplacementMapElement:!1,SVGFEDistantLightElement:!1,SVGFEFloodElement:!1,SVGFEFuncAElement:!1,SVGFEFuncBElement:!1,SVGFEFuncGElement:!1,SVGFEFuncRElement:!1,SVGFEGaussianBlurElement:!1,SVGFEImageElement:!1,SVGFEMergeElement:!1,SVGFEMergeNodeElement:!1,SVGFEMorphologyElement:!1,SVGFEOffsetElement:!1,SVGFEPointLightElement:!1,SVGFESpecularLightingElement:!1,SVGFESpotLightElement:!1,SVGFETileElement:!1,SVGFETurbulenceElement:!1,SVGFilterElement:!1,SVGFilterPrimitiveStandardAttributes:!1,SVGFitToViewBox:!1,SVGFontElement:!1,SVGFontFaceElement:!1,SVGFontFaceFormatElement:!1,SVGFontFaceNameElement:!1,SVGFontFaceSrcElement:!1,SVGFontFaceUriElement:!1,SVGForeignObjectElement:!1,SVGGElement:!1,SVGGlyphElement:!1,SVGGlyphRefElement:!1,SVGGradientElement:!1,SVGHKernElement:!1,SVGICCColor:!1,SVGImageElement:!1,SVGLangSpace:!1,SVGLength:!1,SVGLengthList:!1,SVGLineElement:!1,SVGLinearGradientElement:!1,SVGLocatable:!1,SVGMPathElement:!1,SVGMarkerElement:!1,SVGMaskElement:!1,SVGMatrix:!1,SVGMetadataElement:!1,SVGMissingGlyphElement:!1,SVGNumber:!1,SVGNumberList:!1,SVGPaint:!1,SVGPathElement:!1,SVGPathSeg:!1,SVGPathSegArcAbs:!1,SVGPathSegArcRel:!1,SVGPathSegClosePath:!1,SVGPathSegCurvetoCubicAbs:!1,SVGPathSegCurvetoCubicRel:!1,SVGPathSegCurvetoCubicSmoothAbs:!1,SVGPathSegCurvetoCubicSmoothRel:!1,SVGPathSegCurvetoQuadraticAbs:!1,SVGPathSegCurvetoQuadraticRel:!1,SVGPathSegCurvetoQuadraticSmoothAbs:!1,SVGPathSegCurvetoQuadraticSmoothRel:!1,SVGPathSegLinetoAbs:!1,SVGPathSegLinetoHorizontalAbs:!1,SVGPathSegLinetoHorizontalRel:!1,SVGPathSegLinetoRel:!1,SVGPathSegLinetoVerticalAbs:!1,SVGPathSegLinetoVerticalRel:!1,SVGPathSegList:!1,SVGPathSegMovetoAbs:!1,SVGPathSegMovetoRel:!1,SVGPatternElement:!1,SVGPoint:!1,SVGPointList:!1,SVGPolygonElement:!1,SVGPolylineElement:!1,SVGPreserveAspectRatio:!1,SVGRadialGradientElement:!1,SVGRect:!1,SVGRectElement:!1,SVGRenderingIntent:!1,SVGSVGElement:!1,SVGScriptElement:!1,SVGSetElement:!1,SVGStopElement:!1,SVGStringList:!1,SVGStylable:!1,SVGStyleElement:!1,SVGSwitchElement:!1,SVGSymbolElement:!1,SVGTRefElement:!1,SVGTSpanElement:!1,SVGTests:!1,SVGTextContentElement:!1,SVGTextElement:!1,SVGTextPathElement:!1,SVGTextPositioningElement:!1,SVGTitleElement:!1,SVGTransform:!1,SVGTransformList:!1,SVGTransformable:!1,SVGURIReference:!1,SVGUnitTypes:!1,SVGUseElement:!1,SVGVKernElement:!1,SVGViewElement:!1,SVGViewSpec:!1,SVGZoomAndPan:!1,Text:!1,TextDecoder:!1,TextEncoder:!1,TimeEvent:!1,top:!1,URL:!1,WebGLActiveInfo:!1,WebGLBuffer:!1,WebGLContextEvent:!1,WebGLFramebuffer:!1,WebGLProgram:!1,WebGLRenderbuffer:!1,WebGLRenderingContext:!1,WebGLShader:!1,WebGLShaderPrecisionFormat:!1,WebGLTexture:!1,WebGLUniformLocation:!1,WebSocket:!1,window:!1,Window:!1,Worker:!1,XDomainRequest:!1,XMLHttpRequest:!1,XMLSerializer:!1,XPathEvaluator:!1,XPathException:!1,XPathExpression:!1,XPathNamespace:!1,XPathNSResolver:!1,XPathResult:!1},exports.devel={alert:!1,confirm:!1,console:!1,Debug:!1,opera:!1,prompt:!1},exports.worker={importScripts:!0,postMessage:!0,self:!0,FileReaderSync:!0},exports.nonstandard={escape:!1,unescape:!1},exports.couch={require:!1,respond:!1,getRow:!1,emit:!1,send:!1,start:!1,sum:!1,log:!1,exports:!1,module:!1,provides:!1},exports.node={__filename:!1,__dirname:!1,GLOBAL:!1,global:!1,module:!1,acequire:!1,Buffer:!0,console:!0,exports:!0,process:!0,setTimeout:!0,clearTimeout:!0,setInterval:!0,clearInterval:!0,setImmediate:!0,clearImmediate:!0},exports.browserify={__filename:!1,__dirname:!1,global:!1,module:!1,acequire:!1,Buffer:!0,exports:!0,process:!0},exports.phantom={phantom:!0,acequire:!0,WebPage:!0,console:!0,exports:!0},exports.qunit={asyncTest:!1,deepEqual:!1,equal:!1,expect:!1,module:!1,notDeepEqual:!1,notEqual:!1,notPropEqual:!1,notStrictEqual:!1,ok:!1,propEqual:!1,QUnit:!1,raises:!1,start:!1,stop:!1,strictEqual:!1,test:!1,\"throws\":!1},exports.rhino={defineClass:!1,deserialize:!1,gc:!1,help:!1,importClass:!1,importPackage:!1,java:!1,load:!1,loadClass:!1,Packages:!1,print:!1,quit:!1,readFile:!1,readUrl:!1,runCommand:!1,seal:!1,serialize:!1,spawn:!1,sync:!1,toint32:!1,version:!1},exports.shelljs={target:!1,echo:!1,exit:!1,cd:!1,pwd:!1,ls:!1,find:!1,cp:!1,rm:!1,mv:!1,mkdir:!1,test:!1,cat:!1,sed:!1,grep:!1,which:!1,dirs:!1,pushd:!1,popd:!1,env:!1,exec:!1,chmod:!1,config:!1,error:!1,tempdir:!1},exports.typed={ArrayBuffer:!1,ArrayBufferView:!1,DataView:!1,Float32Array:!1,Float64Array:!1,Int16Array:!1,Int32Array:!1,Int8Array:!1,Uint16Array:!1,Uint32Array:!1,Uint8Array:!1,Uint8ClampedArray:!1},exports.wsh={ActiveXObject:!0,Enumerator:!0,GetObject:!0,ScriptEngine:!0,ScriptEngineBuildVersion:!0,ScriptEngineMajorVersion:!0,ScriptEngineMinorVersion:!0,VBArray:!0,WSH:!0,WScript:!0,XDomainRequest:!0},exports.dojo={dojo:!1,dijit:!1,dojox:!1,define:!1,require:!1},exports.jquery={$:!1,jQuery:!1},exports.mootools={$:!1,$$:!1,Asset:!1,Browser:!1,Chain:!1,Class:!1,Color:!1,Cookie:!1,Core:!1,Document:!1,DomReady:!1,DOMEvent:!1,DOMReady:!1,Drag:!1,Element:!1,Elements:!1,Event:!1,Events:!1,Fx:!1,Group:!1,Hash:!1,HtmlTable:!1,IFrame:!1,IframeShim:!1,InputValidator:!1,instanceOf:!1,Keyboard:!1,Locale:!1,Mask:!1,MooTools:!1,Native:!1,Options:!1,OverText:!1,Request:!1,Scroller:!1,Slick:!1,Slider:!1,Sortables:!1,Spinner:!1,Swiff:!1,Tips:!1,Type:!1,typeOf:!1,URI:!1,Window:!1},exports.prototypejs={$:!1,$$:!1,$A:!1,$F:!1,$H:!1,$R:!1,$break:!1,$continue:!1,$w:!1,Abstract:!1,Ajax:!1,Class:!1,Enumerable:!1,Element:!1,Event:!1,Field:!1,Form:!1,Hash:!1,Insertion:!1,ObjectRange:!1,PeriodicalExecuter:!1,Position:!1,Prototype:!1,Selector:!1,Template:!1,Toggle:!1,Try:!1,Autocompleter:!1,Builder:!1,Control:!1,Draggable:!1,Draggables:!1,Droppables:!1,Effect:!1,Sortable:!1,SortableObserver:!1,Sound:!1,Scriptaculous:!1},exports.yui={YUI:!1,Y:!1,YUI_config:!1},exports.mocha={mocha:!1,describe:!1,xdescribe:!1,it:!1,xit:!1,context:!1,xcontext:!1,before:!1,after:!1,beforeEach:!1,afterEach:!1,suite:!1,test:!1,setup:!1,teardown:!1,suiteSetup:!1,suiteTeardown:!1},exports.jasmine={jasmine:!1,describe:!1,xdescribe:!1,it:!1,xit:!1,beforeEach:!1,afterEach:!1,setFixtures:!1,loadFixtures:!1,spyOn:!1,expect:!1,runs:!1,waitsFor:!1,waits:!1,beforeAll:!1,afterAll:!1,fail:!1,fdescribe:!1,fit:!1,pending:!1}},{}]},{},[\"/node_modules/jshint/src/jshint.js\"])}),ace.define(\"ace/mode/javascript_worker\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/worker/mirror\",\"ace/mode/javascript/jshint\"],function(acequire,exports,module){\"use strict\";function startRegex(arr){return RegExp(\"^(\"+arr.join(\"|\")+\")\")}var oop=acequire(\"../lib/oop\"),Mirror=acequire(\"../worker/mirror\").Mirror,lint=acequire(\"./javascript/jshint\").JSHINT,disabledWarningsRe=startRegex([\"Bad for in variable \\'(.+)\\'.\",\\'Missing \"use strict\"\\']),errorsRe=startRegex([\"Unexpected\",\"Expected \",\"Confusing (plus|minus)\",\"\\\\\\\\{a\\\\\\\\} unterminated regular expression\",\"Unclosed \",\"Unmatched \",\"Unbegun comment\",\"Bad invocation\",\"Missing space after\",\"Missing operator at\"]),infoRe=startRegex([\"Expected an assignment\",\"Bad escapement of EOL\",\"Unexpected comma\",\"Unexpected space\",\"Missing radix parameter.\",\"A leading decimal point can\",\"\\\\\\\\[\\'{a}\\'\\\\\\\\] is better written in dot notation.\",\"\\'{a}\\' used out of scope\"]),JavaScriptWorker=exports.JavaScriptWorker=function(sender){Mirror.call(this,sender),this.setTimeout(500),this.setOptions()};oop.inherits(JavaScriptWorker,Mirror),function(){this.setOptions=function(options){this.options=options||{esnext:!0,moz:!0,devel:!0,browser:!0,node:!0,laxcomma:!0,laxbreak:!0,lastsemic:!0,onevar:!1,passfail:!1,maxerr:100,expr:!0,multistr:!0,globalstrict:!0},this.doc.getValue()&&this.deferredUpdate.schedule(100)},this.changeOptions=function(newOptions){oop.mixin(this.options,newOptions),this.doc.getValue()&&this.deferredUpdate.schedule(100)},this.isValidJS=function(str){try{eval(\"throw 0;\"+str)}catch(e){if(0===e)return!0}return!1},this.onUpdate=function(){var value=this.doc.getValue();if(value=value.replace(/^#!.*\\\\n/,\"\\\\n\"),!value)return this.sender.emit(\"annotate\",[]);var errors=[],maxErrorLevel=this.isValidJS(value)?\"warning\":\"error\";lint(value,this.options,this.options.globals);for(var results=lint.errors,errorAdded=!1,i=0;results.length>i;i++){var error=results[i];if(error){var raw=error.raw,type=\"warning\";if(\"Missing semicolon.\"==raw){var str=error.evidence.substr(error.character);str=str.charAt(str.search(/\\\\S/)),\"error\"==maxErrorLevel&&str&&/[\\\\w\\\\d{([\\'\"]/.test(str)?(error.reason=\\'Missing \";\" before statement\\',type=\"error\"):type=\"info\"}else{if(disabledWarningsRe.test(raw))continue;infoRe.test(raw)?type=\"info\":errorsRe.test(raw)?(errorAdded=!0,type=maxErrorLevel):\"\\'{a}\\' is not defined.\"==raw?type=\"warning\":\"\\'{a}\\' is defined but never used.\"==raw&&(type=\"info\")}errors.push({row:error.line-1,column:error.character-1,text:error.reason,type:type,raw:raw})}}this.sender.emit(\"annotate\",errors)}}.call(JavaScriptWorker.prototype)}),ace.define(\"ace/lib/es5-shim\",[\"require\",\"exports\",\"module\"],function(){function Empty(){}function doesDefinePropertyWork(object){try{return Object.defineProperty(object,\"sentinel\",{}),\"sentinel\"in object}catch(exception){}}function toInteger(n){return n=+n,n!==n?n=0:0!==n&&n!==1/0&&n!==-(1/0)&&(n=(n>0||-1)*Math.floor(Math.abs(n))),n}Function.prototype.bind||(Function.prototype.bind=function(that){var target=this;if(\"function\"!=typeof target)throw new TypeError(\"Function.prototype.bind called on incompatible \"+target);var args=slice.call(arguments,1),bound=function(){if(this instanceof bound){var result=target.apply(this,args.concat(slice.call(arguments)));return Object(result)===result?result:this}return target.apply(that,args.concat(slice.call(arguments)))};return target.prototype&&(Empty.prototype=target.prototype,bound.prototype=new Empty,Empty.prototype=null),bound});var defineGetter,defineSetter,lookupGetter,lookupSetter,supportsAccessors,call=Function.prototype.call,prototypeOfArray=Array.prototype,prototypeOfObject=Object.prototype,slice=prototypeOfArray.slice,_toString=call.bind(prototypeOfObject.toString),owns=call.bind(prototypeOfObject.hasOwnProperty);if((supportsAccessors=owns(prototypeOfObject,\"__defineGetter__\"))&&(defineGetter=call.bind(prototypeOfObject.__defineGetter__),defineSetter=call.bind(prototypeOfObject.__defineSetter__),lookupGetter=call.bind(prototypeOfObject.__lookupGetter__),lookupSetter=call.bind(prototypeOfObject.__lookupSetter__)),2!=[1,2].splice(0).length)if(function(){function makeArray(l){var a=Array(l+2);return a[0]=a[1]=0,a}var lengthBefore,array=[];return array.splice.apply(array,makeArray(20)),array.splice.apply(array,makeArray(26)),lengthBefore=array.length,array.splice(5,0,\"XXX\"),lengthBefore+1==array.length,lengthBefore+1==array.length?!0:void 0}()){var array_splice=Array.prototype.splice;Array.prototype.splice=function(start,deleteCount){return arguments.length?array_splice.apply(this,[void 0===start?0:start,void 0===deleteCount?this.length-start:deleteCount].concat(slice.call(arguments,2))):[]}}else Array.prototype.splice=function(pos,removeCount){var length=this.length;pos>0?pos>length&&(pos=length):void 0==pos?pos=0:0>pos&&(pos=Math.max(length+pos,0)),length>pos+removeCount||(removeCount=length-pos);var removed=this.slice(pos,pos+removeCount),insert=slice.call(arguments,2),add=insert.length;if(pos===length)add&&this.push.apply(this,insert);else{var remove=Math.min(removeCount,length-pos),tailOldPos=pos+remove,tailNewPos=tailOldPos+add-remove,tailCount=length-tailOldPos,lengthAfterRemove=length-remove;if(tailOldPos>tailNewPos)for(var i=0;tailCount>i;++i)this[tailNewPos+i]=this[tailOldPos+i];else if(tailNewPos>tailOldPos)for(i=tailCount;i--;)this[tailNewPos+i]=this[tailOldPos+i];if(add&&pos===lengthAfterRemove)this.length=lengthAfterRemove,this.push.apply(this,insert);else for(this.length=lengthAfterRemove+add,i=0;add>i;++i)this[pos+i]=insert[i]}return removed};Array.isArray||(Array.isArray=function(obj){return\"[object Array]\"==_toString(obj)});var boxedString=Object(\"a\"),splitString=\"a\"!=boxedString[0]||!(0 in boxedString);if(Array.prototype.forEach||(Array.prototype.forEach=function(fun){var object=toObject(this),self=splitString&&\"[object String]\"==_toString(this)?this.split(\"\"):object,thisp=arguments[1],i=-1,length=self.length>>>0;if(\"[object Function]\"!=_toString(fun))throw new TypeError;for(;length>++i;)i in self&&fun.call(thisp,self[i],i,object)}),Array.prototype.map||(Array.prototype.map=function(fun){var object=toObject(this),self=splitString&&\"[object String]\"==_toString(this)?this.split(\"\"):object,length=self.length>>>0,result=Array(length),thisp=arguments[1];if(\"[object Function]\"!=_toString(fun))throw new TypeError(fun+\" is not a function\");for(var i=0;length>i;i++)i in self&&(result[i]=fun.call(thisp,self[i],i,object));return result}),Array.prototype.filter||(Array.prototype.filter=function(fun){var value,object=toObject(this),self=splitString&&\"[object String]\"==_toString(this)?this.split(\"\"):object,length=self.length>>>0,result=[],thisp=arguments[1];if(\"[object Function]\"!=_toString(fun))throw new TypeError(fun+\" is not a function\");for(var i=0;length>i;i++)i in self&&(value=self[i],fun.call(thisp,value,i,object)&&result.push(value));return result}),Array.prototype.every||(Array.prototype.every=function(fun){var object=toObject(this),self=splitString&&\"[object String]\"==_toString(this)?this.split(\"\"):object,length=self.length>>>0,thisp=arguments[1];if(\"[object Function]\"!=_toString(fun))throw new TypeError(fun+\" is not a function\");for(var i=0;length>i;i++)if(i in self&&!fun.call(thisp,self[i],i,object))return!1;return!0}),Array.prototype.some||(Array.prototype.some=function(fun){var object=toObject(this),self=splitString&&\"[object String]\"==_toString(this)?this.split(\"\"):object,length=self.length>>>0,thisp=arguments[1];if(\"[object Function]\"!=_toString(fun))throw new TypeError(fun+\" is not a function\");for(var i=0;length>i;i++)if(i in self&&fun.call(thisp,self[i],i,object))return!0;return!1}),Array.prototype.reduce||(Array.prototype.reduce=function(fun){var object=toObject(this),self=splitString&&\"[object String]\"==_toString(this)?this.split(\"\"):object,length=self.length>>>0;if(\"[object Function]\"!=_toString(fun))throw new TypeError(fun+\" is not a function\");if(!length&&1==arguments.length)throw new TypeError(\"reduce of empty array with no initial value\");var result,i=0;if(arguments.length>=2)result=arguments[1];else for(;;){if(i in self){result=self[i++];break}if(++i>=length)throw new TypeError(\"reduce of empty array with no initial value\")}for(;length>i;i++)i in self&&(result=fun.call(void 0,result,self[i],i,object));return result}),Array.prototype.reduceRight||(Array.prototype.reduceRight=function(fun){var object=toObject(this),self=splitString&&\"[object String]\"==_toString(this)?this.split(\"\"):object,length=self.length>>>0;if(\"[object Function]\"!=_toString(fun))throw new TypeError(fun+\" is not a function\");if(!length&&1==arguments.length)throw new TypeError(\"reduceRight of empty array with no initial value\");var result,i=length-1;if(arguments.length>=2)result=arguments[1];else for(;;){if(i in self){result=self[i--];break}if(0>--i)throw new TypeError(\"reduceRight of empty array with no initial value\")}do i in this&&(result=fun.call(void 0,result,self[i],i,object));while(i--);return result}),Array.prototype.indexOf&&-1==[0,1].indexOf(1,2)||(Array.prototype.indexOf=function(sought){var self=splitString&&\"[object String]\"==_toString(this)?this.split(\"\"):toObject(this),length=self.length>>>0;if(!length)return-1;var i=0;for(arguments.length>1&&(i=toInteger(arguments[1])),i=i>=0?i:Math.max(0,length+i);length>i;i++)if(i in self&&self[i]===sought)return i;return-1}),Array.prototype.lastIndexOf&&-1==[0,1].lastIndexOf(0,-3)||(Array.prototype.lastIndexOf=function(sought){var self=splitString&&\"[object String]\"==_toString(this)?this.split(\"\"):toObject(this),length=self.length>>>0;if(!length)return-1;var i=length-1;for(arguments.length>1&&(i=Math.min(i,toInteger(arguments[1]))),i=i>=0?i:length-Math.abs(i);i>=0;i--)if(i in self&&sought===self[i])return i;return-1}),Object.getPrototypeOf||(Object.getPrototypeOf=function(object){return object.__proto__||(object.constructor?object.constructor.prototype:prototypeOfObject)}),!Object.getOwnPropertyDescriptor){var ERR_NON_OBJECT=\"Object.getOwnPropertyDescriptor called on a non-object: \";Object.getOwnPropertyDescriptor=function(object,property){if(\"object\"!=typeof object&&\"function\"!=typeof object||null===object)throw new TypeError(ERR_NON_OBJECT+object);if(owns(object,property)){var descriptor,getter,setter;if(descriptor={enumerable:!0,configurable:!0},supportsAccessors){var prototype=object.__proto__;object.__proto__=prototypeOfObject;var getter=lookupGetter(object,property),setter=lookupSetter(object,property);if(object.__proto__=prototype,getter||setter)return getter&&(descriptor.get=getter),setter&&(descriptor.set=setter),descriptor}return descriptor.value=object[property],descriptor}}}if(Object.getOwnPropertyNames||(Object.getOwnPropertyNames=function(object){return Object.keys(object)}),!Object.create){var createEmpty;createEmpty=null===Object.prototype.__proto__?function(){return{__proto__:null}}:function(){var empty={};for(var i in empty)empty[i]=null;return empty.constructor=empty.hasOwnProperty=empty.propertyIsEnumerable=empty.isPrototypeOf=empty.toLocaleString=empty.toString=empty.valueOf=empty.__proto__=null,empty},Object.create=function(prototype,properties){var object;if(null===prototype)object=createEmpty();else{if(\"object\"!=typeof prototype)throw new TypeError(\"typeof prototype[\"+typeof prototype+\"] != \\'object\\'\");var Type=function(){};Type.prototype=prototype,object=new Type,object.__proto__=prototype}return void 0!==properties&&Object.defineProperties(object,properties),object}}if(Object.defineProperty){var definePropertyWorksOnObject=doesDefinePropertyWork({}),definePropertyWorksOnDom=\"undefined\"==typeof document||doesDefinePropertyWork(document.createElement(\"div\"));if(!definePropertyWorksOnObject||!definePropertyWorksOnDom)var definePropertyFallback=Object.defineProperty}if(!Object.defineProperty||definePropertyFallback){var ERR_NON_OBJECT_DESCRIPTOR=\"Property description must be an object: \",ERR_NON_OBJECT_TARGET=\"Object.defineProperty called on non-object: \",ERR_ACCESSORS_NOT_SUPPORTED=\"getters & setters can not be defined on this javascript engine\";Object.defineProperty=function(object,property,descriptor){if(\"object\"!=typeof object&&\"function\"!=typeof object||null===object)throw new TypeError(ERR_NON_OBJECT_TARGET+object);if(\"object\"!=typeof descriptor&&\"function\"!=typeof descriptor||null===descriptor)throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR+descriptor);if(definePropertyFallback)try{return definePropertyFallback.call(Object,object,property,descriptor)}catch(exception){}if(owns(descriptor,\"value\"))if(supportsAccessors&&(lookupGetter(object,property)||lookupSetter(object,property))){var prototype=object.__proto__;object.__proto__=prototypeOfObject,delete object[property],object[property]=descriptor.value,object.__proto__=prototype}else object[property]=descriptor.value;else{if(!supportsAccessors)throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);owns(descriptor,\"get\")&&defineGetter(object,property,descriptor.get),owns(descriptor,\"set\")&&defineSetter(object,property,descriptor.set)}return object}}Object.defineProperties||(Object.defineProperties=function(object,properties){for(var property in properties)owns(properties,property)&&Object.defineProperty(object,property,properties[property]);return object}),Object.seal||(Object.seal=function(object){return object}),Object.freeze||(Object.freeze=function(object){return object});try{Object.freeze(function(){})}catch(exception){Object.freeze=function(freezeObject){return function(object){return\"function\"==typeof object?object:freezeObject(object)}}(Object.freeze)}if(Object.preventExtensions||(Object.preventExtensions=function(object){return object}),Object.isSealed||(Object.isSealed=function(){return!1}),Object.isFrozen||(Object.isFrozen=function(){return!1}),Object.isExtensible||(Object.isExtensible=function(object){if(Object(object)===object)throw new TypeError;for(var name=\"\";owns(object,name);)name+=\"?\";object[name]=!0;var returnValue=owns(object,name);return delete object[name],returnValue}),!Object.keys){var hasDontEnumBug=!0,dontEnums=[\"toString\",\"toLocaleString\",\"valueOf\",\"hasOwnProperty\",\"isPrototypeOf\",\"propertyIsEnumerable\",\"constructor\"],dontEnumsLength=dontEnums.length;for(var key in{toString:null})hasDontEnumBug=!1;Object.keys=function(object){if(\"object\"!=typeof object&&\"function\"!=typeof object||null===object)throw new TypeError(\"Object.keys called on a non-object\");var keys=[];for(var name in object)owns(object,name)&&keys.push(name);if(hasDontEnumBug)for(var i=0,ii=dontEnumsLength;ii>i;i++){var dontEnum=dontEnums[i];owns(object,dontEnum)&&keys.push(dontEnum)}return keys}}Date.now||(Date.now=function(){return(new Date).getTime()});var ws=\"\\t\\\\n\\v\\\\f\\\\r   ᠎             　\\\\u2028\\\\u2029\\ufeff\";if(!String.prototype.trim||ws.trim()){ws=\"[\"+ws+\"]\";var trimBeginRegexp=RegExp(\"^\"+ws+ws+\"*\"),trimEndRegexp=RegExp(ws+ws+\"*$\");String.prototype.trim=function(){return(this+\"\").replace(trimBeginRegexp,\"\").replace(trimEndRegexp,\"\")}}var toObject=function(o){if(null==o)throw new TypeError(\"can\\'t convert \"+o+\" to object\");return Object(o)}});'},\"7c9e\":function(e,t,n){var r=n(\"061c\");e.exports={render:function(e){var t=this.height?this.px(this.height):\"100%\",n=this.width?this.px(this.width):\"100%\";return e(\"div\",{attrs:{style:\"height: \"+t+\"; width: \"+n}})},props:{value:{type:String,required:!0},lang:String,theme:String,height:!0,width:!0,options:Object},data:function(){return{editor:null,contentBackup:\"\"}},methods:{px:function(e){return/^\\d*$/.test(e)?e+\"px\":e}},watch:{value:function(e){this.contentBackup!==e&&(this.editor.session.setValue(e,1),this.contentBackup=e)},theme:function(e){this.editor.setTheme(\"ace/theme/\"+e)},lang:function(e){this.editor.getSession().setMode(\"ace/mode/\"+e)},options:function(e){this.editor.setOptions(e)},height:function(){this.$nextTick(function(){this.editor.resize()})},width:function(){this.$nextTick(function(){this.editor.resize()})}},beforeDestroy:function(){this.editor.destroy(),this.editor.container.remove()},mounted:function(){var e=this,t=this.lang||\"text\",i=this.theme||\"chrome\";n(\"b378\");var o=e.editor=r.edit(this.$el);this.$emit(\"init\",o),o.$blockScrolling=1/0,o.getSession().setMode(\"ace/mode/\"+t),o.setTheme(\"ace/theme/\"+i),o.setValue(this.value,1),this.contentBackup=this.value,o.on(\"change\",function(){var t=o.getValue();e.$emit(\"input\",t),e.contentBackup=t}),e.options&&o.setOptions(e.options)}}},\"95b8\":function(e,t){ace.define(\"ace/theme/chrome\",[\"require\",\"exports\",\"module\",\"ace/lib/dom\"],function(e,t,n){t.isDark=!1,t.cssClass=\"ace-chrome\",t.cssText='.ace-chrome .ace_gutter {background: #ebebeb;color: #333;overflow : hidden;}.ace-chrome .ace_print-margin {width: 1px;background: #e8e8e8;}.ace-chrome {background-color: #FFFFFF;color: black;}.ace-chrome .ace_cursor {color: black;}.ace-chrome .ace_invisible {color: rgb(191, 191, 191);}.ace-chrome .ace_constant.ace_buildin {color: rgb(88, 72, 246);}.ace-chrome .ace_constant.ace_language {color: rgb(88, 92, 246);}.ace-chrome .ace_constant.ace_library {color: rgb(6, 150, 14);}.ace-chrome .ace_invalid {background-color: rgb(153, 0, 0);color: white;}.ace-chrome .ace_fold {}.ace-chrome .ace_support.ace_function {color: rgb(60, 76, 114);}.ace-chrome .ace_support.ace_constant {color: rgb(6, 150, 14);}.ace-chrome .ace_support.ace_type,.ace-chrome .ace_support.ace_class.ace-chrome .ace_support.ace_other {color: rgb(109, 121, 222);}.ace-chrome .ace_variable.ace_parameter {font-style:italic;color:#FD971F;}.ace-chrome .ace_keyword.ace_operator {color: rgb(104, 118, 135);}.ace-chrome .ace_comment {color: #236e24;}.ace-chrome .ace_comment.ace_doc {color: #236e24;}.ace-chrome .ace_comment.ace_doc.ace_tag {color: #236e24;}.ace-chrome .ace_constant.ace_numeric {color: rgb(0, 0, 205);}.ace-chrome .ace_variable {color: rgb(49, 132, 149);}.ace-chrome .ace_xml-pe {color: rgb(104, 104, 91);}.ace-chrome .ace_entity.ace_name.ace_function {color: #0000A2;}.ace-chrome .ace_heading {color: rgb(12, 7, 255);}.ace-chrome .ace_list {color:rgb(185, 6, 144);}.ace-chrome .ace_marker-layer .ace_selection {background: rgb(181, 213, 255);}.ace-chrome .ace_marker-layer .ace_step {background: rgb(252, 255, 0);}.ace-chrome .ace_marker-layer .ace_stack {background: rgb(164, 229, 101);}.ace-chrome .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid rgb(192, 192, 192);}.ace-chrome .ace_marker-layer .ace_active-line {background: rgba(0, 0, 0, 0.07);}.ace-chrome .ace_gutter-active-line {background-color : #dcdcdc;}.ace-chrome .ace_marker-layer .ace_selected-word {background: rgb(250, 250, 255);border: 1px solid rgb(200, 200, 250);}.ace-chrome .ace_storage,.ace-chrome .ace_keyword,.ace-chrome .ace_meta.ace_tag {color: rgb(147, 15, 128);}.ace-chrome .ace_string.ace_regex {color: rgb(255, 0, 0)}.ace-chrome .ace_string {color: #1A1AA6;}.ace-chrome .ace_entity.ace_other.ace_attribute-name {color: #994409;}.ace-chrome .ace_indent-guide {background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==\") right repeat-y;}';var r=e(\"../lib/dom\");r.importCssString(t.cssText,t.cssClass)})},b378:function(e,t){ace.define(\"ace/snippets\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/lib/event_emitter\",\"ace/lib/lang\",\"ace/range\",\"ace/anchor\",\"ace/keyboard/hash_handler\",\"ace/tokenizer\",\"ace/lib/dom\",\"ace/editor\"],function(e,t,n){\"use strict\";var r=e(\"./lib/oop\"),i=e(\"./lib/event_emitter\").EventEmitter,o=e(\"./lib/lang\"),a=e(\"./range\").Range,s=e(\"./anchor\").Anchor,l=e(\"./keyboard/hash_handler\").HashHandler,c=e(\"./tokenizer\").Tokenizer,u=a.comparePoints,d=function(){this.snippetMap={},this.snippetNameMap={}};(function(){r.implement(this,i),this.getTokenizer=function(){function e(e,t,n){return e=e.substr(1),/^\\d+$/.test(e)&&!n.inFormatString?[{tabstopId:parseInt(e,10)}]:[{text:e}]}function t(e){return\"(?:[^\\\\\\\\\"+e+\"]|\\\\\\\\.)\"}return d.$tokenizer=new c({start:[{regex:/:/,onMatch:function(e,t,n){return n.length&&n[0].expectIf?(n[0].expectIf=!1,n[0].elseBranch=n[0],[n[0]]):\":\"}},{regex:/\\\\./,onMatch:function(e,t,n){var r=e[1];return\"}\"==r&&n.length?e=r:-1!=\"`$\\\\\".indexOf(r)?e=r:n.inFormatString&&(\"n\"==r?e=\"\\n\":\"t\"==r?e=\"\\n\":-1!=\"ulULE\".indexOf(r)&&(e={changeCase:r,local:r>\"a\"})),[e]}},{regex:/}/,onMatch:function(e,t,n){return[n.length?n.shift():e]}},{regex:/\\$(?:\\d+|\\w+)/,onMatch:e},{regex:/\\$\\{[\\dA-Z_a-z]+/,onMatch:function(t,n,r){var i=e(t.substr(1),n,r);return r.unshift(i[0]),i},next:\"snippetVar\"},{regex:/\\n/,token:\"newline\",merge:!1}],snippetVar:[{regex:\"\\\\|\"+t(\"\\\\|\")+\"*\\\\|\",onMatch:function(e,t,n){n[0].choices=e.slice(1,-1).split(\",\")},next:\"start\"},{regex:\"/(\"+t(\"/\")+\"+)/(?:(\"+t(\"/\")+\"*)/)(\\\\w*):?\",onMatch:function(e,t,n){var r=n[0];return r.fmtString=e,e=this.splitRegex.exec(e),r.guard=e[1],r.fmt=e[2],r.flag=e[3],\"\"},next:\"start\"},{regex:\"`\"+t(\"`\")+\"*`\",onMatch:function(e,t,n){return n[0].code=e.splice(1,-1),\"\"},next:\"start\"},{regex:\"\\\\?\",onMatch:function(e,t,n){n[0]&&(n[0].expectIf=!0)},next:\"start\"},{regex:\"([^:}\\\\\\\\]|\\\\\\\\.)*:?\",token:\"\",next:\"start\"}],formatString:[{regex:\"/(\"+t(\"/\")+\"+)/\",token:\"regex\"},{regex:\"\",onMatch:function(e,t,n){n.inFormatString=!0},next:\"start\"}]}),d.prototype.getTokenizer=function(){return d.$tokenizer},d.$tokenizer},this.tokenizeTmSnippet=function(e,t){return this.getTokenizer().getLineTokens(e,t).tokens.map(function(e){return e.value||e})},this.$getDefaultValue=function(e,t){if(/^[A-Z]\\d+$/.test(t)){var n=t.substr(1);return(this.variables[t[0]+\"__\"]||{})[n]}if(/^\\d+$/.test(t))return(this.variables.__||{})[t];if(t=t.replace(/^TM_/,\"\"),e){var r=e.session;switch(t){case\"CURRENT_WORD\":var i=r.getWordRange();case\"SELECTION\":case\"SELECTED_TEXT\":return r.getTextRange(i);case\"CURRENT_LINE\":return r.getLine(e.getCursorPosition().row);case\"PREV_LINE\":return r.getLine(e.getCursorPosition().row-1);case\"LINE_INDEX\":return e.getCursorPosition().column;case\"LINE_NUMBER\":return e.getCursorPosition().row+1;case\"SOFT_TABS\":return r.getUseSoftTabs()?\"YES\":\"NO\";case\"TAB_SIZE\":return r.getTabSize();case\"FILENAME\":case\"FILEPATH\":return\"\";case\"FULLNAME\":return\"Ace\"}}},this.variables={},this.getVariableValue=function(e,t){return this.variables.hasOwnProperty(t)?this.variables[t](e,t)||\"\":this.$getDefaultValue(e,t)||\"\"},this.tmStrFormat=function(e,t,n){var r=t.flag||\"\",i=t.guard;i=new RegExp(i,r.replace(/[^gi]/,\"\"));var o=this.tokenizeTmSnippet(t.fmt,\"formatString\"),a=this,s=e.replace(i,function(){a.variables.__=arguments;for(var e=a.resolveVariables(o,n),t=\"E\",r=0;r<e.length;r++){var i=e[r];if(\"object\"==typeof i)if(e[r]=\"\",i.changeCase&&i.local){var s=e[r+1];s&&\"string\"==typeof s&&(\"u\"==i.changeCase?e[r]=s[0].toUpperCase():e[r]=s[0].toLowerCase(),e[r+1]=s.substr(1))}else i.changeCase&&(t=i.changeCase);else\"U\"==t?e[r]=i.toUpperCase():\"L\"==t&&(e[r]=i.toLowerCase())}return e.join(\"\")});return this.variables.__=null,s},this.resolveVariables=function(e,t){for(var n=[],r=0;r<e.length;r++){var i=e[r];if(\"string\"==typeof i)n.push(i);else{if(\"object\"!=typeof i)continue;if(i.skip)a(i);else{if(i.processed<r)continue;if(i.text){var o=this.getVariableValue(t,i.text);o&&i.fmtString&&(o=this.tmStrFormat(o,i)),i.processed=r,null==i.expectIf?o&&(n.push(o),a(i)):o?i.skip=i.elseBranch:a(i)}else null!=i.tabstopId?n.push(i):null!=i.changeCase&&n.push(i)}}}function a(t){var n=e.indexOf(t,r+1);-1!=n&&(r=n)}return n},this.insertSnippetForSelection=function(e,t){var n=e.getCursorPosition(),r=e.session.getLine(n.row),i=e.session.getTabString(),o=r.match(/^\\s*/)[0];n.column<o.length&&(o=o.slice(0,n.column)),t=t.replace(/\\r/g,\"\");var a=this.tokenizeTmSnippet(t);a=this.resolveVariables(a,e),a=a.map(function(e){return\"\\n\"==e?e+o:\"string\"==typeof e?e.replace(/\\t/g,i):e});var s=[];a.forEach(function(e,t){if(\"object\"==typeof e){var n=e.tabstopId,r=s[n];if(r||(r=s[n]=[],r.index=n,r.value=\"\"),-1===r.indexOf(e)){r.push(e);var i=a.indexOf(e,t+1);if(-1!==i){var o=a.slice(t+1,i),l=o.some(function(e){return\"object\"===typeof e});l&&!r.value?r.value=o:!o.length||r.value&&\"string\"===typeof r.value||(r.value=o.join(\"\"))}}}}),s.forEach(function(e){e.length=0});var l={};function c(e){for(var t=[],n=0;n<e.length;n++){var r=e[n];if(\"object\"==typeof r){if(l[r.tabstopId])continue;var i=e.lastIndexOf(r,n-1);r=t[i]||{tabstopId:r.tabstopId}}t[n]=r}return t}for(var u=0;u<a.length;u++){var d=a[u];if(\"object\"==typeof d){var p=d.tabstopId,m=a.indexOf(d,u+1);if(l[p])l[p]===d&&(l[p]=null);else{var f=s[p],g=\"string\"==typeof f.value?[f.value]:c(f.value);g.unshift(u+1,Math.max(0,m-u)),g.push(d),l[p]=d,a.splice.apply(a,g),-1===f.indexOf(d)&&f.push(d)}}}var b=0,v=0,k=\"\";a.forEach(function(e){if(\"string\"===typeof e){var t=e.split(\"\\n\");t.length>1?(v=t[t.length-1].length,b+=t.length-1):v+=e.length,k+=e}else e.start?e.end={row:b,column:v}:e.start={row:b,column:v}});var y=e.getSelectionRange(),w=e.session.replace(y,k),x=new h(e),E=e.inVirtualSelectionMode&&e.selection.index;x.addTabstops(s,y.start,w,E)},this.insertSnippet=function(e,t){var n=this;if(e.inVirtualSelectionMode)return n.insertSnippetForSelection(e,t);e.forEachSelection(function(){n.insertSnippetForSelection(e,t)},null,{keepOrder:!0}),e.tabstopManager&&e.tabstopManager.tabNext()},this.$getScope=function(e){var t=e.session.$mode.$id||\"\";if(t=t.split(\"/\").pop(),\"html\"===t||\"php\"===t){\"php\"!==t||e.session.$mode.inlinePhp||(t=\"html\");var n=e.getCursorPosition(),r=e.session.getState(n.row);\"object\"===typeof r&&(r=r[0]),r.substring&&(\"js-\"==r.substring(0,3)?t=\"javascript\":\"css-\"==r.substring(0,4)?t=\"css\":\"php-\"==r.substring(0,4)&&(t=\"php\"))}return t},this.getActiveScopes=function(e){var t=this.$getScope(e),n=[t],r=this.snippetMap;return r[t]&&r[t].includeScopes&&n.push.apply(n,r[t].includeScopes),n.push(\"_\"),n},this.expandWithTab=function(e,t){var n=this,r=e.forEachSelection(function(){return n.expandSnippetForSelection(e,t)},null,{keepOrder:!0});return r&&e.tabstopManager&&e.tabstopManager.tabNext(),r},this.expandSnippetForSelection=function(e,t){var n,r=e.getCursorPosition(),i=e.session.getLine(r.row),o=i.substring(0,r.column),a=i.substr(r.column),s=this.snippetMap;return this.getActiveScopes(e).some(function(e){var t=s[e];return t&&(n=this.findMatchingSnippet(t,o,a)),!!n},this),!!n&&(!(!t||!t.dryRun)||(e.session.doc.removeInLine(r.row,r.column-n.replaceBefore.length,r.column+n.replaceAfter.length),this.variables.M__=n.matchBefore,this.variables.T__=n.matchAfter,this.insertSnippetForSelection(e,n.content),this.variables.M__=this.variables.T__=null,!0))},this.findMatchingSnippet=function(e,t,n){for(var r=e.length;r--;){var i=e[r];if((!i.startRe||i.startRe.test(t))&&((!i.endRe||i.endRe.test(n))&&(i.startRe||i.endRe)))return i.matchBefore=i.startRe?i.startRe.exec(t):[\"\"],i.matchAfter=i.endRe?i.endRe.exec(n):[\"\"],i.replaceBefore=i.triggerRe?i.triggerRe.exec(t)[0]:\"\",i.replaceAfter=i.endTriggerRe?i.endTriggerRe.exec(n)[0]:\"\",i}},this.snippetMap={},this.snippetNameMap={},this.register=function(e,t){var n=this.snippetMap,r=this.snippetNameMap,i=this;function a(e){return e&&!/^\\^?\\(.*\\)\\$?$|^\\\\b$/.test(e)&&(e=\"(?:\"+e+\")\"),e||\"\"}function s(e,t,n){return e=a(e),t=a(t),n?(e=t+e,e&&\"$\"!=e[e.length-1]&&(e+=\"$\")):(e+=t,e&&\"^\"!=e[0]&&(e=\"^\"+e)),new RegExp(e)}function l(e){e.scope||(e.scope=t||\"_\"),t=e.scope,n[t]||(n[t]=[],r[t]={});var a=r[t];if(e.name){var l=a[e.name];l&&i.unregister(l),a[e.name]=e}n[t].push(e),e.tabTrigger&&!e.trigger&&(!e.guard&&/^\\w/.test(e.tabTrigger)&&(e.guard=\"\\\\b\"),e.trigger=o.escapeRegExp(e.tabTrigger)),(e.trigger||e.guard||e.endTrigger||e.endGuard)&&(e.startRe=s(e.trigger,e.guard,!0),e.triggerRe=new RegExp(e.trigger,\"\",!0),e.endRe=s(e.endTrigger,e.endGuard,!0),e.endTriggerRe=new RegExp(e.endTrigger,\"\",!0))}e||(e=[]),e&&e.content?l(e):Array.isArray(e)&&e.forEach(l),this._signal(\"registerSnippets\",{scope:t})},this.unregister=function(e,t){var n=this.snippetMap,r=this.snippetNameMap;function i(e){var i=r[e.scope||t];if(i&&i[e.name]){delete i[e.name];var o=n[e.scope||t],a=o&&o.indexOf(e);a>=0&&o.splice(a,1)}}e.content?i(e):Array.isArray(e)&&e.forEach(i)},this.parseSnippetFile=function(e){e=e.replace(/\\r/g,\"\");var t,n=[],r={},i=/^#.*|^({[\\s\\S]*})\\s*$|^(\\S+) (.*)$|^((?:\\n*\\t.*)+)/gm;while(t=i.exec(e)){if(t[1])try{r=JSON.parse(t[1]),n.push(r)}catch(l){}if(t[4])r.content=t[4].replace(/^\\t/gm,\"\"),n.push(r),r={};else{var o=t[2],a=t[3];if(\"regex\"==o){var s=/\\/((?:[^\\/\\\\]|\\\\.)*)|$/g;r.guard=s.exec(a)[1],r.trigger=s.exec(a)[1],r.endTrigger=s.exec(a)[1],r.endGuard=s.exec(a)[1]}else\"snippet\"==o?(r.tabTrigger=a.match(/^\\S*/)[0],r.name||(r.name=a)):r[o]=a}}return n},this.getSnippetByName=function(e,t){var n,r=this.snippetNameMap;return this.getActiveScopes(t).some(function(t){var i=r[t];return i&&(n=i[e]),!!n},this),n}}).call(d.prototype);var h=function(e){if(e.tabstopManager)return e.tabstopManager;e.tabstopManager=this,this.$onChange=this.onChange.bind(this),this.$onChangeSelection=o.delayedCall(this.onChangeSelection.bind(this)).schedule,this.$onChangeSession=this.onChangeSession.bind(this),this.$onAfterExec=this.onAfterExec.bind(this),this.attach(e)};(function(){this.attach=function(e){this.index=0,this.ranges=[],this.tabstops=[],this.$openTabstops=null,this.selectedTabstop=null,this.editor=e,this.editor.on(\"change\",this.$onChange),this.editor.on(\"changeSelection\",this.$onChangeSelection),this.editor.on(\"changeSession\",this.$onChangeSession),this.editor.commands.on(\"afterExec\",this.$onAfterExec),this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler)},this.detach=function(){this.tabstops.forEach(this.removeTabstopMarkers,this),this.ranges=null,this.tabstops=null,this.selectedTabstop=null,this.editor.removeListener(\"change\",this.$onChange),this.editor.removeListener(\"changeSelection\",this.$onChangeSelection),this.editor.removeListener(\"changeSession\",this.$onChangeSession),this.editor.commands.removeListener(\"afterExec\",this.$onAfterExec),this.editor.keyBinding.removeKeyboardHandler(this.keyboardHandler),this.editor.tabstopManager=null,this.editor=null},this.onChange=function(e){var t=\"r\"==e.action[0],n=e.start,r=e.end,i=n.row,o=r.row,a=o-i,s=r.column-n.column;if(t&&(a=-a,s=-s),!this.$inChange&&t){var l=this.selectedTabstop,c=l&&!l.some(function(e){return u(e.start,n)<=0&&u(e.end,r)>=0});if(c)return this.detach()}for(var d=this.ranges,h=0;h<d.length;h++){var p=d[h];p.end.row<n.row||(t&&u(n,p.start)<0&&u(r,p.end)>0?(this.removeRange(p),h--):(p.start.row==i&&p.start.column>n.column&&(p.start.column+=s),p.end.row==i&&p.end.column>=n.column&&(p.end.column+=s),p.start.row>=i&&(p.start.row+=a),p.end.row>=i&&(p.end.row+=a),u(p.start,p.end)>0&&this.removeRange(p)))}d.length||this.detach()},this.updateLinkedFields=function(){var e=this.selectedTabstop;if(e&&e.hasLinkedRanges){this.$inChange=!0;for(var n=this.editor.session,r=n.getTextRange(e.firstNonLinked),i=e.length;i--;){var o=e[i];if(o.linked){var a=t.snippetManager.tmStrFormat(r,o.original);n.replace(o,a)}}this.$inChange=!1}},this.onAfterExec=function(e){e.command&&!e.command.readOnly&&this.updateLinkedFields()},this.onChangeSelection=function(){if(this.editor){for(var e=this.editor.selection.lead,t=this.editor.selection.anchor,n=this.editor.selection.isEmpty(),r=this.ranges.length;r--;)if(!this.ranges[r].linked){var i=this.ranges[r].contains(e.row,e.column),o=n||this.ranges[r].contains(t.row,t.column);if(i&&o)return}this.detach()}},this.onChangeSession=function(){this.detach()},this.tabNext=function(e){var t=this.tabstops.length,n=this.index+(e||1);n=Math.min(Math.max(n,1),t),n==t&&(n=0),this.selectTabstop(n),0===n&&this.detach()},this.selectTabstop=function(e){this.$openTabstops=null;var t=this.tabstops[this.index];if(t&&this.addTabstopMarkers(t),this.index=e,t=this.tabstops[this.index],t&&t.length){if(this.selectedTabstop=t,this.editor.inVirtualSelectionMode)this.editor.selection.setRange(t.firstNonLinked);else{var n=this.editor.multiSelect;n.toSingleRange(t.firstNonLinked.clone());for(var r=t.length;r--;)t.hasLinkedRanges&&t[r].linked||n.addRange(t[r].clone(),!0);n.ranges[0]&&n.addRange(n.ranges[0].clone())}this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler)}},this.addTabstops=function(e,t,n){if(this.$openTabstops||(this.$openTabstops=[]),!e[0]){var r=a.fromPoints(n,n);f(r.start,t),f(r.end,t),e[0]=[r],e[0].index=0}var i=this.index,o=[i+1,0],s=this.ranges;e.forEach(function(e,n){for(var r=this.$openTabstops[n]||e,i=e.length;i--;){var l=e[i],c=a.fromPoints(l.start,l.end||l.start);m(c.start,t),m(c.end,t),c.original=l,c.tabstop=r,s.push(c),r!=e?r.unshift(c):r[i]=c,l.fmtString?(c.linked=!0,r.hasLinkedRanges=!0):r.firstNonLinked||(r.firstNonLinked=c)}r.firstNonLinked||(r.hasLinkedRanges=!1),r===e&&(o.push(r),this.$openTabstops[n]=r),this.addTabstopMarkers(r)},this),o.length>2&&(this.tabstops.length&&o.push(o.splice(2,1)[0]),this.tabstops.splice.apply(this.tabstops,o))},this.addTabstopMarkers=function(e){var t=this.editor.session;e.forEach(function(e){e.markerId||(e.markerId=t.addMarker(e,\"ace_snippet-marker\",\"text\"))})},this.removeTabstopMarkers=function(e){var t=this.editor.session;e.forEach(function(e){t.removeMarker(e.markerId),e.markerId=null})},this.removeRange=function(e){var t=e.tabstop.indexOf(e);e.tabstop.splice(t,1),t=this.ranges.indexOf(e),this.ranges.splice(t,1),this.editor.session.removeMarker(e.markerId),e.tabstop.length||(t=this.tabstops.indexOf(e.tabstop),-1!=t&&this.tabstops.splice(t,1),this.tabstops.length||this.detach())},this.keyboardHandler=new l,this.keyboardHandler.bindKeys({Tab:function(e){t.snippetManager&&t.snippetManager.expandWithTab(e)||e.tabstopManager.tabNext(1)},\"Shift-Tab\":function(e){e.tabstopManager.tabNext(-1)},Esc:function(e){e.tabstopManager.detach()},Return:function(e){return!1}})}).call(h.prototype);var p={};p.onChange=s.prototype.onChange,p.setPosition=function(e,t){this.pos.row=e,this.pos.column=t},p.update=function(e,t,n){this.$insertRight=n,this.pos=e,this.onChange(t)};var m=function(e,t){0==e.row&&(e.column+=t.column),e.row+=t.row},f=function(e,t){e.row==t.row&&(e.column-=t.column),e.row-=t.row};e(\"./lib/dom\").importCssString(\".ace_snippet-marker {    -moz-box-sizing: border-box;    box-sizing: border-box;    background: rgba(194, 193, 208, 0.09);    border: 1px dotted rgba(211, 208, 235, 0.62);    position: absolute;}\"),t.snippetManager=new d;var g=e(\"./editor\").Editor;(function(){this.insertSnippet=function(e,n){return t.snippetManager.insertSnippet(this,e,n)},this.expandSnippet=function(e){return t.snippetManager.expandWithTab(this,e)}}).call(g.prototype)}),ace.define(\"ace/ext/emmet\",[\"require\",\"exports\",\"module\",\"ace/keyboard/hash_handler\",\"ace/editor\",\"ace/snippets\",\"ace/range\",\"resources\",\"resources\",\"tabStops\",\"resources\",\"utils\",\"actions\",\"ace/config\",\"ace/config\"],function(e,t,n){\"use strict\";var r,i,o=e(\"ace/keyboard/hash_handler\").HashHandler,a=e(\"ace/editor\").Editor,s=e(\"ace/snippets\").snippetManager,l=e(\"ace/range\").Range;function c(){}c.prototype={setupContext:function(e){this.ace=e,this.indentation=e.session.getTabString(),r||(r=window.emmet);var t=r.resources||r.require(\"resources\");t.setVariable(\"indentation\",this.indentation),this.$syntax=null,this.$syntax=this.getSyntax()},getSelectionRange:function(){var e=this.ace.getSelectionRange(),t=this.ace.session.doc;return{start:t.positionToIndex(e.start),end:t.positionToIndex(e.end)}},createSelection:function(e,t){var n=this.ace.session.doc;this.ace.selection.setRange({start:n.indexToPosition(e),end:n.indexToPosition(t)})},getCurrentLineRange:function(){var e=this.ace,t=e.getCursorPosition().row,n=e.session.getLine(t).length,r=e.session.doc.positionToIndex({row:t,column:0});return{start:r,end:r+n}},getCaretPos:function(){var e=this.ace.getCursorPosition();return this.ace.session.doc.positionToIndex(e)},setCaretPos:function(e){var t=this.ace.session.doc.indexToPosition(e);this.ace.selection.moveToPosition(t)},getCurrentLine:function(){var e=this.ace.getCursorPosition().row;return this.ace.session.getLine(e)},replaceContent:function(e,t,n,r){null==n&&(n=null==t?this.getContent().length:t),null==t&&(t=0);var i=this.ace,o=i.session.doc,a=l.fromPoints(o.indexToPosition(t),o.indexToPosition(n));i.session.remove(a),a.end=a.start,e=this.$updateTabstops(e),s.insertSnippet(i,e)},getContent:function(){return this.ace.getValue()},getSyntax:function(){if(this.$syntax)return this.$syntax;var e=this.ace.session.$modeId.split(\"/\").pop();if(\"html\"==e||\"php\"==e){var t=this.ace.getCursorPosition(),n=this.ace.session.getState(t.row);\"string\"!=typeof n&&(n=n[0]),n&&(n=n.split(\"-\"),n.length>1?e=n[0]:\"php\"==e&&(e=\"html\"))}return e},getProfileName:function(){var e=r.resources||r.require(\"resources\");switch(this.getSyntax()){case\"css\":return\"css\";case\"xml\":case\"xsl\":return\"xml\";case\"html\":var t=e.getVariable(\"profile\");return t||(t=-1!=this.ace.session.getLines(0,2).join(\"\").search(/<!DOCTYPE[^>]+XHTML/i)?\"xhtml\":\"html\"),t;default:var n=this.ace.session.$mode;return n.emmetConfig&&n.emmetConfig.profile||\"xhtml\"}},prompt:function(e){return prompt(e)},getSelection:function(){return this.ace.session.getTextRange()},getFilePath:function(){return\"\"},$updateTabstops:function(e){var t=1e3,n=0,i=null,o=r.tabStops||r.require(\"tabStops\"),a=r.resources||r.require(\"resources\"),s=a.getVocabulary(\"user\"),l={tabstop:function(e){var r=parseInt(e.group,10),a=0===r;a?r=++n:r+=t;var s=e.placeholder;s&&(s=o.processText(s,l));var c=\"${\"+r+(s?\":\"+s:\"\")+\"}\";return a&&(i=[e.start,c]),c},escape:function(e){return\"$\"==e?\"\\\\$\":\"\\\\\"==e?\"\\\\\\\\\":e}};if(e=o.processText(e,l),s.variables[\"insert_final_tabstop\"]&&!/\\$\\{0\\}$/.test(e))e+=\"${0}\";else if(i){var c=r.utils?r.utils.common:r.require(\"utils\");e=c.replaceSubstring(e,\"${0}\",i[0],i[1])}return e}};var u={expand_abbreviation:{mac:\"ctrl+alt+e\",win:\"alt+e\"},match_pair_outward:{mac:\"ctrl+d\",win:\"ctrl+,\"},match_pair_inward:{mac:\"ctrl+j\",win:\"ctrl+shift+0\"},matching_pair:{mac:\"ctrl+alt+j\",win:\"alt+j\"},next_edit_point:\"alt+right\",prev_edit_point:\"alt+left\",toggle_comment:{mac:\"command+/\",win:\"ctrl+/\"},split_join_tag:{mac:\"shift+command+'\",win:\"shift+ctrl+`\"},remove_tag:{mac:\"command+'\",win:\"shift+ctrl+;\"},evaluate_math_expression:{mac:\"shift+command+y\",win:\"shift+ctrl+y\"},increment_number_by_1:\"ctrl+up\",decrement_number_by_1:\"ctrl+down\",increment_number_by_01:\"alt+up\",decrement_number_by_01:\"alt+down\",increment_number_by_10:{mac:\"alt+command+up\",win:\"shift+alt+up\"},decrement_number_by_10:{mac:\"alt+command+down\",win:\"shift+alt+down\"},select_next_item:{mac:\"shift+command+.\",win:\"shift+ctrl+.\"},select_previous_item:{mac:\"shift+command+,\",win:\"shift+ctrl+,\"},reflect_css_value:{mac:\"shift+command+r\",win:\"shift+ctrl+r\"},encode_decode_data_url:{mac:\"shift+ctrl+d\",win:\"ctrl+'\"},expand_abbreviation_with_tab:\"Tab\",wrap_with_abbreviation:{mac:\"shift+ctrl+a\",win:\"shift+ctrl+a\"}},d=new c;for(var h in t.commands=new o,t.runEmmetCommand=function e(t){try{d.setupContext(t);var n=r.actions||r.require(\"actions\");if(\"expand_abbreviation_with_tab\"==this.action){if(!t.selection.isEmpty())return!1;var i=t.selection.lead,o=t.session.getTokenAt(i.row,i.column);if(o&&/\\btag\\b/.test(o.type))return!1}if(\"wrap_with_abbreviation\"==this.action)return setTimeout(function(){n.run(\"wrap_with_abbreviation\",d)},0);var a=n.run(this.action,d)}catch(s){if(!r)return m(e.bind(this,t)),!0;t._signal(\"changeStatus\",\"string\"==typeof s?s:s.message),console.log(s),a=!1}return a},u)t.commands.addCommand({name:\"emmet:\"+h,action:h,bindKey:u[h],exec:t.runEmmetCommand,multiSelectAction:\"forEach\"});t.updateCommands=function(e,n){n?e.keyBinding.addKeyboardHandler(t.commands):e.keyBinding.removeKeyboardHandler(t.commands)},t.isSupportedMode=function(e){if(!e)return!1;if(e.emmetConfig)return!0;var t=e.$id||e;return/css|less|scss|sass|stylus|html|php|twig|ejs|handlebars/.test(t)},t.isAvailable=function(e,n){if(/(evaluate_math_expression|expand_abbreviation)$/.test(n))return!0;var r=e.session.$mode,i=t.isSupportedMode(r);if(i&&r.$modes)try{d.setupContext(e),/js|php/.test(d.getSyntax())&&(i=!1)}catch(o){}return i};var p=function(e,n){var r=n;if(r){var i=t.isSupportedMode(r.session.$mode);!1===e.enableEmmet&&(i=!1),i&&m(),t.updateCommands(r,i)}},m=function(t){\"string\"==typeof i&&e(\"ace/config\").loadModule(i,function(){i=null,t&&t()})};t.AceEmmetEditor=c,e(\"ace/config\").defineOptions(a.prototype,\"editor\",{enableEmmet:{set:function(e){this[e?\"on\":\"removeListener\"](\"changeMode\",p),p({enableEmmet:!!e},this)},value:!0}}),t.setCore=function(e){\"string\"==typeof e?i=e:r=e}}),function(){ace.acequire([\"ace/ext/emmet\"],function(){})}()},bb36:function(e,t,n){ace.define(\"ace/mode/doc_comment_highlight_rules\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/mode/text_highlight_rules\"],function(e,t,n){\"use strict\";var r=e(\"../lib/oop\"),i=e(\"./text_highlight_rules\").TextHighlightRules,o=function(){this.$rules={start:[{token:\"comment.doc.tag\",regex:\"@[\\\\w\\\\d_]+\"},o.getTagRule(),{defaultToken:\"comment.doc\",caseInsensitive:!0}]}};r.inherits(o,i),o.getTagRule=function(e){return{token:\"comment.doc.tag.storage.type\",regex:\"\\\\b(?:TODO|FIXME|XXX|HACK)\\\\b\"}},o.getStartRule=function(e){return{token:\"comment.doc\",regex:\"\\\\/\\\\*(?=\\\\*)\",next:e}},o.getEndRule=function(e){return{token:\"comment.doc\",regex:\"\\\\*\\\\/\",next:e}},t.DocCommentHighlightRules=o}),ace.define(\"ace/mode/javascript_highlight_rules\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/mode/doc_comment_highlight_rules\",\"ace/mode/text_highlight_rules\"],function(e,t,n){\"use strict\";var r=e(\"../lib/oop\"),i=e(\"./doc_comment_highlight_rules\").DocCommentHighlightRules,o=e(\"./text_highlight_rules\").TextHighlightRules,a=\"[a-zA-Z\\\\$_¡-￿][a-zA-Z\\\\d\\\\$_¡-￿]*\",s=function(e){var t=this.createKeywordMapper({\"variable.language\":\"Array|Boolean|Date|Function|Iterator|Number|Object|RegExp|String|Proxy|Namespace|QName|XML|XMLList|ArrayBuffer|Float32Array|Float64Array|Int16Array|Int32Array|Int8Array|Uint16Array|Uint32Array|Uint8Array|Uint8ClampedArray|Error|EvalError|InternalError|RangeError|ReferenceError|StopIteration|SyntaxError|TypeError|URIError|decodeURI|decodeURIComponent|encodeURI|encodeURIComponent|eval|isFinite|isNaN|parseFloat|parseInt|JSON|Math|this|arguments|prototype|window|document\",keyword:\"const|yield|import|get|set|async|await|break|case|catch|continue|default|delete|do|else|finally|for|function|if|in|of|instanceof|new|return|switch|throw|try|typeof|let|var|while|with|debugger|__parent__|__count__|escape|unescape|with|__proto__|class|enum|extends|super|export|implements|private|public|interface|package|protected|static\",\"storage.type\":\"const|let|var|function\",\"constant.language\":\"null|Infinity|NaN|undefined\",\"support.function\":\"alert\",\"constant.language.boolean\":\"true|false\"},\"identifier\"),n=\"case|do|else|finally|in|instanceof|return|throw|try|typeof|yield|void\",r=\"\\\\\\\\(?:x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|u{[0-9a-fA-F]{1,6}}|[0-2][0-7]{0,2}|3[0-7][0-7]?|[4-7][0-7]?|.)\";this.$rules={no_regex:[i.getStartRule(\"doc-start\"),c(\"no_regex\"),{token:\"string\",regex:\"'(?=.)\",next:\"qstring\"},{token:\"string\",regex:'\"(?=.)',next:\"qqstring\"},{token:\"constant.numeric\",regex:/0(?:[xX][0-9a-fA-F]+|[oO][0-7]+|[bB][01]+)\\b/},{token:\"constant.numeric\",regex:/(?:\\d\\d*(?:\\.\\d*)?|\\.\\d+)(?:[eE][+-]?\\d+\\b)?/},{token:[\"storage.type\",\"punctuation.operator\",\"support.function\",\"punctuation.operator\",\"entity.name.function\",\"text\",\"keyword.operator\"],regex:\"(\"+a+\")(\\\\.)(prototype)(\\\\.)(\"+a+\")(\\\\s*)(=)\",next:\"function_arguments\"},{token:[\"storage.type\",\"punctuation.operator\",\"entity.name.function\",\"text\",\"keyword.operator\",\"text\",\"storage.type\",\"text\",\"paren.lparen\"],regex:\"(\"+a+\")(\\\\.)(\"+a+\")(\\\\s*)(=)(\\\\s*)(function)(\\\\s*)(\\\\()\",next:\"function_arguments\"},{token:[\"entity.name.function\",\"text\",\"keyword.operator\",\"text\",\"storage.type\",\"text\",\"paren.lparen\"],regex:\"(\"+a+\")(\\\\s*)(=)(\\\\s*)(function)(\\\\s*)(\\\\()\",next:\"function_arguments\"},{token:[\"storage.type\",\"punctuation.operator\",\"entity.name.function\",\"text\",\"keyword.operator\",\"text\",\"storage.type\",\"text\",\"entity.name.function\",\"text\",\"paren.lparen\"],regex:\"(\"+a+\")(\\\\.)(\"+a+\")(\\\\s*)(=)(\\\\s*)(function)(\\\\s+)(\\\\w+)(\\\\s*)(\\\\()\",next:\"function_arguments\"},{token:[\"storage.type\",\"text\",\"entity.name.function\",\"text\",\"paren.lparen\"],regex:\"(function)(\\\\s+)(\"+a+\")(\\\\s*)(\\\\()\",next:\"function_arguments\"},{token:[\"entity.name.function\",\"text\",\"punctuation.operator\",\"text\",\"storage.type\",\"text\",\"paren.lparen\"],regex:\"(\"+a+\")(\\\\s*)(:)(\\\\s*)(function)(\\\\s*)(\\\\()\",next:\"function_arguments\"},{token:[\"text\",\"text\",\"storage.type\",\"text\",\"paren.lparen\"],regex:\"(:)(\\\\s*)(function)(\\\\s*)(\\\\()\",next:\"function_arguments\"},{token:\"keyword\",regex:\"from(?=\\\\s*('|\\\"))\"},{token:\"keyword\",regex:\"(?:\"+n+\")\\\\b\",next:\"start\"},{token:[\"support.constant\"],regex:/that\\b/},{token:[\"storage.type\",\"punctuation.operator\",\"support.function.firebug\"],regex:/(console)(\\.)(warn|info|log|error|time|trace|timeEnd|assert)\\b/},{token:t,regex:a},{token:\"punctuation.operator\",regex:/[.](?![.])/,next:\"property\"},{token:\"storage.type\",regex:/=>/},{token:\"keyword.operator\",regex:/--|\\+\\+|\\.{3}|===|==|=|!=|!==|<+=?|>+=?|!|&&|\\|\\||\\?:|[!$%&*+\\-~\\/^]=?/,next:\"start\"},{token:\"punctuation.operator\",regex:/[?:,;.]/,next:\"start\"},{token:\"paren.lparen\",regex:/[\\[({]/,next:\"start\"},{token:\"paren.rparen\",regex:/[\\])}]/},{token:\"comment\",regex:/^#!.*$/}],property:[{token:\"text\",regex:\"\\\\s+\"},{token:[\"storage.type\",\"punctuation.operator\",\"entity.name.function\",\"text\",\"keyword.operator\",\"text\",\"storage.type\",\"text\",\"entity.name.function\",\"text\",\"paren.lparen\"],regex:\"(\"+a+\")(\\\\.)(\"+a+\")(\\\\s*)(=)(\\\\s*)(function)(?:(\\\\s+)(\\\\w+))?(\\\\s*)(\\\\()\",next:\"function_arguments\"},{token:\"punctuation.operator\",regex:/[.](?![.])/},{token:\"support.function\",regex:/(s(?:h(?:ift|ow(?:Mod(?:elessDialog|alDialog)|Help))|croll(?:X|By(?:Pages|Lines)?|Y|To)?|t(?:op|rike)|i(?:n|zeToContent|debar|gnText)|ort|u(?:p|b(?:str(?:ing)?)?)|pli(?:ce|t)|e(?:nd|t(?:Re(?:sizable|questHeader)|M(?:i(?:nutes|lliseconds)|onth)|Seconds|Ho(?:tKeys|urs)|Year|Cursor|Time(?:out)?|Interval|ZOptions|Date|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Date|FullYear)|FullYear|Active)|arch)|qrt|lice|avePreferences|mall)|h(?:ome|andleEvent)|navigate|c(?:har(?:CodeAt|At)|o(?:s|n(?:cat|textual|firm)|mpile)|eil|lear(?:Timeout|Interval)?|a(?:ptureEvents|ll)|reate(?:StyleSheet|Popup|EventObject))|t(?:o(?:GMTString|S(?:tring|ource)|U(?:TCString|pperCase)|Lo(?:caleString|werCase))|est|a(?:n|int(?:Enabled)?))|i(?:s(?:NaN|Finite)|ndexOf|talics)|d(?:isableExternalCapture|ump|etachEvent)|u(?:n(?:shift|taint|escape|watch)|pdateCommands)|j(?:oin|avaEnabled)|p(?:o(?:p|w)|ush|lugins.refresh|a(?:ddings|rse(?:Int|Float)?)|r(?:int|ompt|eference))|e(?:scape|nableExternalCapture|val|lementFromPoint|x(?:p|ec(?:Script|Command)?))|valueOf|UTC|queryCommand(?:State|Indeterm|Enabled|Value)|f(?:i(?:nd|le(?:ModifiedDate|Size|CreatedDate|UpdatedDate)|xed)|o(?:nt(?:size|color)|rward)|loor|romCharCode)|watch|l(?:ink|o(?:ad|g)|astIndexOf)|a(?:sin|nchor|cos|t(?:tachEvent|ob|an(?:2)?)|pply|lert|b(?:s|ort))|r(?:ou(?:nd|teEvents)|e(?:size(?:By|To)|calc|turnValue|place|verse|l(?:oad|ease(?:Capture|Events)))|andom)|g(?:o|et(?:ResponseHeader|M(?:i(?:nutes|lliseconds)|onth)|Se(?:conds|lection)|Hours|Year|Time(?:zoneOffset)?|Da(?:y|te)|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Da(?:y|te)|FullYear)|FullYear|A(?:ttention|llResponseHeaders)))|m(?:in|ove(?:B(?:y|elow)|To(?:Absolute)?|Above)|ergeAttributes|a(?:tch|rgins|x))|b(?:toa|ig|o(?:ld|rderWidths)|link|ack))\\b(?=\\()/},{token:\"support.function.dom\",regex:/(s(?:ub(?:stringData|mit)|plitText|e(?:t(?:NamedItem|Attribute(?:Node)?)|lect))|has(?:ChildNodes|Feature)|namedItem|c(?:l(?:ick|o(?:se|neNode))|reate(?:C(?:omment|DATASection|aption)|T(?:Head|extNode|Foot)|DocumentFragment|ProcessingInstruction|E(?:ntityReference|lement)|Attribute))|tabIndex|i(?:nsert(?:Row|Before|Cell|Data)|tem)|open|delete(?:Row|C(?:ell|aption)|T(?:Head|Foot)|Data)|focus|write(?:ln)?|a(?:dd|ppend(?:Child|Data))|re(?:set|place(?:Child|Data)|move(?:NamedItem|Child|Attribute(?:Node)?)?)|get(?:NamedItem|Element(?:sBy(?:Name|TagName|ClassName)|ById)|Attribute(?:Node)?)|blur)\\b(?=\\()/},{token:\"support.constant\",regex:/(s(?:ystemLanguage|cr(?:ipts|ollbars|een(?:X|Y|Top|Left))|t(?:yle(?:Sheets)?|atus(?:Text|bar)?)|ibling(?:Below|Above)|ource|uffixes|e(?:curity(?:Policy)?|l(?:ection|f)))|h(?:istory|ost(?:name)?|as(?:h|Focus))|y|X(?:MLDocument|SLDocument)|n(?:ext|ame(?:space(?:s|URI)|Prop))|M(?:IN_VALUE|AX_VALUE)|c(?:haracterSet|o(?:n(?:structor|trollers)|okieEnabled|lorDepth|mp(?:onents|lete))|urrent|puClass|l(?:i(?:p(?:boardData)?|entInformation)|osed|asses)|alle(?:e|r)|rypto)|t(?:o(?:olbar|p)|ext(?:Transform|Indent|Decoration|Align)|ags)|SQRT(?:1_2|2)|i(?:n(?:ner(?:Height|Width)|put)|ds|gnoreCase)|zIndex|o(?:scpu|n(?:readystatechange|Line)|uter(?:Height|Width)|p(?:sProfile|ener)|ffscreenBuffering)|NEGATIVE_INFINITY|d(?:i(?:splay|alog(?:Height|Top|Width|Left|Arguments)|rectories)|e(?:scription|fault(?:Status|Ch(?:ecked|arset)|View)))|u(?:ser(?:Profile|Language|Agent)|n(?:iqueID|defined)|pdateInterval)|_content|p(?:ixelDepth|ort|ersonalbar|kcs11|l(?:ugins|atform)|a(?:thname|dding(?:Right|Bottom|Top|Left)|rent(?:Window|Layer)?|ge(?:X(?:Offset)?|Y(?:Offset)?))|r(?:o(?:to(?:col|type)|duct(?:Sub)?|mpter)|e(?:vious|fix)))|e(?:n(?:coding|abledPlugin)|x(?:ternal|pando)|mbeds)|v(?:isibility|endor(?:Sub)?|Linkcolor)|URLUnencoded|P(?:I|OSITIVE_INFINITY)|f(?:ilename|o(?:nt(?:Size|Family|Weight)|rmName)|rame(?:s|Element)|gColor)|E|whiteSpace|l(?:i(?:stStyleType|n(?:eHeight|kColor))|o(?:ca(?:tion(?:bar)?|lName)|wsrc)|e(?:ngth|ft(?:Context)?)|a(?:st(?:M(?:odified|atch)|Index|Paren)|yer(?:s|X)|nguage))|a(?:pp(?:MinorVersion|Name|Co(?:deName|re)|Version)|vail(?:Height|Top|Width|Left)|ll|r(?:ity|guments)|Linkcolor|bove)|r(?:ight(?:Context)?|e(?:sponse(?:XML|Text)|adyState))|global|x|m(?:imeTypes|ultiline|enubar|argin(?:Right|Bottom|Top|Left))|L(?:N(?:10|2)|OG(?:10E|2E))|b(?:o(?:ttom|rder(?:Width|RightWidth|BottomWidth|Style|Color|TopWidth|LeftWidth))|ufferDepth|elow|ackground(?:Color|Image)))\\b/},{token:\"identifier\",regex:a},{regex:\"\",token:\"empty\",next:\"no_regex\"}],start:[i.getStartRule(\"doc-start\"),c(\"start\"),{token:\"string.regexp\",regex:\"\\\\/\",next:\"regex\"},{token:\"text\",regex:\"\\\\s+|^$\",next:\"start\"},{token:\"empty\",regex:\"\",next:\"no_regex\"}],regex:[{token:\"regexp.keyword.operator\",regex:\"\\\\\\\\(?:u[\\\\da-fA-F]{4}|x[\\\\da-fA-F]{2}|.)\"},{token:\"string.regexp\",regex:\"/[sxngimy]*\",next:\"no_regex\"},{token:\"invalid\",regex:/\\{\\d+\\b,?\\d*\\}[+*]|[+*$^?][+*]|[$^][?]|\\?{3,}/},{token:\"constant.language.escape\",regex:/\\(\\?[:=!]|\\)|\\{\\d+\\b,?\\d*\\}|[+*]\\?|[()$^+*?.]/},{token:\"constant.language.delimiter\",regex:/\\|/},{token:\"constant.language.escape\",regex:/\\[\\^?/,next:\"regex_character_class\"},{token:\"empty\",regex:\"$\",next:\"no_regex\"},{defaultToken:\"string.regexp\"}],regex_character_class:[{token:\"regexp.charclass.keyword.operator\",regex:\"\\\\\\\\(?:u[\\\\da-fA-F]{4}|x[\\\\da-fA-F]{2}|.)\"},{token:\"constant.language.escape\",regex:\"]\",next:\"regex\"},{token:\"constant.language.escape\",regex:\"-\"},{token:\"empty\",regex:\"$\",next:\"no_regex\"},{defaultToken:\"string.regexp.charachterclass\"}],function_arguments:[{token:\"variable.parameter\",regex:a},{token:\"punctuation.operator\",regex:\"[, ]+\"},{token:\"punctuation.operator\",regex:\"$\"},{token:\"empty\",regex:\"\",next:\"no_regex\"}],qqstring:[{token:\"constant.language.escape\",regex:r},{token:\"string\",regex:\"\\\\\\\\$\",consumeLineEnd:!0},{token:\"string\",regex:'\"|$',next:\"no_regex\"},{defaultToken:\"string\"}],qstring:[{token:\"constant.language.escape\",regex:r},{token:\"string\",regex:\"\\\\\\\\$\",consumeLineEnd:!0},{token:\"string\",regex:\"'|$\",next:\"no_regex\"},{defaultToken:\"string\"}]},e&&e.noES6||(this.$rules.no_regex.unshift({regex:\"[{}]\",onMatch:function(e,t,n){if(this.next=\"{\"==e?this.nextState:\"\",\"{\"==e&&n.length)n.unshift(\"start\",t);else if(\"}\"==e&&n.length&&(n.shift(),this.next=n.shift(),-1!=this.next.indexOf(\"string\")||-1!=this.next.indexOf(\"jsx\")))return\"paren.quasi.end\";return\"{\"==e?\"paren.lparen\":\"paren.rparen\"},nextState:\"start\"},{token:\"string.quasi.start\",regex:/`/,push:[{token:\"constant.language.escape\",regex:r},{token:\"paren.quasi.start\",regex:/\\${/,push:\"start\"},{token:\"string.quasi.end\",regex:/`/,next:\"pop\"},{defaultToken:\"string.quasi\"}]}),e&&0==e.jsx||l.call(this)),this.embedRules(i,\"doc-\",[i.getEndRule(\"no_regex\")]),this.normalizeRules()};function l(){var e=a.replace(\"\\\\d\",\"\\\\d\\\\-\"),t={onMatch:function(e,t,n){var r=\"/\"==e.charAt(1)?2:1;return 1==r?(t!=this.nextState?n.unshift(this.next,this.nextState,0):n.unshift(this.next),n[2]++):2==r&&t==this.nextState&&(n[1]--,(!n[1]||n[1]<0)&&(n.shift(),n.shift())),[{type:\"meta.tag.punctuation.\"+(1==r?\"\":\"end-\")+\"tag-open.xml\",value:e.slice(0,r)},{type:\"meta.tag.tag-name.xml\",value:e.substr(r)}]},regex:\"</?\"+e,next:\"jsxAttributes\",nextState:\"jsx\"};this.$rules.start.unshift(t);var n={regex:\"{\",token:\"paren.quasi.start\",push:\"start\"};this.$rules.jsx=[n,t,{include:\"reference\"},{defaultToken:\"string\"}],this.$rules.jsxAttributes=[{token:\"meta.tag.punctuation.tag-close.xml\",regex:\"/?>\",onMatch:function(e,t,n){return t==n[0]&&n.shift(),2==e.length&&(n[0]==this.nextState&&n[1]--,(!n[1]||n[1]<0)&&n.splice(0,2)),this.next=n[0]||\"start\",[{type:this.token,value:e}]},nextState:\"jsx\"},n,c(\"jsxAttributes\"),{token:\"entity.other.attribute-name.xml\",regex:e},{token:\"keyword.operator.attribute-equals.xml\",regex:\"=\"},{token:\"text.tag-whitespace.xml\",regex:\"\\\\s+\"},{token:\"string.attribute-value.xml\",regex:\"'\",stateName:\"jsx_attr_q\",push:[{token:\"string.attribute-value.xml\",regex:\"'\",next:\"pop\"},{include:\"reference\"},{defaultToken:\"string.attribute-value.xml\"}]},{token:\"string.attribute-value.xml\",regex:'\"',stateName:\"jsx_attr_qq\",push:[{token:\"string.attribute-value.xml\",regex:'\"',next:\"pop\"},{include:\"reference\"},{defaultToken:\"string.attribute-value.xml\"}]},t],this.$rules.reference=[{token:\"constant.language.escape.reference.xml\",regex:\"(?:&#[0-9]+;)|(?:&#x[0-9a-fA-F]+;)|(?:&[a-zA-Z0-9_:\\\\.-]+;)\"}]}function c(e){return[{token:\"comment\",regex:/\\/\\*/,next:[i.getTagRule(),{token:\"comment\",regex:\"\\\\*\\\\/\",next:e||\"pop\"},{defaultToken:\"comment\",caseInsensitive:!0}]},{token:\"comment\",regex:\"\\\\/\\\\/\",next:[i.getTagRule(),{token:\"comment\",regex:\"$|^\",next:e||\"pop\"},{defaultToken:\"comment\",caseInsensitive:!0}]}]}r.inherits(s,o),t.JavaScriptHighlightRules=s}),ace.define(\"ace/mode/matching_brace_outdent\",[\"require\",\"exports\",\"module\",\"ace/range\"],function(e,t,n){\"use strict\";var r=e(\"../range\").Range,i=function(){};(function(){this.checkOutdent=function(e,t){return!!/^\\s+$/.test(e)&&/^\\s*\\}/.test(t)},this.autoOutdent=function(e,t){var n=e.getLine(t),i=n.match(/^(\\s*\\})/);if(!i)return 0;var o=i[1].length,a=e.findMatchingBracket({row:t,column:o});if(!a||a.row==t)return 0;var s=this.$getIndent(e.getLine(a.row));e.replace(new r(t,0,t,o-1),s)},this.$getIndent=function(e){return e.match(/^\\s*/)[0]}}).call(i.prototype),t.MatchingBraceOutdent=i}),ace.define(\"ace/mode/folding/cstyle\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/range\",\"ace/mode/folding/fold_mode\"],function(e,t,n){\"use strict\";var r=e(\"../../lib/oop\"),i=e(\"../../range\").Range,o=e(\"./fold_mode\").FoldMode,a=t.FoldMode=function(e){e&&(this.foldingStartMarker=new RegExp(this.foldingStartMarker.source.replace(/\\|[^|]*?$/,\"|\"+e.start)),this.foldingStopMarker=new RegExp(this.foldingStopMarker.source.replace(/\\|[^|]*?$/,\"|\"+e.end)))};r.inherits(a,o),function(){this.foldingStartMarker=/([\\{\\[\\(])[^\\}\\]\\)]*$|^\\s*(\\/\\*)/,this.foldingStopMarker=/^[^\\[\\{\\(]*([\\}\\]\\)])|^[\\s\\*]*(\\*\\/)/,this.singleLineBlockCommentRe=/^\\s*(\\/\\*).*\\*\\/\\s*$/,this.tripleStarBlockCommentRe=/^\\s*(\\/\\*\\*\\*).*\\*\\/\\s*$/,this.startRegionRe=/^\\s*(\\/\\*|\\/\\/)#?region\\b/,this._getFoldWidgetBase=this.getFoldWidget,this.getFoldWidget=function(e,t,n){var r=e.getLine(n);if(this.singleLineBlockCommentRe.test(r)&&!this.startRegionRe.test(r)&&!this.tripleStarBlockCommentRe.test(r))return\"\";var i=this._getFoldWidgetBase(e,t,n);return!i&&this.startRegionRe.test(r)?\"start\":i},this.getFoldWidgetRange=function(e,t,n,r){var i=e.getLine(n);if(this.startRegionRe.test(i))return this.getCommentRegionBlock(e,i,n);var o=i.match(this.foldingStartMarker);if(o){var a=o.index;if(o[1])return this.openingBracketBlock(e,o[1],n,a);var s=e.getCommentFoldRange(n,a+o[0].length,1);return s&&!s.isMultiLine()&&(r?s=this.getSectionRange(e,n):\"all\"!=t&&(s=null)),s}if(\"markbegin\"!==t){o=i.match(this.foldingStopMarker);if(o){a=o.index+o[0].length;return o[1]?this.closingBracketBlock(e,o[1],n,a):e.getCommentFoldRange(n,a,-1)}}},this.getSectionRange=function(e,t){var n=e.getLine(t),r=n.search(/\\S/),o=t,a=n.length;t+=1;var s=t,l=e.getLength();while(++t<l){n=e.getLine(t);var c=n.search(/\\S/);if(-1!==c){if(r>c)break;var u=this.getFoldWidgetRange(e,\"all\",t);if(u){if(u.start.row<=o)break;if(u.isMultiLine())t=u.end.row;else if(r==c)break}s=t}}return new i(o,a,s,e.getLine(s).length)},this.getCommentRegionBlock=function(e,t,n){var r=t.search(/\\s*$/),o=e.getLength(),a=n,s=/^\\s*(?:\\/\\*|\\/\\/|--)#?(end)?region\\b/,l=1;while(++n<o){t=e.getLine(n);var c=s.exec(t);if(c&&(c[1]?l--:l++,!l))break}var u=n;if(u>a)return new i(a,r,u,t.length)}}.call(a.prototype)}),ace.define(\"ace/mode/javascript\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/mode/text\",\"ace/mode/javascript_highlight_rules\",\"ace/mode/matching_brace_outdent\",\"ace/worker/worker_client\",\"ace/mode/behaviour/cstyle\",\"ace/mode/folding/cstyle\"],function(e,t,r){\"use strict\";var i=e(\"../lib/oop\"),o=e(\"./text\").Mode,a=e(\"./javascript_highlight_rules\").JavaScriptHighlightRules,s=e(\"./matching_brace_outdent\").MatchingBraceOutdent,l=e(\"../worker/worker_client\").WorkerClient,c=e(\"./behaviour/cstyle\").CstyleBehaviour,u=e(\"./folding/cstyle\").FoldMode,d=function(){this.HighlightRules=a,this.$outdent=new s,this.$behaviour=new c,this.foldingRules=new u};i.inherits(d,o),function(){this.lineCommentStart=\"//\",this.blockComment={start:\"/*\",end:\"*/\"},this.$quotes={'\"':'\"',\"'\":\"'\",\"`\":\"`\"},this.getNextLineIndent=function(e,t,n){var r=this.$getIndent(t),i=this.getTokenizer().getLineTokens(t,e),o=i.tokens,a=i.state;if(o.length&&\"comment\"==o[o.length-1].type)return r;if(\"start\"==e||\"no_regex\"==e){var s=t.match(/^.*(?:\\bcase\\b.*:|[\\{\\(\\[])\\s*$/);s&&(r+=n)}else if(\"doc-start\"==e){if(\"start\"==a||\"no_regex\"==a)return\"\";s=t.match(/^\\s*(\\/?)\\*/);s&&(s[1]&&(r+=\" \"),r+=\"* \")}return r},this.checkOutdent=function(e,t,n){return this.$outdent.checkOutdent(t,n)},this.autoOutdent=function(e,t,n){this.$outdent.autoOutdent(t,n)},this.createWorker=function(e){var t=new l([\"ace\"],n(\"6d68\"),\"JavaScriptWorker\");return t.attachToDocument(e.getDocument()),t.on(\"annotate\",function(t){e.setAnnotations(t.data)}),t.on(\"terminate\",function(){e.clearAnnotations()}),t},this.$id=\"ace/mode/javascript\"}.call(d.prototype),t.Mode=d})},be9d:function(e,t,n){ace.define(\"ace/mode/doc_comment_highlight_rules\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/mode/text_highlight_rules\"],function(e,t,n){\"use strict\";var r=e(\"../lib/oop\"),i=e(\"./text_highlight_rules\").TextHighlightRules,o=function(){this.$rules={start:[{token:\"comment.doc.tag\",regex:\"@[\\\\w\\\\d_]+\"},o.getTagRule(),{defaultToken:\"comment.doc\",caseInsensitive:!0}]}};r.inherits(o,i),o.getTagRule=function(e){return{token:\"comment.doc.tag.storage.type\",regex:\"\\\\b(?:TODO|FIXME|XXX|HACK)\\\\b\"}},o.getStartRule=function(e){return{token:\"comment.doc\",regex:\"\\\\/\\\\*(?=\\\\*)\",next:e}},o.getEndRule=function(e){return{token:\"comment.doc\",regex:\"\\\\*\\\\/\",next:e}},t.DocCommentHighlightRules=o}),ace.define(\"ace/mode/javascript_highlight_rules\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/mode/doc_comment_highlight_rules\",\"ace/mode/text_highlight_rules\"],function(e,t,n){\"use strict\";var r=e(\"../lib/oop\"),i=e(\"./doc_comment_highlight_rules\").DocCommentHighlightRules,o=e(\"./text_highlight_rules\").TextHighlightRules,a=\"[a-zA-Z\\\\$_¡-￿][a-zA-Z\\\\d\\\\$_¡-￿]*\",s=function(e){var t=this.createKeywordMapper({\"variable.language\":\"Array|Boolean|Date|Function|Iterator|Number|Object|RegExp|String|Proxy|Namespace|QName|XML|XMLList|ArrayBuffer|Float32Array|Float64Array|Int16Array|Int32Array|Int8Array|Uint16Array|Uint32Array|Uint8Array|Uint8ClampedArray|Error|EvalError|InternalError|RangeError|ReferenceError|StopIteration|SyntaxError|TypeError|URIError|decodeURI|decodeURIComponent|encodeURI|encodeURIComponent|eval|isFinite|isNaN|parseFloat|parseInt|JSON|Math|this|arguments|prototype|window|document\",keyword:\"const|yield|import|get|set|async|await|break|case|catch|continue|default|delete|do|else|finally|for|function|if|in|of|instanceof|new|return|switch|throw|try|typeof|let|var|while|with|debugger|__parent__|__count__|escape|unescape|with|__proto__|class|enum|extends|super|export|implements|private|public|interface|package|protected|static\",\"storage.type\":\"const|let|var|function\",\"constant.language\":\"null|Infinity|NaN|undefined\",\"support.function\":\"alert\",\"constant.language.boolean\":\"true|false\"},\"identifier\"),n=\"case|do|else|finally|in|instanceof|return|throw|try|typeof|yield|void\",r=\"\\\\\\\\(?:x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|u{[0-9a-fA-F]{1,6}}|[0-2][0-7]{0,2}|3[0-7][0-7]?|[4-7][0-7]?|.)\";this.$rules={no_regex:[i.getStartRule(\"doc-start\"),c(\"no_regex\"),{token:\"string\",regex:\"'(?=.)\",next:\"qstring\"},{token:\"string\",regex:'\"(?=.)',next:\"qqstring\"},{token:\"constant.numeric\",regex:/0(?:[xX][0-9a-fA-F]+|[oO][0-7]+|[bB][01]+)\\b/},{token:\"constant.numeric\",regex:/(?:\\d\\d*(?:\\.\\d*)?|\\.\\d+)(?:[eE][+-]?\\d+\\b)?/},{token:[\"storage.type\",\"punctuation.operator\",\"support.function\",\"punctuation.operator\",\"entity.name.function\",\"text\",\"keyword.operator\"],regex:\"(\"+a+\")(\\\\.)(prototype)(\\\\.)(\"+a+\")(\\\\s*)(=)\",next:\"function_arguments\"},{token:[\"storage.type\",\"punctuation.operator\",\"entity.name.function\",\"text\",\"keyword.operator\",\"text\",\"storage.type\",\"text\",\"paren.lparen\"],regex:\"(\"+a+\")(\\\\.)(\"+a+\")(\\\\s*)(=)(\\\\s*)(function)(\\\\s*)(\\\\()\",next:\"function_arguments\"},{token:[\"entity.name.function\",\"text\",\"keyword.operator\",\"text\",\"storage.type\",\"text\",\"paren.lparen\"],regex:\"(\"+a+\")(\\\\s*)(=)(\\\\s*)(function)(\\\\s*)(\\\\()\",next:\"function_arguments\"},{token:[\"storage.type\",\"punctuation.operator\",\"entity.name.function\",\"text\",\"keyword.operator\",\"text\",\"storage.type\",\"text\",\"entity.name.function\",\"text\",\"paren.lparen\"],regex:\"(\"+a+\")(\\\\.)(\"+a+\")(\\\\s*)(=)(\\\\s*)(function)(\\\\s+)(\\\\w+)(\\\\s*)(\\\\()\",next:\"function_arguments\"},{token:[\"storage.type\",\"text\",\"entity.name.function\",\"text\",\"paren.lparen\"],regex:\"(function)(\\\\s+)(\"+a+\")(\\\\s*)(\\\\()\",next:\"function_arguments\"},{token:[\"entity.name.function\",\"text\",\"punctuation.operator\",\"text\",\"storage.type\",\"text\",\"paren.lparen\"],regex:\"(\"+a+\")(\\\\s*)(:)(\\\\s*)(function)(\\\\s*)(\\\\()\",next:\"function_arguments\"},{token:[\"text\",\"text\",\"storage.type\",\"text\",\"paren.lparen\"],regex:\"(:)(\\\\s*)(function)(\\\\s*)(\\\\()\",next:\"function_arguments\"},{token:\"keyword\",regex:\"from(?=\\\\s*('|\\\"))\"},{token:\"keyword\",regex:\"(?:\"+n+\")\\\\b\",next:\"start\"},{token:[\"support.constant\"],regex:/that\\b/},{token:[\"storage.type\",\"punctuation.operator\",\"support.function.firebug\"],regex:/(console)(\\.)(warn|info|log|error|time|trace|timeEnd|assert)\\b/},{token:t,regex:a},{token:\"punctuation.operator\",regex:/[.](?![.])/,next:\"property\"},{token:\"storage.type\",regex:/=>/},{token:\"keyword.operator\",regex:/--|\\+\\+|\\.{3}|===|==|=|!=|!==|<+=?|>+=?|!|&&|\\|\\||\\?:|[!$%&*+\\-~\\/^]=?/,next:\"start\"},{token:\"punctuation.operator\",regex:/[?:,;.]/,next:\"start\"},{token:\"paren.lparen\",regex:/[\\[({]/,next:\"start\"},{token:\"paren.rparen\",regex:/[\\])}]/},{token:\"comment\",regex:/^#!.*$/}],property:[{token:\"text\",regex:\"\\\\s+\"},{token:[\"storage.type\",\"punctuation.operator\",\"entity.name.function\",\"text\",\"keyword.operator\",\"text\",\"storage.type\",\"text\",\"entity.name.function\",\"text\",\"paren.lparen\"],regex:\"(\"+a+\")(\\\\.)(\"+a+\")(\\\\s*)(=)(\\\\s*)(function)(?:(\\\\s+)(\\\\w+))?(\\\\s*)(\\\\()\",next:\"function_arguments\"},{token:\"punctuation.operator\",regex:/[.](?![.])/},{token:\"support.function\",regex:/(s(?:h(?:ift|ow(?:Mod(?:elessDialog|alDialog)|Help))|croll(?:X|By(?:Pages|Lines)?|Y|To)?|t(?:op|rike)|i(?:n|zeToContent|debar|gnText)|ort|u(?:p|b(?:str(?:ing)?)?)|pli(?:ce|t)|e(?:nd|t(?:Re(?:sizable|questHeader)|M(?:i(?:nutes|lliseconds)|onth)|Seconds|Ho(?:tKeys|urs)|Year|Cursor|Time(?:out)?|Interval|ZOptions|Date|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Date|FullYear)|FullYear|Active)|arch)|qrt|lice|avePreferences|mall)|h(?:ome|andleEvent)|navigate|c(?:har(?:CodeAt|At)|o(?:s|n(?:cat|textual|firm)|mpile)|eil|lear(?:Timeout|Interval)?|a(?:ptureEvents|ll)|reate(?:StyleSheet|Popup|EventObject))|t(?:o(?:GMTString|S(?:tring|ource)|U(?:TCString|pperCase)|Lo(?:caleString|werCase))|est|a(?:n|int(?:Enabled)?))|i(?:s(?:NaN|Finite)|ndexOf|talics)|d(?:isableExternalCapture|ump|etachEvent)|u(?:n(?:shift|taint|escape|watch)|pdateCommands)|j(?:oin|avaEnabled)|p(?:o(?:p|w)|ush|lugins.refresh|a(?:ddings|rse(?:Int|Float)?)|r(?:int|ompt|eference))|e(?:scape|nableExternalCapture|val|lementFromPoint|x(?:p|ec(?:Script|Command)?))|valueOf|UTC|queryCommand(?:State|Indeterm|Enabled|Value)|f(?:i(?:nd|le(?:ModifiedDate|Size|CreatedDate|UpdatedDate)|xed)|o(?:nt(?:size|color)|rward)|loor|romCharCode)|watch|l(?:ink|o(?:ad|g)|astIndexOf)|a(?:sin|nchor|cos|t(?:tachEvent|ob|an(?:2)?)|pply|lert|b(?:s|ort))|r(?:ou(?:nd|teEvents)|e(?:size(?:By|To)|calc|turnValue|place|verse|l(?:oad|ease(?:Capture|Events)))|andom)|g(?:o|et(?:ResponseHeader|M(?:i(?:nutes|lliseconds)|onth)|Se(?:conds|lection)|Hours|Year|Time(?:zoneOffset)?|Da(?:y|te)|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Da(?:y|te)|FullYear)|FullYear|A(?:ttention|llResponseHeaders)))|m(?:in|ove(?:B(?:y|elow)|To(?:Absolute)?|Above)|ergeAttributes|a(?:tch|rgins|x))|b(?:toa|ig|o(?:ld|rderWidths)|link|ack))\\b(?=\\()/},{token:\"support.function.dom\",regex:/(s(?:ub(?:stringData|mit)|plitText|e(?:t(?:NamedItem|Attribute(?:Node)?)|lect))|has(?:ChildNodes|Feature)|namedItem|c(?:l(?:ick|o(?:se|neNode))|reate(?:C(?:omment|DATASection|aption)|T(?:Head|extNode|Foot)|DocumentFragment|ProcessingInstruction|E(?:ntityReference|lement)|Attribute))|tabIndex|i(?:nsert(?:Row|Before|Cell|Data)|tem)|open|delete(?:Row|C(?:ell|aption)|T(?:Head|Foot)|Data)|focus|write(?:ln)?|a(?:dd|ppend(?:Child|Data))|re(?:set|place(?:Child|Data)|move(?:NamedItem|Child|Attribute(?:Node)?)?)|get(?:NamedItem|Element(?:sBy(?:Name|TagName|ClassName)|ById)|Attribute(?:Node)?)|blur)\\b(?=\\()/},{token:\"support.constant\",regex:/(s(?:ystemLanguage|cr(?:ipts|ollbars|een(?:X|Y|Top|Left))|t(?:yle(?:Sheets)?|atus(?:Text|bar)?)|ibling(?:Below|Above)|ource|uffixes|e(?:curity(?:Policy)?|l(?:ection|f)))|h(?:istory|ost(?:name)?|as(?:h|Focus))|y|X(?:MLDocument|SLDocument)|n(?:ext|ame(?:space(?:s|URI)|Prop))|M(?:IN_VALUE|AX_VALUE)|c(?:haracterSet|o(?:n(?:structor|trollers)|okieEnabled|lorDepth|mp(?:onents|lete))|urrent|puClass|l(?:i(?:p(?:boardData)?|entInformation)|osed|asses)|alle(?:e|r)|rypto)|t(?:o(?:olbar|p)|ext(?:Transform|Indent|Decoration|Align)|ags)|SQRT(?:1_2|2)|i(?:n(?:ner(?:Height|Width)|put)|ds|gnoreCase)|zIndex|o(?:scpu|n(?:readystatechange|Line)|uter(?:Height|Width)|p(?:sProfile|ener)|ffscreenBuffering)|NEGATIVE_INFINITY|d(?:i(?:splay|alog(?:Height|Top|Width|Left|Arguments)|rectories)|e(?:scription|fault(?:Status|Ch(?:ecked|arset)|View)))|u(?:ser(?:Profile|Language|Agent)|n(?:iqueID|defined)|pdateInterval)|_content|p(?:ixelDepth|ort|ersonalbar|kcs11|l(?:ugins|atform)|a(?:thname|dding(?:Right|Bottom|Top|Left)|rent(?:Window|Layer)?|ge(?:X(?:Offset)?|Y(?:Offset)?))|r(?:o(?:to(?:col|type)|duct(?:Sub)?|mpter)|e(?:vious|fix)))|e(?:n(?:coding|abledPlugin)|x(?:ternal|pando)|mbeds)|v(?:isibility|endor(?:Sub)?|Linkcolor)|URLUnencoded|P(?:I|OSITIVE_INFINITY)|f(?:ilename|o(?:nt(?:Size|Family|Weight)|rmName)|rame(?:s|Element)|gColor)|E|whiteSpace|l(?:i(?:stStyleType|n(?:eHeight|kColor))|o(?:ca(?:tion(?:bar)?|lName)|wsrc)|e(?:ngth|ft(?:Context)?)|a(?:st(?:M(?:odified|atch)|Index|Paren)|yer(?:s|X)|nguage))|a(?:pp(?:MinorVersion|Name|Co(?:deName|re)|Version)|vail(?:Height|Top|Width|Left)|ll|r(?:ity|guments)|Linkcolor|bove)|r(?:ight(?:Context)?|e(?:sponse(?:XML|Text)|adyState))|global|x|m(?:imeTypes|ultiline|enubar|argin(?:Right|Bottom|Top|Left))|L(?:N(?:10|2)|OG(?:10E|2E))|b(?:o(?:ttom|rder(?:Width|RightWidth|BottomWidth|Style|Color|TopWidth|LeftWidth))|ufferDepth|elow|ackground(?:Color|Image)))\\b/},{token:\"identifier\",regex:a},{regex:\"\",token:\"empty\",next:\"no_regex\"}],start:[i.getStartRule(\"doc-start\"),c(\"start\"),{token:\"string.regexp\",regex:\"\\\\/\",next:\"regex\"},{token:\"text\",regex:\"\\\\s+|^$\",next:\"start\"},{token:\"empty\",regex:\"\",next:\"no_regex\"}],regex:[{token:\"regexp.keyword.operator\",regex:\"\\\\\\\\(?:u[\\\\da-fA-F]{4}|x[\\\\da-fA-F]{2}|.)\"},{token:\"string.regexp\",regex:\"/[sxngimy]*\",next:\"no_regex\"},{token:\"invalid\",regex:/\\{\\d+\\b,?\\d*\\}[+*]|[+*$^?][+*]|[$^][?]|\\?{3,}/},{token:\"constant.language.escape\",regex:/\\(\\?[:=!]|\\)|\\{\\d+\\b,?\\d*\\}|[+*]\\?|[()$^+*?.]/},{token:\"constant.language.delimiter\",regex:/\\|/},{token:\"constant.language.escape\",regex:/\\[\\^?/,next:\"regex_character_class\"},{token:\"empty\",regex:\"$\",next:\"no_regex\"},{defaultToken:\"string.regexp\"}],regex_character_class:[{token:\"regexp.charclass.keyword.operator\",regex:\"\\\\\\\\(?:u[\\\\da-fA-F]{4}|x[\\\\da-fA-F]{2}|.)\"},{token:\"constant.language.escape\",regex:\"]\",next:\"regex\"},{token:\"constant.language.escape\",regex:\"-\"},{token:\"empty\",regex:\"$\",next:\"no_regex\"},{defaultToken:\"string.regexp.charachterclass\"}],function_arguments:[{token:\"variable.parameter\",regex:a},{token:\"punctuation.operator\",regex:\"[, ]+\"},{token:\"punctuation.operator\",regex:\"$\"},{token:\"empty\",regex:\"\",next:\"no_regex\"}],qqstring:[{token:\"constant.language.escape\",regex:r},{token:\"string\",regex:\"\\\\\\\\$\",consumeLineEnd:!0},{token:\"string\",regex:'\"|$',next:\"no_regex\"},{defaultToken:\"string\"}],qstring:[{token:\"constant.language.escape\",regex:r},{token:\"string\",regex:\"\\\\\\\\$\",consumeLineEnd:!0},{token:\"string\",regex:\"'|$\",next:\"no_regex\"},{defaultToken:\"string\"}]},e&&e.noES6||(this.$rules.no_regex.unshift({regex:\"[{}]\",onMatch:function(e,t,n){if(this.next=\"{\"==e?this.nextState:\"\",\"{\"==e&&n.length)n.unshift(\"start\",t);else if(\"}\"==e&&n.length&&(n.shift(),this.next=n.shift(),-1!=this.next.indexOf(\"string\")||-1!=this.next.indexOf(\"jsx\")))return\"paren.quasi.end\";return\"{\"==e?\"paren.lparen\":\"paren.rparen\"},nextState:\"start\"},{token:\"string.quasi.start\",regex:/`/,push:[{token:\"constant.language.escape\",regex:r},{token:\"paren.quasi.start\",regex:/\\${/,push:\"start\"},{token:\"string.quasi.end\",regex:/`/,next:\"pop\"},{defaultToken:\"string.quasi\"}]}),e&&0==e.jsx||l.call(this)),this.embedRules(i,\"doc-\",[i.getEndRule(\"no_regex\")]),this.normalizeRules()};function l(){var e=a.replace(\"\\\\d\",\"\\\\d\\\\-\"),t={onMatch:function(e,t,n){var r=\"/\"==e.charAt(1)?2:1;return 1==r?(t!=this.nextState?n.unshift(this.next,this.nextState,0):n.unshift(this.next),n[2]++):2==r&&t==this.nextState&&(n[1]--,(!n[1]||n[1]<0)&&(n.shift(),n.shift())),[{type:\"meta.tag.punctuation.\"+(1==r?\"\":\"end-\")+\"tag-open.xml\",value:e.slice(0,r)},{type:\"meta.tag.tag-name.xml\",value:e.substr(r)}]},regex:\"</?\"+e,next:\"jsxAttributes\",nextState:\"jsx\"};this.$rules.start.unshift(t);var n={regex:\"{\",token:\"paren.quasi.start\",push:\"start\"};this.$rules.jsx=[n,t,{include:\"reference\"},{defaultToken:\"string\"}],this.$rules.jsxAttributes=[{token:\"meta.tag.punctuation.tag-close.xml\",regex:\"/?>\",onMatch:function(e,t,n){return t==n[0]&&n.shift(),2==e.length&&(n[0]==this.nextState&&n[1]--,(!n[1]||n[1]<0)&&n.splice(0,2)),this.next=n[0]||\"start\",[{type:this.token,value:e}]},nextState:\"jsx\"},n,c(\"jsxAttributes\"),{token:\"entity.other.attribute-name.xml\",regex:e},{token:\"keyword.operator.attribute-equals.xml\",regex:\"=\"},{token:\"text.tag-whitespace.xml\",regex:\"\\\\s+\"},{token:\"string.attribute-value.xml\",regex:\"'\",stateName:\"jsx_attr_q\",push:[{token:\"string.attribute-value.xml\",regex:\"'\",next:\"pop\"},{include:\"reference\"},{defaultToken:\"string.attribute-value.xml\"}]},{token:\"string.attribute-value.xml\",regex:'\"',stateName:\"jsx_attr_qq\",push:[{token:\"string.attribute-value.xml\",regex:'\"',next:\"pop\"},{include:\"reference\"},{defaultToken:\"string.attribute-value.xml\"}]},t],this.$rules.reference=[{token:\"constant.language.escape.reference.xml\",regex:\"(?:&#[0-9]+;)|(?:&#x[0-9a-fA-F]+;)|(?:&[a-zA-Z0-9_:\\\\.-]+;)\"}]}function c(e){return[{token:\"comment\",regex:/\\/\\*/,next:[i.getTagRule(),{token:\"comment\",regex:\"\\\\*\\\\/\",next:e||\"pop\"},{defaultToken:\"comment\",caseInsensitive:!0}]},{token:\"comment\",regex:\"\\\\/\\\\/\",next:[i.getTagRule(),{token:\"comment\",regex:\"$|^\",next:e||\"pop\"},{defaultToken:\"comment\",caseInsensitive:!0}]}]}r.inherits(s,o),t.JavaScriptHighlightRules=s}),ace.define(\"ace/mode/matching_brace_outdent\",[\"require\",\"exports\",\"module\",\"ace/range\"],function(e,t,n){\"use strict\";var r=e(\"../range\").Range,i=function(){};(function(){this.checkOutdent=function(e,t){return!!/^\\s+$/.test(e)&&/^\\s*\\}/.test(t)},this.autoOutdent=function(e,t){var n=e.getLine(t),i=n.match(/^(\\s*\\})/);if(!i)return 0;var o=i[1].length,a=e.findMatchingBracket({row:t,column:o});if(!a||a.row==t)return 0;var s=this.$getIndent(e.getLine(a.row));e.replace(new r(t,0,t,o-1),s)},this.$getIndent=function(e){return e.match(/^\\s*/)[0]}}).call(i.prototype),t.MatchingBraceOutdent=i}),ace.define(\"ace/mode/folding/cstyle\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/range\",\"ace/mode/folding/fold_mode\"],function(e,t,n){\"use strict\";var r=e(\"../../lib/oop\"),i=e(\"../../range\").Range,o=e(\"./fold_mode\").FoldMode,a=t.FoldMode=function(e){e&&(this.foldingStartMarker=new RegExp(this.foldingStartMarker.source.replace(/\\|[^|]*?$/,\"|\"+e.start)),this.foldingStopMarker=new RegExp(this.foldingStopMarker.source.replace(/\\|[^|]*?$/,\"|\"+e.end)))};r.inherits(a,o),function(){this.foldingStartMarker=/([\\{\\[\\(])[^\\}\\]\\)]*$|^\\s*(\\/\\*)/,this.foldingStopMarker=/^[^\\[\\{\\(]*([\\}\\]\\)])|^[\\s\\*]*(\\*\\/)/,this.singleLineBlockCommentRe=/^\\s*(\\/\\*).*\\*\\/\\s*$/,this.tripleStarBlockCommentRe=/^\\s*(\\/\\*\\*\\*).*\\*\\/\\s*$/,this.startRegionRe=/^\\s*(\\/\\*|\\/\\/)#?region\\b/,this._getFoldWidgetBase=this.getFoldWidget,this.getFoldWidget=function(e,t,n){var r=e.getLine(n);if(this.singleLineBlockCommentRe.test(r)&&!this.startRegionRe.test(r)&&!this.tripleStarBlockCommentRe.test(r))return\"\";var i=this._getFoldWidgetBase(e,t,n);return!i&&this.startRegionRe.test(r)?\"start\":i},this.getFoldWidgetRange=function(e,t,n,r){var i=e.getLine(n);if(this.startRegionRe.test(i))return this.getCommentRegionBlock(e,i,n);var o=i.match(this.foldingStartMarker);if(o){var a=o.index;if(o[1])return this.openingBracketBlock(e,o[1],n,a);var s=e.getCommentFoldRange(n,a+o[0].length,1);return s&&!s.isMultiLine()&&(r?s=this.getSectionRange(e,n):\"all\"!=t&&(s=null)),s}if(\"markbegin\"!==t){o=i.match(this.foldingStopMarker);if(o){a=o.index+o[0].length;return o[1]?this.closingBracketBlock(e,o[1],n,a):e.getCommentFoldRange(n,a,-1)}}},this.getSectionRange=function(e,t){var n=e.getLine(t),r=n.search(/\\S/),o=t,a=n.length;t+=1;var s=t,l=e.getLength();while(++t<l){n=e.getLine(t);var c=n.search(/\\S/);if(-1!==c){if(r>c)break;var u=this.getFoldWidgetRange(e,\"all\",t);if(u){if(u.start.row<=o)break;if(u.isMultiLine())t=u.end.row;else if(r==c)break}s=t}}return new i(o,a,s,e.getLine(s).length)},this.getCommentRegionBlock=function(e,t,n){var r=t.search(/\\s*$/),o=e.getLength(),a=n,s=/^\\s*(?:\\/\\*|\\/\\/|--)#?(end)?region\\b/,l=1;while(++n<o){t=e.getLine(n);var c=s.exec(t);if(c&&(c[1]?l--:l++,!l))break}var u=n;if(u>a)return new i(a,r,u,t.length)}}.call(a.prototype)}),ace.define(\"ace/mode/javascript\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/mode/text\",\"ace/mode/javascript_highlight_rules\",\"ace/mode/matching_brace_outdent\",\"ace/worker/worker_client\",\"ace/mode/behaviour/cstyle\",\"ace/mode/folding/cstyle\"],function(e,t,r){\"use strict\";var i=e(\"../lib/oop\"),o=e(\"./text\").Mode,a=e(\"./javascript_highlight_rules\").JavaScriptHighlightRules,s=e(\"./matching_brace_outdent\").MatchingBraceOutdent,l=e(\"../worker/worker_client\").WorkerClient,c=e(\"./behaviour/cstyle\").CstyleBehaviour,u=e(\"./folding/cstyle\").FoldMode,d=function(){this.HighlightRules=a,this.$outdent=new s,this.$behaviour=new c,this.foldingRules=new u};i.inherits(d,o),function(){this.lineCommentStart=\"//\",this.blockComment={start:\"/*\",end:\"*/\"},this.$quotes={'\"':'\"',\"'\":\"'\",\"`\":\"`\"},this.getNextLineIndent=function(e,t,n){var r=this.$getIndent(t),i=this.getTokenizer().getLineTokens(t,e),o=i.tokens,a=i.state;if(o.length&&\"comment\"==o[o.length-1].type)return r;if(\"start\"==e||\"no_regex\"==e){var s=t.match(/^.*(?:\\bcase\\b.*:|[\\{\\(\\[])\\s*$/);s&&(r+=n)}else if(\"doc-start\"==e){if(\"start\"==a||\"no_regex\"==a)return\"\";s=t.match(/^\\s*(\\/?)\\*/);s&&(s[1]&&(r+=\" \"),r+=\"* \")}return r},this.checkOutdent=function(e,t,n){return this.$outdent.checkOutdent(t,n)},this.autoOutdent=function(e,t,n){this.$outdent.autoOutdent(t,n)},this.createWorker=function(e){var t=new l([\"ace\"],n(\"6d68\"),\"JavaScriptWorker\");return t.attachToDocument(e.getDocument()),t.on(\"annotate\",function(t){e.setAnnotations(t.data)}),t.on(\"terminate\",function(){e.clearAnnotations()}),t},this.$id=\"ace/mode/javascript\"}.call(d.prototype),t.Mode=d}),ace.define(\"ace/mode/css_highlight_rules\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/lib/lang\",\"ace/mode/text_highlight_rules\"],function(e,t,n){\"use strict\";var r=e(\"../lib/oop\"),i=(e(\"../lib/lang\"),e(\"./text_highlight_rules\").TextHighlightRules),o=t.supportType=\"align-content|align-items|align-self|all|animation|animation-delay|animation-direction|animation-duration|animation-fill-mode|animation-iteration-count|animation-name|animation-play-state|animation-timing-function|backface-visibility|background|background-attachment|background-blend-mode|background-clip|background-color|background-image|background-origin|background-position|background-repeat|background-size|border|border-bottom|border-bottom-color|border-bottom-left-radius|border-bottom-right-radius|border-bottom-style|border-bottom-width|border-collapse|border-color|border-image|border-image-outset|border-image-repeat|border-image-slice|border-image-source|border-image-width|border-left|border-left-color|border-left-style|border-left-width|border-radius|border-right|border-right-color|border-right-style|border-right-width|border-spacing|border-style|border-top|border-top-color|border-top-left-radius|border-top-right-radius|border-top-style|border-top-width|border-width|bottom|box-shadow|box-sizing|caption-side|clear|clip|color|column-count|column-fill|column-gap|column-rule|column-rule-color|column-rule-style|column-rule-width|column-span|column-width|columns|content|counter-increment|counter-reset|cursor|direction|display|empty-cells|filter|flex|flex-basis|flex-direction|flex-flow|flex-grow|flex-shrink|flex-wrap|float|font|font-family|font-size|font-size-adjust|font-stretch|font-style|font-variant|font-weight|hanging-punctuation|height|justify-content|left|letter-spacing|line-height|list-style|list-style-image|list-style-position|list-style-type|margin|margin-bottom|margin-left|margin-right|margin-top|max-height|max-width|min-height|min-width|nav-down|nav-index|nav-left|nav-right|nav-up|opacity|order|outline|outline-color|outline-offset|outline-style|outline-width|overflow|overflow-x|overflow-y|padding|padding-bottom|padding-left|padding-right|padding-top|page-break-after|page-break-before|page-break-inside|perspective|perspective-origin|position|quotes|resize|right|tab-size|table-layout|text-align|text-align-last|text-decoration|text-decoration-color|text-decoration-line|text-decoration-style|text-indent|text-justify|text-overflow|text-shadow|text-transform|top|transform|transform-origin|transform-style|transition|transition-delay|transition-duration|transition-property|transition-timing-function|unicode-bidi|vertical-align|visibility|white-space|width|word-break|word-spacing|word-wrap|z-index\",a=t.supportFunction=\"rgb|rgba|url|attr|counter|counters\",s=t.supportConstant=\"absolute|after-edge|after|all-scroll|all|alphabetic|always|antialiased|armenian|auto|avoid-column|avoid-page|avoid|balance|baseline|before-edge|before|below|bidi-override|block-line-height|block|bold|bolder|border-box|both|bottom|box|break-all|break-word|capitalize|caps-height|caption|center|central|char|circle|cjk-ideographic|clone|close-quote|col-resize|collapse|column|consider-shifts|contain|content-box|cover|crosshair|cubic-bezier|dashed|decimal-leading-zero|decimal|default|disabled|disc|disregard-shifts|distribute-all-lines|distribute-letter|distribute-space|distribute|dotted|double|e-resize|ease-in|ease-in-out|ease-out|ease|ellipsis|end|exclude-ruby|fill|fixed|georgian|glyphs|grid-height|groove|hand|hanging|hebrew|help|hidden|hiragana-iroha|hiragana|horizontal|icon|ideograph-alpha|ideograph-numeric|ideograph-parenthesis|ideograph-space|ideographic|inactive|include-ruby|inherit|initial|inline-block|inline-box|inline-line-height|inline-table|inline|inset|inside|inter-ideograph|inter-word|invert|italic|justify|katakana-iroha|katakana|keep-all|last|left|lighter|line-edge|line-through|line|linear|list-item|local|loose|lower-alpha|lower-greek|lower-latin|lower-roman|lowercase|lr-tb|ltr|mathematical|max-height|max-size|medium|menu|message-box|middle|move|n-resize|ne-resize|newspaper|no-change|no-close-quote|no-drop|no-open-quote|no-repeat|none|normal|not-allowed|nowrap|nw-resize|oblique|open-quote|outset|outside|overline|padding-box|page|pointer|pre-line|pre-wrap|pre|preserve-3d|progress|relative|repeat-x|repeat-y|repeat|replaced|reset-size|ridge|right|round|row-resize|rtl|s-resize|scroll|se-resize|separate|slice|small-caps|small-caption|solid|space|square|start|static|status-bar|step-end|step-start|steps|stretch|strict|sub|super|sw-resize|table-caption|table-cell|table-column-group|table-column|table-footer-group|table-header-group|table-row-group|table-row|table|tb-rl|text-after-edge|text-before-edge|text-bottom|text-size|text-top|text|thick|thin|transparent|underline|upper-alpha|upper-latin|upper-roman|uppercase|use-script|vertical-ideographic|vertical-text|visible|w-resize|wait|whitespace|z-index|zero\",l=t.supportConstantColor=\"aliceblue|antiquewhite|aqua|aquamarine|azure|beige|bisque|black|blanchedalmond|blue|blueviolet|brown|burlywood|cadetblue|chartreuse|chocolate|coral|cornflowerblue|cornsilk|crimson|cyan|darkblue|darkcyan|darkgoldenrod|darkgray|darkgreen|darkgrey|darkkhaki|darkmagenta|darkolivegreen|darkorange|darkorchid|darkred|darksalmon|darkseagreen|darkslateblue|darkslategray|darkslategrey|darkturquoise|darkviolet|deeppink|deepskyblue|dimgray|dimgrey|dodgerblue|firebrick|floralwhite|forestgreen|fuchsia|gainsboro|ghostwhite|gold|goldenrod|gray|green|greenyellow|grey|honeydew|hotpink|indianred|indigo|ivory|khaki|lavender|lavenderblush|lawngreen|lemonchiffon|lightblue|lightcoral|lightcyan|lightgoldenrodyellow|lightgray|lightgreen|lightgrey|lightpink|lightsalmon|lightseagreen|lightskyblue|lightslategray|lightslategrey|lightsteelblue|lightyellow|lime|limegreen|linen|magenta|maroon|mediumaquamarine|mediumblue|mediumorchid|mediumpurple|mediumseagreen|mediumslateblue|mediumspringgreen|mediumturquoise|mediumvioletred|midnightblue|mintcream|mistyrose|moccasin|navajowhite|navy|oldlace|olive|olivedrab|orange|orangered|orchid|palegoldenrod|palegreen|paleturquoise|palevioletred|papayawhip|peachpuff|peru|pink|plum|powderblue|purple|rebeccapurple|red|rosybrown|royalblue|saddlebrown|salmon|sandybrown|seagreen|seashell|sienna|silver|skyblue|slateblue|slategray|slategrey|snow|springgreen|steelblue|tan|teal|thistle|tomato|turquoise|violet|wheat|white|whitesmoke|yellow|yellowgreen\",c=t.supportConstantFonts=\"arial|century|comic|courier|cursive|fantasy|garamond|georgia|helvetica|impact|lucida|symbol|system|tahoma|times|trebuchet|utopia|verdana|webdings|sans-serif|serif|monospace\",u=t.numRe=\"\\\\-?(?:(?:[0-9]+(?:\\\\.[0-9]+)?)|(?:\\\\.[0-9]+))\",d=t.pseudoElements=\"(\\\\:+)\\\\b(after|before|first-letter|first-line|moz-selection|selection)\\\\b\",h=t.pseudoClasses=\"(:)\\\\b(active|checked|disabled|empty|enabled|first-child|first-of-type|focus|hover|indeterminate|invalid|last-child|last-of-type|link|not|nth-child|nth-last-child|nth-last-of-type|nth-of-type|only-child|only-of-type|acequired|root|target|valid|visited)\\\\b\",p=function(){var e=this.createKeywordMapper({\"support.function\":a,\"support.constant\":s,\"support.type\":o,\"support.constant.color\":l,\"support.constant.fonts\":c},\"text\",!0);this.$rules={start:[{include:[\"strings\",\"url\",\"comments\"]},{token:\"paren.lparen\",regex:\"\\\\{\",next:\"ruleset\"},{token:\"paren.rparen\",regex:\"\\\\}\"},{token:\"string\",regex:\"@\",next:\"media\"},{token:\"keyword\",regex:\"#[a-z0-9-_]+\"},{token:\"keyword\",regex:\"%\"},{token:\"variable\",regex:\"\\\\.[a-z0-9-_]+\"},{token:\"string\",regex:\":[a-z0-9-_]+\"},{token:\"constant.numeric\",regex:u},{token:\"constant\",regex:\"[a-z0-9-_]+\"},{caseInsensitive:!0}],media:[{include:[\"strings\",\"url\",\"comments\"]},{token:\"paren.lparen\",regex:\"\\\\{\",next:\"start\"},{token:\"paren.rparen\",regex:\"\\\\}\",next:\"start\"},{token:\"string\",regex:\";\",next:\"start\"},{token:\"keyword\",regex:\"(?:media|supports|document|charset|import|namespace|media|supports|document|page|font|keyframes|viewport|counter-style|font-feature-values|swash|ornaments|annotation|stylistic|styleset|character-variant)\"}],comments:[{token:\"comment\",regex:\"\\\\/\\\\*\",push:[{token:\"comment\",regex:\"\\\\*\\\\/\",next:\"pop\"},{defaultToken:\"comment\"}]}],ruleset:[{regex:\"-(webkit|ms|moz|o)-\",token:\"text\"},{token:\"paren.rparen\",regex:\"\\\\}\",next:\"start\"},{include:[\"strings\",\"url\",\"comments\"]},{token:[\"constant.numeric\",\"keyword\"],regex:\"(\"+u+\")(ch|cm|deg|em|ex|fr|gd|grad|Hz|in|kHz|mm|ms|pc|pt|px|rad|rem|s|turn|vh|vm|vw|%)\"},{token:\"constant.numeric\",regex:u},{token:\"constant.numeric\",regex:\"#[a-f0-9]{6}\"},{token:\"constant.numeric\",regex:\"#[a-f0-9]{3}\"},{token:[\"punctuation\",\"entity.other.attribute-name.pseudo-element.css\"],regex:d},{token:[\"punctuation\",\"entity.other.attribute-name.pseudo-class.css\"],regex:h},{include:\"url\"},{token:e,regex:\"\\\\-?[a-zA-Z_][a-zA-Z0-9_\\\\-]*\"},{caseInsensitive:!0}],url:[{token:\"support.function\",regex:\"(?:url(:?-prefix)?|domain|regexp)\\\\(\",push:[{token:\"support.function\",regex:\"\\\\)\",next:\"pop\"},{defaultToken:\"string\"}]}],strings:[{token:\"string.start\",regex:\"'\",push:[{token:\"string.end\",regex:\"'|$\",next:\"pop\"},{include:\"escapes\"},{token:\"constant.language.escape\",regex:/\\\\$/,consumeLineEnd:!0},{defaultToken:\"string\"}]},{token:\"string.start\",regex:'\"',push:[{token:\"string.end\",regex:'\"|$',next:\"pop\"},{include:\"escapes\"},{token:\"constant.language.escape\",regex:/\\\\$/,consumeLineEnd:!0},{defaultToken:\"string\"}]}],escapes:[{token:\"constant.language.escape\",regex:/\\\\([a-fA-F\\d]{1,6}|[^a-fA-F\\d])/}]},this.normalizeRules()};r.inherits(p,i),t.CssHighlightRules=p}),ace.define(\"ace/mode/css_completions\",[\"require\",\"exports\",\"module\"],function(e,t,n){\"use strict\";var r={background:{\"#$0\":1},\"background-color\":{\"#$0\":1,transparent:1,fixed:1},\"background-image\":{\"url('/$0')\":1},\"background-repeat\":{repeat:1,\"repeat-x\":1,\"repeat-y\":1,\"no-repeat\":1,inherit:1},\"background-position\":{bottom:2,center:2,left:2,right:2,top:2,inherit:2},\"background-attachment\":{scroll:1,fixed:1},\"background-size\":{cover:1,contain:1},\"background-clip\":{\"border-box\":1,\"padding-box\":1,\"content-box\":1},\"background-origin\":{\"border-box\":1,\"padding-box\":1,\"content-box\":1},border:{\"solid $0\":1,\"dashed $0\":1,\"dotted $0\":1,\"#$0\":1},\"border-color\":{\"#$0\":1},\"border-style\":{solid:2,dashed:2,dotted:2,double:2,groove:2,hidden:2,inherit:2,inset:2,none:2,outset:2,ridged:2},\"border-collapse\":{collapse:1,separate:1},bottom:{px:1,em:1,\"%\":1},clear:{left:1,right:1,both:1,none:1},color:{\"#$0\":1,\"rgb(#$00,0,0)\":1},cursor:{default:1,pointer:1,move:1,text:1,wait:1,help:1,progress:1,\"n-resize\":1,\"ne-resize\":1,\"e-resize\":1,\"se-resize\":1,\"s-resize\":1,\"sw-resize\":1,\"w-resize\":1,\"nw-resize\":1},display:{none:1,block:1,inline:1,\"inline-block\":1,\"table-cell\":1},\"empty-cells\":{show:1,hide:1},float:{left:1,right:1,none:1},\"font-family\":{Arial:2,\"Comic Sans MS\":2,Consolas:2,\"Courier New\":2,Courier:2,Georgia:2,Monospace:2,\"Sans-Serif\":2,\"Segoe UI\":2,Tahoma:2,\"Times New Roman\":2,\"Trebuchet MS\":2,Verdana:1},\"font-size\":{px:1,em:1,\"%\":1},\"font-weight\":{bold:1,normal:1},\"font-style\":{italic:1,normal:1},\"font-variant\":{normal:1,\"small-caps\":1},height:{px:1,em:1,\"%\":1},left:{px:1,em:1,\"%\":1},\"letter-spacing\":{normal:1},\"line-height\":{normal:1},\"list-style-type\":{none:1,disc:1,circle:1,square:1,decimal:1,\"decimal-leading-zero\":1,\"lower-roman\":1,\"upper-roman\":1,\"lower-greek\":1,\"lower-latin\":1,\"upper-latin\":1,georgian:1,\"lower-alpha\":1,\"upper-alpha\":1},margin:{px:1,em:1,\"%\":1},\"margin-right\":{px:1,em:1,\"%\":1},\"margin-left\":{px:1,em:1,\"%\":1},\"margin-top\":{px:1,em:1,\"%\":1},\"margin-bottom\":{px:1,em:1,\"%\":1},\"max-height\":{px:1,em:1,\"%\":1},\"max-width\":{px:1,em:1,\"%\":1},\"min-height\":{px:1,em:1,\"%\":1},\"min-width\":{px:1,em:1,\"%\":1},overflow:{hidden:1,visible:1,auto:1,scroll:1},\"overflow-x\":{hidden:1,visible:1,auto:1,scroll:1},\"overflow-y\":{hidden:1,visible:1,auto:1,scroll:1},padding:{px:1,em:1,\"%\":1},\"padding-top\":{px:1,em:1,\"%\":1},\"padding-right\":{px:1,em:1,\"%\":1},\"padding-bottom\":{px:1,em:1,\"%\":1},\"padding-left\":{px:1,em:1,\"%\":1},\"page-break-after\":{auto:1,always:1,avoid:1,left:1,right:1},\"page-break-before\":{auto:1,always:1,avoid:1,left:1,right:1},position:{absolute:1,relative:1,fixed:1,static:1},right:{px:1,em:1,\"%\":1},\"table-layout\":{fixed:1,auto:1},\"text-decoration\":{none:1,underline:1,\"line-through\":1,blink:1},\"text-align\":{left:1,right:1,center:1,justify:1},\"text-transform\":{capitalize:1,uppercase:1,lowercase:1,none:1},top:{px:1,em:1,\"%\":1},\"vertical-align\":{top:1,bottom:1},visibility:{hidden:1,visible:1},\"white-space\":{nowrap:1,normal:1,pre:1,\"pre-line\":1,\"pre-wrap\":1},width:{px:1,em:1,\"%\":1},\"word-spacing\":{normal:1},filter:{\"alpha(opacity=$0100)\":1},\"text-shadow\":{\"$02px 2px 2px #777\":1},\"text-overflow\":{\"ellipsis-word\":1,clip:1,ellipsis:1},\"-moz-border-radius\":1,\"-moz-border-radius-topright\":1,\"-moz-border-radius-bottomright\":1,\"-moz-border-radius-topleft\":1,\"-moz-border-radius-bottomleft\":1,\"-webkit-border-radius\":1,\"-webkit-border-top-right-radius\":1,\"-webkit-border-top-left-radius\":1,\"-webkit-border-bottom-right-radius\":1,\"-webkit-border-bottom-left-radius\":1,\"-moz-box-shadow\":1,\"-webkit-box-shadow\":1,transform:{\"rotate($00deg)\":1,\"skew($00deg)\":1},\"-moz-transform\":{\"rotate($00deg)\":1,\"skew($00deg)\":1},\"-webkit-transform\":{\"rotate($00deg)\":1,\"skew($00deg)\":1}},i=function(){};(function(){this.completionsDefined=!1,this.defineCompletions=function(){if(document){var e=document.createElement(\"c\").style;for(var t in e)if(\"string\"===typeof e[t]){var n=t.replace(/[A-Z]/g,function(e){return\"-\"+e.toLowerCase()});r.hasOwnProperty(n)||(r[n]=1)}}this.completionsDefined=!0},this.getCompletions=function(e,t,n,r){this.completionsDefined||this.defineCompletions();var i=t.getTokenAt(n.row,n.column);if(!i)return[];if(\"ruleset\"===e){var o=t.getLine(n.row).substr(0,n.column);return/:[^;]+$/.test(o)?(/([\\w\\-]+):[^:]*$/.test(o),this.getPropertyValueCompletions(e,t,n,r)):this.getPropertyCompletions(e,t,n,r)}return[]},this.getPropertyCompletions=function(e,t,n,i){var o=Object.keys(r);return o.map(function(e){return{caption:e,snippet:e+\": $0;\",meta:\"property\",score:Number.MAX_VALUE}})},this.getPropertyValueCompletions=function(e,t,n,i){var o=t.getLine(n.row).substr(0,n.column),a=(/([\\w\\-]+):[^:]*$/.exec(o)||{})[1];if(!a)return[];var s=[];return a in r&&\"object\"===typeof r[a]&&(s=Object.keys(r[a])),s.map(function(e){return{caption:e,snippet:e,meta:\"property value\",score:Number.MAX_VALUE}})}}).call(i.prototype),t.CssCompletions=i}),ace.define(\"ace/mode/behaviour/css\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/mode/behaviour\",\"ace/mode/behaviour/cstyle\",\"ace/token_iterator\"],function(e,t,n){\"use strict\";var r=e(\"../../lib/oop\"),i=(e(\"../behaviour\").Behaviour,e(\"./cstyle\").CstyleBehaviour),o=e(\"../../token_iterator\").TokenIterator,a=function(){this.inherit(i),this.add(\"colon\",\"insertion\",function(e,t,n,r,i){if(\":\"===i){var a=n.getCursorPosition(),s=new o(r,a.row,a.column),l=s.getCurrentToken();if(l&&l.value.match(/\\s+/)&&(l=s.stepBackward()),l&&\"support.type\"===l.type){var c=r.doc.getLine(a.row),u=c.substring(a.column,a.column+1);if(\":\"===u)return{text:\"\",selection:[1,1]};if(!c.substring(a.column).match(/^\\s*;/))return{text:\":;\",selection:[1,1]}}}}),this.add(\"colon\",\"deletion\",function(e,t,n,r,i){var a=r.doc.getTextRange(i);if(!i.isMultiLine()&&\":\"===a){var s=n.getCursorPosition(),l=new o(r,s.row,s.column),c=l.getCurrentToken();if(c&&c.value.match(/\\s+/)&&(c=l.stepBackward()),c&&\"support.type\"===c.type){var u=r.doc.getLine(i.start.row),d=u.substring(i.end.column,i.end.column+1);if(\";\"===d)return i.end.column++,i}}}),this.add(\"semicolon\",\"insertion\",function(e,t,n,r,i){if(\";\"===i){var o=n.getCursorPosition(),a=r.doc.getLine(o.row),s=a.substring(o.column,o.column+1);if(\";\"===s)return{text:\"\",selection:[1,1]}}})};r.inherits(a,i),t.CssBehaviour=a}),ace.define(\"ace/mode/css\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/mode/text\",\"ace/mode/css_highlight_rules\",\"ace/mode/matching_brace_outdent\",\"ace/worker/worker_client\",\"ace/mode/css_completions\",\"ace/mode/behaviour/css\",\"ace/mode/folding/cstyle\"],function(e,t,r){\"use strict\";var i=e(\"../lib/oop\"),o=e(\"./text\").Mode,a=e(\"./css_highlight_rules\").CssHighlightRules,s=e(\"./matching_brace_outdent\").MatchingBraceOutdent,l=e(\"../worker/worker_client\").WorkerClient,c=e(\"./css_completions\").CssCompletions,u=e(\"./behaviour/css\").CssBehaviour,d=e(\"./folding/cstyle\").FoldMode,h=function(){this.HighlightRules=a,this.$outdent=new s,this.$behaviour=new u,this.$completer=new c,this.foldingRules=new d};i.inherits(h,o),function(){this.foldingRules=\"cStyle\",this.blockComment={start:\"/*\",end:\"*/\"},this.getNextLineIndent=function(e,t,n){var r=this.$getIndent(t),i=this.getTokenizer().getLineTokens(t,e).tokens;if(i.length&&\"comment\"==i[i.length-1].type)return r;var o=t.match(/^.*\\{\\s*$/);return o&&(r+=n),r},this.checkOutdent=function(e,t,n){return this.$outdent.checkOutdent(t,n)},this.autoOutdent=function(e,t,n){this.$outdent.autoOutdent(t,n)},this.getCompletions=function(e,t,n,r){return this.$completer.getCompletions(e,t,n,r)},this.createWorker=function(e){var t=new l([\"ace\"],n(\"e070\"),\"Worker\");return t.attachToDocument(e.getDocument()),t.on(\"annotate\",function(t){e.setAnnotations(t.data)}),t.on(\"terminate\",function(){e.clearAnnotations()}),t},this.$id=\"ace/mode/css\"}.call(h.prototype),t.Mode=h}),ace.define(\"ace/mode/xml_highlight_rules\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/mode/text_highlight_rules\"],function(e,t,n){\"use strict\";var r=e(\"../lib/oop\"),i=e(\"./text_highlight_rules\").TextHighlightRules,o=function(e){var t=\"[_:a-zA-ZÀ-￿][-_:.a-zA-Z0-9À-￿]*\";this.$rules={start:[{token:\"string.cdata.xml\",regex:\"<\\\\!\\\\[CDATA\\\\[\",next:\"cdata\"},{token:[\"punctuation.instruction.xml\",\"keyword.instruction.xml\"],regex:\"(<\\\\?)(\"+t+\")\",next:\"processing_instruction\"},{token:\"comment.start.xml\",regex:\"<\\\\!--\",next:\"comment\"},{token:[\"xml-pe.doctype.xml\",\"xml-pe.doctype.xml\"],regex:\"(<\\\\!)(DOCTYPE)(?=[\\\\s])\",next:\"doctype\",caseInsensitive:!0},{include:\"tag\"},{token:\"text.end-tag-open.xml\",regex:\"</\"},{token:\"text.tag-open.xml\",regex:\"<\"},{include:\"reference\"},{defaultToken:\"text.xml\"}],processing_instruction:[{token:\"entity.other.attribute-name.decl-attribute-name.xml\",regex:t},{token:\"keyword.operator.decl-attribute-equals.xml\",regex:\"=\"},{include:\"whitespace\"},{include:\"string\"},{token:\"punctuation.xml-decl.xml\",regex:\"\\\\?>\",next:\"start\"}],doctype:[{include:\"whitespace\"},{include:\"string\"},{token:\"xml-pe.doctype.xml\",regex:\">\",next:\"start\"},{token:\"xml-pe.xml\",regex:\"[-_a-zA-Z0-9:]+\"},{token:\"punctuation.int-subset\",regex:\"\\\\[\",push:\"int_subset\"}],int_subset:[{token:\"text.xml\",regex:\"\\\\s+\"},{token:\"punctuation.int-subset.xml\",regex:\"]\",next:\"pop\"},{token:[\"punctuation.markup-decl.xml\",\"keyword.markup-decl.xml\"],regex:\"(<\\\\!)(\"+t+\")\",push:[{token:\"text\",regex:\"\\\\s+\"},{token:\"punctuation.markup-decl.xml\",regex:\">\",next:\"pop\"},{include:\"string\"}]}],cdata:[{token:\"string.cdata.xml\",regex:\"\\\\]\\\\]>\",next:\"start\"},{token:\"text.xml\",regex:\"\\\\s+\"},{token:\"text.xml\",regex:\"(?:[^\\\\]]|\\\\](?!\\\\]>))+\"}],comment:[{token:\"comment.end.xml\",regex:\"--\\x3e\",next:\"start\"},{defaultToken:\"comment.xml\"}],reference:[{token:\"constant.language.escape.reference.xml\",regex:\"(?:&#[0-9]+;)|(?:&#x[0-9a-fA-F]+;)|(?:&[a-zA-Z0-9_:\\\\.-]+;)\"}],attr_reference:[{token:\"constant.language.escape.reference.attribute-value.xml\",regex:\"(?:&#[0-9]+;)|(?:&#x[0-9a-fA-F]+;)|(?:&[a-zA-Z0-9_:\\\\.-]+;)\"}],tag:[{token:[\"meta.tag.punctuation.tag-open.xml\",\"meta.tag.punctuation.end-tag-open.xml\",\"meta.tag.tag-name.xml\"],regex:\"(?:(<)|(</))((?:\"+t+\":)?\"+t+\")\",next:[{include:\"attributes\"},{token:\"meta.tag.punctuation.tag-close.xml\",regex:\"/?>\",next:\"start\"}]}],tag_whitespace:[{token:\"text.tag-whitespace.xml\",regex:\"\\\\s+\"}],whitespace:[{token:\"text.whitespace.xml\",regex:\"\\\\s+\"}],string:[{token:\"string.xml\",regex:\"'\",push:[{token:\"string.xml\",regex:\"'\",next:\"pop\"},{defaultToken:\"string.xml\"}]},{token:\"string.xml\",regex:'\"',push:[{token:\"string.xml\",regex:'\"',next:\"pop\"},{defaultToken:\"string.xml\"}]}],attributes:[{token:\"entity.other.attribute-name.xml\",regex:t},{token:\"keyword.operator.attribute-equals.xml\",regex:\"=\"},{include:\"tag_whitespace\"},{include:\"attribute_value\"}],attribute_value:[{token:\"string.attribute-value.xml\",regex:\"'\",push:[{token:\"string.attribute-value.xml\",regex:\"'\",next:\"pop\"},{include:\"attr_reference\"},{defaultToken:\"string.attribute-value.xml\"}]},{token:\"string.attribute-value.xml\",regex:'\"',push:[{token:\"string.attribute-value.xml\",regex:'\"',next:\"pop\"},{include:\"attr_reference\"},{defaultToken:\"string.attribute-value.xml\"}]}]},this.constructor===o&&this.normalizeRules()};(function(){this.embedTagRules=function(e,t,n){this.$rules.tag.unshift({token:[\"meta.tag.punctuation.tag-open.xml\",\"meta.tag.\"+n+\".tag-name.xml\"],regex:\"(<)(\"+n+\"(?=\\\\s|>|$))\",next:[{include:\"attributes\"},{token:\"meta.tag.punctuation.tag-close.xml\",regex:\"/?>\",next:t+\"start\"}]}),this.$rules[n+\"-end\"]=[{include:\"attributes\"},{token:\"meta.tag.punctuation.tag-close.xml\",regex:\"/?>\",next:\"start\",onMatch:function(e,t,n){return n.splice(0),this.token}}],this.embedRules(e,t,[{token:[\"meta.tag.punctuation.end-tag-open.xml\",\"meta.tag.\"+n+\".tag-name.xml\"],regex:\"(</)(\"+n+\"(?=\\\\s|>|$))\",next:n+\"-end\"},{token:\"string.cdata.xml\",regex:\"<\\\\!\\\\[CDATA\\\\[\"},{token:\"string.cdata.xml\",regex:\"\\\\]\\\\]>\"}])}}).call(i.prototype),r.inherits(o,i),t.XmlHighlightRules=o}),ace.define(\"ace/mode/html_highlight_rules\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/lib/lang\",\"ace/mode/css_highlight_rules\",\"ace/mode/javascript_highlight_rules\",\"ace/mode/xml_highlight_rules\"],function(e,t,n){\"use strict\";var r=e(\"../lib/oop\"),i=e(\"../lib/lang\"),o=e(\"./css_highlight_rules\").CssHighlightRules,a=e(\"./javascript_highlight_rules\").JavaScriptHighlightRules,s=e(\"./xml_highlight_rules\").XmlHighlightRules,l=i.createMap({a:\"anchor\",button:\"form\",form:\"form\",img:\"image\",input:\"form\",label:\"form\",option:\"form\",script:\"script\",select:\"form\",textarea:\"form\",style:\"style\",table:\"table\",tbody:\"table\",td:\"table\",tfoot:\"table\",th:\"table\",tr:\"table\"}),c=function(){s.call(this),this.addRules({attributes:[{include:\"tag_whitespace\"},{token:\"entity.other.attribute-name.xml\",regex:\"[-_a-zA-Z0-9:.]+\"},{token:\"keyword.operator.attribute-equals.xml\",regex:\"=\",push:[{include:\"tag_whitespace\"},{token:\"string.unquoted.attribute-value.html\",regex:\"[^<>='\\\"`\\\\s]+\",next:\"pop\"},{token:\"empty\",regex:\"\",next:\"pop\"}]},{include:\"attribute_value\"}],tag:[{token:function(e,t){var n=l[t];return[\"meta.tag.punctuation.\"+(\"<\"==e?\"\":\"end-\")+\"tag-open.xml\",\"meta.tag\"+(n?\".\"+n:\"\")+\".tag-name.xml\"]},regex:\"(</?)([-_a-zA-Z0-9:.]+)\",next:\"tag_stuff\"}],tag_stuff:[{include:\"attributes\"},{token:\"meta.tag.punctuation.tag-close.xml\",regex:\"/?>\",next:\"start\"}]}),this.embedTagRules(o,\"css-\",\"style\"),this.embedTagRules(new a({jsx:!1}).getRules(),\"js-\",\"script\"),this.constructor===c&&this.normalizeRules()};r.inherits(c,s),t.HtmlHighlightRules=c}),ace.define(\"ace/mode/behaviour/xml\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/mode/behaviour\",\"ace/token_iterator\",\"ace/lib/lang\"],function(e,t,n){\"use strict\";var r=e(\"../../lib/oop\"),i=e(\"../behaviour\").Behaviour,o=e(\"../../token_iterator\").TokenIterator;e(\"../../lib/lang\");function a(e,t){return e.type.lastIndexOf(t+\".xml\")>-1}var s=function(){this.add(\"string_dquotes\",\"insertion\",function(e,t,n,r,i){if('\"'==i||\"'\"==i){var s=i,l=r.doc.getTextRange(n.getSelectionRange());if(\"\"!==l&&\"'\"!==l&&'\"'!=l&&n.getWrapBehavioursEnabled())return{text:s+l+s,selection:!1};var c=n.getCursorPosition(),u=r.doc.getLine(c.row),d=u.substring(c.column,c.column+1),h=new o(r,c.row,c.column),p=h.getCurrentToken();if(d==s&&(a(p,\"attribute-value\")||a(p,\"string\")))return{text:\"\",selection:[1,1]};if(p||(p=h.stepBackward()),!p)return;while(a(p,\"tag-whitespace\")||a(p,\"whitespace\"))p=h.stepBackward();var m=!d||d.match(/\\s/);if(a(p,\"attribute-equals\")&&(m||\">\"==d)||a(p,\"decl-attribute-equals\")&&(m||\"?\"==d))return{text:s+s,selection:[1,1]}}}),this.add(\"string_dquotes\",\"deletion\",function(e,t,n,r,i){var o=r.doc.getTextRange(i);if(!i.isMultiLine()&&('\"'==o||\"'\"==o)){var a=r.doc.getLine(i.start.row),s=a.substring(i.start.column+1,i.start.column+2);if(s==o)return i.end.column++,i}}),this.add(\"autoclosing\",\"insertion\",function(e,t,n,r,i){if(\">\"==i){var s=n.getSelectionRange().start,l=new o(r,s.row,s.column),c=l.getCurrentToken()||l.stepBackward();if(!c||!(a(c,\"tag-name\")||a(c,\"tag-whitespace\")||a(c,\"attribute-name\")||a(c,\"attribute-equals\")||a(c,\"attribute-value\")))return;if(a(c,\"reference.attribute-value\"))return;if(a(c,\"attribute-value\")){var u=c.value.charAt(0);if('\"'==u||\"'\"==u){var d=c.value.charAt(c.value.length-1),h=l.getCurrentTokenColumn()+c.value.length;if(h>s.column||h==s.column&&u!=d)return}}while(!a(c,\"tag-name\"))if(c=l.stepBackward(),\"<\"==c.value){c=l.stepForward();break}var p=l.getCurrentTokenRow(),m=l.getCurrentTokenColumn();if(a(l.stepBackward(),\"end-tag-open\"))return;var f=c.value;if(p==s.row&&(f=f.substring(0,s.column-m)),this.voidElements.hasOwnProperty(f.toLowerCase()))return;return{text:\"></\"+f+\">\",selection:[1,1]}}}),this.add(\"autoindent\",\"insertion\",function(e,t,n,r,i){if(\"\\n\"==i){var a=n.getCursorPosition(),s=r.getLine(a.row),l=new o(r,a.row,a.column),c=l.getCurrentToken();if(c&&-1!==c.type.indexOf(\"tag-close\")){if(\"/>\"==c.value)return;while(c&&-1===c.type.indexOf(\"tag-name\"))c=l.stepBackward();if(!c)return;var u=c.value,d=l.getCurrentTokenRow();if(c=l.stepBackward(),!c||-1!==c.type.indexOf(\"end-tag\"))return;if(this.voidElements&&!this.voidElements[u]){var h=r.getTokenAt(a.row,a.column+1),p=(s=r.getLine(d),this.$getIndent(s)),m=p+r.getTabString();return h&&\"</\"===h.value?{text:\"\\n\"+m+\"\\n\"+p,selection:[1,m.length,1,m.length]}:{text:\"\\n\"+m}}}}})};r.inherits(s,i),t.XmlBehaviour=s}),ace.define(\"ace/mode/folding/mixed\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/mode/folding/fold_mode\"],function(e,t,n){\"use strict\";var r=e(\"../../lib/oop\"),i=e(\"./fold_mode\").FoldMode,o=t.FoldMode=function(e,t){this.defaultMode=e,this.subModes=t};r.inherits(o,i),function(){this.$getMode=function(e){for(var t in\"string\"!=typeof e&&(e=e[0]),this.subModes)if(0===e.indexOf(t))return this.subModes[t];return null},this.$tryMode=function(e,t,n,r){var i=this.$getMode(e);return i?i.getFoldWidget(t,n,r):\"\"},this.getFoldWidget=function(e,t,n){return this.$tryMode(e.getState(n-1),e,t,n)||this.$tryMode(e.getState(n),e,t,n)||this.defaultMode.getFoldWidget(e,t,n)},this.getFoldWidgetRange=function(e,t,n){var r=this.$getMode(e.getState(n-1));return r&&r.getFoldWidget(e,t,n)||(r=this.$getMode(e.getState(n))),r&&r.getFoldWidget(e,t,n)||(r=this.defaultMode),r.getFoldWidgetRange(e,t,n)}}.call(o.prototype)}),ace.define(\"ace/mode/folding/xml\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/lib/lang\",\"ace/range\",\"ace/mode/folding/fold_mode\",\"ace/token_iterator\"],function(e,t,n){\"use strict\";var r=e(\"../../lib/oop\"),i=(e(\"../../lib/lang\"),e(\"../../range\").Range),o=e(\"./fold_mode\").FoldMode,a=e(\"../../token_iterator\").TokenIterator,s=t.FoldMode=function(e,t){o.call(this),this.voidElements=e||{},this.optionalEndTags=r.mixin({},this.voidElements),t&&r.mixin(this.optionalEndTags,t)};r.inherits(s,o);var l=function(){this.tagName=\"\",this.closing=!1,this.selfClosing=!1,this.start={row:0,column:0},this.end={row:0,column:0}};function c(e,t){return e.type.lastIndexOf(t+\".xml\")>-1}(function(){this.getFoldWidget=function(e,t,n){var r=this._getFirstTagInLine(e,n);return r?r.closing||!r.tagName&&r.selfClosing?\"markbeginend\"==t?\"end\":\"\":!r.tagName||r.selfClosing||this.voidElements.hasOwnProperty(r.tagName.toLowerCase())?\"\":this._findEndTagInLine(e,n,r.tagName,r.end.column)?\"\":\"start\":this.getCommentFoldWidget(e,n)},this.getCommentFoldWidget=function(e,t){return/comment/.test(e.getState(t))&&/<!-/.test(e.getLine(t))?\"start\":\"\"},this._getFirstTagInLine=function(e,t){for(var n=e.getTokens(t),r=new l,i=0;i<n.length;i++){var o=n[i];if(c(o,\"tag-open\")){if(r.end.column=r.start.column+o.value.length,r.closing=c(o,\"end-tag-open\"),o=n[++i],!o)return null;for(r.tagName=o.value,r.end.column+=o.value.length,i++;i<n.length;i++)if(o=n[i],r.end.column+=o.value.length,c(o,\"tag-close\")){r.selfClosing=\"/>\"==o.value;break}return r}if(c(o,\"tag-close\"))return r.selfClosing=\"/>\"==o.value,r;r.start.column+=o.value.length}return null},this._findEndTagInLine=function(e,t,n,r){for(var i=e.getTokens(t),o=0,a=0;a<i.length;a++){var s=i[a];if(o+=s.value.length,!(o<r)&&c(s,\"end-tag-open\")&&(s=i[a+1],s&&s.value==n))return!0}return!1},this._readTagForward=function(e){var t=e.getCurrentToken();if(!t)return null;var n=new l;do{if(c(t,\"tag-open\"))n.closing=c(t,\"end-tag-open\"),n.start.row=e.getCurrentTokenRow(),n.start.column=e.getCurrentTokenColumn();else if(c(t,\"tag-name\"))n.tagName=t.value;else if(c(t,\"tag-close\"))return n.selfClosing=\"/>\"==t.value,n.end.row=e.getCurrentTokenRow(),n.end.column=e.getCurrentTokenColumn()+t.value.length,e.stepForward(),n}while(t=e.stepForward());return null},this._readTagBackward=function(e){var t=e.getCurrentToken();if(!t)return null;var n=new l;do{if(c(t,\"tag-open\"))return n.closing=c(t,\"end-tag-open\"),n.start.row=e.getCurrentTokenRow(),n.start.column=e.getCurrentTokenColumn(),e.stepBackward(),n;c(t,\"tag-name\")?n.tagName=t.value:c(t,\"tag-close\")&&(n.selfClosing=\"/>\"==t.value,n.end.row=e.getCurrentTokenRow(),n.end.column=e.getCurrentTokenColumn()+t.value.length)}while(t=e.stepBackward());return null},this._pop=function(e,t){while(e.length){var n=e[e.length-1];if(t&&n.tagName!=t.tagName){if(this.optionalEndTags.hasOwnProperty(n.tagName)){e.pop();continue}return null}return e.pop()}},this.getFoldWidgetRange=function(e,t,n){var r=this._getFirstTagInLine(e,n);if(!r)return this.getCommentFoldWidget(e,n)&&e.getCommentFoldRange(n,e.getLine(n).length);var o,s=r.closing||r.selfClosing,l=[];if(s){u=new a(e,n,r.end.column);var c={row:n,column:r.start.column};while(o=this._readTagBackward(u)){if(o.selfClosing){if(l.length)continue;return o.start.column+=o.tagName.length+2,o.end.column-=2,i.fromPoints(o.start,o.end)}if(o.closing)l.push(o);else if(this._pop(l,o),0==l.length)return o.start.column+=o.tagName.length+2,o.start.row==o.end.row&&o.start.column<o.end.column&&(o.start.column=o.end.column),i.fromPoints(o.start,c)}}else{var u=new a(e,n,r.start.column),d={row:n,column:r.start.column+r.tagName.length+2};r.start.row==r.end.row&&(d.column=r.end.column);while(o=this._readTagForward(u)){if(o.selfClosing){if(l.length)continue;return o.start.column+=o.tagName.length+2,o.end.column-=2,i.fromPoints(o.start,o.end)}if(o.closing){if(this._pop(l,o),0==l.length)return i.fromPoints(d,o.start)}else l.push(o)}}}}).call(s.prototype)}),ace.define(\"ace/mode/folding/html\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/mode/folding/mixed\",\"ace/mode/folding/xml\",\"ace/mode/folding/cstyle\"],function(e,t,n){\"use strict\";var r=e(\"../../lib/oop\"),i=e(\"./mixed\").FoldMode,o=e(\"./xml\").FoldMode,a=e(\"./cstyle\").FoldMode,s=t.FoldMode=function(e,t){i.call(this,new o(e,t),{\"js-\":new a,\"css-\":new a})};r.inherits(s,i)}),ace.define(\"ace/mode/html_completions\",[\"require\",\"exports\",\"module\",\"ace/token_iterator\"],function(e,t,n){\"use strict\";var r=e(\"../token_iterator\").TokenIterator,i=[\"accesskey\",\"class\",\"contenteditable\",\"contextmenu\",\"dir\",\"draggable\",\"dropzone\",\"hidden\",\"id\",\"inert\",\"itemid\",\"itemprop\",\"itemref\",\"itemscope\",\"itemtype\",\"lang\",\"spellcheck\",\"style\",\"tabindex\",\"title\",\"translate\"],o=[\"onabort\",\"onblur\",\"oncancel\",\"oncanplay\",\"oncanplaythrough\",\"onchange\",\"onclick\",\"onclose\",\"oncontextmenu\",\"oncuechange\",\"ondblclick\",\"ondrag\",\"ondragend\",\"ondragenter\",\"ondragleave\",\"ondragover\",\"ondragstart\",\"ondrop\",\"ondurationchange\",\"onemptied\",\"onended\",\"onerror\",\"onfocus\",\"oninput\",\"oninvalid\",\"onkeydown\",\"onkeypress\",\"onkeyup\",\"onload\",\"onloadeddata\",\"onloadedmetadata\",\"onloadstart\",\"onmousedown\",\"onmousemove\",\"onmouseout\",\"onmouseover\",\"onmouseup\",\"onmousewheel\",\"onpause\",\"onplay\",\"onplaying\",\"onprogress\",\"onratechange\",\"onreset\",\"onscroll\",\"onseeked\",\"onseeking\",\"onselect\",\"onshow\",\"onstalled\",\"onsubmit\",\"onsuspend\",\"ontimeupdate\",\"onvolumechange\",\"onwaiting\"],a=i.concat(o),s={html:{manifest:1},head:{},title:{},base:{href:1,target:1},link:{href:1,hreflang:1,rel:{stylesheet:1,icon:1},media:{all:1,screen:1,print:1},type:{\"text/css\":1,\"image/png\":1,\"image/jpeg\":1,\"image/gif\":1},sizes:1},meta:{\"http-equiv\":{\"content-type\":1},name:{description:1,keywords:1},content:{\"text/html; charset=UTF-8\":1},charset:1},style:{type:1,media:{all:1,screen:1,print:1},scoped:1},script:{charset:1,type:{\"text/javascript\":1},src:1,defer:1,async:1},noscript:{href:1},body:{onafterprint:1,onbeforeprint:1,onbeforeunload:1,onhashchange:1,onmessage:1,onoffline:1,onpopstate:1,onredo:1,onresize:1,onstorage:1,onundo:1,onunload:1},section:{},nav:{},article:{pubdate:1},aside:{},h1:{},h2:{},h3:{},h4:{},h5:{},h6:{},header:{},footer:{},address:{},main:{},p:{},hr:{},pre:{},blockquote:{cite:1},ol:{start:1,reversed:1},ul:{},li:{value:1},dl:{},dt:{},dd:{},figure:{},figcaption:{},div:{},a:{href:1,target:{_blank:1,top:1},ping:1,rel:{nofollow:1,alternate:1,author:1,bookmark:1,help:1,license:1,next:1,noreferrer:1,prefetch:1,prev:1,search:1,tag:1},media:1,hreflang:1,type:1},em:{},strong:{},small:{},s:{},cite:{},q:{cite:1},dfn:{},abbr:{},data:{},time:{datetime:1},code:{},var:{},samp:{},kbd:{},sub:{},sup:{},i:{},b:{},u:{},mark:{},ruby:{},rt:{},rp:{},bdi:{},bdo:{},span:{},br:{},wbr:{},ins:{cite:1,datetime:1},del:{cite:1,datetime:1},img:{alt:1,src:1,height:1,width:1,usemap:1,ismap:1},iframe:{name:1,src:1,height:1,width:1,sandbox:{\"allow-same-origin\":1,\"allow-top-navigation\":1,\"allow-forms\":1,\"allow-scripts\":1},seamless:{seamless:1}},embed:{src:1,height:1,width:1,type:1},object:{param:1,data:1,type:1,height:1,width:1,usemap:1,name:1,form:1,classid:1},param:{name:1,value:1},video:{src:1,autobuffer:1,autoplay:{autoplay:1},loop:{loop:1},controls:{controls:1},width:1,height:1,poster:1,muted:{muted:1},preload:{auto:1,metadata:1,none:1}},audio:{src:1,autobuffer:1,autoplay:{autoplay:1},loop:{loop:1},controls:{controls:1},muted:{muted:1},preload:{auto:1,metadata:1,none:1}},source:{src:1,type:1,media:1},track:{kind:1,src:1,srclang:1,label:1,default:1},canvas:{width:1,height:1},map:{name:1},area:{shape:1,coords:1,href:1,hreflang:1,alt:1,target:1,media:1,rel:1,ping:1,type:1},svg:{},math:{},table:{summary:1},caption:{},colgroup:{span:1},col:{span:1},tbody:{},thead:{},tfoot:{},tr:{},td:{headers:1,rowspan:1,colspan:1},th:{headers:1,rowspan:1,colspan:1,scope:1},form:{\"accept-charset\":1,action:1,autocomplete:1,enctype:{\"multipart/form-data\":1,\"application/x-www-form-urlencoded\":1},method:{get:1,post:1},name:1,novalidate:1,target:{_blank:1,top:1}},fieldset:{disabled:1,form:1,name:1},legend:{},label:{form:1,for:1},input:{type:{text:1,password:1,hidden:1,checkbox:1,submit:1,radio:1,file:1,button:1,reset:1,image:31,color:1,date:1,datetime:1,\"datetime-local\":1,email:1,month:1,number:1,range:1,search:1,tel:1,time:1,url:1,week:1},accept:1,alt:1,autocomplete:{on:1,off:1},autofocus:{autofocus:1},checked:{checked:1},disabled:{disabled:1},form:1,formaction:1,formenctype:{\"application/x-www-form-urlencoded\":1,\"multipart/form-data\":1,\"text/plain\":1},formmethod:{get:1,post:1},formnovalidate:{formnovalidate:1},formtarget:{_blank:1,_self:1,_parent:1,_top:1},height:1,list:1,max:1,maxlength:1,min:1,multiple:{multiple:1},name:1,pattern:1,placeholder:1,readonly:{readonly:1},acequired:{acequired:1},size:1,src:1,step:1,width:1,files:1,value:1},button:{autofocus:1,disabled:{disabled:1},form:1,formaction:1,formenctype:1,formmethod:1,formnovalidate:1,formtarget:1,name:1,value:1,type:{button:1,submit:1}},select:{autofocus:1,disabled:1,form:1,multiple:{multiple:1},name:1,size:1,readonly:{readonly:1}},datalist:{},optgroup:{disabled:1,label:1},option:{disabled:1,selected:1,label:1,value:1},textarea:{autofocus:{autofocus:1},disabled:{disabled:1},form:1,maxlength:1,name:1,placeholder:1,readonly:{readonly:1},acequired:{acequired:1},rows:1,cols:1,wrap:{on:1,off:1,hard:1,soft:1}},keygen:{autofocus:1,challenge:{challenge:1},disabled:{disabled:1},form:1,keytype:{rsa:1,dsa:1,ec:1},name:1},output:{for:1,form:1,name:1},progress:{value:1,max:1},meter:{value:1,min:1,max:1,low:1,high:1,optimum:1},details:{open:1},summary:{},command:{type:1,label:1,icon:1,disabled:1,checked:1,radiogroup:1,command:1},menu:{type:1,label:1},dialog:{open:1}},l=Object.keys(s);function c(e,t){return e.type.lastIndexOf(t+\".xml\")>-1}function u(e,t){var n=new r(e,t.row,t.column),i=n.getCurrentToken();while(i&&!c(i,\"tag-name\"))i=n.stepBackward();if(i)return i.value}function d(e,t){var n=new r(e,t.row,t.column),i=n.getCurrentToken();while(i&&!c(i,\"attribute-name\"))i=n.stepBackward();if(i)return i.value}var h=function(){};(function(){this.getCompletions=function(e,t,n,r){var i=t.getTokenAt(n.row,n.column);if(!i)return[];if(c(i,\"tag-name\")||c(i,\"tag-open\")||c(i,\"end-tag-open\"))return this.getTagCompletions(e,t,n,r);if(c(i,\"tag-whitespace\")||c(i,\"attribute-name\"))return this.getAttributeCompletions(e,t,n,r);if(c(i,\"attribute-value\"))return this.getAttributeValueCompletions(e,t,n,r);var o=t.getLine(n.row).substr(0,n.column);return/&[a-z]*$/i.test(o)?this.getHTMLEntityCompletions(e,t,n,r):[]},this.getTagCompletions=function(e,t,n,r){return l.map(function(e){return{value:e,meta:\"tag\",score:Number.MAX_VALUE}})},this.getAttributeCompletions=function(e,t,n,r){var i=u(t,n);if(!i)return[];var o=a;return i in s&&(o=o.concat(Object.keys(s[i]))),o.map(function(e){return{caption:e,snippet:e+'=\"$0\"',meta:\"attribute\",score:Number.MAX_VALUE}})},this.getAttributeValueCompletions=function(e,t,n,r){var i=u(t,n),o=d(t,n);if(!i)return[];var a=[];return i in s&&o in s[i]&&\"object\"===typeof s[i][o]&&(a=Object.keys(s[i][o])),a.map(function(e){return{caption:e,snippet:e,meta:\"attribute value\",score:Number.MAX_VALUE}})},this.getHTMLEntityCompletions=function(e,t,n,r){var i=[\"Aacute;\",\"aacute;\",\"Acirc;\",\"acirc;\",\"acute;\",\"AElig;\",\"aelig;\",\"Agrave;\",\"agrave;\",\"alefsym;\",\"Alpha;\",\"alpha;\",\"amp;\",\"and;\",\"ang;\",\"Aring;\",\"aring;\",\"asymp;\",\"Atilde;\",\"atilde;\",\"Auml;\",\"auml;\",\"bdquo;\",\"Beta;\",\"beta;\",\"brvbar;\",\"bull;\",\"cap;\",\"Ccedil;\",\"ccedil;\",\"cedil;\",\"cent;\",\"Chi;\",\"chi;\",\"circ;\",\"clubs;\",\"cong;\",\"copy;\",\"crarr;\",\"cup;\",\"curren;\",\"Dagger;\",\"dagger;\",\"dArr;\",\"darr;\",\"deg;\",\"Delta;\",\"delta;\",\"diams;\",\"divide;\",\"Eacute;\",\"eacute;\",\"Ecirc;\",\"ecirc;\",\"Egrave;\",\"egrave;\",\"empty;\",\"emsp;\",\"ensp;\",\"Epsilon;\",\"epsilon;\",\"equiv;\",\"Eta;\",\"eta;\",\"ETH;\",\"eth;\",\"Euml;\",\"euml;\",\"euro;\",\"exist;\",\"fnof;\",\"forall;\",\"frac12;\",\"frac14;\",\"frac34;\",\"frasl;\",\"Gamma;\",\"gamma;\",\"ge;\",\"gt;\",\"hArr;\",\"harr;\",\"hearts;\",\"hellip;\",\"Iacute;\",\"iacute;\",\"Icirc;\",\"icirc;\",\"iexcl;\",\"Igrave;\",\"igrave;\",\"image;\",\"infin;\",\"int;\",\"Iota;\",\"iota;\",\"iquest;\",\"isin;\",\"Iuml;\",\"iuml;\",\"Kappa;\",\"kappa;\",\"Lambda;\",\"lambda;\",\"lang;\",\"laquo;\",\"lArr;\",\"larr;\",\"lceil;\",\"ldquo;\",\"le;\",\"lfloor;\",\"lowast;\",\"loz;\",\"lrm;\",\"lsaquo;\",\"lsquo;\",\"lt;\",\"macr;\",\"mdash;\",\"micro;\",\"middot;\",\"minus;\",\"Mu;\",\"mu;\",\"nabla;\",\"nbsp;\",\"ndash;\",\"ne;\",\"ni;\",\"not;\",\"notin;\",\"nsub;\",\"Ntilde;\",\"ntilde;\",\"Nu;\",\"nu;\",\"Oacute;\",\"oacute;\",\"Ocirc;\",\"ocirc;\",\"OElig;\",\"oelig;\",\"Ograve;\",\"ograve;\",\"oline;\",\"Omega;\",\"omega;\",\"Omicron;\",\"omicron;\",\"oplus;\",\"or;\",\"ordf;\",\"ordm;\",\"Oslash;\",\"oslash;\",\"Otilde;\",\"otilde;\",\"otimes;\",\"Ouml;\",\"ouml;\",\"para;\",\"part;\",\"permil;\",\"perp;\",\"Phi;\",\"phi;\",\"Pi;\",\"pi;\",\"piv;\",\"plusmn;\",\"pound;\",\"Prime;\",\"prime;\",\"prod;\",\"prop;\",\"Psi;\",\"psi;\",\"quot;\",\"radic;\",\"rang;\",\"raquo;\",\"rArr;\",\"rarr;\",\"rceil;\",\"rdquo;\",\"real;\",\"reg;\",\"rfloor;\",\"Rho;\",\"rho;\",\"rlm;\",\"rsaquo;\",\"rsquo;\",\"sbquo;\",\"Scaron;\",\"scaron;\",\"sdot;\",\"sect;\",\"shy;\",\"Sigma;\",\"sigma;\",\"sigmaf;\",\"sim;\",\"spades;\",\"sub;\",\"sube;\",\"sum;\",\"sup;\",\"sup1;\",\"sup2;\",\"sup3;\",\"supe;\",\"szlig;\",\"Tau;\",\"tau;\",\"there4;\",\"Theta;\",\"theta;\",\"thetasym;\",\"thinsp;\",\"THORN;\",\"thorn;\",\"tilde;\",\"times;\",\"trade;\",\"Uacute;\",\"uacute;\",\"uArr;\",\"uarr;\",\"Ucirc;\",\"ucirc;\",\"Ugrave;\",\"ugrave;\",\"uml;\",\"upsih;\",\"Upsilon;\",\"upsilon;\",\"Uuml;\",\"uuml;\",\"weierp;\",\"Xi;\",\"xi;\",\"Yacute;\",\"yacute;\",\"yen;\",\"Yuml;\",\"yuml;\",\"Zeta;\",\"zeta;\",\"zwj;\",\"zwnj;\"];return i.map(function(e){return{caption:e,snippet:e,meta:\"html entity\",score:Number.MAX_VALUE}})}}).call(h.prototype),t.HtmlCompletions=h}),ace.define(\"ace/mode/html\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/lib/lang\",\"ace/mode/text\",\"ace/mode/javascript\",\"ace/mode/css\",\"ace/mode/html_highlight_rules\",\"ace/mode/behaviour/xml\",\"ace/mode/folding/html\",\"ace/mode/html_completions\",\"ace/worker/worker_client\"],function(e,t,r){\"use strict\";var i=e(\"../lib/oop\"),o=e(\"../lib/lang\"),a=e(\"./text\").Mode,s=e(\"./javascript\").Mode,l=e(\"./css\").Mode,c=e(\"./html_highlight_rules\").HtmlHighlightRules,u=e(\"./behaviour/xml\").XmlBehaviour,d=e(\"./folding/html\").FoldMode,h=e(\"./html_completions\").HtmlCompletions,p=e(\"../worker/worker_client\").WorkerClient,m=[\"area\",\"base\",\"br\",\"col\",\"embed\",\"hr\",\"img\",\"input\",\"keygen\",\"link\",\"meta\",\"menuitem\",\"param\",\"source\",\"track\",\"wbr\"],f=[\"li\",\"dt\",\"dd\",\"p\",\"rt\",\"rp\",\"optgroup\",\"option\",\"colgroup\",\"td\",\"th\"],g=function(e){this.fragmentContext=e&&e.fragmentContext,this.HighlightRules=c,this.$behaviour=new u,this.$completer=new h,this.createModeDelegates({\"js-\":s,\"css-\":l}),this.foldingRules=new d(this.voidElements,o.arrayToMap(f))};i.inherits(g,a),function(){this.blockComment={start:\"\\x3c!--\",end:\"--\\x3e\"},this.voidElements=o.arrayToMap(m),this.getNextLineIndent=function(e,t,n){return this.$getIndent(t)},this.checkOutdent=function(e,t,n){return!1},this.getCompletions=function(e,t,n,r){return this.$completer.getCompletions(e,t,n,r)},this.createWorker=function(e){if(this.constructor==g){var t=new p([\"ace\"],n(\"d57c\"),\"Worker\");return t.attachToDocument(e.getDocument()),this.fragmentContext&&t.call(\"setOptions\",[{context:this.fragmentContext}]),t.on(\"error\",function(t){e.setAnnotations(t.data)}),t.on(\"terminate\",function(){e.clearAnnotations()}),t}},this.$id=\"ace/mode/html\"}.call(g.prototype),t.Mode=g})},d57c:function(e,t){e.exports.id=\"ace/mode/html_worker\",e.exports.src='\"no use strict\";!function(window){function resolveModuleId(id,paths){for(var testPath=id,tail=\"\";testPath;){var alias=paths[testPath];if(\"string\"==typeof alias)return alias+tail;if(alias)return alias.location.replace(/\\\\/*$/,\"/\")+(tail||alias.main||alias.name);if(alias===!1)return\"\";var i=testPath.lastIndexOf(\"/\");if(-1===i)break;tail=testPath.substr(i)+tail,testPath=testPath.slice(0,i)}return id}if(!(void 0!==window.window&&window.document||window.acequire&&window.define)){window.console||(window.console=function(){var msgs=Array.prototype.slice.call(arguments,0);postMessage({type:\"log\",data:msgs})},window.console.error=window.console.warn=window.console.log=window.console.trace=window.console),window.window=window,window.ace=window,window.onerror=function(message,file,line,col,err){postMessage({type:\"error\",data:{message:message,data:err.data,file:file,line:line,col:col,stack:err.stack}})},window.normalizeModule=function(parentId,moduleName){if(-1!==moduleName.indexOf(\"!\")){var chunks=moduleName.split(\"!\");return window.normalizeModule(parentId,chunks[0])+\"!\"+window.normalizeModule(parentId,chunks[1])}if(\".\"==moduleName.charAt(0)){var base=parentId.split(\"/\").slice(0,-1).join(\"/\");for(moduleName=(base?base+\"/\":\"\")+moduleName;-1!==moduleName.indexOf(\".\")&&previous!=moduleName;){var previous=moduleName;moduleName=moduleName.replace(/^\\\\.\\\\//,\"\").replace(/\\\\/\\\\.\\\\//,\"/\").replace(/[^\\\\/]+\\\\/\\\\.\\\\.\\\\//,\"\")}}return moduleName},window.acequire=function acequire(parentId,id){if(id||(id=parentId,parentId=null),!id.charAt)throw Error(\"worker.js acequire() accepts only (parentId, id) as arguments\");id=window.normalizeModule(parentId,id);var module=window.acequire.modules[id];if(module)return module.initialized||(module.initialized=!0,module.exports=module.factory().exports),module.exports;if(!window.acequire.tlns)return console.log(\"unable to load \"+id);var path=resolveModuleId(id,window.acequire.tlns);return\".js\"!=path.slice(-3)&&(path+=\".js\"),window.acequire.id=id,window.acequire.modules[id]={},importScripts(path),window.acequire(parentId,id)},window.acequire.modules={},window.acequire.tlns={},window.define=function(id,deps,factory){if(2==arguments.length?(factory=deps,\"string\"!=typeof id&&(deps=id,id=window.acequire.id)):1==arguments.length&&(factory=id,deps=[],id=window.acequire.id),\"function\"!=typeof factory)return window.acequire.modules[id]={exports:factory,initialized:!0},void 0;deps.length||(deps=[\"require\",\"exports\",\"module\"]);var req=function(childId){return window.acequire(id,childId)};window.acequire.modules[id]={exports:{},factory:function(){var module=this,returnExports=factory.apply(this,deps.map(function(dep){switch(dep){case\"require\":return req;case\"exports\":return module.exports;case\"module\":return module;default:return req(dep)}}));return returnExports&&(module.exports=returnExports),module}}},window.define.amd={},acequire.tlns={},window.initBaseUrls=function(topLevelNamespaces){for(var i in topLevelNamespaces)acequire.tlns[i]=topLevelNamespaces[i]},window.initSender=function(){var EventEmitter=window.acequire(\"ace/lib/event_emitter\").EventEmitter,oop=window.acequire(\"ace/lib/oop\"),Sender=function(){};return function(){oop.implement(this,EventEmitter),this.callback=function(data,callbackId){postMessage({type:\"call\",id:callbackId,data:data})},this.emit=function(name,data){postMessage({type:\"event\",name:name,data:data})}}.call(Sender.prototype),new Sender};var main=window.main=null,sender=window.sender=null;window.onmessage=function(e){var msg=e.data;if(msg.event&&sender)sender._signal(msg.event,msg.data);else if(msg.command)if(main[msg.command])main[msg.command].apply(main,msg.args);else{if(!window[msg.command])throw Error(\"Unknown command:\"+msg.command);window[msg.command].apply(window,msg.args)}else if(msg.init){window.initBaseUrls(msg.tlns),acequire(\"ace/lib/es5-shim\"),sender=window.sender=window.initSender();var clazz=acequire(msg.module)[msg.classname];main=window.main=new clazz(sender)}}}}(this),ace.define(\"ace/lib/oop\",[\"require\",\"exports\",\"module\"],function(acequire,exports){\"use strict\";exports.inherits=function(ctor,superCtor){ctor.super_=superCtor,ctor.prototype=Object.create(superCtor.prototype,{constructor:{value:ctor,enumerable:!1,writable:!0,configurable:!0}})},exports.mixin=function(obj,mixin){for(var key in mixin)obj[key]=mixin[key];return obj},exports.implement=function(proto,mixin){exports.mixin(proto,mixin)}}),ace.define(\"ace/lib/lang\",[\"require\",\"exports\",\"module\"],function(acequire,exports){\"use strict\";exports.last=function(a){return a[a.length-1]},exports.stringReverse=function(string){return string.split(\"\").reverse().join(\"\")},exports.stringRepeat=function(string,count){for(var result=\"\";count>0;)1&count&&(result+=string),(count>>=1)&&(string+=string);return result};var trimBeginRegexp=/^\\\\s\\\\s*/,trimEndRegexp=/\\\\s\\\\s*$/;exports.stringTrimLeft=function(string){return string.replace(trimBeginRegexp,\"\")},exports.stringTrimRight=function(string){return string.replace(trimEndRegexp,\"\")},exports.copyObject=function(obj){var copy={};for(var key in obj)copy[key]=obj[key];return copy},exports.copyArray=function(array){for(var copy=[],i=0,l=array.length;l>i;i++)copy[i]=array[i]&&\"object\"==typeof array[i]?this.copyObject(array[i]):array[i];return copy},exports.deepCopy=function deepCopy(obj){if(\"object\"!=typeof obj||!obj)return obj;var copy;if(Array.isArray(obj)){copy=[];for(var key=0;obj.length>key;key++)copy[key]=deepCopy(obj[key]);return copy}if(\"[object Object]\"!==Object.prototype.toString.call(obj))return obj;copy={};for(var key in obj)copy[key]=deepCopy(obj[key]);return copy},exports.arrayToMap=function(arr){for(var map={},i=0;arr.length>i;i++)map[arr[i]]=1;return map},exports.createMap=function(props){var map=Object.create(null);for(var i in props)map[i]=props[i];return map},exports.arrayRemove=function(array,value){for(var i=0;array.length>=i;i++)value===array[i]&&array.splice(i,1)},exports.escapeRegExp=function(str){return str.replace(/([.*+?^${}()|[\\\\]\\\\/\\\\\\\\])/g,\"\\\\\\\\$1\")},exports.escapeHTML=function(str){return str.replace(/&/g,\"&#38;\").replace(/\"/g,\"&#34;\").replace(/\\'/g,\"&#39;\").replace(/</g,\"&#60;\")},exports.getMatchOffsets=function(string,regExp){var matches=[];return string.replace(regExp,function(str){matches.push({offset:arguments[arguments.length-2],length:str.length})}),matches},exports.deferredCall=function(fcn){var timer=null,callback=function(){timer=null,fcn()},deferred=function(timeout){return deferred.cancel(),timer=setTimeout(callback,timeout||0),deferred};return deferred.schedule=deferred,deferred.call=function(){return this.cancel(),fcn(),deferred},deferred.cancel=function(){return clearTimeout(timer),timer=null,deferred},deferred.isPending=function(){return timer},deferred},exports.delayedCall=function(fcn,defaultTimeout){var timer=null,callback=function(){timer=null,fcn()},_self=function(timeout){null==timer&&(timer=setTimeout(callback,timeout||defaultTimeout))};return _self.delay=function(timeout){timer&&clearTimeout(timer),timer=setTimeout(callback,timeout||defaultTimeout)},_self.schedule=_self,_self.call=function(){this.cancel(),fcn()},_self.cancel=function(){timer&&clearTimeout(timer),timer=null},_self.isPending=function(){return timer},_self}}),ace.define(\"ace/range\",[\"require\",\"exports\",\"module\"],function(acequire,exports){\"use strict\";var comparePoints=function(p1,p2){return p1.row-p2.row||p1.column-p2.column},Range=function(startRow,startColumn,endRow,endColumn){this.start={row:startRow,column:startColumn},this.end={row:endRow,column:endColumn}};(function(){this.isEqual=function(range){return this.start.row===range.start.row&&this.end.row===range.end.row&&this.start.column===range.start.column&&this.end.column===range.end.column},this.toString=function(){return\"Range: [\"+this.start.row+\"/\"+this.start.column+\"] -> [\"+this.end.row+\"/\"+this.end.column+\"]\"},this.contains=function(row,column){return 0==this.compare(row,column)},this.compareRange=function(range){var cmp,end=range.end,start=range.start;return cmp=this.compare(end.row,end.column),1==cmp?(cmp=this.compare(start.row,start.column),1==cmp?2:0==cmp?1:0):-1==cmp?-2:(cmp=this.compare(start.row,start.column),-1==cmp?-1:1==cmp?42:0)},this.comparePoint=function(p){return this.compare(p.row,p.column)},this.containsRange=function(range){return 0==this.comparePoint(range.start)&&0==this.comparePoint(range.end)},this.intersects=function(range){var cmp=this.compareRange(range);return-1==cmp||0==cmp||1==cmp},this.isEnd=function(row,column){return this.end.row==row&&this.end.column==column},this.isStart=function(row,column){return this.start.row==row&&this.start.column==column},this.setStart=function(row,column){\"object\"==typeof row?(this.start.column=row.column,this.start.row=row.row):(this.start.row=row,this.start.column=column)},this.setEnd=function(row,column){\"object\"==typeof row?(this.end.column=row.column,this.end.row=row.row):(this.end.row=row,this.end.column=column)},this.inside=function(row,column){return 0==this.compare(row,column)?this.isEnd(row,column)||this.isStart(row,column)?!1:!0:!1},this.insideStart=function(row,column){return 0==this.compare(row,column)?this.isEnd(row,column)?!1:!0:!1},this.insideEnd=function(row,column){return 0==this.compare(row,column)?this.isStart(row,column)?!1:!0:!1},this.compare=function(row,column){return this.isMultiLine()||row!==this.start.row?this.start.row>row?-1:row>this.end.row?1:this.start.row===row?column>=this.start.column?0:-1:this.end.row===row?this.end.column>=column?0:1:0:this.start.column>column?-1:column>this.end.column?1:0},this.compareStart=function(row,column){return this.start.row==row&&this.start.column==column?-1:this.compare(row,column)},this.compareEnd=function(row,column){return this.end.row==row&&this.end.column==column?1:this.compare(row,column)},this.compareInside=function(row,column){return this.end.row==row&&this.end.column==column?1:this.start.row==row&&this.start.column==column?-1:this.compare(row,column)},this.clipRows=function(firstRow,lastRow){if(this.end.row>lastRow)var end={row:lastRow+1,column:0};else if(firstRow>this.end.row)var end={row:firstRow,column:0};if(this.start.row>lastRow)var start={row:lastRow+1,column:0};else if(firstRow>this.start.row)var start={row:firstRow,column:0};return Range.fromPoints(start||this.start,end||this.end)},this.extend=function(row,column){var cmp=this.compare(row,column);if(0==cmp)return this;if(-1==cmp)var start={row:row,column:column};else var end={row:row,column:column};return Range.fromPoints(start||this.start,end||this.end)},this.isEmpty=function(){return this.start.row===this.end.row&&this.start.column===this.end.column},this.isMultiLine=function(){return this.start.row!==this.end.row},this.clone=function(){return Range.fromPoints(this.start,this.end)},this.collapseRows=function(){return 0==this.end.column?new Range(this.start.row,0,Math.max(this.start.row,this.end.row-1),0):new Range(this.start.row,0,this.end.row,0)},this.toScreenRange=function(session){var screenPosStart=session.documentToScreenPosition(this.start),screenPosEnd=session.documentToScreenPosition(this.end);return new Range(screenPosStart.row,screenPosStart.column,screenPosEnd.row,screenPosEnd.column)},this.moveBy=function(row,column){this.start.row+=row,this.start.column+=column,this.end.row+=row,this.end.column+=column}}).call(Range.prototype),Range.fromPoints=function(start,end){return new Range(start.row,start.column,end.row,end.column)},Range.comparePoints=comparePoints,Range.comparePoints=function(p1,p2){return p1.row-p2.row||p1.column-p2.column},exports.Range=Range}),ace.define(\"ace/apply_delta\",[\"require\",\"exports\",\"module\"],function(acequire,exports){\"use strict\";exports.applyDelta=function(docLines,delta){var row=delta.start.row,startColumn=delta.start.column,line=docLines[row]||\"\";switch(delta.action){case\"insert\":var lines=delta.lines;if(1===lines.length)docLines[row]=line.substring(0,startColumn)+delta.lines[0]+line.substring(startColumn);else{var args=[row,1].concat(delta.lines);docLines.splice.apply(docLines,args),docLines[row]=line.substring(0,startColumn)+docLines[row],docLines[row+delta.lines.length-1]+=line.substring(startColumn)}break;case\"remove\":var endColumn=delta.end.column,endRow=delta.end.row;row===endRow?docLines[row]=line.substring(0,startColumn)+line.substring(endColumn):docLines.splice(row,endRow-row+1,line.substring(0,startColumn)+docLines[endRow].substring(endColumn))}}}),ace.define(\"ace/lib/event_emitter\",[\"require\",\"exports\",\"module\"],function(acequire,exports){\"use strict\";var EventEmitter={},stopPropagation=function(){this.propagationStopped=!0},preventDefault=function(){this.defaultPrevented=!0};EventEmitter._emit=EventEmitter._dispatchEvent=function(eventName,e){this._eventRegistry||(this._eventRegistry={}),this._defaultHandlers||(this._defaultHandlers={});var listeners=this._eventRegistry[eventName]||[],defaultHandler=this._defaultHandlers[eventName];if(listeners.length||defaultHandler){\"object\"==typeof e&&e||(e={}),e.type||(e.type=eventName),e.stopPropagation||(e.stopPropagation=stopPropagation),e.preventDefault||(e.preventDefault=preventDefault),listeners=listeners.slice();for(var i=0;listeners.length>i&&(listeners[i](e,this),!e.propagationStopped);i++);return defaultHandler&&!e.defaultPrevented?defaultHandler(e,this):void 0}},EventEmitter._signal=function(eventName,e){var listeners=(this._eventRegistry||{})[eventName];if(listeners){listeners=listeners.slice();for(var i=0;listeners.length>i;i++)listeners[i](e,this)}},EventEmitter.once=function(eventName,callback){var _self=this;callback&&this.addEventListener(eventName,function newCallback(){_self.removeEventListener(eventName,newCallback),callback.apply(null,arguments)})},EventEmitter.setDefaultHandler=function(eventName,callback){var handlers=this._defaultHandlers;if(handlers||(handlers=this._defaultHandlers={_disabled_:{}}),handlers[eventName]){var old=handlers[eventName],disabled=handlers._disabled_[eventName];disabled||(handlers._disabled_[eventName]=disabled=[]),disabled.push(old);var i=disabled.indexOf(callback);-1!=i&&disabled.splice(i,1)}handlers[eventName]=callback},EventEmitter.removeDefaultHandler=function(eventName,callback){var handlers=this._defaultHandlers;if(handlers){var disabled=handlers._disabled_[eventName];if(handlers[eventName]==callback)handlers[eventName],disabled&&this.setDefaultHandler(eventName,disabled.pop());else if(disabled){var i=disabled.indexOf(callback);-1!=i&&disabled.splice(i,1)}}},EventEmitter.on=EventEmitter.addEventListener=function(eventName,callback,capturing){this._eventRegistry=this._eventRegistry||{};var listeners=this._eventRegistry[eventName];return listeners||(listeners=this._eventRegistry[eventName]=[]),-1==listeners.indexOf(callback)&&listeners[capturing?\"unshift\":\"push\"](callback),callback},EventEmitter.off=EventEmitter.removeListener=EventEmitter.removeEventListener=function(eventName,callback){this._eventRegistry=this._eventRegistry||{};var listeners=this._eventRegistry[eventName];if(listeners){var index=listeners.indexOf(callback);-1!==index&&listeners.splice(index,1)}},EventEmitter.removeAllListeners=function(eventName){this._eventRegistry&&(this._eventRegistry[eventName]=[])},exports.EventEmitter=EventEmitter}),ace.define(\"ace/anchor\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/lib/event_emitter\"],function(acequire,exports){\"use strict\";var oop=acequire(\"./lib/oop\"),EventEmitter=acequire(\"./lib/event_emitter\").EventEmitter,Anchor=exports.Anchor=function(doc,row,column){this.$onChange=this.onChange.bind(this),this.attach(doc),column===void 0?this.setPosition(row.row,row.column):this.setPosition(row,column)};(function(){function $pointsInOrder(point1,point2,equalPointsInOrder){var bColIsAfter=equalPointsInOrder?point1.column<=point2.column:point1.column<point2.column;return point1.row<point2.row||point1.row==point2.row&&bColIsAfter}function $getTransformedPoint(delta,point,moveIfEqual){var deltaIsInsert=\"insert\"==delta.action,deltaRowShift=(deltaIsInsert?1:-1)*(delta.end.row-delta.start.row),deltaColShift=(deltaIsInsert?1:-1)*(delta.end.column-delta.start.column),deltaStart=delta.start,deltaEnd=deltaIsInsert?deltaStart:delta.end;return $pointsInOrder(point,deltaStart,moveIfEqual)?{row:point.row,column:point.column}:$pointsInOrder(deltaEnd,point,!moveIfEqual)?{row:point.row+deltaRowShift,column:point.column+(point.row==deltaEnd.row?deltaColShift:0)}:{row:deltaStart.row,column:deltaStart.column}}oop.implement(this,EventEmitter),this.getPosition=function(){return this.$clipPositionToDocument(this.row,this.column)},this.getDocument=function(){return this.document},this.$insertRight=!1,this.onChange=function(delta){if(!(delta.start.row==delta.end.row&&delta.start.row!=this.row||delta.start.row>this.row)){var point=$getTransformedPoint(delta,{row:this.row,column:this.column},this.$insertRight);this.setPosition(point.row,point.column,!0)}},this.setPosition=function(row,column,noClip){var pos;if(pos=noClip?{row:row,column:column}:this.$clipPositionToDocument(row,column),this.row!=pos.row||this.column!=pos.column){var old={row:this.row,column:this.column};this.row=pos.row,this.column=pos.column,this._signal(\"change\",{old:old,value:pos})}},this.detach=function(){this.document.removeEventListener(\"change\",this.$onChange)},this.attach=function(doc){this.document=doc||this.document,this.document.on(\"change\",this.$onChange)},this.$clipPositionToDocument=function(row,column){var pos={};return row>=this.document.getLength()?(pos.row=Math.max(0,this.document.getLength()-1),pos.column=this.document.getLine(pos.row).length):0>row?(pos.row=0,pos.column=0):(pos.row=row,pos.column=Math.min(this.document.getLine(pos.row).length,Math.max(0,column))),0>column&&(pos.column=0),pos}}).call(Anchor.prototype)}),ace.define(\"ace/document\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/apply_delta\",\"ace/lib/event_emitter\",\"ace/range\",\"ace/anchor\"],function(acequire,exports){\"use strict\";var oop=acequire(\"./lib/oop\"),applyDelta=acequire(\"./apply_delta\").applyDelta,EventEmitter=acequire(\"./lib/event_emitter\").EventEmitter,Range=acequire(\"./range\").Range,Anchor=acequire(\"./anchor\").Anchor,Document=function(textOrLines){this.$lines=[\"\"],0===textOrLines.length?this.$lines=[\"\"]:Array.isArray(textOrLines)?this.insertMergedLines({row:0,column:0},textOrLines):this.insert({row:0,column:0},textOrLines)};(function(){oop.implement(this,EventEmitter),this.setValue=function(text){var len=this.getLength()-1;this.remove(new Range(0,0,len,this.getLine(len).length)),this.insert({row:0,column:0},text)},this.getValue=function(){return this.getAllLines().join(this.getNewLineCharacter())},this.createAnchor=function(row,column){return new Anchor(this,row,column)},this.$split=0===\"aaa\".split(/a/).length?function(text){return text.replace(/\\\\r\\\\n|\\\\r/g,\"\\\\n\").split(\"\\\\n\")}:function(text){return text.split(/\\\\r\\\\n|\\\\r|\\\\n/)},this.$detectNewLine=function(text){var match=text.match(/^.*?(\\\\r\\\\n|\\\\r|\\\\n)/m);this.$autoNewLine=match?match[1]:\"\\\\n\",this._signal(\"changeNewLineMode\")},this.getNewLineCharacter=function(){switch(this.$newLineMode){case\"windows\":return\"\\\\r\\\\n\";case\"unix\":return\"\\\\n\";default:return this.$autoNewLine||\"\\\\n\"}},this.$autoNewLine=\"\",this.$newLineMode=\"auto\",this.setNewLineMode=function(newLineMode){this.$newLineMode!==newLineMode&&(this.$newLineMode=newLineMode,this._signal(\"changeNewLineMode\"))},this.getNewLineMode=function(){return this.$newLineMode},this.isNewLine=function(text){return\"\\\\r\\\\n\"==text||\"\\\\r\"==text||\"\\\\n\"==text},this.getLine=function(row){return this.$lines[row]||\"\"},this.getLines=function(firstRow,lastRow){return this.$lines.slice(firstRow,lastRow+1)},this.getAllLines=function(){return this.getLines(0,this.getLength())},this.getLength=function(){return this.$lines.length},this.getTextRange=function(range){return this.getLinesForRange(range).join(this.getNewLineCharacter())},this.getLinesForRange=function(range){var lines;if(range.start.row===range.end.row)lines=[this.getLine(range.start.row).substring(range.start.column,range.end.column)];else{lines=this.getLines(range.start.row,range.end.row),lines[0]=(lines[0]||\"\").substring(range.start.column);var l=lines.length-1;range.end.row-range.start.row==l&&(lines[l]=lines[l].substring(0,range.end.column))}return lines},this.insertLines=function(row,lines){return console.warn(\"Use of document.insertLines is deprecated. Use the insertFullLines method instead.\"),this.insertFullLines(row,lines)},this.removeLines=function(firstRow,lastRow){return console.warn(\"Use of document.removeLines is deprecated. Use the removeFullLines method instead.\"),this.removeFullLines(firstRow,lastRow)},this.insertNewLine=function(position){return console.warn(\"Use of document.insertNewLine is deprecated. Use insertMergedLines(position, [\\'\\', \\'\\']) instead.\"),this.insertMergedLines(position,[\"\",\"\"])},this.insert=function(position,text){return 1>=this.getLength()&&this.$detectNewLine(text),this.insertMergedLines(position,this.$split(text))},this.insertInLine=function(position,text){var start=this.clippedPos(position.row,position.column),end=this.pos(position.row,position.column+text.length);return this.applyDelta({start:start,end:end,action:\"insert\",lines:[text]},!0),this.clonePos(end)},this.clippedPos=function(row,column){var length=this.getLength();void 0===row?row=length:0>row?row=0:row>=length&&(row=length-1,column=void 0);var line=this.getLine(row);return void 0==column&&(column=line.length),column=Math.min(Math.max(column,0),line.length),{row:row,column:column}},this.clonePos=function(pos){return{row:pos.row,column:pos.column}},this.pos=function(row,column){return{row:row,column:column}},this.$clipPosition=function(position){var length=this.getLength();return position.row>=length?(position.row=Math.max(0,length-1),position.column=this.getLine(length-1).length):(position.row=Math.max(0,position.row),position.column=Math.min(Math.max(position.column,0),this.getLine(position.row).length)),position},this.insertFullLines=function(row,lines){row=Math.min(Math.max(row,0),this.getLength());var column=0;this.getLength()>row?(lines=lines.concat([\"\"]),column=0):(lines=[\"\"].concat(lines),row--,column=this.$lines[row].length),this.insertMergedLines({row:row,column:column},lines)},this.insertMergedLines=function(position,lines){var start=this.clippedPos(position.row,position.column),end={row:start.row+lines.length-1,column:(1==lines.length?start.column:0)+lines[lines.length-1].length};return this.applyDelta({start:start,end:end,action:\"insert\",lines:lines}),this.clonePos(end)},this.remove=function(range){var start=this.clippedPos(range.start.row,range.start.column),end=this.clippedPos(range.end.row,range.end.column);return this.applyDelta({start:start,end:end,action:\"remove\",lines:this.getLinesForRange({start:start,end:end})}),this.clonePos(start)},this.removeInLine=function(row,startColumn,endColumn){var start=this.clippedPos(row,startColumn),end=this.clippedPos(row,endColumn);return this.applyDelta({start:start,end:end,action:\"remove\",lines:this.getLinesForRange({start:start,end:end})},!0),this.clonePos(start)},this.removeFullLines=function(firstRow,lastRow){firstRow=Math.min(Math.max(0,firstRow),this.getLength()-1),lastRow=Math.min(Math.max(0,lastRow),this.getLength()-1);var deleteFirstNewLine=lastRow==this.getLength()-1&&firstRow>0,deleteLastNewLine=this.getLength()-1>lastRow,startRow=deleteFirstNewLine?firstRow-1:firstRow,startCol=deleteFirstNewLine?this.getLine(startRow).length:0,endRow=deleteLastNewLine?lastRow+1:lastRow,endCol=deleteLastNewLine?0:this.getLine(endRow).length,range=new Range(startRow,startCol,endRow,endCol),deletedLines=this.$lines.slice(firstRow,lastRow+1);return this.applyDelta({start:range.start,end:range.end,action:\"remove\",lines:this.getLinesForRange(range)}),deletedLines},this.removeNewLine=function(row){this.getLength()-1>row&&row>=0&&this.applyDelta({start:this.pos(row,this.getLine(row).length),end:this.pos(row+1,0),action:\"remove\",lines:[\"\",\"\"]})},this.replace=function(range,text){if(range instanceof Range||(range=Range.fromPoints(range.start,range.end)),0===text.length&&range.isEmpty())return range.start;if(text==this.getTextRange(range))return range.end;this.remove(range);var end;return end=text?this.insert(range.start,text):range.start},this.applyDeltas=function(deltas){for(var i=0;deltas.length>i;i++)this.applyDelta(deltas[i])},this.revertDeltas=function(deltas){for(var i=deltas.length-1;i>=0;i--)this.revertDelta(deltas[i])},this.applyDelta=function(delta,doNotValidate){var isInsert=\"insert\"==delta.action;(isInsert?1>=delta.lines.length&&!delta.lines[0]:!Range.comparePoints(delta.start,delta.end))||(isInsert&&delta.lines.length>2e4&&this.$splitAndapplyLargeDelta(delta,2e4),applyDelta(this.$lines,delta,doNotValidate),this._signal(\"change\",delta))},this.$splitAndapplyLargeDelta=function(delta,MAX){for(var lines=delta.lines,l=lines.length,row=delta.start.row,column=delta.start.column,from=0,to=0;;){from=to,to+=MAX-1;var chunk=lines.slice(from,to);if(to>l){delta.lines=chunk,delta.start.row=row+from,delta.start.column=column;break}chunk.push(\"\"),this.applyDelta({start:this.pos(row+from,column),end:this.pos(row+to,column=0),action:delta.action,lines:chunk},!0)}},this.revertDelta=function(delta){this.applyDelta({start:this.clonePos(delta.start),end:this.clonePos(delta.end),action:\"insert\"==delta.action?\"remove\":\"insert\",lines:delta.lines.slice()})},this.indexToPosition=function(index,startRow){for(var lines=this.$lines||this.getAllLines(),newlineLength=this.getNewLineCharacter().length,i=startRow||0,l=lines.length;l>i;i++)if(index-=lines[i].length+newlineLength,0>index)return{row:i,column:index+lines[i].length+newlineLength};return{row:l-1,column:lines[l-1].length}},this.positionToIndex=function(pos,startRow){for(var lines=this.$lines||this.getAllLines(),newlineLength=this.getNewLineCharacter().length,index=0,row=Math.min(pos.row,lines.length),i=startRow||0;row>i;++i)index+=lines[i].length+newlineLength;return index+pos.column}}).call(Document.prototype),exports.Document=Document}),ace.define(\"ace/worker/mirror\",[\"require\",\"exports\",\"module\",\"ace/range\",\"ace/document\",\"ace/lib/lang\"],function(acequire,exports){\"use strict\";acequire(\"../range\").Range;var Document=acequire(\"../document\").Document,lang=acequire(\"../lib/lang\"),Mirror=exports.Mirror=function(sender){this.sender=sender;var doc=this.doc=new Document(\"\"),deferredUpdate=this.deferredUpdate=lang.delayedCall(this.onUpdate.bind(this)),_self=this;sender.on(\"change\",function(e){var data=e.data;if(data[0].start)doc.applyDeltas(data);else for(var i=0;data.length>i;i+=2){if(Array.isArray(data[i+1]))var d={action:\"insert\",start:data[i],lines:data[i+1]};else var d={action:\"remove\",start:data[i],end:data[i+1]};doc.applyDelta(d,!0)}return _self.$timeout?deferredUpdate.schedule(_self.$timeout):(_self.onUpdate(),void 0)})};(function(){this.$timeout=500,this.setTimeout=function(timeout){this.$timeout=timeout},this.setValue=function(value){this.doc.setValue(value),this.deferredUpdate.schedule(this.$timeout)},this.getValue=function(callbackId){this.sender.callback(this.doc.getValue(),callbackId)},this.onUpdate=function(){},this.isPending=function(){return this.deferredUpdate.isPending()}}).call(Mirror.prototype)}),ace.define(\"ace/mode/html/saxparser\",[\"require\",\"exports\",\"module\"],function(acequire,exports,module){module.exports=function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=\"function\"==typeof acequire&&acequire;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw Error(\"Cannot find module \\'\"+o+\"\\'\")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}for(var i=\"function\"==typeof acequire&&acequire,o=0;r.length>o;o++)s(r[o]);return s}({1:[function(_dereq_,module,exports){function isScopeMarker(node){return\"http://www.w3.org/1999/xhtml\"===node.namespaceURI?\"applet\"===node.localName||\"caption\"===node.localName||\"marquee\"===node.localName||\"object\"===node.localName||\"table\"===node.localName||\"td\"===node.localName||\"th\"===node.localName:\"http://www.w3.org/1998/Math/MathML\"===node.namespaceURI?\"mi\"===node.localName||\"mo\"===node.localName||\"mn\"===node.localName||\"ms\"===node.localName||\"mtext\"===node.localName||\"annotation-xml\"===node.localName:\"http://www.w3.org/2000/svg\"===node.namespaceURI?\"foreignObject\"===node.localName||\"desc\"===node.localName||\"title\"===node.localName:void 0}function isListItemScopeMarker(node){return isScopeMarker(node)||\"http://www.w3.org/1999/xhtml\"===node.namespaceURI&&\"ol\"===node.localName||\"http://www.w3.org/1999/xhtml\"===node.namespaceURI&&\"ul\"===node.localName}function isTableScopeMarker(node){return\"http://www.w3.org/1999/xhtml\"===node.namespaceURI&&\"table\"===node.localName||\"http://www.w3.org/1999/xhtml\"===node.namespaceURI&&\"html\"===node.localName}function isTableBodyScopeMarker(node){return\"http://www.w3.org/1999/xhtml\"===node.namespaceURI&&\"tbody\"===node.localName||\"http://www.w3.org/1999/xhtml\"===node.namespaceURI&&\"tfoot\"===node.localName||\"http://www.w3.org/1999/xhtml\"===node.namespaceURI&&\"thead\"===node.localName||\"http://www.w3.org/1999/xhtml\"===node.namespaceURI&&\"html\"===node.localName}function isTableRowScopeMarker(node){return\"http://www.w3.org/1999/xhtml\"===node.namespaceURI&&\"tr\"===node.localName||\"http://www.w3.org/1999/xhtml\"===node.namespaceURI&&\"html\"===node.localName}function isButtonScopeMarker(node){return isScopeMarker(node)||\"http://www.w3.org/1999/xhtml\"===node.namespaceURI&&\"button\"===node.localName}function isSelectScopeMarker(node){return!(\"http://www.w3.org/1999/xhtml\"===node.namespaceURI&&\"optgroup\"===node.localName||\"http://www.w3.org/1999/xhtml\"===node.namespaceURI&&\"option\"===node.localName)}function ElementStack(){this.elements=[],this.rootNode=null,this.headElement=null,this.bodyElement=null}ElementStack.prototype._inScope=function(localName,isMarker){for(var i=this.elements.length-1;i>=0;i--){var node=this.elements[i];if(node.localName===localName)return!0;if(isMarker(node))return!1}},ElementStack.prototype.push=function(item){this.elements.push(item)},ElementStack.prototype.pushHtmlElement=function(item){this.rootNode=item.node,this.push(item)},ElementStack.prototype.pushHeadElement=function(item){this.headElement=item.node,this.push(item)},ElementStack.prototype.pushBodyElement=function(item){this.bodyElement=item.node,this.push(item)},ElementStack.prototype.pop=function(){return this.elements.pop()},ElementStack.prototype.remove=function(item){this.elements.splice(this.elements.indexOf(item),1)},ElementStack.prototype.popUntilPopped=function(localName){var element;do element=this.pop();while(element.localName!=localName)},ElementStack.prototype.popUntilTableScopeMarker=function(){for(;!isTableScopeMarker(this.top);)this.pop()},ElementStack.prototype.popUntilTableBodyScopeMarker=function(){for(;!isTableBodyScopeMarker(this.top);)this.pop()},ElementStack.prototype.popUntilTableRowScopeMarker=function(){for(;!isTableRowScopeMarker(this.top);)this.pop()},ElementStack.prototype.item=function(index){return this.elements[index]},ElementStack.prototype.contains=function(element){return-1!==this.elements.indexOf(element)},ElementStack.prototype.inScope=function(localName){return this._inScope(localName,isScopeMarker)},ElementStack.prototype.inListItemScope=function(localName){return this._inScope(localName,isListItemScopeMarker)},ElementStack.prototype.inTableScope=function(localName){return this._inScope(localName,isTableScopeMarker)},ElementStack.prototype.inButtonScope=function(localName){return this._inScope(localName,isButtonScopeMarker)},ElementStack.prototype.inSelectScope=function(localName){return this._inScope(localName,isSelectScopeMarker)},ElementStack.prototype.hasNumberedHeaderElementInScope=function(){for(var i=this.elements.length-1;i>=0;i--){var node=this.elements[i];if(node.isNumberedHeader())return!0;if(isScopeMarker(node))return!1}},ElementStack.prototype.furthestBlockForFormattingElement=function(element){for(var furthestBlock=null,i=this.elements.length-1;i>=0;i--){var node=this.elements[i];\\nif(node.node===element)break;node.isSpecial()&&(furthestBlock=node)}return furthestBlock},ElementStack.prototype.findIndex=function(localName){for(var i=this.elements.length-1;i>=0;i--)if(this.elements[i].localName==localName)return i;return-1},ElementStack.prototype.remove_openElements_until=function(callback){for(var element,finished=!1;!finished;)element=this.elements.pop(),finished=callback(element);return element},Object.defineProperty(ElementStack.prototype,\"top\",{get:function(){return this.elements[this.elements.length-1]}}),Object.defineProperty(ElementStack.prototype,\"length\",{get:function(){return this.elements.length}}),exports.ElementStack=ElementStack},{}],2:[function(_dereq_,module,exports){function isAlphaNumeric(c){return c>=\"0\"&&\"9\">=c||c>=\"a\"&&\"z\">=c||c>=\"A\"&&\"Z\">=c}function isHexDigit(c){return c>=\"0\"&&\"9\">=c||c>=\"a\"&&\"f\">=c||c>=\"A\"&&\"F\">=c}function isDecimalDigit(c){return c>=\"0\"&&\"9\">=c}var entities=_dereq_(\"html5-entities\"),InputStream=_dereq_(\"./InputStream\").InputStream,namedEntityPrefixes={};Object.keys(entities).forEach(function(entityKey){for(var i=0;entityKey.length>i;i++)namedEntityPrefixes[entityKey.substring(0,i+1)]=!0});var EntityParser={};EntityParser.consumeEntity=function(buffer,tokenizer,additionalAllowedCharacter){var decodedCharacter=\"\",consumedCharacters=\"\",ch=buffer.char();if(ch===InputStream.EOF)return!1;if(consumedCharacters+=ch,\"\\t\"==ch||\"\\\\n\"==ch||\"\\v\"==ch||\" \"==ch||\"<\"==ch||\"&\"==ch)return buffer.unget(consumedCharacters),!1;if(additionalAllowedCharacter===ch)return buffer.unget(consumedCharacters),!1;if(\"#\"==ch){if(ch=buffer.shift(1),ch===InputStream.EOF)return tokenizer._parseError(\"expected-numeric-entity-but-got-eof\"),buffer.unget(consumedCharacters),!1;consumedCharacters+=ch;var radix=10,isDigit=isDecimalDigit;if(\"x\"==ch||\"X\"==ch){if(radix=16,isDigit=isHexDigit,ch=buffer.shift(1),ch===InputStream.EOF)return tokenizer._parseError(\"expected-numeric-entity-but-got-eof\"),buffer.unget(consumedCharacters),!1;consumedCharacters+=ch}if(isDigit(ch)){for(var code=\"\";ch!==InputStream.EOF&&isDigit(ch);)code+=ch,ch=buffer.char();code=parseInt(code,radix);var replacement=this.replaceEntityNumbers(code);if(replacement&&(tokenizer._parseError(\"invalid-numeric-entity-replaced\"),code=replacement),code>65535&&1114111>=code){code-=65536;var first=((1047552&code)>>10)+55296,second=(1023&code)+56320;decodedCharacter=String.fromCharCode(first,second)}else decodedCharacter=String.fromCharCode(code);return\";\"!==ch&&(tokenizer._parseError(\"numeric-entity-without-semicolon\"),buffer.unget(ch)),decodedCharacter}return buffer.unget(consumedCharacters),tokenizer._parseError(\"expected-numeric-entity\"),!1}if(ch>=\"a\"&&\"z\">=ch||ch>=\"A\"&&\"Z\">=ch){for(var mostRecentMatch=\"\";namedEntityPrefixes[consumedCharacters]&&(entities[consumedCharacters]&&(mostRecentMatch=consumedCharacters),\";\"!=ch)&&(ch=buffer.char(),ch!==InputStream.EOF);)consumedCharacters+=ch;return mostRecentMatch?(decodedCharacter=entities[mostRecentMatch],\";\"===ch||!additionalAllowedCharacter||!isAlphaNumeric(ch)&&\"=\"!==ch?(consumedCharacters.length>mostRecentMatch.length&&buffer.unget(consumedCharacters.substring(mostRecentMatch.length)),\";\"!==ch&&tokenizer._parseError(\"named-entity-without-semicolon\"),decodedCharacter):(buffer.unget(consumedCharacters),!1)):(tokenizer._parseError(\"expected-named-entity\"),buffer.unget(consumedCharacters),!1)}},EntityParser.replaceEntityNumbers=function(c){switch(c){case 0:return 65533;case 19:return 16;case 128:return 8364;case 129:return 129;case 130:return 8218;case 131:return 402;case 132:return 8222;case 133:return 8230;case 134:return 8224;case 135:return 8225;case 136:return 710;case 137:return 8240;case 138:return 352;case 139:return 8249;case 140:return 338;case 141:return 141;case 142:return 381;case 143:return 143;case 144:return 144;case 145:return 8216;case 146:return 8217;case 147:return 8220;case 148:return 8221;case 149:return 8226;case 150:return 8211;case 151:return 8212;case 152:return 732;case 153:return 8482;case 154:return 353;case 155:return 8250;case 156:return 339;case 157:return 157;case 158:return 382;case 159:return 376;default:if(c>=55296&&57343>=c||c>1114111)return 65533;if(c>=1&&8>=c||c>=14&&31>=c||c>=127&&159>=c||c>=64976&&65007>=c||11==c||65534==c||131070==c||3145726==c||196607==c||262142==c||262143==c||327678==c||327679==c||393214==c||393215==c||458750==c||458751==c||524286==c||524287==c||589822==c||589823==c||655358==c||655359==c||720894==c||720895==c||786430==c||786431==c||851966==c||851967==c||917502==c||917503==c||983038==c||983039==c||1048574==c||1048575==c||1114110==c||1114111==c)return c}},exports.EntityParser=EntityParser},{\"./InputStream\":3,\"html5-entities\":12}],3:[function(_dereq_,module,exports){function InputStream(){this.data=\"\",this.start=0,this.committed=0,this.eof=!1,this.lastLocation={line:0,column:0}}InputStream.EOF=-1,InputStream.DRAIN=-2,InputStream.prototype={slice:function(){if(this.start>=this.data.length){if(!this.eof)throw InputStream.DRAIN;return InputStream.EOF}return this.data.slice(this.start,this.data.length)},\"char\":function(){if(!this.eof&&this.start>=this.data.length-1)throw InputStream.DRAIN;if(this.start>=this.data.length)return InputStream.EOF;var ch=this.data[this.start++];return\"\\\\r\"===ch&&(ch=\"\\\\n\"),ch},advance:function(amount){if(this.start+=amount,this.start>=this.data.length){if(!this.eof)throw InputStream.DRAIN;return InputStream.EOF}this.committed>this.data.length/2&&(this.lastLocation=this.location(),this.data=this.data.slice(this.committed),this.start=this.start-this.committed,this.committed=0)},matchWhile:function(re){if(this.eof&&this.start>=this.data.length)return\"\";var r=RegExp(\"^\"+re+\"+\"),m=r.exec(this.slice());if(m){if(!this.eof&&m[0].length==this.data.length-this.start)throw InputStream.DRAIN;return this.advance(m[0].length),m[0]}return\"\"},matchUntil:function(re){var m,s;if(s=this.slice(),s===InputStream.EOF)return\"\";if(m=RegExp(re+(this.eof?\"|$\":\"\")).exec(s)){var t=this.data.slice(this.start,this.start+m.index);return this.advance(m.index),t.replace(/\\\\r/g,\"\\\\n\").replace(/\\\\n{2,}/g,\"\\\\n\")}throw InputStream.DRAIN},append:function(data){this.data+=data},shift:function(n){if(!this.eof&&this.start+n>=this.data.length)throw InputStream.DRAIN;if(this.eof&&this.start>=this.data.length)return InputStream.EOF;var d=\"\"+this.data.slice(this.start,this.start+n);return this.advance(Math.min(n,this.data.length-this.start)),d},peek:function(n){if(!this.eof&&this.start+n>=this.data.length)throw InputStream.DRAIN;return this.eof&&this.start>=this.data.length?InputStream.EOF:\"\"+this.data.slice(this.start,Math.min(this.start+n,this.data.length))},length:function(){return this.data.length-this.start-1},unget:function(d){d!==InputStream.EOF&&(this.start-=d.length)},undo:function(){this.start=this.committed},commit:function(){this.committed=this.start},location:function(){var lastLine=this.lastLocation.line,lastColumn=this.lastLocation.column,read=this.data.slice(0,this.committed),newlines=read.match(/\\\\n/g),line=newlines?lastLine+newlines.length:lastLine,column=newlines?read.length-read.lastIndexOf(\"\\\\n\")-1:lastColumn+read.length;return{line:line,column:column}}},exports.InputStream=InputStream},{}],4:[function(_dereq_,module,exports){function StackItem(namespaceURI,localName,attributes,node){this.localName=localName,this.namespaceURI=namespaceURI,this.attributes=attributes,this.node=node}function getAttribute(item,name){for(var i=0;item.attributes.length>i;i++)if(item.attributes[i].nodeName==name)return item.attributes[i].nodeValue;return null}var SpecialElements={\"http://www.w3.org/1999/xhtml\":[\"address\",\"applet\",\"area\",\"article\",\"aside\",\"base\",\"basefont\",\"bgsound\",\"blockquote\",\"body\",\"br\",\"button\",\"caption\",\"center\",\"col\",\"colgroup\",\"dd\",\"details\",\"dir\",\"div\",\"dl\",\"dt\",\"embed\",\"fieldset\",\"figcaption\",\"figure\",\"footer\",\"form\",\"frame\",\"frameset\",\"h1\",\"h2\",\"h3\",\"h4\",\"h5\",\"h6\",\"head\",\"header\",\"hgroup\",\"hr\",\"html\",\"iframe\",\"img\",\"input\",\"isindex\",\"li\",\"link\",\"listing\",\"main\",\"marquee\",\"menu\",\"menuitem\",\"meta\",\"nav\",\"noembed\",\"noframes\",\"noscript\",\"object\",\"ol\",\"p\",\"param\",\"plaintext\",\"pre\",\"script\",\"section\",\"select\",\"source\",\"style\",\"summary\",\"table\",\"tbody\",\"td\",\"textarea\",\"tfoot\",\"th\",\"thead\",\"title\",\"tr\",\"track\",\"ul\",\"wbr\",\"xmp\"],\"http://www.w3.org/1998/Math/MathML\":[\"mi\",\"mo\",\"mn\",\"ms\",\"mtext\",\"annotation-xml\"],\"http://www.w3.org/2000/svg\":[\"foreignObject\",\"desc\",\"title\"]};StackItem.prototype.isSpecial=function(){return this.namespaceURI in SpecialElements&&SpecialElements[this.namespaceURI].indexOf(this.localName)>-1},StackItem.prototype.isFosterParenting=function(){return\"http://www.w3.org/1999/xhtml\"===this.namespaceURI?\"table\"===this.localName||\"tbody\"===this.localName||\"tfoot\"===this.localName||\"thead\"===this.localName||\"tr\"===this.localName:!1},StackItem.prototype.isNumberedHeader=function(){return\"http://www.w3.org/1999/xhtml\"===this.namespaceURI?\"h1\"===this.localName||\"h2\"===this.localName||\"h3\"===this.localName||\"h4\"===this.localName||\"h5\"===this.localName||\"h6\"===this.localName:!1},StackItem.prototype.isForeign=function(){return\"http://www.w3.org/1999/xhtml\"!=this.namespaceURI},StackItem.prototype.isHtmlIntegrationPoint=function(){if(\"http://www.w3.org/1998/Math/MathML\"===this.namespaceURI){if(\"annotation-xml\"!==this.localName)return!1;var encoding=getAttribute(this,\"encoding\");return encoding?(encoding=encoding.toLowerCase(),\"text/html\"===encoding||\"application/xhtml+xml\"===encoding):!1}return\"http://www.w3.org/2000/svg\"===this.namespaceURI?\"foreignObject\"===this.localName||\"desc\"===this.localName||\"title\"===this.localName:!1},StackItem.prototype.isMathMLTextIntegrationPoint=function(){return\"http://www.w3.org/1998/Math/MathML\"===this.namespaceURI?\"mi\"===this.localName||\"mo\"===this.localName||\"mn\"===this.localName||\"ms\"===this.localName||\"mtext\"===this.localName:!1},exports.StackItem=StackItem},{}],5:[function(_dereq_,module,exports){function isWhitespace(c){return\" \"===c||\"\\\\n\"===c||\"\\t\"===c||\"\\\\r\"===c||\"\\\\f\"===c}function isAlpha(c){return c>=\"A\"&&\"Z\">=c||c>=\"a\"&&\"z\">=c}function Tokenizer(tokenHandler){this._tokenHandler=tokenHandler,this._state=Tokenizer.DATA,this._inputStream=new InputStream,this._currentToken=null,this._temporaryBuffer=\"\",this._additionalAllowedCharacter=\"\"}var InputStream=_dereq_(\"./InputStream\").InputStream,EntityParser=_dereq_(\"./EntityParser\").EntityParser;Tokenizer.prototype._parseError=function(code,args){this._tokenHandler.parseError(code,args)},Tokenizer.prototype._emitToken=function(token){if(\"StartTag\"===token.type)for(var i=1;token.data.length>i;i++)token.data[i].nodeName||token.data.splice(i--,1);else\"EndTag\"===token.type&&(token.selfClosing&&this._parseError(\"self-closing-flag-on-end-tag\"),0!==token.data.length&&this._parseError(\"attributes-in-end-tag\"));this._tokenHandler.processToken(token),\"StartTag\"===token.type&&token.selfClosing&&!this._tokenHandler.isSelfClosingFlagAcknowledged()&&this._parseError(\"non-void-element-with-trailing-solidus\",{name:token.name})},Tokenizer.prototype._emitCurrentToken=function(){this._state=Tokenizer.DATA,this._emitToken(this._currentToken)},Tokenizer.prototype._currentAttribute=function(){return this._currentToken.data[this._currentToken.data.length-1]},Tokenizer.prototype.setState=function(state){this._state=state},Tokenizer.prototype.tokenize=function(source){function data_state(buffer){var data=buffer.char();if(data===InputStream.EOF)return tokenizer._emitToken({type:\"EOF\",data:null}),!1;if(\"&\"===data)tokenizer.setState(character_reference_in_data_state);else if(\"<\"===data)tokenizer.setState(tag_open_state);else if(\"\\\\0\"===data)tokenizer._emitToken({type:\"Characters\",data:data}),buffer.commit();else{var chars=buffer.matchUntil(\"&|<|\\\\0\");tokenizer._emitToken({type:\"Characters\",data:data+chars}),buffer.commit()}return!0}function character_reference_in_data_state(buffer){var character=EntityParser.consumeEntity(buffer,tokenizer);return tokenizer.setState(data_state),tokenizer._emitToken({type:\"Characters\",data:character||\"&\"}),!0}function rcdata_state(buffer){var data=buffer.char();if(data===InputStream.EOF)return tokenizer._emitToken({type:\"EOF\",data:null}),!1;if(\"&\"===data)tokenizer.setState(character_reference_in_rcdata_state);else if(\"<\"===data)tokenizer.setState(rcdata_less_than_sign_state);else if(\"\\\\0\"===data)tokenizer._parseError(\"invalid-codepoint\"),tokenizer._emitToken({type:\"Characters\",data:\"�\"}),buffer.commit();else{var chars=buffer.matchUntil(\"&|<|\\\\0\");tokenizer._emitToken({type:\"Characters\",data:data+chars}),buffer.commit()}return!0}function character_reference_in_rcdata_state(buffer){var character=EntityParser.consumeEntity(buffer,tokenizer);return tokenizer.setState(rcdata_state),tokenizer._emitToken({type:\"Characters\",data:character||\"&\"}),!0}function rawtext_state(buffer){var data=buffer.char();if(data===InputStream.EOF)return tokenizer._emitToken({type:\"EOF\",data:null}),!1;if(\"<\"===data)tokenizer.setState(rawtext_less_than_sign_state);else if(\"\\\\0\"===data)tokenizer._parseError(\"invalid-codepoint\"),tokenizer._emitToken({type:\"Characters\",data:\"�\"}),buffer.commit();else{var chars=buffer.matchUntil(\"<|\\\\0\");tokenizer._emitToken({type:\"Characters\",data:data+chars})}return!0}function plaintext_state(buffer){var data=buffer.char();if(data===InputStream.EOF)return tokenizer._emitToken({type:\"EOF\",data:null}),!1;if(\"\\\\0\"===data)tokenizer._parseError(\"invalid-codepoint\"),tokenizer._emitToken({type:\"Characters\",data:\"�\"}),buffer.commit();else{var chars=buffer.matchUntil(\"\\\\0\");tokenizer._emitToken({type:\"Characters\",data:data+chars})}return!0}function script_data_state(buffer){var data=buffer.char();if(data===InputStream.EOF)return tokenizer._emitToken({type:\"EOF\",data:null}),!1;if(\"<\"===data)tokenizer.setState(script_data_less_than_sign_state);else if(\"\\\\0\"===data)tokenizer._parseError(\"invalid-codepoint\"),tokenizer._emitToken({type:\"Characters\",data:\"�\"}),buffer.commit();else{var chars=buffer.matchUntil(\"<|\\\\0\");tokenizer._emitToken({type:\"Characters\",data:data+chars})}return!0}function rcdata_less_than_sign_state(buffer){var data=buffer.char();return\"/\"===data?(this._temporaryBuffer=\"\",tokenizer.setState(rcdata_end_tag_open_state)):(tokenizer._emitToken({type:\"Characters\",data:\"<\"}),buffer.unget(data),tokenizer.setState(rcdata_state)),!0}function rcdata_end_tag_open_state(buffer){var data=buffer.char();return isAlpha(data)?(this._temporaryBuffer+=data,tokenizer.setState(rcdata_end_tag_name_state)):(tokenizer._emitToken({type:\"Characters\",data:\"</\"}),buffer.unget(data),tokenizer.setState(rcdata_state)),!0}function rcdata_end_tag_name_state(buffer){var appropriate=tokenizer._currentToken&&tokenizer._currentToken.name===this._temporaryBuffer.toLowerCase(),data=buffer.char();return isWhitespace(data)&&appropriate?(tokenizer._currentToken={type:\"EndTag\",name:this._temporaryBuffer,data:[],selfClosing:!1},tokenizer.setState(before_attribute_name_state)):\"/\"===data&&appropriate?(tokenizer._currentToken={type:\"EndTag\",name:this._temporaryBuffer,data:[],selfClosing:!1},tokenizer.setState(self_closing_tag_state)):\">\"===data&&appropriate?(tokenizer._currentToken={type:\"EndTag\",name:this._temporaryBuffer,data:[],selfClosing:!1},tokenizer._emitCurrentToken(),tokenizer.setState(data_state)):isAlpha(data)?(this._temporaryBuffer+=data,buffer.commit()):(tokenizer._emitToken({type:\"Characters\",data:\"</\"+this._temporaryBuffer}),buffer.unget(data),tokenizer.setState(rcdata_state)),!0}function rawtext_less_than_sign_state(buffer){var data=buffer.char();return\"/\"===data?(this._temporaryBuffer=\"\",tokenizer.setState(rawtext_end_tag_open_state)):(tokenizer._emitToken({type:\"Characters\",data:\"<\"}),buffer.unget(data),tokenizer.setState(rawtext_state)),!0}function rawtext_end_tag_open_state(buffer){var data=buffer.char();return isAlpha(data)?(this._temporaryBuffer+=data,tokenizer.setState(rawtext_end_tag_name_state)):(tokenizer._emitToken({type:\"Characters\",data:\"</\"}),buffer.unget(data),tokenizer.setState(rawtext_state)),!0}function rawtext_end_tag_name_state(buffer){var appropriate=tokenizer._currentToken&&tokenizer._currentToken.name===this._temporaryBuffer.toLowerCase(),data=buffer.char();return isWhitespace(data)&&appropriate?(tokenizer._currentToken={type:\"EndTag\",name:this._temporaryBuffer,data:[],selfClosing:!1},tokenizer.setState(before_attribute_name_state)):\"/\"===data&&appropriate?(tokenizer._currentToken={type:\"EndTag\",name:this._temporaryBuffer,data:[],selfClosing:!1},tokenizer.setState(self_closing_tag_state)):\">\"===data&&appropriate?(tokenizer._currentToken={type:\"EndTag\",name:this._temporaryBuffer,data:[],selfClosing:!1},tokenizer._emitCurrentToken(),tokenizer.setState(data_state)):isAlpha(data)?(this._temporaryBuffer+=data,buffer.commit()):(tokenizer._emitToken({type:\"Characters\",data:\"</\"+this._temporaryBuffer}),buffer.unget(data),tokenizer.setState(rawtext_state)),!0}function script_data_less_than_sign_state(buffer){var data=buffer.char();return\"/\"===data?(this._temporaryBuffer=\"\",tokenizer.setState(script_data_end_tag_open_state)):\"!\"===data?(tokenizer._emitToken({type:\"Characters\",data:\"<!\"}),tokenizer.setState(script_data_escape_start_state)):(tokenizer._emitToken({type:\"Characters\",data:\"<\"}),buffer.unget(data),tokenizer.setState(script_data_state)),!0}function script_data_end_tag_open_state(buffer){var data=buffer.char();return isAlpha(data)?(this._temporaryBuffer+=data,tokenizer.setState(script_data_end_tag_name_state)):(tokenizer._emitToken({type:\"Characters\",data:\"</\"}),buffer.unget(data),tokenizer.setState(script_data_state)),!0}function script_data_end_tag_name_state(buffer){var appropriate=tokenizer._currentToken&&tokenizer._currentToken.name===this._temporaryBuffer.toLowerCase(),data=buffer.char();return isWhitespace(data)&&appropriate?(tokenizer._currentToken={type:\"EndTag\",name:\"script\",data:[],selfClosing:!1},tokenizer.setState(before_attribute_name_state)):\"/\"===data&&appropriate?(tokenizer._currentToken={type:\"EndTag\",name:\"script\",data:[],selfClosing:!1},tokenizer.setState(self_closing_tag_state)):\">\"===data&&appropriate?(tokenizer._currentToken={type:\"EndTag\",name:\"script\",data:[],selfClosing:!1},tokenizer._emitCurrentToken()):isAlpha(data)?(this._temporaryBuffer+=data,buffer.commit()):(tokenizer._emitToken({type:\"Characters\",data:\"</\"+this._temporaryBuffer}),buffer.unget(data),tokenizer.setState(script_data_state)),!0}function script_data_escape_start_state(buffer){var data=buffer.char();return\"-\"===data?(tokenizer._emitToken({type:\"Characters\",data:\"-\"}),tokenizer.setState(script_data_escape_start_dash_state)):(buffer.unget(data),tokenizer.setState(script_data_state)),!0}function script_data_escape_start_dash_state(buffer){var data=buffer.char();return\"-\"===data?(tokenizer._emitToken({type:\"Characters\",data:\"-\"}),tokenizer.setState(script_data_escaped_dash_dash_state)):(buffer.unget(data),tokenizer.setState(script_data_state)),!0}function script_data_escaped_state(buffer){var data=buffer.char();if(data===InputStream.EOF)buffer.unget(data),tokenizer.setState(data_state);else if(\"-\"===data)tokenizer._emitToken({type:\"Characters\",data:\"-\"}),tokenizer.setState(script_data_escaped_dash_state);else if(\"<\"===data)tokenizer.setState(script_data_escaped_less_then_sign_state);else if(\"\\\\0\"===data)tokenizer._parseError(\"invalid-codepoint\"),tokenizer._emitToken({type:\"Characters\",data:\"�\"}),buffer.commit();else{var chars=buffer.matchUntil(\"<|-|\\\\0\");tokenizer._emitToken({type:\"Characters\",data:data+chars})}return!0}function script_data_escaped_dash_state(buffer){var data=buffer.char();return data===InputStream.EOF?(buffer.unget(data),tokenizer.setState(data_state)):\"-\"===data?(tokenizer._emitToken({type:\"Characters\",data:\"-\"}),tokenizer.setState(script_data_escaped_dash_dash_state)):\"<\"===data?tokenizer.setState(script_data_escaped_less_then_sign_state):\"\\\\0\"===data?(tokenizer._parseError(\"invalid-codepoint\"),tokenizer._emitToken({type:\"Characters\",data:\"�\"}),tokenizer.setState(script_data_escaped_state)):(tokenizer._emitToken({type:\"Characters\",data:data}),tokenizer.setState(script_data_escaped_state)),!0}function script_data_escaped_dash_dash_state(buffer){var data=buffer.char();return data===InputStream.EOF?(tokenizer._parseError(\"eof-in-script\"),buffer.unget(data),tokenizer.setState(data_state)):\"<\"===data?tokenizer.setState(script_data_escaped_less_then_sign_state):\">\"===data?(tokenizer._emitToken({type:\"Characters\",data:\">\"}),tokenizer.setState(script_data_state)):\"\\\\0\"===data?(tokenizer._parseError(\"invalid-codepoint\"),tokenizer._emitToken({type:\"Characters\",data:\"�\"}),tokenizer.setState(script_data_escaped_state)):(tokenizer._emitToken({type:\"Characters\",data:data}),tokenizer.setState(script_data_escaped_state)),!0}function script_data_escaped_less_then_sign_state(buffer){var data=buffer.char();return\"/\"===data?(this._temporaryBuffer=\"\",tokenizer.setState(script_data_escaped_end_tag_open_state)):isAlpha(data)?(tokenizer._emitToken({type:\"Characters\",data:\"<\"+data}),this._temporaryBuffer=data,tokenizer.setState(script_data_double_escape_start_state)):(tokenizer._emitToken({type:\"Characters\",data:\"<\"}),buffer.unget(data),tokenizer.setState(script_data_escaped_state)),!0}function script_data_escaped_end_tag_open_state(buffer){var data=buffer.char();return isAlpha(data)?(this._temporaryBuffer=data,tokenizer.setState(script_data_escaped_end_tag_name_state)):(tokenizer._emitToken({type:\"Characters\",data:\"</\"}),buffer.unget(data),tokenizer.setState(script_data_escaped_state)),!0}function script_data_escaped_end_tag_name_state(buffer){var appropriate=tokenizer._currentToken&&tokenizer._currentToken.name===this._temporaryBuffer.toLowerCase(),data=buffer.char();return isWhitespace(data)&&appropriate?(tokenizer._currentToken={type:\"EndTag\",name:\"script\",data:[],selfClosing:!1},tokenizer.setState(before_attribute_name_state)):\"/\"===data&&appropriate?(tokenizer._currentToken={type:\"EndTag\",name:\"script\",data:[],selfClosing:!1},tokenizer.setState(self_closing_tag_state)):\">\"===data&&appropriate?(tokenizer._currentToken={type:\"EndTag\",name:\"script\",data:[],selfClosing:!1},tokenizer.setState(data_state),tokenizer._emitCurrentToken()):isAlpha(data)?(this._temporaryBuffer+=data,buffer.commit()):(tokenizer._emitToken({type:\"Characters\",data:\"</\"+this._temporaryBuffer}),buffer.unget(data),tokenizer.setState(script_data_escaped_state)),!0}function script_data_double_escape_start_state(buffer){var data=buffer.char();return isWhitespace(data)||\"/\"===data||\">\"===data?(tokenizer._emitToken({type:\"Characters\",data:data}),\"script\"===this._temporaryBuffer.toLowerCase()?tokenizer.setState(script_data_double_escaped_state):tokenizer.setState(script_data_escaped_state)):isAlpha(data)?(tokenizer._emitToken({type:\"Characters\",data:data}),this._temporaryBuffer+=data,buffer.commit()):(buffer.unget(data),tokenizer.setState(script_data_escaped_state)),!0}function script_data_double_escaped_state(buffer){var data=buffer.char();return data===InputStream.EOF?(tokenizer._parseError(\"eof-in-script\"),buffer.unget(data),tokenizer.setState(data_state)):\"-\"===data?(tokenizer._emitToken({type:\"Characters\",data:\"-\"}),tokenizer.setState(script_data_double_escaped_dash_state)):\"<\"===data?(tokenizer._emitToken({type:\"Characters\",data:\"<\"}),tokenizer.setState(script_data_double_escaped_less_than_sign_state)):\"\\\\0\"===data?(tokenizer._parseError(\"invalid-codepoint\"),tokenizer._emitToken({type:\"Characters\",data:\"�\"}),buffer.commit()):(tokenizer._emitToken({type:\"Characters\",data:data}),buffer.commit()),!0}function script_data_double_escaped_dash_state(buffer){var data=buffer.char();return data===InputStream.EOF?(tokenizer._parseError(\"eof-in-script\"),buffer.unget(data),tokenizer.setState(data_state)):\"-\"===data?(tokenizer._emitToken({type:\"Characters\",data:\"-\"}),tokenizer.setState(script_data_double_escaped_dash_dash_state)):\"<\"===data?(tokenizer._emitToken({type:\"Characters\",data:\"<\"}),tokenizer.setState(script_data_double_escaped_less_than_sign_state)):\"\\\\0\"===data?(tokenizer._parseError(\"invalid-codepoint\"),tokenizer._emitToken({type:\"Characters\",data:\"�\"}),tokenizer.setState(script_data_double_escaped_state)):(tokenizer._emitToken({type:\"Characters\",data:data}),tokenizer.setState(script_data_double_escaped_state)),!0}function script_data_double_escaped_dash_dash_state(buffer){var data=buffer.char();return data===InputStream.EOF?(tokenizer._parseError(\"eof-in-script\"),buffer.unget(data),tokenizer.setState(data_state)):\"-\"===data?(tokenizer._emitToken({type:\"Characters\",data:\"-\"}),buffer.commit()):\"<\"===data?(tokenizer._emitToken({type:\"Characters\",data:\"<\"}),tokenizer.setState(script_data_double_escaped_less_than_sign_state)):\">\"===data?(tokenizer._emitToken({type:\"Characters\",data:\">\"}),tokenizer.setState(script_data_state)):\"\\\\0\"===data?(tokenizer._parseError(\"invalid-codepoint\"),tokenizer._emitToken({type:\"Characters\",data:\"�\"}),tokenizer.setState(script_data_double_escaped_state)):(tokenizer._emitToken({type:\"Characters\",data:data}),tokenizer.setState(script_data_double_escaped_state)),!0}function script_data_double_escaped_less_than_sign_state(buffer){var data=buffer.char();return\"/\"===data?(tokenizer._emitToken({type:\"Characters\",data:\"/\"}),this._temporaryBuffer=\"\",tokenizer.setState(script_data_double_escape_end_state)):(buffer.unget(data),tokenizer.setState(script_data_double_escaped_state)),!0}function script_data_double_escape_end_state(buffer){var data=buffer.char();return isWhitespace(data)||\"/\"===data||\">\"===data?(tokenizer._emitToken({type:\"Characters\",data:data}),\"script\"===this._temporaryBuffer.toLowerCase()?tokenizer.setState(script_data_escaped_state):tokenizer.setState(script_data_double_escaped_state)):isAlpha(data)?(tokenizer._emitToken({type:\"Characters\",data:data}),this._temporaryBuffer+=data,buffer.commit()):(buffer.unget(data),tokenizer.setState(script_data_double_escaped_state)),!0}function tag_open_state(buffer){var data=buffer.char();return data===InputStream.EOF?(tokenizer._parseError(\"bare-less-than-sign-at-eof\"),tokenizer._emitToken({type:\"Characters\",data:\"<\"}),buffer.unget(data),tokenizer.setState(data_state)):isAlpha(data)?(tokenizer._currentToken={type:\"StartTag\",name:data.toLowerCase(),data:[]},tokenizer.setState(tag_name_state)):\"!\"===data?tokenizer.setState(markup_declaration_open_state):\"/\"===data?tokenizer.setState(close_tag_open_state):\">\"===data?(tokenizer._parseError(\"expected-tag-name-but-got-right-bracket\"),tokenizer._emitToken({type:\"Characters\",data:\"<>\"}),tokenizer.setState(data_state)):\"?\"===data?(tokenizer._parseError(\"expected-tag-name-but-got-question-mark\"),buffer.unget(data),tokenizer.setState(bogus_comment_state)):(tokenizer._parseError(\"expected-tag-name\"),tokenizer._emitToken({type:\"Characters\",data:\"<\"}),buffer.unget(data),tokenizer.setState(data_state)),!0}function close_tag_open_state(buffer){var data=buffer.char();return data===InputStream.EOF?(tokenizer._parseError(\"expected-closing-tag-but-got-eof\"),tokenizer._emitToken({type:\"Characters\",data:\"</\"}),buffer.unget(data),tokenizer.setState(data_state)):isAlpha(data)?(tokenizer._currentToken={type:\"EndTag\",name:data.toLowerCase(),data:[]},tokenizer.setState(tag_name_state)):\">\"===data?(tokenizer._parseError(\"expected-closing-tag-but-got-right-bracket\"),tokenizer.setState(data_state)):(tokenizer._parseError(\"expected-closing-tag-but-got-char\",{data:data}),buffer.unget(data),tokenizer.setState(bogus_comment_state)),!0}function tag_name_state(buffer){var data=buffer.char();return data===InputStream.EOF?(tokenizer._parseError(\"eof-in-tag-name\"),buffer.unget(data),tokenizer.setState(data_state)):isWhitespace(data)?tokenizer.setState(before_attribute_name_state):isAlpha(data)?tokenizer._currentToken.name+=data.toLowerCase():\">\"===data?tokenizer._emitCurrentToken():\"/\"===data?tokenizer.setState(self_closing_tag_state):\"\\\\0\"===data?(tokenizer._parseError(\"invalid-codepoint\"),tokenizer._currentToken.name+=\"�\"):tokenizer._currentToken.name+=data,buffer.commit(),!0}function before_attribute_name_state(buffer){var data=buffer.char();if(data===InputStream.EOF)tokenizer._parseError(\"expected-attribute-name-but-got-eof\"),buffer.unget(data),tokenizer.setState(data_state);else{if(isWhitespace(data))return!0;isAlpha(data)?(tokenizer._currentToken.data.push({nodeName:data.toLowerCase(),nodeValue:\"\"}),tokenizer.setState(attribute_name_state)):\">\"===data?tokenizer._emitCurrentToken():\"/\"===data?tokenizer.setState(self_closing_tag_state):\"\\'\"===data||\\'\"\\'===data||\"=\"===data||\"<\"===data?(tokenizer._parseError(\"invalid-character-in-attribute-name\"),tokenizer._currentToken.data.push({nodeName:data,nodeValue:\"\"}),tokenizer.setState(attribute_name_state)):\"\\\\0\"===data?(tokenizer._parseError(\"invalid-codepoint\"),tokenizer._currentToken.data.push({nodeName:\"�\",nodeValue:\"\"})):(tokenizer._currentToken.data.push({nodeName:data,nodeValue:\"\"}),tokenizer.setState(attribute_name_state))}return!0}function attribute_name_state(buffer){var data=buffer.char(),leavingThisState=!0,shouldEmit=!1;if(data===InputStream.EOF?(tokenizer._parseError(\"eof-in-attribute-name\"),buffer.unget(data),tokenizer.setState(data_state),shouldEmit=!0):\"=\"===data?tokenizer.setState(before_attribute_value_state):isAlpha(data)?(tokenizer._currentAttribute().nodeName+=data.toLowerCase(),leavingThisState=!1):\">\"===data?shouldEmit=!0:isWhitespace(data)?tokenizer.setState(after_attribute_name_state):\"/\"===data?tokenizer.setState(self_closing_tag_state):\"\\'\"===data||\\'\"\\'===data?(tokenizer._parseError(\"invalid-character-in-attribute-name\"),tokenizer._currentAttribute().nodeName+=data,leavingThisState=!1):\"\\\\0\"===data?(tokenizer._parseError(\"invalid-codepoint\"),tokenizer._currentAttribute().nodeName+=\"�\"):(tokenizer._currentAttribute().nodeName+=data,leavingThisState=!1),leavingThisState){for(var attributes=tokenizer._currentToken.data,currentAttribute=attributes[attributes.length-1],i=attributes.length-2;i>=0;i--)if(currentAttribute.nodeName===attributes[i].nodeName){tokenizer._parseError(\"duplicate-attribute\",{name:currentAttribute.nodeName}),currentAttribute.nodeName=null;break}shouldEmit&&tokenizer._emitCurrentToken()}else buffer.commit();return!0}function after_attribute_name_state(buffer){var data=buffer.char();if(data===InputStream.EOF)tokenizer._parseError(\"expected-end-of-tag-but-got-eof\"),buffer.unget(data),tokenizer.setState(data_state);else{if(isWhitespace(data))return!0;\"=\"===data?tokenizer.setState(before_attribute_value_state):\">\"===data?tokenizer._emitCurrentToken():isAlpha(data)?(tokenizer._currentToken.data.push({nodeName:data,nodeValue:\"\"}),tokenizer.setState(attribute_name_state)):\"/\"===data?tokenizer.setState(self_closing_tag_state):\"\\'\"===data||\\'\"\\'===data||\"<\"===data?(tokenizer._parseError(\"invalid-character-after-attribute-name\"),tokenizer._currentToken.data.push({nodeName:data,nodeValue:\"\"}),tokenizer.setState(attribute_name_state)):\"\\\\0\"===data?(tokenizer._parseError(\"invalid-codepoint\"),tokenizer._currentToken.data.push({nodeName:\"�\",nodeValue:\"\"})):(tokenizer._currentToken.data.push({nodeName:data,nodeValue:\"\"}),tokenizer.setState(attribute_name_state))}return!0}function before_attribute_value_state(buffer){var data=buffer.char();if(data===InputStream.EOF)tokenizer._parseError(\"expected-attribute-value-but-got-eof\"),buffer.unget(data),tokenizer.setState(data_state);else{if(isWhitespace(data))return!0;\\'\"\\'===data?tokenizer.setState(attribute_value_double_quoted_state):\"&\"===data?(tokenizer.setState(attribute_value_unquoted_state),buffer.unget(data)):\"\\'\"===data?tokenizer.setState(attribute_value_single_quoted_state):\">\"===data?(tokenizer._parseError(\"expected-attribute-value-but-got-right-bracket\"),tokenizer._emitCurrentToken()):\"=\"===data||\"<\"===data||\"`\"===data?(tokenizer._parseError(\"unexpected-character-in-unquoted-attribute-value\"),tokenizer._currentAttribute().nodeValue+=data,tokenizer.setState(attribute_value_unquoted_state)):\"\\\\0\"===data?(tokenizer._parseError(\"invalid-codepoint\"),tokenizer._currentAttribute().nodeValue+=\"�\"):(tokenizer._currentAttribute().nodeValue+=data,tokenizer.setState(attribute_value_unquoted_state))}return!0\\n}function attribute_value_double_quoted_state(buffer){var data=buffer.char();if(data===InputStream.EOF)tokenizer._parseError(\"eof-in-attribute-value-double-quote\"),buffer.unget(data),tokenizer.setState(data_state);else if(\\'\"\\'===data)tokenizer.setState(after_attribute_value_state);else if(\"&\"===data)this._additionalAllowedCharacter=\\'\"\\',tokenizer.setState(character_reference_in_attribute_value_state);else if(\"\\\\0\"===data)tokenizer._parseError(\"invalid-codepoint\"),tokenizer._currentAttribute().nodeValue+=\"�\";else{var s=buffer.matchUntil(\\'[\\\\0\"&]\\');data+=s,tokenizer._currentAttribute().nodeValue+=data}return!0}function attribute_value_single_quoted_state(buffer){var data=buffer.char();return data===InputStream.EOF?(tokenizer._parseError(\"eof-in-attribute-value-single-quote\"),buffer.unget(data),tokenizer.setState(data_state)):\"\\'\"===data?tokenizer.setState(after_attribute_value_state):\"&\"===data?(this._additionalAllowedCharacter=\"\\'\",tokenizer.setState(character_reference_in_attribute_value_state)):\"\\\\0\"===data?(tokenizer._parseError(\"invalid-codepoint\"),tokenizer._currentAttribute().nodeValue+=\"�\"):tokenizer._currentAttribute().nodeValue+=data+buffer.matchUntil(\"\\\\0|[\\'&]\"),!0}function attribute_value_unquoted_state(buffer){var data=buffer.char();if(data===InputStream.EOF)tokenizer._parseError(\"eof-after-attribute-value\"),buffer.unget(data),tokenizer.setState(data_state);else if(isWhitespace(data))tokenizer.setState(before_attribute_name_state);else if(\"&\"===data)this._additionalAllowedCharacter=\">\",tokenizer.setState(character_reference_in_attribute_value_state);else if(\">\"===data)tokenizer._emitCurrentToken();else if(\\'\"\\'===data||\"\\'\"===data||\"=\"===data||\"`\"===data||\"<\"===data)tokenizer._parseError(\"unexpected-character-in-unquoted-attribute-value\"),tokenizer._currentAttribute().nodeValue+=data,buffer.commit();else if(\"\\\\0\"===data)tokenizer._parseError(\"invalid-codepoint\"),tokenizer._currentAttribute().nodeValue+=\"�\";else{var o=buffer.matchUntil(\"\\\\0|[\\t\\\\n\\v\\\\f \\\\r&<>\\\\\"\\'=`]\");o===InputStream.EOF&&(tokenizer._parseError(\"eof-in-attribute-value-no-quotes\"),tokenizer._emitCurrentToken()),buffer.commit(),tokenizer._currentAttribute().nodeValue+=data+o}return!0}function character_reference_in_attribute_value_state(buffer){var character=EntityParser.consumeEntity(buffer,tokenizer,this._additionalAllowedCharacter);return this._currentAttribute().nodeValue+=character||\"&\",\\'\"\\'===this._additionalAllowedCharacter?tokenizer.setState(attribute_value_double_quoted_state):\"\\'\"===this._additionalAllowedCharacter?tokenizer.setState(attribute_value_single_quoted_state):\">\"===this._additionalAllowedCharacter&&tokenizer.setState(attribute_value_unquoted_state),!0}function after_attribute_value_state(buffer){var data=buffer.char();return data===InputStream.EOF?(tokenizer._parseError(\"eof-after-attribute-value\"),buffer.unget(data),tokenizer.setState(data_state)):isWhitespace(data)?tokenizer.setState(before_attribute_name_state):\">\"===data?(tokenizer.setState(data_state),tokenizer._emitCurrentToken()):\"/\"===data?tokenizer.setState(self_closing_tag_state):(tokenizer._parseError(\"unexpected-character-after-attribute-value\"),buffer.unget(data),tokenizer.setState(before_attribute_name_state)),!0}function self_closing_tag_state(buffer){var c=buffer.char();return c===InputStream.EOF?(tokenizer._parseError(\"unexpected-eof-after-solidus-in-tag\"),buffer.unget(c),tokenizer.setState(data_state)):\">\"===c?(tokenizer._currentToken.selfClosing=!0,tokenizer.setState(data_state),tokenizer._emitCurrentToken()):(tokenizer._parseError(\"unexpected-character-after-solidus-in-tag\"),buffer.unget(c),tokenizer.setState(before_attribute_name_state)),!0}function bogus_comment_state(buffer){var data=buffer.matchUntil(\">\");return data=data.replace(/\\\\u0000/g,\"�\"),buffer.char(),tokenizer._emitToken({type:\"Comment\",data:data}),tokenizer.setState(data_state),!0}function markup_declaration_open_state(buffer){var chars=buffer.shift(2);if(\"--\"===chars)tokenizer._currentToken={type:\"Comment\",data:\"\"},tokenizer.setState(comment_start_state);else{var newchars=buffer.shift(5);if(newchars===InputStream.EOF||chars===InputStream.EOF)return tokenizer._parseError(\"expected-dashes-or-doctype\"),tokenizer.setState(bogus_comment_state),buffer.unget(chars),!0;chars+=newchars,\"DOCTYPE\"===chars.toUpperCase()?(tokenizer._currentToken={type:\"Doctype\",name:\"\",publicId:null,systemId:null,forceQuirks:!1},tokenizer.setState(doctype_state)):tokenizer._tokenHandler.isCdataSectionAllowed()&&\"[CDATA[\"===chars?tokenizer.setState(cdata_section_state):(tokenizer._parseError(\"expected-dashes-or-doctype\"),buffer.unget(chars),tokenizer.setState(bogus_comment_state))}return!0}function cdata_section_state(buffer){var data=buffer.matchUntil(\"]]>\");return buffer.shift(3),data&&tokenizer._emitToken({type:\"Characters\",data:data}),tokenizer.setState(data_state),!0}function comment_start_state(buffer){var data=buffer.char();return data===InputStream.EOF?(tokenizer._parseError(\"eof-in-comment\"),tokenizer._emitToken(tokenizer._currentToken),buffer.unget(data),tokenizer.setState(data_state)):\"-\"===data?tokenizer.setState(comment_start_dash_state):\">\"===data?(tokenizer._parseError(\"incorrect-comment\"),tokenizer._emitToken(tokenizer._currentToken),tokenizer.setState(data_state)):\"\\\\0\"===data?(tokenizer._parseError(\"invalid-codepoint\"),tokenizer._currentToken.data+=\"�\"):(tokenizer._currentToken.data+=data,tokenizer.setState(comment_state)),!0}function comment_start_dash_state(buffer){var data=buffer.char();return data===InputStream.EOF?(tokenizer._parseError(\"eof-in-comment\"),tokenizer._emitToken(tokenizer._currentToken),buffer.unget(data),tokenizer.setState(data_state)):\"-\"===data?tokenizer.setState(comment_end_state):\">\"===data?(tokenizer._parseError(\"incorrect-comment\"),tokenizer._emitToken(tokenizer._currentToken),tokenizer.setState(data_state)):\"\\\\0\"===data?(tokenizer._parseError(\"invalid-codepoint\"),tokenizer._currentToken.data+=\"�\"):(tokenizer._currentToken.data+=\"-\"+data,tokenizer.setState(comment_state)),!0}function comment_state(buffer){var data=buffer.char();return data===InputStream.EOF?(tokenizer._parseError(\"eof-in-comment\"),tokenizer._emitToken(tokenizer._currentToken),buffer.unget(data),tokenizer.setState(data_state)):\"-\"===data?tokenizer.setState(comment_end_dash_state):\"\\\\0\"===data?(tokenizer._parseError(\"invalid-codepoint\"),tokenizer._currentToken.data+=\"�\"):(tokenizer._currentToken.data+=data,buffer.commit()),!0}function comment_end_dash_state(buffer){var data=buffer.char();return data===InputStream.EOF?(tokenizer._parseError(\"eof-in-comment-end-dash\"),tokenizer._emitToken(tokenizer._currentToken),buffer.unget(data),tokenizer.setState(data_state)):\"-\"===data?tokenizer.setState(comment_end_state):\"\\\\0\"===data?(tokenizer._parseError(\"invalid-codepoint\"),tokenizer._currentToken.data+=\"-�\",tokenizer.setState(comment_state)):(tokenizer._currentToken.data+=\"-\"+data+buffer.matchUntil(\"\\\\0|-\"),buffer.char()),!0}function comment_end_state(buffer){var data=buffer.char();return data===InputStream.EOF?(tokenizer._parseError(\"eof-in-comment-double-dash\"),tokenizer._emitToken(tokenizer._currentToken),buffer.unget(data),tokenizer.setState(data_state)):\">\"===data?(tokenizer._emitToken(tokenizer._currentToken),tokenizer.setState(data_state)):\"!\"===data?(tokenizer._parseError(\"unexpected-bang-after-double-dash-in-comment\"),tokenizer.setState(comment_end_bang_state)):\"-\"===data?(tokenizer._parseError(\"unexpected-dash-after-double-dash-in-comment\"),tokenizer._currentToken.data+=data):\"\\\\0\"===data?(tokenizer._parseError(\"invalid-codepoint\"),tokenizer._currentToken.data+=\"--�\",tokenizer.setState(comment_state)):(tokenizer._parseError(\"unexpected-char-in-comment\"),tokenizer._currentToken.data+=\"--\"+data,tokenizer.setState(comment_state)),!0}function comment_end_bang_state(buffer){var data=buffer.char();return data===InputStream.EOF?(tokenizer._parseError(\"eof-in-comment-end-bang-state\"),tokenizer._emitToken(tokenizer._currentToken),buffer.unget(data),tokenizer.setState(data_state)):\">\"===data?(tokenizer._emitToken(tokenizer._currentToken),tokenizer.setState(data_state)):\"-\"===data?(tokenizer._currentToken.data+=\"--!\",tokenizer.setState(comment_end_dash_state)):(tokenizer._currentToken.data+=\"--!\"+data,tokenizer.setState(comment_state)),!0}function doctype_state(buffer){var data=buffer.char();return data===InputStream.EOF?(tokenizer._parseError(\"expected-doctype-name-but-got-eof\"),tokenizer._currentToken.forceQuirks=!0,buffer.unget(data),tokenizer.setState(data_state),tokenizer._emitCurrentToken()):isWhitespace(data)?tokenizer.setState(before_doctype_name_state):(tokenizer._parseError(\"need-space-after-doctype\"),buffer.unget(data),tokenizer.setState(before_doctype_name_state)),!0}function before_doctype_name_state(buffer){var data=buffer.char();return data===InputStream.EOF?(tokenizer._parseError(\"expected-doctype-name-but-got-eof\"),tokenizer._currentToken.forceQuirks=!0,buffer.unget(data),tokenizer.setState(data_state),tokenizer._emitCurrentToken()):isWhitespace(data)||(\">\"===data?(tokenizer._parseError(\"expected-doctype-name-but-got-right-bracket\"),tokenizer._currentToken.forceQuirks=!0,tokenizer.setState(data_state),tokenizer._emitCurrentToken()):(isAlpha(data)&&(data=data.toLowerCase()),tokenizer._currentToken.name=data,tokenizer.setState(doctype_name_state))),!0}function doctype_name_state(buffer){var data=buffer.char();return data===InputStream.EOF?(tokenizer._currentToken.forceQuirks=!0,buffer.unget(data),tokenizer._parseError(\"eof-in-doctype-name\"),tokenizer.setState(data_state),tokenizer._emitCurrentToken()):isWhitespace(data)?tokenizer.setState(after_doctype_name_state):\">\"===data?(tokenizer.setState(data_state),tokenizer._emitCurrentToken()):(isAlpha(data)&&(data=data.toLowerCase()),tokenizer._currentToken.name+=data,buffer.commit()),!0}function after_doctype_name_state(buffer){var data=buffer.char();if(data===InputStream.EOF)tokenizer._currentToken.forceQuirks=!0,buffer.unget(data),tokenizer._parseError(\"eof-in-doctype\"),tokenizer.setState(data_state),tokenizer._emitCurrentToken();else if(isWhitespace(data));else if(\">\"===data)tokenizer.setState(data_state),tokenizer._emitCurrentToken();else{if([\"p\",\"P\"].indexOf(data)>-1){var expected=[[\"u\",\"U\"],[\"b\",\"B\"],[\"l\",\"L\"],[\"i\",\"I\"],[\"c\",\"C\"]],matched=expected.every(function(expected){return data=buffer.char(),expected.indexOf(data)>-1});if(matched)return tokenizer.setState(after_doctype_public_keyword_state),!0}else if([\"s\",\"S\"].indexOf(data)>-1){var expected=[[\"y\",\"Y\"],[\"s\",\"S\"],[\"t\",\"T\"],[\"e\",\"E\"],[\"m\",\"M\"]],matched=expected.every(function(expected){return data=buffer.char(),expected.indexOf(data)>-1});if(matched)return tokenizer.setState(after_doctype_system_keyword_state),!0}buffer.unget(data),tokenizer._currentToken.forceQuirks=!0,data===InputStream.EOF?(tokenizer._parseError(\"eof-in-doctype\"),buffer.unget(data),tokenizer.setState(data_state),tokenizer._emitCurrentToken()):(tokenizer._parseError(\"expected-space-or-right-bracket-in-doctype\",{data:data}),tokenizer.setState(bogus_doctype_state))}return!0}function after_doctype_public_keyword_state(buffer){var data=buffer.char();return data===InputStream.EOF?(tokenizer._parseError(\"eof-in-doctype\"),tokenizer._currentToken.forceQuirks=!0,buffer.unget(data),tokenizer.setState(data_state),tokenizer._emitCurrentToken()):isWhitespace(data)?tokenizer.setState(before_doctype_public_identifier_state):\"\\'\"===data||\\'\"\\'===data?(tokenizer._parseError(\"unexpected-char-in-doctype\"),buffer.unget(data),tokenizer.setState(before_doctype_public_identifier_state)):(buffer.unget(data),tokenizer.setState(before_doctype_public_identifier_state)),!0}function before_doctype_public_identifier_state(buffer){var data=buffer.char();return data===InputStream.EOF?(tokenizer._parseError(\"eof-in-doctype\"),tokenizer._currentToken.forceQuirks=!0,buffer.unget(data),tokenizer.setState(data_state),tokenizer._emitCurrentToken()):isWhitespace(data)||(\\'\"\\'===data?(tokenizer._currentToken.publicId=\"\",tokenizer.setState(doctype_public_identifier_double_quoted_state)):\"\\'\"===data?(tokenizer._currentToken.publicId=\"\",tokenizer.setState(doctype_public_identifier_single_quoted_state)):\">\"===data?(tokenizer._parseError(\"unexpected-end-of-doctype\"),tokenizer._currentToken.forceQuirks=!0,tokenizer.setState(data_state),tokenizer._emitCurrentToken()):(tokenizer._parseError(\"unexpected-char-in-doctype\"),tokenizer._currentToken.forceQuirks=!0,tokenizer.setState(bogus_doctype_state))),!0}function doctype_public_identifier_double_quoted_state(buffer){var data=buffer.char();return data===InputStream.EOF?(tokenizer._parseError(\"eof-in-doctype\"),tokenizer._currentToken.forceQuirks=!0,buffer.unget(data),tokenizer.setState(data_state),tokenizer._emitCurrentToken()):\\'\"\\'===data?tokenizer.setState(after_doctype_public_identifier_state):\">\"===data?(tokenizer._parseError(\"unexpected-end-of-doctype\"),tokenizer._currentToken.forceQuirks=!0,tokenizer.setState(data_state),tokenizer._emitCurrentToken()):tokenizer._currentToken.publicId+=data,!0}function doctype_public_identifier_single_quoted_state(buffer){var data=buffer.char();return data===InputStream.EOF?(tokenizer._parseError(\"eof-in-doctype\"),tokenizer._currentToken.forceQuirks=!0,buffer.unget(data),tokenizer.setState(data_state),tokenizer._emitCurrentToken()):\"\\'\"===data?tokenizer.setState(after_doctype_public_identifier_state):\">\"===data?(tokenizer._parseError(\"unexpected-end-of-doctype\"),tokenizer._currentToken.forceQuirks=!0,tokenizer.setState(data_state),tokenizer._emitCurrentToken()):tokenizer._currentToken.publicId+=data,!0}function after_doctype_public_identifier_state(buffer){var data=buffer.char();return data===InputStream.EOF?(tokenizer._parseError(\"eof-in-doctype\"),tokenizer._currentToken.forceQuirks=!0,tokenizer._emitCurrentToken(),buffer.unget(data),tokenizer.setState(data_state)):isWhitespace(data)?tokenizer.setState(between_doctype_public_and_system_identifiers_state):\">\"===data?(tokenizer.setState(data_state),tokenizer._emitCurrentToken()):\\'\"\\'===data?(tokenizer._parseError(\"unexpected-char-in-doctype\"),tokenizer._currentToken.systemId=\"\",tokenizer.setState(doctype_system_identifier_double_quoted_state)):\"\\'\"===data?(tokenizer._parseError(\"unexpected-char-in-doctype\"),tokenizer._currentToken.systemId=\"\",tokenizer.setState(doctype_system_identifier_single_quoted_state)):(tokenizer._parseError(\"unexpected-char-in-doctype\"),tokenizer._currentToken.forceQuirks=!0,tokenizer.setState(bogus_doctype_state)),!0}function between_doctype_public_and_system_identifiers_state(buffer){var data=buffer.char();return data===InputStream.EOF?(tokenizer._parseError(\"eof-in-doctype\"),tokenizer._currentToken.forceQuirks=!0,tokenizer._emitCurrentToken(),buffer.unget(data),tokenizer.setState(data_state)):isWhitespace(data)||(\">\"===data?(tokenizer._emitCurrentToken(),tokenizer.setState(data_state)):\\'\"\\'===data?(tokenizer._currentToken.systemId=\"\",tokenizer.setState(doctype_system_identifier_double_quoted_state)):\"\\'\"===data?(tokenizer._currentToken.systemId=\"\",tokenizer.setState(doctype_system_identifier_single_quoted_state)):(tokenizer._parseError(\"unexpected-char-in-doctype\"),tokenizer._currentToken.forceQuirks=!0,tokenizer.setState(bogus_doctype_state))),!0}function after_doctype_system_keyword_state(buffer){var data=buffer.char();return data===InputStream.EOF?(tokenizer._parseError(\"eof-in-doctype\"),tokenizer._currentToken.forceQuirks=!0,tokenizer._emitCurrentToken(),buffer.unget(data),tokenizer.setState(data_state)):isWhitespace(data)?tokenizer.setState(before_doctype_system_identifier_state):\"\\'\"===data||\\'\"\\'===data?(tokenizer._parseError(\"unexpected-char-in-doctype\"),buffer.unget(data),tokenizer.setState(before_doctype_system_identifier_state)):(buffer.unget(data),tokenizer.setState(before_doctype_system_identifier_state)),!0}function before_doctype_system_identifier_state(buffer){var data=buffer.char();return data===InputStream.EOF?(tokenizer._parseError(\"eof-in-doctype\"),tokenizer._currentToken.forceQuirks=!0,tokenizer._emitCurrentToken(),buffer.unget(data),tokenizer.setState(data_state)):isWhitespace(data)||(\\'\"\\'===data?(tokenizer._currentToken.systemId=\"\",tokenizer.setState(doctype_system_identifier_double_quoted_state)):\"\\'\"===data?(tokenizer._currentToken.systemId=\"\",tokenizer.setState(doctype_system_identifier_single_quoted_state)):\">\"===data?(tokenizer._parseError(\"unexpected-end-of-doctype\"),tokenizer._currentToken.forceQuirks=!0,tokenizer._emitCurrentToken(),tokenizer.setState(data_state)):(tokenizer._parseError(\"unexpected-char-in-doctype\"),tokenizer._currentToken.forceQuirks=!0,tokenizer.setState(bogus_doctype_state))),!0}function doctype_system_identifier_double_quoted_state(buffer){var data=buffer.char();return data===InputStream.EOF?(tokenizer._parseError(\"eof-in-doctype\"),tokenizer._currentToken.forceQuirks=!0,tokenizer._emitCurrentToken(),buffer.unget(data),tokenizer.setState(data_state)):\\'\"\\'===data?tokenizer.setState(after_doctype_system_identifier_state):\">\"===data?(tokenizer._parseError(\"unexpected-end-of-doctype\"),tokenizer._currentToken.forceQuirks=!0,tokenizer._emitCurrentToken(),tokenizer.setState(data_state)):tokenizer._currentToken.systemId+=data,!0}function doctype_system_identifier_single_quoted_state(buffer){var data=buffer.char();return data===InputStream.EOF?(tokenizer._parseError(\"eof-in-doctype\"),tokenizer._currentToken.forceQuirks=!0,tokenizer._emitCurrentToken(),buffer.unget(data),tokenizer.setState(data_state)):\"\\'\"===data?tokenizer.setState(after_doctype_system_identifier_state):\">\"===data?(tokenizer._parseError(\"unexpected-end-of-doctype\"),tokenizer._currentToken.forceQuirks=!0,tokenizer._emitCurrentToken(),tokenizer.setState(data_state)):tokenizer._currentToken.systemId+=data,!0}function after_doctype_system_identifier_state(buffer){var data=buffer.char();return data===InputStream.EOF?(tokenizer._parseError(\"eof-in-doctype\"),tokenizer._currentToken.forceQuirks=!0,tokenizer._emitCurrentToken(),buffer.unget(data),tokenizer.setState(data_state)):isWhitespace(data)||(\">\"===data?(tokenizer._emitCurrentToken(),tokenizer.setState(data_state)):(tokenizer._parseError(\"unexpected-char-in-doctype\"),tokenizer.setState(bogus_doctype_state))),!0}function bogus_doctype_state(buffer){var data=buffer.char();return data===InputStream.EOF?(buffer.unget(data),tokenizer._emitCurrentToken(),tokenizer.setState(data_state)):\">\"===data&&(tokenizer._emitCurrentToken(),tokenizer.setState(data_state)),!0}Tokenizer.DATA=data_state,Tokenizer.RCDATA=rcdata_state,Tokenizer.RAWTEXT=rawtext_state,Tokenizer.SCRIPT_DATA=script_data_state,Tokenizer.PLAINTEXT=plaintext_state,this._state=Tokenizer.DATA,this._inputStream.append(source),this._tokenHandler.startTokenization(this),this._inputStream.eof=!0;for(var tokenizer=this;this._state.call(this,this._inputStream););},Object.defineProperty(Tokenizer.prototype,\"lineNumber\",{get:function(){return this._inputStream.location().line}}),Object.defineProperty(Tokenizer.prototype,\"columnNumber\",{get:function(){return this._inputStream.location().column}}),exports.Tokenizer=Tokenizer},{\"./EntityParser\":2,\"./InputStream\":3}],6:[function(_dereq_,module,exports){function isWhitespace(ch){return\" \"===ch||\"\\\\n\"===ch||\"\\t\"===ch||\"\\\\r\"===ch||\"\\\\f\"===ch}function isWhitespaceOrReplacementCharacter(ch){return isWhitespace(ch)||\"�\"===ch}function isAllWhitespace(characters){for(var i=0;characters.length>i;i++){var ch=characters[i];if(!isWhitespace(ch))return!1}return!0}function isAllWhitespaceOrReplacementCharacters(characters){for(var i=0;characters.length>i;i++){var ch=characters[i];if(!isWhitespaceOrReplacementCharacter(ch))return!1}return!0}function getAttribute(node,name){for(var i=0;node.attributes.length>i;i++){var attribute=node.attributes[i];if(attribute.nodeName===name)return attribute}return null}function CharacterBuffer(characters){this.characters=characters,this.current=0,this.end=this.characters.length}function TreeBuilder(){this.tokenizer=null,this.errorHandler=null,this.scriptingEnabled=!1,this.document=null,this.head=null,this.form=null,this.openElements=new ElementStack,this.activeFormattingElements=[],this.insertionMode=null,this.insertionModeName=\"\",this.originalInsertionMode=\"\",this.inQuirksMode=!1,this.compatMode=\"no quirks\",this.framesetOk=!0,this.redirectAttachToFosterParent=!1,this.selfClosingFlagAcknowledged=!1,this.context=\"\",this.pendingTableCharacters=[],this.shouldSkipLeadingNewline=!1;var tree=this,modes=this.insertionModes={};modes.base={end_tag_handlers:{\"-default\":\"endTagOther\"},start_tag_handlers:{\"-default\":\"startTagOther\"},processEOF:function(){tree.generateImpliedEndTags(),tree.openElements.length>2?tree.parseError(\"expected-closing-tag-but-got-eof\"):2==tree.openElements.length&&\"body\"!=tree.openElements.item(1).localName?tree.parseError(\"expected-closing-tag-but-got-eof\"):tree.context&&tree.openElements.length>1},processComment:function(data){tree.insertComment(data,tree.currentStackItem().node)},processDoctype:function(){tree.parseError(\"unexpected-doctype\")},processStartTag:function(name,attributes,selfClosing){if(this[this.start_tag_handlers[name]])this[this.start_tag_handlers[name]](name,attributes,selfClosing);else{if(!this[this.start_tag_handlers[\"-default\"]])throw Error(\"No handler found for \"+name);this[this.start_tag_handlers[\"-default\"]](name,attributes,selfClosing)}},processEndTag:function(name){if(this[this.end_tag_handlers[name]])this[this.end_tag_handlers[name]](name);else{if(!this[this.end_tag_handlers[\"-default\"]])throw Error(\"No handler found for \"+name);this[this.end_tag_handlers[\"-default\"]](name)}},startTagHtml:function(name,attributes){modes.inBody.startTagHtml(name,attributes)}},modes.initial=Object.create(modes.base),modes.initial.processEOF=function(){tree.parseError(\"expected-doctype-but-got-eof\"),this.anythingElse(),tree.insertionMode.processEOF()},modes.initial.processComment=function(data){tree.insertComment(data,tree.document)},modes.initial.processDoctype=function(name,publicId,systemId,forceQuirks){function publicIdStartsWith(string){return 0===publicId.toLowerCase().indexOf(string)}tree.insertDoctype(name||\"\",publicId||\"\",systemId||\"\"),forceQuirks||\"html\"!=name||null!=publicId&&([\"+//silmaril//dtd html pro v0r11 19970101//\",\"-//advasoft ltd//dtd html 3.0 aswedit + extensions//\",\"-//as//dtd html 3.0 aswedit + extensions//\",\"-//ietf//dtd html 2.0 level 1//\",\"-//ietf//dtd html 2.0 level 2//\",\"-//ietf//dtd html 2.0 strict level 1//\",\"-//ietf//dtd html 2.0 strict level 2//\",\"-//ietf//dtd html 2.0 strict//\",\"-//ietf//dtd html 2.0//\",\"-//ietf//dtd html 2.1e//\",\"-//ietf//dtd html 3.0//\",\"-//ietf//dtd html 3.0//\",\"-//ietf//dtd html 3.2 final//\",\"-//ietf//dtd html 3.2//\",\"-//ietf//dtd html 3//\",\"-//ietf//dtd html level 0//\",\"-//ietf//dtd html level 0//\",\"-//ietf//dtd html level 1//\",\"-//ietf//dtd html level 1//\",\"-//ietf//dtd html level 2//\",\"-//ietf//dtd html level 2//\",\"-//ietf//dtd html level 3//\",\"-//ietf//dtd html level 3//\",\"-//ietf//dtd html strict level 0//\",\"-//ietf//dtd html strict level 0//\",\"-//ietf//dtd html strict level 1//\",\"-//ietf//dtd html strict level 1//\",\"-//ietf//dtd html strict level 2//\",\"-//ietf//dtd html strict level 2//\",\"-//ietf//dtd html strict level 3//\",\"-//ietf//dtd html strict level 3//\",\"-//ietf//dtd html strict//\",\"-//ietf//dtd html strict//\",\"-//ietf//dtd html strict//\",\"-//ietf//dtd html//\",\"-//ietf//dtd html//\",\"-//ietf//dtd html//\",\"-//metrius//dtd metrius presentational//\",\"-//microsoft//dtd internet explorer 2.0 html strict//\",\"-//microsoft//dtd internet explorer 2.0 html//\",\"-//microsoft//dtd internet explorer 2.0 tables//\",\"-//microsoft//dtd internet explorer 3.0 html strict//\",\"-//microsoft//dtd internet explorer 3.0 html//\",\"-//microsoft//dtd internet explorer 3.0 tables//\",\"-//netscape comm. corp.//dtd html//\",\"-//netscape comm. corp.//dtd strict html//\",\"-//o\\'reilly and associates//dtd html 2.0//\",\"-//o\\'reilly and associates//dtd html extended 1.0//\",\"-//spyglass//dtd html 2.0 extended//\",\"-//sq//dtd html 2.0 hotmetal + extensions//\",\"-//sun microsystems corp.//dtd hotjava html//\",\"-//sun microsystems corp.//dtd hotjava strict html//\",\"-//w3c//dtd html 3 1995-03-24//\",\"-//w3c//dtd html 3.2 draft//\",\"-//w3c//dtd html 3.2 final//\",\"-//w3c//dtd html 3.2//\",\"-//w3c//dtd html 3.2s draft//\",\"-//w3c//dtd html 4.0 frameset//\",\"-//w3c//dtd html 4.0 transitional//\",\"-//w3c//dtd html experimental 19960712//\",\"-//w3c//dtd html experimental 970421//\",\"-//w3c//dtd w3 html//\",\"-//w3o//dtd w3 html 3.0//\",\"-//webtechs//dtd mozilla html 2.0//\",\"-//webtechs//dtd mozilla html//\",\"html\"].some(publicIdStartsWith)||[\"-//w3o//dtd w3 html strict 3.0//en//\",\"-/w3c/dtd html 4.0 transitional/en\",\"html\"].indexOf(publicId.toLowerCase())>-1||null==systemId&&[\"-//w3c//dtd html 4.01 transitional//\",\"-//w3c//dtd html 4.01 frameset//\"].some(publicIdStartsWith))||null!=systemId&&\"http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd\"==systemId.toLowerCase()?(tree.compatMode=\"quirks\",tree.parseError(\"quirky-doctype\")):null!=publicId&&([\"-//w3c//dtd xhtml 1.0 transitional//\",\"-//w3c//dtd xhtml 1.0 frameset//\"].some(publicIdStartsWith)||null!=systemId&&[\"-//w3c//dtd html 4.01 transitional//\",\"-//w3c//dtd html 4.01 frameset//\"].indexOf(publicId.toLowerCase())>-1)?(tree.compatMode=\"limited quirks\",tree.parseError(\"almost-standards-doctype\")):\"-//W3C//DTD HTML 4.0//EN\"==publicId&&(null==systemId||\"http://www.w3.org/TR/REC-html40/strict.dtd\"==systemId)||\"-//W3C//DTD HTML 4.01//EN\"==publicId&&(null==systemId||\"http://www.w3.org/TR/html4/strict.dtd\"==systemId)||\"-//W3C//DTD XHTML 1.0 Strict//EN\"==publicId&&\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\"==systemId||\"-//W3C//DTD XHTML 1.1//EN\"==publicId&&\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\"==systemId||(null!=systemId&&\"about:legacy-compat\"!=systemId||null!=publicId)&&tree.parseError(\"unknown-doctype\"),tree.setInsertionMode(\"beforeHTML\")},modes.initial.processCharacters=function(buffer){buffer.skipLeadingWhitespace(),buffer.length&&(tree.parseError(\"expected-doctype-but-got-chars\"),this.anythingElse(),tree.insertionMode.processCharacters(buffer))},modes.initial.processStartTag=function(name,attributes,selfClosing){tree.parseError(\"expected-doctype-but-got-start-tag\",{name:name}),this.anythingElse(),tree.insertionMode.processStartTag(name,attributes,selfClosing)},modes.initial.processEndTag=function(name){tree.parseError(\"expected-doctype-but-got-end-tag\",{name:name}),this.anythingElse(),tree.insertionMode.processEndTag(name)},modes.initial.anythingElse=function(){tree.compatMode=\"quirks\",tree.setInsertionMode(\"beforeHTML\")},modes.beforeHTML=Object.create(modes.base),modes.beforeHTML.start_tag_handlers={html:\"startTagHtml\",\"-default\":\"startTagOther\"},modes.beforeHTML.processEOF=function(){this.anythingElse(),tree.insertionMode.processEOF()},modes.beforeHTML.processComment=function(data){tree.insertComment(data,tree.document)},modes.beforeHTML.processCharacters=function(buffer){buffer.skipLeadingWhitespace(),buffer.length&&(this.anythingElse(),tree.insertionMode.processCharacters(buffer))},modes.beforeHTML.startTagHtml=function(name,attributes){tree.insertHtmlElement(attributes),tree.setInsertionMode(\"beforeHead\")},modes.beforeHTML.startTagOther=function(name,attributes,selfClosing){this.anythingElse(),tree.insertionMode.processStartTag(name,attributes,selfClosing)},modes.beforeHTML.processEndTag=function(name){this.anythingElse(),tree.insertionMode.processEndTag(name)},modes.beforeHTML.anythingElse=function(){tree.insertHtmlElement(),tree.setInsertionMode(\"beforeHead\")},modes.afterAfterBody=Object.create(modes.base),modes.afterAfterBody.start_tag_handlers={html:\"startTagHtml\",\"-default\":\"startTagOther\"},modes.afterAfterBody.processComment=function(data){tree.insertComment(data,tree.document)},modes.afterAfterBody.processDoctype=function(data){modes.inBody.processDoctype(data)},modes.afterAfterBody.startTagHtml=function(data,attributes){modes.inBody.startTagHtml(data,attributes)},modes.afterAfterBody.startTagOther=function(name,attributes,selfClosing){tree.parseError(\"unexpected-start-tag\",{name:name}),tree.setInsertionMode(\"inBody\"),tree.insertionMode.processStartTag(name,attributes,selfClosing)},modes.afterAfterBody.endTagOther=function(name){tree.parseError(\"unexpected-end-tag\",{name:name}),tree.setInsertionMode(\"inBody\"),tree.insertionMode.processEndTag(name)},modes.afterAfterBody.processCharacters=function(data){return isAllWhitespace(data.characters)?(modes.inBody.processCharacters(data),void 0):(tree.parseError(\"unexpected-char-after-body\"),tree.setInsertionMode(\"inBody\"),tree.insertionMode.processCharacters(data))},modes.afterBody=Object.create(modes.base),modes.afterBody.end_tag_handlers={html:\"endTagHtml\",\"-default\":\"endTagOther\"},modes.afterBody.processComment=function(data){tree.insertComment(data,tree.openElements.rootNode)},modes.afterBody.processCharacters=function(data){return isAllWhitespace(data.characters)?(modes.inBody.processCharacters(data),void 0):(tree.parseError(\"unexpected-char-after-body\"),tree.setInsertionMode(\"inBody\"),tree.insertionMode.processCharacters(data))},modes.afterBody.processStartTag=function(name,attributes,selfClosing){tree.parseError(\"unexpected-start-tag-after-body\",{name:name}),tree.setInsertionMode(\"inBody\"),tree.insertionMode.processStartTag(name,attributes,selfClosing)},modes.afterBody.endTagHtml=function(){tree.context?tree.parseError(\"end-html-in-innerhtml\"):tree.setInsertionMode(\"afterAfterBody\")},modes.afterBody.endTagOther=function(name){tree.parseError(\"unexpected-end-tag-after-body\",{name:name}),tree.setInsertionMode(\"inBody\"),tree.insertionMode.processEndTag(name)},modes.afterFrameset=Object.create(modes.base),modes.afterFrameset.start_tag_handlers={html:\"startTagHtml\",noframes:\"startTagNoframes\",\"-default\":\"startTagOther\"},modes.afterFrameset.end_tag_handlers={html:\"endTagHtml\",\"-default\":\"endTagOther\"},modes.afterFrameset.processCharacters=function(buffer){for(var characters=buffer.takeRemaining(),whitespace=\"\",i=0;characters.length>i;i++){var ch=characters[i];isWhitespace(ch)&&(whitespace+=ch)}whitespace&&tree.insertText(whitespace),whitespace.length<characters.length&&tree.parseError(\"expected-eof-but-got-char\")},modes.afterFrameset.startTagNoframes=function(name,attributes){modes.inHead.processStartTag(name,attributes)},modes.afterFrameset.startTagOther=function(name){tree.parseError(\"unexpected-start-tag-after-frameset\",{name:name})},modes.afterFrameset.endTagHtml=function(){tree.setInsertionMode(\"afterAfterFrameset\")},modes.afterFrameset.endTagOther=function(name){tree.parseError(\"unexpected-end-tag-after-frameset\",{name:name})},modes.beforeHead=Object.create(modes.base),modes.beforeHead.start_tag_handlers={html:\"startTagHtml\",head:\"startTagHead\",\"-default\":\"startTagOther\"},modes.beforeHead.end_tag_handlers={html:\"endTagImplyHead\",head:\"endTagImplyHead\",body:\"endTagImplyHead\",br:\"endTagImplyHead\",\"-default\":\"endTagOther\"},modes.beforeHead.processEOF=function(){this.startTagHead(\"head\",[]),tree.insertionMode.processEOF()},modes.beforeHead.processCharacters=function(buffer){buffer.skipLeadingWhitespace(),buffer.length&&(this.startTagHead(\"head\",[]),tree.insertionMode.processCharacters(buffer))},modes.beforeHead.startTagHead=function(name,attributes){tree.insertHeadElement(attributes),tree.setInsertionMode(\"inHead\")},modes.beforeHead.startTagOther=function(name,attributes,selfClosing){this.startTagHead(\"head\",[]),tree.insertionMode.processStartTag(name,attributes,selfClosing)},modes.beforeHead.endTagImplyHead=function(name){this.startTagHead(\"head\",[]),tree.insertionMode.processEndTag(name)},modes.beforeHead.endTagOther=function(name){tree.parseError(\"end-tag-after-implied-root\",{name:name})},modes.inHead=Object.create(modes.base),modes.inHead.start_tag_handlers={html:\"startTagHtml\",head:\"startTagHead\",title:\"startTagTitle\",script:\"startTagScript\",style:\"startTagNoFramesStyle\",noscript:\"startTagNoScript\",noframes:\"startTagNoFramesStyle\",base:\"startTagBaseBasefontBgsoundLink\",basefont:\"startTagBaseBasefontBgsoundLink\",bgsound:\"startTagBaseBasefontBgsoundLink\",link:\"startTagBaseBasefontBgsoundLink\",meta:\"startTagMeta\",\"-default\":\"startTagOther\"},modes.inHead.end_tag_handlers={head:\"endTagHead\",html:\"endTagHtmlBodyBr\",body:\"endTagHtmlBodyBr\",br:\"endTagHtmlBodyBr\",\"-default\":\"endTagOther\"},modes.inHead.processEOF=function(){var name=tree.currentStackItem().localName;\\n-1!=[\"title\",\"style\",\"script\"].indexOf(name)&&(tree.parseError(\"expected-named-closing-tag-but-got-eof\",{name:name}),tree.popElement()),this.anythingElse(),tree.insertionMode.processEOF()},modes.inHead.processCharacters=function(buffer){var leadingWhitespace=buffer.takeLeadingWhitespace();leadingWhitespace&&tree.insertText(leadingWhitespace),buffer.length&&(this.anythingElse(),tree.insertionMode.processCharacters(buffer))},modes.inHead.startTagHtml=function(name,attributes){modes.inBody.processStartTag(name,attributes)},modes.inHead.startTagHead=function(){tree.parseError(\"two-heads-are-not-better-than-one\")},modes.inHead.startTagTitle=function(name,attributes){tree.processGenericRCDATAStartTag(name,attributes)},modes.inHead.startTagNoScript=function(name,attributes){return tree.scriptingEnabled?tree.processGenericRawTextStartTag(name,attributes):(tree.insertElement(name,attributes),tree.setInsertionMode(\"inHeadNoscript\"),void 0)},modes.inHead.startTagNoFramesStyle=function(name,attributes){tree.processGenericRawTextStartTag(name,attributes)},modes.inHead.startTagScript=function(name,attributes){tree.insertElement(name,attributes),tree.tokenizer.setState(Tokenizer.SCRIPT_DATA),tree.originalInsertionMode=tree.insertionModeName,tree.setInsertionMode(\"text\")},modes.inHead.startTagBaseBasefontBgsoundLink=function(name,attributes){tree.insertSelfClosingElement(name,attributes)},modes.inHead.startTagMeta=function(name,attributes){tree.insertSelfClosingElement(name,attributes)},modes.inHead.startTagOther=function(name,attributes,selfClosing){this.anythingElse(),tree.insertionMode.processStartTag(name,attributes,selfClosing)},modes.inHead.endTagHead=function(){\"head\"==tree.openElements.item(tree.openElements.length-1).localName?tree.openElements.pop():tree.parseError(\"unexpected-end-tag\",{name:\"head\"}),tree.setInsertionMode(\"afterHead\")},modes.inHead.endTagHtmlBodyBr=function(name){this.anythingElse(),tree.insertionMode.processEndTag(name)},modes.inHead.endTagOther=function(name){tree.parseError(\"unexpected-end-tag\",{name:name})},modes.inHead.anythingElse=function(){this.endTagHead(\"head\")},modes.afterHead=Object.create(modes.base),modes.afterHead.start_tag_handlers={html:\"startTagHtml\",head:\"startTagHead\",body:\"startTagBody\",frameset:\"startTagFrameset\",base:\"startTagFromHead\",link:\"startTagFromHead\",meta:\"startTagFromHead\",script:\"startTagFromHead\",style:\"startTagFromHead\",title:\"startTagFromHead\",\"-default\":\"startTagOther\"},modes.afterHead.end_tag_handlers={body:\"endTagBodyHtmlBr\",html:\"endTagBodyHtmlBr\",br:\"endTagBodyHtmlBr\",\"-default\":\"endTagOther\"},modes.afterHead.processEOF=function(){this.anythingElse(),tree.insertionMode.processEOF()},modes.afterHead.processCharacters=function(buffer){var leadingWhitespace=buffer.takeLeadingWhitespace();leadingWhitespace&&tree.insertText(leadingWhitespace),buffer.length&&(this.anythingElse(),tree.insertionMode.processCharacters(buffer))},modes.afterHead.startTagHtml=function(name,attributes){modes.inBody.processStartTag(name,attributes)},modes.afterHead.startTagBody=function(name,attributes){tree.framesetOk=!1,tree.insertBodyElement(attributes),tree.setInsertionMode(\"inBody\")},modes.afterHead.startTagFrameset=function(name,attributes){tree.insertElement(name,attributes),tree.setInsertionMode(\"inFrameset\")},modes.afterHead.startTagFromHead=function(name,attributes,selfClosing){tree.parseError(\"unexpected-start-tag-out-of-my-head\",{name:name}),tree.openElements.push(tree.head),modes.inHead.processStartTag(name,attributes,selfClosing),tree.openElements.remove(tree.head)},modes.afterHead.startTagHead=function(name){tree.parseError(\"unexpected-start-tag\",{name:name})},modes.afterHead.startTagOther=function(name,attributes,selfClosing){this.anythingElse(),tree.insertionMode.processStartTag(name,attributes,selfClosing)},modes.afterHead.endTagBodyHtmlBr=function(name){this.anythingElse(),tree.insertionMode.processEndTag(name)},modes.afterHead.endTagOther=function(name){tree.parseError(\"unexpected-end-tag\",{name:name})},modes.afterHead.anythingElse=function(){tree.insertBodyElement([]),tree.setInsertionMode(\"inBody\"),tree.framesetOk=!0},modes.inBody=Object.create(modes.base),modes.inBody.start_tag_handlers={html:\"startTagHtml\",head:\"startTagMisplaced\",base:\"startTagProcessInHead\",basefont:\"startTagProcessInHead\",bgsound:\"startTagProcessInHead\",link:\"startTagProcessInHead\",meta:\"startTagProcessInHead\",noframes:\"startTagProcessInHead\",script:\"startTagProcessInHead\",style:\"startTagProcessInHead\",title:\"startTagProcessInHead\",body:\"startTagBody\",form:\"startTagForm\",plaintext:\"startTagPlaintext\",a:\"startTagA\",button:\"startTagButton\",xmp:\"startTagXmp\",table:\"startTagTable\",hr:\"startTagHr\",image:\"startTagImage\",input:\"startTagInput\",textarea:\"startTagTextarea\",select:\"startTagSelect\",isindex:\"startTagIsindex\",applet:\"startTagAppletMarqueeObject\",marquee:\"startTagAppletMarqueeObject\",object:\"startTagAppletMarqueeObject\",li:\"startTagListItem\",dd:\"startTagListItem\",dt:\"startTagListItem\",address:\"startTagCloseP\",article:\"startTagCloseP\",aside:\"startTagCloseP\",blockquote:\"startTagCloseP\",center:\"startTagCloseP\",details:\"startTagCloseP\",dir:\"startTagCloseP\",div:\"startTagCloseP\",dl:\"startTagCloseP\",fieldset:\"startTagCloseP\",figcaption:\"startTagCloseP\",figure:\"startTagCloseP\",footer:\"startTagCloseP\",header:\"startTagCloseP\",hgroup:\"startTagCloseP\",main:\"startTagCloseP\",menu:\"startTagCloseP\",nav:\"startTagCloseP\",ol:\"startTagCloseP\",p:\"startTagCloseP\",section:\"startTagCloseP\",summary:\"startTagCloseP\",ul:\"startTagCloseP\",listing:\"startTagPreListing\",pre:\"startTagPreListing\",b:\"startTagFormatting\",big:\"startTagFormatting\",code:\"startTagFormatting\",em:\"startTagFormatting\",font:\"startTagFormatting\",i:\"startTagFormatting\",s:\"startTagFormatting\",small:\"startTagFormatting\",strike:\"startTagFormatting\",strong:\"startTagFormatting\",tt:\"startTagFormatting\",u:\"startTagFormatting\",nobr:\"startTagNobr\",area:\"startTagVoidFormatting\",br:\"startTagVoidFormatting\",embed:\"startTagVoidFormatting\",img:\"startTagVoidFormatting\",keygen:\"startTagVoidFormatting\",wbr:\"startTagVoidFormatting\",param:\"startTagParamSourceTrack\",source:\"startTagParamSourceTrack\",track:\"startTagParamSourceTrack\",iframe:\"startTagIFrame\",noembed:\"startTagRawText\",noscript:\"startTagRawText\",h1:\"startTagHeading\",h2:\"startTagHeading\",h3:\"startTagHeading\",h4:\"startTagHeading\",h5:\"startTagHeading\",h6:\"startTagHeading\",caption:\"startTagMisplaced\",col:\"startTagMisplaced\",colgroup:\"startTagMisplaced\",frame:\"startTagMisplaced\",frameset:\"startTagFrameset\",tbody:\"startTagMisplaced\",td:\"startTagMisplaced\",tfoot:\"startTagMisplaced\",th:\"startTagMisplaced\",thead:\"startTagMisplaced\",tr:\"startTagMisplaced\",option:\"startTagOptionOptgroup\",optgroup:\"startTagOptionOptgroup\",math:\"startTagMath\",svg:\"startTagSVG\",rt:\"startTagRpRt\",rp:\"startTagRpRt\",\"-default\":\"startTagOther\"},modes.inBody.end_tag_handlers={p:\"endTagP\",body:\"endTagBody\",html:\"endTagHtml\",address:\"endTagBlock\",article:\"endTagBlock\",aside:\"endTagBlock\",blockquote:\"endTagBlock\",button:\"endTagBlock\",center:\"endTagBlock\",details:\"endTagBlock\",dir:\"endTagBlock\",div:\"endTagBlock\",dl:\"endTagBlock\",fieldset:\"endTagBlock\",figcaption:\"endTagBlock\",figure:\"endTagBlock\",footer:\"endTagBlock\",header:\"endTagBlock\",hgroup:\"endTagBlock\",listing:\"endTagBlock\",main:\"endTagBlock\",menu:\"endTagBlock\",nav:\"endTagBlock\",ol:\"endTagBlock\",pre:\"endTagBlock\",section:\"endTagBlock\",summary:\"endTagBlock\",ul:\"endTagBlock\",form:\"endTagForm\",applet:\"endTagAppletMarqueeObject\",marquee:\"endTagAppletMarqueeObject\",object:\"endTagAppletMarqueeObject\",dd:\"endTagListItem\",dt:\"endTagListItem\",li:\"endTagListItem\",h1:\"endTagHeading\",h2:\"endTagHeading\",h3:\"endTagHeading\",h4:\"endTagHeading\",h5:\"endTagHeading\",h6:\"endTagHeading\",a:\"endTagFormatting\",b:\"endTagFormatting\",big:\"endTagFormatting\",code:\"endTagFormatting\",em:\"endTagFormatting\",font:\"endTagFormatting\",i:\"endTagFormatting\",nobr:\"endTagFormatting\",s:\"endTagFormatting\",small:\"endTagFormatting\",strike:\"endTagFormatting\",strong:\"endTagFormatting\",tt:\"endTagFormatting\",u:\"endTagFormatting\",br:\"endTagBr\",\"-default\":\"endTagOther\"},modes.inBody.processCharacters=function(buffer){tree.shouldSkipLeadingNewline&&(tree.shouldSkipLeadingNewline=!1,buffer.skipAtMostOneLeadingNewline()),tree.reconstructActiveFormattingElements();var characters=buffer.takeRemaining();characters=characters.replace(/\\\\u0000/g,function(){return tree.parseError(\"invalid-codepoint\"),\"\"}),characters&&(tree.insertText(characters),tree.framesetOk&&!isAllWhitespaceOrReplacementCharacters(characters)&&(tree.framesetOk=!1))},modes.inBody.startTagHtml=function(name,attributes){tree.parseError(\"non-html-root\"),tree.addAttributesToElement(tree.openElements.rootNode,attributes)},modes.inBody.startTagProcessInHead=function(name,attributes){modes.inHead.processStartTag(name,attributes)},modes.inBody.startTagBody=function(name,attributes){tree.parseError(\"unexpected-start-tag\",{name:\"body\"}),1==tree.openElements.length||\"body\"!=tree.openElements.item(1).localName?assert.ok(tree.context):(tree.framesetOk=!1,tree.addAttributesToElement(tree.openElements.bodyElement,attributes))},modes.inBody.startTagFrameset=function(name,attributes){if(tree.parseError(\"unexpected-start-tag\",{name:\"frameset\"}),1==tree.openElements.length||\"body\"!=tree.openElements.item(1).localName)assert.ok(tree.context);else if(tree.framesetOk){for(tree.detachFromParent(tree.openElements.bodyElement);tree.openElements.length>1;)tree.openElements.pop();tree.insertElement(name,attributes),tree.setInsertionMode(\"inFrameset\")}},modes.inBody.startTagCloseP=function(name,attributes){tree.openElements.inButtonScope(\"p\")&&this.endTagP(\"p\"),tree.insertElement(name,attributes)},modes.inBody.startTagPreListing=function(name,attributes){tree.openElements.inButtonScope(\"p\")&&this.endTagP(\"p\"),tree.insertElement(name,attributes),tree.framesetOk=!1,tree.shouldSkipLeadingNewline=!0},modes.inBody.startTagForm=function(name,attributes){tree.form?tree.parseError(\"unexpected-start-tag\",{name:name}):(tree.openElements.inButtonScope(\"p\")&&this.endTagP(\"p\"),tree.insertElement(name,attributes),tree.form=tree.currentStackItem())},modes.inBody.startTagRpRt=function(name,attributes){tree.openElements.inScope(\"ruby\")&&(tree.generateImpliedEndTags(),\"ruby\"!=tree.currentStackItem().localName&&tree.parseError(\"unexpected-start-tag\",{name:name})),tree.insertElement(name,attributes)},modes.inBody.startTagListItem=function(name,attributes){for(var stopNames={li:[\"li\"],dd:[\"dd\",\"dt\"],dt:[\"dd\",\"dt\"]},stopName=stopNames[name],els=tree.openElements,i=els.length-1;i>=0;i--){var node=els.item(i);if(-1!=stopName.indexOf(node.localName)){tree.insertionMode.processEndTag(node.localName);break}if(node.isSpecial()&&\"p\"!==node.localName&&\"address\"!==node.localName&&\"div\"!==node.localName)break}tree.openElements.inButtonScope(\"p\")&&this.endTagP(\"p\"),tree.insertElement(name,attributes),tree.framesetOk=!1},modes.inBody.startTagPlaintext=function(name,attributes){tree.openElements.inButtonScope(\"p\")&&this.endTagP(\"p\"),tree.insertElement(name,attributes),tree.tokenizer.setState(Tokenizer.PLAINTEXT)},modes.inBody.startTagHeading=function(name,attributes){tree.openElements.inButtonScope(\"p\")&&this.endTagP(\"p\"),tree.currentStackItem().isNumberedHeader()&&(tree.parseError(\"unexpected-start-tag\",{name:name}),tree.popElement()),tree.insertElement(name,attributes)},modes.inBody.startTagA=function(name,attributes){var activeA=tree.elementInActiveFormattingElements(\"a\");activeA&&(tree.parseError(\"unexpected-start-tag-implies-end-tag\",{startName:\"a\",endName:\"a\"}),tree.adoptionAgencyEndTag(\"a\"),tree.openElements.contains(activeA)&&tree.openElements.remove(activeA),tree.removeElementFromActiveFormattingElements(activeA)),tree.reconstructActiveFormattingElements(),tree.insertFormattingElement(name,attributes)},modes.inBody.startTagFormatting=function(name,attributes){tree.reconstructActiveFormattingElements(),tree.insertFormattingElement(name,attributes)},modes.inBody.startTagNobr=function(name,attributes){tree.reconstructActiveFormattingElements(),tree.openElements.inScope(\"nobr\")&&(tree.parseError(\"unexpected-start-tag-implies-end-tag\",{startName:\"nobr\",endName:\"nobr\"}),this.processEndTag(\"nobr\"),tree.reconstructActiveFormattingElements()),tree.insertFormattingElement(name,attributes)},modes.inBody.startTagButton=function(name,attributes){tree.openElements.inScope(\"button\")?(tree.parseError(\"unexpected-start-tag-implies-end-tag\",{startName:\"button\",endName:\"button\"}),this.processEndTag(\"button\"),tree.insertionMode.processStartTag(name,attributes)):(tree.framesetOk=!1,tree.reconstructActiveFormattingElements(),tree.insertElement(name,attributes))},modes.inBody.startTagAppletMarqueeObject=function(name,attributes){tree.reconstructActiveFormattingElements(),tree.insertElement(name,attributes),tree.activeFormattingElements.push(Marker),tree.framesetOk=!1},modes.inBody.endTagAppletMarqueeObject=function(name){tree.openElements.inScope(name)?(tree.generateImpliedEndTags(),tree.currentStackItem().localName!=name&&tree.parseError(\"end-tag-too-early\",{name:name}),tree.openElements.popUntilPopped(name),tree.clearActiveFormattingElements()):tree.parseError(\"unexpected-end-tag\",{name:name})},modes.inBody.startTagXmp=function(name,attributes){tree.openElements.inButtonScope(\"p\")&&this.processEndTag(\"p\"),tree.reconstructActiveFormattingElements(),tree.processGenericRawTextStartTag(name,attributes),tree.framesetOk=!1},modes.inBody.startTagTable=function(name,attributes){\"quirks\"!==tree.compatMode&&tree.openElements.inButtonScope(\"p\")&&this.processEndTag(\"p\"),tree.insertElement(name,attributes),tree.setInsertionMode(\"inTable\"),tree.framesetOk=!1},modes.inBody.startTagVoidFormatting=function(name,attributes){tree.reconstructActiveFormattingElements(),tree.insertSelfClosingElement(name,attributes),tree.framesetOk=!1},modes.inBody.startTagParamSourceTrack=function(name,attributes){tree.insertSelfClosingElement(name,attributes)},modes.inBody.startTagHr=function(name,attributes){tree.openElements.inButtonScope(\"p\")&&this.endTagP(\"p\"),tree.insertSelfClosingElement(name,attributes),tree.framesetOk=!1},modes.inBody.startTagImage=function(name,attributes){tree.parseError(\"unexpected-start-tag-treated-as\",{originalName:\"image\",newName:\"img\"}),this.processStartTag(\"img\",attributes)},modes.inBody.startTagInput=function(name,attributes){var currentFramesetOk=tree.framesetOk;this.startTagVoidFormatting(name,attributes);for(var key in attributes)if(\"type\"==attributes[key].nodeName){\"hidden\"==attributes[key].nodeValue.toLowerCase()&&(tree.framesetOk=currentFramesetOk);break}},modes.inBody.startTagIsindex=function(name,attributes){if(tree.parseError(\"deprecated-tag\",{name:\"isindex\"}),tree.selfClosingFlagAcknowledged=!0,!tree.form){var formAttributes=[],inputAttributes=[],prompt=\"This is a searchable index. Enter search keywords: \";for(var key in attributes)switch(attributes[key].nodeName){case\"action\":formAttributes.push({nodeName:\"action\",nodeValue:attributes[key].nodeValue});break;case\"prompt\":prompt=attributes[key].nodeValue;break;case\"name\":break;default:inputAttributes.push({nodeName:attributes[key].nodeName,nodeValue:attributes[key].nodeValue})}inputAttributes.push({nodeName:\"name\",nodeValue:\"isindex\"}),this.processStartTag(\"form\",formAttributes),this.processStartTag(\"hr\"),this.processStartTag(\"label\"),this.processCharacters(new CharacterBuffer(prompt)),this.processStartTag(\"input\",inputAttributes),this.processEndTag(\"label\"),this.processStartTag(\"hr\"),this.processEndTag(\"form\")}},modes.inBody.startTagTextarea=function(name,attributes){tree.insertElement(name,attributes),tree.tokenizer.setState(Tokenizer.RCDATA),tree.originalInsertionMode=tree.insertionModeName,tree.shouldSkipLeadingNewline=!0,tree.framesetOk=!1,tree.setInsertionMode(\"text\")},modes.inBody.startTagIFrame=function(name,attributes){tree.framesetOk=!1,this.startTagRawText(name,attributes)},modes.inBody.startTagRawText=function(name,attributes){tree.processGenericRawTextStartTag(name,attributes)},modes.inBody.startTagSelect=function(name,attributes){tree.reconstructActiveFormattingElements(),tree.insertElement(name,attributes),tree.framesetOk=!1;var insertionModeName=tree.insertionModeName;\"inTable\"==insertionModeName||\"inCaption\"==insertionModeName||\"inColumnGroup\"==insertionModeName||\"inTableBody\"==insertionModeName||\"inRow\"==insertionModeName||\"inCell\"==insertionModeName?tree.setInsertionMode(\"inSelectInTable\"):tree.setInsertionMode(\"inSelect\")},modes.inBody.startTagMisplaced=function(name){tree.parseError(\"unexpected-start-tag-ignored\",{name:name})},modes.inBody.endTagMisplaced=function(name){tree.parseError(\"unexpected-end-tag\",{name:name})},modes.inBody.endTagBr=function(name){tree.parseError(\"unexpected-end-tag-treated-as\",{originalName:\"br\",newName:\"br element\"}),tree.reconstructActiveFormattingElements(),tree.insertElement(name,[]),tree.popElement()},modes.inBody.startTagOptionOptgroup=function(name,attributes){\"option\"==tree.currentStackItem().localName&&tree.popElement(),tree.reconstructActiveFormattingElements(),tree.insertElement(name,attributes)},modes.inBody.startTagOther=function(name,attributes){tree.reconstructActiveFormattingElements(),tree.insertElement(name,attributes)},modes.inBody.endTagOther=function(name){for(var node,i=tree.openElements.length-1;i>0;i--){if(node=tree.openElements.item(i),node.localName==name){tree.generateImpliedEndTags(name),tree.currentStackItem().localName!=name&&tree.parseError(\"unexpected-end-tag\",{name:name}),tree.openElements.remove_openElements_until(function(x){return x===node});break}if(node.isSpecial()){tree.parseError(\"unexpected-end-tag\",{name:name});break}}},modes.inBody.startTagMath=function(name,attributes,selfClosing){tree.reconstructActiveFormattingElements(),attributes=tree.adjustMathMLAttributes(attributes),attributes=tree.adjustForeignAttributes(attributes),tree.insertForeignElement(name,attributes,\"http://www.w3.org/1998/Math/MathML\",selfClosing)},modes.inBody.startTagSVG=function(name,attributes,selfClosing){tree.reconstructActiveFormattingElements(),attributes=tree.adjustSVGAttributes(attributes),attributes=tree.adjustForeignAttributes(attributes),tree.insertForeignElement(name,attributes,\"http://www.w3.org/2000/svg\",selfClosing)},modes.inBody.endTagP=function(name){tree.openElements.inButtonScope(\"p\")?(tree.generateImpliedEndTags(\"p\"),\"p\"!=tree.currentStackItem().localName&&tree.parseError(\"unexpected-implied-end-tag\",{name:\"p\"}),tree.openElements.popUntilPopped(name)):(tree.parseError(\"unexpected-end-tag\",{name:\"p\"}),this.startTagCloseP(\"p\",[]),this.endTagP(\"p\"))},modes.inBody.endTagBody=function(name){return tree.openElements.inScope(\"body\")?(\"body\"!=tree.currentStackItem().localName&&tree.parseError(\"expected-one-end-tag-but-got-another\",{expectedName:tree.currentStackItem().localName,gotName:name}),tree.setInsertionMode(\"afterBody\"),void 0):(tree.parseError(\"unexpected-end-tag\",{name:name}),void 0)},modes.inBody.endTagHtml=function(name){return tree.openElements.inScope(\"body\")?(\"body\"!=tree.currentStackItem().localName&&tree.parseError(\"expected-one-end-tag-but-got-another\",{expectedName:tree.currentStackItem().localName,gotName:name}),tree.setInsertionMode(\"afterBody\"),tree.insertionMode.processEndTag(name),void 0):(tree.parseError(\"unexpected-end-tag\",{name:name}),void 0)},modes.inBody.endTagBlock=function(name){tree.openElements.inScope(name)?(tree.generateImpliedEndTags(),tree.currentStackItem().localName!=name&&tree.parseError(\"end-tag-too-early\",{name:name}),tree.openElements.popUntilPopped(name)):tree.parseError(\"unexpected-end-tag\",{name:name})},modes.inBody.endTagForm=function(name){var node=tree.form;tree.form=null,node&&tree.openElements.inScope(name)?(tree.generateImpliedEndTags(),tree.currentStackItem()!=node&&tree.parseError(\"end-tag-too-early-ignored\",{name:\"form\"}),tree.openElements.remove(node)):tree.parseError(\"unexpected-end-tag\",{name:name})},modes.inBody.endTagListItem=function(name){tree.openElements.inListItemScope(name)?(tree.generateImpliedEndTags(name),tree.currentStackItem().localName!=name&&tree.parseError(\"end-tag-too-early\",{name:name}),tree.openElements.popUntilPopped(name)):tree.parseError(\"unexpected-end-tag\",{name:name})},modes.inBody.endTagHeading=function(name){return tree.openElements.hasNumberedHeaderElementInScope()?(tree.generateImpliedEndTags(),tree.currentStackItem().localName!=name&&tree.parseError(\"end-tag-too-early\",{name:name}),tree.openElements.remove_openElements_until(function(e){return e.isNumberedHeader()}),void 0):(tree.parseError(\"unexpected-end-tag\",{name:name}),void 0)},modes.inBody.endTagFormatting=function(name,attributes){tree.adoptionAgencyEndTag(name)||this.endTagOther(name,attributes)},modes.inCaption=Object.create(modes.base),modes.inCaption.start_tag_handlers={html:\"startTagHtml\",caption:\"startTagTableElement\",col:\"startTagTableElement\",colgroup:\"startTagTableElement\",tbody:\"startTagTableElement\",td:\"startTagTableElement\",tfoot:\"startTagTableElement\",thead:\"startTagTableElement\",tr:\"startTagTableElement\",\"-default\":\"startTagOther\"},modes.inCaption.end_tag_handlers={caption:\"endTagCaption\",table:\"endTagTable\",body:\"endTagIgnore\",col:\"endTagIgnore\",colgroup:\"endTagIgnore\",html:\"endTagIgnore\",tbody:\"endTagIgnore\",td:\"endTagIgnore\",tfood:\"endTagIgnore\",thead:\"endTagIgnore\",tr:\"endTagIgnore\",\"-default\":\"endTagOther\"},modes.inCaption.processCharacters=function(data){modes.inBody.processCharacters(data)},modes.inCaption.startTagTableElement=function(name,attributes){tree.parseError(\"unexpected-end-tag\",{name:name});var ignoreEndTag=!tree.openElements.inTableScope(\"caption\");tree.insertionMode.processEndTag(\"caption\"),ignoreEndTag||tree.insertionMode.processStartTag(name,attributes)},modes.inCaption.startTagOther=function(name,attributes,selfClosing){modes.inBody.processStartTag(name,attributes,selfClosing)},modes.inCaption.endTagCaption=function(name){tree.openElements.inTableScope(\"caption\")?(tree.generateImpliedEndTags(),\"caption\"!=tree.currentStackItem().localName&&tree.parseError(\"expected-one-end-tag-but-got-another\",{gotName:\"caption\",expectedName:tree.currentStackItem().localName}),tree.openElements.popUntilPopped(\"caption\"),tree.clearActiveFormattingElements(),tree.setInsertionMode(\"inTable\")):(assert.ok(tree.context),tree.parseError(\"unexpected-end-tag\",{name:name}))},modes.inCaption.endTagTable=function(name){tree.parseError(\"unexpected-end-table-in-caption\");var ignoreEndTag=!tree.openElements.inTableScope(\"caption\");tree.insertionMode.processEndTag(\"caption\"),ignoreEndTag||tree.insertionMode.processEndTag(name)},modes.inCaption.endTagIgnore=function(name){tree.parseError(\"unexpected-end-tag\",{name:name})},modes.inCaption.endTagOther=function(name){modes.inBody.processEndTag(name)},modes.inCell=Object.create(modes.base),modes.inCell.start_tag_handlers={html:\"startTagHtml\",caption:\"startTagTableOther\",col:\"startTagTableOther\",colgroup:\"startTagTableOther\",tbody:\"startTagTableOther\",td:\"startTagTableOther\",tfoot:\"startTagTableOther\",th:\"startTagTableOther\",thead:\"startTagTableOther\",tr:\"startTagTableOther\",\"-default\":\"startTagOther\"},modes.inCell.end_tag_handlers={td:\"endTagTableCell\",th:\"endTagTableCell\",body:\"endTagIgnore\",caption:\"endTagIgnore\",col:\"endTagIgnore\",colgroup:\"endTagIgnore\",html:\"endTagIgnore\",table:\"endTagImply\",tbody:\"endTagImply\",tfoot:\"endTagImply\",thead:\"endTagImply\",tr:\"endTagImply\",\"-default\":\"endTagOther\"},modes.inCell.processCharacters=function(data){modes.inBody.processCharacters(data)},modes.inCell.startTagTableOther=function(name,attributes,selfClosing){tree.openElements.inTableScope(\"td\")||tree.openElements.inTableScope(\"th\")?(this.closeCell(),tree.insertionMode.processStartTag(name,attributes,selfClosing)):tree.parseError(\"unexpected-start-tag\",{name:name})},modes.inCell.startTagOther=function(name,attributes,selfClosing){modes.inBody.processStartTag(name,attributes,selfClosing)},modes.inCell.endTagTableCell=function(name){tree.openElements.inTableScope(name)?(tree.generateImpliedEndTags(name),tree.currentStackItem().localName!=name.toLowerCase()?(tree.parseError(\"unexpected-cell-end-tag\",{name:name}),tree.openElements.popUntilPopped(name)):tree.popElement(),tree.clearActiveFormattingElements(),tree.setInsertionMode(\"inRow\")):tree.parseError(\"unexpected-end-tag\",{name:name})},modes.inCell.endTagIgnore=function(name){tree.parseError(\"unexpected-end-tag\",{name:name})},modes.inCell.endTagImply=function(name){tree.openElements.inTableScope(name)?(this.closeCell(),tree.insertionMode.processEndTag(name)):tree.parseError(\"unexpected-end-tag\",{name:name})},modes.inCell.endTagOther=function(name){modes.inBody.processEndTag(name)},modes.inCell.closeCell=function(){tree.openElements.inTableScope(\"td\")?this.endTagTableCell(\"td\"):tree.openElements.inTableScope(\"th\")&&this.endTagTableCell(\"th\")},modes.inColumnGroup=Object.create(modes.base),modes.inColumnGroup.start_tag_handlers={html:\"startTagHtml\",col:\"startTagCol\",\"-default\":\"startTagOther\"},modes.inColumnGroup.end_tag_handlers={colgroup:\"endTagColgroup\",col:\"endTagCol\",\"-default\":\"endTagOther\"},modes.inColumnGroup.ignoreEndTagColgroup=function(){return\"html\"==tree.currentStackItem().localName},modes.inColumnGroup.processCharacters=function(buffer){var leadingWhitespace=buffer.takeLeadingWhitespace();if(leadingWhitespace&&tree.insertText(leadingWhitespace),buffer.length){var ignoreEndTag=this.ignoreEndTagColgroup();this.endTagColgroup(\"colgroup\"),ignoreEndTag||tree.insertionMode.processCharacters(buffer)}},modes.inColumnGroup.startTagCol=function(name,attributes){tree.insertSelfClosingElement(name,attributes)},modes.inColumnGroup.startTagOther=function(name,attributes,selfClosing){var ignoreEndTag=this.ignoreEndTagColgroup();this.endTagColgroup(\"colgroup\"),ignoreEndTag||tree.insertionMode.processStartTag(name,attributes,selfClosing)},modes.inColumnGroup.endTagColgroup=function(name){this.ignoreEndTagColgroup()?(assert.ok(tree.context),tree.parseError(\"unexpected-end-tag\",{name:name})):(tree.popElement(),tree.setInsertionMode(\"inTable\"))},modes.inColumnGroup.endTagCol=function(){tree.parseError(\"no-end-tag\",{name:\"col\"})},modes.inColumnGroup.endTagOther=function(name){var ignoreEndTag=this.ignoreEndTagColgroup();this.endTagColgroup(\"colgroup\"),ignoreEndTag||tree.insertionMode.processEndTag(name)},modes.inForeignContent=Object.create(modes.base),modes.inForeignContent.processStartTag=function(name,attributes,selfClosing){if(-1!=[\"b\",\"big\",\"blockquote\",\"body\",\"br\",\"center\",\"code\",\"dd\",\"div\",\"dl\",\"dt\",\"em\",\"embed\",\"h1\",\"h2\",\"h3\",\"h4\",\"h5\",\"h6\",\"head\",\"hr\",\"i\",\"img\",\"li\",\"listing\",\"menu\",\"meta\",\"nobr\",\"ol\",\"p\",\"pre\",\"ruby\",\"s\",\"small\",\"span\",\"strong\",\"strike\",\"sub\",\"sup\",\"table\",\"tt\",\"u\",\"ul\",\"var\"].indexOf(name)||\"font\"==name&&attributes.some(function(attr){return[\"color\",\"face\",\"size\"].indexOf(attr.nodeName)>=0})){for(tree.parseError(\"unexpected-html-element-in-foreign-content\",{name:name});tree.currentStackItem().isForeign()&&!tree.currentStackItem().isHtmlIntegrationPoint()&&!tree.currentStackItem().isMathMLTextIntegrationPoint();)tree.openElements.pop();return tree.insertionMode.processStartTag(name,attributes,selfClosing),void 0}\"http://www.w3.org/1998/Math/MathML\"==tree.currentStackItem().namespaceURI&&(attributes=tree.adjustMathMLAttributes(attributes)),\"http://www.w3.org/2000/svg\"==tree.currentStackItem().namespaceURI&&(name=tree.adjustSVGTagNameCase(name),attributes=tree.adjustSVGAttributes(attributes)),attributes=tree.adjustForeignAttributes(attributes),tree.insertForeignElement(name,attributes,tree.currentStackItem().namespaceURI,selfClosing)},modes.inForeignContent.processEndTag=function(name){var node=tree.currentStackItem(),index=tree.openElements.length-1;for(node.localName.toLowerCase()!=name&&tree.parseError(\"unexpected-end-tag\",{name:name});;){if(0===index)break;if(node.localName.toLowerCase()==name){for(;tree.openElements.pop()!=node;);break}if(index-=1,node=tree.openElements.item(index),!node.isForeign()){tree.insertionMode.processEndTag(name);break}}},modes.inForeignContent.processCharacters=function(buffer){var characters=buffer.takeRemaining();characters=characters.replace(/\\\\u0000/g,function(){return tree.parseError(\"invalid-codepoint\"),\"�\"}),tree.framesetOk&&!isAllWhitespaceOrReplacementCharacters(characters)&&(tree.framesetOk=!1),tree.insertText(characters)},modes.inHeadNoscript=Object.create(modes.base),modes.inHeadNoscript.start_tag_handlers={html:\"startTagHtml\",basefont:\"startTagBasefontBgsoundLinkMetaNoframesStyle\",bgsound:\"startTagBasefontBgsoundLinkMetaNoframesStyle\",link:\"startTagBasefontBgsoundLinkMetaNoframesStyle\",meta:\"startTagBasefontBgsoundLinkMetaNoframesStyle\",noframes:\"startTagBasefontBgsoundLinkMetaNoframesStyle\",style:\"startTagBasefontBgsoundLinkMetaNoframesStyle\",head:\"startTagHeadNoscript\",noscript:\"startTagHeadNoscript\",\"-default\":\"startTagOther\"},modes.inHeadNoscript.end_tag_handlers={noscript:\"endTagNoscript\",br:\"endTagBr\",\"-default\":\"endTagOther\"},modes.inHeadNoscript.processCharacters=function(buffer){var leadingWhitespace=buffer.takeLeadingWhitespace();leadingWhitespace&&tree.insertText(leadingWhitespace),buffer.length&&(tree.parseError(\"unexpected-char-in-frameset\"),this.anythingElse(),tree.insertionMode.processCharacters(buffer))},modes.inHeadNoscript.processComment=function(data){modes.inHead.processComment(data)},modes.inHeadNoscript.startTagBasefontBgsoundLinkMetaNoframesStyle=function(name,attributes){modes.inHead.processStartTag(name,attributes)},modes.inHeadNoscript.startTagHeadNoscript=function(name){tree.parseError(\"unexpected-start-tag-in-frameset\",{name:name})},modes.inHeadNoscript.startTagOther=function(name,attributes){tree.parseError(\"unexpected-start-tag-in-frameset\",{name:name}),this.anythingElse(),tree.insertionMode.processStartTag(name,attributes)},modes.inHeadNoscript.endTagBr=function(name,attributes){tree.parseError(\"unexpected-end-tag-in-frameset\",{name:name}),this.anythingElse(),tree.insertionMode.processEndTag(name,attributes)},modes.inHeadNoscript.endTagNoscript=function(){tree.popElement(),tree.setInsertionMode(\"inHead\")},modes.inHeadNoscript.endTagOther=function(name){tree.parseError(\"unexpected-end-tag-in-frameset\",{name:name})},modes.inHeadNoscript.anythingElse=function(){tree.popElement(),tree.setInsertionMode(\"inHead\")},modes.inFrameset=Object.create(modes.base),modes.inFrameset.start_tag_handlers={html:\"startTagHtml\",frameset:\"startTagFrameset\",frame:\"startTagFrame\",noframes:\"startTagNoframes\",\"-default\":\"startTagOther\"},modes.inFrameset.end_tag_handlers={frameset:\"endTagFrameset\",noframes:\"endTagNoframes\",\"-default\":\"endTagOther\"},modes.inFrameset.processCharacters=function(){tree.parseError(\"unexpected-char-in-frameset\")},modes.inFrameset.startTagFrameset=function(name,attributes){tree.insertElement(name,attributes)},modes.inFrameset.startTagFrame=function(name,attributes){tree.insertSelfClosingElement(name,attributes)},modes.inFrameset.startTagNoframes=function(name,attributes){modes.inBody.processStartTag(name,attributes)},modes.inFrameset.startTagOther=function(name){tree.parseError(\"unexpected-start-tag-in-frameset\",{name:name})},modes.inFrameset.endTagFrameset=function(){\"html\"==tree.currentStackItem().localName?tree.parseError(\"unexpected-frameset-in-frameset-innerhtml\"):tree.popElement(),tree.context||\"frameset\"==tree.currentStackItem().localName||tree.setInsertionMode(\"afterFrameset\")},modes.inFrameset.endTagNoframes=function(name){modes.inBody.processEndTag(name)},modes.inFrameset.endTagOther=function(name){tree.parseError(\"unexpected-end-tag-in-frameset\",{name:name})},modes.inTable=Object.create(modes.base),modes.inTable.start_tag_handlers={html:\"startTagHtml\",caption:\"startTagCaption\",colgroup:\"startTagColgroup\",col:\"startTagCol\",table:\"startTagTable\",tbody:\"startTagRowGroup\",tfoot:\"startTagRowGroup\",thead:\"startTagRowGroup\",td:\"startTagImplyTbody\",th:\"startTagImplyTbody\",tr:\"startTagImplyTbody\",style:\"startTagStyleScript\",script:\"startTagStyleScript\",input:\"startTagInput\",form:\"startTagForm\",\"-default\":\"startTagOther\"},modes.inTable.end_tag_handlers={table:\"endTagTable\",body:\"endTagIgnore\",caption:\"endTagIgnore\",col:\"endTagIgnore\",colgroup:\"endTagIgnore\",html:\"endTagIgnore\",tbody:\"endTagIgnore\",td:\"endTagIgnore\",tfoot:\"endTagIgnore\",th:\"endTagIgnore\",thead:\"endTagIgnore\",tr:\"endTagIgnore\",\"-default\":\"endTagOther\"},modes.inTable.processCharacters=function(data){if(tree.currentStackItem().isFosterParenting()){var originalInsertionMode=tree.insertionModeName;\\ntree.setInsertionMode(\"inTableText\"),tree.originalInsertionMode=originalInsertionMode,tree.insertionMode.processCharacters(data)}else tree.redirectAttachToFosterParent=!0,modes.inBody.processCharacters(data),tree.redirectAttachToFosterParent=!1},modes.inTable.startTagCaption=function(name,attributes){tree.openElements.popUntilTableScopeMarker(),tree.activeFormattingElements.push(Marker),tree.insertElement(name,attributes),tree.setInsertionMode(\"inCaption\")},modes.inTable.startTagColgroup=function(name,attributes){tree.openElements.popUntilTableScopeMarker(),tree.insertElement(name,attributes),tree.setInsertionMode(\"inColumnGroup\")},modes.inTable.startTagCol=function(name,attributes){this.startTagColgroup(\"colgroup\",[]),tree.insertionMode.processStartTag(name,attributes)},modes.inTable.startTagRowGroup=function(name,attributes){tree.openElements.popUntilTableScopeMarker(),tree.insertElement(name,attributes),tree.setInsertionMode(\"inTableBody\")},modes.inTable.startTagImplyTbody=function(name,attributes){this.startTagRowGroup(\"tbody\",[]),tree.insertionMode.processStartTag(name,attributes)},modes.inTable.startTagTable=function(name,attributes){tree.parseError(\"unexpected-start-tag-implies-end-tag\",{startName:\"table\",endName:\"table\"}),tree.insertionMode.processEndTag(\"table\"),tree.context||tree.insertionMode.processStartTag(name,attributes)},modes.inTable.startTagStyleScript=function(name,attributes){modes.inHead.processStartTag(name,attributes)},modes.inTable.startTagInput=function(name,attributes){for(var key in attributes)if(\"type\"==attributes[key].nodeName.toLowerCase()){if(\"hidden\"==attributes[key].nodeValue.toLowerCase())return tree.parseError(\"unexpected-hidden-input-in-table\"),tree.insertElement(name,attributes),tree.openElements.pop(),void 0;break}this.startTagOther(name,attributes)},modes.inTable.startTagForm=function(name,attributes){tree.parseError(\"unexpected-form-in-table\"),tree.form||(tree.insertElement(name,attributes),tree.form=tree.currentStackItem(),tree.openElements.pop())},modes.inTable.startTagOther=function(name,attributes,selfClosing){tree.parseError(\"unexpected-start-tag-implies-table-voodoo\",{name:name}),tree.redirectAttachToFosterParent=!0,modes.inBody.processStartTag(name,attributes,selfClosing),tree.redirectAttachToFosterParent=!1},modes.inTable.endTagTable=function(name){tree.openElements.inTableScope(name)?(tree.generateImpliedEndTags(),tree.currentStackItem().localName!=name&&tree.parseError(\"end-tag-too-early-named\",{gotName:\"table\",expectedName:tree.currentStackItem().localName}),tree.openElements.popUntilPopped(\"table\"),tree.resetInsertionMode()):(assert.ok(tree.context),tree.parseError(\"unexpected-end-tag\",{name:name}))},modes.inTable.endTagIgnore=function(name){tree.parseError(\"unexpected-end-tag\",{name:name})},modes.inTable.endTagOther=function(name){tree.parseError(\"unexpected-end-tag-implies-table-voodoo\",{name:name}),tree.redirectAttachToFosterParent=!0,modes.inBody.processEndTag(name),tree.redirectAttachToFosterParent=!1},modes.inTableText=Object.create(modes.base),modes.inTableText.flushCharacters=function(){var characters=tree.pendingTableCharacters.join(\"\");isAllWhitespace(characters)?tree.insertText(characters):(tree.redirectAttachToFosterParent=!0,tree.reconstructActiveFormattingElements(),tree.insertText(characters),tree.framesetOk=!1,tree.redirectAttachToFosterParent=!1),tree.pendingTableCharacters=[]},modes.inTableText.processComment=function(data){this.flushCharacters(),tree.setInsertionMode(tree.originalInsertionMode),tree.insertionMode.processComment(data)},modes.inTableText.processEOF=function(){this.flushCharacters(),tree.setInsertionMode(tree.originalInsertionMode),tree.insertionMode.processEOF()},modes.inTableText.processCharacters=function(buffer){var characters=buffer.takeRemaining();characters=characters.replace(/\\\\u0000/g,function(){return tree.parseError(\"invalid-codepoint\"),\"\"}),characters&&tree.pendingTableCharacters.push(characters)},modes.inTableText.processStartTag=function(name,attributes,selfClosing){this.flushCharacters(),tree.setInsertionMode(tree.originalInsertionMode),tree.insertionMode.processStartTag(name,attributes,selfClosing)},modes.inTableText.processEndTag=function(name,attributes){this.flushCharacters(),tree.setInsertionMode(tree.originalInsertionMode),tree.insertionMode.processEndTag(name,attributes)},modes.inTableBody=Object.create(modes.base),modes.inTableBody.start_tag_handlers={html:\"startTagHtml\",tr:\"startTagTr\",td:\"startTagTableCell\",th:\"startTagTableCell\",caption:\"startTagTableOther\",col:\"startTagTableOther\",colgroup:\"startTagTableOther\",tbody:\"startTagTableOther\",tfoot:\"startTagTableOther\",thead:\"startTagTableOther\",\"-default\":\"startTagOther\"},modes.inTableBody.end_tag_handlers={table:\"endTagTable\",tbody:\"endTagTableRowGroup\",tfoot:\"endTagTableRowGroup\",thead:\"endTagTableRowGroup\",body:\"endTagIgnore\",caption:\"endTagIgnore\",col:\"endTagIgnore\",colgroup:\"endTagIgnore\",html:\"endTagIgnore\",td:\"endTagIgnore\",th:\"endTagIgnore\",tr:\"endTagIgnore\",\"-default\":\"endTagOther\"},modes.inTableBody.processCharacters=function(data){modes.inTable.processCharacters(data)},modes.inTableBody.startTagTr=function(name,attributes){tree.openElements.popUntilTableBodyScopeMarker(),tree.insertElement(name,attributes),tree.setInsertionMode(\"inRow\")},modes.inTableBody.startTagTableCell=function(name,attributes){tree.parseError(\"unexpected-cell-in-table-body\",{name:name}),this.startTagTr(\"tr\",[]),tree.insertionMode.processStartTag(name,attributes)},modes.inTableBody.startTagTableOther=function(name,attributes){tree.openElements.inTableScope(\"tbody\")||tree.openElements.inTableScope(\"thead\")||tree.openElements.inTableScope(\"tfoot\")?(tree.openElements.popUntilTableBodyScopeMarker(),this.endTagTableRowGroup(tree.currentStackItem().localName),tree.insertionMode.processStartTag(name,attributes)):tree.parseError(\"unexpected-start-tag\",{name:name})},modes.inTableBody.startTagOther=function(name,attributes){modes.inTable.processStartTag(name,attributes)},modes.inTableBody.endTagTableRowGroup=function(name){tree.openElements.inTableScope(name)?(tree.openElements.popUntilTableBodyScopeMarker(),tree.popElement(),tree.setInsertionMode(\"inTable\")):tree.parseError(\"unexpected-end-tag-in-table-body\",{name:name})},modes.inTableBody.endTagTable=function(name){tree.openElements.inTableScope(\"tbody\")||tree.openElements.inTableScope(\"thead\")||tree.openElements.inTableScope(\"tfoot\")?(tree.openElements.popUntilTableBodyScopeMarker(),this.endTagTableRowGroup(tree.currentStackItem().localName),tree.insertionMode.processEndTag(name)):tree.parseError(\"unexpected-end-tag\",{name:name})},modes.inTableBody.endTagIgnore=function(name){tree.parseError(\"unexpected-end-tag-in-table-body\",{name:name})},modes.inTableBody.endTagOther=function(name){modes.inTable.processEndTag(name)},modes.inSelect=Object.create(modes.base),modes.inSelect.start_tag_handlers={html:\"startTagHtml\",option:\"startTagOption\",optgroup:\"startTagOptgroup\",select:\"startTagSelect\",input:\"startTagInput\",keygen:\"startTagInput\",textarea:\"startTagInput\",script:\"startTagScript\",\"-default\":\"startTagOther\"},modes.inSelect.end_tag_handlers={option:\"endTagOption\",optgroup:\"endTagOptgroup\",select:\"endTagSelect\",caption:\"endTagTableElements\",table:\"endTagTableElements\",tbody:\"endTagTableElements\",tfoot:\"endTagTableElements\",thead:\"endTagTableElements\",tr:\"endTagTableElements\",td:\"endTagTableElements\",th:\"endTagTableElements\",\"-default\":\"endTagOther\"},modes.inSelect.processCharacters=function(buffer){var data=buffer.takeRemaining();data=data.replace(/\\\\u0000/g,function(){return tree.parseError(\"invalid-codepoint\"),\"\"}),data&&tree.insertText(data)},modes.inSelect.startTagOption=function(name,attributes){\"option\"==tree.currentStackItem().localName&&tree.popElement(),tree.insertElement(name,attributes)},modes.inSelect.startTagOptgroup=function(name,attributes){\"option\"==tree.currentStackItem().localName&&tree.popElement(),\"optgroup\"==tree.currentStackItem().localName&&tree.popElement(),tree.insertElement(name,attributes)},modes.inSelect.endTagOption=function(name){return\"option\"!==tree.currentStackItem().localName?(tree.parseError(\"unexpected-end-tag-in-select\",{name:name}),void 0):(tree.popElement(),void 0)},modes.inSelect.endTagOptgroup=function(){\"option\"==tree.currentStackItem().localName&&\"optgroup\"==tree.openElements.item(tree.openElements.length-2).localName&&tree.popElement(),\"optgroup\"==tree.currentStackItem().localName?tree.popElement():tree.parseError(\"unexpected-end-tag-in-select\",{name:\"optgroup\"})},modes.inSelect.startTagSelect=function(){tree.parseError(\"unexpected-select-in-select\"),this.endTagSelect(\"select\")},modes.inSelect.endTagSelect=function(name){tree.openElements.inTableScope(\"select\")?(tree.openElements.popUntilPopped(\"select\"),tree.resetInsertionMode()):tree.parseError(\"unexpected-end-tag\",{name:name})},modes.inSelect.startTagInput=function(name,attributes){tree.parseError(\"unexpected-input-in-select\"),tree.openElements.inSelectScope(\"select\")&&(this.endTagSelect(\"select\"),tree.insertionMode.processStartTag(name,attributes))},modes.inSelect.startTagScript=function(name,attributes){modes.inHead.processStartTag(name,attributes)},modes.inSelect.endTagTableElements=function(name){tree.parseError(\"unexpected-end-tag-in-select\",{name:name}),tree.openElements.inTableScope(name)&&(this.endTagSelect(\"select\"),tree.insertionMode.processEndTag(name))},modes.inSelect.startTagOther=function(name){tree.parseError(\"unexpected-start-tag-in-select\",{name:name})},modes.inSelect.endTagOther=function(name){tree.parseError(\"unexpected-end-tag-in-select\",{name:name})},modes.inSelectInTable=Object.create(modes.base),modes.inSelectInTable.start_tag_handlers={caption:\"startTagTable\",table:\"startTagTable\",tbody:\"startTagTable\",tfoot:\"startTagTable\",thead:\"startTagTable\",tr:\"startTagTable\",td:\"startTagTable\",th:\"startTagTable\",\"-default\":\"startTagOther\"},modes.inSelectInTable.end_tag_handlers={caption:\"endTagTable\",table:\"endTagTable\",tbody:\"endTagTable\",tfoot:\"endTagTable\",thead:\"endTagTable\",tr:\"endTagTable\",td:\"endTagTable\",th:\"endTagTable\",\"-default\":\"endTagOther\"},modes.inSelectInTable.processCharacters=function(data){modes.inSelect.processCharacters(data)},modes.inSelectInTable.startTagTable=function(name,attributes){tree.parseError(\"unexpected-table-element-start-tag-in-select-in-table\",{name:name}),this.endTagOther(\"select\"),tree.insertionMode.processStartTag(name,attributes)},modes.inSelectInTable.startTagOther=function(name,attributes,selfClosing){modes.inSelect.processStartTag(name,attributes,selfClosing)},modes.inSelectInTable.endTagTable=function(name){tree.parseError(\"unexpected-table-element-end-tag-in-select-in-table\",{name:name}),tree.openElements.inTableScope(name)&&(this.endTagOther(\"select\"),tree.insertionMode.processEndTag(name))},modes.inSelectInTable.endTagOther=function(name){modes.inSelect.processEndTag(name)},modes.inRow=Object.create(modes.base),modes.inRow.start_tag_handlers={html:\"startTagHtml\",td:\"startTagTableCell\",th:\"startTagTableCell\",caption:\"startTagTableOther\",col:\"startTagTableOther\",colgroup:\"startTagTableOther\",tbody:\"startTagTableOther\",tfoot:\"startTagTableOther\",thead:\"startTagTableOther\",tr:\"startTagTableOther\",\"-default\":\"startTagOther\"},modes.inRow.end_tag_handlers={tr:\"endTagTr\",table:\"endTagTable\",tbody:\"endTagTableRowGroup\",tfoot:\"endTagTableRowGroup\",thead:\"endTagTableRowGroup\",body:\"endTagIgnore\",caption:\"endTagIgnore\",col:\"endTagIgnore\",colgroup:\"endTagIgnore\",html:\"endTagIgnore\",td:\"endTagIgnore\",th:\"endTagIgnore\",\"-default\":\"endTagOther\"},modes.inRow.processCharacters=function(data){modes.inTable.processCharacters(data)},modes.inRow.startTagTableCell=function(name,attributes){tree.openElements.popUntilTableRowScopeMarker(),tree.insertElement(name,attributes),tree.setInsertionMode(\"inCell\"),tree.activeFormattingElements.push(Marker)},modes.inRow.startTagTableOther=function(name,attributes){var ignoreEndTag=this.ignoreEndTagTr();this.endTagTr(\"tr\"),ignoreEndTag||tree.insertionMode.processStartTag(name,attributes)},modes.inRow.startTagOther=function(name,attributes,selfClosing){modes.inTable.processStartTag(name,attributes,selfClosing)},modes.inRow.endTagTr=function(name){this.ignoreEndTagTr()?(assert.ok(tree.context),tree.parseError(\"unexpected-end-tag\",{name:name})):(tree.openElements.popUntilTableRowScopeMarker(),tree.popElement(),tree.setInsertionMode(\"inTableBody\"))},modes.inRow.endTagTable=function(name){var ignoreEndTag=this.ignoreEndTagTr();this.endTagTr(\"tr\"),ignoreEndTag||tree.insertionMode.processEndTag(name)},modes.inRow.endTagTableRowGroup=function(name){tree.openElements.inTableScope(name)?(this.endTagTr(\"tr\"),tree.insertionMode.processEndTag(name)):tree.parseError(\"unexpected-end-tag\",{name:name})},modes.inRow.endTagIgnore=function(name){tree.parseError(\"unexpected-end-tag-in-table-row\",{name:name})},modes.inRow.endTagOther=function(name){modes.inTable.processEndTag(name)},modes.inRow.ignoreEndTagTr=function(){return!tree.openElements.inTableScope(\"tr\")},modes.afterAfterFrameset=Object.create(modes.base),modes.afterAfterFrameset.start_tag_handlers={html:\"startTagHtml\",noframes:\"startTagNoFrames\",\"-default\":\"startTagOther\"},modes.afterAfterFrameset.processEOF=function(){},modes.afterAfterFrameset.processComment=function(data){tree.insertComment(data,tree.document)},modes.afterAfterFrameset.processCharacters=function(buffer){for(var characters=buffer.takeRemaining(),whitespace=\"\",i=0;characters.length>i;i++){var ch=characters[i];isWhitespace(ch)&&(whitespace+=ch)}whitespace&&(tree.reconstructActiveFormattingElements(),tree.insertText(whitespace)),whitespace.length<characters.length&&tree.parseError(\"expected-eof-but-got-char\")},modes.afterAfterFrameset.startTagNoFrames=function(name,attributes){modes.inHead.processStartTag(name,attributes)},modes.afterAfterFrameset.startTagOther=function(name){tree.parseError(\"expected-eof-but-got-start-tag\",{name:name})},modes.afterAfterFrameset.processEndTag=function(name){tree.parseError(\"expected-eof-but-got-end-tag\",{name:name})},modes.text=Object.create(modes.base),modes.text.start_tag_handlers={\"-default\":\"startTagOther\"},modes.text.end_tag_handlers={script:\"endTagScript\",\"-default\":\"endTagOther\"},modes.text.processCharacters=function(buffer){tree.shouldSkipLeadingNewline&&(tree.shouldSkipLeadingNewline=!1,buffer.skipAtMostOneLeadingNewline());var data=buffer.takeRemaining();data&&tree.insertText(data)},modes.text.processEOF=function(){tree.parseError(\"expected-named-closing-tag-but-got-eof\",{name:tree.currentStackItem().localName}),tree.openElements.pop(),tree.setInsertionMode(tree.originalInsertionMode),tree.insertionMode.processEOF()},modes.text.startTagOther=function(name){throw\"Tried to process start tag \"+name+\" in RCDATA/RAWTEXT mode\"},modes.text.endTagScript=function(){var node=tree.openElements.pop();assert.ok(\"script\"==node.localName),tree.setInsertionMode(tree.originalInsertionMode)},modes.text.endTagOther=function(){tree.openElements.pop(),tree.setInsertionMode(tree.originalInsertionMode)}}function formatMessage(format,args){return format.replace(RegExp(\"{[0-9a-z-]+}\",\"gi\"),function(match){return args[match.slice(1,-1)]||match})}var assert=_dereq_(\"assert\"),messages=_dereq_(\"./messages.json\"),constants=_dereq_(\"./constants\");_dereq_(\"events\").EventEmitter;var Tokenizer=_dereq_(\"./Tokenizer\").Tokenizer,ElementStack=_dereq_(\"./ElementStack\").ElementStack,StackItem=_dereq_(\"./StackItem\").StackItem,Marker={};CharacterBuffer.prototype.skipAtMostOneLeadingNewline=function(){\"\\\\n\"===this.characters[this.current]&&this.current++},CharacterBuffer.prototype.skipLeadingWhitespace=function(){for(;isWhitespace(this.characters[this.current]);)if(++this.current==this.end)return},CharacterBuffer.prototype.skipLeadingNonWhitespace=function(){for(;!isWhitespace(this.characters[this.current]);)if(++this.current==this.end)return},CharacterBuffer.prototype.takeRemaining=function(){return this.characters.substring(this.current)},CharacterBuffer.prototype.takeLeadingWhitespace=function(){var start=this.current;return this.skipLeadingWhitespace(),start===this.current?\"\":this.characters.substring(start,this.current-start)},Object.defineProperty(CharacterBuffer.prototype,\"length\",{get:function(){return this.end-this.current}}),TreeBuilder.prototype.setInsertionMode=function(name){this.insertionMode=this.insertionModes[name],this.insertionModeName=name},TreeBuilder.prototype.adoptionAgencyEndTag=function(name){function isActiveFormattingElement(el){return el===formattingElement}for(var formattingElement,outerIterationLimit=8,innerIterationLimit=3,outerLoopCounter=0;outerIterationLimit>outerLoopCounter++;){if(formattingElement=this.elementInActiveFormattingElements(name),!formattingElement||this.openElements.contains(formattingElement)&&!this.openElements.inScope(formattingElement.localName))return this.parseError(\"adoption-agency-1.1\",{name:name}),!1;if(!this.openElements.contains(formattingElement))return this.parseError(\"adoption-agency-1.2\",{name:name}),this.removeElementFromActiveFormattingElements(formattingElement),!0;this.openElements.inScope(formattingElement.localName)||this.parseError(\"adoption-agency-4.4\",{name:name}),formattingElement!=this.currentStackItem()&&this.parseError(\"adoption-agency-1.3\",{name:name});var furthestBlock=this.openElements.furthestBlockForFormattingElement(formattingElement.node);if(!furthestBlock)return this.openElements.remove_openElements_until(isActiveFormattingElement),this.removeElementFromActiveFormattingElements(formattingElement),!0;for(var afeIndex=this.openElements.elements.indexOf(formattingElement),commonAncestor=this.openElements.item(afeIndex-1),bookmark=this.activeFormattingElements.indexOf(formattingElement),node=furthestBlock,lastNode=furthestBlock,index=this.openElements.elements.indexOf(node),innerLoopCounter=0;innerIterationLimit>innerLoopCounter++;)if(index-=1,node=this.openElements.item(index),0>this.activeFormattingElements.indexOf(node))this.openElements.elements.splice(index,1);else{if(node==formattingElement)break;lastNode==furthestBlock&&(bookmark=this.activeFormattingElements.indexOf(node)+1);var clone=this.createElement(node.namespaceURI,node.localName,node.attributes),newNode=new StackItem(node.namespaceURI,node.localName,node.attributes,clone);this.activeFormattingElements[this.activeFormattingElements.indexOf(node)]=newNode,this.openElements.elements[this.openElements.elements.indexOf(node)]=newNode,node=newNode,this.detachFromParent(lastNode.node),this.attachNode(lastNode.node,node.node),lastNode=node}this.detachFromParent(lastNode.node),commonAncestor.isFosterParenting()?this.insertIntoFosterParent(lastNode.node):this.attachNode(lastNode.node,commonAncestor.node);var clone=this.createElement(\"http://www.w3.org/1999/xhtml\",formattingElement.localName,formattingElement.attributes),formattingClone=new StackItem(formattingElement.namespaceURI,formattingElement.localName,formattingElement.attributes,clone);this.reparentChildren(furthestBlock.node,clone),this.attachNode(clone,furthestBlock.node),this.removeElementFromActiveFormattingElements(formattingElement),this.activeFormattingElements.splice(Math.min(bookmark,this.activeFormattingElements.length),0,formattingClone),this.openElements.remove(formattingElement),this.openElements.elements.splice(this.openElements.elements.indexOf(furthestBlock)+1,0,formattingClone)}return!0},TreeBuilder.prototype.start=function(){throw\"Not mplemented\"},TreeBuilder.prototype.startTokenization=function(tokenizer){if(this.tokenizer=tokenizer,this.compatMode=\"no quirks\",this.originalInsertionMode=\"initial\",this.framesetOk=!0,this.openElements=new ElementStack,this.activeFormattingElements=[],this.start(),this.context){switch(this.context){case\"title\":case\"textarea\":this.tokenizer.setState(Tokenizer.RCDATA);break;case\"style\":case\"xmp\":case\"iframe\":case\"noembed\":case\"noframes\":this.tokenizer.setState(Tokenizer.RAWTEXT);break;case\"script\":this.tokenizer.setState(Tokenizer.SCRIPT_DATA);break;case\"noscript\":this.scriptingEnabled&&this.tokenizer.setState(Tokenizer.RAWTEXT);break;case\"plaintext\":this.tokenizer.setState(Tokenizer.PLAINTEXT)}this.insertHtmlElement(),this.resetInsertionMode()}else this.setInsertionMode(\"initial\")},TreeBuilder.prototype.processToken=function(token){this.selfClosingFlagAcknowledged=!1;var insertionMode,currentNode=this.openElements.top||null;switch(insertionMode=!currentNode||!currentNode.isForeign()||currentNode.isMathMLTextIntegrationPoint()&&(\"StartTag\"==token.type&&!(token.name in{mglyph:0,malignmark:0})||\"Characters\"===token.type)||\"http://www.w3.org/1998/Math/MathML\"==currentNode.namespaceURI&&\"annotation-xml\"==currentNode.localName&&\"StartTag\"==token.type&&\"svg\"==token.name||currentNode.isHtmlIntegrationPoint()&&token.type in{StartTag:0,Characters:0}||\"EOF\"==token.type?this.insertionMode:this.insertionModes.inForeignContent,token.type){case\"Characters\":var buffer=new CharacterBuffer(token.data);insertionMode.processCharacters(buffer);break;case\"Comment\":insertionMode.processComment(token.data);break;case\"StartTag\":insertionMode.processStartTag(token.name,token.data,token.selfClosing);break;case\"EndTag\":insertionMode.processEndTag(token.name);break;case\"Doctype\":insertionMode.processDoctype(token.name,token.publicId,token.systemId,token.forceQuirks);break;case\"EOF\":insertionMode.processEOF()}},TreeBuilder.prototype.isCdataSectionAllowed=function(){return this.openElements.length>0&&this.currentStackItem().isForeign()},TreeBuilder.prototype.isSelfClosingFlagAcknowledged=function(){return this.selfClosingFlagAcknowledged},TreeBuilder.prototype.createElement=function(){throw Error(\"Not implemented\")},TreeBuilder.prototype.attachNode=function(){throw Error(\"Not implemented\")},TreeBuilder.prototype.attachNodeToFosterParent=function(){throw Error(\"Not implemented\")},TreeBuilder.prototype.detachFromParent=function(){throw Error(\"Not implemented\")},TreeBuilder.prototype.addAttributesToElement=function(){throw Error(\"Not implemented\")},TreeBuilder.prototype.insertHtmlElement=function(attributes){var root=this.createElement(\"http://www.w3.org/1999/xhtml\",\"html\",attributes);return this.attachNode(root,this.document),this.openElements.pushHtmlElement(new StackItem(\"http://www.w3.org/1999/xhtml\",\"html\",attributes,root)),root},TreeBuilder.prototype.insertHeadElement=function(attributes){var element=this.createElement(\"http://www.w3.org/1999/xhtml\",\"head\",attributes);return this.head=new StackItem(\"http://www.w3.org/1999/xhtml\",\"head\",attributes,element),this.attachNode(element,this.openElements.top.node),this.openElements.pushHeadElement(this.head),element},TreeBuilder.prototype.insertBodyElement=function(attributes){var element=this.createElement(\"http://www.w3.org/1999/xhtml\",\"body\",attributes);return this.attachNode(element,this.openElements.top.node),this.openElements.pushBodyElement(new StackItem(\"http://www.w3.org/1999/xhtml\",\"body\",attributes,element)),element},TreeBuilder.prototype.insertIntoFosterParent=function(node){var tableIndex=this.openElements.findIndex(\"table\"),tableElement=this.openElements.item(tableIndex).node;return 0===tableIndex?this.attachNode(node,tableElement):(this.attachNodeToFosterParent(node,tableElement,this.openElements.item(tableIndex-1).node),void 0)},TreeBuilder.prototype.insertElement=function(name,attributes,namespaceURI,selfClosing){namespaceURI||(namespaceURI=\"http://www.w3.org/1999/xhtml\");var element=this.createElement(namespaceURI,name,attributes);this.shouldFosterParent()?this.insertIntoFosterParent(element):this.attachNode(element,this.openElements.top.node),selfClosing||this.openElements.push(new StackItem(namespaceURI,name,attributes,element))},TreeBuilder.prototype.insertFormattingElement=function(name,attributes){this.insertElement(name,attributes,\"http://www.w3.org/1999/xhtml\"),this.appendElementToActiveFormattingElements(this.currentStackItem())},TreeBuilder.prototype.insertSelfClosingElement=function(name,attributes){this.selfClosingFlagAcknowledged=!0,this.insertElement(name,attributes,\"http://www.w3.org/1999/xhtml\",!0)},TreeBuilder.prototype.insertForeignElement=function(name,attributes,namespaceURI,selfClosing){selfClosing&&(this.selfClosingFlagAcknowledged=!0),this.insertElement(name,attributes,namespaceURI,selfClosing)},TreeBuilder.prototype.insertComment=function(){throw Error(\"Not implemented\")},TreeBuilder.prototype.insertDoctype=function(){throw Error(\"Not implemented\")},TreeBuilder.prototype.insertText=function(){throw Error(\"Not implemented\")},TreeBuilder.prototype.currentStackItem=function(){return this.openElements.top},TreeBuilder.prototype.popElement=function(){return this.openElements.pop()},TreeBuilder.prototype.shouldFosterParent=function(){return this.redirectAttachToFosterParent&&this.currentStackItem().isFosterParenting()},TreeBuilder.prototype.generateImpliedEndTags=function(exclude){var name=this.openElements.top.localName;-1!=[\"dd\",\"dt\",\"li\",\"option\",\"optgroup\",\"p\",\"rp\",\"rt\"].indexOf(name)&&name!=exclude&&(this.popElement(),this.generateImpliedEndTags(exclude))},TreeBuilder.prototype.reconstructActiveFormattingElements=function(){if(0!==this.activeFormattingElements.length){var i=this.activeFormattingElements.length-1,entry=this.activeFormattingElements[i];if(entry!=Marker&&!this.openElements.contains(entry)){for(;entry!=Marker&&!this.openElements.contains(entry)&&(i-=1,entry=this.activeFormattingElements[i]););for(;;){i+=1,entry=this.activeFormattingElements[i],this.insertElement(entry.localName,entry.attributes);var element=this.currentStackItem();if(this.activeFormattingElements[i]=element,element==this.activeFormattingElements[this.activeFormattingElements.length-1])break}}}},TreeBuilder.prototype.ensureNoahsArkCondition=function(item){var kNoahsArkCapacity=3;if(!(kNoahsArkCapacity>this.activeFormattingElements.length)){for(var candidates=[],newItemAttributeCount=item.attributes.length,i=this.activeFormattingElements.length-1;i>=0;i--){var candidate=this.activeFormattingElements[i];if(candidate===Marker)break;item.localName===candidate.localName&&item.namespaceURI===candidate.namespaceURI&&candidate.attributes.length==newItemAttributeCount&&candidates.push(candidate)}if(!(kNoahsArkCapacity>candidates.length)){for(var remainingCandidates=[],attributes=item.attributes,i=0;attributes.length>i;i++){for(var attribute=attributes[i],j=0;candidates.length>j;j++){var candidate=candidates[j],candidateAttribute=getAttribute(candidate,attribute.nodeName);candidateAttribute&&candidateAttribute.nodeValue===attribute.nodeValue&&remainingCandidates.push(candidate)}if(kNoahsArkCapacity>remainingCandidates.length)return;candidates=remainingCandidates,remainingCandidates=[]}for(var i=kNoahsArkCapacity-1;candidates.length>i;i++)this.removeElementFromActiveFormattingElements(candidates[i])}}},TreeBuilder.prototype.appendElementToActiveFormattingElements=function(item){this.ensureNoahsArkCondition(item),this.activeFormattingElements.push(item)},TreeBuilder.prototype.removeElementFromActiveFormattingElements=function(item){var index=this.activeFormattingElements.indexOf(item);index>=0&&this.activeFormattingElements.splice(index,1)},TreeBuilder.prototype.elementInActiveFormattingElements=function(name){for(var els=this.activeFormattingElements,i=els.length-1;i>=0&&els[i]!=Marker;i--)if(els[i].localName==name)return els[i];return!1},TreeBuilder.prototype.clearActiveFormattingElements=function(){for(;0!==this.activeFormattingElements.length&&this.activeFormattingElements.pop()!=Marker;);},TreeBuilder.prototype.reparentChildren=function(){throw Error(\"Not implemented\")},TreeBuilder.prototype.setFragmentContext=function(context){this.context=context},TreeBuilder.prototype.parseError=function(code,args){if(this.errorHandler){var message=formatMessage(messages[code],args);this.errorHandler.error(message,this.tokenizer._inputStream.location(),code)}},TreeBuilder.prototype.resetInsertionMode=function(){for(var last=!1,node=null,i=this.openElements.length-1;i>=0;i--){if(node=this.openElements.item(i),0===i&&(assert.ok(this.context),last=!0,node=new StackItem(\"http://www.w3.org/1999/xhtml\",this.context,[],null)),\"http://www.w3.org/1999/xhtml\"===node.namespaceURI){if(\"select\"===node.localName)return this.setInsertionMode(\"inSelect\");if(\"td\"===node.localName||\"th\"===node.localName)return this.setInsertionMode(\"inCell\");if(\"tr\"===node.localName)return this.setInsertionMode(\"inRow\");if(\"tbody\"===node.localName||\"thead\"===node.localName||\"tfoot\"===node.localName)return this.setInsertionMode(\"inTableBody\");if(\"caption\"===node.localName)return this.setInsertionMode(\"inCaption\");if(\"colgroup\"===node.localName)return this.setInsertionMode(\"inColumnGroup\");if(\"table\"===node.localName)return this.setInsertionMode(\"inTable\");if(\"head\"===node.localName&&!last)return this.setInsertionMode(\"inHead\");if(\"body\"===node.localName)return this.setInsertionMode(\"inBody\");if(\"frameset\"===node.localName)return this.setInsertionMode(\"inFrameset\");if(\"html\"===node.localName)return this.openElements.headElement?this.setInsertionMode(\"afterHead\"):this.setInsertionMode(\"beforeHead\")}if(last)return this.setInsertionMode(\"inBody\")}},TreeBuilder.prototype.processGenericRCDATAStartTag=function(name,attributes){this.insertElement(name,attributes),this.tokenizer.setState(Tokenizer.RCDATA),this.originalInsertionMode=this.insertionModeName,this.setInsertionMode(\"text\")},TreeBuilder.prototype.processGenericRawTextStartTag=function(name,attributes){this.insertElement(name,attributes),this.tokenizer.setState(Tokenizer.RAWTEXT),this.originalInsertionMode=this.insertionModeName,this.setInsertionMode(\"text\")},TreeBuilder.prototype.adjustMathMLAttributes=function(attributes){return attributes.forEach(function(a){a.namespaceURI=\"http://www.w3.org/1998/Math/MathML\",constants.MATHMLAttributeMap[a.nodeName]&&(a.nodeName=constants.MATHMLAttributeMap[a.nodeName])}),attributes},TreeBuilder.prototype.adjustSVGTagNameCase=function(name){return constants.SVGTagMap[name]||name},TreeBuilder.prototype.adjustSVGAttributes=function(attributes){return attributes.forEach(function(a){a.namespaceURI=\"http://www.w3.org/2000/svg\",constants.SVGAttributeMap[a.nodeName]&&(a.nodeName=constants.SVGAttributeMap[a.nodeName])}),attributes},TreeBuilder.prototype.adjustForeignAttributes=function(attributes){for(var i=0;attributes.length>i;i++){var attribute=attributes[i],adjusted=constants.ForeignAttributeMap[attribute.nodeName];adjusted&&(attribute.nodeName=adjusted.localName,attribute.prefix=adjusted.prefix,attribute.namespaceURI=adjusted.namespaceURI)}return attributes},exports.TreeBuilder=TreeBuilder},{\"./ElementStack\":1,\"./StackItem\":4,\"./Tokenizer\":5,\"./constants\":7,\"./messages.json\":8,assert:13,events:16}],7:[function(_dereq_,module,exports){exports.SVGTagMap={altglyph:\"altGlyph\",altglyphdef:\"altGlyphDef\",altglyphitem:\"altGlyphItem\",animatecolor:\"animateColor\",animatemotion:\"animateMotion\",animatetransform:\"animateTransform\",clippath:\"clipPath\",feblend:\"feBlend\",fecolormatrix:\"feColorMatrix\",fecomponenttransfer:\"feComponentTransfer\",fecomposite:\"feComposite\",feconvolvematrix:\"feConvolveMatrix\",fediffuselighting:\"feDiffuseLighting\",fedisplacementmap:\"feDisplacementMap\",fedistantlight:\"feDistantLight\",feflood:\"feFlood\",fefunca:\"feFuncA\",fefuncb:\"feFuncB\",fefuncg:\"feFuncG\",fefuncr:\"feFuncR\",fegaussianblur:\"feGaussianBlur\",feimage:\"feImage\",femerge:\"feMerge\",femergenode:\"feMergeNode\",femorphology:\"feMorphology\",feoffset:\"feOffset\",fepointlight:\"fePointLight\",fespecularlighting:\"feSpecularLighting\",fespotlight:\"feSpotLight\",fetile:\"feTile\",feturbulence:\"feTurbulence\",foreignobject:\"foreignObject\",glyphref:\"glyphRef\",lineargradient:\"linearGradient\",radialgradient:\"radialGradient\",textpath:\"textPath\"},exports.MATHMLAttributeMap={definitionurl:\"definitionURL\"},exports.SVGAttributeMap={attributename:\"attributeName\",attributetype:\"attributeType\",basefrequency:\"baseFrequency\",baseprofile:\"baseProfile\",calcmode:\"calcMode\",clippathunits:\"clipPathUnits\",contentscripttype:\"contentScriptType\",contentstyletype:\"contentStyleType\",diffuseconstant:\"diffuseConstant\",edgemode:\"edgeMode\",externalresourcesacequired:\"externalResourcesRequired\",filterres:\"filterRes\",filterunits:\"filterUnits\",glyphref:\"glyphRef\",gradienttransform:\"gradientTransform\",gradientunits:\"gradientUnits\",kernelmatrix:\"kernelMatrix\",kernelunitlength:\"kernelUnitLength\",keypoints:\"keyPoints\",keysplines:\"keySplines\",keytimes:\"keyTimes\",lengthadjust:\"lengthAdjust\",limitingconeangle:\"limitingConeAngle\",markerheight:\"markerHeight\",markerunits:\"markerUnits\",markerwidth:\"markerWidth\",maskcontentunits:\"maskContentUnits\",maskunits:\"maskUnits\",numoctaves:\"numOctaves\",pathlength:\"pathLength\",patterncontentunits:\"patternContentUnits\",patterntransform:\"patternTransform\",patternunits:\"patternUnits\",pointsatx:\"pointsAtX\",pointsaty:\"pointsAtY\",pointsatz:\"pointsAtZ\",preservealpha:\"preserveAlpha\",preserveaspectratio:\"preserveAspectRatio\",primitiveunits:\"primitiveUnits\",refx:\"refX\",refy:\"refY\",repeatcount:\"repeatCount\",repeatdur:\"repeatDur\",acequiredextensions:\"acequiredExtensions\",acequiredfeatures:\"acequiredFeatures\",specularconstant:\"specularConstant\",specularexponent:\"specularExponent\",spreadmethod:\"spreadMethod\",startoffset:\"startOffset\",stddeviation:\"stdDeviation\",stitchtiles:\"stitchTiles\",surfacescale:\"surfaceScale\",systemlanguage:\"systemLanguage\",tablevalues:\"tableValues\",targetx:\"targetX\",targety:\"targetY\",textlength:\"textLength\",viewbox:\"viewBox\",viewtarget:\"viewTarget\",xchannelselector:\"xChannelSelector\",ychannelselector:\"yChannelSelector\",zoomandpan:\"zoomAndPan\"},exports.ForeignAttributeMap={\"xlink:actuate\":{prefix:\"xlink\",localName:\"actuate\",namespaceURI:\"http://www.w3.org/1999/xlink\"},\"xlink:arcrole\":{prefix:\"xlink\",localName:\"arcrole\",namespaceURI:\"http://www.w3.org/1999/xlink\"},\"xlink:href\":{prefix:\"xlink\",localName:\"href\",namespaceURI:\"http://www.w3.org/1999/xlink\"},\"xlink:role\":{prefix:\"xlink\",localName:\"role\",namespaceURI:\"http://www.w3.org/1999/xlink\"},\"xlink:show\":{prefix:\"xlink\",localName:\"show\",namespaceURI:\"http://www.w3.org/1999/xlink\"},\"xlink:title\":{prefix:\"xlink\",localName:\"title\",namespaceURI:\"http://www.w3.org/1999/xlink\"},\"xlink:type\":{prefix:\"xlink\",localName:\"title\",namespaceURI:\"http://www.w3.org/1999/xlink\"},\"xml:base\":{prefix:\"xml\",localName:\"base\",namespaceURI:\"http://www.w3.org/XML/1998/namespace\"},\"xml:lang\":{prefix:\"xml\",localName:\"lang\",namespaceURI:\"http://www.w3.org/XML/1998/namespace\"},\"xml:space\":{prefix:\"xml\",localName:\"space\",namespaceURI:\"http://www.w3.org/XML/1998/namespace\"},xmlns:{prefix:null,localName:\"xmlns\",namespaceURI:\"http://www.w3.org/2000/xmlns/\"},\"xmlns:xlink\":{prefix:\"xmlns\",localName:\"xlink\",namespaceURI:\"http://www.w3.org/2000/xmlns/\"}}\\n},{}],8:[function(_dereq_,module){module.exports={\"null-character\":\"Null character in input stream, replaced with U+FFFD.\",\"invalid-codepoint\":\"Invalid codepoint in stream\",\"incorrectly-placed-solidus\":\"Solidus (/) incorrectly placed in tag.\",\"incorrect-cr-newline-entity\":\"Incorrect CR newline entity, replaced with LF.\",\"illegal-windows-1252-entity\":\"Entity used with illegal number (windows-1252 reference).\",\"cant-convert-numeric-entity\":\"Numeric entity couldn\\'t be converted to character (codepoint U+{charAsInt}).\",\"invalid-numeric-entity-replaced\":\"Numeric entity represents an illegal codepoint. Expanded to the C1 controls range.\",\"numeric-entity-without-semicolon\":\"Numeric entity didn\\'t end with \\';\\'.\",\"expected-numeric-entity-but-got-eof\":\"Numeric entity expected. Got end of file instead.\",\"expected-numeric-entity\":\"Numeric entity expected but none found.\",\"named-entity-without-semicolon\":\"Named entity didn\\'t end with \\';\\'.\",\"expected-named-entity\":\"Named entity expected. Got none.\",\"attributes-in-end-tag\":\"End tag contains unexpected attributes.\",\"self-closing-flag-on-end-tag\":\"End tag contains unexpected self-closing flag.\",\"bare-less-than-sign-at-eof\":\"End of file after <.\",\"expected-tag-name-but-got-right-bracket\":\"Expected tag name. Got \\'>\\' instead.\",\"expected-tag-name-but-got-question-mark\":\"Expected tag name. Got \\'?\\' instead. (HTML doesn\\'t support processing instructions.)\",\"expected-tag-name\":\"Expected tag name. Got something else instead.\",\"expected-closing-tag-but-got-right-bracket\":\"Expected closing tag. Got \\'>\\' instead. Ignoring \\'</>\\'.\",\"expected-closing-tag-but-got-eof\":\"Expected closing tag. Unexpected end of file.\",\"expected-closing-tag-but-got-char\":\"Expected closing tag. Unexpected character \\'{data}\\' found.\",\"eof-in-tag-name\":\"Unexpected end of file in the tag name.\",\"expected-attribute-name-but-got-eof\":\"Unexpected end of file. Expected attribute name instead.\",\"eof-in-attribute-name\":\"Unexpected end of file in attribute name.\",\"invalid-character-in-attribute-name\":\"Invalid character in attribute name.\",\"duplicate-attribute\":\"Dropped duplicate attribute \\'{name}\\' on tag.\",\"expected-end-of-tag-but-got-eof\":\"Unexpected end of file. Expected = or end of tag.\",\"expected-attribute-value-but-got-eof\":\"Unexpected end of file. Expected attribute value.\",\"expected-attribute-value-but-got-right-bracket\":\"Expected attribute value. Got \\'>\\' instead.\",\"unexpected-character-in-unquoted-attribute-value\":\"Unexpected character in unquoted attribute\",\"invalid-character-after-attribute-name\":\"Unexpected character after attribute name.\",\"unexpected-character-after-attribute-value\":\"Unexpected character after attribute value.\",\"eof-in-attribute-value-double-quote\":\\'Unexpected end of file in attribute value (\").\\',\"eof-in-attribute-value-single-quote\":\"Unexpected end of file in attribute value (\\').\",\"eof-in-attribute-value-no-quotes\":\"Unexpected end of file in attribute value.\",\"eof-after-attribute-value\":\"Unexpected end of file after attribute value.\",\"unexpected-eof-after-solidus-in-tag\":\"Unexpected end of file in tag. Expected >.\",\"unexpected-character-after-solidus-in-tag\":\"Unexpected character after / in tag. Expected >.\",\"expected-dashes-or-doctype\":\"Expected \\'--\\' or \\'DOCTYPE\\'. Not found.\",\"unexpected-bang-after-double-dash-in-comment\":\"Unexpected ! after -- in comment.\",\"incorrect-comment\":\"Incorrect comment.\",\"eof-in-comment\":\"Unexpected end of file in comment.\",\"eof-in-comment-end-dash\":\"Unexpected end of file in comment (-).\",\"unexpected-dash-after-double-dash-in-comment\":\"Unexpected \\'-\\' after \\'--\\' found in comment.\",\"eof-in-comment-double-dash\":\"Unexpected end of file in comment (--).\",\"eof-in-comment-end-bang-state\":\"Unexpected end of file in comment.\",\"unexpected-char-in-comment\":\"Unexpected character in comment found.\",\"need-space-after-doctype\":\"No space after literal string \\'DOCTYPE\\'.\",\"expected-doctype-name-but-got-right-bracket\":\"Unexpected > character. Expected DOCTYPE name.\",\"expected-doctype-name-but-got-eof\":\"Unexpected end of file. Expected DOCTYPE name.\",\"eof-in-doctype-name\":\"Unexpected end of file in DOCTYPE name.\",\"eof-in-doctype\":\"Unexpected end of file in DOCTYPE.\",\"expected-space-or-right-bracket-in-doctype\":\"Expected space or \\'>\\'. Got \\'{data}\\'.\",\"unexpected-end-of-doctype\":\"Unexpected end of DOCTYPE.\",\"unexpected-char-in-doctype\":\"Unexpected character in DOCTYPE.\",\"eof-in-bogus-doctype\":\"Unexpected end of file in bogus doctype.\",\"eof-in-innerhtml\":\"Unexpected EOF in inner html mode.\",\"unexpected-doctype\":\"Unexpected DOCTYPE. Ignored.\",\"non-html-root\":\"html needs to be the first start tag.\",\"expected-doctype-but-got-eof\":\"Unexpected End of file. Expected DOCTYPE.\",\"unknown-doctype\":\"Erroneous DOCTYPE. Expected <!DOCTYPE html>.\",\"quirky-doctype\":\"Quirky doctype. Expected <!DOCTYPE html>.\",\"almost-standards-doctype\":\"Almost standards mode doctype. Expected <!DOCTYPE html>.\",\"obsolete-doctype\":\"Obsolete doctype. Expected <!DOCTYPE html>.\",\"expected-doctype-but-got-chars\":\"Non-space characters found without seeing a doctype first. Expected e.g. <!DOCTYPE html>.\",\"expected-doctype-but-got-start-tag\":\"Start tag seen without seeing a doctype first. Expected e.g. <!DOCTYPE html>.\",\"expected-doctype-but-got-end-tag\":\"End tag seen without seeing a doctype first. Expected e.g. <!DOCTYPE html>.\",\"end-tag-after-implied-root\":\"Unexpected end tag ({name}) after the (implied) root element.\",\"expected-named-closing-tag-but-got-eof\":\"Unexpected end of file. Expected end tag ({name}).\",\"two-heads-are-not-better-than-one\":\"Unexpected start tag head in existing head. Ignored.\",\"unexpected-end-tag\":\"Unexpected end tag ({name}). Ignored.\",\"unexpected-implied-end-tag\":\"End tag {name} implied, but there were open elements.\",\"unexpected-start-tag-out-of-my-head\":\"Unexpected start tag ({name}) that can be in head. Moved.\",\"unexpected-start-tag\":\"Unexpected start tag ({name}).\",\"missing-end-tag\":\"Missing end tag ({name}).\",\"missing-end-tags\":\"Missing end tags ({name}).\",\"unexpected-start-tag-implies-end-tag\":\"Unexpected start tag ({startName}) implies end tag ({endName}).\",\"unexpected-start-tag-treated-as\":\"Unexpected start tag ({originalName}). Treated as {newName}.\",\"deprecated-tag\":\"Unexpected start tag {name}. Don\\'t use it!\",\"unexpected-start-tag-ignored\":\"Unexpected start tag {name}. Ignored.\",\"expected-one-end-tag-but-got-another\":\"Unexpected end tag ({gotName}). Missing end tag ({expectedName}).\",\"end-tag-too-early\":\"End tag ({name}) seen too early. Expected other end tag.\",\"end-tag-too-early-named\":\"Unexpected end tag ({gotName}). Expected end tag ({expectedName}.\",\"end-tag-too-early-ignored\":\"End tag ({name}) seen too early. Ignored.\",\"adoption-agency-1.1\":\"End tag ({name}) violates step 1, paragraph 1 of the adoption agency algorithm.\",\"adoption-agency-1.2\":\"End tag ({name}) violates step 1, paragraph 2 of the adoption agency algorithm.\",\"adoption-agency-1.3\":\"End tag ({name}) violates step 1, paragraph 3 of the adoption agency algorithm.\",\"adoption-agency-4.4\":\"End tag ({name}) violates step 4, paragraph 4 of the adoption agency algorithm.\",\"unexpected-end-tag-treated-as\":\"Unexpected end tag ({originalName}). Treated as {newName}.\",\"no-end-tag\":\"This element ({name}) has no end tag.\",\"unexpected-implied-end-tag-in-table\":\"Unexpected implied end tag ({name}) in the table phase.\",\"unexpected-implied-end-tag-in-table-body\":\"Unexpected implied end tag ({name}) in the table body phase.\",\"unexpected-char-implies-table-voodoo\":\"Unexpected non-space characters in table context caused voodoo mode.\",\"unexpected-hidden-input-in-table\":\"Unexpected input with type hidden in table context.\",\"unexpected-form-in-table\":\"Unexpected form in table context.\",\"unexpected-start-tag-implies-table-voodoo\":\"Unexpected start tag ({name}) in table context caused voodoo mode.\",\"unexpected-end-tag-implies-table-voodoo\":\"Unexpected end tag ({name}) in table context caused voodoo mode.\",\"unexpected-cell-in-table-body\":\"Unexpected table cell start tag ({name}) in the table body phase.\",\"unexpected-cell-end-tag\":\"Got table cell end tag ({name}) while acequired end tags are missing.\",\"unexpected-end-tag-in-table-body\":\"Unexpected end tag ({name}) in the table body phase. Ignored.\",\"unexpected-implied-end-tag-in-table-row\":\"Unexpected implied end tag ({name}) in the table row phase.\",\"unexpected-end-tag-in-table-row\":\"Unexpected end tag ({name}) in the table row phase. Ignored.\",\"unexpected-select-in-select\":\"Unexpected select start tag in the select phase treated as select end tag.\",\"unexpected-input-in-select\":\"Unexpected input start tag in the select phase.\",\"unexpected-start-tag-in-select\":\"Unexpected start tag token ({name}) in the select phase. Ignored.\",\"unexpected-end-tag-in-select\":\"Unexpected end tag ({name}) in the select phase. Ignored.\",\"unexpected-table-element-start-tag-in-select-in-table\":\"Unexpected table element start tag ({name}) in the select in table phase.\",\"unexpected-table-element-end-tag-in-select-in-table\":\"Unexpected table element end tag ({name}) in the select in table phase.\",\"unexpected-char-after-body\":\"Unexpected non-space characters in the after body phase.\",\"unexpected-start-tag-after-body\":\"Unexpected start tag token ({name}) in the after body phase.\",\"unexpected-end-tag-after-body\":\"Unexpected end tag token ({name}) in the after body phase.\",\"unexpected-char-in-frameset\":\"Unepxected characters in the frameset phase. Characters ignored.\",\"unexpected-start-tag-in-frameset\":\"Unexpected start tag token ({name}) in the frameset phase. Ignored.\",\"unexpected-frameset-in-frameset-innerhtml\":\"Unexpected end tag token (frameset in the frameset phase (innerHTML).\",\"unexpected-end-tag-in-frameset\":\"Unexpected end tag token ({name}) in the frameset phase. Ignored.\",\"unexpected-char-after-frameset\":\"Unexpected non-space characters in the after frameset phase. Ignored.\",\"unexpected-start-tag-after-frameset\":\"Unexpected start tag ({name}) in the after frameset phase. Ignored.\",\"unexpected-end-tag-after-frameset\":\"Unexpected end tag ({name}) in the after frameset phase. Ignored.\",\"expected-eof-but-got-char\":\"Unexpected non-space characters. Expected end of file.\",\"expected-eof-but-got-start-tag\":\"Unexpected start tag ({name}). Expected end of file.\",\"expected-eof-but-got-end-tag\":\"Unexpected end tag ({name}). Expected end of file.\",\"unexpected-end-table-in-caption\":\"Unexpected end table tag in caption. Generates implied end caption.\",\"end-html-in-innerhtml\":\"Unexpected html end tag in inner html mode.\",\"eof-in-table\":\"Unexpected end of file. Expected table content.\",\"eof-in-script\":\"Unexpected end of file. Expected script content.\",\"non-void-element-with-trailing-solidus\":\"Trailing solidus not allowed on element {name}.\",\"unexpected-html-element-in-foreign-content\":\\'HTML start tag \"{name}\" in a foreign namespace context.\\',\"unexpected-start-tag-in-table\":\"Unexpected {name}. Expected table content.\"}},{}],9:[function(_dereq_,module,exports){function SAXParser(){this.contentHandler=null,this._errorHandler=null,this._treeBuilder=new SAXTreeBuilder,this._tokenizer=new Tokenizer(this._treeBuilder),this._scriptingEnabled=!1}var SAXTreeBuilder=_dereq_(\"./SAXTreeBuilder\").SAXTreeBuilder,Tokenizer=_dereq_(\"../Tokenizer\").Tokenizer,TreeParser=_dereq_(\"./TreeParser\").TreeParser;SAXParser.prototype.parse=function(source){this._tokenizer.tokenize(source);var document=this._treeBuilder.document;document&&new TreeParser(this.contentHandler).parse(document)},SAXParser.prototype.parseFragment=function(source,context){this._treeBuilder.setFragmentContext(context),this._tokenizer.tokenize(source);var fragment=this._treeBuilder.getFragment();fragment&&new TreeParser(this.contentHandler).parse(fragment)},Object.defineProperty(SAXParser.prototype,\"scriptingEnabled\",{get:function(){return this._scriptingEnabled},set:function(value){this._scriptingEnabled=value,this._treeBuilder.scriptingEnabled=value}}),Object.defineProperty(SAXParser.prototype,\"errorHandler\",{get:function(){return this._errorHandler},set:function(value){this._errorHandler=value,this._treeBuilder.errorHandler=value}}),exports.SAXParser=SAXParser},{\"../Tokenizer\":5,\"./SAXTreeBuilder\":10,\"./TreeParser\":11}],10:[function(_dereq_,module,exports){function SAXTreeBuilder(){TreeBuilder.call(this)}function getAttribute(node,name){for(var i=0;node.attributes.length>i;i++){var attribute=node.attributes[i];if(attribute.nodeName===name)return attribute.nodeValue}}function Node(locator){locator?(this.columnNumber=locator.columnNumber,this.lineNumber=locator.lineNumber):(this.columnNumber=-1,this.lineNumber=-1),this.parentNode=null,this.nextSibling=null,this.firstChild=null}function ParentNode(locator){Node.call(this,locator),this.lastChild=null,this._endLocator=null}function Document(locator){ParentNode.call(this,locator),this.nodeType=NodeType.DOCUMENT}function DocumentFragment(){ParentNode.call(this,new Locator),this.nodeType=NodeType.DOCUMENT_FRAGMENT}function Element(locator,uri,localName,qName,atts,prefixMappings){ParentNode.call(this,locator),this.uri=uri,this.localName=localName,this.qName=qName,this.attributes=atts,this.prefixMappings=prefixMappings,this.nodeType=NodeType.ELEMENT}function Characters(locator,data){Node.call(this,locator),this.data=data,this.nodeType=NodeType.CHARACTERS}function IgnorableWhitespace(locator,data){Node.call(this,locator),this.data=data,this.nodeType=NodeType.IGNORABLE_WHITESPACE}function Comment(locator,data){Node.call(this,locator),this.data=data,this.nodeType=NodeType.COMMENT}function CDATA(locator){ParentNode.call(this,locator),this.nodeType=NodeType.CDATA}function Entity(name){ParentNode.call(this),this.name=name,this.nodeType=NodeType.ENTITY}function SkippedEntity(name){Node.call(this),this.name=name,this.nodeType=NodeType.SKIPPED_ENTITY}function ProcessingInstruction(target,data){Node.call(this),this.target=target,this.data=data}function DTD(name,publicIdentifier,systemIdentifier){ParentNode.call(this),this.name=name,this.publicIdentifier=publicIdentifier,this.systemIdentifier=systemIdentifier,this.nodeType=NodeType.DTD}var util=_dereq_(\"util\"),TreeBuilder=_dereq_(\"../TreeBuilder\").TreeBuilder;util.inherits(SAXTreeBuilder,TreeBuilder),SAXTreeBuilder.prototype.start=function(){this.document=new Document(this.tokenizer)},SAXTreeBuilder.prototype.end=function(){this.document.endLocator=this.tokenizer},SAXTreeBuilder.prototype.insertDoctype=function(name,publicId,systemId){var doctype=new DTD(this.tokenizer,name,publicId,systemId);doctype.endLocator=this.tokenizer,this.document.appendChild(doctype)},SAXTreeBuilder.prototype.createElement=function(namespaceURI,localName,attributes){var element=new Element(this.tokenizer,namespaceURI,localName,localName,attributes||[]);return element},SAXTreeBuilder.prototype.insertComment=function(data,parent){parent||(parent=this.currentStackItem());var comment=new Comment(this.tokenizer,data);parent.appendChild(comment)},SAXTreeBuilder.prototype.appendCharacters=function(parent,data){var text=new Characters(this.tokenizer,data);parent.appendChild(text)},SAXTreeBuilder.prototype.insertText=function(data){if(this.redirectAttachToFosterParent&&this.openElements.top.isFosterParenting()){var tableIndex=this.openElements.findIndex(\"table\"),tableItem=this.openElements.item(tableIndex),table=tableItem.node;if(0===tableIndex)return this.appendCharacters(table,data);var text=new Characters(this.tokenizer,data),parent=table.parentNode;if(parent)return parent.insertBetween(text,table.previousSibling,table),void 0;var stackParent=this.openElements.item(tableIndex-1).node;return stackParent.appendChild(text),void 0}this.appendCharacters(this.currentStackItem().node,data)},SAXTreeBuilder.prototype.attachNode=function(node,parent){parent.appendChild(node)},SAXTreeBuilder.prototype.attachNodeToFosterParent=function(child,table,stackParent){var parent=table.parentNode;parent?parent.insertBetween(child,table.previousSibling,table):stackParent.appendChild(child)},SAXTreeBuilder.prototype.detachFromParent=function(element){element.detach()},SAXTreeBuilder.prototype.reparentChildren=function(oldParent,newParent){newParent.appendChildren(oldParent.firstChild)},SAXTreeBuilder.prototype.getFragment=function(){var fragment=new DocumentFragment;return this.reparentChildren(this.openElements.rootNode,fragment),fragment},SAXTreeBuilder.prototype.addAttributesToElement=function(element,attributes){for(var i=0;attributes.length>i;i++){var attribute=attributes[i];getAttribute(element,attribute.nodeName)||element.attributes.push(attribute)}};var NodeType={CDATA:1,CHARACTERS:2,COMMENT:3,DOCUMENT:4,DOCUMENT_FRAGMENT:5,DTD:6,ELEMENT:7,ENTITY:8,IGNORABLE_WHITESPACE:9,PROCESSING_INSTRUCTION:10,SKIPPED_ENTITY:11};Node.prototype.visit=function(){throw Error(\"Not Implemented\")},Node.prototype.revisit=function(){},Node.prototype.detach=function(){null!==this.parentNode&&(this.parentNode.removeChild(this),this.parentNode=null)},Object.defineProperty(Node.prototype,\"previousSibling\",{get:function(){for(var prev=null,next=this.parentNode.firstChild;;){if(this==next)return prev;prev=next,next=next.nextSibling}}}),ParentNode.prototype=Object.create(Node.prototype),ParentNode.prototype.insertBefore=function(child,sibling){if(!sibling)return this.appendChild(child);if(child.detach(),child.parentNode=this,this.firstChild==sibling)child.nextSibling=sibling,this.firstChild=child;else{for(var prev=this.firstChild,next=this.firstChild.nextSibling;next!=sibling;)prev=next,next=next.nextSibling;prev.nextSibling=child,child.nextSibling=next}return child},ParentNode.prototype.insertBetween=function(child,prev,next){return next?(child.detach(),child.parentNode=this,child.nextSibling=next,prev?prev.nextSibling=child:firstChild=child,child):this.appendChild(child)},ParentNode.prototype.appendChild=function(child){return child.detach(),child.parentNode=this,this.firstChild?this.lastChild.nextSibling=child:this.firstChild=child,this.lastChild=child,child},ParentNode.prototype.appendChildren=function(parent){var child=parent.firstChild;if(child){var another=parent;this.firstChild?this.lastChild.nextSibling=child:this.firstChild=child,this.lastChild=another.lastChild;do child.parentNode=this;while(child=child.nextSibling);another.firstChild=null,another.lastChild=null}},ParentNode.prototype.removeChild=function(node){if(this.firstChild==node)this.firstChild=node.nextSibling,this.lastChild==node&&(this.lastChild=null);else{for(var prev=this.firstChild,next=this.firstChild.nextSibling;next!=node;)prev=next,next=next.nextSibling;prev.nextSibling=node.nextSibling,this.lastChild==node&&(this.lastChild=prev)}return node.parentNode=null,node},Object.defineProperty(ParentNode.prototype,\"endLocator\",{get:function(){return this._endLocator},set:function(endLocator){this._endLocator={lineNumber:endLocator.lineNumber,columnNumber:endLocator.columnNumber}}}),Document.prototype=Object.create(ParentNode.prototype),Document.prototype.visit=function(treeParser){treeParser.startDocument(this)},Document.prototype.revisit=function(treeParser){treeParser.endDocument(this.endLocator)},DocumentFragment.prototype=Object.create(ParentNode.prototype),DocumentFragment.prototype.visit=function(){},Element.prototype=Object.create(ParentNode.prototype),Element.prototype.visit=function(treeParser){if(this.prefixMappings)for(var key in prefixMappings){var mapping=prefixMappings[key];treeParser.startPrefixMapping(mapping.getPrefix(),mapping.getUri(),this)}treeParser.startElement(this.uri,this.localName,this.qName,this.attributes,this)},Element.prototype.revisit=function(treeParser){if(treeParser.endElement(this.uri,this.localName,this.qName,this.endLocator),this.prefixMappings)for(var key in prefixMappings){var mapping=prefixMappings[key];treeParser.endPrefixMapping(mapping.getPrefix(),this.endLocator)}},Characters.prototype=Object.create(Node.prototype),Characters.prototype.visit=function(treeParser){treeParser.characters(this.data,0,this.data.length,this)},IgnorableWhitespace.prototype=Object.create(Node.prototype),IgnorableWhitespace.prototype.visit=function(treeParser){treeParser.ignorableWhitespace(this.data,0,this.data.length,this)},Comment.prototype=Object.create(Node.prototype),Comment.prototype.visit=function(treeParser){treeParser.comment(this.data,0,this.data.length,this)},CDATA.prototype=Object.create(ParentNode.prototype),CDATA.prototype.visit=function(treeParser){treeParser.startCDATA(this)},CDATA.prototype.revisit=function(treeParser){treeParser.endCDATA(this.endLocator)},Entity.prototype=Object.create(ParentNode.prototype),Entity.prototype.visit=function(treeParser){treeParser.startEntity(this.name,this)},Entity.prototype.revisit=function(treeParser){treeParser.endEntity(this.name)},SkippedEntity.prototype=Object.create(Node.prototype),SkippedEntity.prototype.visit=function(treeParser){treeParser.skippedEntity(this.name,this)},ProcessingInstruction.prototype=Object.create(Node.prototype),ProcessingInstruction.prototype.visit=function(treeParser){treeParser.processingInstruction(this.target,this.data,this)},ProcessingInstruction.prototype.getNodeType=function(){return NodeType.PROCESSING_INSTRUCTION},DTD.prototype=Object.create(ParentNode.prototype),DTD.prototype.visit=function(treeParser){treeParser.startDTD(this.name,this.publicIdentifier,this.systemIdentifier,this)},DTD.prototype.revisit=function(treeParser){treeParser.endDTD()},exports.SAXTreeBuilder=SAXTreeBuilder},{\"../TreeBuilder\":6,util:20}],11:[function(_dereq_,module,exports){function TreeParser(contentHandler,lexicalHandler){if(this.contentHandler,this.lexicalHandler,this.locatorDelegate,!contentHandler)throw new IllegalArgumentException(\"contentHandler was null.\");this.contentHandler=contentHandler,this.lexicalHandler=lexicalHandler?lexicalHandler:new NullLexicalHandler}function NullLexicalHandler(){}TreeParser.prototype.parse=function(node){this.contentHandler.documentLocator=this;for(var next,current=node;;)if(current.visit(this),next=current.firstChild)current=next;else for(;;){if(current.revisit(this),current==node)return;if(next=current.nextSibling){current=next;break}current=current.parentNode}},TreeParser.prototype.characters=function(ch,start,length,locator){this.locatorDelegate=locator,this.contentHandler.characters(ch,start,length)},TreeParser.prototype.endDocument=function(locator){this.locatorDelegate=locator,this.contentHandler.endDocument()},TreeParser.prototype.endElement=function(uri,localName,qName,locator){this.locatorDelegate=locator,this.contentHandler.endElement(uri,localName,qName)},TreeParser.prototype.endPrefixMapping=function(prefix,locator){this.locatorDelegate=locator,this.contentHandler.endPrefixMapping(prefix)},TreeParser.prototype.ignorableWhitespace=function(ch,start,length,locator){this.locatorDelegate=locator,this.contentHandler.ignorableWhitespace(ch,start,length)},TreeParser.prototype.processingInstruction=function(target,data,locator){this.locatorDelegate=locator,this.contentHandler.processingInstruction(target,data)},TreeParser.prototype.skippedEntity=function(name,locator){this.locatorDelegate=locator,this.contentHandler.skippedEntity(name)},TreeParser.prototype.startDocument=function(locator){this.locatorDelegate=locator,this.contentHandler.startDocument()},TreeParser.prototype.startElement=function(uri,localName,qName,atts,locator){this.locatorDelegate=locator,this.contentHandler.startElement(uri,localName,qName,atts)},TreeParser.prototype.startPrefixMapping=function(prefix,uri,locator){this.locatorDelegate=locator,this.contentHandler.startPrefixMapping(prefix,uri)},TreeParser.prototype.comment=function(ch,start,length,locator){this.locatorDelegate=locator,this.lexicalHandler.comment(ch,start,length)},TreeParser.prototype.endCDATA=function(locator){this.locatorDelegate=locator,this.lexicalHandler.endCDATA()},TreeParser.prototype.endDTD=function(locator){this.locatorDelegate=locator,this.lexicalHandler.endDTD()},TreeParser.prototype.endEntity=function(name,locator){this.locatorDelegate=locator,this.lexicalHandler.endEntity(name)},TreeParser.prototype.startCDATA=function(locator){this.locatorDelegate=locator,this.lexicalHandler.startCDATA()},TreeParser.prototype.startDTD=function(name,publicId,systemId,locator){this.locatorDelegate=locator,this.lexicalHandler.startDTD(name,publicId,systemId)},TreeParser.prototype.startEntity=function(name,locator){this.locatorDelegate=locator,this.lexicalHandler.startEntity(name)},Object.defineProperty(TreeParser.prototype,\"columnNumber\",{get:function(){return this.locatorDelegate?this.locatorDelegate.columnNumber:-1}}),Object.defineProperty(TreeParser.prototype,\"lineNumber\",{get:function(){return this.locatorDelegate?this.locatorDelegate.lineNumber:-1}}),NullLexicalHandler.prototype.comment=function(){},NullLexicalHandler.prototype.endCDATA=function(){},NullLexicalHandler.prototype.endDTD=function(){},NullLexicalHandler.prototype.endEntity=function(){},NullLexicalHandler.prototype.startCDATA=function(){},NullLexicalHandler.prototype.startDTD=function(){},NullLexicalHandler.prototype.startEntity=function(){},exports.TreeParser=TreeParser},{}],12:[function(_dereq_,module){module.exports={\"Aacute;\":\"Á\",Aacute:\"Á\",\"aacute;\":\"á\",aacute:\"á\",\"Abreve;\":\"Ă\",\"abreve;\":\"ă\",\"ac;\":\"∾\",\"acd;\":\"∿\",\"acE;\":\"∾̳\",\"Acirc;\":\"Â\",Acirc:\"Â\",\"acirc;\":\"â\",acirc:\"â\",\"acute;\":\"´\",acute:\"´\",\"Acy;\":\"А\",\"acy;\":\"а\",\"AElig;\":\"Æ\",AElig:\"Æ\",\"aelig;\":\"æ\",aelig:\"æ\",\"af;\":\"⁡\",\"Afr;\":\"𝔄\",\"afr;\":\"𝔞\",\"Agrave;\":\"À\",Agrave:\"À\",\"agrave;\":\"à\",agrave:\"à\",\"alefsym;\":\"ℵ\",\"aleph;\":\"ℵ\",\"Alpha;\":\"Α\",\"alpha;\":\"α\",\"Amacr;\":\"Ā\",\"amacr;\":\"ā\",\"amalg;\":\"⨿\",\"amp;\":\"&\",amp:\"&\",\"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:\"Å\",\"aring;\":\"å\",aring:\"å\",\"Ascr;\":\"𝒜\",\"ascr;\":\"𝒶\",\"Assign;\":\"≔\",\"ast;\":\"*\",\"asymp;\":\"≈\",\"asympeq;\":\"≍\",\"Atilde;\":\"Ã\",Atilde:\"Ã\",\"atilde;\":\"ã\",atilde:\"ã\",\"Auml;\":\"Ä\",Auml:\"Ä\",\"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;\":\"¦\",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:\"Ç\",\"ccedil;\":\"ç\",ccedil:\"ç\",\"Ccirc;\":\"Ĉ\",\"ccirc;\":\"ĉ\",\"Cconint;\":\"∰\",\"ccups;\":\"⩌\",\"ccupssm;\":\"⩐\",\"Cdot;\":\"Ċ\",\"cdot;\":\"ċ\",\"cedil;\":\"¸\",cedil:\"¸\",\"Cedilla;\":\"¸\",\"cemptyv;\":\"⦲\",\"cent;\":\"¢\",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:\"©\",\"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;\":\"¤\",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;\":\"°\",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;\":\"÷\",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:\"É\",\"eacute;\":\"é\",eacute:\"é\",\"easter;\":\"⩮\",\"Ecaron;\":\"Ě\",\"ecaron;\":\"ě\",\"Ecirc;\":\"Ê\",Ecirc:\"Ê\",\"ecirc;\":\"ê\",ecirc:\"ê\",\"ecir;\":\"≖\",\"ecolon;\":\"≕\",\"Ecy;\":\"Э\",\"ecy;\":\"э\",\"eDDot;\":\"⩷\",\"Edot;\":\"Ė\",\"edot;\":\"ė\",\"eDot;\":\"≑\",\"ee;\":\"ⅇ\",\"efDot;\":\"≒\",\"Efr;\":\"𝔈\",\"efr;\":\"𝔢\",\"eg;\":\"⪚\",\"Egrave;\":\"È\",Egrave:\"È\",\"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:\"Ð\",\"eth;\":\"ð\",eth:\"ð\",\"Euml;\":\"Ë\",Euml:\"Ë\",\"euml;\":\"ë\",euml:\"ë\",\"euro;\":\"€\",\"excl;\":\"!\",\"exist;\":\"∃\",\"Exists;\":\"∃\",\"expectation;\":\"ℰ\",\"exponentiale;\":\"ⅇ\",\"ExponentialE;\":\"ⅇ\",\"fallingdotseq;\":\"≒\",\"Fcy;\":\"Ф\",\"fcy;\":\"ф\",\"female;\":\"♀\",\"ffilig;\":\"ﬃ\",\"fflig;\":\"ﬀ\",\"ffllig;\":\"ﬄ\",\"Ffr;\":\"𝔉\",\"ffr;\":\"𝔣\",\"filig;\":\"ﬁ\",\"FilledSmallSquare;\":\"◼\",\"FilledVerySmallSquare;\":\"▪\",\"fjlig;\":\"fj\",\"flat;\":\"♭\",\"fllig;\":\"ﬂ\",\"fltns;\":\"▱\",\"fnof;\":\"ƒ\",\"Fopf;\":\"𝔽\",\"fopf;\":\"𝕗\",\"forall;\":\"∀\",\"ForAll;\":\"∀\",\"fork;\":\"⋔\",\"forkv;\":\"⫙\",\"Fouriertrf;\":\"ℱ\",\"fpartint;\":\"⨍\",\"frac12;\":\"½\",frac12:\"½\",\"frac13;\":\"⅓\",\"frac14;\":\"¼\",frac14:\"¼\",\"frac15;\":\"⅕\",\"frac16;\":\"⅙\",\"frac18;\":\"⅛\",\"frac23;\":\"⅔\",\"frac25;\":\"⅖\",\"frac34;\":\"¾\",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;\":\">\",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:\"Í\",\"iacute;\":\"í\",iacute:\"í\",\"ic;\":\"⁣\",\"Icirc;\":\"Î\",Icirc:\"Î\",\"icirc;\":\"î\",icirc:\"î\",\"Icy;\":\"И\",\"icy;\":\"и\",\"Idot;\":\"İ\",\"IEcy;\":\"Е\",\"iecy;\":\"е\",\"iexcl;\":\"¡\",iexcl:\"¡\",\"iff;\":\"⇔\",\"ifr;\":\"𝔦\",\"Ifr;\":\"ℑ\",\"Igrave;\":\"Ì\",Igrave:\"Ì\",\"igrave;\":\"ì\",igrave:\"ì\",\"ii;\":\"ⅈ\",\"iiiint;\":\"⨌\",\"iiint;\":\"∭\",\"iinfin;\":\"⧜\",\"iiota;\":\"℩\",\"IJlig;\":\"Ĳ\",\"ijlig;\":\"ĳ\",\"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;\":\"¿\",iquest:\"¿\",\"iscr;\":\"𝒾\",\"Iscr;\":\"ℐ\",\"isin;\":\"∈\",\"isindot;\":\"⋵\",\"isinE;\":\"⋹\",\"isins;\":\"⋴\",\"isinsv;\":\"⋳\",\"isinv;\":\"∈\",\"it;\":\"⁢\",\"Itilde;\":\"Ĩ\",\"itilde;\":\"ĩ\",\"Iukcy;\":\"І\",\"iukcy;\":\"і\",\"Iuml;\":\"Ï\",Iuml:\"Ï\",\"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;\":\"«\",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;\":\"<\",LT:\"<\",\"Lt;\":\"≪\",\"ltdot;\":\"⋖\",\"lthree;\":\"⋋\",\"ltimes;\":\"⋉\",\"ltlarr;\":\"⥶\",\"ltquest;\":\"⩻\",\"ltri;\":\"◃\",\"ltrie;\":\"⊴\",\"ltrif;\":\"◂\",\"ltrPar;\":\"⦖\",\"lurdshar;\":\"⥊\",\"luruhar;\":\"⥦\",\"lvertneqq;\":\"≨︀\",\"lvnE;\":\"≨︀\",\"macr;\":\"¯\",macr:\"¯\",\"male;\":\"♂\",\"malt;\":\"✠\",\"maltese;\":\"✠\",\"Map;\":\"⤅\",\"map;\":\"↦\",\"mapsto;\":\"↦\",\"mapstodown;\":\"↧\",\"mapstoleft;\":\"↤\",\"mapstoup;\":\"↥\",\"marker;\":\"▮\",\"mcomma;\":\"⨩\",\"Mcy;\":\"М\",\"mcy;\":\"м\",\"mdash;\":\"—\",\"mDDot;\":\"∺\",\"measuredangle;\":\"∡\",\"MediumSpace;\":\" \",\"Mellintrf;\":\"ℳ\",\"Mfr;\":\"𝔐\",\"mfr;\":\"𝔪\",\"mho;\":\"℧\",\"micro;\":\"µ\",micro:\"µ\",\"midast;\":\"*\",\"midcir;\":\"⫰\",\"mid;\":\"∣\",\"middot;\":\"·\",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;\":\"ŉ\",\"napprox;\":\"≉\",\"natural;\":\"♮\",\"naturals;\":\"ℕ\",\"natur;\":\"♮\",\"nbsp;\":\" \",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;\":\"¬\",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:\"Ñ\",\"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:\"Ó\",\"oacute;\":\"ó\",oacute:\"ó\",\"oast;\":\"⊛\",\"Ocirc;\":\"Ô\",Ocirc:\"Ô\",\"ocirc;\":\"ô\",ocirc:\"ô\",\"ocir;\":\"⊚\",\"Ocy;\":\"О\",\"ocy;\":\"о\",\"odash;\":\"⊝\",\"Odblac;\":\"Ő\",\"odblac;\":\"ő\",\"odiv;\":\"⨸\",\"odot;\":\"⊙\",\"odsold;\":\"⦼\",\"OElig;\":\"Œ\",\"oelig;\":\"œ\",\"ofcir;\":\"⦿\",\"Ofr;\":\"𝔒\",\"ofr;\":\"𝔬\",\"ogon;\":\"˛\",\"Ograve;\":\"Ò\",Ograve:\"Ò\",\"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;\":\"ª\",ordf:\"ª\",\"ordm;\":\"º\",ordm:\"º\",\"origof;\":\"⊶\",\"oror;\":\"⩖\",\"orslope;\":\"⩗\",\"orv;\":\"⩛\",\"oS;\":\"Ⓢ\",\"Oscr;\":\"𝒪\",\"oscr;\":\"ℴ\",\"Oslash;\":\"Ø\",Oslash:\"Ø\",\"oslash;\":\"ø\",oslash:\"ø\",\"osol;\":\"⊘\",\"Otilde;\":\"Õ\",Otilde:\"Õ\",\"otilde;\":\"õ\",otilde:\"õ\",\"otimesas;\":\"⨶\",\"Otimes;\":\"⨷\",\"otimes;\":\"⊗\",\"Ouml;\":\"Ö\",Ouml:\"Ö\",\"ouml;\":\"ö\",ouml:\"ö\",\"ovbar;\":\"⌽\",\"OverBar;\":\"‾\",\"OverBrace;\":\"⏞\",\"OverBracket;\":\"⎴\",\"OverParenthesis;\":\"⏜\",\"para;\":\"¶\",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;\":\"±\",plusmn:\"±\",\"plussim;\":\"⨦\",\"plustwo;\":\"⨧\",\"pm;\":\"±\",\"Poincareplane;\":\"ℌ\",\"pointint;\":\"⨕\",\"popf;\":\"𝕡\",\"Popf;\":\"ℙ\",\"pound;\":\"£\",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:\\'\"\\',\"QUOT;\":\\'\"\\',QUOT:\\'\"\\',\"rAarr;\":\"⇛\",\"race;\":\"∽̱\",\"Racute;\":\"Ŕ\",\"racute;\":\"ŕ\",\"radic;\":\"√\",\"raemptyv;\":\"⦳\",\"rang;\":\"⟩\",\"Rang;\":\"⟫\",\"rangd;\":\"⦒\",\"range;\":\"⦥\",\"rangle;\":\"⟩\",\"raquo;\":\"»\",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:\"®\",\"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;\":\"§\",sect:\"§\",\"semi;\":\";\",\"seswar;\":\"⤩\",\"setminus;\":\"∖\",\"setmn;\":\"∖\",\"sext;\":\"✶\",\"Sfr;\":\"𝔖\",\"sfr;\":\"𝔰\",\"sfrown;\":\"⌢\",\"sharp;\":\"♯\",\"SHCHcy;\":\"Щ\",\"shchcy;\":\"щ\",\"SHcy;\":\"Ш\",\"shcy;\":\"ш\",\"ShortDownArrow;\":\"↓\",\"ShortLeftArrow;\":\"←\",\"shortmid;\":\"∣\",\"shortparallel;\":\"∥\",\"ShortRightArrow;\":\"→\",\"ShortUpArrow;\":\"↑\",\"shy;\":\"­\",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;\":\"¹\",sup1:\"¹\",\"sup2;\":\"²\",sup2:\"²\",\"sup3;\":\"³\",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;\":\"ß\",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:\"Þ\",\"thorn;\":\"þ\",thorn:\"þ\",\"tilde;\":\"˜\",\"Tilde;\":\"∼\",\"TildeEqual;\":\"≃\",\"TildeFullEqual;\":\"≅\",\"TildeTilde;\":\"≈\",\"timesbar;\":\"⨱\",\"timesb;\":\"⊠\",\"times;\":\"×\",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:\"Ú\",\"uacute;\":\"ú\",uacute:\"ú\",\"uarr;\":\"↑\",\"Uarr;\":\"↟\",\"uArr;\":\"⇑\",\"Uarrocir;\":\"⥉\",\"Ubrcy;\":\"Ў\",\"ubrcy;\":\"ў\",\"Ubreve;\":\"Ŭ\",\"ubreve;\":\"ŭ\",\"Ucirc;\":\"Û\",Ucirc:\"Û\",\"ucirc;\":\"û\",ucirc:\"û\",\"Ucy;\":\"У\",\"ucy;\":\"у\",\"udarr;\":\"⇅\",\"Udblac;\":\"Ű\",\"udblac;\":\"ű\",\"udhar;\":\"⥮\",\"ufisht;\":\"⥾\",\"Ufr;\":\"𝔘\",\"ufr;\":\"𝔲\",\"Ugrave;\":\"Ù\",Ugrave:\"Ù\",\"ugrave;\":\"ù\",ugrave:\"ù\",\"uHar;\":\"⥣\",\"uharl;\":\"↿\",\"uharr;\":\"↾\",\"uhblk;\":\"▀\",\"ulcorn;\":\"⌜\",\"ulcorner;\":\"⌜\",\"ulcrop;\":\"⌏\",\"ultri;\":\"◸\",\"Umacr;\":\"Ū\",\"umacr;\":\"ū\",\"uml;\":\"¨\",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:\"Ü\",\"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:\"Ý\",\"yacute;\":\"ý\",yacute:\"ý\",\"YAcy;\":\"Я\",\"yacy;\":\"я\",\"Ycirc;\":\"Ŷ\",\"ycirc;\":\"ŷ\",\"Ycy;\":\"Ы\",\"ycy;\":\"ы\",\"yen;\":\"¥\",yen:\"¥\",\"Yfr;\":\"𝔜\",\"yfr;\":\"𝔶\",\"YIcy;\":\"Ї\",\"yicy;\":\"ї\",\"Yopf;\":\"𝕐\",\"yopf;\":\"𝕪\",\"Yscr;\":\"𝒴\",\"yscr;\":\"𝓎\",\"YUcy;\":\"Ю\",\"yucy;\":\"ю\",\"yuml;\":\"ÿ\",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;\":\"‌\"}\\n},{}],13:[function(_dereq_,module){function replacer(key,value){return util.isUndefined(value)?\"\"+value:!util.isNumber(value)||!isNaN(value)&&isFinite(value)?util.isFunction(value)||util.isRegExp(value)?\"\"+value:value:\"\"+value}function truncate(s,n){return util.isString(s)?n>s.length?s:s.slice(0,n):s}function getMessage(self){return truncate(JSON.stringify(self.actual,replacer),128)+\" \"+self.operator+\" \"+truncate(JSON.stringify(self.expected,replacer),128)}function fail(actual,expected,message,operator,stackStartFunction){throw new assert.AssertionError({message:message,actual:actual,expected:expected,operator:operator,stackStartFunction:stackStartFunction})}function ok(value,message){value||fail(value,!0,message,\"==\",assert.ok)}function _deepEqual(actual,expected){if(actual===expected)return!0;if(util.isBuffer(actual)&&util.isBuffer(expected)){if(actual.length!=expected.length)return!1;for(var i=0;actual.length>i;i++)if(actual[i]!==expected[i])return!1;return!0}return util.isDate(actual)&&util.isDate(expected)?actual.getTime()===expected.getTime():util.isRegExp(actual)&&util.isRegExp(expected)?actual.source===expected.source&&actual.global===expected.global&&actual.multiline===expected.multiline&&actual.lastIndex===expected.lastIndex&&actual.ignoreCase===expected.ignoreCase:util.isObject(actual)||util.isObject(expected)?objEquiv(actual,expected):actual==expected}function isArguments(object){return\"[object Arguments]\"==Object.prototype.toString.call(object)}function objEquiv(a,b){if(util.isNullOrUndefined(a)||util.isNullOrUndefined(b))return!1;if(a.prototype!==b.prototype)return!1;if(isArguments(a))return isArguments(b)?(a=pSlice.call(a),b=pSlice.call(b),_deepEqual(a,b)):!1;try{var key,i,ka=objectKeys(a),kb=objectKeys(b)}catch(e){return!1}if(ka.length!=kb.length)return!1;for(ka.sort(),kb.sort(),i=ka.length-1;i>=0;i--)if(ka[i]!=kb[i])return!1;for(i=ka.length-1;i>=0;i--)if(key=ka[i],!_deepEqual(a[key],b[key]))return!1;return!0}function expectedException(actual,expected){return actual&&expected?\"[object RegExp]\"==Object.prototype.toString.call(expected)?expected.test(actual):actual instanceof expected?!0:expected.call({},actual)===!0?!0:!1:!1}function _throws(shouldThrow,block,expected,message){var actual;util.isString(expected)&&(message=expected,expected=null);try{block()}catch(e){actual=e}if(message=(expected&&expected.name?\" (\"+expected.name+\").\":\".\")+(message?\" \"+message:\".\"),shouldThrow&&!actual&&fail(actual,expected,\"Missing expected exception\"+message),!shouldThrow&&expectedException(actual,expected)&&fail(actual,expected,\"Got unwanted exception\"+message),shouldThrow&&actual&&expected&&!expectedException(actual,expected)||!shouldThrow&&actual)throw actual}var util=_dereq_(\"util/\"),pSlice=Array.prototype.slice,hasOwn=Object.prototype.hasOwnProperty,assert=module.exports=ok;assert.AssertionError=function(options){this.name=\"AssertionError\",this.actual=options.actual,this.expected=options.expected,this.operator=options.operator,options.message?(this.message=options.message,this.generatedMessage=!1):(this.message=getMessage(this),this.generatedMessage=!0);var stackStartFunction=options.stackStartFunction||fail;if(Error.captureStackTrace)Error.captureStackTrace(this,stackStartFunction);else{var err=Error();if(err.stack){var out=err.stack,fn_name=stackStartFunction.name,idx=out.indexOf(\"\\\\n\"+fn_name);if(idx>=0){var next_line=out.indexOf(\"\\\\n\",idx+1);out=out.substring(next_line+1)}this.stack=out}}},util.inherits(assert.AssertionError,Error),assert.fail=fail,assert.ok=ok,assert.equal=function(actual,expected,message){actual!=expected&&fail(actual,expected,message,\"==\",assert.equal)},assert.notEqual=function(actual,expected,message){actual==expected&&fail(actual,expected,message,\"!=\",assert.notEqual)},assert.deepEqual=function(actual,expected,message){_deepEqual(actual,expected)||fail(actual,expected,message,\"deepEqual\",assert.deepEqual)},assert.notDeepEqual=function(actual,expected,message){_deepEqual(actual,expected)&&fail(actual,expected,message,\"notDeepEqual\",assert.notDeepEqual)},assert.strictEqual=function(actual,expected,message){actual!==expected&&fail(actual,expected,message,\"===\",assert.strictEqual)},assert.notStrictEqual=function(actual,expected,message){actual===expected&&fail(actual,expected,message,\"!==\",assert.notStrictEqual)},assert.throws=function(){_throws.apply(this,[!0].concat(pSlice.call(arguments)))},assert.doesNotThrow=function(){_throws.apply(this,[!1].concat(pSlice.call(arguments)))},assert.ifError=function(err){if(err)throw err};var objectKeys=Object.keys||function(obj){var keys=[];for(var key in obj)hasOwn.call(obj,key)&&keys.push(key);return keys}},{\"util/\":15}],14:[function(_dereq_,module){module.exports=function(arg){return arg&&\"object\"==typeof arg&&\"function\"==typeof arg.copy&&\"function\"==typeof arg.fill&&\"function\"==typeof arg.readUInt8}},{}],15:[function(_dereq_,module,exports){(function(process,global){function inspect(obj,opts){var ctx={seen:[],stylize:stylizeNoColor};return arguments.length>=3&&(ctx.depth=arguments[2]),arguments.length>=4&&(ctx.colors=arguments[3]),isBoolean(opts)?ctx.showHidden=opts:opts&&exports._extend(ctx,opts),isUndefined(ctx.showHidden)&&(ctx.showHidden=!1),isUndefined(ctx.depth)&&(ctx.depth=2),isUndefined(ctx.colors)&&(ctx.colors=!1),isUndefined(ctx.customInspect)&&(ctx.customInspect=!0),ctx.colors&&(ctx.stylize=stylizeWithColor),formatValue(ctx,obj,ctx.depth)}function stylizeWithColor(str,styleType){var style=inspect.styles[styleType];return style?\"\u001b[\"+inspect.colors[style][0]+\"m\"+str+\"\u001b[\"+inspect.colors[style][1]+\"m\":str}function stylizeNoColor(str){return str}function arrayToHash(array){var hash={};return array.forEach(function(val){hash[val]=!0}),hash}function formatValue(ctx,value,recurseTimes){if(ctx.customInspect&&value&&isFunction(value.inspect)&&value.inspect!==exports.inspect&&(!value.constructor||value.constructor.prototype!==value)){var ret=value.inspect(recurseTimes,ctx);return isString(ret)||(ret=formatValue(ctx,ret,recurseTimes)),ret}var primitive=formatPrimitive(ctx,value);if(primitive)return primitive;var keys=Object.keys(value),visibleKeys=arrayToHash(keys);if(ctx.showHidden&&(keys=Object.getOwnPropertyNames(value)),isError(value)&&(keys.indexOf(\"message\")>=0||keys.indexOf(\"description\")>=0))return formatError(value);if(0===keys.length){if(isFunction(value)){var name=value.name?\": \"+value.name:\"\";return ctx.stylize(\"[Function\"+name+\"]\",\"special\")}if(isRegExp(value))return ctx.stylize(RegExp.prototype.toString.call(value),\"regexp\");if(isDate(value))return ctx.stylize(Date.prototype.toString.call(value),\"date\");if(isError(value))return formatError(value)}var base=\"\",array=!1,braces=[\"{\",\"}\"];if(isArray(value)&&(array=!0,braces=[\"[\",\"]\"]),isFunction(value)){var n=value.name?\": \"+value.name:\"\";base=\" [Function\"+n+\"]\"}if(isRegExp(value)&&(base=\" \"+RegExp.prototype.toString.call(value)),isDate(value)&&(base=\" \"+Date.prototype.toUTCString.call(value)),isError(value)&&(base=\" \"+formatError(value)),0===keys.length&&(!array||0==value.length))return braces[0]+base+braces[1];if(0>recurseTimes)return isRegExp(value)?ctx.stylize(RegExp.prototype.toString.call(value),\"regexp\"):ctx.stylize(\"[Object]\",\"special\");ctx.seen.push(value);var output;return output=array?formatArray(ctx,value,recurseTimes,visibleKeys,keys):keys.map(function(key){return formatProperty(ctx,value,recurseTimes,visibleKeys,key,array)}),ctx.seen.pop(),reduceToSingleString(output,base,braces)}function formatPrimitive(ctx,value){if(isUndefined(value))return ctx.stylize(\"undefined\",\"undefined\");if(isString(value)){var simple=\"\\'\"+JSON.stringify(value).replace(/^\"|\"$/g,\"\").replace(/\\'/g,\"\\\\\\\\\\'\").replace(/\\\\\\\\\"/g,\\'\"\\')+\"\\'\";return ctx.stylize(simple,\"string\")}return isNumber(value)?ctx.stylize(\"\"+value,\"number\"):isBoolean(value)?ctx.stylize(\"\"+value,\"boolean\"):isNull(value)?ctx.stylize(\"null\",\"null\"):void 0}function formatError(value){return\"[\"+Error.prototype.toString.call(value)+\"]\"}function formatArray(ctx,value,recurseTimes,visibleKeys,keys){for(var output=[],i=0,l=value.length;l>i;++i)hasOwnProperty(value,i+\"\")?output.push(formatProperty(ctx,value,recurseTimes,visibleKeys,i+\"\",!0)):output.push(\"\");return keys.forEach(function(key){key.match(/^\\\\d+$/)||output.push(formatProperty(ctx,value,recurseTimes,visibleKeys,key,!0))}),output}function formatProperty(ctx,value,recurseTimes,visibleKeys,key,array){var name,str,desc;if(desc=Object.getOwnPropertyDescriptor(value,key)||{value:value[key]},desc.get?str=desc.set?ctx.stylize(\"[Getter/Setter]\",\"special\"):ctx.stylize(\"[Getter]\",\"special\"):desc.set&&(str=ctx.stylize(\"[Setter]\",\"special\")),hasOwnProperty(visibleKeys,key)||(name=\"[\"+key+\"]\"),str||(0>ctx.seen.indexOf(desc.value)?(str=isNull(recurseTimes)?formatValue(ctx,desc.value,null):formatValue(ctx,desc.value,recurseTimes-1),str.indexOf(\"\\\\n\")>-1&&(str=array?str.split(\"\\\\n\").map(function(line){return\"  \"+line}).join(\"\\\\n\").substr(2):\"\\\\n\"+str.split(\"\\\\n\").map(function(line){return\"   \"+line}).join(\"\\\\n\"))):str=ctx.stylize(\"[Circular]\",\"special\")),isUndefined(name)){if(array&&key.match(/^\\\\d+$/))return str;name=JSON.stringify(\"\"+key),name.match(/^\"([a-zA-Z_][a-zA-Z_0-9]*)\"$/)?(name=name.substr(1,name.length-2),name=ctx.stylize(name,\"name\")):(name=name.replace(/\\'/g,\"\\\\\\\\\\'\").replace(/\\\\\\\\\"/g,\\'\"\\').replace(/(^\"|\"$)/g,\"\\'\"),name=ctx.stylize(name,\"string\"))}return name+\": \"+str}function reduceToSingleString(output,base,braces){var numLinesEst=0,length=output.reduce(function(prev,cur){return numLinesEst++,cur.indexOf(\"\\\\n\")>=0&&numLinesEst++,prev+cur.replace(/\\\\u001b\\\\[\\\\d\\\\d?m/g,\"\").length+1},0);return length>60?braces[0]+(\"\"===base?\"\":base+\"\\\\n \")+\" \"+output.join(\",\\\\n  \")+\" \"+braces[1]:braces[0]+base+\" \"+output.join(\", \")+\" \"+braces[1]}function isArray(ar){return Array.isArray(ar)}function isBoolean(arg){return\"boolean\"==typeof arg}function isNull(arg){return null===arg}function isNullOrUndefined(arg){return null==arg}function isNumber(arg){return\"number\"==typeof arg}function isString(arg){return\"string\"==typeof arg}function isSymbol(arg){return\"symbol\"==typeof arg}function isUndefined(arg){return void 0===arg}function isRegExp(re){return isObject(re)&&\"[object RegExp]\"===objectToString(re)}function isObject(arg){return\"object\"==typeof arg&&null!==arg}function isDate(d){return isObject(d)&&\"[object Date]\"===objectToString(d)}function isError(e){return isObject(e)&&(\"[object Error]\"===objectToString(e)||e instanceof Error)}function isFunction(arg){return\"function\"==typeof arg}function isPrimitive(arg){return null===arg||\"boolean\"==typeof arg||\"number\"==typeof arg||\"string\"==typeof arg||\"symbol\"==typeof arg||arg===void 0}function objectToString(o){return Object.prototype.toString.call(o)}function pad(n){return 10>n?\"0\"+n.toString(10):n.toString(10)}function timestamp(){var d=new Date,time=[pad(d.getHours()),pad(d.getMinutes()),pad(d.getSeconds())].join(\":\");return[d.getDate(),months[d.getMonth()],time].join(\" \")}function hasOwnProperty(obj,prop){return Object.prototype.hasOwnProperty.call(obj,prop)}var formatRegExp=/%[sdj%]/g;exports.format=function(f){if(!isString(f)){for(var objects=[],i=0;arguments.length>i;i++)objects.push(inspect(arguments[i]));return objects.join(\" \")}for(var i=1,args=arguments,len=args.length,str=(f+\"\").replace(formatRegExp,function(x){if(\"%%\"===x)return\"%\";if(i>=len)return x;switch(x){case\"%s\":return args[i++]+\"\";case\"%d\":return Number(args[i++]);case\"%j\":try{return JSON.stringify(args[i++])}catch(_){return\"[Circular]\"}default:return x}}),x=args[i];len>i;x=args[++i])str+=isNull(x)||!isObject(x)?\" \"+x:\" \"+inspect(x);return str},exports.deprecate=function(fn,msg){function deprecated(){if(!warned){if(process.throwDeprecation)throw Error(msg);process.traceDeprecation?console.trace(msg):console.error(msg),warned=!0}return fn.apply(this,arguments)}if(isUndefined(global.process))return function(){return exports.deprecate(fn,msg).apply(this,arguments)};if(process.noDeprecation===!0)return fn;var warned=!1;return deprecated};var debugEnviron,debugs={};exports.debuglog=function(set){if(isUndefined(debugEnviron)&&(debugEnviron=process.env.NODE_DEBUG||\"\"),set=set.toUpperCase(),!debugs[set])if(RegExp(\"\\\\\\\\b\"+set+\"\\\\\\\\b\",\"i\").test(debugEnviron)){var pid=process.pid;debugs[set]=function(){var msg=exports.format.apply(exports,arguments);console.error(\"%s %d: %s\",set,pid,msg)}}else debugs[set]=function(){};return debugs[set]},exports.inspect=inspect,inspect.colors={bold:[1,22],italic:[3,23],underline:[4,24],inverse:[7,27],white:[37,39],grey:[90,39],black:[30,39],blue:[34,39],cyan:[36,39],green:[32,39],magenta:[35,39],red:[31,39],yellow:[33,39]},inspect.styles={special:\"cyan\",number:\"yellow\",\"boolean\":\"yellow\",undefined:\"grey\",\"null\":\"bold\",string:\"green\",date:\"magenta\",regexp:\"red\"},exports.isArray=isArray,exports.isBoolean=isBoolean,exports.isNull=isNull,exports.isNullOrUndefined=isNullOrUndefined,exports.isNumber=isNumber,exports.isString=isString,exports.isSymbol=isSymbol,exports.isUndefined=isUndefined,exports.isRegExp=isRegExp,exports.isObject=isObject,exports.isDate=isDate,exports.isError=isError,exports.isFunction=isFunction,exports.isPrimitive=isPrimitive,exports.isBuffer=_dereq_(\"./support/isBuffer\");var months=[\"Jan\",\"Feb\",\"Mar\",\"Apr\",\"May\",\"Jun\",\"Jul\",\"Aug\",\"Sep\",\"Oct\",\"Nov\",\"Dec\"];exports.log=function(){console.log(\"%s - %s\",timestamp(),exports.format.apply(exports,arguments))},exports.inherits=_dereq_(\"inherits\"),exports._extend=function(origin,add){if(!add||!isObject(add))return origin;for(var keys=Object.keys(add),i=keys.length;i--;)origin[keys[i]]=add[keys[i]];return origin}}).call(this,_dereq_(\"/usr/local/lib/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js\"),\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{})},{\"./support/isBuffer\":14,\"/usr/local/lib/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js\":18,inherits:17}],16:[function(_dereq_,module){function EventEmitter(){this._events=this._events||{},this._maxListeners=this._maxListeners||void 0}function isFunction(arg){return\"function\"==typeof arg}function isNumber(arg){return\"number\"==typeof arg}function isObject(arg){return\"object\"==typeof arg&&null!==arg}function isUndefined(arg){return void 0===arg}module.exports=EventEmitter,EventEmitter.EventEmitter=EventEmitter,EventEmitter.prototype._events=void 0,EventEmitter.prototype._maxListeners=void 0,EventEmitter.defaultMaxListeners=10,EventEmitter.prototype.setMaxListeners=function(n){if(!isNumber(n)||0>n||isNaN(n))throw TypeError(\"n must be a positive number\");return this._maxListeners=n,this},EventEmitter.prototype.emit=function(type){var er,handler,len,args,i,listeners;if(this._events||(this._events={}),\"error\"===type&&(!this._events.error||isObject(this._events.error)&&!this._events.error.length))throw er=arguments[1],er instanceof Error?er:TypeError(\\'Uncaught, unspecified \"error\" event.\\');if(handler=this._events[type],isUndefined(handler))return!1;if(isFunction(handler))switch(arguments.length){case 1:handler.call(this);break;case 2:handler.call(this,arguments[1]);break;case 3:handler.call(this,arguments[1],arguments[2]);break;default:for(len=arguments.length,args=Array(len-1),i=1;len>i;i++)args[i-1]=arguments[i];handler.apply(this,args)}else if(isObject(handler)){for(len=arguments.length,args=Array(len-1),i=1;len>i;i++)args[i-1]=arguments[i];for(listeners=handler.slice(),len=listeners.length,i=0;len>i;i++)listeners[i].apply(this,args)}return!0},EventEmitter.prototype.addListener=function(type,listener){var m;if(!isFunction(listener))throw TypeError(\"listener must be a function\");if(this._events||(this._events={}),this._events.newListener&&this.emit(\"newListener\",type,isFunction(listener.listener)?listener.listener:listener),this._events[type]?isObject(this._events[type])?this._events[type].push(listener):this._events[type]=[this._events[type],listener]:this._events[type]=listener,isObject(this._events[type])&&!this._events[type].warned){var m;m=isUndefined(this._maxListeners)?EventEmitter.defaultMaxListeners:this._maxListeners,m&&m>0&&this._events[type].length>m&&(this._events[type].warned=!0,console.error(\"(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.\",this._events[type].length),console.trace())}return this},EventEmitter.prototype.on=EventEmitter.prototype.addListener,EventEmitter.prototype.once=function(type,listener){function g(){this.removeListener(type,g),fired||(fired=!0,listener.apply(this,arguments))}if(!isFunction(listener))throw TypeError(\"listener must be a function\");var fired=!1;return g.listener=listener,this.on(type,g),this},EventEmitter.prototype.removeListener=function(type,listener){var list,position,length,i;if(!isFunction(listener))throw TypeError(\"listener must be a function\");if(!this._events||!this._events[type])return this;if(list=this._events[type],length=list.length,position=-1,list===listener||isFunction(list.listener)&&list.listener===listener)delete this._events[type],this._events.removeListener&&this.emit(\"removeListener\",type,listener);else if(isObject(list)){for(i=length;i--\\x3e0;)if(list[i]===listener||list[i].listener&&list[i].listener===listener){position=i;break}if(0>position)return this;1===list.length?(list.length=0,delete this._events[type]):list.splice(position,1),this._events.removeListener&&this.emit(\"removeListener\",type,listener)}return this},EventEmitter.prototype.removeAllListeners=function(type){var key,listeners;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[type]&&delete this._events[type],this;if(0===arguments.length){for(key in this._events)\"removeListener\"!==key&&this.removeAllListeners(key);return this.removeAllListeners(\"removeListener\"),this._events={},this}if(listeners=this._events[type],isFunction(listeners))this.removeListener(type,listeners);else for(;listeners.length;)this.removeListener(type,listeners[listeners.length-1]);return delete this._events[type],this},EventEmitter.prototype.listeners=function(type){var ret;return ret=this._events&&this._events[type]?isFunction(this._events[type])?[this._events[type]]:this._events[type].slice():[]},EventEmitter.listenerCount=function(emitter,type){var ret;return ret=emitter._events&&emitter._events[type]?isFunction(emitter._events[type])?1:emitter._events[type].length:0}},{}],17:[function(_dereq_,module){module.exports=\"function\"==typeof Object.create?function(ctor,superCtor){ctor.super_=superCtor,ctor.prototype=Object.create(superCtor.prototype,{constructor:{value:ctor,enumerable:!1,writable:!0,configurable:!0}})}:function(ctor,superCtor){ctor.super_=superCtor;var TempCtor=function(){};TempCtor.prototype=superCtor.prototype,ctor.prototype=new TempCtor,ctor.prototype.constructor=ctor}},{}],18:[function(_dereq_,module){function noop(){}var process=module.exports={};process.nextTick=function(){var canSetImmediate=\"undefined\"!=typeof window&&window.setImmediate,canPost=\"undefined\"!=typeof window&&window.postMessage&&window.addEventListener;if(canSetImmediate)return function(f){return window.setImmediate(f)};if(canPost){var queue=[];return window.addEventListener(\"message\",function(ev){var source=ev.source;if((source===window||null===source)&&\"process-tick\"===ev.data&&(ev.stopPropagation(),queue.length>0)){var fn=queue.shift();fn()}},!0),function(fn){queue.push(fn),window.postMessage(\"process-tick\",\"*\")}}return function(fn){setTimeout(fn,0)}}(),process.title=\"browser\",process.browser=!0,process.env={},process.argv=[],process.on=noop,process.once=noop,process.off=noop,process.emit=noop,process.binding=function(){throw Error(\"process.binding is not supported\")},process.cwd=function(){return\"/\"},process.chdir=function(){throw Error(\"process.chdir is not supported\")}},{}],19:[function(_dereq_,module){module.exports=_dereq_(14)},{}],20:[function(_dereq_,module){module.exports=_dereq_(15)},{\"./support/isBuffer\":19,\"/usr/local/lib/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js\":18,inherits:17}]},{},[9])(9)}),ace.define(\"ace/mode/html_worker\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/lib/lang\",\"ace/worker/mirror\",\"ace/mode/html/saxparser\"],function(acequire,exports){\"use strict\";var oop=acequire(\"../lib/oop\");acequire(\"../lib/lang\");var Mirror=acequire(\"../worker/mirror\").Mirror,SAXParser=acequire(\"./html/saxparser\").SAXParser,errorTypes={\"expected-doctype-but-got-start-tag\":\"info\",\"expected-doctype-but-got-chars\":\"info\",\"non-html-root\":\"info\"},Worker=exports.Worker=function(sender){Mirror.call(this,sender),this.setTimeout(400),this.context=null};oop.inherits(Worker,Mirror),function(){this.setOptions=function(options){this.context=options.context},this.onUpdate=function(){var value=this.doc.getValue();if(value){var parser=new SAXParser,errors=[],noop=function(){};parser.contentHandler={startDocument:noop,endDocument:noop,startElement:noop,endElement:noop,characters:noop},parser.errorHandler={error:function(message,location,code){errors.push({row:location.line,column:location.column,text:message,type:errorTypes[code]||\"error\"})}},this.context?parser.parseFragment(value,this.context):parser.parse(value),this.sender.emit(\"error\",errors)}}}.call(Worker.prototype)}),ace.define(\"ace/lib/es5-shim\",[\"require\",\"exports\",\"module\"],function(){function Empty(){}function doesDefinePropertyWork(object){try{return Object.defineProperty(object,\"sentinel\",{}),\"sentinel\"in object}catch(exception){}}function toInteger(n){return n=+n,n!==n?n=0:0!==n&&n!==1/0&&n!==-(1/0)&&(n=(n>0||-1)*Math.floor(Math.abs(n))),n}Function.prototype.bind||(Function.prototype.bind=function(that){var target=this;if(\"function\"!=typeof target)throw new TypeError(\"Function.prototype.bind called on incompatible \"+target);var args=slice.call(arguments,1),bound=function(){if(this instanceof bound){var result=target.apply(this,args.concat(slice.call(arguments)));return Object(result)===result?result:this}return target.apply(that,args.concat(slice.call(arguments)))};return target.prototype&&(Empty.prototype=target.prototype,bound.prototype=new Empty,Empty.prototype=null),bound});var defineGetter,defineSetter,lookupGetter,lookupSetter,supportsAccessors,call=Function.prototype.call,prototypeOfArray=Array.prototype,prototypeOfObject=Object.prototype,slice=prototypeOfArray.slice,_toString=call.bind(prototypeOfObject.toString),owns=call.bind(prototypeOfObject.hasOwnProperty);if((supportsAccessors=owns(prototypeOfObject,\"__defineGetter__\"))&&(defineGetter=call.bind(prototypeOfObject.__defineGetter__),defineSetter=call.bind(prototypeOfObject.__defineSetter__),lookupGetter=call.bind(prototypeOfObject.__lookupGetter__),lookupSetter=call.bind(prototypeOfObject.__lookupSetter__)),2!=[1,2].splice(0).length)if(function(){function makeArray(l){var a=Array(l+2);return a[0]=a[1]=0,a}var lengthBefore,array=[];return array.splice.apply(array,makeArray(20)),array.splice.apply(array,makeArray(26)),lengthBefore=array.length,array.splice(5,0,\"XXX\"),lengthBefore+1==array.length,lengthBefore+1==array.length?!0:void 0}()){var array_splice=Array.prototype.splice;Array.prototype.splice=function(start,deleteCount){return arguments.length?array_splice.apply(this,[void 0===start?0:start,void 0===deleteCount?this.length-start:deleteCount].concat(slice.call(arguments,2))):[]}}else Array.prototype.splice=function(pos,removeCount){var length=this.length;pos>0?pos>length&&(pos=length):void 0==pos?pos=0:0>pos&&(pos=Math.max(length+pos,0)),length>pos+removeCount||(removeCount=length-pos);var removed=this.slice(pos,pos+removeCount),insert=slice.call(arguments,2),add=insert.length;if(pos===length)add&&this.push.apply(this,insert);else{var remove=Math.min(removeCount,length-pos),tailOldPos=pos+remove,tailNewPos=tailOldPos+add-remove,tailCount=length-tailOldPos,lengthAfterRemove=length-remove;if(tailOldPos>tailNewPos)for(var i=0;tailCount>i;++i)this[tailNewPos+i]=this[tailOldPos+i];else if(tailNewPos>tailOldPos)for(i=tailCount;i--;)this[tailNewPos+i]=this[tailOldPos+i];if(add&&pos===lengthAfterRemove)this.length=lengthAfterRemove,this.push.apply(this,insert);else for(this.length=lengthAfterRemove+add,i=0;add>i;++i)this[pos+i]=insert[i]}return removed};Array.isArray||(Array.isArray=function(obj){return\"[object Array]\"==_toString(obj)});var boxedString=Object(\"a\"),splitString=\"a\"!=boxedString[0]||!(0 in boxedString);if(Array.prototype.forEach||(Array.prototype.forEach=function(fun){var object=toObject(this),self=splitString&&\"[object String]\"==_toString(this)?this.split(\"\"):object,thisp=arguments[1],i=-1,length=self.length>>>0;if(\"[object Function]\"!=_toString(fun))throw new TypeError;for(;length>++i;)i in self&&fun.call(thisp,self[i],i,object)}),Array.prototype.map||(Array.prototype.map=function(fun){var object=toObject(this),self=splitString&&\"[object String]\"==_toString(this)?this.split(\"\"):object,length=self.length>>>0,result=Array(length),thisp=arguments[1];if(\"[object Function]\"!=_toString(fun))throw new TypeError(fun+\" is not a function\");for(var i=0;length>i;i++)i in self&&(result[i]=fun.call(thisp,self[i],i,object));return result}),Array.prototype.filter||(Array.prototype.filter=function(fun){var value,object=toObject(this),self=splitString&&\"[object String]\"==_toString(this)?this.split(\"\"):object,length=self.length>>>0,result=[],thisp=arguments[1];if(\"[object Function]\"!=_toString(fun))throw new TypeError(fun+\" is not a function\");for(var i=0;length>i;i++)i in self&&(value=self[i],fun.call(thisp,value,i,object)&&result.push(value));return result}),Array.prototype.every||(Array.prototype.every=function(fun){var object=toObject(this),self=splitString&&\"[object String]\"==_toString(this)?this.split(\"\"):object,length=self.length>>>0,thisp=arguments[1];if(\"[object Function]\"!=_toString(fun))throw new TypeError(fun+\" is not a function\");for(var i=0;length>i;i++)if(i in self&&!fun.call(thisp,self[i],i,object))return!1;return!0}),Array.prototype.some||(Array.prototype.some=function(fun){var object=toObject(this),self=splitString&&\"[object String]\"==_toString(this)?this.split(\"\"):object,length=self.length>>>0,thisp=arguments[1];if(\"[object Function]\"!=_toString(fun))throw new TypeError(fun+\" is not a function\");for(var i=0;length>i;i++)if(i in self&&fun.call(thisp,self[i],i,object))return!0;return!1}),Array.prototype.reduce||(Array.prototype.reduce=function(fun){var object=toObject(this),self=splitString&&\"[object String]\"==_toString(this)?this.split(\"\"):object,length=self.length>>>0;if(\"[object Function]\"!=_toString(fun))throw new TypeError(fun+\" is not a function\");if(!length&&1==arguments.length)throw new TypeError(\"reduce of empty array with no initial value\");var result,i=0;if(arguments.length>=2)result=arguments[1];else for(;;){if(i in self){result=self[i++];break}if(++i>=length)throw new TypeError(\"reduce of empty array with no initial value\")}for(;length>i;i++)i in self&&(result=fun.call(void 0,result,self[i],i,object));return result}),Array.prototype.reduceRight||(Array.prototype.reduceRight=function(fun){var object=toObject(this),self=splitString&&\"[object String]\"==_toString(this)?this.split(\"\"):object,length=self.length>>>0;if(\"[object Function]\"!=_toString(fun))throw new TypeError(fun+\" is not a function\");if(!length&&1==arguments.length)throw new TypeError(\"reduceRight of empty array with no initial value\");var result,i=length-1;if(arguments.length>=2)result=arguments[1];else for(;;){if(i in self){result=self[i--];break}if(0>--i)throw new TypeError(\"reduceRight of empty array with no initial value\")}do i in this&&(result=fun.call(void 0,result,self[i],i,object));while(i--);return result}),Array.prototype.indexOf&&-1==[0,1].indexOf(1,2)||(Array.prototype.indexOf=function(sought){var self=splitString&&\"[object String]\"==_toString(this)?this.split(\"\"):toObject(this),length=self.length>>>0;if(!length)return-1;var i=0;for(arguments.length>1&&(i=toInteger(arguments[1])),i=i>=0?i:Math.max(0,length+i);length>i;i++)if(i in self&&self[i]===sought)return i;return-1}),Array.prototype.lastIndexOf&&-1==[0,1].lastIndexOf(0,-3)||(Array.prototype.lastIndexOf=function(sought){var self=splitString&&\"[object String]\"==_toString(this)?this.split(\"\"):toObject(this),length=self.length>>>0;if(!length)return-1;var i=length-1;for(arguments.length>1&&(i=Math.min(i,toInteger(arguments[1]))),i=i>=0?i:length-Math.abs(i);i>=0;i--)if(i in self&&sought===self[i])return i;return-1}),Object.getPrototypeOf||(Object.getPrototypeOf=function(object){return object.__proto__||(object.constructor?object.constructor.prototype:prototypeOfObject)}),!Object.getOwnPropertyDescriptor){var ERR_NON_OBJECT=\"Object.getOwnPropertyDescriptor called on a non-object: \";Object.getOwnPropertyDescriptor=function(object,property){if(\"object\"!=typeof object&&\"function\"!=typeof object||null===object)throw new TypeError(ERR_NON_OBJECT+object);if(owns(object,property)){var descriptor,getter,setter;if(descriptor={enumerable:!0,configurable:!0},supportsAccessors){var prototype=object.__proto__;object.__proto__=prototypeOfObject;var getter=lookupGetter(object,property),setter=lookupSetter(object,property);if(object.__proto__=prototype,getter||setter)return getter&&(descriptor.get=getter),setter&&(descriptor.set=setter),descriptor}return descriptor.value=object[property],descriptor}}}if(Object.getOwnPropertyNames||(Object.getOwnPropertyNames=function(object){return Object.keys(object)}),!Object.create){var createEmpty;createEmpty=null===Object.prototype.__proto__?function(){return{__proto__:null}}:function(){var empty={};for(var i in empty)empty[i]=null;return empty.constructor=empty.hasOwnProperty=empty.propertyIsEnumerable=empty.isPrototypeOf=empty.toLocaleString=empty.toString=empty.valueOf=empty.__proto__=null,empty},Object.create=function(prototype,properties){var object;if(null===prototype)object=createEmpty();else{if(\"object\"!=typeof prototype)throw new TypeError(\"typeof prototype[\"+typeof prototype+\"] != \\'object\\'\");var Type=function(){};Type.prototype=prototype,object=new Type,object.__proto__=prototype}return void 0!==properties&&Object.defineProperties(object,properties),object}}if(Object.defineProperty){var definePropertyWorksOnObject=doesDefinePropertyWork({}),definePropertyWorksOnDom=\"undefined\"==typeof document||doesDefinePropertyWork(document.createElement(\"div\"));if(!definePropertyWorksOnObject||!definePropertyWorksOnDom)var definePropertyFallback=Object.defineProperty}if(!Object.defineProperty||definePropertyFallback){var ERR_NON_OBJECT_DESCRIPTOR=\"Property description must be an object: \",ERR_NON_OBJECT_TARGET=\"Object.defineProperty called on non-object: \",ERR_ACCESSORS_NOT_SUPPORTED=\"getters & setters can not be defined on this javascript engine\";Object.defineProperty=function(object,property,descriptor){if(\"object\"!=typeof object&&\"function\"!=typeof object||null===object)throw new TypeError(ERR_NON_OBJECT_TARGET+object);if(\"object\"!=typeof descriptor&&\"function\"!=typeof descriptor||null===descriptor)throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR+descriptor);if(definePropertyFallback)try{return definePropertyFallback.call(Object,object,property,descriptor)}catch(exception){}if(owns(descriptor,\"value\"))if(supportsAccessors&&(lookupGetter(object,property)||lookupSetter(object,property))){var prototype=object.__proto__;object.__proto__=prototypeOfObject,delete object[property],object[property]=descriptor.value,object.__proto__=prototype}else object[property]=descriptor.value;else{if(!supportsAccessors)throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);owns(descriptor,\"get\")&&defineGetter(object,property,descriptor.get),owns(descriptor,\"set\")&&defineSetter(object,property,descriptor.set)}return object}}Object.defineProperties||(Object.defineProperties=function(object,properties){for(var property in properties)owns(properties,property)&&Object.defineProperty(object,property,properties[property]);return object}),Object.seal||(Object.seal=function(object){return object}),Object.freeze||(Object.freeze=function(object){return object\\n});try{Object.freeze(function(){})}catch(exception){Object.freeze=function(freezeObject){return function(object){return\"function\"==typeof object?object:freezeObject(object)}}(Object.freeze)}if(Object.preventExtensions||(Object.preventExtensions=function(object){return object}),Object.isSealed||(Object.isSealed=function(){return!1}),Object.isFrozen||(Object.isFrozen=function(){return!1}),Object.isExtensible||(Object.isExtensible=function(object){if(Object(object)===object)throw new TypeError;for(var name=\"\";owns(object,name);)name+=\"?\";object[name]=!0;var returnValue=owns(object,name);return delete object[name],returnValue}),!Object.keys){var hasDontEnumBug=!0,dontEnums=[\"toString\",\"toLocaleString\",\"valueOf\",\"hasOwnProperty\",\"isPrototypeOf\",\"propertyIsEnumerable\",\"constructor\"],dontEnumsLength=dontEnums.length;for(var key in{toString:null})hasDontEnumBug=!1;Object.keys=function(object){if(\"object\"!=typeof object&&\"function\"!=typeof object||null===object)throw new TypeError(\"Object.keys called on a non-object\");var keys=[];for(var name in object)owns(object,name)&&keys.push(name);if(hasDontEnumBug)for(var i=0,ii=dontEnumsLength;ii>i;i++){var dontEnum=dontEnums[i];owns(object,dontEnum)&&keys.push(dontEnum)}return keys}}Date.now||(Date.now=function(){return(new Date).getTime()});var ws=\"\\t\\\\n\\v\\\\f\\\\r   ᠎             　\\\\u2028\\\\u2029\\ufeff\";if(!String.prototype.trim||ws.trim()){ws=\"[\"+ws+\"]\";var trimBeginRegexp=RegExp(\"^\"+ws+ws+\"*\"),trimEndRegexp=RegExp(ws+ws+\"*$\");String.prototype.trim=function(){return(this+\"\").replace(trimBeginRegexp,\"\").replace(trimEndRegexp,\"\")}}var toObject=function(o){if(null==o)throw new TypeError(\"can\\'t convert \"+o+\" to object\");return Object(o)}});'},e070:function(e,t){e.exports.id=\"ace/mode/css_worker\",e.exports.src='\"no use strict\";!function(window){function resolveModuleId(id,paths){for(var testPath=id,tail=\"\";testPath;){var alias=paths[testPath];if(\"string\"==typeof alias)return alias+tail;if(alias)return alias.location.replace(/\\\\/*$/,\"/\")+(tail||alias.main||alias.name);if(alias===!1)return\"\";var i=testPath.lastIndexOf(\"/\");if(-1===i)break;tail=testPath.substr(i)+tail,testPath=testPath.slice(0,i)}return id}if(!(void 0!==window.window&&window.document||window.acequire&&window.define)){window.console||(window.console=function(){var msgs=Array.prototype.slice.call(arguments,0);postMessage({type:\"log\",data:msgs})},window.console.error=window.console.warn=window.console.log=window.console.trace=window.console),window.window=window,window.ace=window,window.onerror=function(message,file,line,col,err){postMessage({type:\"error\",data:{message:message,data:err.data,file:file,line:line,col:col,stack:err.stack}})},window.normalizeModule=function(parentId,moduleName){if(-1!==moduleName.indexOf(\"!\")){var chunks=moduleName.split(\"!\");return window.normalizeModule(parentId,chunks[0])+\"!\"+window.normalizeModule(parentId,chunks[1])}if(\".\"==moduleName.charAt(0)){var base=parentId.split(\"/\").slice(0,-1).join(\"/\");for(moduleName=(base?base+\"/\":\"\")+moduleName;-1!==moduleName.indexOf(\".\")&&previous!=moduleName;){var previous=moduleName;moduleName=moduleName.replace(/^\\\\.\\\\//,\"\").replace(/\\\\/\\\\.\\\\//,\"/\").replace(/[^\\\\/]+\\\\/\\\\.\\\\.\\\\//,\"\")}}return moduleName},window.acequire=function acequire(parentId,id){if(id||(id=parentId,parentId=null),!id.charAt)throw Error(\"worker.js acequire() accepts only (parentId, id) as arguments\");id=window.normalizeModule(parentId,id);var module=window.acequire.modules[id];if(module)return module.initialized||(module.initialized=!0,module.exports=module.factory().exports),module.exports;if(!window.acequire.tlns)return console.log(\"unable to load \"+id);var path=resolveModuleId(id,window.acequire.tlns);return\".js\"!=path.slice(-3)&&(path+=\".js\"),window.acequire.id=id,window.acequire.modules[id]={},importScripts(path),window.acequire(parentId,id)},window.acequire.modules={},window.acequire.tlns={},window.define=function(id,deps,factory){if(2==arguments.length?(factory=deps,\"string\"!=typeof id&&(deps=id,id=window.acequire.id)):1==arguments.length&&(factory=id,deps=[],id=window.acequire.id),\"function\"!=typeof factory)return window.acequire.modules[id]={exports:factory,initialized:!0},void 0;deps.length||(deps=[\"require\",\"exports\",\"module\"]);var req=function(childId){return window.acequire(id,childId)};window.acequire.modules[id]={exports:{},factory:function(){var module=this,returnExports=factory.apply(this,deps.map(function(dep){switch(dep){case\"require\":return req;case\"exports\":return module.exports;case\"module\":return module;default:return req(dep)}}));return returnExports&&(module.exports=returnExports),module}}},window.define.amd={},acequire.tlns={},window.initBaseUrls=function(topLevelNamespaces){for(var i in topLevelNamespaces)acequire.tlns[i]=topLevelNamespaces[i]},window.initSender=function(){var EventEmitter=window.acequire(\"ace/lib/event_emitter\").EventEmitter,oop=window.acequire(\"ace/lib/oop\"),Sender=function(){};return function(){oop.implement(this,EventEmitter),this.callback=function(data,callbackId){postMessage({type:\"call\",id:callbackId,data:data})},this.emit=function(name,data){postMessage({type:\"event\",name:name,data:data})}}.call(Sender.prototype),new Sender};var main=window.main=null,sender=window.sender=null;window.onmessage=function(e){var msg=e.data;if(msg.event&&sender)sender._signal(msg.event,msg.data);else if(msg.command)if(main[msg.command])main[msg.command].apply(main,msg.args);else{if(!window[msg.command])throw Error(\"Unknown command:\"+msg.command);window[msg.command].apply(window,msg.args)}else if(msg.init){window.initBaseUrls(msg.tlns),acequire(\"ace/lib/es5-shim\"),sender=window.sender=window.initSender();var clazz=acequire(msg.module)[msg.classname];main=window.main=new clazz(sender)}}}}(this),ace.define(\"ace/lib/oop\",[\"require\",\"exports\",\"module\"],function(acequire,exports){\"use strict\";exports.inherits=function(ctor,superCtor){ctor.super_=superCtor,ctor.prototype=Object.create(superCtor.prototype,{constructor:{value:ctor,enumerable:!1,writable:!0,configurable:!0}})},exports.mixin=function(obj,mixin){for(var key in mixin)obj[key]=mixin[key];return obj},exports.implement=function(proto,mixin){exports.mixin(proto,mixin)}}),ace.define(\"ace/lib/lang\",[\"require\",\"exports\",\"module\"],function(acequire,exports){\"use strict\";exports.last=function(a){return a[a.length-1]},exports.stringReverse=function(string){return string.split(\"\").reverse().join(\"\")},exports.stringRepeat=function(string,count){for(var result=\"\";count>0;)1&count&&(result+=string),(count>>=1)&&(string+=string);return result};var trimBeginRegexp=/^\\\\s\\\\s*/,trimEndRegexp=/\\\\s\\\\s*$/;exports.stringTrimLeft=function(string){return string.replace(trimBeginRegexp,\"\")},exports.stringTrimRight=function(string){return string.replace(trimEndRegexp,\"\")},exports.copyObject=function(obj){var copy={};for(var key in obj)copy[key]=obj[key];return copy},exports.copyArray=function(array){for(var copy=[],i=0,l=array.length;l>i;i++)copy[i]=array[i]&&\"object\"==typeof array[i]?this.copyObject(array[i]):array[i];return copy},exports.deepCopy=function deepCopy(obj){if(\"object\"!=typeof obj||!obj)return obj;var copy;if(Array.isArray(obj)){copy=[];for(var key=0;obj.length>key;key++)copy[key]=deepCopy(obj[key]);return copy}if(\"[object Object]\"!==Object.prototype.toString.call(obj))return obj;copy={};for(var key in obj)copy[key]=deepCopy(obj[key]);return copy},exports.arrayToMap=function(arr){for(var map={},i=0;arr.length>i;i++)map[arr[i]]=1;return map},exports.createMap=function(props){var map=Object.create(null);for(var i in props)map[i]=props[i];return map},exports.arrayRemove=function(array,value){for(var i=0;array.length>=i;i++)value===array[i]&&array.splice(i,1)},exports.escapeRegExp=function(str){return str.replace(/([.*+?^${}()|[\\\\]\\\\/\\\\\\\\])/g,\"\\\\\\\\$1\")},exports.escapeHTML=function(str){return str.replace(/&/g,\"&#38;\").replace(/\"/g,\"&#34;\").replace(/\\'/g,\"&#39;\").replace(/</g,\"&#60;\")},exports.getMatchOffsets=function(string,regExp){var matches=[];return string.replace(regExp,function(str){matches.push({offset:arguments[arguments.length-2],length:str.length})}),matches},exports.deferredCall=function(fcn){var timer=null,callback=function(){timer=null,fcn()},deferred=function(timeout){return deferred.cancel(),timer=setTimeout(callback,timeout||0),deferred};return deferred.schedule=deferred,deferred.call=function(){return this.cancel(),fcn(),deferred},deferred.cancel=function(){return clearTimeout(timer),timer=null,deferred},deferred.isPending=function(){return timer},deferred},exports.delayedCall=function(fcn,defaultTimeout){var timer=null,callback=function(){timer=null,fcn()},_self=function(timeout){null==timer&&(timer=setTimeout(callback,timeout||defaultTimeout))};return _self.delay=function(timeout){timer&&clearTimeout(timer),timer=setTimeout(callback,timeout||defaultTimeout)},_self.schedule=_self,_self.call=function(){this.cancel(),fcn()},_self.cancel=function(){timer&&clearTimeout(timer),timer=null},_self.isPending=function(){return timer},_self}}),ace.define(\"ace/range\",[\"require\",\"exports\",\"module\"],function(acequire,exports){\"use strict\";var comparePoints=function(p1,p2){return p1.row-p2.row||p1.column-p2.column},Range=function(startRow,startColumn,endRow,endColumn){this.start={row:startRow,column:startColumn},this.end={row:endRow,column:endColumn}};(function(){this.isEqual=function(range){return this.start.row===range.start.row&&this.end.row===range.end.row&&this.start.column===range.start.column&&this.end.column===range.end.column},this.toString=function(){return\"Range: [\"+this.start.row+\"/\"+this.start.column+\"] -> [\"+this.end.row+\"/\"+this.end.column+\"]\"},this.contains=function(row,column){return 0==this.compare(row,column)},this.compareRange=function(range){var cmp,end=range.end,start=range.start;return cmp=this.compare(end.row,end.column),1==cmp?(cmp=this.compare(start.row,start.column),1==cmp?2:0==cmp?1:0):-1==cmp?-2:(cmp=this.compare(start.row,start.column),-1==cmp?-1:1==cmp?42:0)},this.comparePoint=function(p){return this.compare(p.row,p.column)},this.containsRange=function(range){return 0==this.comparePoint(range.start)&&0==this.comparePoint(range.end)},this.intersects=function(range){var cmp=this.compareRange(range);return-1==cmp||0==cmp||1==cmp},this.isEnd=function(row,column){return this.end.row==row&&this.end.column==column},this.isStart=function(row,column){return this.start.row==row&&this.start.column==column},this.setStart=function(row,column){\"object\"==typeof row?(this.start.column=row.column,this.start.row=row.row):(this.start.row=row,this.start.column=column)},this.setEnd=function(row,column){\"object\"==typeof row?(this.end.column=row.column,this.end.row=row.row):(this.end.row=row,this.end.column=column)},this.inside=function(row,column){return 0==this.compare(row,column)?this.isEnd(row,column)||this.isStart(row,column)?!1:!0:!1},this.insideStart=function(row,column){return 0==this.compare(row,column)?this.isEnd(row,column)?!1:!0:!1},this.insideEnd=function(row,column){return 0==this.compare(row,column)?this.isStart(row,column)?!1:!0:!1},this.compare=function(row,column){return this.isMultiLine()||row!==this.start.row?this.start.row>row?-1:row>this.end.row?1:this.start.row===row?column>=this.start.column?0:-1:this.end.row===row?this.end.column>=column?0:1:0:this.start.column>column?-1:column>this.end.column?1:0},this.compareStart=function(row,column){return this.start.row==row&&this.start.column==column?-1:this.compare(row,column)},this.compareEnd=function(row,column){return this.end.row==row&&this.end.column==column?1:this.compare(row,column)},this.compareInside=function(row,column){return this.end.row==row&&this.end.column==column?1:this.start.row==row&&this.start.column==column?-1:this.compare(row,column)},this.clipRows=function(firstRow,lastRow){if(this.end.row>lastRow)var end={row:lastRow+1,column:0};else if(firstRow>this.end.row)var end={row:firstRow,column:0};if(this.start.row>lastRow)var start={row:lastRow+1,column:0};else if(firstRow>this.start.row)var start={row:firstRow,column:0};return Range.fromPoints(start||this.start,end||this.end)},this.extend=function(row,column){var cmp=this.compare(row,column);if(0==cmp)return this;if(-1==cmp)var start={row:row,column:column};else var end={row:row,column:column};return Range.fromPoints(start||this.start,end||this.end)},this.isEmpty=function(){return this.start.row===this.end.row&&this.start.column===this.end.column},this.isMultiLine=function(){return this.start.row!==this.end.row},this.clone=function(){return Range.fromPoints(this.start,this.end)},this.collapseRows=function(){return 0==this.end.column?new Range(this.start.row,0,Math.max(this.start.row,this.end.row-1),0):new Range(this.start.row,0,this.end.row,0)},this.toScreenRange=function(session){var screenPosStart=session.documentToScreenPosition(this.start),screenPosEnd=session.documentToScreenPosition(this.end);return new Range(screenPosStart.row,screenPosStart.column,screenPosEnd.row,screenPosEnd.column)},this.moveBy=function(row,column){this.start.row+=row,this.start.column+=column,this.end.row+=row,this.end.column+=column}}).call(Range.prototype),Range.fromPoints=function(start,end){return new Range(start.row,start.column,end.row,end.column)},Range.comparePoints=comparePoints,Range.comparePoints=function(p1,p2){return p1.row-p2.row||p1.column-p2.column},exports.Range=Range}),ace.define(\"ace/apply_delta\",[\"require\",\"exports\",\"module\"],function(acequire,exports){\"use strict\";exports.applyDelta=function(docLines,delta){var row=delta.start.row,startColumn=delta.start.column,line=docLines[row]||\"\";switch(delta.action){case\"insert\":var lines=delta.lines;if(1===lines.length)docLines[row]=line.substring(0,startColumn)+delta.lines[0]+line.substring(startColumn);else{var args=[row,1].concat(delta.lines);docLines.splice.apply(docLines,args),docLines[row]=line.substring(0,startColumn)+docLines[row],docLines[row+delta.lines.length-1]+=line.substring(startColumn)}break;case\"remove\":var endColumn=delta.end.column,endRow=delta.end.row;row===endRow?docLines[row]=line.substring(0,startColumn)+line.substring(endColumn):docLines.splice(row,endRow-row+1,line.substring(0,startColumn)+docLines[endRow].substring(endColumn))}}}),ace.define(\"ace/lib/event_emitter\",[\"require\",\"exports\",\"module\"],function(acequire,exports){\"use strict\";var EventEmitter={},stopPropagation=function(){this.propagationStopped=!0},preventDefault=function(){this.defaultPrevented=!0};EventEmitter._emit=EventEmitter._dispatchEvent=function(eventName,e){this._eventRegistry||(this._eventRegistry={}),this._defaultHandlers||(this._defaultHandlers={});var listeners=this._eventRegistry[eventName]||[],defaultHandler=this._defaultHandlers[eventName];if(listeners.length||defaultHandler){\"object\"==typeof e&&e||(e={}),e.type||(e.type=eventName),e.stopPropagation||(e.stopPropagation=stopPropagation),e.preventDefault||(e.preventDefault=preventDefault),listeners=listeners.slice();for(var i=0;listeners.length>i&&(listeners[i](e,this),!e.propagationStopped);i++);return defaultHandler&&!e.defaultPrevented?defaultHandler(e,this):void 0}},EventEmitter._signal=function(eventName,e){var listeners=(this._eventRegistry||{})[eventName];if(listeners){listeners=listeners.slice();for(var i=0;listeners.length>i;i++)listeners[i](e,this)}},EventEmitter.once=function(eventName,callback){var _self=this;callback&&this.addEventListener(eventName,function newCallback(){_self.removeEventListener(eventName,newCallback),callback.apply(null,arguments)})},EventEmitter.setDefaultHandler=function(eventName,callback){var handlers=this._defaultHandlers;if(handlers||(handlers=this._defaultHandlers={_disabled_:{}}),handlers[eventName]){var old=handlers[eventName],disabled=handlers._disabled_[eventName];disabled||(handlers._disabled_[eventName]=disabled=[]),disabled.push(old);var i=disabled.indexOf(callback);-1!=i&&disabled.splice(i,1)}handlers[eventName]=callback},EventEmitter.removeDefaultHandler=function(eventName,callback){var handlers=this._defaultHandlers;if(handlers){var disabled=handlers._disabled_[eventName];if(handlers[eventName]==callback)handlers[eventName],disabled&&this.setDefaultHandler(eventName,disabled.pop());else if(disabled){var i=disabled.indexOf(callback);-1!=i&&disabled.splice(i,1)}}},EventEmitter.on=EventEmitter.addEventListener=function(eventName,callback,capturing){this._eventRegistry=this._eventRegistry||{};var listeners=this._eventRegistry[eventName];return listeners||(listeners=this._eventRegistry[eventName]=[]),-1==listeners.indexOf(callback)&&listeners[capturing?\"unshift\":\"push\"](callback),callback},EventEmitter.off=EventEmitter.removeListener=EventEmitter.removeEventListener=function(eventName,callback){this._eventRegistry=this._eventRegistry||{};var listeners=this._eventRegistry[eventName];if(listeners){var index=listeners.indexOf(callback);-1!==index&&listeners.splice(index,1)}},EventEmitter.removeAllListeners=function(eventName){this._eventRegistry&&(this._eventRegistry[eventName]=[])},exports.EventEmitter=EventEmitter}),ace.define(\"ace/anchor\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/lib/event_emitter\"],function(acequire,exports){\"use strict\";var oop=acequire(\"./lib/oop\"),EventEmitter=acequire(\"./lib/event_emitter\").EventEmitter,Anchor=exports.Anchor=function(doc,row,column){this.$onChange=this.onChange.bind(this),this.attach(doc),column===void 0?this.setPosition(row.row,row.column):this.setPosition(row,column)};(function(){function $pointsInOrder(point1,point2,equalPointsInOrder){var bColIsAfter=equalPointsInOrder?point1.column<=point2.column:point1.column<point2.column;return point1.row<point2.row||point1.row==point2.row&&bColIsAfter}function $getTransformedPoint(delta,point,moveIfEqual){var deltaIsInsert=\"insert\"==delta.action,deltaRowShift=(deltaIsInsert?1:-1)*(delta.end.row-delta.start.row),deltaColShift=(deltaIsInsert?1:-1)*(delta.end.column-delta.start.column),deltaStart=delta.start,deltaEnd=deltaIsInsert?deltaStart:delta.end;return $pointsInOrder(point,deltaStart,moveIfEqual)?{row:point.row,column:point.column}:$pointsInOrder(deltaEnd,point,!moveIfEqual)?{row:point.row+deltaRowShift,column:point.column+(point.row==deltaEnd.row?deltaColShift:0)}:{row:deltaStart.row,column:deltaStart.column}}oop.implement(this,EventEmitter),this.getPosition=function(){return this.$clipPositionToDocument(this.row,this.column)},this.getDocument=function(){return this.document},this.$insertRight=!1,this.onChange=function(delta){if(!(delta.start.row==delta.end.row&&delta.start.row!=this.row||delta.start.row>this.row)){var point=$getTransformedPoint(delta,{row:this.row,column:this.column},this.$insertRight);this.setPosition(point.row,point.column,!0)}},this.setPosition=function(row,column,noClip){var pos;if(pos=noClip?{row:row,column:column}:this.$clipPositionToDocument(row,column),this.row!=pos.row||this.column!=pos.column){var old={row:this.row,column:this.column};this.row=pos.row,this.column=pos.column,this._signal(\"change\",{old:old,value:pos})}},this.detach=function(){this.document.removeEventListener(\"change\",this.$onChange)},this.attach=function(doc){this.document=doc||this.document,this.document.on(\"change\",this.$onChange)},this.$clipPositionToDocument=function(row,column){var pos={};return row>=this.document.getLength()?(pos.row=Math.max(0,this.document.getLength()-1),pos.column=this.document.getLine(pos.row).length):0>row?(pos.row=0,pos.column=0):(pos.row=row,pos.column=Math.min(this.document.getLine(pos.row).length,Math.max(0,column))),0>column&&(pos.column=0),pos}}).call(Anchor.prototype)}),ace.define(\"ace/document\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/apply_delta\",\"ace/lib/event_emitter\",\"ace/range\",\"ace/anchor\"],function(acequire,exports){\"use strict\";var oop=acequire(\"./lib/oop\"),applyDelta=acequire(\"./apply_delta\").applyDelta,EventEmitter=acequire(\"./lib/event_emitter\").EventEmitter,Range=acequire(\"./range\").Range,Anchor=acequire(\"./anchor\").Anchor,Document=function(textOrLines){this.$lines=[\"\"],0===textOrLines.length?this.$lines=[\"\"]:Array.isArray(textOrLines)?this.insertMergedLines({row:0,column:0},textOrLines):this.insert({row:0,column:0},textOrLines)};(function(){oop.implement(this,EventEmitter),this.setValue=function(text){var len=this.getLength()-1;this.remove(new Range(0,0,len,this.getLine(len).length)),this.insert({row:0,column:0},text)},this.getValue=function(){return this.getAllLines().join(this.getNewLineCharacter())},this.createAnchor=function(row,column){return new Anchor(this,row,column)},this.$split=0===\"aaa\".split(/a/).length?function(text){return text.replace(/\\\\r\\\\n|\\\\r/g,\"\\\\n\").split(\"\\\\n\")}:function(text){return text.split(/\\\\r\\\\n|\\\\r|\\\\n/)},this.$detectNewLine=function(text){var match=text.match(/^.*?(\\\\r\\\\n|\\\\r|\\\\n)/m);this.$autoNewLine=match?match[1]:\"\\\\n\",this._signal(\"changeNewLineMode\")},this.getNewLineCharacter=function(){switch(this.$newLineMode){case\"windows\":return\"\\\\r\\\\n\";case\"unix\":return\"\\\\n\";default:return this.$autoNewLine||\"\\\\n\"}},this.$autoNewLine=\"\",this.$newLineMode=\"auto\",this.setNewLineMode=function(newLineMode){this.$newLineMode!==newLineMode&&(this.$newLineMode=newLineMode,this._signal(\"changeNewLineMode\"))},this.getNewLineMode=function(){return this.$newLineMode},this.isNewLine=function(text){return\"\\\\r\\\\n\"==text||\"\\\\r\"==text||\"\\\\n\"==text},this.getLine=function(row){return this.$lines[row]||\"\"},this.getLines=function(firstRow,lastRow){return this.$lines.slice(firstRow,lastRow+1)},this.getAllLines=function(){return this.getLines(0,this.getLength())},this.getLength=function(){return this.$lines.length},this.getTextRange=function(range){return this.getLinesForRange(range).join(this.getNewLineCharacter())},this.getLinesForRange=function(range){var lines;if(range.start.row===range.end.row)lines=[this.getLine(range.start.row).substring(range.start.column,range.end.column)];else{lines=this.getLines(range.start.row,range.end.row),lines[0]=(lines[0]||\"\").substring(range.start.column);var l=lines.length-1;range.end.row-range.start.row==l&&(lines[l]=lines[l].substring(0,range.end.column))}return lines},this.insertLines=function(row,lines){return console.warn(\"Use of document.insertLines is deprecated. Use the insertFullLines method instead.\"),this.insertFullLines(row,lines)},this.removeLines=function(firstRow,lastRow){return console.warn(\"Use of document.removeLines is deprecated. Use the removeFullLines method instead.\"),this.removeFullLines(firstRow,lastRow)},this.insertNewLine=function(position){return console.warn(\"Use of document.insertNewLine is deprecated. Use insertMergedLines(position, [\\'\\', \\'\\']) instead.\"),this.insertMergedLines(position,[\"\",\"\"])},this.insert=function(position,text){return 1>=this.getLength()&&this.$detectNewLine(text),this.insertMergedLines(position,this.$split(text))},this.insertInLine=function(position,text){var start=this.clippedPos(position.row,position.column),end=this.pos(position.row,position.column+text.length);return this.applyDelta({start:start,end:end,action:\"insert\",lines:[text]},!0),this.clonePos(end)},this.clippedPos=function(row,column){var length=this.getLength();void 0===row?row=length:0>row?row=0:row>=length&&(row=length-1,column=void 0);var line=this.getLine(row);return void 0==column&&(column=line.length),column=Math.min(Math.max(column,0),line.length),{row:row,column:column}},this.clonePos=function(pos){return{row:pos.row,column:pos.column}},this.pos=function(row,column){return{row:row,column:column}},this.$clipPosition=function(position){var length=this.getLength();return position.row>=length?(position.row=Math.max(0,length-1),position.column=this.getLine(length-1).length):(position.row=Math.max(0,position.row),position.column=Math.min(Math.max(position.column,0),this.getLine(position.row).length)),position},this.insertFullLines=function(row,lines){row=Math.min(Math.max(row,0),this.getLength());var column=0;this.getLength()>row?(lines=lines.concat([\"\"]),column=0):(lines=[\"\"].concat(lines),row--,column=this.$lines[row].length),this.insertMergedLines({row:row,column:column},lines)},this.insertMergedLines=function(position,lines){var start=this.clippedPos(position.row,position.column),end={row:start.row+lines.length-1,column:(1==lines.length?start.column:0)+lines[lines.length-1].length};return this.applyDelta({start:start,end:end,action:\"insert\",lines:lines}),this.clonePos(end)},this.remove=function(range){var start=this.clippedPos(range.start.row,range.start.column),end=this.clippedPos(range.end.row,range.end.column);return this.applyDelta({start:start,end:end,action:\"remove\",lines:this.getLinesForRange({start:start,end:end})}),this.clonePos(start)},this.removeInLine=function(row,startColumn,endColumn){var start=this.clippedPos(row,startColumn),end=this.clippedPos(row,endColumn);return this.applyDelta({start:start,end:end,action:\"remove\",lines:this.getLinesForRange({start:start,end:end})},!0),this.clonePos(start)},this.removeFullLines=function(firstRow,lastRow){firstRow=Math.min(Math.max(0,firstRow),this.getLength()-1),lastRow=Math.min(Math.max(0,lastRow),this.getLength()-1);var deleteFirstNewLine=lastRow==this.getLength()-1&&firstRow>0,deleteLastNewLine=this.getLength()-1>lastRow,startRow=deleteFirstNewLine?firstRow-1:firstRow,startCol=deleteFirstNewLine?this.getLine(startRow).length:0,endRow=deleteLastNewLine?lastRow+1:lastRow,endCol=deleteLastNewLine?0:this.getLine(endRow).length,range=new Range(startRow,startCol,endRow,endCol),deletedLines=this.$lines.slice(firstRow,lastRow+1);return this.applyDelta({start:range.start,end:range.end,action:\"remove\",lines:this.getLinesForRange(range)}),deletedLines},this.removeNewLine=function(row){this.getLength()-1>row&&row>=0&&this.applyDelta({start:this.pos(row,this.getLine(row).length),end:this.pos(row+1,0),action:\"remove\",lines:[\"\",\"\"]})},this.replace=function(range,text){if(range instanceof Range||(range=Range.fromPoints(range.start,range.end)),0===text.length&&range.isEmpty())return range.start;if(text==this.getTextRange(range))return range.end;this.remove(range);var end;return end=text?this.insert(range.start,text):range.start},this.applyDeltas=function(deltas){for(var i=0;deltas.length>i;i++)this.applyDelta(deltas[i])},this.revertDeltas=function(deltas){for(var i=deltas.length-1;i>=0;i--)this.revertDelta(deltas[i])},this.applyDelta=function(delta,doNotValidate){var isInsert=\"insert\"==delta.action;(isInsert?1>=delta.lines.length&&!delta.lines[0]:!Range.comparePoints(delta.start,delta.end))||(isInsert&&delta.lines.length>2e4&&this.$splitAndapplyLargeDelta(delta,2e4),applyDelta(this.$lines,delta,doNotValidate),this._signal(\"change\",delta))},this.$splitAndapplyLargeDelta=function(delta,MAX){for(var lines=delta.lines,l=lines.length,row=delta.start.row,column=delta.start.column,from=0,to=0;;){from=to,to+=MAX-1;var chunk=lines.slice(from,to);if(to>l){delta.lines=chunk,delta.start.row=row+from,delta.start.column=column;break}chunk.push(\"\"),this.applyDelta({start:this.pos(row+from,column),end:this.pos(row+to,column=0),action:delta.action,lines:chunk},!0)}},this.revertDelta=function(delta){this.applyDelta({start:this.clonePos(delta.start),end:this.clonePos(delta.end),action:\"insert\"==delta.action?\"remove\":\"insert\",lines:delta.lines.slice()})},this.indexToPosition=function(index,startRow){for(var lines=this.$lines||this.getAllLines(),newlineLength=this.getNewLineCharacter().length,i=startRow||0,l=lines.length;l>i;i++)if(index-=lines[i].length+newlineLength,0>index)return{row:i,column:index+lines[i].length+newlineLength};return{row:l-1,column:lines[l-1].length}},this.positionToIndex=function(pos,startRow){for(var lines=this.$lines||this.getAllLines(),newlineLength=this.getNewLineCharacter().length,index=0,row=Math.min(pos.row,lines.length),i=startRow||0;row>i;++i)index+=lines[i].length+newlineLength;return index+pos.column}}).call(Document.prototype),exports.Document=Document}),ace.define(\"ace/worker/mirror\",[\"require\",\"exports\",\"module\",\"ace/range\",\"ace/document\",\"ace/lib/lang\"],function(acequire,exports){\"use strict\";acequire(\"../range\").Range;var Document=acequire(\"../document\").Document,lang=acequire(\"../lib/lang\"),Mirror=exports.Mirror=function(sender){this.sender=sender;var doc=this.doc=new Document(\"\"),deferredUpdate=this.deferredUpdate=lang.delayedCall(this.onUpdate.bind(this)),_self=this;sender.on(\"change\",function(e){var data=e.data;if(data[0].start)doc.applyDeltas(data);else for(var i=0;data.length>i;i+=2){if(Array.isArray(data[i+1]))var d={action:\"insert\",start:data[i],lines:data[i+1]};else var d={action:\"remove\",start:data[i],end:data[i+1]};doc.applyDelta(d,!0)}return _self.$timeout?deferredUpdate.schedule(_self.$timeout):(_self.onUpdate(),void 0)})};(function(){this.$timeout=500,this.setTimeout=function(timeout){this.$timeout=timeout},this.setValue=function(value){this.doc.setValue(value),this.deferredUpdate.schedule(this.$timeout)},this.getValue=function(callbackId){this.sender.callback(this.doc.getValue(),callbackId)},this.onUpdate=function(){},this.isPending=function(){return this.deferredUpdate.isPending()}}).call(Mirror.prototype)}),ace.define(\"ace/mode/css/csslint\",[\"require\",\"exports\",\"module\"],function(acequire,exports,module){function objectToString(o){return Object.prototype.toString.call(o)}function clone(parent,circular,depth,prototype){function _clone(parent,depth){if(null===parent)return null;if(0==depth)return parent;var child;if(\"object\"!=typeof parent)return parent;if(util.isArray(parent))child=[];else if(util.isRegExp(parent))child=RegExp(parent.source,util.getRegExpFlags(parent)),parent.lastIndex&&(child.lastIndex=parent.lastIndex);else if(util.isDate(parent))child=new Date(parent.getTime());else{if(useBuffer&&Buffer.isBuffer(parent))return child=new Buffer(parent.length),parent.copy(child),child;child=prototype===void 0?Object.create(Object.getPrototypeOf(parent)):Object.create(prototype)}if(circular){var index=allParents.indexOf(parent);if(-1!=index)return allChildren[index];allParents.push(parent),allChildren.push(child)}for(var i in parent)child[i]=_clone(parent[i],depth-1);return child}var allParents=[],allChildren=[],useBuffer=\"undefined\"!=typeof Buffer;return circular===void 0&&(circular=!0),depth===void 0&&(depth=1/0),_clone(parent,depth)}function Reporter(lines,ruleset){this.messages=[],this.stats=[],this.lines=lines,this.ruleset=ruleset}var parserlib={};(function(){function EventTarget(){this._listeners={}}function StringReader(text){this._input=text.replace(/\\\\n\\\\r?/g,\"\\\\n\"),this._line=1,this._col=1,this._cursor=0}function SyntaxError(message,line,col){this.col=col,this.line=line,this.message=message}function SyntaxUnit(text,line,col,type){this.col=col,this.line=line,this.text=text,this.type=type}function TokenStreamBase(input,tokenData){this._reader=input?new StringReader(\"\"+input):null,this._token=null,this._tokenData=tokenData,this._lt=[],this._ltIndex=0,this._ltIndexCache=[]}EventTarget.prototype={constructor:EventTarget,addListener:function(type,listener){this._listeners[type]||(this._listeners[type]=[]),this._listeners[type].push(listener)},fire:function(event){if(\"string\"==typeof event&&(event={type:event}),event.target!==void 0&&(event.target=this),event.type===void 0)throw Error(\"Event object missing \\'type\\' property.\");if(this._listeners[event.type])for(var listeners=this._listeners[event.type].concat(),i=0,len=listeners.length;len>i;i++)listeners[i].call(this,event)},removeListener:function(type,listener){if(this._listeners[type])for(var listeners=this._listeners[type],i=0,len=listeners.length;len>i;i++)if(listeners[i]===listener){listeners.splice(i,1);break}}},StringReader.prototype={constructor:StringReader,getCol:function(){return this._col},getLine:function(){return this._line},eof:function(){return this._cursor==this._input.length},peek:function(count){var c=null;return count=count===void 0?1:count,this._cursor<this._input.length&&(c=this._input.charAt(this._cursor+count-1)),c},read:function(){var c=null;return this._cursor<this._input.length&&(\"\\\\n\"==this._input.charAt(this._cursor)?(this._line++,this._col=1):this._col++,c=this._input.charAt(this._cursor++)),c},mark:function(){this._bookmark={cursor:this._cursor,line:this._line,col:this._col}},reset:function(){this._bookmark&&(this._cursor=this._bookmark.cursor,this._line=this._bookmark.line,this._col=this._bookmark.col,delete this._bookmark)},readTo:function(pattern){for(var c,buffer=\"\";buffer.length<pattern.length||buffer.lastIndexOf(pattern)!=buffer.length-pattern.length;){if(c=this.read(),!c)throw Error(\\'Expected \"\\'+pattern+\\'\" at line \\'+this._line+\", col \"+this._col+\".\");buffer+=c}return buffer},readWhile:function(filter){for(var buffer=\"\",c=this.read();null!==c&&filter(c);)buffer+=c,c=this.read();return buffer},readMatch:function(matcher){var source=this._input.substring(this._cursor),value=null;return\"string\"==typeof matcher?0===source.indexOf(matcher)&&(value=this.readCount(matcher.length)):matcher instanceof RegExp&&matcher.test(source)&&(value=this.readCount(RegExp.lastMatch.length)),value},readCount:function(count){for(var buffer=\"\";count--;)buffer+=this.read();return buffer}},SyntaxError.prototype=Error(),SyntaxUnit.fromToken=function(token){return new SyntaxUnit(token.value,token.startLine,token.startCol)},SyntaxUnit.prototype={constructor:SyntaxUnit,valueOf:function(){return this.text},toString:function(){return this.text}},TokenStreamBase.createTokenData=function(tokens){var nameMap=[],typeMap={},tokenData=tokens.concat([]),i=0,len=tokenData.length+1;for(tokenData.UNKNOWN=-1,tokenData.unshift({name:\"EOF\"});len>i;i++)nameMap.push(tokenData[i].name),tokenData[tokenData[i].name]=i,tokenData[i].text&&(typeMap[tokenData[i].text]=i);return tokenData.name=function(tt){return nameMap[tt]},tokenData.type=function(c){return typeMap[c]},tokenData},TokenStreamBase.prototype={constructor:TokenStreamBase,match:function(tokenTypes,channel){tokenTypes instanceof Array||(tokenTypes=[tokenTypes]);\\nfor(var tt=this.get(channel),i=0,len=tokenTypes.length;len>i;)if(tt==tokenTypes[i++])return!0;return this.unget(),!1},mustMatch:function(tokenTypes){var token;if(tokenTypes instanceof Array||(tokenTypes=[tokenTypes]),!this.match.apply(this,arguments))throw token=this.LT(1),new SyntaxError(\"Expected \"+this._tokenData[tokenTypes[0]].name+\" at line \"+token.startLine+\", col \"+token.startCol+\".\",token.startLine,token.startCol)},advance:function(tokenTypes,channel){for(;0!==this.LA(0)&&!this.match(tokenTypes,channel);)this.get();return this.LA(0)},get:function(channel){var token,info,tokenInfo=this._tokenData,i=(this._reader,0);if(tokenInfo.length,this._lt.length&&this._ltIndex>=0&&this._ltIndex<this._lt.length){for(i++,this._token=this._lt[this._ltIndex++],info=tokenInfo[this._token.type];void 0!==info.channel&&channel!==info.channel&&this._ltIndex<this._lt.length;)this._token=this._lt[this._ltIndex++],info=tokenInfo[this._token.type],i++;if((void 0===info.channel||channel===info.channel)&&this._ltIndex<=this._lt.length)return this._ltIndexCache.push(i),this._token.type}return token=this._getToken(),token.type>-1&&!tokenInfo[token.type].hide&&(token.channel=tokenInfo[token.type].channel,this._token=token,this._lt.push(token),this._ltIndexCache.push(this._lt.length-this._ltIndex+i),this._lt.length>5&&this._lt.shift(),this._ltIndexCache.length>5&&this._ltIndexCache.shift(),this._ltIndex=this._lt.length),info=tokenInfo[token.type],info&&(info.hide||void 0!==info.channel&&channel!==info.channel)?this.get(channel):token.type},LA:function(index){var tt,total=index;if(index>0){if(index>5)throw Error(\"Too much lookahead.\");for(;total;)tt=this.get(),total--;for(;index>total;)this.unget(),total++}else if(0>index){if(!this._lt[this._ltIndex+index])throw Error(\"Too much lookbehind.\");tt=this._lt[this._ltIndex+index].type}else tt=this._token.type;return tt},LT:function(index){return this.LA(index),this._lt[this._ltIndex+index-1]},peek:function(){return this.LA(1)},token:function(){return this._token},tokenName:function(tokenType){return 0>tokenType||tokenType>this._tokenData.length?\"UNKNOWN_TOKEN\":this._tokenData[tokenType].name},tokenType:function(tokenName){return this._tokenData[tokenName]||-1},unget:function(){if(!this._ltIndexCache.length)throw Error(\"Too much lookahead.\");this._ltIndex-=this._ltIndexCache.pop(),this._token=this._lt[this._ltIndex-1]}},parserlib.util={StringReader:StringReader,SyntaxError:SyntaxError,SyntaxUnit:SyntaxUnit,EventTarget:EventTarget,TokenStreamBase:TokenStreamBase}})(),function(){function Combinator(text,line,col){SyntaxUnit.call(this,text,line,col,Parser.COMBINATOR_TYPE),this.type=\"unknown\",/^\\\\s+$/.test(text)?this.type=\"descendant\":\">\"==text?this.type=\"child\":\"+\"==text?this.type=\"adjacent-sibling\":\"~\"==text&&(this.type=\"sibling\")}function MediaFeature(name,value){SyntaxUnit.call(this,\"(\"+name+(null!==value?\":\"+value:\"\")+\")\",name.startLine,name.startCol,Parser.MEDIA_FEATURE_TYPE),this.name=name,this.value=value}function MediaQuery(modifier,mediaType,features,line,col){SyntaxUnit.call(this,(modifier?modifier+\" \":\"\")+(mediaType?mediaType:\"\")+(mediaType&&features.length>0?\" and \":\"\")+features.join(\" and \"),line,col,Parser.MEDIA_QUERY_TYPE),this.modifier=modifier,this.mediaType=mediaType,this.features=features}function Parser(options){EventTarget.call(this),this.options=options||{},this._tokenStream=null}function PropertyName(text,hack,line,col){SyntaxUnit.call(this,text,line,col,Parser.PROPERTY_NAME_TYPE),this.hack=hack}function PropertyValue(parts,line,col){SyntaxUnit.call(this,parts.join(\" \"),line,col,Parser.PROPERTY_VALUE_TYPE),this.parts=parts}function PropertyValueIterator(value){this._i=0,this._parts=value.parts,this._marks=[],this.value=value}function PropertyValuePart(text,line,col){SyntaxUnit.call(this,text,line,col,Parser.PROPERTY_VALUE_PART_TYPE),this.type=\"unknown\";var temp;if(/^([+\\\\-]?[\\\\d\\\\.]+)([a-z]+)$/i.test(text))switch(this.type=\"dimension\",this.value=+RegExp.$1,this.units=RegExp.$2,this.units.toLowerCase()){case\"em\":case\"rem\":case\"ex\":case\"px\":case\"cm\":case\"mm\":case\"in\":case\"pt\":case\"pc\":case\"ch\":case\"vh\":case\"vw\":case\"vmax\":case\"vmin\":this.type=\"length\";break;case\"deg\":case\"rad\":case\"grad\":this.type=\"angle\";break;case\"ms\":case\"s\":this.type=\"time\";break;case\"hz\":case\"khz\":this.type=\"frequency\";break;case\"dpi\":case\"dpcm\":this.type=\"resolution\"}else/^([+\\\\-]?[\\\\d\\\\.]+)%$/i.test(text)?(this.type=\"percentage\",this.value=+RegExp.$1):/^([+\\\\-]?\\\\d+)$/i.test(text)?(this.type=\"integer\",this.value=+RegExp.$1):/^([+\\\\-]?[\\\\d\\\\.]+)$/i.test(text)?(this.type=\"number\",this.value=+RegExp.$1):/^#([a-f0-9]{3,6})/i.test(text)?(this.type=\"color\",temp=RegExp.$1,3==temp.length?(this.red=parseInt(temp.charAt(0)+temp.charAt(0),16),this.green=parseInt(temp.charAt(1)+temp.charAt(1),16),this.blue=parseInt(temp.charAt(2)+temp.charAt(2),16)):(this.red=parseInt(temp.substring(0,2),16),this.green=parseInt(temp.substring(2,4),16),this.blue=parseInt(temp.substring(4,6),16))):/^rgb\\\\(\\\\s*(\\\\d+)\\\\s*,\\\\s*(\\\\d+)\\\\s*,\\\\s*(\\\\d+)\\\\s*\\\\)/i.test(text)?(this.type=\"color\",this.red=+RegExp.$1,this.green=+RegExp.$2,this.blue=+RegExp.$3):/^rgb\\\\(\\\\s*(\\\\d+)%\\\\s*,\\\\s*(\\\\d+)%\\\\s*,\\\\s*(\\\\d+)%\\\\s*\\\\)/i.test(text)?(this.type=\"color\",this.red=255*+RegExp.$1/100,this.green=255*+RegExp.$2/100,this.blue=255*+RegExp.$3/100):/^rgba\\\\(\\\\s*(\\\\d+)\\\\s*,\\\\s*(\\\\d+)\\\\s*,\\\\s*(\\\\d+)\\\\s*,\\\\s*([\\\\d\\\\.]+)\\\\s*\\\\)/i.test(text)?(this.type=\"color\",this.red=+RegExp.$1,this.green=+RegExp.$2,this.blue=+RegExp.$3,this.alpha=+RegExp.$4):/^rgba\\\\(\\\\s*(\\\\d+)%\\\\s*,\\\\s*(\\\\d+)%\\\\s*,\\\\s*(\\\\d+)%\\\\s*,\\\\s*([\\\\d\\\\.]+)\\\\s*\\\\)/i.test(text)?(this.type=\"color\",this.red=255*+RegExp.$1/100,this.green=255*+RegExp.$2/100,this.blue=255*+RegExp.$3/100,this.alpha=+RegExp.$4):/^hsl\\\\(\\\\s*(\\\\d+)\\\\s*,\\\\s*(\\\\d+)%\\\\s*,\\\\s*(\\\\d+)%\\\\s*\\\\)/i.test(text)?(this.type=\"color\",this.hue=+RegExp.$1,this.saturation=+RegExp.$2/100,this.lightness=+RegExp.$3/100):/^hsla\\\\(\\\\s*(\\\\d+)\\\\s*,\\\\s*(\\\\d+)%\\\\s*,\\\\s*(\\\\d+)%\\\\s*,\\\\s*([\\\\d\\\\.]+)\\\\s*\\\\)/i.test(text)?(this.type=\"color\",this.hue=+RegExp.$1,this.saturation=+RegExp.$2/100,this.lightness=+RegExp.$3/100,this.alpha=+RegExp.$4):/^url\\\\([\"\\']?([^\\\\)\"\\']+)[\"\\']?\\\\)/i.test(text)?(this.type=\"uri\",this.uri=RegExp.$1):/^([^\\\\(]+)\\\\(/i.test(text)?(this.type=\"function\",this.name=RegExp.$1,this.value=text):/^[\"\\'][^\"\\']*[\"\\']/.test(text)?(this.type=\"string\",this.value=eval(text)):Colors[text.toLowerCase()]?(this.type=\"color\",temp=Colors[text.toLowerCase()].substring(1),this.red=parseInt(temp.substring(0,2),16),this.green=parseInt(temp.substring(2,4),16),this.blue=parseInt(temp.substring(4,6),16)):/^[\\\\,\\\\/]$/.test(text)?(this.type=\"operator\",this.value=text):/^[a-z\\\\-_\\\\u0080-\\\\uFFFF][a-z0-9\\\\-_\\\\u0080-\\\\uFFFF]*$/i.test(text)&&(this.type=\"identifier\",this.value=text)}function Selector(parts,line,col){SyntaxUnit.call(this,parts.join(\" \"),line,col,Parser.SELECTOR_TYPE),this.parts=parts,this.specificity=Specificity.calculate(this)}function SelectorPart(elementName,modifiers,text,line,col){SyntaxUnit.call(this,text,line,col,Parser.SELECTOR_PART_TYPE),this.elementName=elementName,this.modifiers=modifiers}function SelectorSubPart(text,type,line,col){SyntaxUnit.call(this,text,line,col,Parser.SELECTOR_SUB_PART_TYPE),this.type=type,this.args=[]}function Specificity(a,b,c,d){this.a=a,this.b=b,this.c=c,this.d=d}function isHexDigit(c){return null!==c&&h.test(c)}function isDigit(c){return null!==c&&/\\\\d/.test(c)}function isWhitespace(c){return null!==c&&/\\\\s/.test(c)}function isNewLine(c){return null!==c&&nl.test(c)}function isNameStart(c){return null!==c&&/[a-z_\\\\u0080-\\\\uFFFF\\\\\\\\]/i.test(c)}function isNameChar(c){return null!==c&&(isNameStart(c)||/[0-9\\\\-\\\\\\\\]/.test(c))}function isIdentStart(c){return null!==c&&(isNameStart(c)||/\\\\-\\\\\\\\/.test(c))}function mix(receiver,supplier){for(var prop in supplier)supplier.hasOwnProperty(prop)&&(receiver[prop]=supplier[prop]);return receiver}function TokenStream(input){TokenStreamBase.call(this,input,Tokens)}function ValidationError(message,line,col){this.col=col,this.line=line,this.message=message}var EventTarget=parserlib.util.EventTarget,TokenStreamBase=parserlib.util.TokenStreamBase,StringReader=parserlib.util.StringReader,SyntaxError=parserlib.util.SyntaxError,SyntaxUnit=parserlib.util.SyntaxUnit,Colors={aliceblue:\"#f0f8ff\",antiquewhite:\"#faebd7\",aqua:\"#00ffff\",aquamarine:\"#7fffd4\",azure:\"#f0ffff\",beige:\"#f5f5dc\",bisque:\"#ffe4c4\",black:\"#000000\",blanchedalmond:\"#ffebcd\",blue:\"#0000ff\",blueviolet:\"#8a2be2\",brown:\"#a52a2a\",burlywood:\"#deb887\",cadetblue:\"#5f9ea0\",chartreuse:\"#7fff00\",chocolate:\"#d2691e\",coral:\"#ff7f50\",cornflowerblue:\"#6495ed\",cornsilk:\"#fff8dc\",crimson:\"#dc143c\",cyan:\"#00ffff\",darkblue:\"#00008b\",darkcyan:\"#008b8b\",darkgoldenrod:\"#b8860b\",darkgray:\"#a9a9a9\",darkgrey:\"#a9a9a9\",darkgreen:\"#006400\",darkkhaki:\"#bdb76b\",darkmagenta:\"#8b008b\",darkolivegreen:\"#556b2f\",darkorange:\"#ff8c00\",darkorchid:\"#9932cc\",darkred:\"#8b0000\",darksalmon:\"#e9967a\",darkseagreen:\"#8fbc8f\",darkslateblue:\"#483d8b\",darkslategray:\"#2f4f4f\",darkslategrey:\"#2f4f4f\",darkturquoise:\"#00ced1\",darkviolet:\"#9400d3\",deeppink:\"#ff1493\",deepskyblue:\"#00bfff\",dimgray:\"#696969\",dimgrey:\"#696969\",dodgerblue:\"#1e90ff\",firebrick:\"#b22222\",floralwhite:\"#fffaf0\",forestgreen:\"#228b22\",fuchsia:\"#ff00ff\",gainsboro:\"#dcdcdc\",ghostwhite:\"#f8f8ff\",gold:\"#ffd700\",goldenrod:\"#daa520\",gray:\"#808080\",grey:\"#808080\",green:\"#008000\",greenyellow:\"#adff2f\",honeydew:\"#f0fff0\",hotpink:\"#ff69b4\",indianred:\"#cd5c5c\",indigo:\"#4b0082\",ivory:\"#fffff0\",khaki:\"#f0e68c\",lavender:\"#e6e6fa\",lavenderblush:\"#fff0f5\",lawngreen:\"#7cfc00\",lemonchiffon:\"#fffacd\",lightblue:\"#add8e6\",lightcoral:\"#f08080\",lightcyan:\"#e0ffff\",lightgoldenrodyellow:\"#fafad2\",lightgray:\"#d3d3d3\",lightgrey:\"#d3d3d3\",lightgreen:\"#90ee90\",lightpink:\"#ffb6c1\",lightsalmon:\"#ffa07a\",lightseagreen:\"#20b2aa\",lightskyblue:\"#87cefa\",lightslategray:\"#778899\",lightslategrey:\"#778899\",lightsteelblue:\"#b0c4de\",lightyellow:\"#ffffe0\",lime:\"#00ff00\",limegreen:\"#32cd32\",linen:\"#faf0e6\",magenta:\"#ff00ff\",maroon:\"#800000\",mediumaquamarine:\"#66cdaa\",mediumblue:\"#0000cd\",mediumorchid:\"#ba55d3\",mediumpurple:\"#9370d8\",mediumseagreen:\"#3cb371\",mediumslateblue:\"#7b68ee\",mediumspringgreen:\"#00fa9a\",mediumturquoise:\"#48d1cc\",mediumvioletred:\"#c71585\",midnightblue:\"#191970\",mintcream:\"#f5fffa\",mistyrose:\"#ffe4e1\",moccasin:\"#ffe4b5\",navajowhite:\"#ffdead\",navy:\"#000080\",oldlace:\"#fdf5e6\",olive:\"#808000\",olivedrab:\"#6b8e23\",orange:\"#ffa500\",orangered:\"#ff4500\",orchid:\"#da70d6\",palegoldenrod:\"#eee8aa\",palegreen:\"#98fb98\",paleturquoise:\"#afeeee\",palevioletred:\"#d87093\",papayawhip:\"#ffefd5\",peachpuff:\"#ffdab9\",peru:\"#cd853f\",pink:\"#ffc0cb\",plum:\"#dda0dd\",powderblue:\"#b0e0e6\",purple:\"#800080\",red:\"#ff0000\",rosybrown:\"#bc8f8f\",royalblue:\"#4169e1\",saddlebrown:\"#8b4513\",salmon:\"#fa8072\",sandybrown:\"#f4a460\",seagreen:\"#2e8b57\",seashell:\"#fff5ee\",sienna:\"#a0522d\",silver:\"#c0c0c0\",skyblue:\"#87ceeb\",slateblue:\"#6a5acd\",slategray:\"#708090\",slategrey:\"#708090\",snow:\"#fffafa\",springgreen:\"#00ff7f\",steelblue:\"#4682b4\",tan:\"#d2b48c\",teal:\"#008080\",thistle:\"#d8bfd8\",tomato:\"#ff6347\",turquoise:\"#40e0d0\",violet:\"#ee82ee\",wheat:\"#f5deb3\",white:\"#ffffff\",whitesmoke:\"#f5f5f5\",yellow:\"#ffff00\",yellowgreen:\"#9acd32\",activeBorder:\"Active window border.\",activecaption:\"Active window caption.\",appworkspace:\"Background color of multiple document interface.\",background:\"Desktop background.\",buttonface:\"The face background color for 3-D elements that appear 3-D due to one layer of surrounding border.\",buttonhighlight:\"The color of the border facing the light source for 3-D elements that appear 3-D due to one layer of surrounding border.\",buttonshadow:\"The color of the border away from the light source for 3-D elements that appear 3-D due to one layer of surrounding border.\",buttontext:\"Text on push buttons.\",captiontext:\"Text in caption, size box, and scrollbar arrow box.\",graytext:\"Grayed (disabled) text. This color is set to #000 if the current display driver does not support a solid gray color.\",greytext:\"Greyed (disabled) text. This color is set to #000 if the current display driver does not support a solid grey color.\",highlight:\"Item(s) selected in a control.\",highlighttext:\"Text of item(s) selected in a control.\",inactiveborder:\"Inactive window border.\",inactivecaption:\"Inactive window caption.\",inactivecaptiontext:\"Color of text in an inactive caption.\",infobackground:\"Background color for tooltip controls.\",infotext:\"Text color for tooltip controls.\",menu:\"Menu background.\",menutext:\"Text in menus.\",scrollbar:\"Scroll bar gray area.\",threeddarkshadow:\"The color of the darker (generally outer) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.\",threedface:\"The face background color for 3-D elements that appear 3-D due to two concentric layers of surrounding border.\",threedhighlight:\"The color of the lighter (generally outer) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.\",threedlightshadow:\"The color of the darker (generally inner) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.\",threedshadow:\"The color of the lighter (generally inner) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.\",window:\"Window background.\",windowframe:\"Window frame.\",windowtext:\"Text in windows.\"};Combinator.prototype=new SyntaxUnit,Combinator.prototype.constructor=Combinator,MediaFeature.prototype=new SyntaxUnit,MediaFeature.prototype.constructor=MediaFeature,MediaQuery.prototype=new SyntaxUnit,MediaQuery.prototype.constructor=MediaQuery,Parser.DEFAULT_TYPE=0,Parser.COMBINATOR_TYPE=1,Parser.MEDIA_FEATURE_TYPE=2,Parser.MEDIA_QUERY_TYPE=3,Parser.PROPERTY_NAME_TYPE=4,Parser.PROPERTY_VALUE_TYPE=5,Parser.PROPERTY_VALUE_PART_TYPE=6,Parser.SELECTOR_TYPE=7,Parser.SELECTOR_PART_TYPE=8,Parser.SELECTOR_SUB_PART_TYPE=9,Parser.prototype=function(){var prop,proto=new EventTarget,additions={constructor:Parser,DEFAULT_TYPE:0,COMBINATOR_TYPE:1,MEDIA_FEATURE_TYPE:2,MEDIA_QUERY_TYPE:3,PROPERTY_NAME_TYPE:4,PROPERTY_VALUE_TYPE:5,PROPERTY_VALUE_PART_TYPE:6,SELECTOR_TYPE:7,SELECTOR_PART_TYPE:8,SELECTOR_SUB_PART_TYPE:9,_stylesheet:function(){var count,token,tt,tokenStream=this._tokenStream;for(this.fire(\"startstylesheet\"),this._charset(),this._skipCruft();tokenStream.peek()==Tokens.IMPORT_SYM;)this._import(),this._skipCruft();for(;tokenStream.peek()==Tokens.NAMESPACE_SYM;)this._namespace(),this._skipCruft();for(tt=tokenStream.peek();tt>Tokens.EOF;){try{switch(tt){case Tokens.MEDIA_SYM:this._media(),this._skipCruft();break;case Tokens.PAGE_SYM:this._page(),this._skipCruft();break;case Tokens.FONT_FACE_SYM:this._font_face(),this._skipCruft();break;case Tokens.KEYFRAMES_SYM:this._keyframes(),this._skipCruft();break;case Tokens.VIEWPORT_SYM:this._viewport(),this._skipCruft();break;case Tokens.UNKNOWN_SYM:if(tokenStream.get(),this.options.strict)throw new SyntaxError(\"Unknown @ rule.\",tokenStream.LT(0).startLine,tokenStream.LT(0).startCol);for(this.fire({type:\"error\",error:null,message:\"Unknown @ rule: \"+tokenStream.LT(0).value+\".\",line:tokenStream.LT(0).startLine,col:tokenStream.LT(0).startCol}),count=0;tokenStream.advance([Tokens.LBRACE,Tokens.RBRACE])==Tokens.LBRACE;)count++;for(;count;)tokenStream.advance([Tokens.RBRACE]),count--;break;case Tokens.S:this._readWhitespace();break;default:if(!this._ruleset())switch(tt){case Tokens.CHARSET_SYM:throw token=tokenStream.LT(1),this._charset(!1),new SyntaxError(\"@charset not allowed here.\",token.startLine,token.startCol);case Tokens.IMPORT_SYM:throw token=tokenStream.LT(1),this._import(!1),new SyntaxError(\"@import not allowed here.\",token.startLine,token.startCol);case Tokens.NAMESPACE_SYM:throw token=tokenStream.LT(1),this._namespace(!1),new SyntaxError(\"@namespace not allowed here.\",token.startLine,token.startCol);default:tokenStream.get(),this._unexpectedToken(tokenStream.token())}}}catch(ex){if(!(ex instanceof SyntaxError)||this.options.strict)throw ex;this.fire({type:\"error\",error:ex,message:ex.message,line:ex.line,col:ex.col})}tt=tokenStream.peek()}tt!=Tokens.EOF&&this._unexpectedToken(tokenStream.token()),this.fire(\"endstylesheet\")},_charset:function(emit){var charset,token,line,col,tokenStream=this._tokenStream;tokenStream.match(Tokens.CHARSET_SYM)&&(line=tokenStream.token().startLine,col=tokenStream.token().startCol,this._readWhitespace(),tokenStream.mustMatch(Tokens.STRING),token=tokenStream.token(),charset=token.value,this._readWhitespace(),tokenStream.mustMatch(Tokens.SEMICOLON),emit!==!1&&this.fire({type:\"charset\",charset:charset,line:line,col:col}))},_import:function(emit){var uri,importToken,tokenStream=this._tokenStream,mediaList=[];tokenStream.mustMatch(Tokens.IMPORT_SYM),importToken=tokenStream.token(),this._readWhitespace(),tokenStream.mustMatch([Tokens.STRING,Tokens.URI]),uri=tokenStream.token().value.replace(/^(?:url\\\\()?[\"\\']?([^\"\\']+?)[\"\\']?\\\\)?$/,\"$1\"),this._readWhitespace(),mediaList=this._media_query_list(),tokenStream.mustMatch(Tokens.SEMICOLON),this._readWhitespace(),emit!==!1&&this.fire({type:\"import\",uri:uri,media:mediaList,line:importToken.startLine,col:importToken.startCol})},_namespace:function(emit){var line,col,prefix,uri,tokenStream=this._tokenStream;tokenStream.mustMatch(Tokens.NAMESPACE_SYM),line=tokenStream.token().startLine,col=tokenStream.token().startCol,this._readWhitespace(),tokenStream.match(Tokens.IDENT)&&(prefix=tokenStream.token().value,this._readWhitespace()),tokenStream.mustMatch([Tokens.STRING,Tokens.URI]),uri=tokenStream.token().value.replace(/(?:url\\\\()?[\"\\']([^\"\\']+)[\"\\']\\\\)?/,\"$1\"),this._readWhitespace(),tokenStream.mustMatch(Tokens.SEMICOLON),this._readWhitespace(),emit!==!1&&this.fire({type:\"namespace\",prefix:prefix,uri:uri,line:line,col:col})},_media:function(){var line,col,mediaList,tokenStream=this._tokenStream;for(tokenStream.mustMatch(Tokens.MEDIA_SYM),line=tokenStream.token().startLine,col=tokenStream.token().startCol,this._readWhitespace(),mediaList=this._media_query_list(),tokenStream.mustMatch(Tokens.LBRACE),this._readWhitespace(),this.fire({type:\"startmedia\",media:mediaList,line:line,col:col});;)if(tokenStream.peek()==Tokens.PAGE_SYM)this._page();else if(tokenStream.peek()==Tokens.FONT_FACE_SYM)this._font_face();else if(tokenStream.peek()==Tokens.VIEWPORT_SYM)this._viewport();else if(!this._ruleset())break;tokenStream.mustMatch(Tokens.RBRACE),this._readWhitespace(),this.fire({type:\"endmedia\",media:mediaList,line:line,col:col})},_media_query_list:function(){var tokenStream=this._tokenStream,mediaList=[];for(this._readWhitespace(),(tokenStream.peek()==Tokens.IDENT||tokenStream.peek()==Tokens.LPAREN)&&mediaList.push(this._media_query());tokenStream.match(Tokens.COMMA);)this._readWhitespace(),mediaList.push(this._media_query());return mediaList},_media_query:function(){var tokenStream=this._tokenStream,type=null,ident=null,token=null,expressions=[];if(tokenStream.match(Tokens.IDENT)&&(ident=tokenStream.token().value.toLowerCase(),\"only\"!=ident&&\"not\"!=ident?(tokenStream.unget(),ident=null):token=tokenStream.token()),this._readWhitespace(),tokenStream.peek()==Tokens.IDENT?(type=this._media_type(),null===token&&(token=tokenStream.token())):tokenStream.peek()==Tokens.LPAREN&&(null===token&&(token=tokenStream.LT(1)),expressions.push(this._media_expression())),null===type&&0===expressions.length)return null;for(this._readWhitespace();tokenStream.match(Tokens.IDENT);)\"and\"!=tokenStream.token().value.toLowerCase()&&this._unexpectedToken(tokenStream.token()),this._readWhitespace(),expressions.push(this._media_expression());return new MediaQuery(ident,type,expressions,token.startLine,token.startCol)},_media_type:function(){return this._media_feature()},_media_expression:function(){var token,tokenStream=this._tokenStream,feature=null,expression=null;return tokenStream.mustMatch(Tokens.LPAREN),this._readWhitespace(),feature=this._media_feature(),this._readWhitespace(),tokenStream.match(Tokens.COLON)&&(this._readWhitespace(),token=tokenStream.LT(1),expression=this._expression()),tokenStream.mustMatch(Tokens.RPAREN),this._readWhitespace(),new MediaFeature(feature,expression?new SyntaxUnit(expression,token.startLine,token.startCol):null)},_media_feature:function(){var tokenStream=this._tokenStream;return tokenStream.mustMatch(Tokens.IDENT),SyntaxUnit.fromToken(tokenStream.token())},_page:function(){var line,col,tokenStream=this._tokenStream,identifier=null,pseudoPage=null;tokenStream.mustMatch(Tokens.PAGE_SYM),line=tokenStream.token().startLine,col=tokenStream.token().startCol,this._readWhitespace(),tokenStream.match(Tokens.IDENT)&&(identifier=tokenStream.token().value,\"auto\"===identifier.toLowerCase()&&this._unexpectedToken(tokenStream.token())),tokenStream.peek()==Tokens.COLON&&(pseudoPage=this._pseudo_page()),this._readWhitespace(),this.fire({type:\"startpage\",id:identifier,pseudo:pseudoPage,line:line,col:col}),this._readDeclarations(!0,!0),this.fire({type:\"endpage\",id:identifier,pseudo:pseudoPage,line:line,col:col})},_margin:function(){var line,col,tokenStream=this._tokenStream,marginSym=this._margin_sym();return marginSym?(line=tokenStream.token().startLine,col=tokenStream.token().startCol,this.fire({type:\"startpagemargin\",margin:marginSym,line:line,col:col}),this._readDeclarations(!0),this.fire({type:\"endpagemargin\",margin:marginSym,line:line,col:col}),!0):!1},_margin_sym:function(){var tokenStream=this._tokenStream;return tokenStream.match([Tokens.TOPLEFTCORNER_SYM,Tokens.TOPLEFT_SYM,Tokens.TOPCENTER_SYM,Tokens.TOPRIGHT_SYM,Tokens.TOPRIGHTCORNER_SYM,Tokens.BOTTOMLEFTCORNER_SYM,Tokens.BOTTOMLEFT_SYM,Tokens.BOTTOMCENTER_SYM,Tokens.BOTTOMRIGHT_SYM,Tokens.BOTTOMRIGHTCORNER_SYM,Tokens.LEFTTOP_SYM,Tokens.LEFTMIDDLE_SYM,Tokens.LEFTBOTTOM_SYM,Tokens.RIGHTTOP_SYM,Tokens.RIGHTMIDDLE_SYM,Tokens.RIGHTBOTTOM_SYM])?SyntaxUnit.fromToken(tokenStream.token()):null},_pseudo_page:function(){var tokenStream=this._tokenStream;return tokenStream.mustMatch(Tokens.COLON),tokenStream.mustMatch(Tokens.IDENT),tokenStream.token().value},_font_face:function(){var line,col,tokenStream=this._tokenStream;tokenStream.mustMatch(Tokens.FONT_FACE_SYM),line=tokenStream.token().startLine,col=tokenStream.token().startCol,this._readWhitespace(),this.fire({type:\"startfontface\",line:line,col:col}),this._readDeclarations(!0),this.fire({type:\"endfontface\",line:line,col:col})},_viewport:function(){var line,col,tokenStream=this._tokenStream;tokenStream.mustMatch(Tokens.VIEWPORT_SYM),line=tokenStream.token().startLine,col=tokenStream.token().startCol,this._readWhitespace(),this.fire({type:\"startviewport\",line:line,col:col}),this._readDeclarations(!0),this.fire({type:\"endviewport\",line:line,col:col})},_operator:function(inFunction){var tokenStream=this._tokenStream,token=null;return(tokenStream.match([Tokens.SLASH,Tokens.COMMA])||inFunction&&tokenStream.match([Tokens.PLUS,Tokens.STAR,Tokens.MINUS]))&&(token=tokenStream.token(),this._readWhitespace()),token?PropertyValuePart.fromToken(token):null},_combinator:function(){var token,tokenStream=this._tokenStream,value=null;return tokenStream.match([Tokens.PLUS,Tokens.GREATER,Tokens.TILDE])&&(token=tokenStream.token(),value=new Combinator(token.value,token.startLine,token.startCol),this._readWhitespace()),value},_unary_operator:function(){var tokenStream=this._tokenStream;return tokenStream.match([Tokens.MINUS,Tokens.PLUS])?tokenStream.token().value:null},_property:function(){var tokenValue,token,line,col,tokenStream=this._tokenStream,value=null,hack=null;return tokenStream.peek()==Tokens.STAR&&this.options.starHack&&(tokenStream.get(),token=tokenStream.token(),hack=token.value,line=token.startLine,col=token.startCol),tokenStream.match(Tokens.IDENT)&&(token=tokenStream.token(),tokenValue=token.value,\"_\"==tokenValue.charAt(0)&&this.options.underscoreHack&&(hack=\"_\",tokenValue=tokenValue.substring(1)),value=new PropertyName(tokenValue,hack,line||token.startLine,col||token.startCol),this._readWhitespace()),value},_ruleset:function(){var tt,selectors,tokenStream=this._tokenStream;try{selectors=this._selectors_group()}catch(ex){if(!(ex instanceof SyntaxError)||this.options.strict)throw ex;if(this.fire({type:\"error\",error:ex,message:ex.message,line:ex.line,col:ex.col}),tt=tokenStream.advance([Tokens.RBRACE]),tt!=Tokens.RBRACE)throw ex;return!0}return selectors&&(this.fire({type:\"startrule\",selectors:selectors,line:selectors[0].line,col:selectors[0].col}),this._readDeclarations(!0),this.fire({type:\"endrule\",selectors:selectors,line:selectors[0].line,col:selectors[0].col})),selectors},_selectors_group:function(){var selector,tokenStream=this._tokenStream,selectors=[];if(selector=this._selector(),null!==selector)for(selectors.push(selector);tokenStream.match(Tokens.COMMA);)this._readWhitespace(),selector=this._selector(),null!==selector?selectors.push(selector):this._unexpectedToken(tokenStream.LT(1));return selectors.length?selectors:null},_selector:function(){var tokenStream=this._tokenStream,selector=[],nextSelector=null,combinator=null,ws=null;if(nextSelector=this._simple_selector_sequence(),null===nextSelector)return null;for(selector.push(nextSelector);;)if(combinator=this._combinator(),null!==combinator)selector.push(combinator),nextSelector=this._simple_selector_sequence(),null===nextSelector?this._unexpectedToken(tokenStream.LT(1)):selector.push(nextSelector);else{if(!this._readWhitespace())break;ws=new Combinator(tokenStream.token().value,tokenStream.token().startLine,tokenStream.token().startCol),combinator=this._combinator(),nextSelector=this._simple_selector_sequence(),null===nextSelector?null!==combinator&&this._unexpectedToken(tokenStream.LT(1)):(null!==combinator?selector.push(combinator):selector.push(ws),selector.push(nextSelector))}return new Selector(selector,selector[0].line,selector[0].col)},_simple_selector_sequence:function(){var line,col,tokenStream=this._tokenStream,elementName=null,modifiers=[],selectorText=\"\",components=[function(){return tokenStream.match(Tokens.HASH)?new SelectorSubPart(tokenStream.token().value,\"id\",tokenStream.token().startLine,tokenStream.token().startCol):null},this._class,this._attrib,this._pseudo,this._negation],i=0,len=components.length,component=null;for(line=tokenStream.LT(1).startLine,col=tokenStream.LT(1).startCol,elementName=this._type_selector(),elementName||(elementName=this._universal()),null!==elementName&&(selectorText+=elementName);;){if(tokenStream.peek()===Tokens.S)break;for(;len>i&&null===component;)component=components[i++].call(this);if(null===component){if(\"\"===selectorText)return null;break}i=0,modifiers.push(component),selectorText+=\"\"+component,component=null}return\"\"!==selectorText?new SelectorPart(elementName,modifiers,selectorText,line,col):null},_type_selector:function(){var tokenStream=this._tokenStream,ns=this._namespace_prefix(),elementName=this._element_name();return elementName?(ns&&(elementName.text=ns+elementName.text,elementName.col-=ns.length),elementName):(ns&&(tokenStream.unget(),ns.length>1&&tokenStream.unget()),null)},_class:function(){var token,tokenStream=this._tokenStream;return tokenStream.match(Tokens.DOT)?(tokenStream.mustMatch(Tokens.IDENT),token=tokenStream.token(),new SelectorSubPart(\".\"+token.value,\"class\",token.startLine,token.startCol-1)):null},_element_name:function(){var token,tokenStream=this._tokenStream;return tokenStream.match(Tokens.IDENT)?(token=tokenStream.token(),new SelectorSubPart(token.value,\"elementName\",token.startLine,token.startCol)):null},_namespace_prefix:function(){var tokenStream=this._tokenStream,value=\"\";return(tokenStream.LA(1)===Tokens.PIPE||tokenStream.LA(2)===Tokens.PIPE)&&(tokenStream.match([Tokens.IDENT,Tokens.STAR])&&(value+=tokenStream.token().value),tokenStream.mustMatch(Tokens.PIPE),value+=\"|\"),value.length?value:null},_universal:function(){var ns,tokenStream=this._tokenStream,value=\"\";return ns=this._namespace_prefix(),ns&&(value+=ns),tokenStream.match(Tokens.STAR)&&(value+=\"*\"),value.length?value:null},_attrib:function(){var ns,token,tokenStream=this._tokenStream,value=null;return tokenStream.match(Tokens.LBRACKET)?(token=tokenStream.token(),value=token.value,value+=this._readWhitespace(),ns=this._namespace_prefix(),ns&&(value+=ns),tokenStream.mustMatch(Tokens.IDENT),value+=tokenStream.token().value,value+=this._readWhitespace(),tokenStream.match([Tokens.PREFIXMATCH,Tokens.SUFFIXMATCH,Tokens.SUBSTRINGMATCH,Tokens.EQUALS,Tokens.INCLUDES,Tokens.DASHMATCH])&&(value+=tokenStream.token().value,value+=this._readWhitespace(),tokenStream.mustMatch([Tokens.IDENT,Tokens.STRING]),value+=tokenStream.token().value,value+=this._readWhitespace()),tokenStream.mustMatch(Tokens.RBRACKET),new SelectorSubPart(value+\"]\",\"attribute\",token.startLine,token.startCol)):null},_pseudo:function(){var line,col,tokenStream=this._tokenStream,pseudo=null,colons=\":\";return tokenStream.match(Tokens.COLON)&&(tokenStream.match(Tokens.COLON)&&(colons+=\":\"),tokenStream.match(Tokens.IDENT)?(pseudo=tokenStream.token().value,line=tokenStream.token().startLine,col=tokenStream.token().startCol-colons.length):tokenStream.peek()==Tokens.FUNCTION&&(line=tokenStream.LT(1).startLine,col=tokenStream.LT(1).startCol-colons.length,pseudo=this._functional_pseudo()),pseudo&&(pseudo=new SelectorSubPart(colons+pseudo,\"pseudo\",line,col))),pseudo},_functional_pseudo:function(){var tokenStream=this._tokenStream,value=null;return tokenStream.match(Tokens.FUNCTION)&&(value=tokenStream.token().value,value+=this._readWhitespace(),value+=this._expression(),tokenStream.mustMatch(Tokens.RPAREN),value+=\")\"),value},_expression:function(){for(var tokenStream=this._tokenStream,value=\"\";tokenStream.match([Tokens.PLUS,Tokens.MINUS,Tokens.DIMENSION,Tokens.NUMBER,Tokens.STRING,Tokens.IDENT,Tokens.LENGTH,Tokens.FREQ,Tokens.ANGLE,Tokens.TIME,Tokens.RESOLUTION,Tokens.SLASH]);)value+=tokenStream.token().value,value+=this._readWhitespace();return value.length?value:null},_negation:function(){var line,col,arg,tokenStream=this._tokenStream,value=\"\",subpart=null;return tokenStream.match(Tokens.NOT)&&(value=tokenStream.token().value,line=tokenStream.token().startLine,col=tokenStream.token().startCol,value+=this._readWhitespace(),arg=this._negation_arg(),value+=arg,value+=this._readWhitespace(),tokenStream.match(Tokens.RPAREN),value+=tokenStream.token().value,subpart=new SelectorSubPart(value,\"not\",line,col),subpart.args.push(arg)),subpart},_negation_arg:function(){var line,col,part,tokenStream=this._tokenStream,args=[this._type_selector,this._universal,function(){return tokenStream.match(Tokens.HASH)?new SelectorSubPart(tokenStream.token().value,\"id\",tokenStream.token().startLine,tokenStream.token().startCol):null},this._class,this._attrib,this._pseudo],arg=null,i=0,len=args.length;for(line=tokenStream.LT(1).startLine,col=tokenStream.LT(1).startCol;len>i&&null===arg;)arg=args[i].call(this),i++;return null===arg&&this._unexpectedToken(tokenStream.LT(1)),part=\"elementName\"==arg.type?new SelectorPart(arg,[],\"\"+arg,line,col):new SelectorPart(null,[arg],\"\"+arg,line,col)},_declaration:function(){var tokenStream=this._tokenStream,property=null,expr=null,prio=null,invalid=null,propertyName=\"\";if(property=this._property(),null!==property){tokenStream.mustMatch(Tokens.COLON),this._readWhitespace(),expr=this._expr(),expr&&0!==expr.length||this._unexpectedToken(tokenStream.LT(1)),prio=this._prio(),propertyName=\"\"+property,(this.options.starHack&&\"*\"==property.hack||this.options.underscoreHack&&\"_\"==property.hack)&&(propertyName=property.text);try{this._validateProperty(propertyName,expr)}catch(ex){invalid=ex}return this.fire({type:\"property\",property:property,value:expr,important:prio,line:property.line,col:property.col,invalid:invalid}),!0}return!1},_prio:function(){var tokenStream=this._tokenStream,result=tokenStream.match(Tokens.IMPORTANT_SYM);return this._readWhitespace(),result},_expr:function(inFunction){var values=(this._tokenStream,[]),value=null,operator=null;if(value=this._term(inFunction),null!==value)for(values.push(value);;){if(operator=this._operator(inFunction),operator&&values.push(operator),value=this._term(inFunction),null===value)break;\\nvalues.push(value)}return values.length>0?new PropertyValue(values,values[0].line,values[0].col):null},_term:function(inFunction){var token,line,col,tokenStream=this._tokenStream,unary=null,value=null,endChar=null;return unary=this._unary_operator(),null!==unary&&(line=tokenStream.token().startLine,col=tokenStream.token().startCol),tokenStream.peek()==Tokens.IE_FUNCTION&&this.options.ieFilters?(value=this._ie_function(),null===unary&&(line=tokenStream.token().startLine,col=tokenStream.token().startCol)):inFunction&&tokenStream.match([Tokens.LPAREN,Tokens.LBRACE,Tokens.LBRACKET])?(token=tokenStream.token(),endChar=token.endChar,value=token.value+this._expr(inFunction).text,null===unary&&(line=tokenStream.token().startLine,col=tokenStream.token().startCol),tokenStream.mustMatch(Tokens.type(endChar)),value+=endChar,this._readWhitespace()):tokenStream.match([Tokens.NUMBER,Tokens.PERCENTAGE,Tokens.LENGTH,Tokens.ANGLE,Tokens.TIME,Tokens.FREQ,Tokens.STRING,Tokens.IDENT,Tokens.URI,Tokens.UNICODE_RANGE])?(value=tokenStream.token().value,null===unary&&(line=tokenStream.token().startLine,col=tokenStream.token().startCol),this._readWhitespace()):(token=this._hexcolor(),null===token?(null===unary&&(line=tokenStream.LT(1).startLine,col=tokenStream.LT(1).startCol),null===value&&(value=tokenStream.LA(3)==Tokens.EQUALS&&this.options.ieFilters?this._ie_function():this._function())):(value=token.value,null===unary&&(line=token.startLine,col=token.startCol))),null!==value?new PropertyValuePart(null!==unary?unary+value:value,line,col):null},_function:function(){var lt,tokenStream=this._tokenStream,functionText=null,expr=null;if(tokenStream.match(Tokens.FUNCTION)){if(functionText=tokenStream.token().value,this._readWhitespace(),expr=this._expr(!0),functionText+=expr,this.options.ieFilters&&tokenStream.peek()==Tokens.EQUALS)do for(this._readWhitespace()&&(functionText+=tokenStream.token().value),tokenStream.LA(0)==Tokens.COMMA&&(functionText+=tokenStream.token().value),tokenStream.match(Tokens.IDENT),functionText+=tokenStream.token().value,tokenStream.match(Tokens.EQUALS),functionText+=tokenStream.token().value,lt=tokenStream.peek();lt!=Tokens.COMMA&&lt!=Tokens.S&&lt!=Tokens.RPAREN;)tokenStream.get(),functionText+=tokenStream.token().value,lt=tokenStream.peek();while(tokenStream.match([Tokens.COMMA,Tokens.S]));tokenStream.match(Tokens.RPAREN),functionText+=\")\",this._readWhitespace()}return functionText},_ie_function:function(){var lt,tokenStream=this._tokenStream,functionText=null;if(tokenStream.match([Tokens.IE_FUNCTION,Tokens.FUNCTION])){functionText=tokenStream.token().value;do for(this._readWhitespace()&&(functionText+=tokenStream.token().value),tokenStream.LA(0)==Tokens.COMMA&&(functionText+=tokenStream.token().value),tokenStream.match(Tokens.IDENT),functionText+=tokenStream.token().value,tokenStream.match(Tokens.EQUALS),functionText+=tokenStream.token().value,lt=tokenStream.peek();lt!=Tokens.COMMA&&lt!=Tokens.S&&lt!=Tokens.RPAREN;)tokenStream.get(),functionText+=tokenStream.token().value,lt=tokenStream.peek();while(tokenStream.match([Tokens.COMMA,Tokens.S]));tokenStream.match(Tokens.RPAREN),functionText+=\")\",this._readWhitespace()}return functionText},_hexcolor:function(){var color,tokenStream=this._tokenStream,token=null;if(tokenStream.match(Tokens.HASH)){if(token=tokenStream.token(),color=token.value,!/#[a-f0-9]{3,6}/i.test(color))throw new SyntaxError(\"Expected a hex color but found \\'\"+color+\"\\' at line \"+token.startLine+\", col \"+token.startCol+\".\",token.startLine,token.startCol);this._readWhitespace()}return token},_keyframes:function(){var token,tt,name,tokenStream=this._tokenStream,prefix=\"\";for(tokenStream.mustMatch(Tokens.KEYFRAMES_SYM),token=tokenStream.token(),/^@\\\\-([^\\\\-]+)\\\\-/.test(token.value)&&(prefix=RegExp.$1),this._readWhitespace(),name=this._keyframe_name(),this._readWhitespace(),tokenStream.mustMatch(Tokens.LBRACE),this.fire({type:\"startkeyframes\",name:name,prefix:prefix,line:token.startLine,col:token.startCol}),this._readWhitespace(),tt=tokenStream.peek();tt==Tokens.IDENT||tt==Tokens.PERCENTAGE;)this._keyframe_rule(),this._readWhitespace(),tt=tokenStream.peek();this.fire({type:\"endkeyframes\",name:name,prefix:prefix,line:token.startLine,col:token.startCol}),this._readWhitespace(),tokenStream.mustMatch(Tokens.RBRACE)},_keyframe_name:function(){var tokenStream=this._tokenStream;return tokenStream.mustMatch([Tokens.IDENT,Tokens.STRING]),SyntaxUnit.fromToken(tokenStream.token())},_keyframe_rule:function(){var keyList=(this._tokenStream,this._key_list());this.fire({type:\"startkeyframerule\",keys:keyList,line:keyList[0].line,col:keyList[0].col}),this._readDeclarations(!0),this.fire({type:\"endkeyframerule\",keys:keyList,line:keyList[0].line,col:keyList[0].col})},_key_list:function(){var tokenStream=this._tokenStream,keyList=[];for(keyList.push(this._key()),this._readWhitespace();tokenStream.match(Tokens.COMMA);)this._readWhitespace(),keyList.push(this._key()),this._readWhitespace();return keyList},_key:function(){var token,tokenStream=this._tokenStream;if(tokenStream.match(Tokens.PERCENTAGE))return SyntaxUnit.fromToken(tokenStream.token());if(tokenStream.match(Tokens.IDENT)){if(token=tokenStream.token(),/from|to/i.test(token.value))return SyntaxUnit.fromToken(token);tokenStream.unget()}this._unexpectedToken(tokenStream.LT(1))},_skipCruft:function(){for(;this._tokenStream.match([Tokens.S,Tokens.CDO,Tokens.CDC]););},_readDeclarations:function(checkStart,readMargins){var tt,tokenStream=this._tokenStream;this._readWhitespace(),checkStart&&tokenStream.mustMatch(Tokens.LBRACE),this._readWhitespace();try{for(;;){if(tokenStream.match(Tokens.SEMICOLON)||readMargins&&this._margin());else{if(!this._declaration())break;if(!tokenStream.match(Tokens.SEMICOLON))break}this._readWhitespace()}tokenStream.mustMatch(Tokens.RBRACE),this._readWhitespace()}catch(ex){if(!(ex instanceof SyntaxError)||this.options.strict)throw ex;if(this.fire({type:\"error\",error:ex,message:ex.message,line:ex.line,col:ex.col}),tt=tokenStream.advance([Tokens.SEMICOLON,Tokens.RBRACE]),tt==Tokens.SEMICOLON)this._readDeclarations(!1,readMargins);else if(tt!=Tokens.RBRACE)throw ex}},_readWhitespace:function(){for(var tokenStream=this._tokenStream,ws=\"\";tokenStream.match(Tokens.S);)ws+=tokenStream.token().value;return ws},_unexpectedToken:function(token){throw new SyntaxError(\"Unexpected token \\'\"+token.value+\"\\' at line \"+token.startLine+\", col \"+token.startCol+\".\",token.startLine,token.startCol)},_verifyEnd:function(){this._tokenStream.LA(1)!=Tokens.EOF&&this._unexpectedToken(this._tokenStream.LT(1))},_validateProperty:function(property,value){Validation.validate(property,value)},parse:function(input){this._tokenStream=new TokenStream(input,Tokens),this._stylesheet()},parseStyleSheet:function(input){return this.parse(input)},parseMediaQuery:function(input){this._tokenStream=new TokenStream(input,Tokens);var result=this._media_query();return this._verifyEnd(),result},parsePropertyValue:function(input){this._tokenStream=new TokenStream(input,Tokens),this._readWhitespace();var result=this._expr();return this._readWhitespace(),this._verifyEnd(),result},parseRule:function(input){this._tokenStream=new TokenStream(input,Tokens),this._readWhitespace();var result=this._ruleset();return this._readWhitespace(),this._verifyEnd(),result},parseSelector:function(input){this._tokenStream=new TokenStream(input,Tokens),this._readWhitespace();var result=this._selector();return this._readWhitespace(),this._verifyEnd(),result},parseStyleAttribute:function(input){input+=\"}\",this._tokenStream=new TokenStream(input,Tokens),this._readDeclarations()}};for(prop in additions)additions.hasOwnProperty(prop)&&(proto[prop]=additions[prop]);return proto}();var Properties={\"align-items\":\"flex-start | flex-end | center | baseline | stretch\",\"align-content\":\"flex-start | flex-end | center | space-between | space-around | stretch\",\"align-self\":\"auto | flex-start | flex-end | center | baseline | stretch\",\"-webkit-align-items\":\"flex-start | flex-end | center | baseline | stretch\",\"-webkit-align-content\":\"flex-start | flex-end | center | space-between | space-around | stretch\",\"-webkit-align-self\":\"auto | flex-start | flex-end | center | baseline | stretch\",\"alignment-adjust\":\"auto | baseline | before-edge | text-before-edge | middle | central | after-edge | text-after-edge | ideographic | alphabetic | hanging | mathematical | <percentage> | <length>\",\"alignment-baseline\":\"baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical\",animation:1,\"animation-delay\":{multi:\"<time>\",comma:!0},\"animation-direction\":{multi:\"normal | reverse | alternate | alternate-reverse\",comma:!0},\"animation-duration\":{multi:\"<time>\",comma:!0},\"animation-fill-mode\":{multi:\"none | forwards | backwards | both\",comma:!0},\"animation-iteration-count\":{multi:\"<number> | infinite\",comma:!0},\"animation-name\":{multi:\"none | <ident>\",comma:!0},\"animation-play-state\":{multi:\"running | paused\",comma:!0},\"animation-timing-function\":1,\"-moz-animation-delay\":{multi:\"<time>\",comma:!0},\"-moz-animation-direction\":{multi:\"normal | reverse | alternate | alternate-reverse\",comma:!0},\"-moz-animation-duration\":{multi:\"<time>\",comma:!0},\"-moz-animation-iteration-count\":{multi:\"<number> | infinite\",comma:!0},\"-moz-animation-name\":{multi:\"none | <ident>\",comma:!0},\"-moz-animation-play-state\":{multi:\"running | paused\",comma:!0},\"-ms-animation-delay\":{multi:\"<time>\",comma:!0},\"-ms-animation-direction\":{multi:\"normal | reverse | alternate | alternate-reverse\",comma:!0},\"-ms-animation-duration\":{multi:\"<time>\",comma:!0},\"-ms-animation-iteration-count\":{multi:\"<number> | infinite\",comma:!0},\"-ms-animation-name\":{multi:\"none | <ident>\",comma:!0},\"-ms-animation-play-state\":{multi:\"running | paused\",comma:!0},\"-webkit-animation-delay\":{multi:\"<time>\",comma:!0},\"-webkit-animation-direction\":{multi:\"normal | reverse | alternate | alternate-reverse\",comma:!0},\"-webkit-animation-duration\":{multi:\"<time>\",comma:!0},\"-webkit-animation-fill-mode\":{multi:\"none | forwards | backwards | both\",comma:!0},\"-webkit-animation-iteration-count\":{multi:\"<number> | infinite\",comma:!0},\"-webkit-animation-name\":{multi:\"none | <ident>\",comma:!0},\"-webkit-animation-play-state\":{multi:\"running | paused\",comma:!0},\"-o-animation-delay\":{multi:\"<time>\",comma:!0},\"-o-animation-direction\":{multi:\"normal | reverse | alternate | alternate-reverse\",comma:!0},\"-o-animation-duration\":{multi:\"<time>\",comma:!0},\"-o-animation-iteration-count\":{multi:\"<number> | infinite\",comma:!0},\"-o-animation-name\":{multi:\"none | <ident>\",comma:!0},\"-o-animation-play-state\":{multi:\"running | paused\",comma:!0},appearance:\"icon | window | desktop | workspace | document | tooltip | dialog | button | push-button | hyperlink | radio-button | checkbox | menu-item | tab | menu | menubar | pull-down-menu | pop-up-menu | list-menu | radio-group | checkbox-group | outline-tree | range | field | combo-box | signature | password | normal | none | inherit\",azimuth:function(expression){var part,simple=\"<angle> | leftwards | rightwards | inherit\",direction=\"left-side | far-left | left | center-left | center | center-right | right | far-right | right-side\",behind=!1,valid=!1;if(ValidationTypes.isAny(expression,simple)||(ValidationTypes.isAny(expression,\"behind\")&&(behind=!0,valid=!0),ValidationTypes.isAny(expression,direction)&&(valid=!0,behind||ValidationTypes.isAny(expression,\"behind\"))),expression.hasNext())throw part=expression.next(),valid?new ValidationError(\"Expected end of value but found \\'\"+part+\"\\'.\",part.line,part.col):new ValidationError(\"Expected (<\\'azimuth\\'>) but found \\'\"+part+\"\\'.\",part.line,part.col)},\"backface-visibility\":\"visible | hidden\",background:1,\"background-attachment\":{multi:\"<attachment>\",comma:!0},\"background-clip\":{multi:\"<box>\",comma:!0},\"background-color\":\"<color> | inherit\",\"background-image\":{multi:\"<bg-image>\",comma:!0},\"background-origin\":{multi:\"<box>\",comma:!0},\"background-position\":{multi:\"<bg-position>\",comma:!0},\"background-repeat\":{multi:\"<repeat-style>\"},\"background-size\":{multi:\"<bg-size>\",comma:!0},\"baseline-shift\":\"baseline | sub | super | <percentage> | <length>\",behavior:1,binding:1,bleed:\"<length>\",\"bookmark-label\":\"<content> | <attr> | <string>\",\"bookmark-level\":\"none | <integer>\",\"bookmark-state\":\"open | closed\",\"bookmark-target\":\"none | <uri> | <attr>\",border:\"<border-width> || <border-style> || <color>\",\"border-bottom\":\"<border-width> || <border-style> || <color>\",\"border-bottom-color\":\"<color> | inherit\",\"border-bottom-left-radius\":\"<x-one-radius>\",\"border-bottom-right-radius\":\"<x-one-radius>\",\"border-bottom-style\":\"<border-style>\",\"border-bottom-width\":\"<border-width>\",\"border-collapse\":\"collapse | separate | inherit\",\"border-color\":{multi:\"<color> | inherit\",max:4},\"border-image\":1,\"border-image-outset\":{multi:\"<length> | <number>\",max:4},\"border-image-repeat\":{multi:\"stretch | repeat | round\",max:2},\"border-image-slice\":function(expression){var part,valid=!1,numeric=\"<number> | <percentage>\",fill=!1,count=0,max=4;for(ValidationTypes.isAny(expression,\"fill\")&&(fill=!0,valid=!0);expression.hasNext()&&max>count&&(valid=ValidationTypes.isAny(expression,numeric));)count++;if(fill?valid=!0:ValidationTypes.isAny(expression,\"fill\"),expression.hasNext())throw part=expression.next(),valid?new ValidationError(\"Expected end of value but found \\'\"+part+\"\\'.\",part.line,part.col):new ValidationError(\"Expected ([<number> | <percentage>]{1,4} && fill?) but found \\'\"+part+\"\\'.\",part.line,part.col)},\"border-image-source\":\"<image> | none\",\"border-image-width\":{multi:\"<length> | <percentage> | <number> | auto\",max:4},\"border-left\":\"<border-width> || <border-style> || <color>\",\"border-left-color\":\"<color> | inherit\",\"border-left-style\":\"<border-style>\",\"border-left-width\":\"<border-width>\",\"border-radius\":function(expression){for(var part,valid=!1,simple=\"<length> | <percentage> | inherit\",slash=!1,count=0,max=8;expression.hasNext()&&max>count;){if(valid=ValidationTypes.isAny(expression,simple),!valid){if(!(\"/\"==expression.peek()&&count>0)||slash)break;slash=!0,max=count+5,expression.next()}count++}if(expression.hasNext())throw part=expression.next(),valid?new ValidationError(\"Expected end of value but found \\'\"+part+\"\\'.\",part.line,part.col):new ValidationError(\"Expected (<\\'border-radius\\'>) but found \\'\"+part+\"\\'.\",part.line,part.col)},\"border-right\":\"<border-width> || <border-style> || <color>\",\"border-right-color\":\"<color> | inherit\",\"border-right-style\":\"<border-style>\",\"border-right-width\":\"<border-width>\",\"border-spacing\":{multi:\"<length> | inherit\",max:2},\"border-style\":{multi:\"<border-style>\",max:4},\"border-top\":\"<border-width> || <border-style> || <color>\",\"border-top-color\":\"<color> | inherit\",\"border-top-left-radius\":\"<x-one-radius>\",\"border-top-right-radius\":\"<x-one-radius>\",\"border-top-style\":\"<border-style>\",\"border-top-width\":\"<border-width>\",\"border-width\":{multi:\"<border-width>\",max:4},bottom:\"<margin-width> | inherit\",\"-moz-box-align\":\"start | end | center | baseline | stretch\",\"-moz-box-decoration-break\":\"slice |clone\",\"-moz-box-direction\":\"normal | reverse | inherit\",\"-moz-box-flex\":\"<number>\",\"-moz-box-flex-group\":\"<integer>\",\"-moz-box-lines\":\"single | multiple\",\"-moz-box-ordinal-group\":\"<integer>\",\"-moz-box-orient\":\"horizontal | vertical | inline-axis | block-axis | inherit\",\"-moz-box-pack\":\"start | end | center | justify\",\"-webkit-box-align\":\"start | end | center | baseline | stretch\",\"-webkit-box-decoration-break\":\"slice |clone\",\"-webkit-box-direction\":\"normal | reverse | inherit\",\"-webkit-box-flex\":\"<number>\",\"-webkit-box-flex-group\":\"<integer>\",\"-webkit-box-lines\":\"single | multiple\",\"-webkit-box-ordinal-group\":\"<integer>\",\"-webkit-box-orient\":\"horizontal | vertical | inline-axis | block-axis | inherit\",\"-webkit-box-pack\":\"start | end | center | justify\",\"box-shadow\":function(expression){var part;if(ValidationTypes.isAny(expression,\"none\")){if(expression.hasNext())throw part=expression.next(),new ValidationError(\"Expected end of value but found \\'\"+part+\"\\'.\",part.line,part.col)}else Validation.multiProperty(\"<shadow>\",expression,!0,1/0)},\"box-sizing\":\"content-box | border-box | inherit\",\"break-after\":\"auto | always | avoid | left | right | page | column | avoid-page | avoid-column\",\"break-before\":\"auto | always | avoid | left | right | page | column | avoid-page | avoid-column\",\"break-inside\":\"auto | avoid | avoid-page | avoid-column\",\"caption-side\":\"top | bottom | inherit\",clear:\"none | right | left | both | inherit\",clip:1,color:\"<color> | inherit\",\"color-profile\":1,\"column-count\":\"<integer> | auto\",\"column-fill\":\"auto | balance\",\"column-gap\":\"<length> | normal\",\"column-rule\":\"<border-width> || <border-style> || <color>\",\"column-rule-color\":\"<color>\",\"column-rule-style\":\"<border-style>\",\"column-rule-width\":\"<border-width>\",\"column-span\":\"none | all\",\"column-width\":\"<length> | auto\",columns:1,content:1,\"counter-increment\":1,\"counter-reset\":1,crop:\"<shape> | auto\",cue:\"cue-after | cue-before | inherit\",\"cue-after\":1,\"cue-before\":1,cursor:1,direction:\"ltr | rtl | inherit\",display:\"inline | block | list-item | inline-block | table | inline-table | table-row-group | table-header-group | table-footer-group | table-row | table-column-group | table-column | table-cell | table-caption | grid | inline-grid | none | inherit | -moz-box | -moz-inline-block | -moz-inline-box | -moz-inline-grid | -moz-inline-stack | -moz-inline-table | -moz-grid | -moz-grid-group | -moz-grid-line | -moz-groupbox | -moz-deck | -moz-popup | -moz-stack | -moz-marker | -webkit-box | -webkit-inline-box | -ms-flexbox | -ms-inline-flexbox | flex | -webkit-flex | inline-flex | -webkit-inline-flex\",\"dominant-baseline\":1,\"drop-initial-after-adjust\":\"central | middle | after-edge | text-after-edge | ideographic | alphabetic | mathematical | <percentage> | <length>\",\"drop-initial-after-align\":\"baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical\",\"drop-initial-before-adjust\":\"before-edge | text-before-edge | central | middle | hanging | mathematical | <percentage> | <length>\",\"drop-initial-before-align\":\"caps-height | baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical\",\"drop-initial-size\":\"auto | line | <length> | <percentage>\",\"drop-initial-value\":\"initial | <integer>\",elevation:\"<angle> | below | level | above | higher | lower | inherit\",\"empty-cells\":\"show | hide | inherit\",filter:1,fit:\"fill | hidden | meet | slice\",\"fit-position\":1,flex:\"<flex>\",\"flex-basis\":\"<width>\",\"flex-direction\":\"row | row-reverse | column | column-reverse\",\"flex-flow\":\"<flex-direction> || <flex-wrap>\",\"flex-grow\":\"<number>\",\"flex-shrink\":\"<number>\",\"flex-wrap\":\"nowrap | wrap | wrap-reverse\",\"-webkit-flex\":\"<flex>\",\"-webkit-flex-basis\":\"<width>\",\"-webkit-flex-direction\":\"row | row-reverse | column | column-reverse\",\"-webkit-flex-flow\":\"<flex-direction> || <flex-wrap>\",\"-webkit-flex-grow\":\"<number>\",\"-webkit-flex-shrink\":\"<number>\",\"-webkit-flex-wrap\":\"nowrap | wrap | wrap-reverse\",\"-ms-flex\":\"<flex>\",\"-ms-flex-align\":\"start | end | center | stretch | baseline\",\"-ms-flex-direction\":\"row | row-reverse | column | column-reverse | inherit\",\"-ms-flex-order\":\"<number>\",\"-ms-flex-pack\":\"start | end | center | justify\",\"-ms-flex-wrap\":\"nowrap | wrap | wrap-reverse\",\"float\":\"left | right | none | inherit\",\"float-offset\":1,font:1,\"font-family\":1,\"font-size\":\"<absolute-size> | <relative-size> | <length> | <percentage> | inherit\",\"font-size-adjust\":\"<number> | none | inherit\",\"font-stretch\":\"normal | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded | inherit\",\"font-style\":\"normal | italic | oblique | inherit\",\"font-variant\":\"normal | small-caps | inherit\",\"font-weight\":\"normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit\",\"grid-cell-stacking\":\"columns | rows | layer\",\"grid-column\":1,\"grid-columns\":1,\"grid-column-align\":\"start | end | center | stretch\",\"grid-column-sizing\":1,\"grid-column-span\":\"<integer>\",\"grid-flow\":\"none | rows | columns\",\"grid-layer\":\"<integer>\",\"grid-row\":1,\"grid-rows\":1,\"grid-row-align\":\"start | end | center | stretch\",\"grid-row-span\":\"<integer>\",\"grid-row-sizing\":1,\"hanging-punctuation\":1,height:\"<margin-width> | <content-sizing> | inherit\",\"hyphenate-after\":\"<integer> | auto\",\"hyphenate-before\":\"<integer> | auto\",\"hyphenate-character\":\"<string> | auto\",\"hyphenate-lines\":\"no-limit | <integer>\",\"hyphenate-resource\":1,hyphens:\"none | manual | auto\",icon:1,\"image-orientation\":\"angle | auto\",\"image-rendering\":1,\"image-resolution\":1,\"inline-box-align\":\"initial | last | <integer>\",\"justify-content\":\"flex-start | flex-end | center | space-between | space-around\",\"-webkit-justify-content\":\"flex-start | flex-end | center | space-between | space-around\",left:\"<margin-width> | inherit\",\"letter-spacing\":\"<length> | normal | inherit\",\"line-height\":\"<number> | <length> | <percentage> | normal | inherit\",\"line-break\":\"auto | loose | normal | strict\",\"line-stacking\":1,\"line-stacking-ruby\":\"exclude-ruby | include-ruby\",\"line-stacking-shift\":\"consider-shifts | disregard-shifts\",\"line-stacking-strategy\":\"inline-line-height | block-line-height | max-height | grid-height\",\"list-style\":1,\"list-style-image\":\"<uri> | none | inherit\",\"list-style-position\":\"inside | outside | inherit\",\"list-style-type\":\"disc | circle | square | decimal | decimal-leading-zero | lower-roman | upper-roman | lower-greek | lower-latin | upper-latin | armenian | georgian | lower-alpha | upper-alpha | none | inherit\",margin:{multi:\"<margin-width> | inherit\",max:4},\"margin-bottom\":\"<margin-width> | inherit\",\"margin-left\":\"<margin-width> | inherit\",\"margin-right\":\"<margin-width> | inherit\",\"margin-top\":\"<margin-width> | inherit\",mark:1,\"mark-after\":1,\"mark-before\":1,marks:1,\"marquee-direction\":1,\"marquee-play-count\":1,\"marquee-speed\":1,\"marquee-style\":1,\"max-height\":\"<length> | <percentage> | <content-sizing> | none | inherit\",\"max-width\":\"<length> | <percentage> | <content-sizing> | none | inherit\",\"min-height\":\"<length> | <percentage> | <content-sizing> | contain-floats | -moz-contain-floats | -webkit-contain-floats | inherit\",\"min-width\":\"<length> | <percentage> | <content-sizing> | contain-floats | -moz-contain-floats | -webkit-contain-floats | inherit\",\"move-to\":1,\"nav-down\":1,\"nav-index\":1,\"nav-left\":1,\"nav-right\":1,\"nav-up\":1,opacity:\"<number> | inherit\",order:\"<integer>\",\"-webkit-order\":\"<integer>\",orphans:\"<integer> | inherit\",outline:1,\"outline-color\":\"<color> | invert | inherit\",\"outline-offset\":1,\"outline-style\":\"<border-style> | inherit\",\"outline-width\":\"<border-width> | inherit\",overflow:\"visible | hidden | scroll | auto | inherit\",\"overflow-style\":1,\"overflow-wrap\":\"normal | break-word\",\"overflow-x\":1,\"overflow-y\":1,padding:{multi:\"<padding-width> | inherit\",max:4},\"padding-bottom\":\"<padding-width> | inherit\",\"padding-left\":\"<padding-width> | inherit\",\"padding-right\":\"<padding-width> | inherit\",\"padding-top\":\"<padding-width> | inherit\",page:1,\"page-break-after\":\"auto | always | avoid | left | right | inherit\",\"page-break-before\":\"auto | always | avoid | left | right | inherit\",\"page-break-inside\":\"auto | avoid | inherit\",\"page-policy\":1,pause:1,\"pause-after\":1,\"pause-before\":1,perspective:1,\"perspective-origin\":1,phonemes:1,pitch:1,\"pitch-range\":1,\"play-during\":1,\"pointer-events\":\"auto | none | visiblePainted | visibleFill | visibleStroke | visible | painted | fill | stroke | all | inherit\",position:\"static | relative | absolute | fixed | inherit\",\"presentation-level\":1,\"punctuation-trim\":1,quotes:1,\"rendering-intent\":1,resize:1,rest:1,\"rest-after\":1,\"rest-before\":1,richness:1,right:\"<margin-width> | inherit\",rotation:1,\"rotation-point\":1,\"ruby-align\":1,\"ruby-overhang\":1,\"ruby-position\":1,\"ruby-span\":1,size:1,speak:\"normal | none | spell-out | inherit\",\"speak-header\":\"once | always | inherit\",\"speak-numeral\":\"digits | continuous | inherit\",\"speak-punctuation\":\"code | none | inherit\",\"speech-rate\":1,src:1,stress:1,\"string-set\":1,\"table-layout\":\"auto | fixed | inherit\",\"tab-size\":\"<integer> | <length>\",target:1,\"target-name\":1,\"target-new\":1,\"target-position\":1,\"text-align\":\"left | right | center | justify | inherit\",\"text-align-last\":1,\"text-decoration\":1,\"text-emphasis\":1,\"text-height\":1,\"text-indent\":\"<length> | <percentage> | inherit\",\"text-justify\":\"auto | none | inter-word | inter-ideograph | inter-cluster | distribute | kashida\",\"text-outline\":1,\"text-overflow\":1,\"text-rendering\":\"auto | optimizeSpeed | optimizeLegibility | geometricPrecision | inherit\",\"text-shadow\":1,\"text-transform\":\"capitalize | uppercase | lowercase | none | inherit\",\"text-wrap\":\"normal | none | avoid\",top:\"<margin-width> | inherit\",\"-ms-touch-action\":\"auto | none | pan-x | pan-y\",\"touch-action\":\"auto | none | pan-x | pan-y\",transform:1,\"transform-origin\":1,\"transform-style\":1,transition:1,\"transition-delay\":1,\"transition-duration\":1,\"transition-property\":1,\"transition-timing-function\":1,\"unicode-bidi\":\"normal | embed | isolate | bidi-override | isolate-override | plaintext | inherit\",\"user-modify\":\"read-only | read-write | write-only | inherit\",\"user-select\":\"none | text | toggle | element | elements | all | inherit\",\"vertical-align\":\"auto | use-script | baseline | sub | super | top | text-top | central | middle | bottom | text-bottom | <percentage> | <length>\",visibility:\"visible | hidden | collapse | inherit\",\"voice-balance\":1,\"voice-duration\":1,\"voice-family\":1,\"voice-pitch\":1,\"voice-pitch-range\":1,\"voice-rate\":1,\"voice-stress\":1,\"voice-volume\":1,volume:1,\"white-space\":\"normal | pre | nowrap | pre-wrap | pre-line | inherit | -pre-wrap | -o-pre-wrap | -moz-pre-wrap | -hp-pre-wrap\",\"white-space-collapse\":1,widows:\"<integer> | inherit\",width:\"<length> | <percentage> | <content-sizing> | auto | inherit\",\"word-break\":\"normal | keep-all | break-all\",\"word-spacing\":\"<length> | normal | inherit\",\"word-wrap\":\"normal | break-word\",\"writing-mode\":\"horizontal-tb | vertical-rl | vertical-lr | lr-tb | rl-tb | tb-rl | bt-rl | tb-lr | bt-lr | lr-bt | rl-bt | lr | rl | tb | inherit\",\"z-index\":\"<integer> | auto | inherit\",zoom:\"<number> | <percentage> | normal\"};PropertyName.prototype=new SyntaxUnit,PropertyName.prototype.constructor=PropertyName,PropertyName.prototype.toString=function(){return(this.hack?this.hack:\"\")+this.text},PropertyValue.prototype=new SyntaxUnit,PropertyValue.prototype.constructor=PropertyValue,PropertyValueIterator.prototype.count=function(){return this._parts.length},PropertyValueIterator.prototype.isFirst=function(){return 0===this._i},PropertyValueIterator.prototype.hasNext=function(){return this._i<this._parts.length},PropertyValueIterator.prototype.mark=function(){this._marks.push(this._i)},PropertyValueIterator.prototype.peek=function(count){return this.hasNext()?this._parts[this._i+(count||0)]:null},PropertyValueIterator.prototype.next=function(){return this.hasNext()?this._parts[this._i++]:null},PropertyValueIterator.prototype.previous=function(){return this._i>0?this._parts[--this._i]:null},PropertyValueIterator.prototype.restore=function(){this._marks.length&&(this._i=this._marks.pop())},PropertyValuePart.prototype=new SyntaxUnit,PropertyValuePart.prototype.constructor=PropertyValuePart,PropertyValuePart.fromToken=function(token){return new PropertyValuePart(token.value,token.startLine,token.startCol)};var Pseudos={\":first-letter\":1,\":first-line\":1,\":before\":1,\":after\":1};Pseudos.ELEMENT=1,Pseudos.CLASS=2,Pseudos.isElement=function(pseudo){return 0===pseudo.indexOf(\"::\")||Pseudos[pseudo.toLowerCase()]==Pseudos.ELEMENT},Selector.prototype=new SyntaxUnit,Selector.prototype.constructor=Selector,SelectorPart.prototype=new SyntaxUnit,SelectorPart.prototype.constructor=SelectorPart,SelectorSubPart.prototype=new SyntaxUnit,SelectorSubPart.prototype.constructor=SelectorSubPart,Specificity.prototype={constructor:Specificity,compare:function(other){var i,len,comps=[\"a\",\"b\",\"c\",\"d\"];for(i=0,len=comps.length;len>i;i++){if(this[comps[i]]<other[comps[i]])return-1;if(this[comps[i]]>other[comps[i]])return 1}return 0},valueOf:function(){return 1e3*this.a+100*this.b+10*this.c+this.d},toString:function(){return this.a+\",\"+this.b+\",\"+this.c+\",\"+this.d}},Specificity.calculate=function(selector){function updateValues(part){var i,j,len,num,modifier,elementName=part.elementName?part.elementName.text:\"\";for(elementName&&\"*\"!=elementName.charAt(elementName.length-1)&&d++,i=0,len=part.modifiers.length;len>i;i++)switch(modifier=part.modifiers[i],modifier.type){case\"class\":case\"attribute\":c++;break;case\"id\":b++;break;case\"pseudo\":Pseudos.isElement(modifier.text)?d++:c++;break;case\"not\":for(j=0,num=modifier.args.length;num>j;j++)updateValues(modifier.args[j])}}var i,len,part,b=0,c=0,d=0;for(i=0,len=selector.parts.length;len>i;i++)part=selector.parts[i],part instanceof SelectorPart&&updateValues(part);return new Specificity(0,b,c,d)};var h=/^[0-9a-fA-F]$/,nonascii=/^[\\\\u0080-\\\\uFFFF]$/,nl=/\\\\n|\\\\r\\\\n|\\\\r|\\\\f/;TokenStream.prototype=mix(new TokenStreamBase,{_getToken:function(){var c,reader=this._reader,token=null,startLine=reader.getLine(),startCol=reader.getCol();for(c=reader.read();c;){switch(c){case\"/\":token=\"*\"==reader.peek()?this.commentToken(c,startLine,startCol):this.charToken(c,startLine,startCol);break;case\"|\":case\"~\":case\"^\":case\"$\":case\"*\":token=\"=\"==reader.peek()?this.comparisonToken(c,startLine,startCol):this.charToken(c,startLine,startCol);break;case\\'\"\\':case\"\\'\":token=this.stringToken(c,startLine,startCol);break;case\"#\":token=isNameChar(reader.peek())?this.hashToken(c,startLine,startCol):this.charToken(c,startLine,startCol);break;case\".\":token=isDigit(reader.peek())?this.numberToken(c,startLine,startCol):this.charToken(c,startLine,startCol);break;case\"-\":token=\"-\"==reader.peek()?this.htmlCommentEndToken(c,startLine,startCol):isNameStart(reader.peek())?this.identOrFunctionToken(c,startLine,startCol):this.charToken(c,startLine,startCol);break;case\"!\":token=this.importantToken(c,startLine,startCol);break;case\"@\":token=this.atRuleToken(c,startLine,startCol);break;case\":\":token=this.notToken(c,startLine,startCol);break;case\"<\":token=this.htmlCommentStartToken(c,startLine,startCol);break;case\"U\":case\"u\":if(\"+\"==reader.peek()){token=this.unicodeRangeToken(c,startLine,startCol);break}default:token=isDigit(c)?this.numberToken(c,startLine,startCol):isWhitespace(c)?this.whitespaceToken(c,startLine,startCol):isIdentStart(c)?this.identOrFunctionToken(c,startLine,startCol):this.charToken(c,startLine,startCol)}break}return token||null!==c||(token=this.createToken(Tokens.EOF,null,startLine,startCol)),token},createToken:function(tt,value,startLine,startCol,options){var reader=this._reader;return options=options||{},{value:value,type:tt,channel:options.channel,endChar:options.endChar,hide:options.hide||!1,startLine:startLine,startCol:startCol,endLine:reader.getLine(),endCol:reader.getCol()}},atRuleToken:function(first,startLine,startCol){var ident,rule=first,reader=this._reader,tt=Tokens.CHAR;return reader.mark(),ident=this.readName(),rule=first+ident,tt=Tokens.type(rule.toLowerCase()),(tt==Tokens.CHAR||tt==Tokens.UNKNOWN)&&(rule.length>1?tt=Tokens.UNKNOWN_SYM:(tt=Tokens.CHAR,rule=first,reader.reset())),this.createToken(tt,rule,startLine,startCol)},charToken:function(c,startLine,startCol){var tt=Tokens.type(c),opts={};return-1==tt?tt=Tokens.CHAR:opts.endChar=Tokens[tt].endChar,this.createToken(tt,c,startLine,startCol,opts)},commentToken:function(first,startLine,startCol){var comment=(this._reader,this.readComment(first));return this.createToken(Tokens.COMMENT,comment,startLine,startCol)},comparisonToken:function(c,startLine,startCol){var reader=this._reader,comparison=c+reader.read(),tt=Tokens.type(comparison)||Tokens.CHAR;return this.createToken(tt,comparison,startLine,startCol)\\n},hashToken:function(first,startLine,startCol){var name=(this._reader,this.readName(first));return this.createToken(Tokens.HASH,name,startLine,startCol)},htmlCommentStartToken:function(first,startLine,startCol){var reader=this._reader,text=first;return reader.mark(),text+=reader.readCount(3),\"\\x3c!--\"==text?this.createToken(Tokens.CDO,text,startLine,startCol):(reader.reset(),this.charToken(first,startLine,startCol))},htmlCommentEndToken:function(first,startLine,startCol){var reader=this._reader,text=first;return reader.mark(),text+=reader.readCount(2),\"--\\x3e\"==text?this.createToken(Tokens.CDC,text,startLine,startCol):(reader.reset(),this.charToken(first,startLine,startCol))},identOrFunctionToken:function(first,startLine,startCol){var reader=this._reader,ident=this.readName(first),tt=Tokens.IDENT;return\"(\"==reader.peek()?(ident+=reader.read(),\"url(\"==ident.toLowerCase()?(tt=Tokens.URI,ident=this.readURI(ident),\"url(\"==ident.toLowerCase()&&(tt=Tokens.FUNCTION)):tt=Tokens.FUNCTION):\":\"==reader.peek()&&\"progid\"==ident.toLowerCase()&&(ident+=reader.readTo(\"(\"),tt=Tokens.IE_FUNCTION),this.createToken(tt,ident,startLine,startCol)},importantToken:function(first,startLine,startCol){var temp,c,reader=this._reader,important=first,tt=Tokens.CHAR;for(reader.mark(),c=reader.read();c;){if(\"/\"==c){if(\"*\"!=reader.peek())break;if(temp=this.readComment(c),\"\"===temp)break}else{if(!isWhitespace(c)){if(/i/i.test(c)){temp=reader.readCount(8),/mportant/i.test(temp)&&(important+=c+temp,tt=Tokens.IMPORTANT_SYM);break}break}important+=c+this.readWhitespace()}c=reader.read()}return tt==Tokens.CHAR?(reader.reset(),this.charToken(first,startLine,startCol)):this.createToken(tt,important,startLine,startCol)},notToken:function(first,startLine,startCol){var reader=this._reader,text=first;return reader.mark(),text+=reader.readCount(4),\":not(\"==text.toLowerCase()?this.createToken(Tokens.NOT,text,startLine,startCol):(reader.reset(),this.charToken(first,startLine,startCol))},numberToken:function(first,startLine,startCol){var ident,reader=this._reader,value=this.readNumber(first),tt=Tokens.NUMBER,c=reader.peek();return isIdentStart(c)?(ident=this.readName(reader.read()),value+=ident,tt=/^em$|^ex$|^px$|^gd$|^rem$|^vw$|^vh$|^vmax$|^vmin$|^ch$|^cm$|^mm$|^in$|^pt$|^pc$/i.test(ident)?Tokens.LENGTH:/^deg|^rad$|^grad$/i.test(ident)?Tokens.ANGLE:/^ms$|^s$/i.test(ident)?Tokens.TIME:/^hz$|^khz$/i.test(ident)?Tokens.FREQ:/^dpi$|^dpcm$/i.test(ident)?Tokens.RESOLUTION:Tokens.DIMENSION):\"%\"==c&&(value+=reader.read(),tt=Tokens.PERCENTAGE),this.createToken(tt,value,startLine,startCol)},stringToken:function(first,startLine,startCol){for(var delim=first,string=first,reader=this._reader,prev=first,tt=Tokens.STRING,c=reader.read();c&&(string+=c,c!=delim||\"\\\\\\\\\"==prev);){if(isNewLine(reader.peek())&&\"\\\\\\\\\"!=c){tt=Tokens.INVALID;break}prev=c,c=reader.read()}return null===c&&(tt=Tokens.INVALID),this.createToken(tt,string,startLine,startCol)},unicodeRangeToken:function(first,startLine,startCol){var temp,reader=this._reader,value=first,tt=Tokens.CHAR;return\"+\"==reader.peek()&&(reader.mark(),value+=reader.read(),value+=this.readUnicodeRangePart(!0),2==value.length?reader.reset():(tt=Tokens.UNICODE_RANGE,-1==value.indexOf(\"?\")&&\"-\"==reader.peek()&&(reader.mark(),temp=reader.read(),temp+=this.readUnicodeRangePart(!1),1==temp.length?reader.reset():value+=temp))),this.createToken(tt,value,startLine,startCol)},whitespaceToken:function(first,startLine,startCol){var value=(this._reader,first+this.readWhitespace());return this.createToken(Tokens.S,value,startLine,startCol)},readUnicodeRangePart:function(allowQuestionMark){for(var reader=this._reader,part=\"\",c=reader.peek();isHexDigit(c)&&6>part.length;)reader.read(),part+=c,c=reader.peek();if(allowQuestionMark)for(;\"?\"==c&&6>part.length;)reader.read(),part+=c,c=reader.peek();return part},readWhitespace:function(){for(var reader=this._reader,whitespace=\"\",c=reader.peek();isWhitespace(c);)reader.read(),whitespace+=c,c=reader.peek();return whitespace},readNumber:function(first){for(var reader=this._reader,number=first,hasDot=\".\"==first,c=reader.peek();c;){if(isDigit(c))number+=reader.read();else{if(\".\"!=c)break;if(hasDot)break;hasDot=!0,number+=reader.read()}c=reader.peek()}return number},readString:function(){for(var reader=this._reader,delim=reader.read(),string=delim,prev=delim,c=reader.peek();c&&(c=reader.read(),string+=c,c!=delim||\"\\\\\\\\\"==prev);){if(isNewLine(reader.peek())&&\"\\\\\\\\\"!=c){string=\"\";break}prev=c,c=reader.peek()}return null===c&&(string=\"\"),string},readURI:function(first){var reader=this._reader,uri=first,inner=\"\",c=reader.peek();for(reader.mark();c&&isWhitespace(c);)reader.read(),c=reader.peek();for(inner=\"\\'\"==c||\\'\"\\'==c?this.readString():this.readURL(),c=reader.peek();c&&isWhitespace(c);)reader.read(),c=reader.peek();return\"\"===inner||\")\"!=c?(uri=first,reader.reset()):uri+=inner+reader.read(),uri},readURL:function(){for(var reader=this._reader,url=\"\",c=reader.peek();/^[!#$%&\\\\\\\\*-~]$/.test(c);)url+=reader.read(),c=reader.peek();return url},readName:function(first){for(var reader=this._reader,ident=first||\"\",c=reader.peek();;)if(\"\\\\\\\\\"==c)ident+=this.readEscape(reader.read()),c=reader.peek();else{if(!c||!isNameChar(c))break;ident+=reader.read(),c=reader.peek()}return ident},readEscape:function(first){var reader=this._reader,cssEscape=first||\"\",i=0,c=reader.peek();if(isHexDigit(c))do cssEscape+=reader.read(),c=reader.peek();while(c&&isHexDigit(c)&&6>++i);return 3==cssEscape.length&&/\\\\s/.test(c)||7==cssEscape.length||1==cssEscape.length?reader.read():c=\"\",cssEscape+c},readComment:function(first){var reader=this._reader,comment=first||\"\",c=reader.read();if(\"*\"==c){for(;c;){if(comment+=c,comment.length>2&&\"*\"==c&&\"/\"==reader.peek()){comment+=reader.read();break}c=reader.read()}return comment}return\"\"}});var Tokens=[{name:\"CDO\"},{name:\"CDC\"},{name:\"S\",whitespace:!0},{name:\"COMMENT\",comment:!0,hide:!0,channel:\"comment\"},{name:\"INCLUDES\",text:\"~=\"},{name:\"DASHMATCH\",text:\"|=\"},{name:\"PREFIXMATCH\",text:\"^=\"},{name:\"SUFFIXMATCH\",text:\"$=\"},{name:\"SUBSTRINGMATCH\",text:\"*=\"},{name:\"STRING\"},{name:\"IDENT\"},{name:\"HASH\"},{name:\"IMPORT_SYM\",text:\"@import\"},{name:\"PAGE_SYM\",text:\"@page\"},{name:\"MEDIA_SYM\",text:\"@media\"},{name:\"FONT_FACE_SYM\",text:\"@font-face\"},{name:\"CHARSET_SYM\",text:\"@charset\"},{name:\"NAMESPACE_SYM\",text:\"@namespace\"},{name:\"VIEWPORT_SYM\",text:[\"@viewport\",\"@-ms-viewport\"]},{name:\"UNKNOWN_SYM\"},{name:\"KEYFRAMES_SYM\",text:[\"@keyframes\",\"@-webkit-keyframes\",\"@-moz-keyframes\",\"@-o-keyframes\"]},{name:\"IMPORTANT_SYM\"},{name:\"LENGTH\"},{name:\"ANGLE\"},{name:\"TIME\"},{name:\"FREQ\"},{name:\"DIMENSION\"},{name:\"PERCENTAGE\"},{name:\"NUMBER\"},{name:\"URI\"},{name:\"FUNCTION\"},{name:\"UNICODE_RANGE\"},{name:\"INVALID\"},{name:\"PLUS\",text:\"+\"},{name:\"GREATER\",text:\">\"},{name:\"COMMA\",text:\",\"},{name:\"TILDE\",text:\"~\"},{name:\"NOT\"},{name:\"TOPLEFTCORNER_SYM\",text:\"@top-left-corner\"},{name:\"TOPLEFT_SYM\",text:\"@top-left\"},{name:\"TOPCENTER_SYM\",text:\"@top-center\"},{name:\"TOPRIGHT_SYM\",text:\"@top-right\"},{name:\"TOPRIGHTCORNER_SYM\",text:\"@top-right-corner\"},{name:\"BOTTOMLEFTCORNER_SYM\",text:\"@bottom-left-corner\"},{name:\"BOTTOMLEFT_SYM\",text:\"@bottom-left\"},{name:\"BOTTOMCENTER_SYM\",text:\"@bottom-center\"},{name:\"BOTTOMRIGHT_SYM\",text:\"@bottom-right\"},{name:\"BOTTOMRIGHTCORNER_SYM\",text:\"@bottom-right-corner\"},{name:\"LEFTTOP_SYM\",text:\"@left-top\"},{name:\"LEFTMIDDLE_SYM\",text:\"@left-middle\"},{name:\"LEFTBOTTOM_SYM\",text:\"@left-bottom\"},{name:\"RIGHTTOP_SYM\",text:\"@right-top\"},{name:\"RIGHTMIDDLE_SYM\",text:\"@right-middle\"},{name:\"RIGHTBOTTOM_SYM\",text:\"@right-bottom\"},{name:\"RESOLUTION\",state:\"media\"},{name:\"IE_FUNCTION\"},{name:\"CHAR\"},{name:\"PIPE\",text:\"|\"},{name:\"SLASH\",text:\"/\"},{name:\"MINUS\",text:\"-\"},{name:\"STAR\",text:\"*\"},{name:\"LBRACE\",endChar:\"}\",text:\"{\"},{name:\"RBRACE\",text:\"}\"},{name:\"LBRACKET\",endChar:\"]\",text:\"[\"},{name:\"RBRACKET\",text:\"]\"},{name:\"EQUALS\",text:\"=\"},{name:\"COLON\",text:\":\"},{name:\"SEMICOLON\",text:\";\"},{name:\"LPAREN\",endChar:\")\",text:\"(\"},{name:\"RPAREN\",text:\")\"},{name:\"DOT\",text:\".\"}];(function(){var nameMap=[],typeMap={};Tokens.UNKNOWN=-1,Tokens.unshift({name:\"EOF\"});for(var i=0,len=Tokens.length;len>i;i++)if(nameMap.push(Tokens[i].name),Tokens[Tokens[i].name]=i,Tokens[i].text)if(Tokens[i].text instanceof Array)for(var j=0;Tokens[i].text.length>j;j++)typeMap[Tokens[i].text[j]]=i;else typeMap[Tokens[i].text]=i;Tokens.name=function(tt){return nameMap[tt]},Tokens.type=function(c){return typeMap[c]||-1}})();var Validation={validate:function(property,value){var name=(\"\"+property).toLowerCase(),expression=(value.parts,new PropertyValueIterator(value)),spec=Properties[name];if(spec)\"number\"!=typeof spec&&(\"string\"==typeof spec?spec.indexOf(\"||\")>-1?this.groupProperty(spec,expression):this.singleProperty(spec,expression,1):spec.multi?this.multiProperty(spec.multi,expression,spec.comma,spec.max||1/0):\"function\"==typeof spec&&spec(expression));else if(0!==name.indexOf(\"-\"))throw new ValidationError(\"Unknown property \\'\"+property+\"\\'.\",property.line,property.col)},singleProperty:function(types,expression,max){for(var part,result=!1,value=expression.value,count=0;expression.hasNext()&&max>count&&(result=ValidationTypes.isAny(expression,types));)count++;if(!result)throw expression.hasNext()&&!expression.isFirst()?(part=expression.peek(),new ValidationError(\"Expected end of value but found \\'\"+part+\"\\'.\",part.line,part.col)):new ValidationError(\"Expected (\"+types+\") but found \\'\"+value+\"\\'.\",value.line,value.col);if(expression.hasNext())throw part=expression.next(),new ValidationError(\"Expected end of value but found \\'\"+part+\"\\'.\",part.line,part.col)},multiProperty:function(types,expression,comma,max){for(var part,result=!1,value=expression.value,count=0;expression.hasNext()&&!result&&max>count&&ValidationTypes.isAny(expression,types);)if(count++,expression.hasNext()){if(comma){if(\",\"!=expression.peek())break;part=expression.next()}}else result=!0;if(!result)throw expression.hasNext()&&!expression.isFirst()?(part=expression.peek(),new ValidationError(\"Expected end of value but found \\'\"+part+\"\\'.\",part.line,part.col)):(part=expression.previous(),comma&&\",\"==part?new ValidationError(\"Expected end of value but found \\'\"+part+\"\\'.\",part.line,part.col):new ValidationError(\"Expected (\"+types+\") but found \\'\"+value+\"\\'.\",value.line,value.col));if(expression.hasNext())throw part=expression.next(),new ValidationError(\"Expected end of value but found \\'\"+part+\"\\'.\",part.line,part.col)},groupProperty:function(types,expression){for(var name,part,result=!1,value=expression.value,typeCount=types.split(\"||\").length,groups={count:0},partial=!1;expression.hasNext()&&!result&&(name=ValidationTypes.isAnyOfGroup(expression,types))&&!groups[name];)groups[name]=1,groups.count++,partial=!0,groups.count!=typeCount&&expression.hasNext()||(result=!0);if(!result)throw partial&&expression.hasNext()?(part=expression.peek(),new ValidationError(\"Expected end of value but found \\'\"+part+\"\\'.\",part.line,part.col)):new ValidationError(\"Expected (\"+types+\") but found \\'\"+value+\"\\'.\",value.line,value.col);if(expression.hasNext())throw part=expression.next(),new ValidationError(\"Expected end of value but found \\'\"+part+\"\\'.\",part.line,part.col)}};ValidationError.prototype=Error();var ValidationTypes={isLiteral:function(part,literals){var i,len,text=(\"\"+part.text).toLowerCase(),args=literals.split(\" | \"),found=!1;for(i=0,len=args.length;len>i&&!found;i++)text==args[i].toLowerCase()&&(found=!0);return found},isSimple:function(type){return!!this.simple[type]},isComplex:function(type){return!!this.complex[type]},isAny:function(expression,types){var i,len,args=types.split(\" | \"),found=!1;for(i=0,len=args.length;len>i&&!found&&expression.hasNext();i++)found=this.isType(expression,args[i]);return found},isAnyOfGroup:function(expression,types){var i,len,args=types.split(\" || \"),found=!1;for(i=0,len=args.length;len>i&&!found;i++)found=this.isType(expression,args[i]);return found?args[i-1]:!1},isType:function(expression,type){var part=expression.peek(),result=!1;return\"<\"!=type.charAt(0)?(result=this.isLiteral(part,type),result&&expression.next()):this.simple[type]?(result=this.simple[type](part),result&&expression.next()):result=this.complex[type](expression),result},simple:{\"<absolute-size>\":function(part){return ValidationTypes.isLiteral(part,\"xx-small | x-small | small | medium | large | x-large | xx-large\")},\"<attachment>\":function(part){return ValidationTypes.isLiteral(part,\"scroll | fixed | local\")},\"<attr>\":function(part){return\"function\"==part.type&&\"attr\"==part.name},\"<bg-image>\":function(part){return this[\"<image>\"](part)||this[\"<gradient>\"](part)||\"none\"==part},\"<gradient>\":function(part){return\"function\"==part.type&&/^(?:\\\\-(?:ms|moz|o|webkit)\\\\-)?(?:repeating\\\\-)?(?:radial\\\\-|linear\\\\-)?gradient/i.test(part)},\"<box>\":function(part){return ValidationTypes.isLiteral(part,\"padding-box | border-box | content-box\")},\"<content>\":function(part){return\"function\"==part.type&&\"content\"==part.name},\"<relative-size>\":function(part){return ValidationTypes.isLiteral(part,\"smaller | larger\")},\"<ident>\":function(part){return\"identifier\"==part.type},\"<length>\":function(part){return\"function\"==part.type&&/^(?:\\\\-(?:ms|moz|o|webkit)\\\\-)?calc/i.test(part)?!0:\"length\"==part.type||\"number\"==part.type||\"integer\"==part.type||\"0\"==part},\"<color>\":function(part){return\"color\"==part.type||\"transparent\"==part},\"<number>\":function(part){return\"number\"==part.type||this[\"<integer>\"](part)},\"<integer>\":function(part){return\"integer\"==part.type},\"<line>\":function(part){return\"integer\"==part.type},\"<angle>\":function(part){return\"angle\"==part.type},\"<uri>\":function(part){return\"uri\"==part.type},\"<image>\":function(part){return this[\"<uri>\"](part)},\"<percentage>\":function(part){return\"percentage\"==part.type||\"0\"==part},\"<border-width>\":function(part){return this[\"<length>\"](part)||ValidationTypes.isLiteral(part,\"thin | medium | thick\")},\"<border-style>\":function(part){return ValidationTypes.isLiteral(part,\"none | hidden | dotted | dashed | solid | double | groove | ridge | inset | outset\")},\"<content-sizing>\":function(part){return ValidationTypes.isLiteral(part,\"fill-available | -moz-available | -webkit-fill-available | max-content | -moz-max-content | -webkit-max-content | min-content | -moz-min-content | -webkit-min-content | fit-content | -moz-fit-content | -webkit-fit-content\")},\"<margin-width>\":function(part){return this[\"<length>\"](part)||this[\"<percentage>\"](part)||ValidationTypes.isLiteral(part,\"auto\")},\"<padding-width>\":function(part){return this[\"<length>\"](part)||this[\"<percentage>\"](part)},\"<shape>\":function(part){return\"function\"==part.type&&(\"rect\"==part.name||\"inset-rect\"==part.name)},\"<time>\":function(part){return\"time\"==part.type},\"<flex-grow>\":function(part){return this[\"<number>\"](part)},\"<flex-shrink>\":function(part){return this[\"<number>\"](part)},\"<width>\":function(part){return this[\"<margin-width>\"](part)},\"<flex-basis>\":function(part){return this[\"<width>\"](part)},\"<flex-direction>\":function(part){return ValidationTypes.isLiteral(part,\"row | row-reverse | column | column-reverse\")},\"<flex-wrap>\":function(part){return ValidationTypes.isLiteral(part,\"nowrap | wrap | wrap-reverse\")}},complex:{\"<bg-position>\":function(expression){for(var result=!1,numeric=\"<percentage> | <length>\",xDir=\"left | right\",yDir=\"top | bottom\",count=0;expression.peek(count)&&\",\"!=expression.peek(count);)count++;return 3>count?ValidationTypes.isAny(expression,xDir+\" | center | \"+numeric)?(result=!0,ValidationTypes.isAny(expression,yDir+\" | center | \"+numeric)):ValidationTypes.isAny(expression,yDir)&&(result=!0,ValidationTypes.isAny(expression,xDir+\" | center\")):ValidationTypes.isAny(expression,xDir)?ValidationTypes.isAny(expression,yDir)?(result=!0,ValidationTypes.isAny(expression,numeric)):ValidationTypes.isAny(expression,numeric)&&(ValidationTypes.isAny(expression,yDir)?(result=!0,ValidationTypes.isAny(expression,numeric)):ValidationTypes.isAny(expression,\"center\")&&(result=!0)):ValidationTypes.isAny(expression,yDir)?ValidationTypes.isAny(expression,xDir)?(result=!0,ValidationTypes.isAny(expression,numeric)):ValidationTypes.isAny(expression,numeric)&&(ValidationTypes.isAny(expression,xDir)?(result=!0,ValidationTypes.isAny(expression,numeric)):ValidationTypes.isAny(expression,\"center\")&&(result=!0)):ValidationTypes.isAny(expression,\"center\")&&ValidationTypes.isAny(expression,xDir+\" | \"+yDir)&&(result=!0,ValidationTypes.isAny(expression,numeric)),result},\"<bg-size>\":function(expression){var result=!1,numeric=\"<percentage> | <length> | auto\";return ValidationTypes.isAny(expression,\"cover | contain\")?result=!0:ValidationTypes.isAny(expression,numeric)&&(result=!0,ValidationTypes.isAny(expression,numeric)),result},\"<repeat-style>\":function(expression){var part,result=!1,values=\"repeat | space | round | no-repeat\";return expression.hasNext()&&(part=expression.next(),ValidationTypes.isLiteral(part,\"repeat-x | repeat-y\")?result=!0:ValidationTypes.isLiteral(part,values)&&(result=!0,expression.hasNext()&&ValidationTypes.isLiteral(expression.peek(),values)&&expression.next())),result},\"<shadow>\":function(expression){var result=!1,count=0,inset=!1,color=!1;if(expression.hasNext()){for(ValidationTypes.isAny(expression,\"inset\")&&(inset=!0),ValidationTypes.isAny(expression,\"<color>\")&&(color=!0);ValidationTypes.isAny(expression,\"<length>\")&&4>count;)count++;expression.hasNext()&&(color||ValidationTypes.isAny(expression,\"<color>\"),inset||ValidationTypes.isAny(expression,\"inset\")),result=count>=2&&4>=count}return result},\"<x-one-radius>\":function(expression){var result=!1,simple=\"<length> | <percentage> | inherit\";return ValidationTypes.isAny(expression,simple)&&(result=!0,ValidationTypes.isAny(expression,simple)),result},\"<flex>\":function(expression){var part,result=!1;if(ValidationTypes.isAny(expression,\"none | inherit\")?result=!0:ValidationTypes.isType(expression,\"<flex-grow>\")?expression.peek()?ValidationTypes.isType(expression,\"<flex-shrink>\")?result=expression.peek()?ValidationTypes.isType(expression,\"<flex-basis>\"):!0:ValidationTypes.isType(expression,\"<flex-basis>\")&&(result=null===expression.peek()):result=!0:ValidationTypes.isType(expression,\"<flex-basis>\")&&(result=!0),!result)throw part=expression.peek(),new ValidationError(\"Expected (none | [ <flex-grow> <flex-shrink>? || <flex-basis> ]) but found \\'\"+expression.value.text+\"\\'.\",part.line,part.col);return result}}};parserlib.css={Colors:Colors,Combinator:Combinator,Parser:Parser,PropertyName:PropertyName,PropertyValue:PropertyValue,PropertyValuePart:PropertyValuePart,MediaFeature:MediaFeature,MediaQuery:MediaQuery,Selector:Selector,SelectorPart:SelectorPart,SelectorSubPart:SelectorSubPart,Specificity:Specificity,TokenStream:TokenStream,Tokens:Tokens,ValidationError:ValidationError}}(),function(){for(var prop in parserlib)exports[prop]=parserlib[prop]}();var util={isArray:function(ar){return Array.isArray(ar)||\"object\"==typeof ar&&\"[object Array]\"===objectToString(ar)},isDate:function(d){return\"object\"==typeof d&&\"[object Date]\"===objectToString(d)},isRegExp:function(re){return\"object\"==typeof re&&\"[object RegExp]\"===objectToString(re)},getRegExpFlags:function(re){var flags=\"\";return re.global&&(flags+=\"g\"),re.ignoreCase&&(flags+=\"i\"),re.multiline&&(flags+=\"m\"),flags}};\"object\"==typeof module&&(module.exports=clone),clone.clonePrototype=function(parent){if(null===parent)return null;var c=function(){};return c.prototype=parent,new c};var CSSLint=function(){function applyEmbeddedRuleset(text,ruleset){var valueMap,embedded=text&&text.match(embeddedRuleset),rules=embedded&&embedded[1];return rules&&(valueMap={\"true\":2,\"\":1,\"false\":0,2:2,1:1,0:0},rules.toLowerCase().split(\",\").forEach(function(rule){var pair=rule.split(\":\"),property=pair[0]||\"\",value=pair[1]||\"\";ruleset[property.trim()]=valueMap[value.trim()]})),ruleset}var rules=[],formatters=[],embeddedRuleset=/\\\\/\\\\*csslint([^\\\\*]*)\\\\*\\\\//,api=new parserlib.util.EventTarget;return api.version=\"@VERSION@\",api.addRule=function(rule){rules.push(rule),rules[rule.id]=rule},api.clearRules=function(){rules=[]},api.getRules=function(){return[].concat(rules).sort(function(a,b){return a.id>b.id?1:0})},api.getRuleset=function(){for(var ruleset={},i=0,len=rules.length;len>i;)ruleset[rules[i++].id]=1;return ruleset},api.addFormatter=function(formatter){formatters[formatter.id]=formatter},api.getFormatter=function(formatId){return formatters[formatId]},api.format=function(results,filename,formatId,options){var formatter=this.getFormatter(formatId),result=null;return formatter&&(result=formatter.startFormat(),result+=formatter.formatResults(results,filename,options||{}),result+=formatter.endFormat()),result},api.hasFormat=function(formatId){return formatters.hasOwnProperty(formatId)},api.verify=function(text,ruleset){var reporter,lines,report,i=0,parser=new parserlib.css.Parser({starHack:!0,ieFilters:!0,underscoreHack:!0,strict:!1});lines=text.replace(/\\\\n\\\\r?/g,\"$split$\").split(\"$split$\"),ruleset||(ruleset=this.getRuleset()),embeddedRuleset.test(text)&&(ruleset=clone(ruleset),ruleset=applyEmbeddedRuleset(text,ruleset)),reporter=new Reporter(lines,ruleset),ruleset.errors=2;for(i in ruleset)ruleset.hasOwnProperty(i)&&ruleset[i]&&rules[i]&&rules[i].init(parser,reporter);try{parser.parse(text)}catch(ex){reporter.error(\"Fatal error, cannot continue: \"+ex.message,ex.line,ex.col,{})}return report={messages:reporter.messages,stats:reporter.stats,ruleset:reporter.ruleset},report.messages.sort(function(a,b){return a.rollup&&!b.rollup?1:!a.rollup&&b.rollup?-1:a.line-b.line}),report},api}();Reporter.prototype={constructor:Reporter,error:function(message,line,col,rule){this.messages.push({type:\"error\",line:line,col:col,message:message,evidence:this.lines[line-1],rule:rule||{}})},warn:function(message,line,col,rule){this.report(message,line,col,rule)},report:function(message,line,col,rule){this.messages.push({type:2===this.ruleset[rule.id]?\"error\":\"warning\",line:line,col:col,message:message,evidence:this.lines[line-1],rule:rule})},info:function(message,line,col,rule){this.messages.push({type:\"info\",line:line,col:col,message:message,evidence:this.lines[line-1],rule:rule})},rollupError:function(message,rule){this.messages.push({type:\"error\",rollup:!0,message:message,rule:rule})},rollupWarn:function(message,rule){this.messages.push({type:\"warning\",rollup:!0,message:message,rule:rule})},stat:function(name,value){this.stats[name]=value}},CSSLint._Reporter=Reporter,CSSLint.Util={mix:function(receiver,supplier){var prop;for(prop in supplier)supplier.hasOwnProperty(prop)&&(receiver[prop]=supplier[prop]);return prop},indexOf:function(values,value){if(values.indexOf)return values.indexOf(value);for(var i=0,len=values.length;len>i;i++)if(values[i]===value)return i;return-1},forEach:function(values,func){if(values.forEach)return values.forEach(func);for(var i=0,len=values.length;len>i;i++)func(values[i],i,values)}},CSSLint.addRule({id:\"adjoining-classes\",name:\"Disallow adjoining classes\",desc:\"Don\\'t use adjoining classes.\",browsers:\"IE6\",init:function(parser,reporter){var rule=this;parser.addListener(\"startrule\",function(event){var selector,part,modifier,classCount,i,j,k,selectors=event.selectors;for(i=0;selectors.length>i;i++)for(selector=selectors[i],j=0;selector.parts.length>j;j++)if(part=selector.parts[j],part.type===parser.SELECTOR_PART_TYPE)for(classCount=0,k=0;part.modifiers.length>k;k++)modifier=part.modifiers[k],\"class\"===modifier.type&&classCount++,classCount>1&&reporter.report(\"Don\\'t use adjoining classes.\",part.line,part.col,rule)})}}),CSSLint.addRule({id:\"box-model\",name:\"Beware of broken box size\",desc:\"Don\\'t use width or height when using padding or border.\",browsers:\"All\",init:function(parser,reporter){function startRule(){properties={},boxSizing=!1}function endRule(){var prop,value;if(!boxSizing){if(properties.height)for(prop in heightProperties)heightProperties.hasOwnProperty(prop)&&properties[prop]&&(value=properties[prop].value,(\"padding\"!==prop||2!==value.parts.length||0!==value.parts[0].value)&&reporter.report(\"Using height with \"+prop+\" can sometimes make elements larger than you expect.\",properties[prop].line,properties[prop].col,rule));if(properties.width)for(prop in widthProperties)widthProperties.hasOwnProperty(prop)&&properties[prop]&&(value=properties[prop].value,(\"padding\"!==prop||2!==value.parts.length||0!==value.parts[1].value)&&reporter.report(\"Using width with \"+prop+\" can sometimes make elements larger than you expect.\",properties[prop].line,properties[prop].col,rule))}}var properties,rule=this,widthProperties={border:1,\"border-left\":1,\"border-right\":1,padding:1,\"padding-left\":1,\"padding-right\":1},heightProperties={border:1,\"border-bottom\":1,\"border-top\":1,padding:1,\"padding-bottom\":1,\"padding-top\":1},boxSizing=!1;parser.addListener(\"startrule\",startRule),parser.addListener(\"startfontface\",startRule),parser.addListener(\"startpage\",startRule),parser.addListener(\"startpagemargin\",startRule),parser.addListener(\"startkeyframerule\",startRule),parser.addListener(\"property\",function(event){var name=event.property.text.toLowerCase();heightProperties[name]||widthProperties[name]?/^0\\\\S*$/.test(event.value)||\"border\"===name&&\"none\"==\"\"+event.value||(properties[name]={line:event.property.line,col:event.property.col,value:event.value}):/^(width|height)/i.test(name)&&/^(length|percentage)/.test(event.value.parts[0].type)?properties[name]=1:\"box-sizing\"===name&&(boxSizing=!0)}),parser.addListener(\"endrule\",endRule),parser.addListener(\"endfontface\",endRule),parser.addListener(\"endpage\",endRule),parser.addListener(\"endpagemargin\",endRule),parser.addListener(\"endkeyframerule\",endRule)}}),CSSLint.addRule({id:\"box-sizing\",name:\"Disallow use of box-sizing\",desc:\"The box-sizing properties isn\\'t supported in IE6 and IE7.\",browsers:\"IE6, IE7\",tags:[\"Compatibility\"],init:function(parser,reporter){var rule=this;parser.addListener(\"property\",function(event){var name=event.property.text.toLowerCase();\"box-sizing\"===name&&reporter.report(\"The box-sizing property isn\\'t supported in IE6 and IE7.\",event.line,event.col,rule)})}}),CSSLint.addRule({id:\"bulletproof-font-face\",name:\"Use the bulletproof @font-face syntax\",desc:\"Use the bulletproof @font-face syntax to avoid 404\\'s in old IE (http://www.fontspring.com/blog/the-new-bulletproof-font-face-syntax).\",browsers:\"All\",init:function(parser,reporter){var line,col,rule=this,fontFaceRule=!1,firstSrc=!0,ruleFailed=!1;parser.addListener(\"startfontface\",function(){fontFaceRule=!0}),parser.addListener(\"property\",function(event){if(fontFaceRule){var propertyName=(\"\"+event.property).toLowerCase(),value=\"\"+event.value;if(line=event.line,col=event.col,\"src\"===propertyName){var regex=/^\\\\s?url\\\\([\\'\"].+\\\\.eot\\\\?.*[\\'\"]\\\\)\\\\s*format\\\\([\\'\"]embedded-opentype[\\'\"]\\\\).*$/i;!value.match(regex)&&firstSrc?(ruleFailed=!0,firstSrc=!1):value.match(regex)&&!firstSrc&&(ruleFailed=!1)}}}),parser.addListener(\"endfontface\",function(){fontFaceRule=!1,ruleFailed&&reporter.report(\"@font-face declaration doesn\\'t follow the fontspring bulletproof syntax.\",line,col,rule)})}}),CSSLint.addRule({id:\"compatible-vendor-prefixes\",name:\"Require compatible vendor prefixes\",desc:\"Include all compatible vendor prefixes to reach a wider range of users.\",browsers:\"All\",init:function(parser,reporter){var compatiblePrefixes,properties,prop,variations,prefixed,i,len,rule=this,inKeyFrame=!1,arrayPush=Array.prototype.push,applyTo=[];compatiblePrefixes={animation:\"webkit moz\",\"animation-delay\":\"webkit moz\",\"animation-direction\":\"webkit moz\",\"animation-duration\":\"webkit moz\",\"animation-fill-mode\":\"webkit moz\",\"animation-iteration-count\":\"webkit moz\",\"animation-name\":\"webkit moz\",\"animation-play-state\":\"webkit moz\",\"animation-timing-function\":\"webkit moz\",appearance:\"webkit moz\",\"border-end\":\"webkit moz\",\"border-end-color\":\"webkit moz\",\"border-end-style\":\"webkit moz\",\"border-end-width\":\"webkit moz\",\"border-image\":\"webkit moz o\",\"border-radius\":\"webkit\",\"border-start\":\"webkit moz\",\"border-start-color\":\"webkit moz\",\"border-start-style\":\"webkit moz\",\"border-start-width\":\"webkit moz\",\"box-align\":\"webkit moz ms\",\"box-direction\":\"webkit moz ms\",\"box-flex\":\"webkit moz ms\",\"box-lines\":\"webkit ms\",\"box-ordinal-group\":\"webkit moz ms\",\"box-orient\":\"webkit moz ms\",\"box-pack\":\"webkit moz ms\",\"box-sizing\":\"webkit moz\",\"box-shadow\":\"webkit moz\",\"column-count\":\"webkit moz ms\",\"column-gap\":\"webkit moz ms\",\"column-rule\":\"webkit moz ms\",\"column-rule-color\":\"webkit moz ms\",\"column-rule-style\":\"webkit moz ms\",\"column-rule-width\":\"webkit moz ms\",\"column-width\":\"webkit moz ms\",hyphens:\"epub moz\",\"line-break\":\"webkit ms\",\"margin-end\":\"webkit moz\",\"margin-start\":\"webkit moz\",\"marquee-speed\":\"webkit wap\",\"marquee-style\":\"webkit wap\",\"padding-end\":\"webkit moz\",\"padding-start\":\"webkit moz\",\"tab-size\":\"moz o\",\"text-size-adjust\":\"webkit ms\",transform:\"webkit moz ms o\",\"transform-origin\":\"webkit moz ms o\",transition:\"webkit moz o\",\"transition-delay\":\"webkit moz o\",\"transition-duration\":\"webkit moz o\",\"transition-property\":\"webkit moz o\",\"transition-timing-function\":\"webkit moz o\",\"user-modify\":\"webkit moz\",\"user-select\":\"webkit moz ms\",\"word-break\":\"epub ms\",\"writing-mode\":\"epub ms\"};for(prop in compatiblePrefixes)if(compatiblePrefixes.hasOwnProperty(prop)){for(variations=[],prefixed=compatiblePrefixes[prop].split(\" \"),i=0,len=prefixed.length;len>i;i++)variations.push(\"-\"+prefixed[i]+\"-\"+prop);compatiblePrefixes[prop]=variations,arrayPush.apply(applyTo,variations)}parser.addListener(\"startrule\",function(){properties=[]}),parser.addListener(\"startkeyframes\",function(event){inKeyFrame=event.prefix||!0}),parser.addListener(\"endkeyframes\",function(){inKeyFrame=!1}),parser.addListener(\"property\",function(event){var name=event.property;CSSLint.Util.indexOf(applyTo,name.text)>-1&&(inKeyFrame&&\"string\"==typeof inKeyFrame&&0===name.text.indexOf(\"-\"+inKeyFrame+\"-\")||properties.push(name))}),parser.addListener(\"endrule\",function(){if(properties.length){var i,len,name,prop,variations,value,full,actual,item,propertiesSpecified,propertyGroups={};for(i=0,len=properties.length;len>i;i++){name=properties[i];for(prop in compatiblePrefixes)compatiblePrefixes.hasOwnProperty(prop)&&(variations=compatiblePrefixes[prop],CSSLint.Util.indexOf(variations,name.text)>-1&&(propertyGroups[prop]||(propertyGroups[prop]={full:variations.slice(0),actual:[],actualNodes:[]}),-1===CSSLint.Util.indexOf(propertyGroups[prop].actual,name.text)&&(propertyGroups[prop].actual.push(name.text),propertyGroups[prop].actualNodes.push(name))))}for(prop in propertyGroups)if(propertyGroups.hasOwnProperty(prop)&&(value=propertyGroups[prop],full=value.full,actual=value.actual,full.length>actual.length))for(i=0,len=full.length;len>i;i++)item=full[i],-1===CSSLint.Util.indexOf(actual,item)&&(propertiesSpecified=1===actual.length?actual[0]:2===actual.length?actual.join(\" and \"):actual.join(\", \"),reporter.report(\"The property \"+item+\" is compatible with \"+propertiesSpecified+\" and should be included as well.\",value.actualNodes[0].line,value.actualNodes[0].col,rule))}})}}),CSSLint.addRule({id:\"display-property-grouping\",name:\"Require properties appropriate for display\",desc:\"Certain properties shouldn\\'t be used with certain display property values.\",browsers:\"All\",init:function(parser,reporter){function reportProperty(name,display,msg){properties[name]&&(\"string\"!=typeof propertiesToCheck[name]||properties[name].value.toLowerCase()!==propertiesToCheck[name])&&reporter.report(msg||name+\" can\\'t be used with display: \"+display+\".\",properties[name].line,properties[name].col,rule)}function startRule(){properties={}}function endRule(){var display=properties.display?properties.display.value:null;if(display)switch(display){case\"inline\":reportProperty(\"height\",display),reportProperty(\"width\",display),reportProperty(\"margin\",display),reportProperty(\"margin-top\",display),reportProperty(\"margin-bottom\",display),reportProperty(\"float\",display,\"display:inline has no effect on floated elements (but may be used to fix the IE6 double-margin bug).\");break;case\"block\":reportProperty(\"vertical-align\",display);\\nbreak;case\"inline-block\":reportProperty(\"float\",display);break;default:0===display.indexOf(\"table-\")&&(reportProperty(\"margin\",display),reportProperty(\"margin-left\",display),reportProperty(\"margin-right\",display),reportProperty(\"margin-top\",display),reportProperty(\"margin-bottom\",display),reportProperty(\"float\",display))}}var properties,rule=this,propertiesToCheck={display:1,\"float\":\"none\",height:1,width:1,margin:1,\"margin-left\":1,\"margin-right\":1,\"margin-bottom\":1,\"margin-top\":1,padding:1,\"padding-left\":1,\"padding-right\":1,\"padding-bottom\":1,\"padding-top\":1,\"vertical-align\":1};parser.addListener(\"startrule\",startRule),parser.addListener(\"startfontface\",startRule),parser.addListener(\"startkeyframerule\",startRule),parser.addListener(\"startpagemargin\",startRule),parser.addListener(\"startpage\",startRule),parser.addListener(\"property\",function(event){var name=event.property.text.toLowerCase();propertiesToCheck[name]&&(properties[name]={value:event.value.text,line:event.property.line,col:event.property.col})}),parser.addListener(\"endrule\",endRule),parser.addListener(\"endfontface\",endRule),parser.addListener(\"endkeyframerule\",endRule),parser.addListener(\"endpagemargin\",endRule),parser.addListener(\"endpage\",endRule)}}),CSSLint.addRule({id:\"duplicate-background-images\",name:\"Disallow duplicate background images\",desc:\"Every background-image should be unique. Use a common class for e.g. sprites.\",browsers:\"All\",init:function(parser,reporter){var rule=this,stack={};parser.addListener(\"property\",function(event){var i,len,name=event.property.text,value=event.value;if(name.match(/background/i))for(i=0,len=value.parts.length;len>i;i++)\"uri\"===value.parts[i].type&&(stack[value.parts[i].uri]===void 0?stack[value.parts[i].uri]=event:reporter.report(\"Background image \\'\"+value.parts[i].uri+\"\\' was used multiple times, first declared at line \"+stack[value.parts[i].uri].line+\", col \"+stack[value.parts[i].uri].col+\".\",event.line,event.col,rule))})}}),CSSLint.addRule({id:\"duplicate-properties\",name:\"Disallow duplicate properties\",desc:\"Duplicate properties must appear one after the other.\",browsers:\"All\",init:function(parser,reporter){function startRule(){properties={}}var properties,lastProperty,rule=this;parser.addListener(\"startrule\",startRule),parser.addListener(\"startfontface\",startRule),parser.addListener(\"startpage\",startRule),parser.addListener(\"startpagemargin\",startRule),parser.addListener(\"startkeyframerule\",startRule),parser.addListener(\"property\",function(event){var property=event.property,name=property.text.toLowerCase();!properties[name]||lastProperty===name&&properties[name]!==event.value.text||reporter.report(\"Duplicate property \\'\"+event.property+\"\\' found.\",event.line,event.col,rule),properties[name]=event.value.text,lastProperty=name})}}),CSSLint.addRule({id:\"empty-rules\",name:\"Disallow empty rules\",desc:\"Rules without any properties specified should be removed.\",browsers:\"All\",init:function(parser,reporter){var rule=this,count=0;parser.addListener(\"startrule\",function(){count=0}),parser.addListener(\"property\",function(){count++}),parser.addListener(\"endrule\",function(event){var selectors=event.selectors;0===count&&reporter.report(\"Rule is empty.\",selectors[0].line,selectors[0].col,rule)})}}),CSSLint.addRule({id:\"errors\",name:\"Parsing Errors\",desc:\"This rule looks for recoverable syntax errors.\",browsers:\"All\",init:function(parser,reporter){var rule=this;parser.addListener(\"error\",function(event){reporter.error(event.message,event.line,event.col,rule)})}}),CSSLint.addRule({id:\"fallback-colors\",name:\"Require fallback colors\",desc:\"For older browsers that don\\'t support RGBA, HSL, or HSLA, provide a fallback color.\",browsers:\"IE6,IE7,IE8\",init:function(parser,reporter){function startRule(){properties={},lastProperty=null}var lastProperty,properties,rule=this,propertiesToCheck={color:1,background:1,\"border-color\":1,\"border-top-color\":1,\"border-right-color\":1,\"border-bottom-color\":1,\"border-left-color\":1,border:1,\"border-top\":1,\"border-right\":1,\"border-bottom\":1,\"border-left\":1,\"background-color\":1};parser.addListener(\"startrule\",startRule),parser.addListener(\"startfontface\",startRule),parser.addListener(\"startpage\",startRule),parser.addListener(\"startpagemargin\",startRule),parser.addListener(\"startkeyframerule\",startRule),parser.addListener(\"property\",function(event){var property=event.property,name=property.text.toLowerCase(),parts=event.value.parts,i=0,colorType=\"\",len=parts.length;if(propertiesToCheck[name])for(;len>i;)\"color\"===parts[i].type&&(\"alpha\"in parts[i]||\"hue\"in parts[i]?(/([^\\\\)]+)\\\\(/.test(parts[i])&&(colorType=RegExp.$1.toUpperCase()),lastProperty&&lastProperty.property.text.toLowerCase()===name&&\"compat\"===lastProperty.colorType||reporter.report(\"Fallback \"+name+\" (hex or RGB) should precede \"+colorType+\" \"+name+\".\",event.line,event.col,rule)):event.colorType=\"compat\"),i++;lastProperty=event})}}),CSSLint.addRule({id:\"floats\",name:\"Disallow too many floats\",desc:\"This rule tests if the float property is used too many times\",browsers:\"All\",init:function(parser,reporter){var rule=this,count=0;parser.addListener(\"property\",function(event){\"float\"===event.property.text.toLowerCase()&&\"none\"!==event.value.text.toLowerCase()&&count++}),parser.addListener(\"endstylesheet\",function(){reporter.stat(\"floats\",count),count>=10&&reporter.rollupWarn(\"Too many floats (\"+count+\"), you\\'re probably using them for layout. Consider using a grid system instead.\",rule)})}}),CSSLint.addRule({id:\"font-faces\",name:\"Don\\'t use too many web fonts\",desc:\"Too many different web fonts in the same stylesheet.\",browsers:\"All\",init:function(parser,reporter){var rule=this,count=0;parser.addListener(\"startfontface\",function(){count++}),parser.addListener(\"endstylesheet\",function(){count>5&&reporter.rollupWarn(\"Too many @font-face declarations (\"+count+\").\",rule)})}}),CSSLint.addRule({id:\"font-sizes\",name:\"Disallow too many font sizes\",desc:\"Checks the number of font-size declarations.\",browsers:\"All\",init:function(parser,reporter){var rule=this,count=0;parser.addListener(\"property\",function(event){\"font-size\"==\"\"+event.property&&count++}),parser.addListener(\"endstylesheet\",function(){reporter.stat(\"font-sizes\",count),count>=10&&reporter.rollupWarn(\"Too many font-size declarations (\"+count+\"), abstraction needed.\",rule)})}}),CSSLint.addRule({id:\"gradients\",name:\"Require all gradient definitions\",desc:\"When using a vendor-prefixed gradient, make sure to use them all.\",browsers:\"All\",init:function(parser,reporter){var gradients,rule=this;parser.addListener(\"startrule\",function(){gradients={moz:0,webkit:0,oldWebkit:0,o:0}}),parser.addListener(\"property\",function(event){/\\\\-(moz|o|webkit)(?:\\\\-(?:linear|radial))\\\\-gradient/i.test(event.value)?gradients[RegExp.$1]=1:/\\\\-webkit\\\\-gradient/i.test(event.value)&&(gradients.oldWebkit=1)}),parser.addListener(\"endrule\",function(event){var missing=[];gradients.moz||missing.push(\"Firefox 3.6+\"),gradients.webkit||missing.push(\"Webkit (Safari 5+, Chrome)\"),gradients.oldWebkit||missing.push(\"Old Webkit (Safari 4+, Chrome)\"),gradients.o||missing.push(\"Opera 11.1+\"),missing.length&&4>missing.length&&reporter.report(\"Missing vendor-prefixed CSS gradients for \"+missing.join(\", \")+\".\",event.selectors[0].line,event.selectors[0].col,rule)})}}),CSSLint.addRule({id:\"ids\",name:\"Disallow IDs in selectors\",desc:\"Selectors should not contain IDs.\",browsers:\"All\",init:function(parser,reporter){var rule=this;parser.addListener(\"startrule\",function(event){var selector,part,modifier,idCount,i,j,k,selectors=event.selectors;for(i=0;selectors.length>i;i++){for(selector=selectors[i],idCount=0,j=0;selector.parts.length>j;j++)if(part=selector.parts[j],part.type===parser.SELECTOR_PART_TYPE)for(k=0;part.modifiers.length>k;k++)modifier=part.modifiers[k],\"id\"===modifier.type&&idCount++;1===idCount?reporter.report(\"Don\\'t use IDs in selectors.\",selector.line,selector.col,rule):idCount>1&&reporter.report(idCount+\" IDs in the selector, really?\",selector.line,selector.col,rule)}})}}),CSSLint.addRule({id:\"import\",name:\"Disallow @import\",desc:\"Don\\'t use @import, use <link> instead.\",browsers:\"All\",init:function(parser,reporter){var rule=this;parser.addListener(\"import\",function(event){reporter.report(\"@import prevents parallel downloads, use <link> instead.\",event.line,event.col,rule)})}}),CSSLint.addRule({id:\"important\",name:\"Disallow !important\",desc:\"Be careful when using !important declaration\",browsers:\"All\",init:function(parser,reporter){var rule=this,count=0;parser.addListener(\"property\",function(event){event.important===!0&&(count++,reporter.report(\"Use of !important\",event.line,event.col,rule))}),parser.addListener(\"endstylesheet\",function(){reporter.stat(\"important\",count),count>=10&&reporter.rollupWarn(\"Too many !important declarations (\"+count+\"), try to use less than 10 to avoid specificity issues.\",rule)})}}),CSSLint.addRule({id:\"known-properties\",name:\"Require use of known properties\",desc:\"Properties should be known (listed in CSS3 specification) or be a vendor-prefixed property.\",browsers:\"All\",init:function(parser,reporter){var rule=this;parser.addListener(\"property\",function(event){event.invalid&&reporter.report(event.invalid.message,event.line,event.col,rule)})}}),CSSLint.addRule({id:\"order-alphabetical\",name:\"Alphabetical order\",desc:\"Assure properties are in alphabetical order\",browsers:\"All\",init:function(parser,reporter){var properties,rule=this,startRule=function(){properties=[]};parser.addListener(\"startrule\",startRule),parser.addListener(\"startfontface\",startRule),parser.addListener(\"startpage\",startRule),parser.addListener(\"startpagemargin\",startRule),parser.addListener(\"startkeyframerule\",startRule),parser.addListener(\"property\",function(event){var name=event.property.text,lowerCasePrefixLessName=name.toLowerCase().replace(/^-.*?-/,\"\");properties.push(lowerCasePrefixLessName)}),parser.addListener(\"endrule\",function(event){var currentProperties=properties.join(\",\"),expectedProperties=properties.sort().join(\",\");currentProperties!==expectedProperties&&reporter.report(\"Rule doesn\\'t have all its properties in alphabetical ordered.\",event.line,event.col,rule)})}}),CSSLint.addRule({id:\"outline-none\",name:\"Disallow outline: none\",desc:\"Use of outline: none or outline: 0 should be limited to :focus rules.\",browsers:\"All\",tags:[\"Accessibility\"],init:function(parser,reporter){function startRule(event){lastRule=event.selectors?{line:event.line,col:event.col,selectors:event.selectors,propCount:0,outline:!1}:null}function endRule(){lastRule&&lastRule.outline&&(-1===(\"\"+lastRule.selectors).toLowerCase().indexOf(\":focus\")?reporter.report(\"Outlines should only be modified using :focus.\",lastRule.line,lastRule.col,rule):1===lastRule.propCount&&reporter.report(\"Outlines shouldn\\'t be hidden unless other visual changes are made.\",lastRule.line,lastRule.col,rule))}var lastRule,rule=this;parser.addListener(\"startrule\",startRule),parser.addListener(\"startfontface\",startRule),parser.addListener(\"startpage\",startRule),parser.addListener(\"startpagemargin\",startRule),parser.addListener(\"startkeyframerule\",startRule),parser.addListener(\"property\",function(event){var name=event.property.text.toLowerCase(),value=event.value;lastRule&&(lastRule.propCount++,\"outline\"!==name||\"none\"!=\"\"+value&&\"0\"!=\"\"+value||(lastRule.outline=!0))}),parser.addListener(\"endrule\",endRule),parser.addListener(\"endfontface\",endRule),parser.addListener(\"endpage\",endRule),parser.addListener(\"endpagemargin\",endRule),parser.addListener(\"endkeyframerule\",endRule)}}),CSSLint.addRule({id:\"overqualified-elements\",name:\"Disallow overqualified elements\",desc:\"Don\\'t use classes or IDs with elements (a.foo or a#foo).\",browsers:\"All\",init:function(parser,reporter){var rule=this,classes={};parser.addListener(\"startrule\",function(event){var selector,part,modifier,i,j,k,selectors=event.selectors;for(i=0;selectors.length>i;i++)for(selector=selectors[i],j=0;selector.parts.length>j;j++)if(part=selector.parts[j],part.type===parser.SELECTOR_PART_TYPE)for(k=0;part.modifiers.length>k;k++)modifier=part.modifiers[k],part.elementName&&\"id\"===modifier.type?reporter.report(\"Element (\"+part+\") is overqualified, just use \"+modifier+\" without element name.\",part.line,part.col,rule):\"class\"===modifier.type&&(classes[modifier]||(classes[modifier]=[]),classes[modifier].push({modifier:modifier,part:part}))}),parser.addListener(\"endstylesheet\",function(){var prop;for(prop in classes)classes.hasOwnProperty(prop)&&1===classes[prop].length&&classes[prop][0].part.elementName&&reporter.report(\"Element (\"+classes[prop][0].part+\") is overqualified, just use \"+classes[prop][0].modifier+\" without element name.\",classes[prop][0].part.line,classes[prop][0].part.col,rule)})}}),CSSLint.addRule({id:\"qualified-headings\",name:\"Disallow qualified headings\",desc:\"Headings should not be qualified (namespaced).\",browsers:\"All\",init:function(parser,reporter){var rule=this;parser.addListener(\"startrule\",function(event){var selector,part,i,j,selectors=event.selectors;for(i=0;selectors.length>i;i++)for(selector=selectors[i],j=0;selector.parts.length>j;j++)part=selector.parts[j],part.type===parser.SELECTOR_PART_TYPE&&part.elementName&&/h[1-6]/.test(\"\"+part.elementName)&&j>0&&reporter.report(\"Heading (\"+part.elementName+\") should not be qualified.\",part.line,part.col,rule)})}}),CSSLint.addRule({id:\"regex-selectors\",name:\"Disallow selectors that look like regexs\",desc:\"Selectors that look like regular expressions are slow and should be avoided.\",browsers:\"All\",init:function(parser,reporter){var rule=this;parser.addListener(\"startrule\",function(event){var selector,part,modifier,i,j,k,selectors=event.selectors;for(i=0;selectors.length>i;i++)for(selector=selectors[i],j=0;selector.parts.length>j;j++)if(part=selector.parts[j],part.type===parser.SELECTOR_PART_TYPE)for(k=0;part.modifiers.length>k;k++)modifier=part.modifiers[k],\"attribute\"===modifier.type&&/([\\\\~\\\\|\\\\^\\\\$\\\\*]=)/.test(modifier)&&reporter.report(\"Attribute selectors with \"+RegExp.$1+\" are slow!\",modifier.line,modifier.col,rule)})}}),CSSLint.addRule({id:\"rules-count\",name:\"Rules Count\",desc:\"Track how many rules there are.\",browsers:\"All\",init:function(parser,reporter){var count=0;parser.addListener(\"startrule\",function(){count++}),parser.addListener(\"endstylesheet\",function(){reporter.stat(\"rule-count\",count)})}}),CSSLint.addRule({id:\"selector-max-approaching\",name:\"Warn when approaching the 4095 selector limit for IE\",desc:\"Will warn when selector count is >= 3800 selectors.\",browsers:\"IE\",init:function(parser,reporter){var rule=this,count=0;parser.addListener(\"startrule\",function(event){count+=event.selectors.length}),parser.addListener(\"endstylesheet\",function(){count>=3800&&reporter.report(\"You have \"+count+\" selectors. Internet Explorer supports a maximum of 4095 selectors per stylesheet. Consider refactoring.\",0,0,rule)})}}),CSSLint.addRule({id:\"selector-max\",name:\"Error when past the 4095 selector limit for IE\",desc:\"Will error when selector count is > 4095.\",browsers:\"IE\",init:function(parser,reporter){var rule=this,count=0;parser.addListener(\"startrule\",function(event){count+=event.selectors.length}),parser.addListener(\"endstylesheet\",function(){count>4095&&reporter.report(\"You have \"+count+\" selectors. Internet Explorer supports a maximum of 4095 selectors per stylesheet. Consider refactoring.\",0,0,rule)})}}),CSSLint.addRule({id:\"selector-newline\",name:\"Disallow new-line characters in selectors\",desc:\"New-line characters in selectors are usually a forgotten comma and not a descendant combinator.\",browsers:\"All\",init:function(parser,reporter){function startRule(event){var i,len,selector,p,n,pLen,part,part2,type,currentLine,nextLine,selectors=event.selectors;for(i=0,len=selectors.length;len>i;i++)for(selector=selectors[i],p=0,pLen=selector.parts.length;pLen>p;p++)for(n=p+1;pLen>n;n++)part=selector.parts[p],part2=selector.parts[n],type=part.type,currentLine=part.line,nextLine=part2.line,\"descendant\"===type&&nextLine>currentLine&&reporter.report(\"newline character found in selector (forgot a comma?)\",currentLine,selectors[i].parts[0].col,rule)}var rule=this;parser.addListener(\"startrule\",startRule)}}),CSSLint.addRule({id:\"shorthand\",name:\"Require shorthand properties\",desc:\"Use shorthand properties where possible.\",browsers:\"All\",init:function(parser,reporter){function startRule(){properties={}}function endRule(event){var prop,i,len,total;for(prop in mapping)if(mapping.hasOwnProperty(prop)){for(total=0,i=0,len=mapping[prop].length;len>i;i++)total+=properties[mapping[prop][i]]?1:0;total===mapping[prop].length&&reporter.report(\"The properties \"+mapping[prop].join(\", \")+\" can be replaced by \"+prop+\".\",event.line,event.col,rule)}}var prop,i,len,properties,rule=this,propertiesToCheck={},mapping={margin:[\"margin-top\",\"margin-bottom\",\"margin-left\",\"margin-right\"],padding:[\"padding-top\",\"padding-bottom\",\"padding-left\",\"padding-right\"]};for(prop in mapping)if(mapping.hasOwnProperty(prop))for(i=0,len=mapping[prop].length;len>i;i++)propertiesToCheck[mapping[prop][i]]=prop;parser.addListener(\"startrule\",startRule),parser.addListener(\"startfontface\",startRule),parser.addListener(\"property\",function(event){var name=(\"\"+event.property).toLowerCase();propertiesToCheck[name]&&(properties[name]=1)}),parser.addListener(\"endrule\",endRule),parser.addListener(\"endfontface\",endRule)}}),CSSLint.addRule({id:\"star-property-hack\",name:\"Disallow properties with a star prefix\",desc:\"Checks for the star property hack (targets IE6/7)\",browsers:\"All\",init:function(parser,reporter){var rule=this;parser.addListener(\"property\",function(event){var property=event.property;\"*\"===property.hack&&reporter.report(\"Property with star prefix found.\",event.property.line,event.property.col,rule)})}}),CSSLint.addRule({id:\"text-indent\",name:\"Disallow negative text-indent\",desc:\"Checks for text indent less than -99px\",browsers:\"All\",init:function(parser,reporter){function startRule(){textIndent=!1,direction=\"inherit\"}function endRule(){textIndent&&\"ltr\"!==direction&&reporter.report(\"Negative text-indent doesn\\'t work well with RTL. If you use text-indent for image replacement explicitly set direction for that item to ltr.\",textIndent.line,textIndent.col,rule)}var textIndent,direction,rule=this;parser.addListener(\"startrule\",startRule),parser.addListener(\"startfontface\",startRule),parser.addListener(\"property\",function(event){var name=(\"\"+event.property).toLowerCase(),value=event.value;\"text-indent\"===name&&-99>value.parts[0].value?textIndent=event.property:\"direction\"===name&&\"ltr\"==\"\"+value&&(direction=\"ltr\")}),parser.addListener(\"endrule\",endRule),parser.addListener(\"endfontface\",endRule)}}),CSSLint.addRule({id:\"underscore-property-hack\",name:\"Disallow properties with an underscore prefix\",desc:\"Checks for the underscore property hack (targets IE6)\",browsers:\"All\",init:function(parser,reporter){var rule=this;parser.addListener(\"property\",function(event){var property=event.property;\"_\"===property.hack&&reporter.report(\"Property with underscore prefix found.\",event.property.line,event.property.col,rule)})}}),CSSLint.addRule({id:\"unique-headings\",name:\"Headings should only be defined once\",desc:\"Headings should be defined only once.\",browsers:\"All\",init:function(parser,reporter){var rule=this,headings={h1:0,h2:0,h3:0,h4:0,h5:0,h6:0};parser.addListener(\"startrule\",function(event){var selector,part,pseudo,i,j,selectors=event.selectors;for(i=0;selectors.length>i;i++)if(selector=selectors[i],part=selector.parts[selector.parts.length-1],part.elementName&&/(h[1-6])/i.test(\"\"+part.elementName)){for(j=0;part.modifiers.length>j;j++)if(\"pseudo\"===part.modifiers[j].type){pseudo=!0;break}pseudo||(headings[RegExp.$1]++,headings[RegExp.$1]>1&&reporter.report(\"Heading (\"+part.elementName+\") has already been defined.\",part.line,part.col,rule))}}),parser.addListener(\"endstylesheet\",function(){var prop,messages=[];for(prop in headings)headings.hasOwnProperty(prop)&&headings[prop]>1&&messages.push(headings[prop]+\" \"+prop+\"s\");messages.length&&reporter.rollupWarn(\"You have \"+messages.join(\", \")+\" defined in this stylesheet.\",rule)})}}),CSSLint.addRule({id:\"universal-selector\",name:\"Disallow universal selector\",desc:\"The universal selector (*) is known to be slow.\",browsers:\"All\",init:function(parser,reporter){var rule=this;parser.addListener(\"startrule\",function(event){var selector,part,i,selectors=event.selectors;for(i=0;selectors.length>i;i++)selector=selectors[i],part=selector.parts[selector.parts.length-1],\"*\"===part.elementName&&reporter.report(rule.desc,part.line,part.col,rule)})}}),CSSLint.addRule({id:\"unqualified-attributes\",name:\"Disallow unqualified attribute selectors\",desc:\"Unqualified attribute selectors are known to be slow.\",browsers:\"All\",init:function(parser,reporter){var rule=this;parser.addListener(\"startrule\",function(event){var selector,part,modifier,i,k,selectors=event.selectors;for(i=0;selectors.length>i;i++)if(selector=selectors[i],part=selector.parts[selector.parts.length-1],part.type===parser.SELECTOR_PART_TYPE)for(k=0;part.modifiers.length>k;k++)modifier=part.modifiers[k],\"attribute\"!==modifier.type||part.elementName&&\"*\"!==part.elementName||reporter.report(rule.desc,part.line,part.col,rule)})}}),CSSLint.addRule({id:\"vendor-prefix\",name:\"Require standard property with vendor prefix\",desc:\"When using a vendor-prefixed property, make sure to include the standard one.\",browsers:\"All\",init:function(parser,reporter){function startRule(){properties={},num=1}function endRule(){var prop,i,len,needed,actual,needsStandard=[];for(prop in properties)propertiesToCheck[prop]&&needsStandard.push({actual:prop,needed:propertiesToCheck[prop]});for(i=0,len=needsStandard.length;len>i;i++)needed=needsStandard[i].needed,actual=needsStandard[i].actual,properties[needed]?properties[needed][0].pos<properties[actual][0].pos&&reporter.report(\"Standard property \\'\"+needed+\"\\' should come after vendor-prefixed property \\'\"+actual+\"\\'.\",properties[actual][0].name.line,properties[actual][0].name.col,rule):reporter.report(\"Missing standard property \\'\"+needed+\"\\' to go along with \\'\"+actual+\"\\'.\",properties[actual][0].name.line,properties[actual][0].name.col,rule)}var properties,num,rule=this,propertiesToCheck={\"-webkit-border-radius\":\"border-radius\",\"-webkit-border-top-left-radius\":\"border-top-left-radius\",\"-webkit-border-top-right-radius\":\"border-top-right-radius\",\"-webkit-border-bottom-left-radius\":\"border-bottom-left-radius\",\"-webkit-border-bottom-right-radius\":\"border-bottom-right-radius\",\"-o-border-radius\":\"border-radius\",\"-o-border-top-left-radius\":\"border-top-left-radius\",\"-o-border-top-right-radius\":\"border-top-right-radius\",\"-o-border-bottom-left-radius\":\"border-bottom-left-radius\",\"-o-border-bottom-right-radius\":\"border-bottom-right-radius\",\"-moz-border-radius\":\"border-radius\",\"-moz-border-radius-topleft\":\"border-top-left-radius\",\"-moz-border-radius-topright\":\"border-top-right-radius\",\"-moz-border-radius-bottomleft\":\"border-bottom-left-radius\",\"-moz-border-radius-bottomright\":\"border-bottom-right-radius\",\"-moz-column-count\":\"column-count\",\"-webkit-column-count\":\"column-count\",\"-moz-column-gap\":\"column-gap\",\"-webkit-column-gap\":\"column-gap\",\"-moz-column-rule\":\"column-rule\",\"-webkit-column-rule\":\"column-rule\",\"-moz-column-rule-style\":\"column-rule-style\",\"-webkit-column-rule-style\":\"column-rule-style\",\"-moz-column-rule-color\":\"column-rule-color\",\"-webkit-column-rule-color\":\"column-rule-color\",\"-moz-column-rule-width\":\"column-rule-width\",\"-webkit-column-rule-width\":\"column-rule-width\",\"-moz-column-width\":\"column-width\",\"-webkit-column-width\":\"column-width\",\"-webkit-column-span\":\"column-span\",\"-webkit-columns\":\"columns\",\"-moz-box-shadow\":\"box-shadow\",\"-webkit-box-shadow\":\"box-shadow\",\"-moz-transform\":\"transform\",\"-webkit-transform\":\"transform\",\"-o-transform\":\"transform\",\"-ms-transform\":\"transform\",\"-moz-transform-origin\":\"transform-origin\",\"-webkit-transform-origin\":\"transform-origin\",\"-o-transform-origin\":\"transform-origin\",\"-ms-transform-origin\":\"transform-origin\",\"-moz-box-sizing\":\"box-sizing\",\"-webkit-box-sizing\":\"box-sizing\"};parser.addListener(\"startrule\",startRule),parser.addListener(\"startfontface\",startRule),parser.addListener(\"startpage\",startRule),parser.addListener(\"startpagemargin\",startRule),parser.addListener(\"startkeyframerule\",startRule),parser.addListener(\"property\",function(event){var name=event.property.text.toLowerCase();properties[name]||(properties[name]=[]),properties[name].push({name:event.property,value:event.value,pos:num++})}),parser.addListener(\"endrule\",endRule),parser.addListener(\"endfontface\",endRule),parser.addListener(\"endpage\",endRule),parser.addListener(\"endpagemargin\",endRule),parser.addListener(\"endkeyframerule\",endRule)}}),CSSLint.addRule({id:\"zero-units\",name:\"Disallow units for 0 values\",desc:\"You don\\'t need to specify units when a value is 0.\",browsers:\"All\",init:function(parser,reporter){var rule=this;parser.addListener(\"property\",function(event){for(var parts=event.value.parts,i=0,len=parts.length;len>i;)!parts[i].units&&\"percentage\"!==parts[i].type||0!==parts[i].value||\"time\"===parts[i].type||reporter.report(\"Values of 0 shouldn\\'t have units specified.\",parts[i].line,parts[i].col,rule),i++})}}),function(){var xmlEscape=function(str){return str&&str.constructor===String?str.replace(/[\\\\\"&><]/g,function(match){switch(match){case\\'\"\\':return\"&quot;\";case\"&\":return\"&amp;\";case\"<\":return\"&lt;\";case\">\":return\"&gt;\"}}):\"\"};CSSLint.addFormatter({id:\"checkstyle-xml\",name:\"Checkstyle XML format\",startFormat:function(){return\\'<?xml version=\"1.0\" encoding=\"utf-8\"?><checkstyle>\\'},endFormat:function(){return\"</checkstyle>\"},readError:function(filename,message){return\\'<file name=\"\\'+xmlEscape(filename)+\\'\"><error line=\"0\" column=\"0\" severty=\"error\" message=\"\\'+xmlEscape(message)+\\'\"></error></file>\\'},formatResults:function(results,filename){var messages=results.messages,output=[],generateSource=function(rule){return rule&&\"name\"in rule?\"net.csslint.\"+rule.name.replace(/\\\\s/g,\"\"):\"\"};return messages.length>0&&(output.push(\\'<file name=\"\\'+filename+\\'\">\\'),CSSLint.Util.forEach(messages,function(message){message.rollup||output.push(\\'<error line=\"\\'+message.line+\\'\" column=\"\\'+message.col+\\'\" severity=\"\\'+message.type+\\'\"\\'+\\' message=\"\\'+xmlEscape(message.message)+\\'\" source=\"\\'+generateSource(message.rule)+\\'\"/>\\')}),output.push(\"</file>\")),output.join(\"\")}})}(),CSSLint.addFormatter({id:\"compact\",name:\"Compact, \\'porcelain\\' format\",startFormat:function(){return\"\"},endFormat:function(){return\"\"},formatResults:function(results,filename,options){var messages=results.messages,output=\"\";options=options||{};var capitalize=function(str){return str.charAt(0).toUpperCase()+str.slice(1)};return 0===messages.length?options.quiet?\"\":filename+\": Lint Free!\":(CSSLint.Util.forEach(messages,function(message){output+=message.rollup?filename+\": \"+capitalize(message.type)+\" - \"+message.message+\"\\\\n\":filename+\": \"+\"line \"+message.line+\", col \"+message.col+\", \"+capitalize(message.type)+\" - \"+message.message+\" (\"+message.rule.id+\")\\\\n\"}),output)}}),CSSLint.addFormatter({id:\"csslint-xml\",name:\"CSSLint XML format\",startFormat:function(){return\\'<?xml version=\"1.0\" encoding=\"utf-8\"?><csslint>\\'},endFormat:function(){return\"</csslint>\"},formatResults:function(results,filename){var messages=results.messages,output=[],escapeSpecialCharacters=function(str){return str&&str.constructor===String?str.replace(/\\\\\"/g,\"\\'\").replace(/&/g,\"&amp;\").replace(/</g,\"&lt;\").replace(/>/g,\"&gt;\"):\"\"};return messages.length>0&&(output.push(\\'<file name=\"\\'+filename+\\'\">\\'),CSSLint.Util.forEach(messages,function(message){message.rollup?output.push(\\'<issue severity=\"\\'+message.type+\\'\" reason=\"\\'+escapeSpecialCharacters(message.message)+\\'\" evidence=\"\\'+escapeSpecialCharacters(message.evidence)+\\'\"/>\\'):output.push(\\'<issue line=\"\\'+message.line+\\'\" char=\"\\'+message.col+\\'\" severity=\"\\'+message.type+\\'\"\\'+\\' reason=\"\\'+escapeSpecialCharacters(message.message)+\\'\" evidence=\"\\'+escapeSpecialCharacters(message.evidence)+\\'\"/>\\')}),output.push(\"</file>\")),output.join(\"\")}}),CSSLint.addFormatter({id:\"junit-xml\",name:\"JUNIT XML format\",startFormat:function(){return\\'<?xml version=\"1.0\" encoding=\"utf-8\"?><testsuites>\\'},endFormat:function(){return\"</testsuites>\"},formatResults:function(results,filename){var messages=results.messages,output=[],tests={error:0,failure:0},generateSource=function(rule){return rule&&\"name\"in rule?\"net.csslint.\"+rule.name.replace(/\\\\s/g,\"\"):\"\"},escapeSpecialCharacters=function(str){return str&&str.constructor===String?str.replace(/\\\\\"/g,\"\\'\").replace(/</g,\"&lt;\").replace(/>/g,\"&gt;\"):\"\"};return messages.length>0&&(messages.forEach(function(message){var type=\"warning\"===message.type?\"error\":message.type;message.rollup||(output.push(\\'<testcase time=\"0\" name=\"\\'+generateSource(message.rule)+\\'\">\\'),output.push(\"<\"+type+\\' message=\"\\'+escapeSpecialCharacters(message.message)+\\'\"><![CDATA[\\'+message.line+\":\"+message.col+\":\"+escapeSpecialCharacters(message.evidence)+\"]]></\"+type+\">\"),output.push(\"</testcase>\"),tests[type]+=1)}),output.unshift(\\'<testsuite time=\"0\" tests=\"\\'+messages.length+\\'\" skipped=\"0\" errors=\"\\'+tests.error+\\'\" failures=\"\\'+tests.failure+\\'\" package=\"net.csslint\" name=\"\\'+filename+\\'\">\\'),output.push(\"</testsuite>\")),output.join(\"\")}}),CSSLint.addFormatter({id:\"lint-xml\",name:\"Lint XML format\",startFormat:function(){return\\'<?xml version=\"1.0\" encoding=\"utf-8\"?><lint>\\'},endFormat:function(){return\"</lint>\"},formatResults:function(results,filename){var messages=results.messages,output=[],escapeSpecialCharacters=function(str){return str&&str.constructor===String?str.replace(/\\\\\"/g,\"\\'\").replace(/&/g,\"&amp;\").replace(/</g,\"&lt;\").replace(/>/g,\"&gt;\"):\"\"};return messages.length>0&&(output.push(\\'<file name=\"\\'+filename+\\'\">\\'),CSSLint.Util.forEach(messages,function(message){message.rollup?output.push(\\'<issue severity=\"\\'+message.type+\\'\" reason=\"\\'+escapeSpecialCharacters(message.message)+\\'\" evidence=\"\\'+escapeSpecialCharacters(message.evidence)+\\'\"/>\\'):output.push(\\'<issue line=\"\\'+message.line+\\'\" char=\"\\'+message.col+\\'\" severity=\"\\'+message.type+\\'\"\\'+\\' reason=\"\\'+escapeSpecialCharacters(message.message)+\\'\" evidence=\"\\'+escapeSpecialCharacters(message.evidence)+\\'\"/>\\')}),output.push(\"</file>\")),output.join(\"\")}}),CSSLint.addFormatter({id:\"text\",name:\"Plain Text\",startFormat:function(){return\"\"},endFormat:function(){return\"\"},formatResults:function(results,filename,options){var messages=results.messages,output=\"\";if(options=options||{},0===messages.length)return options.quiet?\"\":\"\\\\n\\\\ncsslint: No errors in \"+filename+\".\";output=\"\\\\n\\\\ncsslint: There \",output+=1===messages.length?\"is 1 problem\":\"are \"+messages.length+\" problems\",output+=\" in \"+filename+\".\";var pos=filename.lastIndexOf(\"/\"),shortFilename=filename;return-1===pos&&(pos=filename.lastIndexOf(\"\\\\\\\\\")),pos>-1&&(shortFilename=filename.substring(pos+1)),CSSLint.Util.forEach(messages,function(message,i){output=output+\"\\\\n\\\\n\"+shortFilename,message.rollup?(output+=\"\\\\n\"+(i+1)+\": \"+message.type,output+=\"\\\\n\"+message.message):(output+=\"\\\\n\"+(i+1)+\": \"+message.type+\" at line \"+message.line+\", col \"+message.col,output+=\"\\\\n\"+message.message,output+=\"\\\\n\"+message.evidence)}),output}}),module.exports.CSSLint=CSSLint}),ace.define(\"ace/mode/css_worker\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/lib/lang\",\"ace/worker/mirror\",\"ace/mode/css/csslint\"],function(acequire,exports){\"use strict\";var oop=acequire(\"../lib/oop\"),lang=acequire(\"../lib/lang\"),Mirror=acequire(\"../worker/mirror\").Mirror,CSSLint=acequire(\"./css/csslint\").CSSLint,Worker=exports.Worker=function(sender){Mirror.call(this,sender),this.setTimeout(400),this.ruleset=null,this.setDisabledRules(\"ids|order-alphabetical\"),this.setInfoRules(\"adjoining-classes|qualified-headings|zero-units|gradients|import|outline-none|vendor-prefix\")};oop.inherits(Worker,Mirror),function(){this.setInfoRules=function(ruleNames){\"string\"==typeof ruleNames&&(ruleNames=ruleNames.split(\"|\")),this.infoRules=lang.arrayToMap(ruleNames),this.doc.getValue()&&this.deferredUpdate.schedule(100)},this.setDisabledRules=function(ruleNames){if(ruleNames){\"string\"==typeof ruleNames&&(ruleNames=ruleNames.split(\"|\"));\\nvar all={};CSSLint.getRules().forEach(function(x){all[x.id]=!0}),ruleNames.forEach(function(x){delete all[x]}),this.ruleset=all}else this.ruleset=null;this.doc.getValue()&&this.deferredUpdate.schedule(100)},this.onUpdate=function(){var value=this.doc.getValue();if(!value)return this.sender.emit(\"annotate\",[]);var infoRules=this.infoRules,result=CSSLint.verify(value,this.ruleset);this.sender.emit(\"annotate\",result.messages.map(function(msg){return{row:msg.line-1,column:msg.col-1,text:msg.message,type:infoRules[msg.rule.id]?\"info\":msg.type,rule:msg.rule.name}}))}}.call(Worker.prototype)}),ace.define(\"ace/lib/es5-shim\",[\"require\",\"exports\",\"module\"],function(){function Empty(){}function doesDefinePropertyWork(object){try{return Object.defineProperty(object,\"sentinel\",{}),\"sentinel\"in object}catch(exception){}}function toInteger(n){return n=+n,n!==n?n=0:0!==n&&n!==1/0&&n!==-(1/0)&&(n=(n>0||-1)*Math.floor(Math.abs(n))),n}Function.prototype.bind||(Function.prototype.bind=function(that){var target=this;if(\"function\"!=typeof target)throw new TypeError(\"Function.prototype.bind called on incompatible \"+target);var args=slice.call(arguments,1),bound=function(){if(this instanceof bound){var result=target.apply(this,args.concat(slice.call(arguments)));return Object(result)===result?result:this}return target.apply(that,args.concat(slice.call(arguments)))};return target.prototype&&(Empty.prototype=target.prototype,bound.prototype=new Empty,Empty.prototype=null),bound});var defineGetter,defineSetter,lookupGetter,lookupSetter,supportsAccessors,call=Function.prototype.call,prototypeOfArray=Array.prototype,prototypeOfObject=Object.prototype,slice=prototypeOfArray.slice,_toString=call.bind(prototypeOfObject.toString),owns=call.bind(prototypeOfObject.hasOwnProperty);if((supportsAccessors=owns(prototypeOfObject,\"__defineGetter__\"))&&(defineGetter=call.bind(prototypeOfObject.__defineGetter__),defineSetter=call.bind(prototypeOfObject.__defineSetter__),lookupGetter=call.bind(prototypeOfObject.__lookupGetter__),lookupSetter=call.bind(prototypeOfObject.__lookupSetter__)),2!=[1,2].splice(0).length)if(function(){function makeArray(l){var a=Array(l+2);return a[0]=a[1]=0,a}var lengthBefore,array=[];return array.splice.apply(array,makeArray(20)),array.splice.apply(array,makeArray(26)),lengthBefore=array.length,array.splice(5,0,\"XXX\"),lengthBefore+1==array.length,lengthBefore+1==array.length?!0:void 0}()){var array_splice=Array.prototype.splice;Array.prototype.splice=function(start,deleteCount){return arguments.length?array_splice.apply(this,[void 0===start?0:start,void 0===deleteCount?this.length-start:deleteCount].concat(slice.call(arguments,2))):[]}}else Array.prototype.splice=function(pos,removeCount){var length=this.length;pos>0?pos>length&&(pos=length):void 0==pos?pos=0:0>pos&&(pos=Math.max(length+pos,0)),length>pos+removeCount||(removeCount=length-pos);var removed=this.slice(pos,pos+removeCount),insert=slice.call(arguments,2),add=insert.length;if(pos===length)add&&this.push.apply(this,insert);else{var remove=Math.min(removeCount,length-pos),tailOldPos=pos+remove,tailNewPos=tailOldPos+add-remove,tailCount=length-tailOldPos,lengthAfterRemove=length-remove;if(tailOldPos>tailNewPos)for(var i=0;tailCount>i;++i)this[tailNewPos+i]=this[tailOldPos+i];else if(tailNewPos>tailOldPos)for(i=tailCount;i--;)this[tailNewPos+i]=this[tailOldPos+i];if(add&&pos===lengthAfterRemove)this.length=lengthAfterRemove,this.push.apply(this,insert);else for(this.length=lengthAfterRemove+add,i=0;add>i;++i)this[pos+i]=insert[i]}return removed};Array.isArray||(Array.isArray=function(obj){return\"[object Array]\"==_toString(obj)});var boxedString=Object(\"a\"),splitString=\"a\"!=boxedString[0]||!(0 in boxedString);if(Array.prototype.forEach||(Array.prototype.forEach=function(fun){var object=toObject(this),self=splitString&&\"[object String]\"==_toString(this)?this.split(\"\"):object,thisp=arguments[1],i=-1,length=self.length>>>0;if(\"[object Function]\"!=_toString(fun))throw new TypeError;for(;length>++i;)i in self&&fun.call(thisp,self[i],i,object)}),Array.prototype.map||(Array.prototype.map=function(fun){var object=toObject(this),self=splitString&&\"[object String]\"==_toString(this)?this.split(\"\"):object,length=self.length>>>0,result=Array(length),thisp=arguments[1];if(\"[object Function]\"!=_toString(fun))throw new TypeError(fun+\" is not a function\");for(var i=0;length>i;i++)i in self&&(result[i]=fun.call(thisp,self[i],i,object));return result}),Array.prototype.filter||(Array.prototype.filter=function(fun){var value,object=toObject(this),self=splitString&&\"[object String]\"==_toString(this)?this.split(\"\"):object,length=self.length>>>0,result=[],thisp=arguments[1];if(\"[object Function]\"!=_toString(fun))throw new TypeError(fun+\" is not a function\");for(var i=0;length>i;i++)i in self&&(value=self[i],fun.call(thisp,value,i,object)&&result.push(value));return result}),Array.prototype.every||(Array.prototype.every=function(fun){var object=toObject(this),self=splitString&&\"[object String]\"==_toString(this)?this.split(\"\"):object,length=self.length>>>0,thisp=arguments[1];if(\"[object Function]\"!=_toString(fun))throw new TypeError(fun+\" is not a function\");for(var i=0;length>i;i++)if(i in self&&!fun.call(thisp,self[i],i,object))return!1;return!0}),Array.prototype.some||(Array.prototype.some=function(fun){var object=toObject(this),self=splitString&&\"[object String]\"==_toString(this)?this.split(\"\"):object,length=self.length>>>0,thisp=arguments[1];if(\"[object Function]\"!=_toString(fun))throw new TypeError(fun+\" is not a function\");for(var i=0;length>i;i++)if(i in self&&fun.call(thisp,self[i],i,object))return!0;return!1}),Array.prototype.reduce||(Array.prototype.reduce=function(fun){var object=toObject(this),self=splitString&&\"[object String]\"==_toString(this)?this.split(\"\"):object,length=self.length>>>0;if(\"[object Function]\"!=_toString(fun))throw new TypeError(fun+\" is not a function\");if(!length&&1==arguments.length)throw new TypeError(\"reduce of empty array with no initial value\");var result,i=0;if(arguments.length>=2)result=arguments[1];else for(;;){if(i in self){result=self[i++];break}if(++i>=length)throw new TypeError(\"reduce of empty array with no initial value\")}for(;length>i;i++)i in self&&(result=fun.call(void 0,result,self[i],i,object));return result}),Array.prototype.reduceRight||(Array.prototype.reduceRight=function(fun){var object=toObject(this),self=splitString&&\"[object String]\"==_toString(this)?this.split(\"\"):object,length=self.length>>>0;if(\"[object Function]\"!=_toString(fun))throw new TypeError(fun+\" is not a function\");if(!length&&1==arguments.length)throw new TypeError(\"reduceRight of empty array with no initial value\");var result,i=length-1;if(arguments.length>=2)result=arguments[1];else for(;;){if(i in self){result=self[i--];break}if(0>--i)throw new TypeError(\"reduceRight of empty array with no initial value\")}do i in this&&(result=fun.call(void 0,result,self[i],i,object));while(i--);return result}),Array.prototype.indexOf&&-1==[0,1].indexOf(1,2)||(Array.prototype.indexOf=function(sought){var self=splitString&&\"[object String]\"==_toString(this)?this.split(\"\"):toObject(this),length=self.length>>>0;if(!length)return-1;var i=0;for(arguments.length>1&&(i=toInteger(arguments[1])),i=i>=0?i:Math.max(0,length+i);length>i;i++)if(i in self&&self[i]===sought)return i;return-1}),Array.prototype.lastIndexOf&&-1==[0,1].lastIndexOf(0,-3)||(Array.prototype.lastIndexOf=function(sought){var self=splitString&&\"[object String]\"==_toString(this)?this.split(\"\"):toObject(this),length=self.length>>>0;if(!length)return-1;var i=length-1;for(arguments.length>1&&(i=Math.min(i,toInteger(arguments[1]))),i=i>=0?i:length-Math.abs(i);i>=0;i--)if(i in self&&sought===self[i])return i;return-1}),Object.getPrototypeOf||(Object.getPrototypeOf=function(object){return object.__proto__||(object.constructor?object.constructor.prototype:prototypeOfObject)}),!Object.getOwnPropertyDescriptor){var ERR_NON_OBJECT=\"Object.getOwnPropertyDescriptor called on a non-object: \";Object.getOwnPropertyDescriptor=function(object,property){if(\"object\"!=typeof object&&\"function\"!=typeof object||null===object)throw new TypeError(ERR_NON_OBJECT+object);if(owns(object,property)){var descriptor,getter,setter;if(descriptor={enumerable:!0,configurable:!0},supportsAccessors){var prototype=object.__proto__;object.__proto__=prototypeOfObject;var getter=lookupGetter(object,property),setter=lookupSetter(object,property);if(object.__proto__=prototype,getter||setter)return getter&&(descriptor.get=getter),setter&&(descriptor.set=setter),descriptor}return descriptor.value=object[property],descriptor}}}if(Object.getOwnPropertyNames||(Object.getOwnPropertyNames=function(object){return Object.keys(object)}),!Object.create){var createEmpty;createEmpty=null===Object.prototype.__proto__?function(){return{__proto__:null}}:function(){var empty={};for(var i in empty)empty[i]=null;return empty.constructor=empty.hasOwnProperty=empty.propertyIsEnumerable=empty.isPrototypeOf=empty.toLocaleString=empty.toString=empty.valueOf=empty.__proto__=null,empty},Object.create=function(prototype,properties){var object;if(null===prototype)object=createEmpty();else{if(\"object\"!=typeof prototype)throw new TypeError(\"typeof prototype[\"+typeof prototype+\"] != \\'object\\'\");var Type=function(){};Type.prototype=prototype,object=new Type,object.__proto__=prototype}return void 0!==properties&&Object.defineProperties(object,properties),object}}if(Object.defineProperty){var definePropertyWorksOnObject=doesDefinePropertyWork({}),definePropertyWorksOnDom=\"undefined\"==typeof document||doesDefinePropertyWork(document.createElement(\"div\"));if(!definePropertyWorksOnObject||!definePropertyWorksOnDom)var definePropertyFallback=Object.defineProperty}if(!Object.defineProperty||definePropertyFallback){var ERR_NON_OBJECT_DESCRIPTOR=\"Property description must be an object: \",ERR_NON_OBJECT_TARGET=\"Object.defineProperty called on non-object: \",ERR_ACCESSORS_NOT_SUPPORTED=\"getters & setters can not be defined on this javascript engine\";Object.defineProperty=function(object,property,descriptor){if(\"object\"!=typeof object&&\"function\"!=typeof object||null===object)throw new TypeError(ERR_NON_OBJECT_TARGET+object);if(\"object\"!=typeof descriptor&&\"function\"!=typeof descriptor||null===descriptor)throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR+descriptor);if(definePropertyFallback)try{return definePropertyFallback.call(Object,object,property,descriptor)}catch(exception){}if(owns(descriptor,\"value\"))if(supportsAccessors&&(lookupGetter(object,property)||lookupSetter(object,property))){var prototype=object.__proto__;object.__proto__=prototypeOfObject,delete object[property],object[property]=descriptor.value,object.__proto__=prototype}else object[property]=descriptor.value;else{if(!supportsAccessors)throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);owns(descriptor,\"get\")&&defineGetter(object,property,descriptor.get),owns(descriptor,\"set\")&&defineSetter(object,property,descriptor.set)}return object}}Object.defineProperties||(Object.defineProperties=function(object,properties){for(var property in properties)owns(properties,property)&&Object.defineProperty(object,property,properties[property]);return object}),Object.seal||(Object.seal=function(object){return object}),Object.freeze||(Object.freeze=function(object){return object});try{Object.freeze(function(){})}catch(exception){Object.freeze=function(freezeObject){return function(object){return\"function\"==typeof object?object:freezeObject(object)}}(Object.freeze)}if(Object.preventExtensions||(Object.preventExtensions=function(object){return object}),Object.isSealed||(Object.isSealed=function(){return!1}),Object.isFrozen||(Object.isFrozen=function(){return!1}),Object.isExtensible||(Object.isExtensible=function(object){if(Object(object)===object)throw new TypeError;for(var name=\"\";owns(object,name);)name+=\"?\";object[name]=!0;var returnValue=owns(object,name);return delete object[name],returnValue}),!Object.keys){var hasDontEnumBug=!0,dontEnums=[\"toString\",\"toLocaleString\",\"valueOf\",\"hasOwnProperty\",\"isPrototypeOf\",\"propertyIsEnumerable\",\"constructor\"],dontEnumsLength=dontEnums.length;for(var key in{toString:null})hasDontEnumBug=!1;Object.keys=function(object){if(\"object\"!=typeof object&&\"function\"!=typeof object||null===object)throw new TypeError(\"Object.keys called on a non-object\");var keys=[];for(var name in object)owns(object,name)&&keys.push(name);if(hasDontEnumBug)for(var i=0,ii=dontEnumsLength;ii>i;i++){var dontEnum=dontEnums[i];owns(object,dontEnum)&&keys.push(dontEnum)}return keys}}Date.now||(Date.now=function(){return(new Date).getTime()});var ws=\"\\t\\\\n\\v\\\\f\\\\r   ᠎             　\\\\u2028\\\\u2029\\ufeff\";if(!String.prototype.trim||ws.trim()){ws=\"[\"+ws+\"]\";var trimBeginRegexp=RegExp(\"^\"+ws+ws+\"*\"),trimEndRegexp=RegExp(ws+ws+\"*$\");String.prototype.trim=function(){return(this+\"\").replace(trimBeginRegexp,\"\").replace(trimEndRegexp,\"\")}}var toObject=function(o){if(null==o)throw new TypeError(\"can\\'t convert \"+o+\" to object\");return Object(o)}});'},e0e5:function(e,t){ace.define(\"ace/mode/properties_highlight_rules\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/mode/text_highlight_rules\"],function(e,t,n){\"use strict\";var r=e(\"../lib/oop\"),i=e(\"./text_highlight_rules\").TextHighlightRules,o=function(){var e=/\\\\u[0-9a-fA-F]{4}|\\\\/;this.$rules={start:[{token:\"comment\",regex:/[!#].*$/},{token:\"keyword\",regex:/[=:]$/},{token:\"keyword\",regex:/[=:]/,next:\"value\"},{token:\"constant.language.escape\",regex:e},{defaultToken:\"variable\"}],value:[{regex:/\\\\$/,token:\"string\",next:\"value\"},{regex:/$/,token:\"string\",next:\"start\"},{token:\"constant.language.escape\",regex:e},{defaultToken:\"string\"}]}};r.inherits(o,i),t.PropertiesHighlightRules=o}),ace.define(\"ace/mode/properties\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/mode/text\",\"ace/mode/properties_highlight_rules\"],function(e,t,n){\"use strict\";var r=e(\"../lib/oop\"),i=e(\"./text\").Mode,o=e(\"./properties_highlight_rules\").PropertiesHighlightRules,a=function(){this.HighlightRules=o,this.$behaviour=this.$defaultBehaviour};r.inherits(a,i),function(){this.$id=\"ace/mode/properties\"}.call(a.prototype),t.Mode=a})}}]);"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/js/chunk-101fc062.372a5ca5.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[\"chunk-101fc062\"],{2017:function(e,t,s){\"use strict\";var n=s(\"3b76\"),o=s.n(n);o.a},\"3b76\":function(e,t,s){},\"562b\":function(e,t,s){},\"9ed6\":function(e,t,s){\"use strict\";s.r(t);var n=function(){var e=this,t=e.$createElement,s=e._self._c||t;return s(\"div\",{staticClass:\"login-container\"},[s(\"el-form\",{ref:\"loginForm\",staticClass:\"login-form\",attrs:{model:e.loginForm,rules:e.loginRules,\"auto-complete\":\"on\",\"label-position\":\"left\"}},[s(\"div\",{staticClass:\"title-container\"},[s(\"h3\",{staticClass:\"title\"},[e._v(\"Canal Admin Login\")])]),e._v(\" \"),s(\"el-form-item\",{attrs:{prop:\"username\"}},[s(\"span\",{staticClass:\"svg-container\"},[s(\"svg-icon\",{attrs:{\"icon-class\":\"user\"}})],1),e._v(\" \"),s(\"el-input\",{ref:\"username\",attrs:{placeholder:\"Username\",name:\"username\",type:\"text\",tabindex:\"1\",\"auto-complete\":\"on\"},model:{value:e.loginForm.username,callback:function(t){e.$set(e.loginForm,\"username\",t)},expression:\"loginForm.username\"}})],1),e._v(\" \"),s(\"el-form-item\",{attrs:{prop:\"password\"}},[s(\"span\",{staticClass:\"svg-container\"},[s(\"svg-icon\",{attrs:{\"icon-class\":\"password\"}})],1),e._v(\" \"),s(\"el-input\",{key:e.passwordType,ref:\"password\",attrs:{type:e.passwordType,placeholder:\"Password\",name:\"password\",tabindex:\"2\",\"auto-complete\":\"on\"},nativeOn:{keyup:function(t){return!t.type.indexOf(\"key\")&&e._k(t.keyCode,\"enter\",13,t.key,\"Enter\")?null:e.handleLogin(t)}},model:{value:e.loginForm.password,callback:function(t){e.$set(e.loginForm,\"password\",t)},expression:\"loginForm.password\"}}),e._v(\" \"),s(\"span\",{staticClass:\"show-pwd\",on:{click:e.showPwd}},[s(\"svg-icon\",{attrs:{\"icon-class\":\"password\"===e.passwordType?\"eye\":\"eye-open\"}})],1)],1),e._v(\" \"),s(\"el-button\",{staticStyle:{width:\"100%\",\"margin-bottom\":\"30px\"},attrs:{loading:e.loading,type:\"primary\"},nativeOn:{click:function(t){return t.preventDefault(),e.handleLogin(t)}}},[e._v(\"Login\")]),e._v(\" \"),s(\"div\",{staticClass:\"tips\"})],1)],1)},o=[],r=s(\"61f7\"),a={name:\"Login\",data:function(){var e=function(e,t,s){Object(r[\"b\"])(t)?s():s(new Error(\"Please enter the correct user name\"))},t=function(e,t,s){t.length<6?s(new Error(\"The password can not be less than 6 digits\")):s()};return{loginForm:{username:\"\",password:\"\"},loginRules:{username:[{required:!0,trigger:\"blur\",validator:e}],password:[{required:!0,trigger:\"blur\",validator:t}]},loading:!1,passwordType:\"password\",redirect:void 0}},watch:{$route:{handler:function(e){this.redirect=e.query&&e.query.redirect},immediate:!0}},methods:{showPwd:function(){var e=this;\"password\"===this.passwordType?this.passwordType=\"\":this.passwordType=\"password\",this.$nextTick(function(){e.$refs.password.focus()})},handleLogin:function(){var e=this;this.$refs.loginForm.validate(function(t){if(!t)return console.log(\"error submit!!\"),!1;e.loading=!0,e.$store.dispatch(\"user/login\",e.loginForm).then(function(){e.$router.push({path:e.redirect||\"/\"}),e.loading=!1}).catch(function(){e.loading=!1})})}}},i=a,l=(s(\"2017\"),s(\"ec2d\"),s(\"2877\")),c=Object(l[\"a\"])(i,n,o,!1,null,\"31c14ebf\",null);t[\"default\"]=c.exports},ec2d:function(e,t,s){\"use strict\";var n=s(\"562b\"),o=s.n(n);o.a}}]);"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/js/chunk-101fc062.bc898027.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[\"chunk-101fc062\"],{2017:function(e,t,s){\"use strict\";var n=s(\"3b76\"),o=s.n(n);o.a},\"3b76\":function(e,t,s){},\"562b\":function(e,t,s){},\"9ed6\":function(e,t,s){\"use strict\";s.r(t);var n=function(){var e=this,t=e.$createElement,s=e._self._c||t;return s(\"div\",{staticClass:\"login-container\"},[s(\"el-form\",{ref:\"loginForm\",staticClass:\"login-form\",attrs:{model:e.loginForm,rules:e.loginRules,\"auto-complete\":\"on\",\"label-position\":\"left\"}},[s(\"div\",{staticClass:\"title-container\"},[s(\"h3\",{staticClass:\"title\"},[e._v(\"Canal Admin Login\")])]),e._v(\" \"),s(\"el-form-item\",{attrs:{prop:\"username\"}},[s(\"span\",{staticClass:\"svg-container\"},[s(\"svg-icon\",{attrs:{\"icon-class\":\"user\"}})],1),e._v(\" \"),s(\"el-input\",{ref:\"username\",attrs:{placeholder:\"Username\",name:\"username\",type:\"text\",tabindex:\"1\",\"auto-complete\":\"on\"},model:{value:e.loginForm.username,callback:function(t){e.$set(e.loginForm,\"username\",t)},expression:\"loginForm.username\"}})],1),e._v(\" \"),s(\"el-form-item\",{attrs:{prop:\"password\"}},[s(\"span\",{staticClass:\"svg-container\"},[s(\"svg-icon\",{attrs:{\"icon-class\":\"password\"}})],1),e._v(\" \"),s(\"el-input\",{key:e.passwordType,ref:\"password\",attrs:{type:e.passwordType,placeholder:\"Password\",name:\"password\",tabindex:\"2\",\"auto-complete\":\"on\"},nativeOn:{keyup:function(t){return!t.type.indexOf(\"key\")&&e._k(t.keyCode,\"enter\",13,t.key,\"Enter\")?null:e.handleLogin(t)}},model:{value:e.loginForm.password,callback:function(t){e.$set(e.loginForm,\"password\",t)},expression:\"loginForm.password\"}}),e._v(\" \"),s(\"span\",{staticClass:\"show-pwd\",on:{click:e.showPwd}},[s(\"svg-icon\",{attrs:{\"icon-class\":\"password\"===e.passwordType?\"eye\":\"eye-open\"}})],1)],1),e._v(\" \"),s(\"el-button\",{staticStyle:{width:\"100%\",\"margin-bottom\":\"30px\"},attrs:{loading:e.loading,type:\"primary\"},nativeOn:{click:function(t){return t.preventDefault(),e.handleLogin(t)}}},[e._v(\"Login\")]),e._v(\" \"),s(\"div\",{staticClass:\"tips\"})],1)],1)},o=[],r=s(\"61f7\"),a={name:\"Login\",data:function(){var e=function(e,t,s){Object(r[\"b\"])(t)?s():s(new Error(\"Please enter the correct user name\"))},t=function(e,t,s){t.length<6?s(new Error(\"The password can not be less than 6 digits\")):s()};return{loginForm:{username:\"\",password:\"\"},loginRules:{username:[{required:!0,trigger:\"blur\",validator:e}],password:[{required:!0,trigger:\"blur\",validator:t}]},loading:!1,passwordType:\"password\",redirect:void 0}},watch:{$route:{handler:function(e){this.redirect=e.query&&e.query.redirect},immediate:!0}},methods:{showPwd:function(){var e=this;\"password\"===this.passwordType?this.passwordType=\"\":this.passwordType=\"password\",this.$nextTick(function(){e.$refs.password.focus()})},handleLogin:function(){var e=this;this.$refs.loginForm.validate(function(t){if(!t)return console.log(\"error submit!!\"),!1;e.loading=!0,e.$store.dispatch(\"user/login\",e.loginForm).then(function(){e.$router.push({path:e.redirect||\"/\"}),e.loading=!1}).catch(function(){e.loading=!1})})}}},i=a,l=(s(\"2017\"),s(\"ec2d\"),s(\"2877\")),c=Object(l[\"a\"])(i,n,o,!1,null,\"31c14ebf\",null);t[\"default\"]=c.exports},ec2d:function(e,t,s){\"use strict\";var n=s(\"562b\"),o=s.n(n);o.a}}]);"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/js/chunk-14b5f7a4.013449e9.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[\"chunk-14b5f7a4\"],{\"11e9\":function(t,e,n){var r=n(\"52a7\"),a=n(\"4630\"),i=n(\"6821\"),o=n(\"6a99\"),l=n(\"69a8\"),s=n(\"c69a\"),c=Object.getOwnPropertyDescriptor;e.f=n(\"9e1e\")?c:function(t,e){if(t=i(t),e=o(e,!0),s)try{return c(t,e)}catch(n){}if(l(t,e))return a(!r.f.call(t,e),t[e])}},\"1ca3\":function(t,e,n){\"use strict\";var r=n(\"c002\"),a=n.n(r);a.a},\"333d\":function(t,e,n){\"use strict\";var r=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n(\"div\",{staticClass:\"pagination-container\",class:{hidden:t.hidden}},[n(\"el-pagination\",t._b({attrs:{background:t.background,\"current-page\":t.currentPage,\"page-size\":t.pageSize,layout:t.layout,\"page-sizes\":t.pageSizes,total:t.total},on:{\"update:currentPage\":function(e){t.currentPage=e},\"update:current-page\":function(e){t.currentPage=e},\"update:pageSize\":function(e){t.pageSize=e},\"update:page-size\":function(e){t.pageSize=e},\"size-change\":t.handleSizeChange,\"current-change\":t.handleCurrentChange}},\"el-pagination\",t.$attrs,!1))],1)},a=[];n(\"c5f6\");Math.easeInOutQuad=function(t,e,n,r){return t/=r/2,t<1?n/2*t*t+e:(t--,-n/2*(t*(t-2)-1)+e)};var i=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||function(t){window.setTimeout(t,1e3/60)}}();function o(t){document.documentElement.scrollTop=t,document.body.parentNode.scrollTop=t,document.body.scrollTop=t}function l(){return document.documentElement.scrollTop||document.body.parentNode.scrollTop||document.body.scrollTop}function s(t,e,n){var r=l(),a=t-r,s=20,c=0;e=\"undefined\"===typeof e?500:e;var u=function t(){c+=s;var l=Math.easeInOutQuad(c,r,a,e);o(l),c<e?i(t):n&&\"function\"===typeof n&&n()};u()}var c={name:\"Pagination\",props:{total:{required:!0,type:Number},page:{type:Number,default:1},limit:{type:Number,default:20},pageSizes:{type:Array,default:function(){return[10,20,30,50]}},layout:{type:String,default:\"total, sizes, prev, pager, next, jumper\"},background:{type:Boolean,default:!0},autoScroll:{type:Boolean,default:!0},hidden:{type:Boolean,default:!1}},computed:{currentPage:{get:function(){return this.page},set:function(t){this.$emit(\"update:page\",t)}},pageSize:{get:function(){return this.limit},set:function(t){this.$emit(\"update:limit\",t)}}},methods:{handleSizeChange:function(t){this.$emit(\"pagination\",{page:this.currentPage,limit:t}),this.autoScroll&&s(0,800)},handleCurrentChange:function(t){this.$emit(\"pagination\",{page:t,limit:this.pageSize}),this.autoScroll&&s(0,800)}}},u=c,d=(n(\"1ca3\"),n(\"2877\")),f=Object(d[\"a\"])(u,r,a,!1,null,\"cebf2f0c\",null);e[\"a\"]=f.exports},\"5dbc\":function(t,e,n){var r=n(\"d3f4\"),a=n(\"8b97\").set;t.exports=function(t,e,n){var i,o=e.constructor;return o!==n&&\"function\"==typeof o&&(i=o.prototype)!==n.prototype&&r(i)&&a&&a(t,i),t}},\"8b97\":function(t,e,n){var r=n(\"d3f4\"),a=n(\"cb7c\"),i=function(t,e){if(a(t),!r(e)&&null!==e)throw TypeError(e+\": can't set as prototype!\")};t.exports={set:Object.setPrototypeOf||(\"__proto__\"in{}?function(t,e,r){try{r=n(\"9b43\")(Function.call,n(\"11e9\").f(Object.prototype,\"__proto__\").set,2),r(t,[]),e=!(t instanceof Array)}catch(a){e=!0}return function(t,n){return i(t,n),e?t.__proto__=n:r(t,n),t}}({},!1):void 0),check:i}},9093:function(t,e,n){var r=n(\"ce10\"),a=n(\"e11e\").concat(\"length\",\"prototype\");e.f=Object.getOwnPropertyNames||function(t){return r(t,a)}},\"9f66\":function(t,e,n){\"use strict\";n.r(e);var r=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n(\"div\",{staticClass:\"app-container\"},[n(\"div\",{staticClass:\"filter-container\"},[n(\"el-select\",{staticClass:\"filter-item\",attrs:{placeholder:\"所属集群\"},model:{value:t.listQuery.clusterId,callback:function(e){t.$set(t.listQuery,\"clusterId\",e)},expression:\"listQuery.clusterId\"}},[n(\"el-option\",{key:\"\",attrs:{label:\"所属集群\",value:\"\"}}),t._v(\" \"),n(\"el-option\",{key:\"-1\",attrs:{label:\"单机\",value:\"-1\"}}),t._v(\" \"),t._l(t.canalClusters,function(t){return n(\"el-option\",{key:t.id,attrs:{label:t.name,value:t.id}})})],2),t._v(\" \"),n(\"el-input\",{staticClass:\"filter-item\",staticStyle:{width:\"200px\"},attrs:{placeholder:\"Server IP\"},model:{value:t.listQuery.ip,callback:function(e){t.$set(t.listQuery,\"ip\",e)},expression:\"listQuery.ip\"}}),t._v(\" \"),n(\"el-button\",{staticClass:\"filter-item\",attrs:{type:\"primary\",icon:\"el-icon-search\",plain:\"\"},on:{click:function(e){return t.queryData()}}},[t._v(\"查询\")]),t._v(\" \"),n(\"el-button\",{staticClass:\"filter-item\",attrs:{type:\"primary\"},on:{click:function(e){return t.handleCreate()}}},[t._v(\"新建Server\")]),t._v(\" \"),n(\"el-button\",{staticClass:\"filter-item\",attrs:{type:\"info\"},on:{click:function(e){return t.fetchData()}}},[t._v(\"刷新列表\")])],1),t._v(\" \"),n(\"el-table\",{directives:[{name:\"loading\",rawName:\"v-loading\",value:t.listLoading,expression:\"listLoading\"}],attrs:{data:t.list,\"element-loading-text\":\"Loading\",border:\"\",fit:\"\",\"highlight-current-row\":\"\"}},[n(\"el-table-column\",{attrs:{label:\"所属集群\",\"min-width\":\"200\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[null!==e.row.canalCluster?n(\"span\",[t._v(\"\\n          \"+t._s(e.row.canalCluster.name)+\"\\n        \")]):n(\"span\",[t._v(\"\\n          -\\n        \")])]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{label:\"Server 名称\",\"min-width\":\"200\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[t._v(\"\\n        \"+t._s(e.row.name)+\"\\n      \")]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{label:\"Server IP\",\"min-width\":\"200\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[n(\"span\",[t._v(t._s(e.row.ip))])]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{label:\"admin 端口\",\"min-width\":\"100\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[t._v(\"\\n        \"+t._s(e.row.adminPort)+\"\\n      \")]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{label:\"tcp 端口\",\"min-width\":\"100\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[t._v(\"\\n        \"+t._s(e.row.tcpPort)+\"\\n      \")]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{label:\"metric 端口\",\"min-width\":\"100\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[t._v(\"\\n        \"+t._s(e.row.metricPort)+\"\\n      \")]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{\"class-name\":\"status-col\",label:\"状态\",\"min-width\":\"150\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[n(\"el-tag\",{attrs:{type:t._f(\"statusFilter\")(e.row.status)}},[t._v(t._s(t._f(\"statusLabel\")(e.row.status)))])]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{align:\"center\",prop:\"created_at\",label:\"操作\",\"min-width\":\"150\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[n(\"el-dropdown\",{attrs:{trigger:\"click\"}},[n(\"el-button\",{attrs:{type:\"primary\",size:\"mini\"}},[t._v(\"\\n            操作\"),n(\"i\",{staticClass:\"el-icon-arrow-down el-icon--right\"})]),t._v(\" \"),n(\"el-dropdown-menu\",{attrs:{slot:\"dropdown\"},slot:\"dropdown\"},[n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleConfig(e.row)}}},[t._v(\"配置\")]),t._v(\" \"),n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleUpdate(e.row)}}},[t._v(\"修改\")]),t._v(\" \"),n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleDelete(e.row)}}},[t._v(\"删除\")]),t._v(\" \"),n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleStart(e.row)}}},[t._v(\"启动\")]),t._v(\" \"),n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleStop(e.row)}}},[t._v(\"停止\")]),t._v(\" \"),n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleInstances(e.row)}}},[t._v(\"详情\")]),t._v(\" \"),n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleLog(e.row)}}},[t._v(\"日志\")])],1)],1)]}}])})],1),t._v(\" \"),n(\"pagination\",{directives:[{name:\"show\",rawName:\"v-show\",value:t.count>0,expression:\"count>0\"}],attrs:{total:t.count,page:t.listQuery.page,limit:t.listQuery.size},on:{\"update:page\":function(e){return t.$set(t.listQuery,\"page\",e)},\"update:limit\":function(e){return t.$set(t.listQuery,\"size\",e)},pagination:function(e){return t.fetchData()}}}),t._v(\" \"),n(\"el-dialog\",{attrs:{visible:t.dialogFormVisible,title:t.textMap[t.dialogStatus],width:\"600px\"},on:{\"update:visible\":function(e){t.dialogFormVisible=e}}},[n(\"el-form\",{ref:\"dataForm\",staticStyle:{width:\"400px\",\"margin-left\":\"30px\"},attrs:{rules:t.rules,model:t.nodeModel,\"label-position\":\"left\",\"label-width\":\"120px\"}},[n(\"el-form-item\",{attrs:{label:\"所属集群\",prop:\"clusterId\"}},[\"create\"===t.dialogStatus?n(\"el-select\",{attrs:{placeholder:\"选择所属集群\"},model:{value:t.nodeModel.clusterId,callback:function(e){t.$set(t.nodeModel,\"clusterId\",e)},expression:\"nodeModel.clusterId\"}},[n(\"el-option\",{key:\"\",attrs:{label:\"单机\",value:\"\"}}),t._v(\" \"),t._l(t.canalClusters,function(t){return n(\"el-option\",{key:t.id,attrs:{label:t.name,value:t.id}})})],2):n(\"el-select\",{attrs:{placeholder:\"选择所属集群\",disabled:\"disabled\"},model:{value:t.nodeModel.clusterId,callback:function(e){t.$set(t.nodeModel,\"clusterId\",e)},expression:\"nodeModel.clusterId\"}},[n(\"el-option\",{key:\"\",attrs:{label:\"单机\",value:\"\"}}),t._v(\" \"),t._l(t.canalClusters,function(t){return n(\"el-option\",{key:t.id,attrs:{label:t.name,value:t.id}})})],2)],1),t._v(\" \"),n(\"el-form-item\",{attrs:{label:\"Server 名称\",prop:\"name\"}},[n(\"el-input\",{model:{value:t.nodeModel.name,callback:function(e){t.$set(t.nodeModel,\"name\",e)},expression:\"nodeModel.name\"}})],1),t._v(\" \"),n(\"el-form-item\",{attrs:{label:\"Server IP\",prop:\"ip\"}},[n(\"el-input\",{model:{value:t.nodeModel.ip,callback:function(e){t.$set(t.nodeModel,\"ip\",e)},expression:\"nodeModel.ip\"}})],1),t._v(\" \"),n(\"el-form-item\",{attrs:{label:\"admin 端口\",prop:\"adminPort\"}},[n(\"el-input\",{attrs:{placeholder:\"11110\",type:\"number\"},model:{value:t.nodeModel.adminPort,callback:function(e){t.$set(t.nodeModel,\"adminPort\",e)},expression:\"nodeModel.adminPort\"}})],1),t._v(\" \"),n(\"el-form-item\",{attrs:{label:\"tcp 端口\",prop:\"tcpPort\"}},[n(\"el-input\",{attrs:{placeholder:\"11111\",type:\"number\"},model:{value:t.nodeModel.tcpPort,callback:function(e){t.$set(t.nodeModel,\"tcpPort\",e)},expression:\"nodeModel.tcpPort\"}})],1),t._v(\" \"),n(\"el-form-item\",{attrs:{label:\"metric 端口\",prop:\"metricPort\"}},[n(\"el-input\",{attrs:{placeholder:\"11112\",type:\"number\"},model:{value:t.nodeModel.metricPort,callback:function(e){t.$set(t.nodeModel,\"metricPort\",e)},expression:\"nodeModel.metricPort\"}})],1)],1),t._v(\" \"),n(\"div\",{staticClass:\"dialog-footer\",attrs:{slot:\"footer\"},slot:\"footer\"},[n(\"el-button\",{on:{click:function(e){t.dialogFormVisible=!1}}},[t._v(\"取消\")]),t._v(\" \"),n(\"el-button\",{attrs:{type:\"primary\"},on:{click:function(e){return t.dataOperation()}}},[t._v(\"确定\")])],1)],1),t._v(\" \"),n(\"el-dialog\",{attrs:{visible:t.dialogInstances,title:\"instance 列表\",width:\"800px\"},on:{\"update:visible\":function(e){t.dialogInstances=e}}},[n(\"div\",{staticClass:\"filter-container\"},[n(\"el-button\",{staticClass:\"filter-item\",attrs:{type:\"info\"},on:{click:function(e){return t.activeInstances()}}},[t._v(\"刷新列表\")])],1),t._v(\" \"),n(\"el-table\",{directives:[{name:\"loading\",rawName:\"v-loading\",value:t.listLoading2,expression:\"listLoading2\"}],attrs:{data:t.instanceList,\"element-loading-text\":\"Loading\",border:\"\",fit:\"\",\"highlight-current-row\":\"\"}},[n(\"el-table-column\",{attrs:{label:\"Instance 名称\",\"min-width\":\"200\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[t._v(\"\\n          \"+t._s(e.row.name)+\"\\n        \")]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{label:\"状态\",\"min-width\":\"200\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[n(\"el-tag\",{attrs:{type:t._f(\"statusFilter\")(e.row.runningStatus)}},[t._v(t._s(t._f(\"statusLabel\")(e.row.runningStatus)))])]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{label:\"操作\",\"min-width\":\"200\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[n(\"el-dropdown\",{attrs:{trigger:\"click\"}},[n(\"el-button\",{attrs:{type:\"primary\",size:\"mini\"}},[t._v(\"\\n              操作\"),n(\"i\",{staticClass:\"el-icon-arrow-down el-icon--right\"})]),t._v(\" \"),n(\"el-dropdown-menu\",{attrs:{slot:\"dropdown\"},slot:\"dropdown\"},[n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleStartInstance(e.row)}}},[t._v(\"启动\")]),t._v(\" \"),n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleStopInstance(e.row)}}},[t._v(\"停止\")])],1)],1)]}}])})],1)],1)],1)},a=[],i=(n(\"c5f6\"),n(\"c6ed\")),o=n(\"f546\"),l=n(\"d631\"),s=n(\"333d\"),c={components:{Pagination:s[\"a\"]},filters:{statusFilter:function(t){var e={1:\"success\",0:\"gray\",\"-1\":\"danger\"};return e[t]},statusLabel:function(t){var e={1:\"启动\",0:\"停止\",\"-1\":\"断开\"};return e[t]}},data:function(){return{list:null,instanceList:null,listLoading:!0,listLoading2:!0,serverIdTmp:null,canalClusters:[],count:0,listQuery:{name:\"\",ip:\"\",clusterId:null,page:1,size:20},dialogFormVisible:!1,dialogInstances:!1,textMap:{create:\"新建Server信息\",update:\"修改Server信息\"},nodeModel:{id:void 0,clusterId:null,name:null,ip:null,adminPort:11110,tcpPort:11111,metricPort:11112},rules:{name:[{required:!0,message:\"Server 名称不能为空\",trigger:\"change\"}],ip:[{required:!0,message:\"Server IP不能为空\",trigger:\"change\"}],adminPort:[{required:!0,message:\"Server admin端口不能为空\",trigger:\"change\"}]},dialogStatus:\"create\"}},created:function(){var t=this;if(Object(l[\"c\"])().then(function(e){t.canalClusters=e.data}),this.$route.query.clusterId)try{this.listQuery.clusterId=Number(this.$route.query.clusterId)}catch(e){console.log(e)}this.fetchData()},methods:{fetchData:function(){var t=this;this.listLoading=!0,Object(i[\"c\"])(this.listQuery).then(function(e){t.list=e.data.items,t.count=e.data.count}).finally(function(){t.listLoading=!1})},queryData:function(){this.listQuery.page=1,this.fetchData()},resetModel:function(){this.nodeModel={id:void 0,clusterId:null,name:null,ip:null,adminPort:null,tcpPort:null,metricPort:null}},handleCreate:function(){var t=this;this.resetModel(),this.dialogStatus=\"create\",this.dialogFormVisible=!0,this.$nextTick(function(){t.$refs[\"dataForm\"].clearValidate()})},handleInstances:function(t){this.serverIdTmp=t.id,this.activeInstances()},activeInstances:function(){var t=this;this.listLoading2=!0,this.dialogInstances=!0,Object(o[\"d\"])(this.serverIdTmp).then(function(e){t.instanceList=e.data}).finally(function(){t.listLoading2=!1})},dataOperation:function(){var t=this;this.$refs[\"dataForm\"].validate(function(e){e&&(\"create\"===t.dialogStatus&&Object(i[\"a\"])(t.nodeModel).then(function(e){t.operationRes(e)}),\"update\"===t.dialogStatus&&Object(i[\"g\"])(t.nodeModel).then(function(e){t.operationRes(e)}))})},operationRes:function(t){\"success\"===t.data?(this.fetchData(),this.dialogFormVisible=!1,this.$message({message:this.textMap[this.dialogStatus]+\"成功\",type:\"success\"})):this.$message({message:this.textMap[this.dialogStatus]+\"失败\",type:\"error\"})},handleConfig:function(t){null===t.canalCluster?this.$router.push(\"/canalServer/nodeServer/config?serverId=\"+t.id):this.$message({message:\"集群模式Server不允许单独变更配置，请在集群配置变更\",type:\"error\"})},handleUpdate:function(t){var e=this;this.resetModel(),this.nodeModel=Object.assign({},t),this.dialogStatus=\"update\",this.dialogFormVisible=!0,this.$nextTick(function(){e.$refs[\"dataForm\"].clearValidate()})},handleDelete:function(t){var e=this;this.$confirm(\"删除Server信息会导致节点服务停止\",\"确定删除Server信息\",{confirmButtonText:\"确定\",cancelButtonText:\"取消\",type:\"warning\"}).then(function(){Object(i[\"b\"])(t.id).then(function(t){\"success\"===t.data?(e.fetchData(),e.$message({message:\"删除Server信息成功\",type:\"success\"})):e.$message({message:\"删除Server信息失败\",type:\"error\"})})})},handleStart:function(t){var e=this;\"0\"===t.status?this.$confirm(\"启动Server服务\",\"确定启动Server服务\",{confirmButtonText:\"确定\",cancelButtonText:\"取消\",type:\"warning\"}).then(function(){Object(i[\"e\"])(t.id).then(function(t){t.data?(e.fetchData(),e.$message({message:\"启动成功\",type:\"success\"})):e.$message({message:\"启动Server服务出现异常\",type:\"error\"})})}):this.$message({message:\"当前Server不是停止状态，无法启动\",type:\"error\"})},handleStop:function(t){var e=this;\"1\"===t.status?this.$confirm(\"停止Server服务会导致所有Instance都停止服务\",\"确定停止Server服务\",{confirmButtonText:\"确定\",cancelButtonText:\"取消\",type:\"warning\"}).then(function(){Object(i[\"f\"])(t.id).then(function(t){t.data?(e.fetchData(),e.$message({message:\"停止成功\",type:\"success\"})):e.$message({message:\"停止Server服务出现异常\",type:\"error\"})})}):this.$message({message:\"当前Server不是启动状态，无法停止\",type:\"error\"})},handleLog:function(t){this.$router.push(\"nodeServer/log?id=\"+t.id)},handleStartInstance:function(t){var e=this;\"0\"===t.runningStatus?this.$confirm(\"启动Instance服务\",\"确定启动Instance服务\",{confirmButtonText:\"确定\",cancelButtonText:\"取消\",type:\"warning\"}).then(function(){Object(o[\"h\"])(t.id,e.serverIdTmp).then(function(t){t.data?(e.activeInstances(),e.$message({message:\"启动成功, 稍后请刷新列表查看状态\",type:\"success\"})):e.$message({message:\"启动Instance服务出现异常\",type:\"error\"})})}):this.$message({message:\"当前Instance不是停止状态，无法启动\",type:\"error\"})},handleStopInstance:function(t){var e=this;\"1\"===t.runningStatus?this.$confirm(\"集群模式下停止实例其它主机将会抢占执行该实例\",\"停止 Instance 服务\",{confirmButtonText:\"确定\",cancelButtonText:\"取消\",type:\"warning\"}).then(function(){Object(o[\"i\"])(t.id,e.serverIdTmp).then(function(t){t.data?(e.activeInstances(),e.$message({message:\"停止成功, 稍后请刷新列表查看状态\",type:\"success\"})):e.$message({message:\"停止Instance服务出现异常\",type:\"error\"})})}):this.$message({message:\"当前Instance不是运行状态，无法停止\",type:\"error\"})}}},u=c,d=n(\"2877\"),f=Object(d[\"a\"])(u,r,a,!1,null,null,null);e[\"default\"]=f.exports},aa77:function(t,e,n){var r=n(\"5ca1\"),a=n(\"be13\"),i=n(\"79e5\"),o=n(\"fdef\"),l=\"[\"+o+\"]\",s=\"​\",c=RegExp(\"^\"+l+l+\"*\"),u=RegExp(l+l+\"*$\"),d=function(t,e,n){var a={},l=i(function(){return!!o[t]()||s[t]()!=s}),c=a[t]=l?e(f):o[t];n&&(a[n]=c),r(r.P+r.F*l,\"String\",a)},f=d.trim=function(t,e){return t=String(a(t)),1&e&&(t=t.replace(c,\"\")),2&e&&(t=t.replace(u,\"\")),t};t.exports=d},c002:function(t,e,n){},c5f6:function(t,e,n){\"use strict\";var r=n(\"7726\"),a=n(\"69a8\"),i=n(\"2d95\"),o=n(\"5dbc\"),l=n(\"6a99\"),s=n(\"79e5\"),c=n(\"9093\").f,u=n(\"11e9\").f,d=n(\"86cc\").f,f=n(\"aa77\").trim,p=\"Number\",m=r[p],g=m,h=m.prototype,v=i(n(\"2aeb\")(h))==p,b=\"trim\"in String.prototype,_=function(t){var e=l(t,!1);if(\"string\"==typeof e&&e.length>2){e=b?e.trim():f(e,3);var n,r,a,i=e.charCodeAt(0);if(43===i||45===i){if(n=e.charCodeAt(2),88===n||120===n)return NaN}else if(48===i){switch(e.charCodeAt(1)){case 66:case 98:r=2,a=49;break;case 79:case 111:r=8,a=55;break;default:return+e}for(var o,s=e.slice(2),c=0,u=s.length;c<u;c++)if(o=s.charCodeAt(c),o<48||o>a)return NaN;return parseInt(s,r)}}return+e};if(!m(\" 0o1\")||!m(\"0b1\")||m(\"+0x1\")){m=function(t){var e=arguments.length<1?0:t,n=this;return n instanceof m&&(v?s(function(){h.valueOf.call(n)}):i(n)!=p)?o(new g(_(e)),n,m):_(e)};for(var y,S=n(\"9e1e\")?c(g):\"MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,EPSILON,isFinite,isInteger,isNaN,isSafeInteger,MAX_SAFE_INTEGER,MIN_SAFE_INTEGER,parseFloat,parseInt,isInteger\".split(\",\"),w=0;S.length>w;w++)a(g,y=S[w])&&!a(m,y)&&d(m,y,u(g,y));m.prototype=h,h.constructor=m,n(\"2aba\")(r,p,m)}},c6ed:function(t,e,n){\"use strict\";n.d(e,\"c\",function(){return a}),n.d(e,\"a\",function(){return i}),n.d(e,\"g\",function(){return o}),n.d(e,\"b\",function(){return l}),n.d(e,\"e\",function(){return s}),n.d(e,\"f\",function(){return c}),n.d(e,\"d\",function(){return u});var r=n(\"b775\");function a(t){return Object(r[\"a\"])({url:\"/nodeServers\",method:\"get\",params:t})}function i(t){return Object(r[\"a\"])({url:\"/nodeServer\",method:\"post\",data:t})}function o(t){return Object(r[\"a\"])({url:\"/nodeServer\",method:\"put\",data:t})}function l(t){return Object(r[\"a\"])({url:\"/nodeServer/\"+t,method:\"delete\"})}function s(t){return Object(r[\"a\"])({url:\"/nodeServer/start/\"+t,method:\"put\"})}function c(t){return Object(r[\"a\"])({url:\"/nodeServer/stop/\"+t,method:\"put\"})}function u(t){return Object(r[\"a\"])({url:\"/nodeServer/log/\"+t,method:\"get\"})}},d631:function(t,e,n){\"use strict\";n.d(e,\"c\",function(){return a}),n.d(e,\"a\",function(){return i}),n.d(e,\"e\",function(){return o}),n.d(e,\"b\",function(){return l}),n.d(e,\"d\",function(){return s});var r=n(\"b775\");function a(t){return Object(r[\"a\"])({url:\"/canal/clusters\",method:\"get\",params:t})}function i(t){return Object(r[\"a\"])({url:\"/canal/cluster\",method:\"post\",data:t})}function o(t){return Object(r[\"a\"])({url:\"/canal/cluster\",method:\"put\",data:t})}function l(t){return Object(r[\"a\"])({url:\"/canal/cluster/\"+t,method:\"delete\"})}function s(){return Object(r[\"a\"])({url:\"/canal/clustersAndServers\",method:\"get\"})}},f546:function(t,e,n){\"use strict\";n.d(e,\"e\",function(){return a}),n.d(e,\"b\",function(){return i}),n.d(e,\"j\",function(){return o}),n.d(e,\"a\",function(){return l}),n.d(e,\"c\",function(){return s}),n.d(e,\"h\",function(){return c}),n.d(e,\"i\",function(){return u}),n.d(e,\"f\",function(){return d}),n.d(e,\"g\",function(){return f}),n.d(e,\"d\",function(){return p});var r=n(\"b775\");function a(t){return Object(r[\"a\"])({url:\"/canal/instances\",method:\"get\",params:t})}function i(t){return Object(r[\"a\"])({url:\"/canal/instance/\"+t,method:\"get\"})}function o(t){return Object(r[\"a\"])({url:\"/canal/instance\",method:\"put\",data:t})}function l(t){return Object(r[\"a\"])({url:\"/canal/instance\",method:\"post\",data:t})}function s(t){return Object(r[\"a\"])({url:\"/canal/instance/\"+t,method:\"delete\"})}function c(t,e){return Object(r[\"a\"])({url:\"/canal/instance/start/\"+t+\"/\"+e,method:\"put\"})}function u(t,e){return Object(r[\"a\"])({url:\"/canal/instance/stop/\"+t+\"/\"+e,method:\"put\"})}function d(t,e){return Object(r[\"a\"])({url:\"/canal/instance/log/\"+t+\"/\"+e,method:\"get\"})}function f(t,e){return Object(r[\"a\"])({url:\"/canal/instance/status/\"+t+\"?option=\"+e,method:\"put\"})}function p(t){return Object(r[\"a\"])({url:\"/canal/active/instances/\"+t,method:\"get\"})}},fdef:function(t,e){t.exports=\"\\t\\n\\v\\f\\r   ᠎             　\\u2028\\u2029\\ufeff\"}}]);"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/js/chunk-22553be3.e6d72de5.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[\"chunk-22553be3\"],{\"11e9\":function(t,e,n){var a=n(\"52a7\"),r=n(\"4630\"),i=n(\"6821\"),o=n(\"6a99\"),c=n(\"69a8\"),u=n(\"c69a\"),s=Object.getOwnPropertyDescriptor;e.f=n(\"9e1e\")?s:function(t,e){if(t=i(t),e=o(e,!0),u)try{return s(t,e)}catch(n){}if(c(t,e))return r(!a.f.call(t,e),t[e])}},\"1c98\":function(t,e,n){\"use strict\";n.r(e);var a=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n(\"div\",{staticClass:\"app-container\"},[n(\"div\",{staticClass:\"filter-container\"},[n(\"el-input\",{staticClass:\"filter-item\",staticStyle:{width:\"200px\"},attrs:{placeholder:\"Instance 名称\"},model:{value:t.listQuery.name,callback:function(e){t.$set(t.listQuery,\"name\",e)},expression:\"listQuery.name\"}}),t._v(\" \"),n(\"el-select\",{staticClass:\"filter-item\",attrs:{placeholder:\"所属集群/主机\"},model:{value:t.listQuery.clusterServerId,callback:function(e){t.$set(t.listQuery,\"clusterServerId\",e)},expression:\"listQuery.clusterServerId\"}},[n(\"el-option\",{key:\"\",attrs:{label:\"所属集群/主机\",value:\"\"}}),t._v(\" \"),t._l(t.options,function(e){return n(\"el-option-group\",{key:e.label,attrs:{label:e.label}},t._l(e.options,function(t){return n(\"el-option\",{key:t.value,attrs:{label:t.label,value:t.value}})}),1)})],2),t._v(\" \"),n(\"el-button\",{staticClass:\"filter-item\",attrs:{type:\"primary\",icon:\"el-icon-search\",plain:\"\"},on:{click:function(e){return t.queryData()}}},[t._v(\"查询\")]),t._v(\"\\n      \\n    \"),n(\"el-button\",{staticClass:\"filter-item\",attrs:{type:\"primary\"},on:{click:function(e){return t.handleCreate()}}},[t._v(\"新建 Instance\")]),t._v(\" \"),n(\"el-button\",{staticClass:\"filter-item\",attrs:{type:\"info\"},on:{click:function(e){return t.fetchData()}}},[t._v(\"刷新列表\")])],1),t._v(\" \"),n(\"el-table\",{directives:[{name:\"loading\",rawName:\"v-loading\",value:t.listLoading,expression:\"listLoading\"}],attrs:{data:t.list,\"element-loading-text\":\"Loading\",border:\"\",fit:\"\",\"highlight-current-row\":\"\"}},[n(\"el-table-column\",{attrs:{label:\"Instance 名称\",\"min-width\":\"200\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[t._v(\"\\n        \"+t._s(e.row.name)+\"\\n      \")]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{label:\"所属集群\",\"min-width\":\"200\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[null!==e.row.canalCluster?n(\"span\",[t._v(\"\\n          \"+t._s(e.row.canalCluster.name)+\"\\n        \")]):n(\"span\",[t._v(\"-\")])]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{label:\"所属主机\",\"min-width\":\"200\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[null!==e.row.nodeServer?n(\"span\",[t._v(\"\\n          \"+t._s(e.row.nodeServer.name)+\"\\n        \")]):n(\"span\",[t._v(\"-\")])]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{\"class-name\":\"status-col\",label:\"状态\",\"min-width\":\"150\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[n(\"el-tag\",{attrs:{type:t._f(\"statusFilter\")(e.row.runningStatus)}},[t._v(t._s(t._f(\"statusLabel\")(e.row.runningStatus)))])]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{label:\"修改时间\",\"min-width\":\"200\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[t._v(\"\\n        \"+t._s(e.row.modifiedTime)+\"\\n      \")]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{align:\"center\",prop:\"created_at\",label:\"操作\",\"min-width\":\"150\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[n(\"el-dropdown\",{attrs:{trigger:\"click\"}},[n(\"el-button\",{attrs:{type:\"primary\",size:\"mini\"}},[t._v(\"\\n            操作\"),n(\"i\",{staticClass:\"el-icon-arrow-down el-icon--right\"})]),t._v(\" \"),n(\"el-dropdown-menu\",{attrs:{slot:\"dropdown\"},slot:\"dropdown\"},[n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleUpdate(e.row)}}},[t._v(\"修改\")]),t._v(\" \"),n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleDelete(e.row)}}},[t._v(\"删除\")]),t._v(\" \"),n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleStart(e.row)}}},[t._v(\"启动\")]),t._v(\" \"),n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleStop(e.row)}}},[t._v(\"停止\")]),t._v(\" \"),n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleLog(e.row)}}},[t._v(\"日志\")])],1)],1)]}}])})],1),t._v(\" \"),n(\"pagination\",{directives:[{name:\"show\",rawName:\"v-show\",value:t.count>0,expression:\"count>0\"}],attrs:{total:t.count,page:t.listQuery.page,limit:t.listQuery.size},on:{\"update:page\":function(e){return t.$set(t.listQuery,\"page\",e)},\"update:limit\":function(e){return t.$set(t.listQuery,\"size\",e)},pagination:function(e){return t.fetchData()}}})],1)},r=[],i=(n(\"7f7f\"),n(\"f546\")),o=n(\"333d\"),c=n(\"d631\"),u={components:{Pagination:o[\"a\"]},filters:{statusFilter:function(t){var e={1:\"success\",0:\"gray\"};return e[t]},statusLabel:function(t){var e={1:\"启动\",0:\"停止\"};return e[t]}},data:function(){return{list:null,listLoading:!0,dialogFormVisible:!1,nodeServices:[],count:0,options:[],listQuery:{name:\"\",clusterServerId:\"\",page:1,size:20},currentId:null,rules:{id:[{required:!0,message:\"请选择运行Server\",trigger:\"change\"}]}}},created:function(){var t=this;Object(c[\"d\"])().then(function(e){t.options=e.data}),this.fetchData()},methods:{queryData:function(){this.listQuery.page=1,this.fetchData()},fetchData:function(){var t=this;this.listLoading=!0,Object(i[\"e\"])(this.listQuery).then(function(e){t.list=e.data.items,t.count=e.data.count}).finally(function(){t.listLoading=!1})},handleCreate:function(){this.$router.push(\"/canalServer/canalInstance/add\")},handleUpdate:function(t){this.$router.push(\"/canalServer/canalInstance/modify?id=\"+t.id)},handleDelete:function(t){var e=this;this.$confirm(\"删除Instance配置会导致停止\",\"确定删除Instance信息\",{confirmButtonText:\"确定\",cancelButtonText:\"取消\",type:\"warning\"}).then(function(){Object(i[\"c\"])(t.id).then(function(t){\"success\"===t.data?(e.fetchData(),e.$message({message:\"删除Instance信息成功\",type:\"success\"})):e.$message({message:\"删除Instance信息失败\",type:\"error\"})})})},handleStart:function(t){var e=this;this.$confirm(\"启动Instance: \"+t.name,\"确定启动Instance服务\",{confirmButtonText:\"确定\",cancelButtonText:\"取消\",type:\"warning\"}).then(function(){Object(i[\"g\"])(t.id,\"start\").then(function(t){t.data?(e.fetchData(),e.$message({message:\"启动成功, 稍后请刷新列表查看状态\",type:\"success\"})):e.$message({message:\"启动Instance出现异常\",type:\"error\"})})})},handleStop:function(t){var e=this;this.$confirm(\"停止Instance: \"+t.name,\"确定停止Instance服务\",{confirmButtonText:\"确定\",cancelButtonText:\"取消\",type:\"warning\"}).then(function(){Object(i[\"g\"])(t.id,\"stop\").then(function(t){t.data?(e.fetchData(),e.$message({message:\"停止成功, 稍后请刷新列表查看状态\",type:\"success\"})):e.$message({message:\"停止Instance出现异常\",type:\"error\"})})})},handleLog:function(t){null!==t.nodeId?this.$router.push(\"canalInstance/log?id=\"+t.id+\"&nodeId=\"+t.nodeServer.id):this.$message({message:\"当前Instance不是启动状态，无法查看日志\",type:\"warning\"})}}},s=u,l=n(\"2877\"),d=Object(l[\"a\"])(s,a,r,!1,null,null,null);e[\"default\"]=d.exports},\"1ca3\":function(t,e,n){\"use strict\";var a=n(\"c002\"),r=n.n(a);r.a},\"333d\":function(t,e,n){\"use strict\";var a=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n(\"div\",{staticClass:\"pagination-container\",class:{hidden:t.hidden}},[n(\"el-pagination\",t._b({attrs:{background:t.background,\"current-page\":t.currentPage,\"page-size\":t.pageSize,layout:t.layout,\"page-sizes\":t.pageSizes,total:t.total},on:{\"update:currentPage\":function(e){t.currentPage=e},\"update:current-page\":function(e){t.currentPage=e},\"update:pageSize\":function(e){t.pageSize=e},\"update:page-size\":function(e){t.pageSize=e},\"size-change\":t.handleSizeChange,\"current-change\":t.handleCurrentChange}},\"el-pagination\",t.$attrs,!1))],1)},r=[];n(\"c5f6\");Math.easeInOutQuad=function(t,e,n,a){return t/=a/2,t<1?n/2*t*t+e:(t--,-n/2*(t*(t-2)-1)+e)};var i=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||function(t){window.setTimeout(t,1e3/60)}}();function o(t){document.documentElement.scrollTop=t,document.body.parentNode.scrollTop=t,document.body.scrollTop=t}function c(){return document.documentElement.scrollTop||document.body.parentNode.scrollTop||document.body.scrollTop}function u(t,e,n){var a=c(),r=t-a,u=20,s=0;e=\"undefined\"===typeof e?500:e;var l=function t(){s+=u;var c=Math.easeInOutQuad(s,a,r,e);o(c),s<e?i(t):n&&\"function\"===typeof n&&n()};l()}var s={name:\"Pagination\",props:{total:{required:!0,type:Number},page:{type:Number,default:1},limit:{type:Number,default:20},pageSizes:{type:Array,default:function(){return[10,20,30,50]}},layout:{type:String,default:\"total, sizes, prev, pager, next, jumper\"},background:{type:Boolean,default:!0},autoScroll:{type:Boolean,default:!0},hidden:{type:Boolean,default:!1}},computed:{currentPage:{get:function(){return this.page},set:function(t){this.$emit(\"update:page\",t)}},pageSize:{get:function(){return this.limit},set:function(t){this.$emit(\"update:limit\",t)}}},methods:{handleSizeChange:function(t){this.$emit(\"pagination\",{page:this.currentPage,limit:t}),this.autoScroll&&u(0,800)},handleCurrentChange:function(t){this.$emit(\"pagination\",{page:t,limit:this.pageSize}),this.autoScroll&&u(0,800)}}},l=s,d=(n(\"1ca3\"),n(\"2877\")),f=Object(d[\"a\"])(l,a,r,!1,null,\"cebf2f0c\",null);e[\"a\"]=f.exports},\"5dbc\":function(t,e,n){var a=n(\"d3f4\"),r=n(\"8b97\").set;t.exports=function(t,e,n){var i,o=e.constructor;return o!==n&&\"function\"==typeof o&&(i=o.prototype)!==n.prototype&&a(i)&&r&&r(t,i),t}},\"8b97\":function(t,e,n){var a=n(\"d3f4\"),r=n(\"cb7c\"),i=function(t,e){if(r(t),!a(e)&&null!==e)throw TypeError(e+\": can't set as prototype!\")};t.exports={set:Object.setPrototypeOf||(\"__proto__\"in{}?function(t,e,a){try{a=n(\"9b43\")(Function.call,n(\"11e9\").f(Object.prototype,\"__proto__\").set,2),a(t,[]),e=!(t instanceof Array)}catch(r){e=!0}return function(t,n){return i(t,n),e?t.__proto__=n:a(t,n),t}}({},!1):void 0),check:i}},9093:function(t,e,n){var a=n(\"ce10\"),r=n(\"e11e\").concat(\"length\",\"prototype\");e.f=Object.getOwnPropertyNames||function(t){return a(t,r)}},aa77:function(t,e,n){var a=n(\"5ca1\"),r=n(\"be13\"),i=n(\"79e5\"),o=n(\"fdef\"),c=\"[\"+o+\"]\",u=\"​\",s=RegExp(\"^\"+c+c+\"*\"),l=RegExp(c+c+\"*$\"),d=function(t,e,n){var r={},c=i(function(){return!!o[t]()||u[t]()!=u}),s=r[t]=c?e(f):o[t];n&&(r[n]=s),a(a.P+a.F*c,\"String\",r)},f=d.trim=function(t,e){return t=String(r(t)),1&e&&(t=t.replace(s,\"\")),2&e&&(t=t.replace(l,\"\")),t};t.exports=d},c002:function(t,e,n){},c5f6:function(t,e,n){\"use strict\";var a=n(\"7726\"),r=n(\"69a8\"),i=n(\"2d95\"),o=n(\"5dbc\"),c=n(\"6a99\"),u=n(\"79e5\"),s=n(\"9093\").f,l=n(\"11e9\").f,d=n(\"86cc\").f,f=n(\"aa77\").trim,p=\"Number\",m=a[p],g=m,h=m.prototype,v=i(n(\"2aeb\")(h))==p,b=\"trim\"in String.prototype,y=function(t){var e=c(t,!1);if(\"string\"==typeof e&&e.length>2){e=b?e.trim():f(e,3);var n,a,r,i=e.charCodeAt(0);if(43===i||45===i){if(n=e.charCodeAt(2),88===n||120===n)return NaN}else if(48===i){switch(e.charCodeAt(1)){case 66:case 98:a=2,r=49;break;case 79:case 111:a=8,r=55;break;default:return+e}for(var o,u=e.slice(2),s=0,l=u.length;s<l;s++)if(o=u.charCodeAt(s),o<48||o>r)return NaN;return parseInt(u,a)}}return+e};if(!m(\" 0o1\")||!m(\"0b1\")||m(\"+0x1\")){m=function(t){var e=arguments.length<1?0:t,n=this;return n instanceof m&&(v?u(function(){h.valueOf.call(n)}):i(n)!=p)?o(new g(y(e)),n,m):y(e)};for(var _,w=n(\"9e1e\")?s(g):\"MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,EPSILON,isFinite,isInteger,isNaN,isSafeInteger,MAX_SAFE_INTEGER,MIN_SAFE_INTEGER,parseFloat,parseInt,isInteger\".split(\",\"),S=0;w.length>S;S++)r(g,_=w[S])&&!r(m,_)&&d(m,_,l(g,_));m.prototype=h,h.constructor=m,n(\"2aba\")(a,p,m)}},d631:function(t,e,n){\"use strict\";n.d(e,\"c\",function(){return r}),n.d(e,\"a\",function(){return i}),n.d(e,\"e\",function(){return o}),n.d(e,\"b\",function(){return c}),n.d(e,\"d\",function(){return u});var a=n(\"b775\");function r(t){return Object(a[\"a\"])({url:\"/canal/clusters\",method:\"get\",params:t})}function i(t){return Object(a[\"a\"])({url:\"/canal/cluster\",method:\"post\",data:t})}function o(t){return Object(a[\"a\"])({url:\"/canal/cluster\",method:\"put\",data:t})}function c(t){return Object(a[\"a\"])({url:\"/canal/cluster/\"+t,method:\"delete\"})}function u(){return Object(a[\"a\"])({url:\"/canal/clustersAndServers\",method:\"get\"})}},f546:function(t,e,n){\"use strict\";n.d(e,\"e\",function(){return r}),n.d(e,\"b\",function(){return i}),n.d(e,\"j\",function(){return o}),n.d(e,\"a\",function(){return c}),n.d(e,\"c\",function(){return u}),n.d(e,\"h\",function(){return s}),n.d(e,\"i\",function(){return l}),n.d(e,\"f\",function(){return d}),n.d(e,\"g\",function(){return f}),n.d(e,\"d\",function(){return p});var a=n(\"b775\");function r(t){return Object(a[\"a\"])({url:\"/canal/instances\",method:\"get\",params:t})}function i(t){return Object(a[\"a\"])({url:\"/canal/instance/\"+t,method:\"get\"})}function o(t){return Object(a[\"a\"])({url:\"/canal/instance\",method:\"put\",data:t})}function c(t){return Object(a[\"a\"])({url:\"/canal/instance\",method:\"post\",data:t})}function u(t){return Object(a[\"a\"])({url:\"/canal/instance/\"+t,method:\"delete\"})}function s(t,e){return Object(a[\"a\"])({url:\"/canal/instance/start/\"+t+\"/\"+e,method:\"put\"})}function l(t,e){return Object(a[\"a\"])({url:\"/canal/instance/stop/\"+t+\"/\"+e,method:\"put\"})}function d(t,e){return Object(a[\"a\"])({url:\"/canal/instance/log/\"+t+\"/\"+e,method:\"get\"})}function f(t,e){return Object(a[\"a\"])({url:\"/canal/instance/status/\"+t+\"?option=\"+e,method:\"put\"})}function p(t){return Object(a[\"a\"])({url:\"/canal/active/instances/\"+t,method:\"get\"})}},fdef:function(t,e){t.exports=\"\\t\\n\\v\\f\\r   ᠎             　\\u2028\\u2029\\ufeff\"}}]);"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/js/chunk-2301924a.1774b851.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[\"chunk-2301924a\"],{\"10df\":function(t,e,n){},1248:function(t,e,n){\"use strict\";n.r(e);var r=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n(\"div\",[n(\"el-form\",{ref:\"form\",attrs:{model:t.form}},[n(\"div\",{staticClass:\"filter-container\",staticStyle:{\"padding-left\":\"10px\",\"padding-top\":\"20px\"}},[n(\"el-input\",{staticClass:\"filter-item\",staticStyle:{width:\"200px\"},attrs:{placeholder:\"Instance名称\"},model:{value:t.form.name,callback:function(e){t.$set(t.form,\"name\",e)},expression:\"form.name\"}}),t._v(\" \"),n(\"el-select\",{staticClass:\"filter-item\",attrs:{placeholder:\"所属集群/主机\"},model:{value:t.form.clusterServerId,callback:function(e){t.$set(t.form,\"clusterServerId\",e)},expression:\"form.clusterServerId\"}},t._l(t.options,function(e){return n(\"el-option-group\",{key:e.label,attrs:{label:e.label}},t._l(e.options,function(t){return n(\"el-option\",{key:t.value,attrs:{label:t.label,value:t.value}})}),1)}),1),t._v(\" \"),n(\"el-button\",{staticClass:\"filter-item\",attrs:{type:\"primary\"},on:{click:t.onSubmit}},[t._v(\"保存\")]),t._v(\" \"),n(\"el-button\",{staticClass:\"filter-item\",attrs:{type:\"info\"},on:{click:t.onBack}},[t._v(\"返回\")])],1),t._v(\" \"),n(\"editor\",{attrs:{lang:\"properties\",theme:\"chrome\",width:\"100%\",height:800},on:{init:t.editorInit},model:{value:t.form.content,callback:function(e){t.$set(t.form,\"content\",e)},expression:\"form.content\"}})],1)],1)},a=[],c=(n(\"7f7f\"),n(\"f546\")),o=n(\"d631\"),u={components:{editor:n(\"7c9e\")},data:function(){return{options:[],form:{name:\"\",content:\"\",clusterServerId:\"\"}}},created:function(){var t=this;Object(o[\"d\"])().then(function(e){t.options=e.data})},methods:{editorInit:function(){n(\"2099\"),n(\"be9d\"),n(\"2968\"),n(\"e0e5\"),n(\"bb36\"),n(\"0329\"),n(\"95b8\"),n(\"6a21\")},onSubmit:function(){var t=this;\"\"!==this.form.name?\"\"!==this.form.clusterServerId?null!==this.form.content&&\"\"!==this.form.content?this.$confirm(\"确定新建\",\"确定新建\",{confirmButtonText:\"确定\",cancelButtonText:\"取消\",type:\"warning\"}).then(function(){Object(c[\"a\"])(t.form).then(function(e){\"success\"===e.data?(t.$message({message:\"新建成功\",type:\"success\"}),t.$router.push(\"/canalServer/canalInstances\")):t.$message({message:\"新建失败\",type:\"error\"})})}):this.$message({message:\"请输入配置内容\",type:\"error\"}):this.$message({message:\"请选择所属集群/主机\",type:\"error\"}):this.$message({message:\"请输入Instance名称\",type:\"error\"})},onBack:function(){history.go(-1)}}},i=u,s=(n(\"2eb8\"),n(\"2877\")),l=Object(s[\"a\"])(i,r,a,!1,null,\"28f0cd0f\",null);e[\"default\"]=l.exports},\"2eb8\":function(t,e,n){\"use strict\";var r=n(\"10df\"),a=n.n(r);a.a},d631:function(t,e,n){\"use strict\";n.d(e,\"c\",function(){return a}),n.d(e,\"a\",function(){return c}),n.d(e,\"e\",function(){return o}),n.d(e,\"b\",function(){return u}),n.d(e,\"d\",function(){return i});var r=n(\"b775\");function a(t){return Object(r[\"a\"])({url:\"/canal/clusters\",method:\"get\",params:t})}function c(t){return Object(r[\"a\"])({url:\"/canal/cluster\",method:\"post\",data:t})}function o(t){return Object(r[\"a\"])({url:\"/canal/cluster\",method:\"put\",data:t})}function u(t){return Object(r[\"a\"])({url:\"/canal/cluster/\"+t,method:\"delete\"})}function i(){return Object(r[\"a\"])({url:\"/canal/clustersAndServers\",method:\"get\"})}},f546:function(t,e,n){\"use strict\";n.d(e,\"e\",function(){return a}),n.d(e,\"b\",function(){return c}),n.d(e,\"j\",function(){return o}),n.d(e,\"a\",function(){return u}),n.d(e,\"c\",function(){return i}),n.d(e,\"h\",function(){return s}),n.d(e,\"i\",function(){return l}),n.d(e,\"f\",function(){return f}),n.d(e,\"g\",function(){return d}),n.d(e,\"d\",function(){return m});var r=n(\"b775\");function a(t){return Object(r[\"a\"])({url:\"/canal/instances\",method:\"get\",params:t})}function c(t){return Object(r[\"a\"])({url:\"/canal/instance/\"+t,method:\"get\"})}function o(t){return Object(r[\"a\"])({url:\"/canal/instance\",method:\"put\",data:t})}function u(t){return Object(r[\"a\"])({url:\"/canal/instance\",method:\"post\",data:t})}function i(t){return Object(r[\"a\"])({url:\"/canal/instance/\"+t,method:\"delete\"})}function s(t,e){return Object(r[\"a\"])({url:\"/canal/instance/start/\"+t+\"/\"+e,method:\"put\"})}function l(t,e){return Object(r[\"a\"])({url:\"/canal/instance/stop/\"+t+\"/\"+e,method:\"put\"})}function f(t,e){return Object(r[\"a\"])({url:\"/canal/instance/log/\"+t+\"/\"+e,method:\"get\"})}function d(t,e){return Object(r[\"a\"])({url:\"/canal/instance/status/\"+t+\"?option=\"+e,method:\"put\"})}function m(t){return Object(r[\"a\"])({url:\"/canal/active/instances/\"+t,method:\"get\"})}}}]);"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/js/chunk-2b9b6c5c.cc2181b9.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[\"chunk-2b9b6c5c\"],{\"11e9\":function(t,e,n){var a=n(\"52a7\"),r=n(\"4630\"),i=n(\"6821\"),o=n(\"6a99\"),c=n(\"69a8\"),u=n(\"c69a\"),s=Object.getOwnPropertyDescriptor;e.f=n(\"9e1e\")?s:function(t,e){if(t=i(t),e=o(e,!0),u)try{return s(t,e)}catch(n){}if(c(t,e))return r(!a.f.call(t,e),t[e])}},\"1c98\":function(t,e,n){\"use strict\";n.r(e);var a=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n(\"div\",{staticClass:\"app-container\"},[n(\"div\",{staticClass:\"filter-container\"},[n(\"el-input\",{staticClass:\"filter-item\",staticStyle:{width:\"200px\"},attrs:{placeholder:\"Instance 名称\"},model:{value:t.listQuery.name,callback:function(e){t.$set(t.listQuery,\"name\",e)},expression:\"listQuery.name\"}}),t._v(\" \"),n(\"el-select\",{staticClass:\"filter-item\",attrs:{placeholder:\"所属集群/主机\"},model:{value:t.listQuery.clusterServerId,callback:function(e){t.$set(t.listQuery,\"clusterServerId\",e)},expression:\"listQuery.clusterServerId\"}},[n(\"el-option\",{key:\"\",attrs:{label:\"所属集群/主机\",value:\"\"}}),t._v(\" \"),t._l(t.options,function(e){return n(\"el-option-group\",{key:e.label,attrs:{label:e.label}},t._l(e.options,function(t){return n(\"el-option\",{key:t.value,attrs:{label:t.label,value:t.value}})}),1)})],2),t._v(\" \"),n(\"el-button\",{staticClass:\"filter-item\",attrs:{type:\"primary\",icon:\"el-icon-search\",plain:\"\"},on:{click:function(e){return t.queryData()}}},[t._v(\"查询\")]),t._v(\"\\n      \\n    \"),n(\"el-button\",{staticClass:\"filter-item\",attrs:{type:\"primary\"},on:{click:function(e){return t.handleCreate()}}},[t._v(\"新建 Instance\")]),t._v(\" \"),n(\"el-button\",{staticClass:\"filter-item\",attrs:{type:\"info\"},on:{click:function(e){return t.fetchData()}}},[t._v(\"刷新列表\")])],1),t._v(\" \"),n(\"el-table\",{directives:[{name:\"loading\",rawName:\"v-loading\",value:t.listLoading,expression:\"listLoading\"}],attrs:{data:t.list,\"element-loading-text\":\"Loading\",border:\"\",fit:\"\",\"highlight-current-row\":\"\"}},[n(\"el-table-column\",{attrs:{label:\"Instance 名称\",\"min-width\":\"200\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[t._v(\"\\n        \"+t._s(e.row.name)+\"\\n      \")]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{label:\"所属集群\",\"min-width\":\"200\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[null!==e.row.canalCluster?n(\"span\",[t._v(\"\\n          \"+t._s(e.row.canalCluster.name)+\"\\n        \")]):n(\"span\",[t._v(\"-\")])]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{label:\"所属主机\",\"min-width\":\"200\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[null!==e.row.nodeServer?n(\"span\",[t._v(\"\\n          \"+t._s(e.row.nodeServer.name)+\"\\n        \")]):n(\"span\",[t._v(\"-\")])]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{\"class-name\":\"status-col\",label:\"状态\",\"min-width\":\"150\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[n(\"el-tag\",{attrs:{type:t._f(\"statusFilter\")(e.row.runningStatus)}},[t._v(t._s(t._f(\"statusLabel\")(e.row.runningStatus)))])]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{label:\"修改时间\",\"min-width\":\"200\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[t._v(\"\\n        \"+t._s(e.row.modifiedTime)+\"\\n      \")]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{align:\"center\",prop:\"created_at\",label:\"操作\",\"min-width\":\"150\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[n(\"el-dropdown\",{attrs:{trigger:\"click\"}},[n(\"el-button\",{attrs:{type:\"primary\",size:\"mini\"}},[t._v(\"\\n            操作\"),n(\"i\",{staticClass:\"el-icon-arrow-down el-icon--right\"})]),t._v(\" \"),n(\"el-dropdown-menu\",{attrs:{slot:\"dropdown\"},slot:\"dropdown\"},[n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleUpdate(e.row)}}},[t._v(\"修改\")]),t._v(\" \"),n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleDelete(e.row)}}},[t._v(\"删除\")]),t._v(\" \"),n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleStart(e.row)}}},[t._v(\"启动\")]),t._v(\" \"),n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleStop(e.row)}}},[t._v(\"停止\")]),t._v(\" \"),n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleLog(e.row)}}},[t._v(\"日志\")])],1)],1)]}}])})],1),t._v(\" \"),n(\"pagination\",{directives:[{name:\"show\",rawName:\"v-show\",value:t.count>0,expression:\"count>0\"}],attrs:{total:t.count,page:t.listQuery.page,limit:t.listQuery.size},on:{\"update:page\":function(e){return t.$set(t.listQuery,\"page\",e)},\"update:limit\":function(e){return t.$set(t.listQuery,\"size\",e)},pagination:function(e){return t.fetchData()}}})],1)},r=[],i=(n(\"7f7f\"),n(\"f546\")),o=n(\"333d\"),c=n(\"d631\"),u={components:{Pagination:o[\"a\"]},filters:{statusFilter:function(t){var e={1:\"success\",0:\"gray\"};return e[t]},statusLabel:function(t){var e={1:\"启动\",0:\"停止\"};return e[t]}},data:function(){return{list:null,listLoading:!0,dialogFormVisible:!1,nodeServices:[],count:0,options:[],listQuery:{name:\"\",clusterServerId:\"\",page:1,size:20},currentId:null,rules:{id:[{required:!0,message:\"请选择运行Server\",trigger:\"change\"}]}}},created:function(){var t=this;Object(c[\"d\"])().then(function(e){t.options=e.data}),this.fetchData()},methods:{queryData:function(){this.listQuery.page=1,this.fetchData()},fetchData:function(){var t=this;this.listLoading=!0,Object(i[\"e\"])(this.listQuery).then(function(e){t.list=e.data.items,t.count=e.data.count}).finally(function(){t.listLoading=!1})},handleCreate:function(){this.$router.push(\"/canalServer/canalInstance/add\")},handleUpdate:function(t){this.$router.push(\"/canalServer/canalInstance/modify?id=\"+t.id)},handleDelete:function(t){var e=this;this.$confirm(\"删除Instance配置会导致停止\",\"确定删除Instance信息\",{confirmButtonText:\"确定\",cancelButtonText:\"取消\",type:\"warning\"}).then(function(){Object(i[\"c\"])(t.id).then(function(t){\"success\"===t.data?(e.fetchData(),e.$message({message:\"删除Instance信息成功\",type:\"success\"})):e.$message({message:\"删除Instance信息失败\",type:\"error\"})})})},handleStart:function(t){var e=this;this.$confirm(\"启动Instance: \"+t.name,\"确定启动Instance服务\",{confirmButtonText:\"确定\",cancelButtonText:\"取消\",type:\"warning\"}).then(function(){Object(i[\"h\"])(t.id,\"start\").then(function(t){t.data?(e.fetchData(),e.$message({message:\"启动成功, 稍后请刷新列表查看状态\",type:\"success\"})):e.$message({message:\"启动Instance出现异常\",type:\"error\"})})})},handleStop:function(t){var e=this;this.$confirm(\"停止Instance: \"+t.name,\"确定停止Instance服务\",{confirmButtonText:\"确定\",cancelButtonText:\"取消\",type:\"warning\"}).then(function(){Object(i[\"h\"])(t.id,\"stop\").then(function(t){t.data?(e.fetchData(),e.$message({message:\"停止成功, 稍后请刷新列表查看状态\",type:\"success\"})):e.$message({message:\"停止Instance出现异常\",type:\"error\"})})})},handleLog:function(t){null!==t.nodeId?this.$router.push(\"canalInstance/log?id=\"+t.id+\"&nodeId=\"+t.nodeServer.id):this.$message({message:\"当前Instance不是启动状态，无法查看日志\",type:\"warning\"})}}},s=u,l=n(\"2877\"),d=Object(l[\"a\"])(s,a,r,!1,null,null,null);e[\"default\"]=d.exports},\"333d\":function(t,e,n){\"use strict\";var a=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n(\"div\",{staticClass:\"pagination-container\",class:{hidden:t.hidden}},[n(\"el-pagination\",t._b({attrs:{background:t.background,\"current-page\":t.currentPage,\"page-size\":t.pageSize,layout:t.layout,\"page-sizes\":t.pageSizes,total:t.total},on:{\"update:currentPage\":function(e){t.currentPage=e},\"update:current-page\":function(e){t.currentPage=e},\"update:pageSize\":function(e){t.pageSize=e},\"update:page-size\":function(e){t.pageSize=e},\"size-change\":t.handleSizeChange,\"current-change\":t.handleCurrentChange}},\"el-pagination\",t.$attrs,!1))],1)},r=[];n(\"c5f6\");Math.easeInOutQuad=function(t,e,n,a){return t/=a/2,t<1?n/2*t*t+e:(t--,-n/2*(t*(t-2)-1)+e)};var i=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||function(t){window.setTimeout(t,1e3/60)}}();function o(t){document.documentElement.scrollTop=t,document.body.parentNode.scrollTop=t,document.body.scrollTop=t}function c(){return document.documentElement.scrollTop||document.body.parentNode.scrollTop||document.body.scrollTop}function u(t,e,n){var a=c(),r=t-a,u=20,s=0;e=\"undefined\"===typeof e?500:e;var l=function t(){s+=u;var c=Math.easeInOutQuad(s,a,r,e);o(c),s<e?i(t):n&&\"function\"===typeof n&&n()};l()}var s={name:\"Pagination\",props:{total:{required:!0,type:Number},page:{type:Number,default:1},limit:{type:Number,default:20},pageSizes:{type:Array,default:function(){return[10,20,30,50]}},layout:{type:String,default:\"total, sizes, prev, pager, next, jumper\"},background:{type:Boolean,default:!0},autoScroll:{type:Boolean,default:!0},hidden:{type:Boolean,default:!1}},computed:{currentPage:{get:function(){return this.page},set:function(t){this.$emit(\"update:page\",t)}},pageSize:{get:function(){return this.limit},set:function(t){this.$emit(\"update:limit\",t)}}},methods:{handleSizeChange:function(t){this.$emit(\"pagination\",{page:this.currentPage,limit:t}),this.autoScroll&&u(0,800)},handleCurrentChange:function(t){this.$emit(\"pagination\",{page:t,limit:this.pageSize}),this.autoScroll&&u(0,800)}}},l=s,d=(n(\"dfcf\"),n(\"2877\")),f=Object(d[\"a\"])(l,a,r,!1,null,\"38ef71f0\",null);e[\"a\"]=f.exports},\"5dbc\":function(t,e,n){var a=n(\"d3f4\"),r=n(\"8b97\").set;t.exports=function(t,e,n){var i,o=e.constructor;return o!==n&&\"function\"==typeof o&&(i=o.prototype)!==n.prototype&&a(i)&&r&&r(t,i),t}},\"690d\":function(t,e,n){},\"8b97\":function(t,e,n){var a=n(\"d3f4\"),r=n(\"cb7c\"),i=function(t,e){if(r(t),!a(e)&&null!==e)throw TypeError(e+\": can't set as prototype!\")};t.exports={set:Object.setPrototypeOf||(\"__proto__\"in{}?function(t,e,a){try{a=n(\"9b43\")(Function.call,n(\"11e9\").f(Object.prototype,\"__proto__\").set,2),a(t,[]),e=!(t instanceof Array)}catch(r){e=!0}return function(t,n){return i(t,n),e?t.__proto__=n:a(t,n),t}}({},!1):void 0),check:i}},9093:function(t,e,n){var a=n(\"ce10\"),r=n(\"e11e\").concat(\"length\",\"prototype\");e.f=Object.getOwnPropertyNames||function(t){return a(t,r)}},aa77:function(t,e,n){var a=n(\"5ca1\"),r=n(\"be13\"),i=n(\"79e5\"),o=n(\"fdef\"),c=\"[\"+o+\"]\",u=\"​\",s=RegExp(\"^\"+c+c+\"*\"),l=RegExp(c+c+\"*$\"),d=function(t,e,n){var r={},c=i(function(){return!!o[t]()||u[t]()!=u}),s=r[t]=c?e(f):o[t];n&&(r[n]=s),a(a.P+a.F*c,\"String\",r)},f=d.trim=function(t,e){return t=String(r(t)),1&e&&(t=t.replace(s,\"\")),2&e&&(t=t.replace(l,\"\")),t};t.exports=d},c5f6:function(t,e,n){\"use strict\";var a=n(\"7726\"),r=n(\"69a8\"),i=n(\"2d95\"),o=n(\"5dbc\"),c=n(\"6a99\"),u=n(\"79e5\"),s=n(\"9093\").f,l=n(\"11e9\").f,d=n(\"86cc\").f,f=n(\"aa77\").trim,p=\"Number\",m=a[p],h=m,g=m.prototype,v=i(n(\"2aeb\")(g))==p,b=\"trim\"in String.prototype,y=function(t){var e=c(t,!1);if(\"string\"==typeof e&&e.length>2){e=b?e.trim():f(e,3);var n,a,r,i=e.charCodeAt(0);if(43===i||45===i){if(n=e.charCodeAt(2),88===n||120===n)return NaN}else if(48===i){switch(e.charCodeAt(1)){case 66:case 98:a=2,r=49;break;case 79:case 111:a=8,r=55;break;default:return+e}for(var o,u=e.slice(2),s=0,l=u.length;s<l;s++)if(o=u.charCodeAt(s),o<48||o>r)return NaN;return parseInt(u,a)}}return+e};if(!m(\" 0o1\")||!m(\"0b1\")||m(\"+0x1\")){m=function(t){var e=arguments.length<1?0:t,n=this;return n instanceof m&&(v?u(function(){g.valueOf.call(n)}):i(n)!=p)?o(new h(y(e)),n,m):y(e)};for(var _,w=n(\"9e1e\")?s(h):\"MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,EPSILON,isFinite,isInteger,isNaN,isSafeInteger,MAX_SAFE_INTEGER,MIN_SAFE_INTEGER,parseFloat,parseInt,isInteger\".split(\",\"),S=0;w.length>S;S++)r(h,_=w[S])&&!r(m,_)&&d(m,_,l(h,_));m.prototype=g,g.constructor=m,n(\"2aba\")(a,p,m)}},d631:function(t,e,n){\"use strict\";n.d(e,\"c\",function(){return r}),n.d(e,\"a\",function(){return i}),n.d(e,\"e\",function(){return o}),n.d(e,\"b\",function(){return c}),n.d(e,\"d\",function(){return u});var a=n(\"b775\");function r(t){return Object(a[\"a\"])({url:\"/canal/clusters\",method:\"get\",params:t})}function i(t){return Object(a[\"a\"])({url:\"/canal/cluster\",method:\"post\",data:t})}function o(t){return Object(a[\"a\"])({url:\"/canal/cluster\",method:\"put\",data:t})}function c(t){return Object(a[\"a\"])({url:\"/canal/cluster/\"+t,method:\"delete\"})}function u(){return Object(a[\"a\"])({url:\"/canal/clustersAndServers\",method:\"get\"})}},dfcf:function(t,e,n){\"use strict\";var a=n(\"690d\"),r=n.n(a);r.a},f546:function(t,e,n){\"use strict\";n.d(e,\"e\",function(){return r}),n.d(e,\"b\",function(){return i}),n.d(e,\"k\",function(){return o}),n.d(e,\"a\",function(){return c}),n.d(e,\"c\",function(){return u}),n.d(e,\"i\",function(){return s}),n.d(e,\"j\",function(){return l}),n.d(e,\"g\",function(){return d}),n.d(e,\"h\",function(){return f}),n.d(e,\"d\",function(){return p}),n.d(e,\"f\",function(){return m});var a=n(\"b775\");function r(t){return Object(a[\"a\"])({url:\"/canal/instances\",method:\"get\",params:t})}function i(t){return Object(a[\"a\"])({url:\"/canal/instance/\"+t,method:\"get\"})}function o(t){return Object(a[\"a\"])({url:\"/canal/instance\",method:\"put\",data:t})}function c(t){return Object(a[\"a\"])({url:\"/canal/instance\",method:\"post\",data:t})}function u(t){return Object(a[\"a\"])({url:\"/canal/instance/\"+t,method:\"delete\"})}function s(t,e){return Object(a[\"a\"])({url:\"/canal/instance/start/\"+t+\"/\"+e,method:\"put\"})}function l(t,e){return Object(a[\"a\"])({url:\"/canal/instance/stop/\"+t+\"/\"+e,method:\"put\"})}function d(t,e){return Object(a[\"a\"])({url:\"/canal/instance/log/\"+t+\"/\"+e,method:\"get\"})}function f(t,e){return Object(a[\"a\"])({url:\"/canal/instance/status/\"+t+\"?option=\"+e,method:\"put\"})}function p(t){return Object(a[\"a\"])({url:\"/canal/active/instances/\"+t,method:\"get\"})}function m(){return Object(a[\"a\"])({url:\"/canal/instance/template\",method:\"get\"})}},fdef:function(t,e){t.exports=\"\\t\\n\\v\\f\\r   ᠎             　\\u2028\\u2029\\ufeff\"}}]);"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/js/chunk-37c49cbf.64d26540.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[\"chunk-37c49cbf\"],{3671:function(t,e,n){\"use strict\";var a=n(\"afe4\"),c=n.n(a);c.a},9406:function(t,e,n){\"use strict\";n.r(e);var a=function(){var t=this,e=t.$createElement;t._self._c;return t._m(0)},c=[function(){var t=this,e=t.$createElement,n=t._self._c||e;return n(\"div\",{staticClass:\"dashboard-container\"},[n(\"div\",{staticClass:\"dashboard-text\"},[t._v(\" \")])])}],s=n(\"db72\"),r=n(\"2f62\"),u={name:\"Dashboard\",computed:Object(s[\"a\"])({},Object(r[\"b\"])([\"name\"])),mounted:function(){this.$router.push(\"/canalServer\")}},i=u,o=(n(\"3671\"),n(\"2877\")),d=Object(o[\"a\"])(i,a,c,!1,null,\"42037c2b\",null);e[\"default\"]=d.exports},afe4:function(t,e,n){}}]);"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/js/chunk-37c49cbf.92ebe0ae.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[\"chunk-37c49cbf\"],{3671:function(t,e,n){\"use strict\";var a=n(\"afe4\"),c=n.n(a);c.a},9406:function(t,e,n){\"use strict\";n.r(e);var a=function(){var t=this,e=t.$createElement;t._self._c;return t._m(0)},c=[function(){var t=this,e=t.$createElement,n=t._self._c||e;return n(\"div\",{staticClass:\"dashboard-container\"},[n(\"div\",{staticClass:\"dashboard-text\"},[t._v(\" \")])])}],s=n(\"db72\"),r=n(\"2f62\"),u={name:\"Dashboard\",computed:Object(s[\"a\"])({},Object(r[\"b\"])([\"name\"])),mounted:function(){this.$router.push(\"/canalServer\")}},i=u,o=(n(\"3671\"),n(\"2877\")),d=Object(o[\"a\"])(i,a,c,!1,null,\"42037c2b\",null);e[\"default\"]=d.exports},afe4:function(t,e,n){}}]);"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/js/chunk-49959c8b.058266cb.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[\"chunk-49959c8b\"],{\"26fc\":function(t,s,a){t.exports=a.p+\"static/img/404_cloud.0f4bc32b.png\"},\"8cdb\":function(t,s,a){\"use strict\";a.r(s);var e=function(){var t=this,s=t.$createElement,a=t._self._c||s;return a(\"div\",{staticClass:\"wscn-http404-container\"},[a(\"div\",{staticClass:\"wscn-http404\"},[t._m(0),t._v(\" \"),a(\"div\",{staticClass:\"bullshit\"},[a(\"div\",{staticClass:\"bullshit__oops\"},[t._v(\"OOPS!\")]),t._v(\" \"),t._m(1),t._v(\" \"),a(\"div\",{staticClass:\"bullshit__headline\"},[t._v(t._s(t.message))]),t._v(\" \"),a(\"div\",{staticClass:\"bullshit__info\"},[t._v(\"Please check that the URL you entered is correct, or click the button below to return to the homepage.\")]),t._v(\" \"),a(\"a\",{staticClass:\"bullshit__return-home\",attrs:{href:\"\"}},[t._v(\"Back to home\")])])])])},c=[function(){var t=this,s=t.$createElement,e=t._self._c||s;return e(\"div\",{staticClass:\"pic-404\"},[e(\"img\",{staticClass:\"pic-404__parent\",attrs:{src:a(\"a36b\"),alt:\"404\"}}),t._v(\" \"),e(\"img\",{staticClass:\"pic-404__child left\",attrs:{src:a(\"26fc\"),alt:\"404\"}}),t._v(\" \"),e(\"img\",{staticClass:\"pic-404__child mid\",attrs:{src:a(\"26fc\"),alt:\"404\"}}),t._v(\" \"),e(\"img\",{staticClass:\"pic-404__child right\",attrs:{src:a(\"26fc\"),alt:\"404\"}})])},function(){var t=this,s=t.$createElement,a=t._self._c||s;return a(\"div\",{staticClass:\"bullshit__info\"},[t._v(\"All rights reserved\\n        \"),a(\"a\",{staticStyle:{color:\"#20a0ff\"},attrs:{href:\"https://wallstreetcn.com\",target:\"_blank\"}},[t._v(\"wallstreetcn\")])])}],i={name:\"Page404\",computed:{message:function(){return\"The webmaster said that you can not enter this page...\"}}},l=i,n=(a(\"97ef\"),a(\"2877\")),r=Object(n[\"a\"])(l,e,c,!1,null,\"c095f994\",null);s[\"default\"]=r.exports},\"97ef\":function(t,s,a){\"use strict\";var e=a(\"b51e\"),c=a.n(e);c.a},a36b:function(t,s,a){t.exports=a.p+\"static/img/404.a57b6f31.png\"},b51e:function(t,s,a){}}]);"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/js/chunk-49959c8b.6d226f70.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[\"chunk-49959c8b\"],{\"26fc\":function(t,s,a){t.exports=a.p+\"static/img/404_cloud.0f4bc32b.png\"},\"8cdb\":function(t,s,a){\"use strict\";a.r(s);var e=function(){var t=this,s=t.$createElement,a=t._self._c||s;return a(\"div\",{staticClass:\"wscn-http404-container\"},[a(\"div\",{staticClass:\"wscn-http404\"},[t._m(0),t._v(\" \"),a(\"div\",{staticClass:\"bullshit\"},[a(\"div\",{staticClass:\"bullshit__oops\"},[t._v(\"OOPS!\")]),t._v(\" \"),t._m(1),t._v(\" \"),a(\"div\",{staticClass:\"bullshit__headline\"},[t._v(t._s(t.message))]),t._v(\" \"),a(\"div\",{staticClass:\"bullshit__info\"},[t._v(\"Please check that the URL you entered is correct, or click the button below to return to the homepage.\")]),t._v(\" \"),a(\"a\",{staticClass:\"bullshit__return-home\",attrs:{href:\"\"}},[t._v(\"Back to home\")])])])])},c=[function(){var t=this,s=t.$createElement,e=t._self._c||s;return e(\"div\",{staticClass:\"pic-404\"},[e(\"img\",{staticClass:\"pic-404__parent\",attrs:{src:a(\"a36b\"),alt:\"404\"}}),t._v(\" \"),e(\"img\",{staticClass:\"pic-404__child left\",attrs:{src:a(\"26fc\"),alt:\"404\"}}),t._v(\" \"),e(\"img\",{staticClass:\"pic-404__child mid\",attrs:{src:a(\"26fc\"),alt:\"404\"}}),t._v(\" \"),e(\"img\",{staticClass:\"pic-404__child right\",attrs:{src:a(\"26fc\"),alt:\"404\"}})])},function(){var t=this,s=t.$createElement,a=t._self._c||s;return a(\"div\",{staticClass:\"bullshit__info\"},[t._v(\"All rights reserved\\n        \"),a(\"a\",{staticStyle:{color:\"#20a0ff\"},attrs:{href:\"https://wallstreetcn.com\",target:\"_blank\"}},[t._v(\"wallstreetcn\")])])}],i={name:\"Page404\",computed:{message:function(){return\"The webmaster said that you can not enter this page...\"}}},l=i,n=(a(\"97ef\"),a(\"2877\")),r=Object(n[\"a\"])(l,e,c,!1,null,\"c095f994\",null);s[\"default\"]=r.exports},\"97ef\":function(t,s,a){\"use strict\";var e=a(\"b51e\"),c=a.n(e);c.a},a36b:function(t,s,a){t.exports=a.p+\"static/img/404.a57b6f31.png\"},b51e:function(t,s,a){}}]);"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/js/chunk-4f09fed2.d107437b.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[\"chunk-4f09fed2\"],{\"68d6\":function(t,e,n){\"use strict\";var r=n(\"9d07\"),o=n.n(r);o.a},\"9d07\":function(t,e,n){},c6ed:function(t,e,n){\"use strict\";n.d(e,\"c\",function(){return o}),n.d(e,\"a\",function(){return c}),n.d(e,\"g\",function(){return u}),n.d(e,\"b\",function(){return a}),n.d(e,\"e\",function(){return d}),n.d(e,\"f\",function(){return i}),n.d(e,\"d\",function(){return f});var r=n(\"b775\");function o(t){return Object(r[\"a\"])({url:\"/nodeServers\",method:\"get\",params:t})}function c(t){return Object(r[\"a\"])({url:\"/nodeServer\",method:\"post\",data:t})}function u(t){return Object(r[\"a\"])({url:\"/nodeServer\",method:\"put\",data:t})}function a(t){return Object(r[\"a\"])({url:\"/nodeServer/\"+t,method:\"delete\"})}function d(t){return Object(r[\"a\"])({url:\"/nodeServer/start/\"+t,method:\"put\"})}function i(t){return Object(r[\"a\"])({url:\"/nodeServer/stop/\"+t,method:\"put\"})}function f(t){return Object(r[\"a\"])({url:\"/nodeServer/log/\"+t,method:\"get\"})}},caf8:function(t,e,n){\"use strict\";n.r(e);var r=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n(\"div\",[n(\"el-form\",{ref:\"form\",attrs:{model:t.form}},[n(\"div\",{staticStyle:{\"padding-left\":\"10px\",\"padding-right\":\"10px\",\"padding-top\":\"20px\"}},[n(\"el-form-item\",[t._v(\"\\n        canal.log    \\n        \"),n(\"el-button\",{attrs:{type:\"primary\"},on:{click:t.onRefresh}},[t._v(\"刷新\")]),t._v(\" \"),n(\"el-button\",{attrs:{type:\"info\"},on:{click:t.onBack}},[t._v(\"返回\")])],1),t._v(\" \"),n(\"el-input\",{attrs:{rows:35,readonly:\"readonly\",type:\"textarea\"},model:{value:t.form.desc,callback:function(e){t.$set(t.form,\"desc\",e)},expression:\"form.desc\"}})],1)])],1)},o=[],c=n(\"c6ed\"),u={data:function(){return{form:{desc:\"\"}}},created:function(){this.fetchData()},methods:{fetchData:function(){var t=this;Object(c[\"d\"])(this.$route.query.id).then(function(e){t.form.desc=e.data})},onRefresh:function(){this.fetchData()},onBack:function(){history.go(-1)}}},a=u,d=(n(\"68d6\"),n(\"2877\")),i=Object(d[\"a\"])(a,r,o,!1,null,\"64c3fae5\",null);e[\"default\"]=i.exports}}]);"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/js/chunk-4f09fed2.ff28d88d.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[\"chunk-4f09fed2\"],{\"68d6\":function(t,e,n){\"use strict\";var r=n(\"9d07\"),o=n.n(r);o.a},\"9d07\":function(t,e,n){},c6ed:function(t,e,n){\"use strict\";n.d(e,\"c\",function(){return o}),n.d(e,\"a\",function(){return c}),n.d(e,\"g\",function(){return u}),n.d(e,\"b\",function(){return a}),n.d(e,\"e\",function(){return d}),n.d(e,\"f\",function(){return i}),n.d(e,\"d\",function(){return f});var r=n(\"b775\");function o(t){return Object(r[\"a\"])({url:\"/nodeServers\",method:\"get\",params:t})}function c(t){return Object(r[\"a\"])({url:\"/nodeServer\",method:\"post\",data:t})}function u(t){return Object(r[\"a\"])({url:\"/nodeServer\",method:\"put\",data:t})}function a(t){return Object(r[\"a\"])({url:\"/nodeServer/\"+t,method:\"delete\"})}function d(t){return Object(r[\"a\"])({url:\"/nodeServer/start/\"+t,method:\"put\"})}function i(t){return Object(r[\"a\"])({url:\"/nodeServer/stop/\"+t,method:\"put\"})}function f(t){return Object(r[\"a\"])({url:\"/nodeServer/log/\"+t,method:\"get\"})}},caf8:function(t,e,n){\"use strict\";n.r(e);var r=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n(\"div\",[n(\"el-form\",{ref:\"form\",attrs:{model:t.form}},[n(\"div\",{staticStyle:{\"padding-left\":\"10px\",\"padding-right\":\"10px\",\"padding-top\":\"20px\"}},[n(\"el-form-item\",[t._v(\"\\n        canal.log    \\n        \"),n(\"el-button\",{attrs:{type:\"primary\"},on:{click:t.onRefresh}},[t._v(\"刷新\")]),t._v(\" \"),n(\"el-button\",{attrs:{type:\"info\"},on:{click:t.onBack}},[t._v(\"返回\")])],1),t._v(\" \"),n(\"el-input\",{attrs:{rows:35,readonly:\"readonly\",type:\"textarea\"},model:{value:t.form.desc,callback:function(e){t.$set(t.form,\"desc\",e)},expression:\"form.desc\"}})],1)])],1)},o=[],c=n(\"c6ed\"),u={data:function(){return{form:{desc:\"\"}}},created:function(){this.fetchData()},methods:{fetchData:function(){var t=this;Object(c[\"d\"])(this.$route.query.id).then(function(e){t.form.desc=e.data})},onRefresh:function(){this.fetchData()},onBack:function(){history.go(-1)}}},a=u,d=(n(\"68d6\"),n(\"2877\")),i=Object(d[\"a\"])(a,r,o,!1,null,\"64c3fae5\",null);e[\"default\"]=i.exports}}]);"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/js/chunk-55380ff2.430ee174.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[\"chunk-55380ff2\"],{d631:function(t,e,n){\"use strict\";n.d(e,\"c\",function(){return i}),n.d(e,\"a\",function(){return r}),n.d(e,\"e\",function(){return l}),n.d(e,\"b\",function(){return s}),n.d(e,\"d\",function(){return o});var a=n(\"b775\");function i(t){return Object(a[\"a\"])({url:\"/canal/clusters\",method:\"get\",params:t})}function r(t){return Object(a[\"a\"])({url:\"/canal/cluster\",method:\"post\",data:t})}function l(t){return Object(a[\"a\"])({url:\"/canal/cluster\",method:\"put\",data:t})}function s(t){return Object(a[\"a\"])({url:\"/canal/cluster/\"+t,method:\"delete\"})}function o(){return Object(a[\"a\"])({url:\"/canal/clustersAndServers\",method:\"get\"})}},e509:function(t,e,n){\"use strict\";n.r(e);var a=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n(\"div\",{staticClass:\"app-container\"},[n(\"div\",{staticClass:\"filter-container\"},[n(\"el-button\",{staticClass:\"filter-item\",attrs:{type:\"primary\"},on:{click:function(e){return t.handleCreate()}}},[t._v(\"新建集群\")])],1),t._v(\" \"),n(\"el-table\",{directives:[{name:\"loading\",rawName:\"v-loading\",value:t.listLoading,expression:\"listLoading\"}],attrs:{data:t.list,\"element-loading-text\":\"Loading\",border:\"\",fit:\"\",\"highlight-current-row\":\"\"}},[n(\"el-table-column\",{attrs:{label:\"集群名称\",\"min-width\":\"200\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[t._v(\"\\n        \"+t._s(e.row.name)+\"\\n      \")]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{label:\"ZK地址\",\"min-width\":\"300\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[n(\"span\",[t._v(t._s(e.row.zkHosts))])]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{align:\"center\",prop:\"created_at\",label:\"操作\",\"min-width\":\"150\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[n(\"el-dropdown\",{attrs:{trigger:\"click\"}},[n(\"el-button\",{attrs:{type:\"primary\",size:\"mini\"}},[t._v(\"\\n            操作\"),n(\"i\",{staticClass:\"el-icon-arrow-down el-icon--right\"})]),t._v(\" \"),n(\"el-dropdown-menu\",{attrs:{slot:\"dropdown\"},slot:\"dropdown\"},[n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleConfig(e.row)}}},[t._v(\"主配置\")]),t._v(\" \"),n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleUpdate(e.row)}}},[t._v(\"修改集群\")]),t._v(\" \"),n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleDelete(e.row)}}},[t._v(\"删除集群\")]),t._v(\" \"),n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleView(e.row)}}},[t._v(\"查看Server\")])],1)],1)]}}])})],1),t._v(\" \"),n(\"el-dialog\",{attrs:{visible:t.dialogFormVisible,title:t.textMap[t.dialogStatus],width:\"600px\"},on:{\"update:visible\":function(e){t.dialogFormVisible=e}}},[n(\"el-form\",{ref:\"dataForm\",staticStyle:{width:\"400px\",\"margin-left\":\"30px\"},attrs:{rules:t.rules,model:t.canalCluster,\"label-position\":\"left\",\"label-width\":\"120px\"}},[n(\"el-form-item\",{attrs:{label:\"集群名称\",prop:\"name\"}},[n(\"el-input\",{model:{value:t.canalCluster.name,callback:function(e){t.$set(t.canalCluster,\"name\",e)},expression:\"canalCluster.name\"}})],1),t._v(\" \"),n(\"el-form-item\",{attrs:{label:\"ZK地址\",prop:\"zkHosts\"}},[n(\"el-input\",{model:{value:t.canalCluster.zkHosts,callback:function(e){t.$set(t.canalCluster,\"zkHosts\",e)},expression:\"canalCluster.zkHosts\"}})],1)],1),t._v(\" \"),n(\"div\",{staticClass:\"dialog-footer\",attrs:{slot:\"footer\"},slot:\"footer\"},[n(\"el-button\",{on:{click:function(e){t.dialogFormVisible=!1}}},[t._v(\"取消\")]),t._v(\" \"),n(\"el-button\",{attrs:{type:\"primary\"},on:{click:function(e){return t.dataOperation()}}},[t._v(\"确定\")])],1)],1)],1)},i=[],r=n(\"d631\"),l={filters:{statusFilter:function(t){var e={1:\"success\",0:\"gray\",\"-1\":\"danger\"};return e[t]},statusLabel:function(t){var e={1:\"启动\",0:\"停止\",\"-1\":\"断开\"};return e[t]}},data:function(){return{list:null,listLoading:!0,listQuery:{name:\"\",ip:\"\"},dialogFormVisible:!1,textMap:{create:\"新建集群信息\",update:\"修改集群信息\"},canalCluster:{id:null,name:null,zkHosts:null},rules:{name:[{required:!0,message:\"集群名称不能为空\",trigger:\"change\"}],zkHosts:[{required:!0,message:\"zk地址不能为空\",trigger:\"change\"}]},dialogStatus:\"create\"}},created:function(){this.fetchData()},methods:{fetchData:function(){var t=this;this.listLoading=!0,Object(r[\"c\"])(this.listQuery).then(function(e){t.list=e.data}).finally(function(){t.listLoading=!1})},resetModel:function(){this.canalCluster={id:null,name:null,zkHosts:null}},handleCreate:function(){var t=this;this.resetModel(),this.dialogStatus=\"create\",this.dialogFormVisible=!0,this.$nextTick(function(){t.$refs[\"dataForm\"].clearValidate()})},dataOperation:function(){var t=this;this.$refs[\"dataForm\"].validate(function(e){e&&(\"create\"===t.dialogStatus&&Object(r[\"a\"])(t.canalCluster).then(function(e){t.operationRes(e)}),\"update\"===t.dialogStatus&&Object(r[\"e\"])(t.canalCluster).then(function(e){t.operationRes(e)}))})},operationRes:function(t){\"success\"===t.data?(this.fetchData(),this.dialogFormVisible=!1,this.$message({message:this.textMap[this.dialogStatus]+\"成功\",type:\"success\"})):this.$message({message:this.textMap[this.dialogStatus]+\"失败\",type:\"error\"})},handleView:function(t){this.$router.push(\"/canalServer/nodeServers?clusterId=\"+t.id)},handleConfig:function(t){this.$router.push(\"/canalServer/nodeServer/config?clusterId=\"+t.id)},handleUpdate:function(t){var e=this;this.resetModel(),this.canalCluster=Object.assign({},t),this.dialogStatus=\"update\",this.dialogFormVisible=!0,this.$nextTick(function(){e.$refs[\"dataForm\"].clearValidate()})},handleDelete:function(t){var e=this;this.$confirm(\"删除集群信息会导致服务停止\",\"确定删除集群信息\",{confirmButtonText:\"确定\",cancelButtonText:\"取消\",type:\"warning\"}).then(function(){Object(r[\"b\"])(t.id).then(function(t){\"success\"===t.data?(e.fetchData(),e.$message({message:\"删除集群信息成功\",type:\"success\"})):e.$message({message:\"删除集群信息失败\",type:\"error\"})})})}}},s=l,o=n(\"2877\"),c=Object(o[\"a\"])(s,a,i,!1,null,null,null);e[\"default\"]=c.exports}}]);"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/js/chunk-55380ff2.681c71c9.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[\"chunk-55380ff2\"],{d631:function(t,e,n){\"use strict\";n.d(e,\"c\",function(){return i}),n.d(e,\"a\",function(){return r}),n.d(e,\"e\",function(){return l}),n.d(e,\"b\",function(){return s}),n.d(e,\"d\",function(){return o});var a=n(\"b775\");function i(t){return Object(a[\"a\"])({url:\"/canal/clusters\",method:\"get\",params:t})}function r(t){return Object(a[\"a\"])({url:\"/canal/cluster\",method:\"post\",data:t})}function l(t){return Object(a[\"a\"])({url:\"/canal/cluster\",method:\"put\",data:t})}function s(t){return Object(a[\"a\"])({url:\"/canal/cluster/\"+t,method:\"delete\"})}function o(){return Object(a[\"a\"])({url:\"/canal/clustersAndServers\",method:\"get\"})}},e509:function(t,e,n){\"use strict\";n.r(e);var a=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n(\"div\",{staticClass:\"app-container\"},[n(\"div\",{staticClass:\"filter-container\"},[n(\"el-button\",{staticClass:\"filter-item\",attrs:{type:\"primary\"},on:{click:function(e){return t.handleCreate()}}},[t._v(\"新建集群\")])],1),t._v(\" \"),n(\"el-table\",{directives:[{name:\"loading\",rawName:\"v-loading\",value:t.listLoading,expression:\"listLoading\"}],attrs:{data:t.list,\"element-loading-text\":\"Loading\",border:\"\",fit:\"\",\"highlight-current-row\":\"\"}},[n(\"el-table-column\",{attrs:{label:\"集群名称\",\"min-width\":\"200\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[t._v(\"\\n        \"+t._s(e.row.name)+\"\\n      \")]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{label:\"ZK地址\",\"min-width\":\"300\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[n(\"span\",[t._v(t._s(e.row.zkHosts))])]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{align:\"center\",prop:\"created_at\",label:\"操作\",\"min-width\":\"150\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[n(\"el-dropdown\",{attrs:{trigger:\"click\"}},[n(\"el-button\",{attrs:{type:\"primary\",size:\"mini\"}},[t._v(\"\\n            操作\"),n(\"i\",{staticClass:\"el-icon-arrow-down el-icon--right\"})]),t._v(\" \"),n(\"el-dropdown-menu\",{attrs:{slot:\"dropdown\"},slot:\"dropdown\"},[n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleConfig(e.row)}}},[t._v(\"主配置\")]),t._v(\" \"),n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleUpdate(e.row)}}},[t._v(\"修改集群\")]),t._v(\" \"),n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleDelete(e.row)}}},[t._v(\"删除集群\")]),t._v(\" \"),n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleView(e.row)}}},[t._v(\"查看Server\")])],1)],1)]}}])})],1),t._v(\" \"),n(\"el-dialog\",{attrs:{visible:t.dialogFormVisible,title:t.textMap[t.dialogStatus],width:\"600px\"},on:{\"update:visible\":function(e){t.dialogFormVisible=e}}},[n(\"el-form\",{ref:\"dataForm\",staticStyle:{width:\"400px\",\"margin-left\":\"30px\"},attrs:{rules:t.rules,model:t.canalCluster,\"label-position\":\"left\",\"label-width\":\"120px\"}},[n(\"el-form-item\",{attrs:{label:\"集群名称\",prop:\"name\"}},[n(\"el-input\",{model:{value:t.canalCluster.name,callback:function(e){t.$set(t.canalCluster,\"name\",e)},expression:\"canalCluster.name\"}})],1),t._v(\" \"),n(\"el-form-item\",{attrs:{label:\"ZK地址\",prop:\"zkHosts\"}},[n(\"el-input\",{model:{value:t.canalCluster.zkHosts,callback:function(e){t.$set(t.canalCluster,\"zkHosts\",e)},expression:\"canalCluster.zkHosts\"}})],1)],1),t._v(\" \"),n(\"div\",{staticClass:\"dialog-footer\",attrs:{slot:\"footer\"},slot:\"footer\"},[n(\"el-button\",{on:{click:function(e){t.dialogFormVisible=!1}}},[t._v(\"取消\")]),t._v(\" \"),n(\"el-button\",{attrs:{type:\"primary\"},on:{click:function(e){return t.dataOperation()}}},[t._v(\"确定\")])],1)],1)],1)},i=[],r=n(\"d631\"),l={filters:{statusFilter:function(t){var e={1:\"success\",0:\"gray\",\"-1\":\"danger\"};return e[t]},statusLabel:function(t){var e={1:\"启动\",0:\"停止\",\"-1\":\"断开\"};return e[t]}},data:function(){return{list:null,listLoading:!0,listQuery:{name:\"\",ip:\"\"},dialogFormVisible:!1,textMap:{create:\"新建集群信息\",update:\"修改集群信息\"},canalCluster:{id:null,name:null,zkHosts:null},rules:{name:[{required:!0,message:\"集群名称不能为空\",trigger:\"change\"}],zkHosts:[{required:!0,message:\"zk地址不能为空\",trigger:\"change\"}]},dialogStatus:\"create\"}},created:function(){this.fetchData()},methods:{fetchData:function(){var t=this;this.listLoading=!0,Object(r[\"c\"])(this.listQuery).then(function(e){t.list=e.data}).finally(function(){t.listLoading=!1})},resetModel:function(){this.canalCluster={id:null,name:null,zkHosts:null}},handleCreate:function(){var t=this;this.resetModel(),this.dialogStatus=\"create\",this.dialogFormVisible=!0,this.$nextTick(function(){t.$refs[\"dataForm\"].clearValidate()})},dataOperation:function(){var t=this;this.$refs[\"dataForm\"].validate(function(e){e&&(\"create\"===t.dialogStatus&&Object(r[\"a\"])(t.canalCluster).then(function(e){t.operationRes(e)}),\"update\"===t.dialogStatus&&Object(r[\"e\"])(t.canalCluster).then(function(e){t.operationRes(e)}))})},operationRes:function(t){\"success\"===t.data?(this.fetchData(),this.dialogFormVisible=!1,this.$message({message:this.textMap[this.dialogStatus]+\"成功\",type:\"success\"})):this.$message({message:this.textMap[this.dialogStatus]+\"失败\",type:\"error\"})},handleView:function(t){this.$router.push(\"/canalServer/nodeServers?clusterId=\"+t.id)},handleConfig:function(t){this.$router.push(\"/canalServer/nodeServer/config?clusterId=\"+t.id)},handleUpdate:function(t){var e=this;this.resetModel(),this.canalCluster=Object.assign({},t),this.dialogStatus=\"update\",this.dialogFormVisible=!0,this.$nextTick(function(){e.$refs[\"dataForm\"].clearValidate()})},handleDelete:function(t){var e=this;this.$confirm(\"删除集群信息会导致服务停止\",\"确定删除集群信息\",{confirmButtonText:\"确定\",cancelButtonText:\"取消\",type:\"warning\"}).then(function(){Object(r[\"b\"])(t.id).then(function(t){\"success\"===t.data?(e.fetchData(),e.$message({message:\"删除集群信息成功\",type:\"success\"})):e.$message({message:\"删除集群信息失败\",type:\"error\"})})})}}},s=l,o=n(\"2877\"),c=Object(o[\"a\"])(s,a,i,!1,null,null,null);e[\"default\"]=c.exports}}]);"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/js/chunk-5afa45f5.79ddcc04.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[\"chunk-5afa45f5\"],{\"0984\":function(t,e,n){},\"0f47\":function(t,e,n){\"use strict\";var o=n(\"0984\"),r=n.n(o);r.a},aa99:function(t,e,n){\"use strict\";n.r(e);var o=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n(\"div\",[n(\"el-form\",{ref:\"form\",attrs:{model:t.form}},[n(\"div\",{staticStyle:{\"padding-left\":\"10px\",\"padding-top\":\"20px\"}},[n(\"el-form-item\",[t._v(\"\\n        \"+t._s(t.form.name)+\"    \\n        \"),n(\"el-button\",{attrs:{type:\"primary\"},on:{click:t.onSubmit}},[t._v(\"保存\")]),t._v(\" \"),n(\"el-button\",{attrs:{type:\"warning\"},on:{click:t.onCancel}},[t._v(\"重置\")]),t._v(\" \"),n(\"el-button\",{attrs:{type:\"success\"},on:{click:t.onLoadTemplate}},[t._v(\"载入模板\")]),t._v(\" \"),n(\"el-button\",{attrs:{type:\"info\"},on:{click:t.onBack}},[t._v(\"返回\")])],1)],1),t._v(\" \"),n(\"editor\",{attrs:{lang:\"properties\",theme:\"chrome\",width:\"100%\",height:800},on:{init:t.editorInit},model:{value:t.form.content,callback:function(e){t.$set(t.form,\"content\",e)},expression:\"form.content\"}})],1)],1)},r=[],a=(n(\"7f7f\"),n(\"b775\"));function c(t,e){return Object(a[\"a\"])({url:\"/canal/config/\"+t+\"/\"+e,method:\"get\"})}function i(t){return Object(a[\"a\"])({url:\"/canal/config\",method:\"put\",data:t})}function s(){return Object(a[\"a\"])({url:\"/canal/config/template\",method:\"get\"})}var u={components:{editor:n(\"7c9e\")},data:function(){return{form:{id:null,name:\"\",content:\"\",serverId:null,clusterId:null}}},created:function(){this.loadCanalConfig()},methods:{editorInit:function(){n(\"2099\"),n(\"be9d\"),n(\"2968\"),n(\"e0e5\"),n(\"bb36\"),n(\"0329\"),n(\"95b8\"),n(\"6a21\")},loadCanalConfig:function(){var t=this,e=0,n=0;this.$route.query.clusterId?e=this.$route.query.clusterId:this.$route.query.serverId&&(n=this.$route.query.serverId),c(e,n).then(function(e){var n=e.data;t.form.id=n.id,t.form.name=n.name,t.form.content=n.content,t.form.serverId=t.$route.query.serverId,t.form.clusterId=t.$route.query.clusterId})},onSubmit:function(){var t=this;null!==this.form.content&&\"\"!==this.form.content?this.$confirm(\"修改主配置可能会导致Server重启，是否继续？\",\"确定修改\",{confirmButtonText:\"确定\",cancelButtonText:\"取消\",type:\"warning\"}).then(function(){i(t.form).then(function(e){\"success\"===e.data?(t.$message({message:\"保存成功\",type:\"success\"}),t.loadCanalConfig()):t.$message({message:\"保存失败\",type:\"error\"})})}):this.$message({message:\"配置内容不能为空\",type:\"error\"})},onCancel:function(){this.loadCanalConfig()},onBack:function(){history.go(-1)},onLoadTemplate:function(){var t=this;s().then(function(e){t.form.content=e.data})}}},f=u,l=(n(\"0f47\"),n(\"2877\")),m=Object(l[\"a\"])(f,o,r,!1,null,\"2e6a6604\",null);e[\"default\"]=m.exports}}]);"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/js/chunk-5b373aad.90a2d8e7.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[\"chunk-5b373aad\"],{1248:function(t,e,n){\"use strict\";n.r(e);var r=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n(\"div\",[n(\"el-form\",{ref:\"form\",attrs:{model:t.form}},[n(\"div\",{staticClass:\"filter-container\",staticStyle:{\"padding-left\":\"10px\",\"padding-top\":\"20px\"}},[n(\"el-input\",{staticClass:\"filter-item\",staticStyle:{width:\"200px\"},attrs:{placeholder:\"Instance名称\"},model:{value:t.form.name,callback:function(e){t.$set(t.form,\"name\",e)},expression:\"form.name\"}}),t._v(\" \"),n(\"el-select\",{staticClass:\"filter-item\",attrs:{placeholder:\"所属集群/主机\"},model:{value:t.form.clusterServerId,callback:function(e){t.$set(t.form,\"clusterServerId\",e)},expression:\"form.clusterServerId\"}},t._l(t.options,function(e){return n(\"el-option-group\",{key:e.label,attrs:{label:e.label}},t._l(e.options,function(t){return n(\"el-option\",{key:t.value,attrs:{label:t.label,value:t.value}})}),1)}),1),t._v(\" \"),n(\"el-button\",{staticClass:\"filter-item\",attrs:{type:\"primary\"},on:{click:t.onSubmit}},[t._v(\"保存\")]),t._v(\" \"),n(\"el-button\",{staticClass:\"filter-item\",attrs:{type:\"success\"},on:{click:t.onLoadTemplate}},[t._v(\"载入模板\")]),t._v(\" \"),n(\"el-button\",{staticClass:\"filter-item\",attrs:{type:\"info\"},on:{click:t.onBack}},[t._v(\"返回\")])],1),t._v(\" \"),n(\"editor\",{attrs:{lang:\"properties\",theme:\"chrome\",width:\"100%\",height:800},on:{init:t.editorInit},model:{value:t.form.content,callback:function(e){t.$set(t.form,\"content\",e)},expression:\"form.content\"}})],1)],1)},a=[],c=(n(\"7f7f\"),n(\"f546\")),o=n(\"d631\"),u={components:{editor:n(\"7c9e\")},data:function(){return{options:[],form:{name:\"\",content:\"\",clusterServerId:\"\"}}},created:function(){var t=this;Object(o[\"d\"])().then(function(e){t.options=e.data})},methods:{editorInit:function(){n(\"2099\"),n(\"be9d\"),n(\"2968\"),n(\"e0e5\"),n(\"bb36\"),n(\"0329\"),n(\"95b8\"),n(\"6a21\")},onSubmit:function(){var t=this;\"\"!==this.form.name?\"\"!==this.form.clusterServerId?null!==this.form.content&&\"\"!==this.form.content?this.$confirm(\"确定新建\",\"确定新建\",{confirmButtonText:\"确定\",cancelButtonText:\"取消\",type:\"warning\"}).then(function(){Object(c[\"a\"])(t.form).then(function(e){\"success\"===e.data?(t.$message({message:\"新建成功\",type:\"success\"}),t.$router.push(\"/canalServer/canalInstances\")):t.$message({message:\"新建失败\",type:\"error\"})})}):this.$message({message:\"请输入配置内容\",type:\"error\"}):this.$message({message:\"请选择所属集群/主机\",type:\"error\"}):this.$message({message:\"请输入Instance名称\",type:\"error\"})},onBack:function(){history.go(-1)},onLoadTemplate:function(){var t=this;Object(c[\"f\"])().then(function(e){t.form.content=e.data})}}},i=u,s=(n(\"890e\"),n(\"2877\")),l=Object(s[\"a\"])(i,r,a,!1,null,\"e884438a\",null);e[\"default\"]=l.exports},\"41be\":function(t,e,n){},\"890e\":function(t,e,n){\"use strict\";var r=n(\"41be\"),a=n.n(r);a.a},d631:function(t,e,n){\"use strict\";n.d(e,\"c\",function(){return a}),n.d(e,\"a\",function(){return c}),n.d(e,\"e\",function(){return o}),n.d(e,\"b\",function(){return u}),n.d(e,\"d\",function(){return i});var r=n(\"b775\");function a(t){return Object(r[\"a\"])({url:\"/canal/clusters\",method:\"get\",params:t})}function c(t){return Object(r[\"a\"])({url:\"/canal/cluster\",method:\"post\",data:t})}function o(t){return Object(r[\"a\"])({url:\"/canal/cluster\",method:\"put\",data:t})}function u(t){return Object(r[\"a\"])({url:\"/canal/cluster/\"+t,method:\"delete\"})}function i(){return Object(r[\"a\"])({url:\"/canal/clustersAndServers\",method:\"get\"})}},f546:function(t,e,n){\"use strict\";n.d(e,\"e\",function(){return a}),n.d(e,\"b\",function(){return c}),n.d(e,\"k\",function(){return o}),n.d(e,\"a\",function(){return u}),n.d(e,\"c\",function(){return i}),n.d(e,\"i\",function(){return s}),n.d(e,\"j\",function(){return l}),n.d(e,\"g\",function(){return f}),n.d(e,\"h\",function(){return d}),n.d(e,\"d\",function(){return m}),n.d(e,\"f\",function(){return p});var r=n(\"b775\");function a(t){return Object(r[\"a\"])({url:\"/canal/instances\",method:\"get\",params:t})}function c(t){return Object(r[\"a\"])({url:\"/canal/instance/\"+t,method:\"get\"})}function o(t){return Object(r[\"a\"])({url:\"/canal/instance\",method:\"put\",data:t})}function u(t){return Object(r[\"a\"])({url:\"/canal/instance\",method:\"post\",data:t})}function i(t){return Object(r[\"a\"])({url:\"/canal/instance/\"+t,method:\"delete\"})}function s(t,e){return Object(r[\"a\"])({url:\"/canal/instance/start/\"+t+\"/\"+e,method:\"put\"})}function l(t,e){return Object(r[\"a\"])({url:\"/canal/instance/stop/\"+t+\"/\"+e,method:\"put\"})}function f(t,e){return Object(r[\"a\"])({url:\"/canal/instance/log/\"+t+\"/\"+e,method:\"get\"})}function d(t,e){return Object(r[\"a\"])({url:\"/canal/instance/status/\"+t+\"?option=\"+e,method:\"put\"})}function m(t){return Object(r[\"a\"])({url:\"/canal/active/instances/\"+t,method:\"get\"})}function p(){return Object(r[\"a\"])({url:\"/canal/instance/template\",method:\"get\"})}}}]);"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/js/chunk-69386cf0.76d77f5c.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[\"chunk-69386cf0\"],{2829:function(e,t,s){},\"646d\":function(e,t,s){\"use strict\";var r=s(\"2829\"),o=s.n(r);o.a},\"9fb7\":function(e,t,s){\"use strict\";s.r(t);var r=function(){var e=this,t=e.$createElement,s=e._self._c||t;return s(\"div\",{staticClass:\"app-container\",staticStyle:{width:\"600px\"}},[s(\"el-form\",{ref:\"form\",attrs:{rules:e.rules,model:e.form,\"label-width\":\"120px\"}},[s(\"el-form-item\",{attrs:{label:\"用户名\",prop:\"username\"}},[s(\"el-input\",{staticStyle:{width:\"200px\"},model:{value:e.form.username,callback:function(t){e.$set(e.form,\"username\",t)},expression:\"form.username\"}})],1),e._v(\" \"),s(\"el-form-item\",{attrs:{label:\"旧密码\",prop:\"oldPassword\"}},[s(\"el-input\",{staticStyle:{width:\"200px\"},attrs:{type:\"password\"},model:{value:e.form.oldPassword,callback:function(t){e.$set(e.form,\"oldPassword\",t)},expression:\"form.oldPassword\"}})],1),e._v(\" \"),s(\"el-form-item\",{attrs:{label:\"密码\",prop:\"password\"}},[s(\"el-input\",{staticStyle:{width:\"200px\"},attrs:{placeholder:\"空为不修改密码\",type:\"password\"},model:{value:e.form.password,callback:function(t){e.$set(e.form,\"password\",t)},expression:\"form.password\"}})],1),e._v(\" \"),s(\"el-form-item\",[s(\"el-button\",{attrs:{type:\"primary\"},on:{click:e.onSubmit}},[e._v(\"修改\")]),e._v(\" \"),s(\"el-button\",{on:{click:e.onCancel}},[e._v(\"取消\")])],1)],1)],1)},o=[],a=s(\"c24f\"),n=s(\"5f87\"),l={data:function(){return{form:{username:\"\",oldPassword:\"\",password:null},rules:{username:[{required:!0,message:\"用户名能为空\",trigger:\"change\"}],oldPassword:[{required:!0,message:\"旧密码不能为空\",trigger:\"change\"}]}}},created:function(){this.fetchUserInfo()},methods:{fetchUserInfo:function(){var e=this;Object(a[\"a\"])(Object(n[\"a\"])()).then(function(t){e.form.username=t.data.username})},onSubmit:function(){var e=this;this.$refs[\"form\"].validate(function(t){t&&Object(a[\"d\"])(e.form).then(function(t){\"success\"===t.data?(e.form.oldPassword=\"\",e.form.password=null,e.$nextTick(function(){e.$refs[\"form\"].clearValidate()}),e.$message({message:\"修改用户信息成功\",type:\"success\"})):e.$message({message:\"修改用户信息成功\",type:\"error\"})})})},onCancel:function(){history.go(-1)}}},i=l,c=(s(\"646d\"),s(\"2877\")),f=Object(c[\"a\"])(i,r,o,!1,null,\"756ebb70\",null);t[\"default\"]=f.exports}}]);"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/js/chunk-69386cf0.bdbe3f0c.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[\"chunk-69386cf0\"],{2829:function(e,t,s){},\"646d\":function(e,t,s){\"use strict\";var r=s(\"2829\"),o=s.n(r);o.a},\"9fb7\":function(e,t,s){\"use strict\";s.r(t);var r=function(){var e=this,t=e.$createElement,s=e._self._c||t;return s(\"div\",{staticClass:\"app-container\",staticStyle:{width:\"600px\"}},[s(\"el-form\",{ref:\"form\",attrs:{rules:e.rules,model:e.form,\"label-width\":\"120px\"}},[s(\"el-form-item\",{attrs:{label:\"用户名\",prop:\"username\"}},[s(\"el-input\",{staticStyle:{width:\"200px\"},model:{value:e.form.username,callback:function(t){e.$set(e.form,\"username\",t)},expression:\"form.username\"}})],1),e._v(\" \"),s(\"el-form-item\",{attrs:{label:\"旧密码\",prop:\"oldPassword\"}},[s(\"el-input\",{staticStyle:{width:\"200px\"},attrs:{type:\"password\"},model:{value:e.form.oldPassword,callback:function(t){e.$set(e.form,\"oldPassword\",t)},expression:\"form.oldPassword\"}})],1),e._v(\" \"),s(\"el-form-item\",{attrs:{label:\"密码\",prop:\"password\"}},[s(\"el-input\",{staticStyle:{width:\"200px\"},attrs:{placeholder:\"空为不修改密码\",type:\"password\"},model:{value:e.form.password,callback:function(t){e.$set(e.form,\"password\",t)},expression:\"form.password\"}})],1),e._v(\" \"),s(\"el-form-item\",[s(\"el-button\",{attrs:{type:\"primary\"},on:{click:e.onSubmit}},[e._v(\"修改\")]),e._v(\" \"),s(\"el-button\",{on:{click:e.onCancel}},[e._v(\"取消\")])],1)],1)],1)},o=[],a=s(\"c24f\"),n=s(\"5f87\"),l={data:function(){return{form:{username:\"\",oldPassword:\"\",password:null},rules:{username:[{required:!0,message:\"用户名能为空\",trigger:\"change\"}],oldPassword:[{required:!0,message:\"旧密码不能为空\",trigger:\"change\"}]}}},created:function(){this.fetchUserInfo()},methods:{fetchUserInfo:function(){var e=this;Object(a[\"a\"])(Object(n[\"a\"])()).then(function(t){e.form.username=t.data.username})},onSubmit:function(){var e=this;this.$refs[\"form\"].validate(function(t){t&&Object(a[\"d\"])(e.form).then(function(t){\"success\"===t.data?(e.form.oldPassword=\"\",e.form.password=null,e.$nextTick(function(){e.$refs[\"form\"].clearValidate()}),e.$message({message:\"修改用户信息成功\",type:\"success\"})):e.$message({message:\"修改用户信息成功\",type:\"error\"})})})},onCancel:function(){history.go(-1)}}},i=l,c=(s(\"646d\"),s(\"2877\")),f=Object(c[\"a\"])(i,r,o,!1,null,\"756ebb70\",null);t[\"default\"]=f.exports}}]);"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/js/chunk-7ec889b7.5f730d9b.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[\"chunk-7ec889b7\"],{\"11ec\":function(t,n,e){},\"7f19\":function(t,n,e){\"use strict\";var c=e(\"11ec\"),r=e.n(c);r.a},\"7f84\":function(t,n,e){\"use strict\";e.r(n);var c=function(){var t=this,n=t.$createElement,e=t._self._c||n;return e(\"div\",[e(\"el-form\",{ref:\"form\",attrs:{model:t.form}},[e(\"div\",{staticStyle:{\"padding-left\":\"10px\",\"padding-right\":\"10px\",\"padding-top\":\"20px\"}},[e(\"el-form-item\",[t._v(\"\\n        \"+t._s(t.form.instance)+\"    \\n        \"),e(\"el-button\",{attrs:{type:\"primary\"},on:{click:t.onRefresh}},[t._v(\"刷新\")]),t._v(\" \"),e(\"el-button\",{attrs:{type:\"info\"},on:{click:t.onBack}},[t._v(\"返回\")])],1),t._v(\" \"),e(\"el-input\",{attrs:{rows:35,readonly:\"readonly\",type:\"textarea\"},model:{value:t.form.desc,callback:function(n){t.$set(t.form,\"desc\",n)},expression:\"form.desc\"}})],1)])],1)},r=[],a=e(\"f546\"),o={data:function(){return{form:{instance:\"\",desc:\"\"}}},created:function(){this.fetchData()},methods:{fetchData:function(){var t=this;Object(a[\"f\"])(this.$route.query.id,this.$route.query.nodeId).then(function(n){t.form.instance=n.data.instance+\".log\",t.form.desc=n.data.log})},onRefresh:function(){this.fetchData()},onBack:function(){history.go(-1)}}},u=o,i=(e(\"7f19\"),e(\"2877\")),f=Object(i[\"a\"])(u,c,r,!1,null,\"0b80198c\",null);n[\"default\"]=f.exports},f546:function(t,n,e){\"use strict\";e.d(n,\"e\",function(){return r}),e.d(n,\"b\",function(){return a}),e.d(n,\"j\",function(){return o}),e.d(n,\"a\",function(){return u}),e.d(n,\"c\",function(){return i}),e.d(n,\"h\",function(){return f}),e.d(n,\"i\",function(){return s}),e.d(n,\"f\",function(){return d}),e.d(n,\"g\",function(){return l}),e.d(n,\"d\",function(){return h});var c=e(\"b775\");function r(t){return Object(c[\"a\"])({url:\"/canal/instances\",method:\"get\",params:t})}function a(t){return Object(c[\"a\"])({url:\"/canal/instance/\"+t,method:\"get\"})}function o(t){return Object(c[\"a\"])({url:\"/canal/instance\",method:\"put\",data:t})}function u(t){return Object(c[\"a\"])({url:\"/canal/instance\",method:\"post\",data:t})}function i(t){return Object(c[\"a\"])({url:\"/canal/instance/\"+t,method:\"delete\"})}function f(t,n){return Object(c[\"a\"])({url:\"/canal/instance/start/\"+t+\"/\"+n,method:\"put\"})}function s(t,n){return Object(c[\"a\"])({url:\"/canal/instance/stop/\"+t+\"/\"+n,method:\"put\"})}function d(t,n){return Object(c[\"a\"])({url:\"/canal/instance/log/\"+t+\"/\"+n,method:\"get\"})}function l(t,n){return Object(c[\"a\"])({url:\"/canal/instance/status/\"+t+\"?option=\"+n,method:\"put\"})}function h(t){return Object(c[\"a\"])({url:\"/canal/active/instances/\"+t,method:\"get\"})}}}]);"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/js/chunk-7ec889b7.bd1ca803.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[\"chunk-7ec889b7\"],{\"11ec\":function(t,n,e){},\"7f19\":function(t,n,e){\"use strict\";var c=e(\"11ec\"),r=e.n(c);r.a},\"7f84\":function(t,n,e){\"use strict\";e.r(n);var c=function(){var t=this,n=t.$createElement,e=t._self._c||n;return e(\"div\",[e(\"el-form\",{ref:\"form\",attrs:{model:t.form}},[e(\"div\",{staticStyle:{\"padding-left\":\"10px\",\"padding-right\":\"10px\",\"padding-top\":\"20px\"}},[e(\"el-form-item\",[t._v(\"\\n        \"+t._s(t.form.instance)+\"    \\n        \"),e(\"el-button\",{attrs:{type:\"primary\"},on:{click:t.onRefresh}},[t._v(\"刷新\")]),t._v(\" \"),e(\"el-button\",{attrs:{type:\"info\"},on:{click:t.onBack}},[t._v(\"返回\")])],1),t._v(\" \"),e(\"el-input\",{attrs:{rows:35,readonly:\"readonly\",type:\"textarea\"},model:{value:t.form.desc,callback:function(n){t.$set(t.form,\"desc\",n)},expression:\"form.desc\"}})],1)])],1)},r=[],a=e(\"f546\"),o={data:function(){return{form:{instance:\"\",desc:\"\"}}},created:function(){this.fetchData()},methods:{fetchData:function(){var t=this;Object(a[\"g\"])(this.$route.query.id,this.$route.query.nodeId).then(function(n){t.form.instance=n.data.instance+\".log\",t.form.desc=n.data.log})},onRefresh:function(){this.fetchData()},onBack:function(){history.go(-1)}}},u=o,i=(e(\"7f19\"),e(\"2877\")),f=Object(i[\"a\"])(u,c,r,!1,null,\"0b80198c\",null);n[\"default\"]=f.exports},f546:function(t,n,e){\"use strict\";e.d(n,\"e\",function(){return r}),e.d(n,\"b\",function(){return a}),e.d(n,\"k\",function(){return o}),e.d(n,\"a\",function(){return u}),e.d(n,\"c\",function(){return i}),e.d(n,\"i\",function(){return f}),e.d(n,\"j\",function(){return s}),e.d(n,\"g\",function(){return d}),e.d(n,\"h\",function(){return l}),e.d(n,\"d\",function(){return m}),e.d(n,\"f\",function(){return h});var c=e(\"b775\");function r(t){return Object(c[\"a\"])({url:\"/canal/instances\",method:\"get\",params:t})}function a(t){return Object(c[\"a\"])({url:\"/canal/instance/\"+t,method:\"get\"})}function o(t){return Object(c[\"a\"])({url:\"/canal/instance\",method:\"put\",data:t})}function u(t){return Object(c[\"a\"])({url:\"/canal/instance\",method:\"post\",data:t})}function i(t){return Object(c[\"a\"])({url:\"/canal/instance/\"+t,method:\"delete\"})}function f(t,n){return Object(c[\"a\"])({url:\"/canal/instance/start/\"+t+\"/\"+n,method:\"put\"})}function s(t,n){return Object(c[\"a\"])({url:\"/canal/instance/stop/\"+t+\"/\"+n,method:\"put\"})}function d(t,n){return Object(c[\"a\"])({url:\"/canal/instance/log/\"+t+\"/\"+n,method:\"get\"})}function l(t,n){return Object(c[\"a\"])({url:\"/canal/instance/status/\"+t+\"?option=\"+n,method:\"put\"})}function m(t){return Object(c[\"a\"])({url:\"/canal/active/instances/\"+t,method:\"get\"})}function h(){return Object(c[\"a\"])({url:\"/canal/instance/template\",method:\"get\"})}}}]);"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/js/chunk-98f505d0.f3096ce7.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[\"chunk-98f505d0\"],{\"4e8a\":function(t,e,n){\"use strict\";var o=n(\"727e\"),r=n.n(o);r.a},\"727e\":function(t,e,n){},aa99:function(t,e,n){\"use strict\";n.r(e);var o=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n(\"div\",[n(\"el-form\",{ref:\"form\",attrs:{model:t.form}},[n(\"div\",{staticStyle:{\"padding-left\":\"10px\",\"padding-top\":\"20px\"}},[n(\"el-form-item\",[t._v(\"\\n        \"+t._s(t.form.name)+\"    \\n        \"),n(\"el-button\",{attrs:{type:\"primary\"},on:{click:t.onSubmit}},[t._v(\"保存\")]),t._v(\" \"),n(\"el-button\",{attrs:{type:\"warning\"},on:{click:t.onCancel}},[t._v(\"重置\")]),t._v(\" \"),n(\"el-button\",{attrs:{type:\"info\"},on:{click:t.onBack}},[t._v(\"返回\")])],1)],1),t._v(\" \"),n(\"editor\",{attrs:{lang:\"properties\",theme:\"chrome\",width:\"100%\",height:800},on:{init:t.editorInit},model:{value:t.form.content,callback:function(e){t.$set(t.form,\"content\",e)},expression:\"form.content\"}})],1)],1)},r=[],a=(n(\"7f7f\"),n(\"b775\"));function i(t,e){return Object(a[\"a\"])({url:\"/canal/config/\"+t+\"/\"+e,method:\"get\"})}function c(t){return Object(a[\"a\"])({url:\"/canal/config\",method:\"put\",data:t})}var s={components:{editor:n(\"7c9e\")},data:function(){return{form:{id:null,name:\"\",content:\"\",serverId:null,clusterId:null}}},created:function(){this.loadCanalConfig()},methods:{editorInit:function(){n(\"2099\"),n(\"be9d\"),n(\"2968\"),n(\"e0e5\"),n(\"bb36\"),n(\"0329\"),n(\"95b8\"),n(\"6a21\")},loadCanalConfig:function(){var t=this,e=0,n=0;this.$route.query.clusterId?e=this.$route.query.clusterId:this.$route.query.serverId&&(n=this.$route.query.serverId),i(e,n).then(function(e){var n=e.data;t.form.id=n.id,t.form.name=n.name,t.form.content=n.content,t.form.serverId=t.$route.query.serverId,t.form.clusterId=t.$route.query.clusterId})},onSubmit:function(){var t=this;null!==this.form.content&&\"\"!==this.form.content?this.$confirm(\"修改主配置可能会导致Server重启，是否继续？\",\"确定修改\",{confirmButtonText:\"确定\",cancelButtonText:\"取消\",type:\"warning\"}).then(function(){c(t.form).then(function(e){\"success\"===e.data?(t.$message({message:\"保存成功\",type:\"success\"}),t.loadCanalConfig()):t.$message({message:\"保存失败\",type:\"error\"})})}):this.$message({message:\"配置内容不能为空\",type:\"error\"})},onCancel:function(){this.loadCanalConfig()},onBack:function(){history.go(-1)}}},u=s,f=(n(\"4e8a\"),n(\"2877\")),l=Object(f[\"a\"])(u,o,r,!1,null,\"35af5ff9\",null);e[\"default\"]=l.exports}}]);"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/js/chunk-bd1d44ee.8c8282cc.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[\"chunk-bd1d44ee\"],{\"878d\":function(t,n,e){},b0a2:function(t,n,e){\"use strict\";e.r(n);var r=function(){var t=this,n=t.$createElement,e=t._self._c||n;return e(\"div\",[e(\"el-form\",{ref:\"form\",attrs:{model:t.form}},[e(\"div\",{staticStyle:{\"padding-left\":\"10px\",\"padding-top\":\"20px\"}},[e(\"el-form-item\",[t._v(\"\\n        \"+t._s(t.form.name)+\"    \\n        \"),e(\"el-select\",{staticClass:\"filter-item\",attrs:{placeholder:\"所属集群/主机\"},model:{value:t.form.clusterServerId,callback:function(n){t.$set(t.form,\"clusterServerId\",n)},expression:\"form.clusterServerId\"}},t._l(t.options,function(n){return e(\"el-option-group\",{key:n.label,attrs:{label:n.label}},t._l(n.options,function(t){return e(\"el-option\",{key:t.value,attrs:{label:t.label,value:t.value}})}),1)}),1),t._v(\" \"),e(\"el-button\",{attrs:{type:\"primary\"},on:{click:t.onSubmit}},[t._v(\"修改\")]),t._v(\" \"),e(\"el-button\",{attrs:{type:\"warning\"},on:{click:t.onCancel}},[t._v(\"重置\")]),t._v(\" \"),e(\"el-button\",{attrs:{type:\"info\"},on:{click:t.onBack}},[t._v(\"返回\")])],1)],1),t._v(\" \"),e(\"editor\",{attrs:{lang:\"properties\",theme:\"chrome\",width:\"100%\",height:800},on:{init:t.editorInit},model:{value:t.form.content,callback:function(n){t.$set(t.form,\"content\",n)},expression:\"form.content\"}})],1)],1)},o=[],c=(e(\"7f7f\"),e(\"f546\")),a=e(\"d631\"),u={components:{editor:e(\"7c9e\")},data:function(){return{options:[],form:{id:null,name:\"\",content:\"\",clusterServerId:\"\"}}},created:function(){var t=this;this.loadCanalConfig(),Object(a[\"d\"])().then(function(n){t.options=n.data})},methods:{editorInit:function(){e(\"2099\"),e(\"be9d\"),e(\"2968\"),e(\"e0e5\"),e(\"bb36\"),e(\"0329\"),e(\"95b8\"),e(\"6a21\")},loadCanalConfig:function(){var t=this;Object(c[\"b\"])(this.$route.query.id).then(function(n){var e=n.data;t.form.id=e.id,t.form.name=e.name+\"/instance.propertios\",t.form.content=e.content,t.form.clusterServerId=e.clusterServerId})},onSubmit:function(){var t=this;this.$confirm(\"修改Instance配置可能会导致重启，是否继续？\",\"确定修改\",{confirmButtonText:\"确定\",cancelButtonText:\"取消\",type:\"warning\"}).then(function(){Object(c[\"j\"])(t.form).then(function(n){\"success\"===n.data?(t.$message({message:\"修改成功\",type:\"success\"}),t.loadCanalConfig()):t.$message({message:\"修改失败\",type:\"error\"})})})},onCancel:function(){this.loadCanalConfig()},onBack:function(){history.go(-1)}}},i=u,l=(e(\"de9c\"),e(\"2877\")),s=Object(l[\"a\"])(i,r,o,!1,null,\"5c332416\",null);n[\"default\"]=s.exports},d631:function(t,n,e){\"use strict\";e.d(n,\"c\",function(){return o}),e.d(n,\"a\",function(){return c}),e.d(n,\"e\",function(){return a}),e.d(n,\"b\",function(){return u}),e.d(n,\"d\",function(){return i});var r=e(\"b775\");function o(t){return Object(r[\"a\"])({url:\"/canal/clusters\",method:\"get\",params:t})}function c(t){return Object(r[\"a\"])({url:\"/canal/cluster\",method:\"post\",data:t})}function a(t){return Object(r[\"a\"])({url:\"/canal/cluster\",method:\"put\",data:t})}function u(t){return Object(r[\"a\"])({url:\"/canal/cluster/\"+t,method:\"delete\"})}function i(){return Object(r[\"a\"])({url:\"/canal/clustersAndServers\",method:\"get\"})}},de9c:function(t,n,e){\"use strict\";var r=e(\"878d\"),o=e.n(r);o.a},f546:function(t,n,e){\"use strict\";e.d(n,\"e\",function(){return o}),e.d(n,\"b\",function(){return c}),e.d(n,\"j\",function(){return a}),e.d(n,\"a\",function(){return u}),e.d(n,\"c\",function(){return i}),e.d(n,\"h\",function(){return l}),e.d(n,\"i\",function(){return s}),e.d(n,\"f\",function(){return d}),e.d(n,\"g\",function(){return f}),e.d(n,\"d\",function(){return m});var r=e(\"b775\");function o(t){return Object(r[\"a\"])({url:\"/canal/instances\",method:\"get\",params:t})}function c(t){return Object(r[\"a\"])({url:\"/canal/instance/\"+t,method:\"get\"})}function a(t){return Object(r[\"a\"])({url:\"/canal/instance\",method:\"put\",data:t})}function u(t){return Object(r[\"a\"])({url:\"/canal/instance\",method:\"post\",data:t})}function i(t){return Object(r[\"a\"])({url:\"/canal/instance/\"+t,method:\"delete\"})}function l(t,n){return Object(r[\"a\"])({url:\"/canal/instance/start/\"+t+\"/\"+n,method:\"put\"})}function s(t,n){return Object(r[\"a\"])({url:\"/canal/instance/stop/\"+t+\"/\"+n,method:\"put\"})}function d(t,n){return Object(r[\"a\"])({url:\"/canal/instance/log/\"+t+\"/\"+n,method:\"get\"})}function f(t,n){return Object(r[\"a\"])({url:\"/canal/instance/status/\"+t+\"?option=\"+n,method:\"put\"})}function m(t){return Object(r[\"a\"])({url:\"/canal/active/instances/\"+t,method:\"get\"})}}}]);"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/js/chunk-bd1d44ee.8e2c4851.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[\"chunk-bd1d44ee\"],{\"878d\":function(t,n,e){},b0a2:function(t,n,e){\"use strict\";e.r(n);var r=function(){var t=this,n=t.$createElement,e=t._self._c||n;return e(\"div\",[e(\"el-form\",{ref:\"form\",attrs:{model:t.form}},[e(\"div\",{staticStyle:{\"padding-left\":\"10px\",\"padding-top\":\"20px\"}},[e(\"el-form-item\",[t._v(\"\\n        \"+t._s(t.form.name)+\"    \\n        \"),e(\"el-select\",{staticClass:\"filter-item\",attrs:{placeholder:\"所属集群/主机\"},model:{value:t.form.clusterServerId,callback:function(n){t.$set(t.form,\"clusterServerId\",n)},expression:\"form.clusterServerId\"}},t._l(t.options,function(n){return e(\"el-option-group\",{key:n.label,attrs:{label:n.label}},t._l(n.options,function(t){return e(\"el-option\",{key:t.value,attrs:{label:t.label,value:t.value}})}),1)}),1),t._v(\" \"),e(\"el-button\",{attrs:{type:\"primary\"},on:{click:t.onSubmit}},[t._v(\"修改\")]),t._v(\" \"),e(\"el-button\",{attrs:{type:\"warning\"},on:{click:t.onCancel}},[t._v(\"重置\")]),t._v(\" \"),e(\"el-button\",{attrs:{type:\"info\"},on:{click:t.onBack}},[t._v(\"返回\")])],1)],1),t._v(\" \"),e(\"editor\",{attrs:{lang:\"properties\",theme:\"chrome\",width:\"100%\",height:800},on:{init:t.editorInit},model:{value:t.form.content,callback:function(n){t.$set(t.form,\"content\",n)},expression:\"form.content\"}})],1)],1)},c=[],o=(e(\"7f7f\"),e(\"f546\")),a=e(\"d631\"),u={components:{editor:e(\"7c9e\")},data:function(){return{options:[],form:{id:null,name:\"\",content:\"\",clusterServerId:\"\"}}},created:function(){var t=this;this.loadCanalConfig(),Object(a[\"d\"])().then(function(n){t.options=n.data})},methods:{editorInit:function(){e(\"2099\"),e(\"be9d\"),e(\"2968\"),e(\"e0e5\"),e(\"bb36\"),e(\"0329\"),e(\"95b8\"),e(\"6a21\")},loadCanalConfig:function(){var t=this;Object(o[\"b\"])(this.$route.query.id).then(function(n){var e=n.data;t.form.id=e.id,t.form.name=e.name+\"/instance.propertios\",t.form.content=e.content,t.form.clusterServerId=e.clusterServerId})},onSubmit:function(){var t=this;this.$confirm(\"修改Instance配置可能会导致重启，是否继续？\",\"确定修改\",{confirmButtonText:\"确定\",cancelButtonText:\"取消\",type:\"warning\"}).then(function(){Object(o[\"k\"])(t.form).then(function(n){\"success\"===n.data?(t.$message({message:\"修改成功\",type:\"success\"}),t.loadCanalConfig()):t.$message({message:\"修改失败\",type:\"error\"})})})},onCancel:function(){this.loadCanalConfig()},onBack:function(){history.go(-1)}}},i=u,l=(e(\"de9c\"),e(\"2877\")),s=Object(l[\"a\"])(i,r,c,!1,null,\"5c332416\",null);n[\"default\"]=s.exports},d631:function(t,n,e){\"use strict\";e.d(n,\"c\",function(){return c}),e.d(n,\"a\",function(){return o}),e.d(n,\"e\",function(){return a}),e.d(n,\"b\",function(){return u}),e.d(n,\"d\",function(){return i});var r=e(\"b775\");function c(t){return Object(r[\"a\"])({url:\"/canal/clusters\",method:\"get\",params:t})}function o(t){return Object(r[\"a\"])({url:\"/canal/cluster\",method:\"post\",data:t})}function a(t){return Object(r[\"a\"])({url:\"/canal/cluster\",method:\"put\",data:t})}function u(t){return Object(r[\"a\"])({url:\"/canal/cluster/\"+t,method:\"delete\"})}function i(){return Object(r[\"a\"])({url:\"/canal/clustersAndServers\",method:\"get\"})}},de9c:function(t,n,e){\"use strict\";var r=e(\"878d\"),c=e.n(r);c.a},f546:function(t,n,e){\"use strict\";e.d(n,\"e\",function(){return c}),e.d(n,\"b\",function(){return o}),e.d(n,\"k\",function(){return a}),e.d(n,\"a\",function(){return u}),e.d(n,\"c\",function(){return i}),e.d(n,\"i\",function(){return l}),e.d(n,\"j\",function(){return s}),e.d(n,\"g\",function(){return d}),e.d(n,\"h\",function(){return f}),e.d(n,\"d\",function(){return m}),e.d(n,\"f\",function(){return b});var r=e(\"b775\");function c(t){return Object(r[\"a\"])({url:\"/canal/instances\",method:\"get\",params:t})}function o(t){return Object(r[\"a\"])({url:\"/canal/instance/\"+t,method:\"get\"})}function a(t){return Object(r[\"a\"])({url:\"/canal/instance\",method:\"put\",data:t})}function u(t){return Object(r[\"a\"])({url:\"/canal/instance\",method:\"post\",data:t})}function i(t){return Object(r[\"a\"])({url:\"/canal/instance/\"+t,method:\"delete\"})}function l(t,n){return Object(r[\"a\"])({url:\"/canal/instance/start/\"+t+\"/\"+n,method:\"put\"})}function s(t,n){return Object(r[\"a\"])({url:\"/canal/instance/stop/\"+t+\"/\"+n,method:\"put\"})}function d(t,n){return Object(r[\"a\"])({url:\"/canal/instance/log/\"+t+\"/\"+n,method:\"get\"})}function f(t,n){return Object(r[\"a\"])({url:\"/canal/instance/status/\"+t+\"?option=\"+n,method:\"put\"})}function m(t){return Object(r[\"a\"])({url:\"/canal/active/instances/\"+t,method:\"get\"})}function b(){return Object(r[\"a\"])({url:\"/canal/instance/template\",method:\"get\"})}}}]);"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/js/chunk-da289616.7def925e.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[\"chunk-da289616\"],{\"11e9\":function(t,e,n){var r=n(\"52a7\"),a=n(\"4630\"),i=n(\"6821\"),o=n(\"6a99\"),l=n(\"69a8\"),s=n(\"c69a\"),c=Object.getOwnPropertyDescriptor;e.f=n(\"9e1e\")?c:function(t,e){if(t=i(t),e=o(e,!0),s)try{return c(t,e)}catch(n){}if(l(t,e))return a(!r.f.call(t,e),t[e])}},\"333d\":function(t,e,n){\"use strict\";var r=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n(\"div\",{staticClass:\"pagination-container\",class:{hidden:t.hidden}},[n(\"el-pagination\",t._b({attrs:{background:t.background,\"current-page\":t.currentPage,\"page-size\":t.pageSize,layout:t.layout,\"page-sizes\":t.pageSizes,total:t.total},on:{\"update:currentPage\":function(e){t.currentPage=e},\"update:current-page\":function(e){t.currentPage=e},\"update:pageSize\":function(e){t.pageSize=e},\"update:page-size\":function(e){t.pageSize=e},\"size-change\":t.handleSizeChange,\"current-change\":t.handleCurrentChange}},\"el-pagination\",t.$attrs,!1))],1)},a=[];n(\"c5f6\");Math.easeInOutQuad=function(t,e,n,r){return t/=r/2,t<1?n/2*t*t+e:(t--,-n/2*(t*(t-2)-1)+e)};var i=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||function(t){window.setTimeout(t,1e3/60)}}();function o(t){document.documentElement.scrollTop=t,document.body.parentNode.scrollTop=t,document.body.scrollTop=t}function l(){return document.documentElement.scrollTop||document.body.parentNode.scrollTop||document.body.scrollTop}function s(t,e,n){var r=l(),a=t-r,s=20,c=0;e=\"undefined\"===typeof e?500:e;var u=function t(){c+=s;var l=Math.easeInOutQuad(c,r,a,e);o(l),c<e?i(t):n&&\"function\"===typeof n&&n()};u()}var c={name:\"Pagination\",props:{total:{required:!0,type:Number},page:{type:Number,default:1},limit:{type:Number,default:20},pageSizes:{type:Array,default:function(){return[10,20,30,50]}},layout:{type:String,default:\"total, sizes, prev, pager, next, jumper\"},background:{type:Boolean,default:!0},autoScroll:{type:Boolean,default:!0},hidden:{type:Boolean,default:!1}},computed:{currentPage:{get:function(){return this.page},set:function(t){this.$emit(\"update:page\",t)}},pageSize:{get:function(){return this.limit},set:function(t){this.$emit(\"update:limit\",t)}}},methods:{handleSizeChange:function(t){this.$emit(\"pagination\",{page:this.currentPage,limit:t}),this.autoScroll&&s(0,800)},handleCurrentChange:function(t){this.$emit(\"pagination\",{page:t,limit:this.pageSize}),this.autoScroll&&s(0,800)}}},u=c,d=(n(\"dfcf\"),n(\"2877\")),f=Object(d[\"a\"])(u,r,a,!1,null,\"38ef71f0\",null);e[\"a\"]=f.exports},\"5dbc\":function(t,e,n){var r=n(\"d3f4\"),a=n(\"8b97\").set;t.exports=function(t,e,n){var i,o=e.constructor;return o!==n&&\"function\"==typeof o&&(i=o.prototype)!==n.prototype&&r(i)&&a&&a(t,i),t}},\"690d\":function(t,e,n){},\"8b97\":function(t,e,n){var r=n(\"d3f4\"),a=n(\"cb7c\"),i=function(t,e){if(a(t),!r(e)&&null!==e)throw TypeError(e+\": can't set as prototype!\")};t.exports={set:Object.setPrototypeOf||(\"__proto__\"in{}?function(t,e,r){try{r=n(\"9b43\")(Function.call,n(\"11e9\").f(Object.prototype,\"__proto__\").set,2),r(t,[]),e=!(t instanceof Array)}catch(a){e=!0}return function(t,n){return i(t,n),e?t.__proto__=n:r(t,n),t}}({},!1):void 0),check:i}},9093:function(t,e,n){var r=n(\"ce10\"),a=n(\"e11e\").concat(\"length\",\"prototype\");e.f=Object.getOwnPropertyNames||function(t){return r(t,a)}},\"9f66\":function(t,e,n){\"use strict\";n.r(e);var r=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n(\"div\",{staticClass:\"app-container\"},[n(\"div\",{staticClass:\"filter-container\"},[n(\"el-select\",{staticClass:\"filter-item\",attrs:{placeholder:\"所属集群\"},model:{value:t.listQuery.clusterId,callback:function(e){t.$set(t.listQuery,\"clusterId\",e)},expression:\"listQuery.clusterId\"}},[n(\"el-option\",{key:\"\",attrs:{label:\"所属集群\",value:\"\"}}),t._v(\" \"),n(\"el-option\",{key:\"-1\",attrs:{label:\"单机\",value:\"-1\"}}),t._v(\" \"),t._l(t.canalClusters,function(t){return n(\"el-option\",{key:t.id,attrs:{label:t.name,value:t.id}})})],2),t._v(\" \"),n(\"el-input\",{staticClass:\"filter-item\",staticStyle:{width:\"200px\"},attrs:{placeholder:\"Server IP\"},model:{value:t.listQuery.ip,callback:function(e){t.$set(t.listQuery,\"ip\",e)},expression:\"listQuery.ip\"}}),t._v(\" \"),n(\"el-button\",{staticClass:\"filter-item\",attrs:{type:\"primary\",icon:\"el-icon-search\",plain:\"\"},on:{click:function(e){return t.queryData()}}},[t._v(\"查询\")]),t._v(\" \"),n(\"el-button\",{staticClass:\"filter-item\",attrs:{type:\"primary\"},on:{click:function(e){return t.handleCreate()}}},[t._v(\"新建Server\")]),t._v(\" \"),n(\"el-button\",{staticClass:\"filter-item\",attrs:{type:\"info\"},on:{click:function(e){return t.fetchData()}}},[t._v(\"刷新列表\")])],1),t._v(\" \"),n(\"el-table\",{directives:[{name:\"loading\",rawName:\"v-loading\",value:t.listLoading,expression:\"listLoading\"}],attrs:{data:t.list,\"element-loading-text\":\"Loading\",border:\"\",fit:\"\",\"highlight-current-row\":\"\"}},[n(\"el-table-column\",{attrs:{label:\"所属集群\",\"min-width\":\"200\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[null!==e.row.canalCluster?n(\"span\",[t._v(\"\\n          \"+t._s(e.row.canalCluster.name)+\"\\n        \")]):n(\"span\",[t._v(\"\\n          -\\n        \")])]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{label:\"Server 名称\",\"min-width\":\"200\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[t._v(\"\\n        \"+t._s(e.row.name)+\"\\n      \")]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{label:\"Server IP\",\"min-width\":\"200\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[n(\"span\",[t._v(t._s(e.row.ip))])]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{label:\"admin 端口\",\"min-width\":\"100\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[t._v(\"\\n        \"+t._s(e.row.adminPort)+\"\\n      \")]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{label:\"tcp 端口\",\"min-width\":\"100\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[t._v(\"\\n        \"+t._s(e.row.tcpPort)+\"\\n      \")]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{label:\"metric 端口\",\"min-width\":\"100\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[t._v(\"\\n        \"+t._s(e.row.metricPort)+\"\\n      \")]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{\"class-name\":\"status-col\",label:\"状态\",\"min-width\":\"150\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[n(\"el-tag\",{attrs:{type:t._f(\"statusFilter\")(e.row.status)}},[t._v(t._s(t._f(\"statusLabel\")(e.row.status)))])]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{align:\"center\",prop:\"created_at\",label:\"操作\",\"min-width\":\"150\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[n(\"el-dropdown\",{attrs:{trigger:\"click\"}},[n(\"el-button\",{attrs:{type:\"primary\",size:\"mini\"}},[t._v(\"\\n            操作\"),n(\"i\",{staticClass:\"el-icon-arrow-down el-icon--right\"})]),t._v(\" \"),n(\"el-dropdown-menu\",{attrs:{slot:\"dropdown\"},slot:\"dropdown\"},[n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleConfig(e.row)}}},[t._v(\"配置\")]),t._v(\" \"),n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleUpdate(e.row)}}},[t._v(\"修改\")]),t._v(\" \"),n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleDelete(e.row)}}},[t._v(\"删除\")]),t._v(\" \"),n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleStart(e.row)}}},[t._v(\"启动\")]),t._v(\" \"),n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleStop(e.row)}}},[t._v(\"停止\")]),t._v(\" \"),n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleInstances(e.row)}}},[t._v(\"详情\")]),t._v(\" \"),n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleLog(e.row)}}},[t._v(\"日志\")])],1)],1)]}}])})],1),t._v(\" \"),n(\"pagination\",{directives:[{name:\"show\",rawName:\"v-show\",value:t.count>0,expression:\"count>0\"}],attrs:{total:t.count,page:t.listQuery.page,limit:t.listQuery.size},on:{\"update:page\":function(e){return t.$set(t.listQuery,\"page\",e)},\"update:limit\":function(e){return t.$set(t.listQuery,\"size\",e)},pagination:function(e){return t.fetchData()}}}),t._v(\" \"),n(\"el-dialog\",{attrs:{visible:t.dialogFormVisible,title:t.textMap[t.dialogStatus],width:\"600px\"},on:{\"update:visible\":function(e){t.dialogFormVisible=e}}},[n(\"el-form\",{ref:\"dataForm\",staticStyle:{width:\"400px\",\"margin-left\":\"30px\"},attrs:{rules:t.rules,model:t.nodeModel,\"label-position\":\"left\",\"label-width\":\"120px\"}},[n(\"el-form-item\",{attrs:{label:\"所属集群\",prop:\"clusterId\"}},[\"create\"===t.dialogStatus?n(\"el-select\",{attrs:{placeholder:\"选择所属集群\"},model:{value:t.nodeModel.clusterId,callback:function(e){t.$set(t.nodeModel,\"clusterId\",e)},expression:\"nodeModel.clusterId\"}},[n(\"el-option\",{key:\"\",attrs:{label:\"单机\",value:\"\"}}),t._v(\" \"),t._l(t.canalClusters,function(t){return n(\"el-option\",{key:t.id,attrs:{label:t.name,value:t.id}})})],2):n(\"el-select\",{attrs:{placeholder:\"选择所属集群\",disabled:\"disabled\"},model:{value:t.nodeModel.clusterId,callback:function(e){t.$set(t.nodeModel,\"clusterId\",e)},expression:\"nodeModel.clusterId\"}},[n(\"el-option\",{key:\"\",attrs:{label:\"单机\",value:\"\"}}),t._v(\" \"),t._l(t.canalClusters,function(t){return n(\"el-option\",{key:t.id,attrs:{label:t.name,value:t.id}})})],2)],1),t._v(\" \"),n(\"el-form-item\",{attrs:{label:\"Server 名称\",prop:\"name\"}},[n(\"el-input\",{model:{value:t.nodeModel.name,callback:function(e){t.$set(t.nodeModel,\"name\",e)},expression:\"nodeModel.name\"}})],1),t._v(\" \"),n(\"el-form-item\",{attrs:{label:\"Server IP\",prop:\"ip\"}},[n(\"el-input\",{model:{value:t.nodeModel.ip,callback:function(e){t.$set(t.nodeModel,\"ip\",e)},expression:\"nodeModel.ip\"}})],1),t._v(\" \"),n(\"el-form-item\",{attrs:{label:\"admin 端口\",prop:\"adminPort\"}},[n(\"el-input\",{attrs:{placeholder:\"11110\",type:\"number\"},model:{value:t.nodeModel.adminPort,callback:function(e){t.$set(t.nodeModel,\"adminPort\",e)},expression:\"nodeModel.adminPort\"}})],1),t._v(\" \"),n(\"el-form-item\",{attrs:{label:\"tcp 端口\",prop:\"tcpPort\"}},[n(\"el-input\",{attrs:{placeholder:\"11111\",type:\"number\"},model:{value:t.nodeModel.tcpPort,callback:function(e){t.$set(t.nodeModel,\"tcpPort\",e)},expression:\"nodeModel.tcpPort\"}})],1),t._v(\" \"),n(\"el-form-item\",{attrs:{label:\"metric 端口\",prop:\"metricPort\"}},[n(\"el-input\",{attrs:{placeholder:\"11112\",type:\"number\"},model:{value:t.nodeModel.metricPort,callback:function(e){t.$set(t.nodeModel,\"metricPort\",e)},expression:\"nodeModel.metricPort\"}})],1)],1),t._v(\" \"),n(\"div\",{staticClass:\"dialog-footer\",attrs:{slot:\"footer\"},slot:\"footer\"},[n(\"el-button\",{on:{click:function(e){t.dialogFormVisible=!1}}},[t._v(\"取消\")]),t._v(\" \"),n(\"el-button\",{attrs:{type:\"primary\"},on:{click:function(e){return t.dataOperation()}}},[t._v(\"确定\")])],1)],1),t._v(\" \"),n(\"el-dialog\",{attrs:{visible:t.dialogInstances,title:\"instance 列表\",width:\"800px\"},on:{\"update:visible\":function(e){t.dialogInstances=e}}},[n(\"div\",{staticClass:\"filter-container\"},[n(\"el-button\",{staticClass:\"filter-item\",attrs:{type:\"info\"},on:{click:function(e){return t.activeInstances()}}},[t._v(\"刷新列表\")])],1),t._v(\" \"),n(\"el-table\",{directives:[{name:\"loading\",rawName:\"v-loading\",value:t.listLoading2,expression:\"listLoading2\"}],attrs:{data:t.instanceList,\"element-loading-text\":\"Loading\",border:\"\",fit:\"\",\"highlight-current-row\":\"\"}},[n(\"el-table-column\",{attrs:{label:\"Instance 名称\",\"min-width\":\"200\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[t._v(\"\\n          \"+t._s(e.row.name)+\"\\n        \")]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{label:\"状态\",\"min-width\":\"200\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[n(\"el-tag\",{attrs:{type:t._f(\"statusFilter\")(e.row.runningStatus)}},[t._v(t._s(t._f(\"statusLabel\")(e.row.runningStatus)))])]}}])}),t._v(\" \"),n(\"el-table-column\",{attrs:{label:\"操作\",\"min-width\":\"200\",align:\"center\"},scopedSlots:t._u([{key:\"default\",fn:function(e){return[n(\"el-dropdown\",{attrs:{trigger:\"click\"}},[n(\"el-button\",{attrs:{type:\"primary\",size:\"mini\"}},[t._v(\"\\n              操作\"),n(\"i\",{staticClass:\"el-icon-arrow-down el-icon--right\"})]),t._v(\" \"),n(\"el-dropdown-menu\",{attrs:{slot:\"dropdown\"},slot:\"dropdown\"},[n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleStartInstance(e.row)}}},[t._v(\"启动\")]),t._v(\" \"),n(\"el-dropdown-item\",{nativeOn:{click:function(n){return t.handleStopInstance(e.row)}}},[t._v(\"停止\")])],1)],1)]}}])})],1)],1)],1)},a=[],i=(n(\"c5f6\"),n(\"c6ed\")),o=n(\"f546\"),l=n(\"d631\"),s=n(\"333d\"),c={components:{Pagination:s[\"a\"]},filters:{statusFilter:function(t){var e={1:\"success\",0:\"gray\",\"-1\":\"danger\"};return e[t]},statusLabel:function(t){var e={1:\"启动\",0:\"停止\",\"-1\":\"断开\"};return e[t]}},data:function(){return{list:null,instanceList:null,listLoading:!0,listLoading2:!0,serverIdTmp:null,canalClusters:[],count:0,listQuery:{name:\"\",ip:\"\",clusterId:null,page:1,size:20},dialogFormVisible:!1,dialogInstances:!1,textMap:{create:\"新建Server信息\",update:\"修改Server信息\"},nodeModel:{id:void 0,clusterId:null,name:null,ip:null,adminPort:11110,tcpPort:11111,metricPort:11112},rules:{name:[{required:!0,message:\"Server 名称不能为空\",trigger:\"change\"}],ip:[{required:!0,message:\"Server IP不能为空\",trigger:\"change\"}],adminPort:[{required:!0,message:\"Server admin端口不能为空\",trigger:\"change\"}]},dialogStatus:\"create\"}},created:function(){var t=this;if(Object(l[\"c\"])().then(function(e){t.canalClusters=e.data}),this.$route.query.clusterId)try{this.listQuery.clusterId=Number(this.$route.query.clusterId)}catch(e){console.log(e)}this.fetchData()},methods:{fetchData:function(){var t=this;this.listLoading=!0,Object(i[\"c\"])(this.listQuery).then(function(e){t.list=e.data.items,t.count=e.data.count}).finally(function(){t.listLoading=!1})},queryData:function(){this.listQuery.page=1,this.fetchData()},resetModel:function(){this.nodeModel={id:void 0,clusterId:null,name:null,ip:null,adminPort:null,tcpPort:null,metricPort:null}},handleCreate:function(){var t=this;this.resetModel(),this.dialogStatus=\"create\",this.dialogFormVisible=!0,this.$nextTick(function(){t.$refs[\"dataForm\"].clearValidate()})},handleInstances:function(t){this.serverIdTmp=t.id,this.activeInstances()},activeInstances:function(){var t=this;this.listLoading2=!0,this.dialogInstances=!0,Object(o[\"d\"])(this.serverIdTmp).then(function(e){t.instanceList=e.data}).finally(function(){t.listLoading2=!1})},dataOperation:function(){var t=this;this.$refs[\"dataForm\"].validate(function(e){e&&(\"create\"===t.dialogStatus&&Object(i[\"a\"])(t.nodeModel).then(function(e){t.operationRes(e)}),\"update\"===t.dialogStatus&&Object(i[\"g\"])(t.nodeModel).then(function(e){t.operationRes(e)}))})},operationRes:function(t){\"success\"===t.data?(this.fetchData(),this.dialogFormVisible=!1,this.$message({message:this.textMap[this.dialogStatus]+\"成功\",type:\"success\"})):this.$message({message:this.textMap[this.dialogStatus]+\"失败\",type:\"error\"})},handleConfig:function(t){null===t.canalCluster?this.$router.push(\"/canalServer/nodeServer/config?serverId=\"+t.id):this.$message({message:\"集群模式Server不允许单独变更配置，请在集群配置变更\",type:\"error\"})},handleUpdate:function(t){var e=this;this.resetModel(),this.nodeModel=Object.assign({},t),this.dialogStatus=\"update\",this.dialogFormVisible=!0,this.$nextTick(function(){e.$refs[\"dataForm\"].clearValidate()})},handleDelete:function(t){var e=this;this.$confirm(\"删除Server信息会导致节点服务停止\",\"确定删除Server信息\",{confirmButtonText:\"确定\",cancelButtonText:\"取消\",type:\"warning\"}).then(function(){Object(i[\"b\"])(t.id).then(function(t){\"success\"===t.data?(e.fetchData(),e.$message({message:\"删除Server信息成功\",type:\"success\"})):e.$message({message:\"删除Server信息失败\",type:\"error\"})})})},handleStart:function(t){var e=this;\"0\"===t.status?this.$confirm(\"启动Server服务\",\"确定启动Server服务\",{confirmButtonText:\"确定\",cancelButtonText:\"取消\",type:\"warning\"}).then(function(){Object(i[\"e\"])(t.id).then(function(t){t.data?(e.fetchData(),e.$message({message:\"启动成功\",type:\"success\"})):e.$message({message:\"启动Server服务出现异常\",type:\"error\"})})}):this.$message({message:\"当前Server不是停止状态，无法启动\",type:\"error\"})},handleStop:function(t){var e=this;\"1\"===t.status?this.$confirm(\"停止Server服务会导致所有Instance都停止服务\",\"确定停止Server服务\",{confirmButtonText:\"确定\",cancelButtonText:\"取消\",type:\"warning\"}).then(function(){Object(i[\"f\"])(t.id).then(function(t){t.data?(e.fetchData(),e.$message({message:\"停止成功\",type:\"success\"})):e.$message({message:\"停止Server服务出现异常\",type:\"error\"})})}):this.$message({message:\"当前Server不是启动状态，无法停止\",type:\"error\"})},handleLog:function(t){this.$router.push(\"nodeServer/log?id=\"+t.id)},handleStartInstance:function(t){var e=this;\"0\"===t.runningStatus?this.$confirm(\"启动Instance服务\",\"确定启动Instance服务\",{confirmButtonText:\"确定\",cancelButtonText:\"取消\",type:\"warning\"}).then(function(){Object(o[\"i\"])(t.id,e.serverIdTmp).then(function(t){t.data?(e.activeInstances(),e.$message({message:\"启动成功, 稍后请刷新列表查看状态\",type:\"success\"})):e.$message({message:\"启动Instance服务出现异常\",type:\"error\"})})}):this.$message({message:\"当前Instance不是停止状态，无法启动\",type:\"error\"})},handleStopInstance:function(t){var e=this;\"1\"===t.runningStatus?this.$confirm(\"集群模式下停止实例其它主机将会抢占执行该实例\",\"停止 Instance 服务\",{confirmButtonText:\"确定\",cancelButtonText:\"取消\",type:\"warning\"}).then(function(){Object(o[\"j\"])(t.id,e.serverIdTmp).then(function(t){t.data?(e.activeInstances(),e.$message({message:\"停止成功, 稍后请刷新列表查看状态\",type:\"success\"})):e.$message({message:\"停止Instance服务出现异常\",type:\"error\"})})}):this.$message({message:\"当前Instance不是运行状态，无法停止\",type:\"error\"})}}},u=c,d=n(\"2877\"),f=Object(d[\"a\"])(u,r,a,!1,null,null,null);e[\"default\"]=f.exports},aa77:function(t,e,n){var r=n(\"5ca1\"),a=n(\"be13\"),i=n(\"79e5\"),o=n(\"fdef\"),l=\"[\"+o+\"]\",s=\"​\",c=RegExp(\"^\"+l+l+\"*\"),u=RegExp(l+l+\"*$\"),d=function(t,e,n){var a={},l=i(function(){return!!o[t]()||s[t]()!=s}),c=a[t]=l?e(f):o[t];n&&(a[n]=c),r(r.P+r.F*l,\"String\",a)},f=d.trim=function(t,e){return t=String(a(t)),1&e&&(t=t.replace(c,\"\")),2&e&&(t=t.replace(u,\"\")),t};t.exports=d},c5f6:function(t,e,n){\"use strict\";var r=n(\"7726\"),a=n(\"69a8\"),i=n(\"2d95\"),o=n(\"5dbc\"),l=n(\"6a99\"),s=n(\"79e5\"),c=n(\"9093\").f,u=n(\"11e9\").f,d=n(\"86cc\").f,f=n(\"aa77\").trim,p=\"Number\",m=r[p],g=m,h=m.prototype,v=i(n(\"2aeb\")(h))==p,b=\"trim\"in String.prototype,_=function(t){var e=l(t,!1);if(\"string\"==typeof e&&e.length>2){e=b?e.trim():f(e,3);var n,r,a,i=e.charCodeAt(0);if(43===i||45===i){if(n=e.charCodeAt(2),88===n||120===n)return NaN}else if(48===i){switch(e.charCodeAt(1)){case 66:case 98:r=2,a=49;break;case 79:case 111:r=8,a=55;break;default:return+e}for(var o,s=e.slice(2),c=0,u=s.length;c<u;c++)if(o=s.charCodeAt(c),o<48||o>a)return NaN;return parseInt(s,r)}}return+e};if(!m(\" 0o1\")||!m(\"0b1\")||m(\"+0x1\")){m=function(t){var e=arguments.length<1?0:t,n=this;return n instanceof m&&(v?s(function(){h.valueOf.call(n)}):i(n)!=p)?o(new g(_(e)),n,m):_(e)};for(var y,S=n(\"9e1e\")?c(g):\"MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,EPSILON,isFinite,isInteger,isNaN,isSafeInteger,MAX_SAFE_INTEGER,MIN_SAFE_INTEGER,parseFloat,parseInt,isInteger\".split(\",\"),w=0;S.length>w;w++)a(g,y=S[w])&&!a(m,y)&&d(m,y,u(g,y));m.prototype=h,h.constructor=m,n(\"2aba\")(r,p,m)}},c6ed:function(t,e,n){\"use strict\";n.d(e,\"c\",function(){return a}),n.d(e,\"a\",function(){return i}),n.d(e,\"g\",function(){return o}),n.d(e,\"b\",function(){return l}),n.d(e,\"e\",function(){return s}),n.d(e,\"f\",function(){return c}),n.d(e,\"d\",function(){return u});var r=n(\"b775\");function a(t){return Object(r[\"a\"])({url:\"/nodeServers\",method:\"get\",params:t})}function i(t){return Object(r[\"a\"])({url:\"/nodeServer\",method:\"post\",data:t})}function o(t){return Object(r[\"a\"])({url:\"/nodeServer\",method:\"put\",data:t})}function l(t){return Object(r[\"a\"])({url:\"/nodeServer/\"+t,method:\"delete\"})}function s(t){return Object(r[\"a\"])({url:\"/nodeServer/start/\"+t,method:\"put\"})}function c(t){return Object(r[\"a\"])({url:\"/nodeServer/stop/\"+t,method:\"put\"})}function u(t){return Object(r[\"a\"])({url:\"/nodeServer/log/\"+t,method:\"get\"})}},d631:function(t,e,n){\"use strict\";n.d(e,\"c\",function(){return a}),n.d(e,\"a\",function(){return i}),n.d(e,\"e\",function(){return o}),n.d(e,\"b\",function(){return l}),n.d(e,\"d\",function(){return s});var r=n(\"b775\");function a(t){return Object(r[\"a\"])({url:\"/canal/clusters\",method:\"get\",params:t})}function i(t){return Object(r[\"a\"])({url:\"/canal/cluster\",method:\"post\",data:t})}function o(t){return Object(r[\"a\"])({url:\"/canal/cluster\",method:\"put\",data:t})}function l(t){return Object(r[\"a\"])({url:\"/canal/cluster/\"+t,method:\"delete\"})}function s(){return Object(r[\"a\"])({url:\"/canal/clustersAndServers\",method:\"get\"})}},dfcf:function(t,e,n){\"use strict\";var r=n(\"690d\"),a=n.n(r);a.a},f546:function(t,e,n){\"use strict\";n.d(e,\"e\",function(){return a}),n.d(e,\"b\",function(){return i}),n.d(e,\"k\",function(){return o}),n.d(e,\"a\",function(){return l}),n.d(e,\"c\",function(){return s}),n.d(e,\"i\",function(){return c}),n.d(e,\"j\",function(){return u}),n.d(e,\"g\",function(){return d}),n.d(e,\"h\",function(){return f}),n.d(e,\"d\",function(){return p}),n.d(e,\"f\",function(){return m});var r=n(\"b775\");function a(t){return Object(r[\"a\"])({url:\"/canal/instances\",method:\"get\",params:t})}function i(t){return Object(r[\"a\"])({url:\"/canal/instance/\"+t,method:\"get\"})}function o(t){return Object(r[\"a\"])({url:\"/canal/instance\",method:\"put\",data:t})}function l(t){return Object(r[\"a\"])({url:\"/canal/instance\",method:\"post\",data:t})}function s(t){return Object(r[\"a\"])({url:\"/canal/instance/\"+t,method:\"delete\"})}function c(t,e){return Object(r[\"a\"])({url:\"/canal/instance/start/\"+t+\"/\"+e,method:\"put\"})}function u(t,e){return Object(r[\"a\"])({url:\"/canal/instance/stop/\"+t+\"/\"+e,method:\"put\"})}function d(t,e){return Object(r[\"a\"])({url:\"/canal/instance/log/\"+t+\"/\"+e,method:\"get\"})}function f(t,e){return Object(r[\"a\"])({url:\"/canal/instance/status/\"+t+\"?option=\"+e,method:\"put\"})}function p(t){return Object(r[\"a\"])({url:\"/canal/active/instances/\"+t,method:\"get\"})}function m(){return Object(r[\"a\"])({url:\"/canal/instance/template\",method:\"get\"})}},fdef:function(t,e){t.exports=\"\\t\\n\\v\\f\\r   ᠎             　\\u2028\\u2029\\ufeff\"}}]);"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/js/chunk-elementUI.667f4c87.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[\"chunk-elementUI\"],{\"0fae\":function(e,t,i){},\"12f2\":function(e,t,i){\"use strict\";t.__esModule=!0,t.default=function(e){return{methods:{focus:function(){this.$refs[e].focus()}}}}},\"14e9\":function(e,t,i){e.exports=function(e){var t={};function i(n){if(t[n])return t[n].exports;var s=t[n]={i:n,l:!1,exports:{}};return e[n].call(s.exports,s,s.exports,i),s.l=!0,s.exports}return i.m=e,i.c=t,i.d=function(e,t,n){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},i.r=function(e){\"undefined\"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(e,\"__esModule\",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&\"object\"===typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,\"default\",{enumerable:!0,value:e}),2&t&&\"string\"!=typeof e)for(var s in e)i.d(n,s,function(t){return e[t]}.bind(null,s));return n},i.n=function(e){var t=e&&e.__esModule?function(){return e[\"default\"]}:function(){return e};return i.d(t,\"a\",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p=\"/dist/\",i(i.s=112)}({112:function(e,t,i){\"use strict\";i.r(t);var n=i(15),s=i(34),r=i.n(s),o=i(4),a=i(2),l={vertical:{offset:\"offsetHeight\",scroll:\"scrollTop\",scrollSize:\"scrollHeight\",size:\"height\",key:\"vertical\",axis:\"Y\",client:\"clientY\",direction:\"top\"},horizontal:{offset:\"offsetWidth\",scroll:\"scrollLeft\",scrollSize:\"scrollWidth\",size:\"width\",key:\"horizontal\",axis:\"X\",client:\"clientX\",direction:\"left\"}};function u(e){var t=e.move,i=e.size,n=e.bar,s={},r=\"translate\"+n.axis+\"(\"+t+\"%)\";return s[n.size]=i,s.transform=r,s.msTransform=r,s.webkitTransform=r,s}var c={name:\"Bar\",props:{vertical:Boolean,size:String,move:Number},computed:{bar:function(){return l[this.vertical?\"vertical\":\"horizontal\"]},wrap:function(){return this.$parent.wrap}},render:function(e){var t=this.size,i=this.move,n=this.bar;return e(\"div\",{class:[\"el-scrollbar__bar\",\"is-\"+n.key],on:{mousedown:this.clickTrackHandler}},[e(\"div\",{ref:\"thumb\",class:\"el-scrollbar__thumb\",on:{mousedown:this.clickThumbHandler},style:u({size:t,move:i,bar:n})})])},methods:{clickThumbHandler:function(e){e.ctrlKey||2===e.button||(this.startDrag(e),this[this.bar.axis]=e.currentTarget[this.bar.offset]-(e[this.bar.client]-e.currentTarget.getBoundingClientRect()[this.bar.direction]))},clickTrackHandler:function(e){var t=Math.abs(e.target.getBoundingClientRect()[this.bar.direction]-e[this.bar.client]),i=this.$refs.thumb[this.bar.offset]/2,n=100*(t-i)/this.$el[this.bar.offset];this.wrap[this.bar.scroll]=n*this.wrap[this.bar.scrollSize]/100},startDrag:function(e){e.stopImmediatePropagation(),this.cursorDown=!0,Object(a[\"on\"])(document,\"mousemove\",this.mouseMoveDocumentHandler),Object(a[\"on\"])(document,\"mouseup\",this.mouseUpDocumentHandler),document.onselectstart=function(){return!1}},mouseMoveDocumentHandler:function(e){if(!1!==this.cursorDown){var t=this[this.bar.axis];if(t){var i=-1*(this.$el.getBoundingClientRect()[this.bar.direction]-e[this.bar.client]),n=this.$refs.thumb[this.bar.offset]-t,s=100*(i-n)/this.$el[this.bar.offset];this.wrap[this.bar.scroll]=s*this.wrap[this.bar.scrollSize]/100}}},mouseUpDocumentHandler:function(e){this.cursorDown=!1,this[this.bar.axis]=0,Object(a[\"off\"])(document,\"mousemove\",this.mouseMoveDocumentHandler),document.onselectstart=null}},destroyed:function(){Object(a[\"off\"])(document,\"mouseup\",this.mouseUpDocumentHandler)}},h={name:\"ElScrollbar\",components:{Bar:c},props:{native:Boolean,wrapStyle:{},wrapClass:{},viewClass:{},viewStyle:{},noresize:Boolean,tag:{type:String,default:\"div\"}},data:function(){return{sizeWidth:\"0\",sizeHeight:\"0\",moveX:0,moveY:0}},computed:{wrap:function(){return this.$refs.wrap}},render:function(e){var t=r()(),i=this.wrapStyle;if(t){var n=\"-\"+t+\"px\",s=\"margin-bottom: \"+n+\"; margin-right: \"+n+\";\";Array.isArray(this.wrapStyle)?(i=Object(o[\"toObject\"])(this.wrapStyle),i.marginRight=i.marginBottom=n):\"string\"===typeof this.wrapStyle?i+=s:i=s}var a=e(this.tag,{class:[\"el-scrollbar__view\",this.viewClass],style:this.viewStyle,ref:\"resize\"},this.$slots.default),l=e(\"div\",{ref:\"wrap\",style:i,on:{scroll:this.handleScroll},class:[this.wrapClass,\"el-scrollbar__wrap\",t?\"\":\"el-scrollbar__wrap--hidden-default\"]},[[a]]),u=void 0;return u=this.native?[e(\"div\",{ref:\"wrap\",class:[this.wrapClass,\"el-scrollbar__wrap\"],style:i},[[a]])]:[l,e(c,{attrs:{move:this.moveX,size:this.sizeWidth}}),e(c,{attrs:{vertical:!0,move:this.moveY,size:this.sizeHeight}})],e(\"div\",{class:\"el-scrollbar\"},u)},methods:{handleScroll:function(){var e=this.wrap;this.moveY=100*e.scrollTop/e.clientHeight,this.moveX=100*e.scrollLeft/e.clientWidth},update:function(){var e=void 0,t=void 0,i=this.wrap;i&&(e=100*i.clientHeight/i.scrollHeight,t=100*i.clientWidth/i.scrollWidth,this.sizeHeight=e<100?e+\"%\":\"\",this.sizeWidth=t<100?t+\"%\":\"\")}},mounted:function(){this.native||(this.$nextTick(this.update),!this.noresize&&Object(n[\"addResizeListener\"])(this.$refs.resize,this.update))},beforeDestroy:function(){this.native||!this.noresize&&Object(n[\"removeResizeListener\"])(this.$refs.resize,this.update)},install:function(e){e.component(h.name,h)}};t[\"default\"]=h},15:function(e,t){e.exports=i(\"4010\")},2:function(e,t){e.exports=i(\"5924\")},34:function(e,t){e.exports=i(\"e62d\")},4:function(e,t){e.exports=i(\"8122\")}})},\"299c\":function(e,t,i){e.exports=function(e){var t={};function i(n){if(t[n])return t[n].exports;var s=t[n]={i:n,l:!1,exports:{}};return e[n].call(s.exports,s,s.exports,i),s.l=!0,s.exports}return i.m=e,i.c=t,i.d=function(e,t,n){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},i.r=function(e){\"undefined\"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(e,\"__esModule\",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&\"object\"===typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,\"default\",{enumerable:!0,value:e}),2&t&&\"string\"!=typeof e)for(var s in e)i.d(n,s,function(t){return e[t]}.bind(null,s));return n},i.n=function(e){var t=e&&e.__esModule?function(){return e[\"default\"]}:function(){return e};return i.d(t,\"a\",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p=\"/dist/\",i(i.s=115)}({115:function(e,t,i){\"use strict\";i.r(t);var n=i(5),s=i.n(n),r=i(14),o=i.n(r),a=i(2),l=i(4),u=i(6),c=i.n(u),h={name:\"ElTooltip\",mixins:[s.a],props:{openDelay:{type:Number,default:0},disabled:Boolean,manual:Boolean,effect:{type:String,default:\"dark\"},arrowOffset:{type:Number,default:0},popperClass:String,content:String,visibleArrow:{default:!0},transition:{type:String,default:\"el-fade-in-linear\"},popperOptions:{default:function(){return{boundariesPadding:10,gpuAcceleration:!1}}},enterable:{type:Boolean,default:!0},hideAfter:{type:Number,default:0}},data:function(){return{tooltipId:\"el-tooltip-\"+Object(l[\"generateId\"])(),timeoutPending:null,focusing:!1}},beforeCreate:function(){var e=this;this.$isServer||(this.popperVM=new c.a({data:{node:\"\"},render:function(e){return this.node}}).$mount(),this.debounceClose=o()(200,function(){return e.handleClosePopper()}))},render:function(e){var t=this;this.popperVM&&(this.popperVM.node=e(\"transition\",{attrs:{name:this.transition},on:{afterLeave:this.doDestroy}},[e(\"div\",{on:{mouseleave:function(){t.setExpectedState(!1),t.debounceClose()},mouseenter:function(){t.setExpectedState(!0)}},ref:\"popper\",attrs:{role:\"tooltip\",id:this.tooltipId,\"aria-hidden\":this.disabled||!this.showPopper?\"true\":\"false\"},directives:[{name:\"show\",value:!this.disabled&&this.showPopper}],class:[\"el-tooltip__popper\",\"is-\"+this.effect,this.popperClass]},[this.$slots.content||this.content])]));var i=this.getFirstElement();if(!i)return null;var n=i.data=i.data||{};return n.staticClass=this.addTooltipClass(n.staticClass),i},mounted:function(){var e=this;this.referenceElm=this.$el,1===this.$el.nodeType&&(this.$el.setAttribute(\"aria-describedby\",this.tooltipId),this.$el.setAttribute(\"tabindex\",0),Object(a[\"on\"])(this.referenceElm,\"mouseenter\",this.show),Object(a[\"on\"])(this.referenceElm,\"mouseleave\",this.hide),Object(a[\"on\"])(this.referenceElm,\"focus\",function(){if(e.$slots.default&&e.$slots.default.length){var t=e.$slots.default[0].componentInstance;t&&t.focus?t.focus():e.handleFocus()}else e.handleFocus()}),Object(a[\"on\"])(this.referenceElm,\"blur\",this.handleBlur),Object(a[\"on\"])(this.referenceElm,\"click\",this.removeFocusing)),this.value&&this.popperVM&&this.popperVM.$nextTick(function(){e.value&&e.updatePopper()})},watch:{focusing:function(e){e?Object(a[\"addClass\"])(this.referenceElm,\"focusing\"):Object(a[\"removeClass\"])(this.referenceElm,\"focusing\")}},methods:{show:function(){this.setExpectedState(!0),this.handleShowPopper()},hide:function(){this.setExpectedState(!1),this.debounceClose()},handleFocus:function(){this.focusing=!0,this.show()},handleBlur:function(){this.focusing=!1,this.hide()},removeFocusing:function(){this.focusing=!1},addTooltipClass:function(e){return e?\"el-tooltip \"+e.replace(\"el-tooltip\",\"\"):\"el-tooltip\"},handleShowPopper:function(){var e=this;this.expectedState&&!this.manual&&(clearTimeout(this.timeout),this.timeout=setTimeout(function(){e.showPopper=!0},this.openDelay),this.hideAfter>0&&(this.timeoutPending=setTimeout(function(){e.showPopper=!1},this.hideAfter)))},handleClosePopper:function(){this.enterable&&this.expectedState||this.manual||(clearTimeout(this.timeout),this.timeoutPending&&clearTimeout(this.timeoutPending),this.showPopper=!1,this.disabled&&this.doDestroy())},setExpectedState:function(e){!1===e&&clearTimeout(this.timeoutPending),this.expectedState=e},getFirstElement:function(){var e=this.$slots.default;if(!Array.isArray(e))return null;for(var t=null,i=0;i<e.length;i++)e[i]&&e[i].tag&&(t=e[i]);return t}},beforeDestroy:function(){this.popperVM&&this.popperVM.$destroy()},destroyed:function(){var e=this.referenceElm;Object(a[\"off\"])(e,\"mouseenter\",this.show),Object(a[\"off\"])(e,\"mouseleave\",this.hide),Object(a[\"off\"])(e,\"focus\",this.handleFocus),Object(a[\"off\"])(e,\"blur\",this.handleBlur),Object(a[\"off\"])(e,\"click\",this.removeFocusing)},install:function(e){e.component(h.name,h)}};t[\"default\"]=h},14:function(e,t){e.exports=i(\"0e15\")},2:function(e,t){e.exports=i(\"5924\")},4:function(e,t){e.exports=i(\"8122\")},5:function(e,t){e.exports=i(\"e974\")},6:function(e,t){e.exports=i(\"2b0e\")}})},\"2a5e\":function(e,t,i){\"use strict\";t.__esModule=!0,t.default=o;var n=i(\"2b0e\"),s=r(n);function r(e){return e&&e.__esModule?e:{default:e}}function o(e,t){if(!s.default.prototype.$isServer)if(t){var i=[],n=t.offsetParent;while(n&&e!==n&&e.contains(n))i.push(n),n=n.offsetParent;var r=t.offsetTop+i.reduce(function(e,t){return e+t.offsetTop},0),o=r+t.offsetHeight,a=e.scrollTop,l=a+e.clientHeight;r<a?e.scrollTop=r:o>l&&(e.scrollTop=o-e.clientHeight)}else e.scrollTop=0}},\"2bb5\":function(e,t,i){\"use strict\";t.__esModule=!0,t.default={mounted:function(){},methods:{getMigratingConfig:function(){return{props:{},events:{}}}}}},4010:function(e,t,i){\"use strict\";t.__esModule=!0,t.removeResizeListener=t.addResizeListener=void 0;var n=i(\"6dd8\"),s=r(n);function r(e){return e&&e.__esModule?e:{default:e}}var o=\"undefined\"===typeof window,a=function(e){var t=e,i=Array.isArray(t),n=0;for(t=i?t:t[Symbol.iterator]();;){var s;if(i){if(n>=t.length)break;s=t[n++]}else{if(n=t.next(),n.done)break;s=n.value}var r=s,o=r.target.__resizeListeners__||[];o.length&&o.forEach(function(e){e()})}};t.addResizeListener=function(e,t){o||(e.__resizeListeners__||(e.__resizeListeners__=[],e.__ro__=new s.default(a),e.__ro__.observe(e)),e.__resizeListeners__.push(t))},t.removeResizeListener=function(e,t){e&&e.__resizeListeners__&&(e.__resizeListeners__.splice(e.__resizeListeners__.indexOf(t),1),e.__resizeListeners__.length||e.__ro__.disconnect())}},\"417f\":function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(\"2b0e\"),s=o(n),r=i(\"5924\");function o(e){return e&&e.__esModule?e:{default:e}}var a=[],l=\"@@clickoutsideContext\",u=void 0,c=0;function h(e,t,i){return function(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},s=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};!(i&&i.context&&n.target&&s.target)||e.contains(n.target)||e.contains(s.target)||e===n.target||i.context.popperElm&&(i.context.popperElm.contains(n.target)||i.context.popperElm.contains(s.target))||(t.expression&&e[l].methodName&&i.context[e[l].methodName]?i.context[e[l].methodName]():e[l].bindingFn&&e[l].bindingFn())}}!s.default.prototype.$isServer&&(0,r.on)(document,\"mousedown\",function(e){return u=e}),!s.default.prototype.$isServer&&(0,r.on)(document,\"mouseup\",function(e){a.forEach(function(t){return t[l].documentHandler(e,u)})}),t.default={bind:function(e,t,i){a.push(e);var n=c++;e[l]={id:n,documentHandler:h(e,t,i),methodName:t.expression,bindingFn:t.value}},update:function(e,t,i){e[l].documentHandler=h(e,t,i),e[l].methodName=t.expression,e[l].bindingFn=t.value},unbind:function(e){for(var t=a.length,i=0;i<t;i++)if(a[i][l].id===e[l].id){a.splice(i,1);break}delete e[l]}}},\"41f8\":function(e,t,i){\"use strict\";t.__esModule=!0;var n=\"function\"===typeof Symbol&&\"symbol\"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e};t.isVNode=r;var s=i(\"8122\");function r(e){return null!==e&&\"object\"===(\"undefined\"===typeof e?\"undefined\":n(e))&&(0,s.hasOwn)(e,\"componentOptions\")}},4897:function(e,t,i){\"use strict\";t.__esModule=!0,t.i18n=t.use=t.t=void 0;var n=i(\"f0d9\"),s=h(n),r=i(\"2b0e\"),o=h(r),a=i(\"3c4e\"),l=h(a),u=i(\"9d7e\"),c=h(u);function h(e){return e&&e.__esModule?e:{default:e}}var d=(0,c.default)(o.default),p=s.default,f=!1,m=function(){var e=Object.getPrototypeOf(this||o.default).$t;if(\"function\"===typeof e&&o.default.locale)return f||(f=!0,o.default.locale(o.default.config.lang,(0,l.default)(p,o.default.locale(o.default.config.lang)||{},{clone:!0}))),e.apply(this,arguments)},v=t.t=function(e,t){var i=m.apply(this,arguments);if(null!==i&&void 0!==i)return i;for(var n=e.split(\".\"),s=p,r=0,o=n.length;r<o;r++){var a=n[r];if(i=s[a],r===o-1)return d(i,t);if(!i)return\"\";s=i}return\"\"},g=t.use=function(e){p=e||p},b=t.i18n=function(e){m=e||m};t.default={use:g,t:v,i18n:b}},\"4b26\":function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(\"2b0e\"),s=o(n),r=i(\"5924\");function o(e){return e&&e.__esModule?e:{default:e}}var a=!1,l=!1,u=2e3,c=function(){if(!s.default.prototype.$isServer){var e=d.modalDom;return e?a=!0:(a=!1,e=document.createElement(\"div\"),d.modalDom=e,e.addEventListener(\"touchmove\",function(e){e.preventDefault(),e.stopPropagation()}),e.addEventListener(\"click\",function(){d.doOnModalClick&&d.doOnModalClick()})),e}},h={},d={modalFade:!0,getInstance:function(e){return h[e]},register:function(e,t){e&&t&&(h[e]=t)},deregister:function(e){e&&(h[e]=null,delete h[e])},nextZIndex:function(){return d.zIndex++},modalStack:[],doOnModalClick:function(){var e=d.modalStack[d.modalStack.length-1];if(e){var t=d.getInstance(e.id);t&&t.closeOnClickModal&&t.close()}},openModal:function(e,t,i,n,o){if(!s.default.prototype.$isServer&&e&&void 0!==t){this.modalFade=o;for(var l=this.modalStack,u=0,h=l.length;u<h;u++){var d=l[u];if(d.id===e)return}var p=c();if((0,r.addClass)(p,\"v-modal\"),this.modalFade&&!a&&(0,r.addClass)(p,\"v-modal-enter\"),n){var f=n.trim().split(/\\s+/);f.forEach(function(e){return(0,r.addClass)(p,e)})}setTimeout(function(){(0,r.removeClass)(p,\"v-modal-enter\")},200),i&&i.parentNode&&11!==i.parentNode.nodeType?i.parentNode.appendChild(p):document.body.appendChild(p),t&&(p.style.zIndex=t),p.tabIndex=0,p.style.display=\"\",this.modalStack.push({id:e,zIndex:t,modalClass:n})}},closeModal:function(e){var t=this.modalStack,i=c();if(t.length>0){var n=t[t.length-1];if(n.id===e){if(n.modalClass){var s=n.modalClass.trim().split(/\\s+/);s.forEach(function(e){return(0,r.removeClass)(i,e)})}t.pop(),t.length>0&&(i.style.zIndex=t[t.length-1].zIndex)}else for(var o=t.length-1;o>=0;o--)if(t[o].id===e){t.splice(o,1);break}}0===t.length&&(this.modalFade&&(0,r.addClass)(i,\"v-modal-leave\"),setTimeout(function(){0===t.length&&(i.parentNode&&i.parentNode.removeChild(i),i.style.display=\"none\",d.modalDom=void 0),(0,r.removeClass)(i,\"v-modal-leave\")},200))}};Object.defineProperty(d,\"zIndex\",{configurable:!0,get:function(){return l||(u=(s.default.prototype.$ELEMENT||{}).zIndex||u,l=!0),u},set:function(e){u=e}});var p=function(){if(!s.default.prototype.$isServer&&d.modalStack.length>0){var e=d.modalStack[d.modalStack.length-1];if(!e)return;var t=d.getInstance(e.id);return t}};s.default.prototype.$isServer||window.addEventListener(\"keydown\",function(e){if(27===e.keyCode){var t=p();t&&t.closeOnPressEscape&&(t.handleClose?t.handleClose():t.handleAction?t.handleAction(\"cancel\"):t.close())}}),t.default=d},\"4e4b\":function(e,t,i){e.exports=function(e){var t={};function i(n){if(t[n])return t[n].exports;var s=t[n]={i:n,l:!1,exports:{}};return e[n].call(s.exports,s,s.exports,i),s.l=!0,s.exports}return i.m=e,i.c=t,i.d=function(e,t,n){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},i.r=function(e){\"undefined\"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(e,\"__esModule\",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&\"object\"===typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,\"default\",{enumerable:!0,value:e}),2&t&&\"string\"!=typeof e)for(var s in e)i.d(n,s,function(t){return e[t]}.bind(null,s));return n},i.n=function(e){var t=e&&e.__esModule?function(){return e[\"default\"]}:function(){return e};return i.d(t,\"a\",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p=\"/dist/\",i(i.s=53)}([function(e,t,i){\"use strict\";function n(e,t,i,n,s,r,o,a){var l,u=\"function\"===typeof e?e.options:e;if(t&&(u.render=t,u.staticRenderFns=i,u._compiled=!0),n&&(u.functional=!0),r&&(u._scopeId=\"data-v-\"+r),o?(l=function(e){e=e||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext,e||\"undefined\"===typeof __VUE_SSR_CONTEXT__||(e=__VUE_SSR_CONTEXT__),s&&s.call(this,e),e&&e._registeredComponents&&e._registeredComponents.add(o)},u._ssrRegister=l):s&&(l=a?function(){s.call(this,this.$root.$options.shadowRoot)}:s),l)if(u.functional){u._injectStyles=l;var c=u.render;u.render=function(e,t){return l.call(t),c(e,t)}}else{var h=u.beforeCreate;u.beforeCreate=h?[].concat(h,l):[l]}return{exports:e,options:u}}i.d(t,\"a\",function(){return n})},,,function(e,t){e.exports=i(\"d010\")},function(e,t){e.exports=i(\"8122\")},function(e,t){e.exports=i(\"e974\")},,function(e,t){e.exports=i(\"6b7c\")},,function(e,t){e.exports=i(\"f3ad\")},,function(e,t){e.exports=i(\"417f\")},function(e,t){e.exports=i(\"4897\")},,function(e,t){e.exports=i(\"0e15\")},function(e,t){e.exports=i(\"4010\")},,,,function(e,t){e.exports=i(\"14e9\")},function(e,t){e.exports=i(\"12f2\")},,,,,,function(e,t){e.exports=i(\"8bbc\")},function(e,t){e.exports=i(\"2a5e\")},,function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"li\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible,expression:\"visible\"}],staticClass:\"el-select-dropdown__item\",class:{selected:e.itemSelected,\"is-disabled\":e.disabled||e.groupDisabled||e.limitReached,hover:e.hover},on:{mouseenter:e.hoverItem,click:function(t){return t.stopPropagation(),e.selectOptionClick(t)}}},[e._t(\"default\",[i(\"span\",[e._v(e._s(e.currentLabel))])])],2)},s=[];n._withStripped=!0;var r=i(3),o=i.n(r),a=i(4),l=\"function\"===typeof Symbol&&\"symbol\"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},u={mixins:[o.a],name:\"ElOption\",componentName:\"ElOption\",inject:[\"select\"],props:{value:{required:!0},label:[String,Number],created:Boolean,disabled:{type:Boolean,default:!1}},data:function(){return{index:-1,groupDisabled:!1,visible:!0,hitState:!1,hover:!1}},computed:{isObject:function(){return\"[object object]\"===Object.prototype.toString.call(this.value).toLowerCase()},currentLabel:function(){return this.label||(this.isObject?\"\":this.value)},currentValue:function(){return this.value||this.label||\"\"},itemSelected:function(){return this.select.multiple?this.contains(this.select.value,this.value):this.isEqual(this.value,this.select.value)},limitReached:function(){return!!this.select.multiple&&(!this.itemSelected&&(this.select.value||[]).length>=this.select.multipleLimit&&this.select.multipleLimit>0)}},watch:{currentLabel:function(){this.created||this.select.remote||this.dispatch(\"ElSelect\",\"setSelected\")},value:function(e,t){var i=this.select,n=i.remote,s=i.valueKey;if(!this.created&&!n){if(s&&\"object\"===(\"undefined\"===typeof e?\"undefined\":l(e))&&\"object\"===(\"undefined\"===typeof t?\"undefined\":l(t))&&e[s]===t[s])return;this.dispatch(\"ElSelect\",\"setSelected\")}}},methods:{isEqual:function(e,t){if(this.isObject){var i=this.select.valueKey;return Object(a[\"getValueByPath\"])(e,i)===Object(a[\"getValueByPath\"])(t,i)}return e===t},contains:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments[1];if(this.isObject){var i=this.select.valueKey;return e.some(function(e){return Object(a[\"getValueByPath\"])(e,i)===Object(a[\"getValueByPath\"])(t,i)})}return e.indexOf(t)>-1},handleGroupDisabled:function(e){this.groupDisabled=e},hoverItem:function(){this.disabled||this.groupDisabled||(this.select.hoverIndex=this.select.options.indexOf(this))},selectOptionClick:function(){!0!==this.disabled&&!0!==this.groupDisabled&&this.dispatch(\"ElSelect\",\"handleOptionClick\",[this,!0])},queryChange:function(e){this.visible=new RegExp(Object(a[\"escapeRegexpString\"])(e),\"i\").test(this.currentLabel)||this.created,this.visible||this.select.filteredOptionsCount--}},created:function(){this.select.options.push(this),this.select.cachedOptions.push(this),this.select.optionsCount++,this.select.filteredOptionsCount++,this.$on(\"queryChange\",this.queryChange),this.$on(\"handleGroupDisabled\",this.handleGroupDisabled)},beforeDestroy:function(){this.select.onOptionDestroy(this.select.options.indexOf(this))}},c=u,h=i(0),d=Object(h[\"a\"])(c,n,s,!1,null,null,null);d.options.__file=\"packages/select/src/option.vue\";t[\"a\"]=d.exports},,,,function(e,t){e.exports=i(\"d397\")},,,,,,,,,,,,,,,,,,,,function(e,t,i){\"use strict\";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{directives:[{name:\"clickoutside\",rawName:\"v-clickoutside\",value:e.handleClose,expression:\"handleClose\"}],staticClass:\"el-select\",class:[e.selectSize?\"el-select--\"+e.selectSize:\"\"],on:{click:function(t){return t.stopPropagation(),e.toggleMenu(t)}}},[e.multiple?i(\"div\",{ref:\"tags\",staticClass:\"el-select__tags\",style:{\"max-width\":e.inputWidth-32+\"px\",width:\"100%\"}},[e.collapseTags&&e.selected.length?i(\"span\",[i(\"el-tag\",{attrs:{closable:!e.selectDisabled,size:e.collapseTagSize,hit:e.selected[0].hitState,type:\"info\",\"disable-transitions\":\"\"},on:{close:function(t){e.deleteTag(t,e.selected[0])}}},[i(\"span\",{staticClass:\"el-select__tags-text\"},[e._v(e._s(e.selected[0].currentLabel))])]),e.selected.length>1?i(\"el-tag\",{attrs:{closable:!1,size:e.collapseTagSize,type:\"info\",\"disable-transitions\":\"\"}},[i(\"span\",{staticClass:\"el-select__tags-text\"},[e._v(\"+ \"+e._s(e.selected.length-1))])]):e._e()],1):e._e(),e.collapseTags?e._e():i(\"transition-group\",{on:{\"after-leave\":e.resetInputHeight}},e._l(e.selected,function(t){return i(\"el-tag\",{key:e.getValueKey(t),attrs:{closable:!e.selectDisabled,size:e.collapseTagSize,hit:t.hitState,type:\"info\",\"disable-transitions\":\"\"},on:{close:function(i){e.deleteTag(i,t)}}},[i(\"span\",{staticClass:\"el-select__tags-text\"},[e._v(e._s(t.currentLabel))])])}),1),e.filterable?i(\"input\",{directives:[{name:\"model\",rawName:\"v-model\",value:e.query,expression:\"query\"}],ref:\"input\",staticClass:\"el-select__input\",class:[e.selectSize?\"is-\"+e.selectSize:\"\"],style:{\"flex-grow\":\"1\",width:e.inputLength/(e.inputWidth-32)+\"%\",\"max-width\":e.inputWidth-42+\"px\"},attrs:{type:\"text\",disabled:e.selectDisabled,autocomplete:e.autoComplete||e.autocomplete},domProps:{value:e.query},on:{focus:e.handleFocus,blur:function(t){e.softFocus=!1},click:function(e){e.stopPropagation()},keyup:e.managePlaceholder,keydown:[e.resetInputState,function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"down\",40,t.key,[\"Down\",\"ArrowDown\"]))return null;t.preventDefault(),e.navigateOptions(\"next\")},function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"up\",38,t.key,[\"Up\",\"ArrowUp\"]))return null;t.preventDefault(),e.navigateOptions(\"prev\")},function(t){return\"button\"in t||!e._k(t.keyCode,\"enter\",13,t.key,\"Enter\")?(t.preventDefault(),e.selectOption(t)):null},function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"esc\",27,t.key,[\"Esc\",\"Escape\"]))return null;t.stopPropagation(),t.preventDefault(),e.visible=!1},function(t){return\"button\"in t||!e._k(t.keyCode,\"delete\",[8,46],t.key,[\"Backspace\",\"Delete\",\"Del\"])?e.deletePrevTag(t):null}],compositionstart:e.handleComposition,compositionupdate:e.handleComposition,compositionend:e.handleComposition,input:[function(t){t.target.composing||(e.query=t.target.value)},e.debouncedQueryChange]}}):e._e()],1):e._e(),i(\"el-input\",{ref:\"reference\",class:{\"is-focus\":e.visible},attrs:{type:\"text\",placeholder:e.currentPlaceholder,name:e.name,id:e.id,autocomplete:e.autoComplete||e.autocomplete,size:e.selectSize,disabled:e.selectDisabled,readonly:e.readonly,\"validate-event\":!1},on:{focus:e.handleFocus,blur:e.handleBlur},nativeOn:{keyup:function(t){return e.debouncedOnInputChange(t)},keydown:[function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"down\",40,t.key,[\"Down\",\"ArrowDown\"]))return null;t.stopPropagation(),t.preventDefault(),e.navigateOptions(\"next\")},function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"up\",38,t.key,[\"Up\",\"ArrowUp\"]))return null;t.stopPropagation(),t.preventDefault(),e.navigateOptions(\"prev\")},function(t){return\"button\"in t||!e._k(t.keyCode,\"enter\",13,t.key,\"Enter\")?(t.preventDefault(),e.selectOption(t)):null},function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"esc\",27,t.key,[\"Esc\",\"Escape\"]))return null;t.stopPropagation(),t.preventDefault(),e.visible=!1},function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"tab\",9,t.key,\"Tab\"))return null;e.visible=!1}],paste:function(t){return e.debouncedOnInputChange(t)},mouseenter:function(t){e.inputHovering=!0},mouseleave:function(t){e.inputHovering=!1}},model:{value:e.selectedLabel,callback:function(t){e.selectedLabel=t},expression:\"selectedLabel\"}},[e.$slots.prefix?i(\"template\",{slot:\"prefix\"},[e._t(\"prefix\")],2):e._e(),i(\"template\",{slot:\"suffix\"},[i(\"i\",{directives:[{name:\"show\",rawName:\"v-show\",value:!e.showClose,expression:\"!showClose\"}],class:[\"el-select__caret\",\"el-input__icon\",\"el-icon-\"+e.iconClass]}),e.showClose?i(\"i\",{staticClass:\"el-select__caret el-input__icon el-icon-circle-close\",on:{click:e.handleClearClick}}):e._e()])],2),i(\"transition\",{attrs:{name:\"el-zoom-in-top\"},on:{\"before-enter\":e.handleMenuEnter,\"after-leave\":e.doDestroy}},[i(\"el-select-menu\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible&&!1!==e.emptyText,expression:\"visible && emptyText !== false\"}],ref:\"popper\",attrs:{\"append-to-body\":e.popperAppendToBody}},[i(\"el-scrollbar\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.options.length>0&&!e.loading,expression:\"options.length > 0 && !loading\"}],ref:\"scrollbar\",class:{\"is-empty\":!e.allowCreate&&e.query&&0===e.filteredOptionsCount},attrs:{tag:\"ul\",\"wrap-class\":\"el-select-dropdown__wrap\",\"view-class\":\"el-select-dropdown__list\"}},[e.showNewOption?i(\"el-option\",{attrs:{value:e.query,created:\"\"}}):e._e(),e._t(\"default\")],2),e.emptyText&&(!e.allowCreate||e.loading||e.allowCreate&&0===e.options.length)?[e.$slots.empty?e._t(\"empty\"):i(\"p\",{staticClass:\"el-select-dropdown__empty\"},[e._v(\"\\n          \"+e._s(e.emptyText)+\"\\n        \")])]:e._e()],2)],1)],1)},s=[];n._withStripped=!0;var r=i(3),o=i.n(r),a=i(20),l=i.n(a),u=i(7),c=i.n(u),h=i(9),d=i.n(h),p=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-select-dropdown el-popper\",class:[{\"is-multiple\":e.$parent.multiple},e.popperClass],style:{minWidth:e.minWidth}},[e._t(\"default\")],2)},f=[];p._withStripped=!0;var m=i(5),v=i.n(m),g={name:\"ElSelectDropdown\",componentName:\"ElSelectDropdown\",mixins:[v.a],props:{placement:{default:\"bottom-start\"},boundariesPadding:{default:0},popperOptions:{default:function(){return{gpuAcceleration:!1}}},visibleArrow:{default:!0},appendToBody:{type:Boolean,default:!0}},data:function(){return{minWidth:\"\"}},computed:{popperClass:function(){return this.$parent.popperClass}},watch:{\"$parent.inputWidth\":function(){this.minWidth=this.$parent.$el.getBoundingClientRect().width+\"px\"}},mounted:function(){var e=this;this.referenceElm=this.$parent.$refs.reference.$el,this.$parent.popperElm=this.popperElm=this.$el,this.$on(\"updatePopper\",function(){e.$parent.visible&&e.updatePopper()}),this.$on(\"destroyPopper\",this.destroyPopper)}},b=g,y=i(0),_=Object(y[\"a\"])(b,p,f,!1,null,null,null);_.options.__file=\"packages/select/src/select-dropdown.vue\";var x=_.exports,C=i(29),w=i(26),k=i.n(w),S=i(19),$=i.n(S),D=i(14),E=i.n(D),T=i(11),O=i.n(T),I=i(15),P=i(12),M=i(27),N=i.n(M),F=i(4),A={data:function(){return{hoverOption:-1}},computed:{optionsAllDisabled:function(){return this.options.filter(function(e){return e.visible}).every(function(e){return e.disabled})}},watch:{hoverIndex:function(e){var t=this;\"number\"===typeof e&&e>-1&&(this.hoverOption=this.options[e]||{}),this.options.forEach(function(e){e.hover=t.hoverOption===e})}},methods:{navigateOptions:function(e){var t=this;if(this.visible){if(0!==this.options.length&&0!==this.filteredOptionsCount&&!this.optionsAllDisabled){\"next\"===e?(this.hoverIndex++,this.hoverIndex===this.options.length&&(this.hoverIndex=0)):\"prev\"===e&&(this.hoverIndex--,this.hoverIndex<0&&(this.hoverIndex=this.options.length-1));var i=this.options[this.hoverIndex];!0!==i.disabled&&!0!==i.groupDisabled&&i.visible||this.navigateOptions(e),this.$nextTick(function(){return t.scrollToOption(t.hoverOption)})}}else this.visible=!0}}},L=i(33),V={mixins:[o.a,c.a,l()(\"reference\"),A],name:\"ElSelect\",componentName:\"ElSelect\",inject:{elForm:{default:\"\"},elFormItem:{default:\"\"}},provide:function(){return{select:this}},computed:{_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},readonly:function(){return!this.filterable||this.multiple||!Object(F[\"isIE\"])()&&!Object(F[\"isEdge\"])()&&!this.visible},showClose:function(){var e=this.multiple?Array.isArray(this.value)&&this.value.length>0:void 0!==this.value&&null!==this.value&&\"\"!==this.value,t=this.clearable&&!this.selectDisabled&&this.inputHovering&&e;return t},iconClass:function(){return this.remote&&this.filterable?\"\":this.visible?\"arrow-up is-reverse\":\"arrow-up\"},debounce:function(){return this.remote?300:0},emptyText:function(){return this.loading?this.loadingText||this.t(\"el.select.loading\"):(!this.remote||\"\"!==this.query||0!==this.options.length)&&(this.filterable&&this.query&&this.options.length>0&&0===this.filteredOptionsCount?this.noMatchText||this.t(\"el.select.noMatch\"):0===this.options.length?this.noDataText||this.t(\"el.select.noData\"):null)},showNewOption:function(){var e=this,t=this.options.filter(function(e){return!e.created}).some(function(t){return t.currentLabel===e.query});return this.filterable&&this.allowCreate&&\"\"!==this.query&&!t},selectSize:function(){return this.size||this._elFormItemSize||(this.$ELEMENT||{}).size},selectDisabled:function(){return this.disabled||(this.elForm||{}).disabled},collapseTagSize:function(){return[\"small\",\"mini\"].indexOf(this.selectSize)>-1?\"mini\":\"small\"}},components:{ElInput:d.a,ElSelectMenu:x,ElOption:C[\"a\"],ElTag:k.a,ElScrollbar:$.a},directives:{Clickoutside:O.a},props:{name:String,id:String,value:{required:!0},autocomplete:{type:String,default:\"off\"},autoComplete:{type:String,validator:function(e){return!0}},automaticDropdown:Boolean,size:String,disabled:Boolean,clearable:Boolean,filterable:Boolean,allowCreate:Boolean,loading:Boolean,popperClass:String,remote:Boolean,loadingText:String,noMatchText:String,noDataText:String,remoteMethod:Function,filterMethod:Function,multiple:Boolean,multipleLimit:{type:Number,default:0},placeholder:{type:String,default:function(){return Object(P[\"t\"])(\"el.select.placeholder\")}},defaultFirstOption:Boolean,reserveKeyword:Boolean,valueKey:{type:String,default:\"value\"},collapseTags:Boolean,popperAppendToBody:{type:Boolean,default:!0}},data:function(){return{options:[],cachedOptions:[],createdLabel:null,createdSelected:!1,selected:this.multiple?[]:{},inputLength:20,inputWidth:0,initialInputHeight:0,cachedPlaceHolder:\"\",optionsCount:0,filteredOptionsCount:0,visible:!1,softFocus:!1,selectedLabel:\"\",hoverIndex:-1,query:\"\",previousQuery:null,inputHovering:!1,currentPlaceholder:\"\",menuVisibleOnFocus:!1,isOnComposition:!1,isSilentBlur:!1}},watch:{selectDisabled:function(){var e=this;this.$nextTick(function(){e.resetInputHeight()})},placeholder:function(e){this.cachedPlaceHolder=this.currentPlaceholder=e},value:function(e,t){this.multiple&&(this.resetInputHeight(),e.length>0||this.$refs.input&&\"\"!==this.query?this.currentPlaceholder=\"\":this.currentPlaceholder=this.cachedPlaceHolder,this.filterable&&!this.reserveKeyword&&(this.query=\"\",this.handleQueryChange(this.query))),this.setSelected(),this.filterable&&!this.multiple&&(this.inputLength=20),Object(F[\"valueEquals\"])(e,t)||this.dispatch(\"ElFormItem\",\"el.form.change\",e)},visible:function(e){var t=this;e?(this.broadcast(\"ElSelectDropdown\",\"updatePopper\"),this.filterable&&(this.query=this.remote?\"\":this.selectedLabel,this.handleQueryChange(this.query),this.multiple?this.$refs.input.focus():(this.remote||(this.broadcast(\"ElOption\",\"queryChange\",\"\"),this.broadcast(\"ElOptionGroup\",\"queryChange\")),this.broadcast(\"ElInput\",\"inputSelect\")))):(this.broadcast(\"ElSelectDropdown\",\"destroyPopper\"),this.$refs.input&&this.$refs.input.blur(),this.query=\"\",this.previousQuery=null,this.selectedLabel=\"\",this.inputLength=20,this.menuVisibleOnFocus=!1,this.resetHoverIndex(),this.$nextTick(function(){t.$refs.input&&\"\"===t.$refs.input.value&&0===t.selected.length&&(t.currentPlaceholder=t.cachedPlaceHolder)}),this.multiple||this.selected&&(this.filterable&&this.allowCreate&&this.createdSelected&&this.createdLabel?this.selectedLabel=this.createdLabel:this.selectedLabel=this.selected.currentLabel,this.filterable&&(this.query=this.selectedLabel))),this.$emit(\"visible-change\",e)},options:function(){var e=this;if(!this.$isServer){this.$nextTick(function(){e.broadcast(\"ElSelectDropdown\",\"updatePopper\")}),this.multiple&&this.resetInputHeight();var t=this.$el.querySelectorAll(\"input\");-1===[].indexOf.call(t,document.activeElement)&&this.setSelected(),this.defaultFirstOption&&(this.filterable||this.remote)&&this.filteredOptionsCount&&this.checkDefaultFirstOption()}}},methods:{handleComposition:function(e){var t=e.target.value;if(\"compositionend\"===e.type)this.isOnComposition=!1,this.handleQueryChange(t);else{var i=t[t.length-1]||\"\";this.isOnComposition=!Object(L[\"isKorean\"])(i)}},handleQueryChange:function(e){var t=this;if(this.previousQuery!==e&&!this.isOnComposition)if(null!==this.previousQuery||\"function\"!==typeof this.filterMethod&&\"function\"!==typeof this.remoteMethod){if(this.previousQuery=e,this.$nextTick(function(){t.visible&&t.broadcast(\"ElSelectDropdown\",\"updatePopper\")}),this.hoverIndex=-1,this.multiple&&this.filterable){var i=15*this.$refs.input.value.length+20;this.inputLength=this.collapseTags?Math.min(50,i):i,this.managePlaceholder(),this.resetInputHeight()}this.remote&&\"function\"===typeof this.remoteMethod?(this.hoverIndex=-1,this.remoteMethod(e)):\"function\"===typeof this.filterMethod?(this.filterMethod(e),this.broadcast(\"ElOptionGroup\",\"queryChange\")):(this.filteredOptionsCount=this.optionsCount,this.broadcast(\"ElOption\",\"queryChange\",e),this.broadcast(\"ElOptionGroup\",\"queryChange\")),this.defaultFirstOption&&(this.filterable||this.remote)&&this.filteredOptionsCount&&this.checkDefaultFirstOption()}else this.previousQuery=e},scrollToOption:function(e){var t=Array.isArray(e)&&e[0]?e[0].$el:e.$el;if(this.$refs.popper&&t){var i=this.$refs.popper.$el.querySelector(\".el-select-dropdown__wrap\");N()(i,t)}this.$refs.scrollbar&&this.$refs.scrollbar.handleScroll()},handleMenuEnter:function(){var e=this;this.$nextTick(function(){return e.scrollToOption(e.selected)})},emitChange:function(e){Object(F[\"valueEquals\"])(this.value,e)||this.$emit(\"change\",e)},getOption:function(e){for(var t=void 0,i=\"[object object]\"===Object.prototype.toString.call(e).toLowerCase(),n=\"[object null]\"===Object.prototype.toString.call(e).toLowerCase(),s=this.cachedOptions.length-1;s>=0;s--){var r=this.cachedOptions[s],o=i?Object(F[\"getValueByPath\"])(r.value,this.valueKey)===Object(F[\"getValueByPath\"])(e,this.valueKey):r.value===e;if(o){t=r;break}}if(t)return t;var a=i||n?\"\":e,l={value:e,currentLabel:a};return this.multiple&&(l.hitState=!1),l},setSelected:function(){var e=this;if(!this.multiple){var t=this.getOption(this.value);return t.created?(this.createdLabel=t.currentLabel,this.createdSelected=!0):this.createdSelected=!1,this.selectedLabel=t.currentLabel,this.selected=t,void(this.filterable&&(this.query=this.selectedLabel))}var i=[];Array.isArray(this.value)&&this.value.forEach(function(t){i.push(e.getOption(t))}),this.selected=i,this.$nextTick(function(){e.resetInputHeight()})},handleFocus:function(e){this.softFocus?this.softFocus=!1:((this.automaticDropdown||this.filterable)&&(this.visible=!0,this.menuVisibleOnFocus=!0),this.$emit(\"focus\",e))},blur:function(){this.visible=!1,this.$refs.reference.blur()},handleBlur:function(e){var t=this;setTimeout(function(){t.isSilentBlur?t.isSilentBlur=!1:t.$emit(\"blur\",e)},50),this.softFocus=!1},handleClearClick:function(e){this.deleteSelected(e)},doDestroy:function(){this.$refs.popper&&this.$refs.popper.doDestroy()},handleClose:function(){this.visible=!1},toggleLastOptionHitState:function(e){if(Array.isArray(this.selected)){var t=this.selected[this.selected.length-1];if(t)return!0===e||!1===e?(t.hitState=e,e):(t.hitState=!t.hitState,t.hitState)}},deletePrevTag:function(e){if(e.target.value.length<=0&&!this.toggleLastOptionHitState()){var t=this.value.slice();t.pop(),this.$emit(\"input\",t),this.emitChange(t)}},managePlaceholder:function(){\"\"!==this.currentPlaceholder&&(this.currentPlaceholder=this.$refs.input.value?\"\":this.cachedPlaceHolder)},resetInputState:function(e){8!==e.keyCode&&this.toggleLastOptionHitState(!1),this.inputLength=15*this.$refs.input.value.length+20,this.resetInputHeight()},resetInputHeight:function(){var e=this;this.collapseTags&&!this.filterable||this.$nextTick(function(){if(e.$refs.reference){var t=e.$refs.reference.$el.childNodes,i=[].filter.call(t,function(e){return\"INPUT\"===e.tagName})[0],n=e.$refs.tags,s=e.initialInputHeight||40;i.style.height=0===e.selected.length?s+\"px\":Math.max(n?n.clientHeight+(n.clientHeight>s?6:0):0,s)+\"px\",e.visible&&!1!==e.emptyText&&e.broadcast(\"ElSelectDropdown\",\"updatePopper\")}})},resetHoverIndex:function(){var e=this;setTimeout(function(){e.multiple?e.selected.length>0?e.hoverIndex=Math.min.apply(null,e.selected.map(function(t){return e.options.indexOf(t)})):e.hoverIndex=-1:e.hoverIndex=e.options.indexOf(e.selected)},300)},handleOptionSelect:function(e,t){var i=this;if(this.multiple){var n=this.value.slice(),s=this.getValueIndex(n,e.value);s>-1?n.splice(s,1):(this.multipleLimit<=0||n.length<this.multipleLimit)&&n.push(e.value),this.$emit(\"input\",n),this.emitChange(n),e.created&&(this.query=\"\",this.handleQueryChange(\"\"),this.inputLength=20),this.filterable&&this.$refs.input.focus()}else this.$emit(\"input\",e.value),this.emitChange(e.value),this.visible=!1;this.isSilentBlur=t,this.setSoftFocus(),this.visible||this.$nextTick(function(){i.scrollToOption(e)})},setSoftFocus:function(){this.softFocus=!0;var e=this.$refs.input||this.$refs.reference;e&&e.focus()},getValueIndex:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments[1],i=\"[object object]\"===Object.prototype.toString.call(t).toLowerCase();if(i){var n=this.valueKey,s=-1;return e.some(function(e,i){return Object(F[\"getValueByPath\"])(e,n)===Object(F[\"getValueByPath\"])(t,n)&&(s=i,!0)}),s}return e.indexOf(t)},toggleMenu:function(){this.selectDisabled||(this.menuVisibleOnFocus?this.menuVisibleOnFocus=!1:this.visible=!this.visible,this.visible&&(this.$refs.input||this.$refs.reference).focus())},selectOption:function(){this.visible?this.options[this.hoverIndex]&&this.handleOptionSelect(this.options[this.hoverIndex]):this.toggleMenu()},deleteSelected:function(e){e.stopPropagation();var t=this.multiple?[]:null;this.$emit(\"input\",t),this.emitChange(t),this.visible=!1,this.$emit(\"clear\")},deleteTag:function(e,t){var i=this.selected.indexOf(t);if(i>-1&&!this.selectDisabled){var n=this.value.slice();n.splice(i,1),this.$emit(\"input\",n),this.emitChange(n),this.$emit(\"remove-tag\",t.value)}e.stopPropagation()},onInputChange:function(){this.filterable&&this.query!==this.selectedLabel&&(this.query=this.selectedLabel,this.handleQueryChange(this.query))},onOptionDestroy:function(e){e>-1&&(this.optionsCount--,this.filteredOptionsCount--,this.options.splice(e,1))},resetInputWidth:function(){this.inputWidth=this.$refs.reference.$el.getBoundingClientRect().width},handleResize:function(){this.resetInputWidth(),this.multiple&&this.resetInputHeight()},checkDefaultFirstOption:function(){this.hoverIndex=-1;for(var e=!1,t=this.options.length-1;t>=0;t--)if(this.options[t].created){e=!0,this.hoverIndex=t;break}if(!e)for(var i=0;i!==this.options.length;++i){var n=this.options[i];if(this.query){if(!n.disabled&&!n.groupDisabled&&n.visible){this.hoverIndex=i;break}}else if(n.itemSelected){this.hoverIndex=i;break}}},getValueKey:function(e){return\"[object object]\"!==Object.prototype.toString.call(e.value).toLowerCase()?e.value:Object(F[\"getValueByPath\"])(e.value,this.valueKey)}},created:function(){var e=this;this.cachedPlaceHolder=this.currentPlaceholder=this.placeholder,this.multiple&&!Array.isArray(this.value)&&this.$emit(\"input\",[]),!this.multiple&&Array.isArray(this.value)&&this.$emit(\"input\",\"\"),this.debouncedOnInputChange=E()(this.debounce,function(){e.onInputChange()}),this.debouncedQueryChange=E()(this.debounce,function(t){e.handleQueryChange(t.target.value)}),this.$on(\"handleOptionClick\",this.handleOptionSelect),this.$on(\"setSelected\",this.setSelected)},mounted:function(){var e=this;this.multiple&&Array.isArray(this.value)&&this.value.length>0&&(this.currentPlaceholder=\"\"),Object(I[\"addResizeListener\"])(this.$el,this.handleResize);var t=this.$refs.reference;if(t&&t.$el){var i={medium:36,small:32,mini:28};this.initialInputHeight=t.$el.getBoundingClientRect().height||i[this.selectSize]}this.remote&&this.multiple&&this.resetInputHeight(),this.$nextTick(function(){t&&t.$el&&(e.inputWidth=t.$el.getBoundingClientRect().width)}),this.setSelected()},beforeDestroy:function(){this.$el&&this.handleResize&&Object(I[\"removeResizeListener\"])(this.$el,this.handleResize)}},B=V,z=Object(y[\"a\"])(B,n,s,!1,null,null,null);z.options.__file=\"packages/select/src/select.vue\";var j=z.exports;j.install=function(e){e.component(j.name,j)};t[\"default\"]=j}])},5128:function(e,t,i){\"use strict\";t.__esModule=!0,t.PopupManager=void 0;var n=i(\"2b0e\"),s=d(n),r=i(\"7f4d\"),o=d(r),a=i(\"4b26\"),l=d(a),u=i(\"e62d\"),c=d(u),h=i(\"5924\");function d(e){return e&&e.__esModule?e:{default:e}}var p=1,f=void 0;t.default={props:{visible:{type:Boolean,default:!1},openDelay:{},closeDelay:{},zIndex:{},modal:{type:Boolean,default:!1},modalFade:{type:Boolean,default:!0},modalClass:{},modalAppendToBody:{type:Boolean,default:!1},lockScroll:{type:Boolean,default:!0},closeOnPressEscape:{type:Boolean,default:!1},closeOnClickModal:{type:Boolean,default:!1}},beforeMount:function(){this._popupId=\"popup-\"+p++,l.default.register(this._popupId,this)},beforeDestroy:function(){l.default.deregister(this._popupId),l.default.closeModal(this._popupId),this.restoreBodyStyle()},data:function(){return{opened:!1,bodyPaddingRight:null,computedBodyPaddingRight:0,withoutHiddenClass:!0,rendered:!1}},watch:{visible:function(e){var t=this;if(e){if(this._opening)return;this.rendered?this.open():(this.rendered=!0,s.default.nextTick(function(){t.open()}))}else this.close()}},methods:{open:function(e){var t=this;this.rendered||(this.rendered=!0);var i=(0,o.default)({},this.$props||this,e);this._closeTimer&&(clearTimeout(this._closeTimer),this._closeTimer=null),clearTimeout(this._openTimer);var n=Number(i.openDelay);n>0?this._openTimer=setTimeout(function(){t._openTimer=null,t.doOpen(i)},n):this.doOpen(i)},doOpen:function(e){if(!this.$isServer&&(!this.willOpen||this.willOpen())&&!this.opened){this._opening=!0;var t=this.$el,i=e.modal,n=e.zIndex;if(n&&(l.default.zIndex=n),i&&(this._closing&&(l.default.closeModal(this._popupId),this._closing=!1),l.default.openModal(this._popupId,l.default.nextZIndex(),this.modalAppendToBody?void 0:t,e.modalClass,e.modalFade),e.lockScroll)){this.withoutHiddenClass=!(0,h.hasClass)(document.body,\"el-popup-parent--hidden\"),this.withoutHiddenClass&&(this.bodyPaddingRight=document.body.style.paddingRight,this.computedBodyPaddingRight=parseInt((0,h.getStyle)(document.body,\"paddingRight\"),10)),f=(0,c.default)();var s=document.documentElement.clientHeight<document.body.scrollHeight,r=(0,h.getStyle)(document.body,\"overflowY\");f>0&&(s||\"scroll\"===r)&&this.withoutHiddenClass&&(document.body.style.paddingRight=this.computedBodyPaddingRight+f+\"px\"),(0,h.addClass)(document.body,\"el-popup-parent--hidden\")}\"static\"===getComputedStyle(t).position&&(t.style.position=\"absolute\"),t.style.zIndex=l.default.nextZIndex(),this.opened=!0,this.onOpen&&this.onOpen(),this.doAfterOpen()}},doAfterOpen:function(){this._opening=!1},close:function(){var e=this;if(!this.willClose||this.willClose()){null!==this._openTimer&&(clearTimeout(this._openTimer),this._openTimer=null),clearTimeout(this._closeTimer);var t=Number(this.closeDelay);t>0?this._closeTimer=setTimeout(function(){e._closeTimer=null,e.doClose()},t):this.doClose()}},doClose:function(){this._closing=!0,this.onClose&&this.onClose(),this.lockScroll&&setTimeout(this.restoreBodyStyle,200),this.opened=!1,this.doAfterClose()},doAfterClose:function(){l.default.closeModal(this._popupId),this._closing=!1},restoreBodyStyle:function(){this.modal&&this.withoutHiddenClass&&(document.body.style.paddingRight=this.bodyPaddingRight,(0,h.removeClass)(document.body,\"el-popup-parent--hidden\")),this.withoutHiddenClass=!0}}},t.PopupManager=l.default},5488:function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(\"5924\");function s(e,t){if(!(e instanceof t))throw new TypeError(\"Cannot call a class as a function\")}var r=function(){function e(){s(this,e)}return e.prototype.beforeEnter=function(e){(0,n.addClass)(e,\"collapse-transition\"),e.dataset||(e.dataset={}),e.dataset.oldPaddingTop=e.style.paddingTop,e.dataset.oldPaddingBottom=e.style.paddingBottom,e.style.height=\"0\",e.style.paddingTop=0,e.style.paddingBottom=0},e.prototype.enter=function(e){e.dataset.oldOverflow=e.style.overflow,0!==e.scrollHeight?(e.style.height=e.scrollHeight+\"px\",e.style.paddingTop=e.dataset.oldPaddingTop,e.style.paddingBottom=e.dataset.oldPaddingBottom):(e.style.height=\"\",e.style.paddingTop=e.dataset.oldPaddingTop,e.style.paddingBottom=e.dataset.oldPaddingBottom),e.style.overflow=\"hidden\"},e.prototype.afterEnter=function(e){(0,n.removeClass)(e,\"collapse-transition\"),e.style.height=\"\",e.style.overflow=e.dataset.oldOverflow},e.prototype.beforeLeave=function(e){e.dataset||(e.dataset={}),e.dataset.oldPaddingTop=e.style.paddingTop,e.dataset.oldPaddingBottom=e.style.paddingBottom,e.dataset.oldOverflow=e.style.overflow,e.style.height=e.scrollHeight+\"px\",e.style.overflow=\"hidden\"},e.prototype.leave=function(e){0!==e.scrollHeight&&((0,n.addClass)(e,\"collapse-transition\"),e.style.height=0,e.style.paddingTop=0,e.style.paddingBottom=0)},e.prototype.afterLeave=function(e){(0,n.removeClass)(e,\"collapse-transition\"),e.style.height=\"\",e.style.overflow=e.dataset.oldOverflow,e.style.paddingTop=e.dataset.oldPaddingTop,e.style.paddingBottom=e.dataset.oldPaddingBottom},e}();t.default={name:\"ElCollapseTransition\",functional:!0,render:function(e,t){var i=t.children,n={on:new r};return e(\"transition\",n,i)}}},5924:function(e,t,i){\"use strict\";t.__esModule=!0,t.getStyle=t.once=t.off=t.on=void 0;var n=\"function\"===typeof Symbol&&\"symbol\"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e};t.hasClass=m,t.addClass=v,t.removeClass=g,t.setStyle=b;var s=i(\"2b0e\"),r=o(s);function o(e){return e&&e.__esModule?e:{default:e}}var a=r.default.prototype.$isServer,l=/([\\:\\-\\_]+(.))/g,u=/^moz([A-Z])/,c=a?0:Number(document.documentMode),h=function(e){return(e||\"\").replace(/^[\\s\\uFEFF]+|[\\s\\uFEFF]+$/g,\"\")},d=function(e){return e.replace(l,function(e,t,i,n){return n?i.toUpperCase():i}).replace(u,\"Moz$1\")},p=t.on=function(){return!a&&document.addEventListener?function(e,t,i){e&&t&&i&&e.addEventListener(t,i,!1)}:function(e,t,i){e&&t&&i&&e.attachEvent(\"on\"+t,i)}}(),f=t.off=function(){return!a&&document.removeEventListener?function(e,t,i){e&&t&&e.removeEventListener(t,i,!1)}:function(e,t,i){e&&t&&e.detachEvent(\"on\"+t,i)}}();t.once=function(e,t,i){var n=function n(){i&&i.apply(this,arguments),f(e,t,n)};p(e,t,n)};function m(e,t){if(!e||!t)return!1;if(-1!==t.indexOf(\" \"))throw new Error(\"className should not contain space.\");return e.classList?e.classList.contains(t):(\" \"+e.className+\" \").indexOf(\" \"+t+\" \")>-1}function v(e,t){if(e){for(var i=e.className,n=(t||\"\").split(\" \"),s=0,r=n.length;s<r;s++){var o=n[s];o&&(e.classList?e.classList.add(o):m(e,o)||(i+=\" \"+o))}e.classList||(e.className=i)}}function g(e,t){if(e&&t){for(var i=t.split(\" \"),n=\" \"+e.className+\" \",s=0,r=i.length;s<r;s++){var o=i[s];o&&(e.classList?e.classList.remove(o):m(e,o)&&(n=n.replace(\" \"+o+\" \",\" \")))}e.classList||(e.className=h(n))}}t.getStyle=c<9?function(e,t){if(!a){if(!e||!t)return null;t=d(t),\"float\"===t&&(t=\"styleFloat\");try{switch(t){case\"opacity\":try{return e.filters.item(\"alpha\").opacity/100}catch(i){return 1}default:return e.style[t]||e.currentStyle?e.currentStyle[t]:null}}catch(i){return e.style[t]}}}:function(e,t){if(!a){if(!e||!t)return null;t=d(t),\"float\"===t&&(t=\"cssFloat\");try{var i=document.defaultView.getComputedStyle(e,\"\");return e.style[t]||i?i[t]:null}catch(n){return e.style[t]}}};function b(e,t,i){if(e&&t)if(\"object\"===(\"undefined\"===typeof t?\"undefined\":n(t)))for(var s in t)t.hasOwnProperty(s)&&b(e,s,t[s]);else t=d(t),\"opacity\"===t&&c<9?e.style.filter=isNaN(i)?\"\":\"alpha(opacity=\"+100*i+\")\":e.style[t]=i}},\"5c96\":function(e,t,i){e.exports=function(e){var t={};function i(n){if(t[n])return t[n].exports;var s=t[n]={i:n,l:!1,exports:{}};return e[n].call(s.exports,s,s.exports,i),s.l=!0,s.exports}return i.m=e,i.c=t,i.d=function(e,t,n){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},i.r=function(e){\"undefined\"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(e,\"__esModule\",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&\"object\"===typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,\"default\",{enumerable:!0,value:e}),2&t&&\"string\"!=typeof e)for(var s in e)i.d(n,s,function(t){return e[t]}.bind(null,s));return n},i.n=function(e){var t=e&&e.__esModule?function(){return e[\"default\"]}:function(){return e};return i.d(t,\"a\",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p=\"/dist/\",i(i.s=38)}([function(e,t){e.exports=i(\"5924\")},function(e,t){e.exports=i(\"8122\")},function(e,t){e.exports=i(\"d010\")},function(e,t){e.exports=i(\"2b0e\")},function(e,t){e.exports=i(\"e974\")},function(e,t){e.exports=i(\"6b7c\")},function(e,t){e.exports=i(\"7f4d\")},function(e,t){e.exports=i(\"f3ad\")},function(e,t){e.exports=i(\"2bb5\")},function(e,t){e.exports=i(\"417f\")},function(e,t){e.exports=i(\"4897\")},function(e,t){e.exports=i(\"5128\")},function(e,t){e.exports=i(\"0e15\")},function(e,t){e.exports=i(\"4010\")},function(e,t){e.exports=i(\"eedf\")},function(e,t){e.exports=i(\"dcdc\")},function(e,t){e.exports=i(\"5488\")},function(e,t){e.exports=i(\"14e9\")},function(e,t){e.exports=i(\"12f2\")},function(e,t){e.exports=i(\"41f8\")},function(e,t){e.exports=i(\"299c\")},function(e,t){e.exports=i(\"8bbc\")},function(e,t){e.exports=i(\"2a5e\")},function(e,t){e.exports=i(\"92fa\")},function(e,t){e.exports=i(\"d7d1\")},function(e,t){e.exports=i(\"d397\")},function(e,t){e.exports=i(\"e62d\")},function(e,t){e.exports=i(\"7fc1\")},function(e,t){e.exports=i(\"c56a\")},function(e,t){e.exports=i(\"c284\")},function(e,t){e.exports=i(\"597f\")},function(e,t){e.exports=i(\"4e4b\")},function(e,t){e.exports=i(\"e772\")},function(e,t){e.exports=i(\"845f\")},function(e,t){e.exports=i(\"c098\")},function(e,t){e.exports=i(\"722f\")},function(e,t){e.exports=i(\"a15e\")},function(e,t){e.exports=i(\"e450\")},function(e,t,i){e.exports=i(39)},function(e,t,i){\"use strict\";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"ul\",{staticClass:\"el-pager\",on:{click:e.onPagerClick}},[e.pageCount>0?i(\"li\",{staticClass:\"number\",class:{active:1===e.currentPage,disabled:e.disabled}},[e._v(\"1\")]):e._e(),e.showPrevMore?i(\"li\",{staticClass:\"el-icon more btn-quickprev\",class:[e.quickprevIconClass,{disabled:e.disabled}],on:{mouseenter:function(t){e.onMouseenter(\"left\")},mouseleave:function(t){e.quickprevIconClass=\"el-icon-more\"}}}):e._e(),e._l(e.pagers,function(t){return i(\"li\",{key:t,staticClass:\"number\",class:{active:e.currentPage===t,disabled:e.disabled}},[e._v(e._s(t))])}),e.showNextMore?i(\"li\",{staticClass:\"el-icon more btn-quicknext\",class:[e.quicknextIconClass,{disabled:e.disabled}],on:{mouseenter:function(t){e.onMouseenter(\"right\")},mouseleave:function(t){e.quicknextIconClass=\"el-icon-more\"}}}):e._e(),e.pageCount>1?i(\"li\",{staticClass:\"number\",class:{active:e.currentPage===e.pageCount,disabled:e.disabled}},[e._v(e._s(e.pageCount))]):e._e()],2)},s=[];n._withStripped=!0;var r={name:\"ElPager\",props:{currentPage:Number,pageCount:Number,pagerCount:Number,disabled:Boolean},watch:{showPrevMore:function(e){e||(this.quickprevIconClass=\"el-icon-more\")},showNextMore:function(e){e||(this.quicknextIconClass=\"el-icon-more\")}},methods:{onPagerClick:function(e){var t=e.target;if(\"UL\"!==t.tagName&&!this.disabled){var i=Number(e.target.textContent),n=this.pageCount,s=this.currentPage,r=this.pagerCount-2;-1!==t.className.indexOf(\"more\")&&(-1!==t.className.indexOf(\"quickprev\")?i=s-r:-1!==t.className.indexOf(\"quicknext\")&&(i=s+r)),isNaN(i)||(i<1&&(i=1),i>n&&(i=n)),i!==s&&this.$emit(\"change\",i)}},onMouseenter:function(e){this.disabled||(\"left\"===e?this.quickprevIconClass=\"el-icon-d-arrow-left\":this.quicknextIconClass=\"el-icon-d-arrow-right\")}},computed:{pagers:function(){var e=this.pagerCount,t=(e-1)/2,i=Number(this.currentPage),n=Number(this.pageCount),s=!1,r=!1;n>e&&(i>e-t&&(s=!0),i<n-t&&(r=!0));var o=[];if(s&&!r)for(var a=n-(e-2),l=a;l<n;l++)o.push(l);else if(!s&&r)for(var u=2;u<e;u++)o.push(u);else if(s&&r)for(var c=Math.floor(e/2)-1,h=i-c;h<=i+c;h++)o.push(h);else for(var d=2;d<n;d++)o.push(d);return this.showPrevMore=s,this.showNextMore=r,o}},data:function(){return{current:null,showPrevMore:!1,showNextMore:!1,quicknextIconClass:\"el-icon-more\",quickprevIconClass:\"el-icon-more\"}}},o=r;function a(e,t,i,n,s,r,o,a){var l,u=\"function\"===typeof e?e.options:e;if(t&&(u.render=t,u.staticRenderFns=i,u._compiled=!0),n&&(u.functional=!0),r&&(u._scopeId=\"data-v-\"+r),o?(l=function(e){e=e||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext,e||\"undefined\"===typeof __VUE_SSR_CONTEXT__||(e=__VUE_SSR_CONTEXT__),s&&s.call(this,e),e&&e._registeredComponents&&e._registeredComponents.add(o)},u._ssrRegister=l):s&&(l=a?function(){s.call(this,this.$root.$options.shadowRoot)}:s),l)if(u.functional){u._injectStyles=l;var c=u.render;u.render=function(e,t){return l.call(t),c(e,t)}}else{var h=u.beforeCreate;u.beforeCreate=h?[].concat(h,l):[l]}return{exports:e,options:u}}var l=a(o,n,s,!1,null,null,null);l.options.__file=\"packages/pagination/src/pager.vue\";var u=l.exports,c=i(31),h=i.n(c),d=i(32),p=i.n(d),f=i(7),m=i.n(f),v=i(5),g=i.n(v),b=i(1),y={name:\"ElPagination\",props:{pageSize:{type:Number,default:10},small:Boolean,total:Number,pageCount:Number,pagerCount:{type:Number,validator:function(e){return(0|e)===e&&e>4&&e<22&&e%2===1},default:7},currentPage:{type:Number,default:1},layout:{default:\"prev, pager, next, jumper, ->, total\"},pageSizes:{type:Array,default:function(){return[10,20,30,40,50,100]}},popperClass:String,prevText:String,nextText:String,background:Boolean,disabled:Boolean},data:function(){return{internalCurrentPage:1,internalPageSize:0,lastEmittedPage:-1,userChangePageSize:!1}},render:function(e){var t=e(\"div\",{class:[\"el-pagination\",{\"is-background\":this.background,\"el-pagination--small\":this.small}]}),i=this.layout||\"\";if(i){var n={prev:e(\"prev\"),jumper:e(\"jumper\"),pager:e(\"pager\",{attrs:{currentPage:this.internalCurrentPage,pageCount:this.internalPageCount,pagerCount:this.pagerCount,disabled:this.disabled},on:{change:this.handleCurrentChange}}),next:e(\"next\"),sizes:e(\"sizes\",{attrs:{pageSizes:this.pageSizes}}),slot:e(\"my-slot\"),total:e(\"total\")},s=i.split(\",\").map(function(e){return e.trim()}),r=e(\"div\",{class:\"el-pagination__rightwrapper\"}),o=!1;return t.children=t.children||[],r.children=r.children||[],s.forEach(function(e){\"->\"!==e?o?r.children.push(n[e]):t.children.push(n[e]):o=!0}),o&&t.children.unshift(r),t}},components:{MySlot:{render:function(e){return this.$parent.$slots.default?this.$parent.$slots.default[0]:\"\"}},Prev:{render:function(e){return e(\"button\",{attrs:{type:\"button\",disabled:this.$parent.disabled||this.$parent.internalCurrentPage<=1},class:\"btn-prev\",on:{click:this.$parent.prev}},[this.$parent.prevText?e(\"span\",[this.$parent.prevText]):e(\"i\",{class:\"el-icon el-icon-arrow-left\"})])}},Next:{render:function(e){return e(\"button\",{attrs:{type:\"button\",disabled:this.$parent.disabled||this.$parent.internalCurrentPage===this.$parent.internalPageCount||0===this.$parent.internalPageCount},class:\"btn-next\",on:{click:this.$parent.next}},[this.$parent.nextText?e(\"span\",[this.$parent.nextText]):e(\"i\",{class:\"el-icon el-icon-arrow-right\"})])}},Sizes:{mixins:[g.a],props:{pageSizes:Array},watch:{pageSizes:{immediate:!0,handler:function(e,t){Object(b[\"valueEquals\"])(e,t)||Array.isArray(e)&&(this.$parent.internalPageSize=e.indexOf(this.$parent.pageSize)>-1?this.$parent.pageSize:this.pageSizes[0])}}},render:function(e){var t=this;return e(\"span\",{class:\"el-pagination__sizes\"},[e(\"el-select\",{attrs:{value:this.$parent.internalPageSize,popperClass:this.$parent.popperClass||\"\",size:\"mini\",disabled:this.$parent.disabled},on:{input:this.handleChange}},[this.pageSizes.map(function(i){return e(\"el-option\",{attrs:{value:i,label:i+t.t(\"el.pagination.pagesize\")}})})])])},components:{ElSelect:h.a,ElOption:p.a},methods:{handleChange:function(e){e!==this.$parent.internalPageSize&&(this.$parent.internalPageSize=e=parseInt(e,10),this.$parent.userChangePageSize=!0,this.$parent.$emit(\"update:pageSize\",e),this.$parent.$emit(\"size-change\",e))}}},Jumper:{mixins:[g.a],components:{ElInput:m.a},data:function(){return{userInput:null}},watch:{\"$parent.internalCurrentPage\":function(){this.userInput=null}},methods:{handleKeyup:function(e){var t=e.keyCode,i=e.target;13===t&&this.handleChange(i.value)},handleInput:function(e){this.userInput=e},handleChange:function(e){this.$parent.internalCurrentPage=this.$parent.getValidCurrentPage(e),this.$parent.emitChange(),this.userInput=null}},render:function(e){return e(\"span\",{class:\"el-pagination__jump\"},[this.t(\"el.pagination.goto\"),e(\"el-input\",{class:\"el-pagination__editor is-in-pagination\",attrs:{min:1,max:this.$parent.internalPageCount,value:null!==this.userInput?this.userInput:this.$parent.internalCurrentPage,type:\"number\",disabled:this.$parent.disabled},nativeOn:{keyup:this.handleKeyup},on:{input:this.handleInput,change:this.handleChange}}),this.t(\"el.pagination.pageClassifier\")])}},Total:{mixins:[g.a],render:function(e){return\"number\"===typeof this.$parent.total?e(\"span\",{class:\"el-pagination__total\"},[this.t(\"el.pagination.total\",{total:this.$parent.total})]):\"\"}},Pager:u},methods:{handleCurrentChange:function(e){this.internalCurrentPage=this.getValidCurrentPage(e),this.userChangePageSize=!0,this.emitChange()},prev:function(){if(!this.disabled){var e=this.internalCurrentPage-1;this.internalCurrentPage=this.getValidCurrentPage(e),this.$emit(\"prev-click\",this.internalCurrentPage),this.emitChange()}},next:function(){if(!this.disabled){var e=this.internalCurrentPage+1;this.internalCurrentPage=this.getValidCurrentPage(e),this.$emit(\"next-click\",this.internalCurrentPage),this.emitChange()}},getValidCurrentPage:function(e){e=parseInt(e,10);var t=\"number\"===typeof this.internalPageCount,i=void 0;return t?e<1?i=1:e>this.internalPageCount&&(i=this.internalPageCount):(isNaN(e)||e<1)&&(i=1),void 0===i&&isNaN(e)?i=1:0===i&&(i=1),void 0===i?e:i},emitChange:function(){var e=this;this.$nextTick(function(){(e.internalCurrentPage!==e.lastEmittedPage||e.userChangePageSize)&&(e.$emit(\"current-change\",e.internalCurrentPage),e.lastEmittedPage=e.internalCurrentPage,e.userChangePageSize=!1)})}},computed:{internalPageCount:function(){return\"number\"===typeof this.total?Math.max(1,Math.ceil(this.total/this.internalPageSize)):\"number\"===typeof this.pageCount?Math.max(1,this.pageCount):null}},watch:{currentPage:{immediate:!0,handler:function(e){this.internalCurrentPage=this.getValidCurrentPage(e)}},pageSize:{immediate:!0,handler:function(e){this.internalPageSize=isNaN(e)?10:e}},internalCurrentPage:{immediate:!0,handler:function(e){this.$emit(\"update:currentPage\",e),this.lastEmittedPage=-1}},internalPageCount:function(e){var t=this.internalCurrentPage;e>0&&0===t?this.internalCurrentPage=1:t>e&&(this.internalCurrentPage=0===e?1:e,this.userChangePageSize&&this.emitChange()),this.userChangePageSize=!1}},install:function(e){e.component(y.name,y)}},_=y,x=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"dialog-fade\"},on:{\"after-enter\":e.afterEnter,\"after-leave\":e.afterLeave}},[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible,expression:\"visible\"}],staticClass:\"el-dialog__wrapper\",on:{click:function(t){return t.target!==t.currentTarget?null:e.handleWrapperClick(t)}}},[i(\"div\",{ref:\"dialog\",staticClass:\"el-dialog\",class:[{\"is-fullscreen\":e.fullscreen,\"el-dialog--center\":e.center},e.customClass],style:e.style,attrs:{role:\"dialog\",\"aria-modal\":\"true\",\"aria-label\":e.title||\"dialog\"}},[i(\"div\",{staticClass:\"el-dialog__header\"},[e._t(\"title\",[i(\"span\",{staticClass:\"el-dialog__title\"},[e._v(e._s(e.title))])]),e.showClose?i(\"button\",{staticClass:\"el-dialog__headerbtn\",attrs:{type:\"button\",\"aria-label\":\"Close\"},on:{click:e.handleClose}},[i(\"i\",{staticClass:\"el-dialog__close el-icon el-icon-close\"})]):e._e()],2),e.rendered?i(\"div\",{staticClass:\"el-dialog__body\"},[e._t(\"default\")],2):e._e(),e.$slots.footer?i(\"div\",{staticClass:\"el-dialog__footer\"},[e._t(\"footer\")],2):e._e()])])])},C=[];x._withStripped=!0;var w=i(11),k=i.n(w),S=i(8),$=i.n(S),D=i(2),E=i.n(D),T={name:\"ElDialog\",mixins:[k.a,E.a,$.a],props:{title:{type:String,default:\"\"},modal:{type:Boolean,default:!0},modalAppendToBody:{type:Boolean,default:!0},appendToBody:{type:Boolean,default:!1},lockScroll:{type:Boolean,default:!0},closeOnClickModal:{type:Boolean,default:!0},closeOnPressEscape:{type:Boolean,default:!0},showClose:{type:Boolean,default:!0},width:String,fullscreen:Boolean,customClass:{type:String,default:\"\"},top:{type:String,default:\"15vh\"},beforeClose:Function,center:{type:Boolean,default:!1}},data:function(){return{closed:!1}},watch:{visible:function(e){var t=this;e?(this.closed=!1,this.$emit(\"open\"),this.$el.addEventListener(\"scroll\",this.updatePopper),this.$nextTick(function(){t.$refs.dialog.scrollTop=0}),this.appendToBody&&document.body.appendChild(this.$el)):(this.$el.removeEventListener(\"scroll\",this.updatePopper),this.closed||this.$emit(\"close\"))}},computed:{style:function(){var e={};return this.fullscreen||(e.marginTop=this.top,this.width&&(e.width=this.width)),e}},methods:{getMigratingConfig:function(){return{props:{size:\"size is removed.\"}}},handleWrapperClick:function(){this.closeOnClickModal&&this.handleClose()},handleClose:function(){\"function\"===typeof this.beforeClose?this.beforeClose(this.hide):this.hide()},hide:function(e){!1!==e&&(this.$emit(\"update:visible\",!1),this.$emit(\"close\"),this.closed=!0)},updatePopper:function(){this.broadcast(\"ElSelectDropdown\",\"updatePopper\"),this.broadcast(\"ElDropdownMenu\",\"updatePopper\")},afterEnter:function(){this.$emit(\"opened\")},afterLeave:function(){this.$emit(\"closed\")}},mounted:function(){this.visible&&(this.rendered=!0,this.open(),this.appendToBody&&document.body.appendChild(this.$el))},destroyed:function(){this.appendToBody&&this.$el&&this.$el.parentNode&&this.$el.parentNode.removeChild(this.$el)}},O=T,I=a(O,x,C,!1,null,null,null);I.options.__file=\"packages/dialog/src/component.vue\";var P=I.exports;P.install=function(e){e.component(P.name,P)};var M=P,N=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{directives:[{name:\"clickoutside\",rawName:\"v-clickoutside\",value:e.close,expression:\"close\"}],staticClass:\"el-autocomplete\",attrs:{\"aria-haspopup\":\"listbox\",role:\"combobox\",\"aria-expanded\":e.suggestionVisible,\"aria-owns\":e.id}},[i(\"el-input\",e._b({ref:\"input\",on:{input:e.handleChange,focus:e.handleFocus,blur:e.handleBlur,clear:e.handleClear},nativeOn:{keydown:[function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"up\",38,t.key,[\"Up\",\"ArrowUp\"]))return null;t.preventDefault(),e.highlight(e.highlightedIndex-1)},function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"down\",40,t.key,[\"Down\",\"ArrowDown\"]))return null;t.preventDefault(),e.highlight(e.highlightedIndex+1)},function(t){return\"button\"in t||!e._k(t.keyCode,\"enter\",13,t.key,\"Enter\")?e.handleKeyEnter(t):null},function(t){return\"button\"in t||!e._k(t.keyCode,\"tab\",9,t.key,\"Tab\")?e.close(t):null}]}},\"el-input\",[e.$props,e.$attrs],!1),[e.$slots.prepend?i(\"template\",{slot:\"prepend\"},[e._t(\"prepend\")],2):e._e(),e.$slots.append?i(\"template\",{slot:\"append\"},[e._t(\"append\")],2):e._e(),e.$slots.prefix?i(\"template\",{slot:\"prefix\"},[e._t(\"prefix\")],2):e._e(),e.$slots.suffix?i(\"template\",{slot:\"suffix\"},[e._t(\"suffix\")],2):e._e()],2),i(\"el-autocomplete-suggestions\",{ref:\"suggestions\",class:[e.popperClass?e.popperClass:\"\"],attrs:{\"visible-arrow\":\"\",\"popper-options\":e.popperOptions,\"append-to-body\":e.popperAppendToBody,placement:e.placement,id:e.id}},e._l(e.suggestions,function(t,n){return i(\"li\",{key:n,class:{highlighted:e.highlightedIndex===n},attrs:{id:e.id+\"-item-\"+n,role:\"option\",\"aria-selected\":e.highlightedIndex===n},on:{click:function(i){e.select(t)}}},[e._t(\"default\",[e._v(\"\\n        \"+e._s(t[e.valueKey])+\"\\n      \")],{item:t})],2)}),0)],1)},F=[];N._withStripped=!0;var A=i(12),L=i.n(A),V=i(9),B=i.n(V),z=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"el-zoom-in-top\"},on:{\"after-leave\":e.doDestroy}},[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.showPopper,expression:\"showPopper\"}],staticClass:\"el-autocomplete-suggestion el-popper\",class:{\"is-loading\":!e.parent.hideLoading&&e.parent.loading},style:{width:e.dropdownWidth},attrs:{role:\"region\"}},[i(\"el-scrollbar\",{attrs:{tag:\"ul\",\"wrap-class\":\"el-autocomplete-suggestion__wrap\",\"view-class\":\"el-autocomplete-suggestion__list\"}},[!e.parent.hideLoading&&e.parent.loading?i(\"li\",[i(\"i\",{staticClass:\"el-icon-loading\"})]):e._t(\"default\")],2)],1)])},j=[];z._withStripped=!0;var H=i(4),R=i.n(H),W=i(17),q=i.n(W),K={components:{ElScrollbar:q.a},mixins:[R.a,E.a],componentName:\"ElAutocompleteSuggestions\",data:function(){return{parent:this.$parent,dropdownWidth:\"\"}},props:{options:{default:function(){return{gpuAcceleration:!1}}},id:String},methods:{select:function(e){this.dispatch(\"ElAutocomplete\",\"item-click\",e)}},updated:function(){var e=this;this.$nextTick(function(t){e.popperJS&&e.updatePopper()})},mounted:function(){this.$parent.popperElm=this.popperElm=this.$el,this.referenceElm=this.$parent.$refs.input.$refs.input,this.referenceList=this.$el.querySelector(\".el-autocomplete-suggestion__list\"),this.referenceList.setAttribute(\"role\",\"listbox\"),this.referenceList.setAttribute(\"id\",this.id)},created:function(){var e=this;this.$on(\"visible\",function(t,i){e.dropdownWidth=i+\"px\",e.showPopper=t})}},Y=K,U=a(Y,z,j,!1,null,null,null);U.options.__file=\"packages/autocomplete/src/autocomplete-suggestions.vue\";var G=U.exports,X=i(18),Q=i.n(X),J={name:\"ElAutocomplete\",mixins:[E.a,Q()(\"input\"),$.a],inheritAttrs:!1,componentName:\"ElAutocomplete\",components:{ElInput:m.a,ElAutocompleteSuggestions:G},directives:{Clickoutside:B.a},props:{valueKey:{type:String,default:\"value\"},popperClass:String,popperOptions:Object,placeholder:String,clearable:{type:Boolean,default:!1},disabled:Boolean,name:String,size:String,value:String,maxlength:Number,minlength:Number,autofocus:Boolean,fetchSuggestions:Function,triggerOnFocus:{type:Boolean,default:!0},customItem:String,selectWhenUnmatched:{type:Boolean,default:!1},prefixIcon:String,suffixIcon:String,label:String,debounce:{type:Number,default:300},placement:{type:String,default:\"bottom-start\"},hideLoading:Boolean,popperAppendToBody:{type:Boolean,default:!0},highlightFirstItem:{type:Boolean,default:!1}},data:function(){return{activated:!1,suggestions:[],loading:!1,highlightedIndex:-1,suggestionDisabled:!1}},computed:{suggestionVisible:function(){var e=this.suggestions,t=Array.isArray(e)&&e.length>0;return(t||this.loading)&&this.activated},id:function(){return\"el-autocomplete-\"+Object(b[\"generateId\"])()}},watch:{suggestionVisible:function(e){var t=this.getInput();t&&this.broadcast(\"ElAutocompleteSuggestions\",\"visible\",[e,t.offsetWidth])}},methods:{getMigratingConfig:function(){return{props:{\"custom-item\":\"custom-item is removed, use scoped slot instead.\",props:\"props is removed, use value-key instead.\"}}},getData:function(e){var t=this;this.suggestionDisabled||(this.loading=!0,this.fetchSuggestions(e,function(e){t.loading=!1,t.suggestionDisabled||(Array.isArray(e)?(t.suggestions=e,t.highlightedIndex=t.highlightFirstItem?0:-1):console.error(\"[Element Error][Autocomplete]autocomplete suggestions must be an array\"))}))},handleChange:function(e){if(this.$emit(\"input\",e),this.suggestionDisabled=!1,!this.triggerOnFocus&&!e)return this.suggestionDisabled=!0,void(this.suggestions=[]);this.debouncedGetData(e)},handleFocus:function(e){this.activated=!0,this.$emit(\"focus\",e),this.triggerOnFocus&&this.debouncedGetData(this.value)},handleBlur:function(e){this.$emit(\"blur\",e)},handleClear:function(){this.activated=!1,this.$emit(\"clear\")},close:function(e){this.activated=!1},handleKeyEnter:function(e){var t=this;this.suggestionVisible&&this.highlightedIndex>=0&&this.highlightedIndex<this.suggestions.length?(e.preventDefault(),this.select(this.suggestions[this.highlightedIndex])):this.selectWhenUnmatched&&(this.$emit(\"select\",{value:this.value}),this.$nextTick(function(e){t.suggestions=[],t.highlightedIndex=-1}))},select:function(e){var t=this;this.$emit(\"input\",e[this.valueKey]),this.$emit(\"select\",e),this.$nextTick(function(e){t.suggestions=[],t.highlightedIndex=-1})},highlight:function(e){if(this.suggestionVisible&&!this.loading)if(e<0)this.highlightedIndex=-1;else{e>=this.suggestions.length&&(e=this.suggestions.length-1);var t=this.$refs.suggestions.$el.querySelector(\".el-autocomplete-suggestion__wrap\"),i=t.querySelectorAll(\".el-autocomplete-suggestion__list li\"),n=i[e],s=t.scrollTop,r=n.offsetTop;r+n.scrollHeight>s+t.clientHeight&&(t.scrollTop+=n.scrollHeight),r<s&&(t.scrollTop-=n.scrollHeight),this.highlightedIndex=e;var o=this.getInput();o.setAttribute(\"aria-activedescendant\",this.id+\"-item-\"+this.highlightedIndex)}},getInput:function(){return this.$refs.input.getInput()}},mounted:function(){var e=this;this.debouncedGetData=L()(this.debounce,this.getData),this.$on(\"item-click\",function(t){e.select(t)});var t=this.getInput();t.setAttribute(\"role\",\"textbox\"),t.setAttribute(\"aria-autocomplete\",\"list\"),t.setAttribute(\"aria-controls\",\"id\"),t.setAttribute(\"aria-activedescendant\",this.id+\"-item-\"+this.highlightedIndex)},beforeDestroy:function(){this.$refs.suggestions.$destroy()}},Z=J,ee=a(Z,N,F,!1,null,null,null);ee.options.__file=\"packages/autocomplete/src/autocomplete.vue\";var te=ee.exports;te.install=function(e){e.component(te.name,te)};var ie,ne,se=te,re=i(14),oe=i.n(re),ae=i(33),le=i.n(ae),ue={name:\"ElDropdown\",componentName:\"ElDropdown\",mixins:[E.a,$.a],directives:{Clickoutside:B.a},components:{ElButton:oe.a,ElButtonGroup:le.a},provide:function(){return{dropdown:this}},props:{trigger:{type:String,default:\"hover\"},type:String,size:{type:String,default:\"\"},splitButton:Boolean,hideOnClick:{type:Boolean,default:!0},placement:{type:String,default:\"bottom-end\"},visibleArrow:{default:!0},showTimeout:{type:Number,default:250},hideTimeout:{type:Number,default:150}},data:function(){return{timeout:null,visible:!1,triggerElm:null,menuItems:null,menuItemsArray:null,dropdownElm:null,focusing:!1,listId:\"dropdown-menu-\"+Object(b[\"generateId\"])()}},computed:{dropdownSize:function(){return this.size||(this.$ELEMENT||{}).size}},mounted:function(){this.$on(\"menu-item-click\",this.handleMenuItemClick)},watch:{visible:function(e){this.broadcast(\"ElDropdownMenu\",\"visible\",e),this.$emit(\"visible-change\",e)},focusing:function(e){var t=this.$el.querySelector(\".el-dropdown-selfdefine\");t&&(e?t.className+=\" focusing\":t.className=t.className.replace(\"focusing\",\"\"))}},methods:{getMigratingConfig:function(){return{props:{\"menu-align\":\"menu-align is renamed to placement.\"}}},show:function(){var e=this;this.triggerElm.disabled||(clearTimeout(this.timeout),this.timeout=setTimeout(function(){e.visible=!0},\"click\"===this.trigger?0:this.showTimeout))},hide:function(){var e=this;this.triggerElm.disabled||(this.removeTabindex(),this.resetTabindex(this.triggerElm),clearTimeout(this.timeout),this.timeout=setTimeout(function(){e.visible=!1},\"click\"===this.trigger?0:this.hideTimeout))},handleClick:function(){this.triggerElm.disabled||(this.visible?this.hide():this.show())},handleTriggerKeyDown:function(e){var t=e.keyCode;[38,40].indexOf(t)>-1?(this.removeTabindex(),this.resetTabindex(this.menuItems[0]),this.menuItems[0].focus(),e.preventDefault(),e.stopPropagation()):13===t?this.handleClick():[9,27].indexOf(t)>-1&&this.hide()},handleItemKeyDown:function(e){var t=e.keyCode,i=e.target,n=this.menuItemsArray.indexOf(i),s=this.menuItemsArray.length-1,r=void 0;[38,40].indexOf(t)>-1?(r=38===t?0!==n?n-1:0:n<s?n+1:s,this.removeTabindex(),this.resetTabindex(this.menuItems[r]),this.menuItems[r].focus(),e.preventDefault(),e.stopPropagation()):13===t?(this.triggerElm.focus(),i.click(),this.hideOnClick&&(this.visible=!1)):[9,27].indexOf(t)>-1&&(this.hide(),this.triggerElm.focus())},resetTabindex:function(e){this.removeTabindex(),e.setAttribute(\"tabindex\",\"0\")},removeTabindex:function(){this.triggerElm.setAttribute(\"tabindex\",\"-1\"),this.menuItemsArray.forEach(function(e){e.setAttribute(\"tabindex\",\"-1\")})},initAria:function(){this.dropdownElm.setAttribute(\"id\",this.listId),this.triggerElm.setAttribute(\"aria-haspopup\",\"list\"),this.triggerElm.setAttribute(\"aria-controls\",this.listId),this.splitButton||(this.triggerElm.setAttribute(\"role\",\"button\"),this.triggerElm.setAttribute(\"tabindex\",\"0\"),this.triggerElm.setAttribute(\"class\",(this.triggerElm.getAttribute(\"class\")||\"\")+\" el-dropdown-selfdefine\"))},initEvent:function(){var e=this,t=this.trigger,i=this.show,n=this.hide,s=this.handleClick,r=this.splitButton,o=this.handleTriggerKeyDown,a=this.handleItemKeyDown;this.triggerElm=r?this.$refs.trigger.$el:this.$slots.default[0].elm;var l=this.dropdownElm;this.triggerElm.addEventListener(\"keydown\",o),l.addEventListener(\"keydown\",a,!0),r||(this.triggerElm.addEventListener(\"focus\",function(){e.focusing=!0}),this.triggerElm.addEventListener(\"blur\",function(){e.focusing=!1}),this.triggerElm.addEventListener(\"click\",function(){e.focusing=!1})),\"hover\"===t?(this.triggerElm.addEventListener(\"mouseenter\",i),this.triggerElm.addEventListener(\"mouseleave\",n),l.addEventListener(\"mouseenter\",i),l.addEventListener(\"mouseleave\",n)):\"click\"===t&&this.triggerElm.addEventListener(\"click\",s)},handleMenuItemClick:function(e,t){this.hideOnClick&&(this.visible=!1),this.$emit(\"command\",e,t)},focus:function(){this.triggerElm.focus&&this.triggerElm.focus()},initDomOperation:function(){this.dropdownElm=this.popperElm,this.menuItems=this.dropdownElm.querySelectorAll(\"[tabindex='-1']\"),this.menuItemsArray=[].slice.call(this.menuItems),this.initEvent(),this.initAria()}},render:function(e){var t=this,i=this.hide,n=this.splitButton,s=this.type,r=this.dropdownSize,o=function(e){t.$emit(\"click\",e),i()},a=n?e(\"el-button-group\",[e(\"el-button\",{attrs:{type:s,size:r},nativeOn:{click:o}},[this.$slots.default]),e(\"el-button\",{ref:\"trigger\",attrs:{type:s,size:r},class:\"el-dropdown__caret-button\"},[e(\"i\",{class:\"el-dropdown__icon el-icon-arrow-down\"})])]):this.$slots.default;return e(\"div\",{class:\"el-dropdown\",directives:[{name:\"clickoutside\",value:i}]},[a,this.$slots.dropdown])}},ce=ue,he=a(ce,ie,ne,!1,null,null,null);he.options.__file=\"packages/dropdown/src/dropdown.vue\";var de=he.exports;de.install=function(e){e.component(de.name,de)};var pe=de,fe=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"el-zoom-in-top\"},on:{\"after-leave\":e.doDestroy}},[i(\"ul\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.showPopper,expression:\"showPopper\"}],staticClass:\"el-dropdown-menu el-popper\",class:[e.size&&\"el-dropdown-menu--\"+e.size]},[e._t(\"default\")],2)])},me=[];fe._withStripped=!0;var ve={name:\"ElDropdownMenu\",componentName:\"ElDropdownMenu\",mixins:[R.a],props:{visibleArrow:{type:Boolean,default:!0},arrowOffset:{type:Number,default:0}},data:function(){return{size:this.dropdown.dropdownSize}},inject:[\"dropdown\"],created:function(){var e=this;this.$on(\"updatePopper\",function(){e.showPopper&&e.updatePopper()}),this.$on(\"visible\",function(t){e.showPopper=t})},mounted:function(){this.dropdown.popperElm=this.popperElm=this.$el,this.referenceElm=this.dropdown.$el,this.dropdown.initDomOperation()},watch:{\"dropdown.placement\":{immediate:!0,handler:function(e){this.currentPlacement=e}}}},ge=ve,be=a(ge,fe,me,!1,null,null,null);be.options.__file=\"packages/dropdown/src/dropdown-menu.vue\";var ye=be.exports;ye.install=function(e){e.component(ye.name,ye)};var _e=ye,xe=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"li\",{staticClass:\"el-dropdown-menu__item\",class:{\"is-disabled\":e.disabled,\"el-dropdown-menu__item--divided\":e.divided},attrs:{\"aria-disabled\":e.disabled,tabindex:e.disabled?null:-1},on:{click:e.handleClick}},[e.icon?i(\"i\",{class:e.icon}):e._e(),e._t(\"default\")],2)},Ce=[];xe._withStripped=!0;var we={name:\"ElDropdownItem\",mixins:[E.a],props:{command:{},disabled:Boolean,divided:Boolean,icon:String},methods:{handleClick:function(e){this.dispatch(\"ElDropdown\",\"menu-item-click\",[this.command,this])}}},ke=we,Se=a(ke,xe,Ce,!1,null,null,null);Se.options.__file=\"packages/dropdown/src/dropdown-item.vue\";var $e=Se.exports;$e.install=function(e){e.component($e.name,$e)};var De=$e,Ee=Ee||{};Ee.Utils=Ee.Utils||{},Ee.Utils.focusFirstDescendant=function(e){for(var t=0;t<e.childNodes.length;t++){var i=e.childNodes[t];if(Ee.Utils.attemptFocus(i)||Ee.Utils.focusFirstDescendant(i))return!0}return!1},Ee.Utils.focusLastDescendant=function(e){for(var t=e.childNodes.length-1;t>=0;t--){var i=e.childNodes[t];if(Ee.Utils.attemptFocus(i)||Ee.Utils.focusLastDescendant(i))return!0}return!1},Ee.Utils.attemptFocus=function(e){if(!Ee.Utils.isFocusable(e))return!1;Ee.Utils.IgnoreUtilFocusChanges=!0;try{e.focus()}catch(t){}return Ee.Utils.IgnoreUtilFocusChanges=!1,document.activeElement===e},Ee.Utils.isFocusable=function(e){if(e.tabIndex>0||0===e.tabIndex&&null!==e.getAttribute(\"tabIndex\"))return!0;if(e.disabled)return!1;switch(e.nodeName){case\"A\":return!!e.href&&\"ignore\"!==e.rel;case\"INPUT\":return\"hidden\"!==e.type&&\"file\"!==e.type;case\"BUTTON\":case\"SELECT\":case\"TEXTAREA\":return!0;default:return!1}},Ee.Utils.triggerEvent=function(e,t){var i=void 0;i=/^mouse|click/.test(t)?\"MouseEvents\":/^key/.test(t)?\"KeyboardEvent\":\"HTMLEvents\";for(var n=document.createEvent(i),s=arguments.length,r=Array(s>2?s-2:0),o=2;o<s;o++)r[o-2]=arguments[o];return n.initEvent.apply(n,[t].concat(r)),e.dispatchEvent?e.dispatchEvent(n):e.fireEvent(\"on\"+t,n),e},Ee.Utils.keys={tab:9,enter:13,space:32,left:37,up:38,right:39,down:40};var Te=Ee.Utils,Oe=function(e,t){this.domNode=t,this.parent=e,this.subMenuItems=[],this.subIndex=0,this.init()};Oe.prototype.init=function(){this.subMenuItems=this.domNode.querySelectorAll(\"li\"),this.addListeners()},Oe.prototype.gotoSubIndex=function(e){e===this.subMenuItems.length?e=0:e<0&&(e=this.subMenuItems.length-1),this.subMenuItems[e].focus(),this.subIndex=e},Oe.prototype.addListeners=function(){var e=this,t=Te.keys,i=this.parent.domNode;Array.prototype.forEach.call(this.subMenuItems,function(n){n.addEventListener(\"keydown\",function(n){var s=!1;switch(n.keyCode){case t.down:e.gotoSubIndex(e.subIndex+1),s=!0;break;case t.up:e.gotoSubIndex(e.subIndex-1),s=!0;break;case t.tab:Te.triggerEvent(i,\"mouseleave\");break;case t.enter:case t.space:s=!0,n.currentTarget.click();break}return s&&(n.preventDefault(),n.stopPropagation()),!1})})};var Ie=Oe,Pe=function(e){this.domNode=e,this.submenu=null,this.init()};Pe.prototype.init=function(){this.domNode.setAttribute(\"tabindex\",\"0\");var e=this.domNode.querySelector(\".el-menu\");e&&(this.submenu=new Ie(this,e)),this.addListeners()},Pe.prototype.addListeners=function(){var e=this,t=Te.keys;this.domNode.addEventListener(\"keydown\",function(i){var n=!1;switch(i.keyCode){case t.down:Te.triggerEvent(i.currentTarget,\"mouseenter\"),e.submenu&&e.submenu.gotoSubIndex(0),n=!0;break;case t.up:Te.triggerEvent(i.currentTarget,\"mouseenter\"),e.submenu&&e.submenu.gotoSubIndex(e.submenu.subMenuItems.length-1),n=!0;break;case t.tab:Te.triggerEvent(i.currentTarget,\"mouseleave\");break;case t.enter:case t.space:n=!0,i.currentTarget.click();break}n&&i.preventDefault()})};var Me=Pe,Ne=function(e){this.domNode=e,this.init()};Ne.prototype.init=function(){var e=this.domNode.childNodes;[].filter.call(e,function(e){return 1===e.nodeType}).forEach(function(e){new Me(e)})};var Fe,Ae,Le=Ne,Ve=i(0),Be={name:\"ElMenu\",render:function(e){var t=e(\"ul\",{attrs:{role:\"menubar\"},key:+this.collapse,style:{backgroundColor:this.backgroundColor||\"\"},class:{\"el-menu--horizontal\":\"horizontal\"===this.mode,\"el-menu--collapse\":this.collapse,\"el-menu\":!0}},[this.$slots.default]);return this.collapseTransition?e(\"el-menu-collapse-transition\",[t]):t},componentName:\"ElMenu\",mixins:[E.a,$.a],provide:function(){return{rootMenu:this}},components:{\"el-menu-collapse-transition\":{functional:!0,render:function(e,t){var i={props:{mode:\"out-in\"},on:{beforeEnter:function(e){e.style.opacity=.2},enter:function(e){Object(Ve[\"addClass\"])(e,\"el-opacity-transition\"),e.style.opacity=1},afterEnter:function(e){Object(Ve[\"removeClass\"])(e,\"el-opacity-transition\"),e.style.opacity=\"\"},beforeLeave:function(e){e.dataset||(e.dataset={}),Object(Ve[\"hasClass\"])(e,\"el-menu--collapse\")?(Object(Ve[\"removeClass\"])(e,\"el-menu--collapse\"),e.dataset.oldOverflow=e.style.overflow,e.dataset.scrollWidth=e.clientWidth,Object(Ve[\"addClass\"])(e,\"el-menu--collapse\")):(Object(Ve[\"addClass\"])(e,\"el-menu--collapse\"),e.dataset.oldOverflow=e.style.overflow,e.dataset.scrollWidth=e.clientWidth,Object(Ve[\"removeClass\"])(e,\"el-menu--collapse\")),e.style.width=e.scrollWidth+\"px\",e.style.overflow=\"hidden\"},leave:function(e){Object(Ve[\"addClass\"])(e,\"horizontal-collapse-transition\"),e.style.width=e.dataset.scrollWidth+\"px\"}}};return e(\"transition\",i,t.children)}}},props:{mode:{type:String,default:\"vertical\"},defaultActive:{type:String,default:\"\"},defaultOpeneds:Array,uniqueOpened:Boolean,router:Boolean,menuTrigger:{type:String,default:\"hover\"},collapse:Boolean,backgroundColor:String,textColor:String,activeTextColor:String,collapseTransition:{type:Boolean,default:!0}},data:function(){return{activeIndex:this.defaultActive,openedMenus:this.defaultOpeneds&&!this.collapse?this.defaultOpeneds.slice(0):[],items:{},submenus:{}}},computed:{hoverBackground:function(){return this.backgroundColor?this.mixColor(this.backgroundColor,.2):\"\"},isMenuPopup:function(){return\"horizontal\"===this.mode||\"vertical\"===this.mode&&this.collapse}},watch:{defaultActive:\"updateActiveIndex\",defaultOpeneds:function(e){this.collapse||(this.openedMenus=e)},collapse:function(e){e&&(this.openedMenus=[]),this.broadcast(\"ElSubmenu\",\"toggle-collapse\",e)}},methods:{updateActiveIndex:function(e){var t=this.items[e]||this.items[this.activeIndex]||this.items[this.defaultActive];t?(this.activeIndex=t.index,this.initOpenedMenu()):this.activeIndex=null},getMigratingConfig:function(){return{props:{theme:\"theme is removed.\"}}},getColorChannels:function(e){if(e=e.replace(\"#\",\"\"),/^[0-9a-fA-F]{3}$/.test(e)){e=e.split(\"\");for(var t=2;t>=0;t--)e.splice(t,0,e[t]);e=e.join(\"\")}return/^[0-9a-fA-F]{6}$/.test(e)?{red:parseInt(e.slice(0,2),16),green:parseInt(e.slice(2,4),16),blue:parseInt(e.slice(4,6),16)}:{red:255,green:255,blue:255}},mixColor:function(e,t){var i=this.getColorChannels(e),n=i.red,s=i.green,r=i.blue;return t>0?(n*=1-t,s*=1-t,r*=1-t):(n+=(255-n)*t,s+=(255-s)*t,r+=(255-r)*t),\"rgb(\"+Math.round(n)+\", \"+Math.round(s)+\", \"+Math.round(r)+\")\"},addItem:function(e){this.$set(this.items,e.index,e)},removeItem:function(e){delete this.items[e.index]},addSubmenu:function(e){this.$set(this.submenus,e.index,e)},removeSubmenu:function(e){delete this.submenus[e.index]},openMenu:function(e,t){var i=this.openedMenus;-1===i.indexOf(e)&&(this.uniqueOpened&&(this.openedMenus=i.filter(function(e){return-1!==t.indexOf(e)})),this.openedMenus.push(e))},closeMenu:function(e){var t=this.openedMenus.indexOf(e);-1!==t&&this.openedMenus.splice(t,1)},handleSubmenuClick:function(e){var t=e.index,i=e.indexPath,n=-1!==this.openedMenus.indexOf(t);n?(this.closeMenu(t),this.$emit(\"close\",t,i)):(this.openMenu(t,i),this.$emit(\"open\",t,i))},handleItemClick:function(e){var t=this,i=e.index,n=e.indexPath,s=this.activeIndex,r=null!==e.index;r&&(this.activeIndex=e.index),this.$emit(\"select\",i,n,e),(\"horizontal\"===this.mode||this.collapse)&&(this.openedMenus=[]),this.router&&r&&this.routeToItem(e,function(e){t.activeIndex=s,e&&console.error(e)})},initOpenedMenu:function(){var e=this,t=this.activeIndex,i=this.items[t];if(i&&\"horizontal\"!==this.mode&&!this.collapse){var n=i.indexPath;n.forEach(function(t){var i=e.submenus[t];i&&e.openMenu(t,i.indexPath)})}},routeToItem:function(e,t){var i=e.route||e.index;try{this.$router.push(i,function(){},t)}catch(n){console.error(n)}},open:function(e){var t=this,i=this.submenus[e.toString()].indexPath;i.forEach(function(e){return t.openMenu(e,i)})},close:function(e){this.closeMenu(e)}},mounted:function(){this.initOpenedMenu(),this.$on(\"item-click\",this.handleItemClick),this.$on(\"submenu-click\",this.handleSubmenuClick),\"horizontal\"===this.mode&&new Le(this.$el),this.$watch(\"items\",this.updateActiveIndex)}},ze=Be,je=a(ze,Fe,Ae,!1,null,null,null);je.options.__file=\"packages/menu/src/menu.vue\";var He=je.exports;He.install=function(e){e.component(He.name,He)};var Re,We,qe=He,Ke=i(16),Ye=i.n(Ke),Ue={inject:[\"rootMenu\"],computed:{indexPath:function(){var e=[this.index],t=this.$parent;while(\"ElMenu\"!==t.$options.componentName)t.index&&e.unshift(t.index),t=t.$parent;return e},parentMenu:function(){var e=this.$parent;while(e&&-1===[\"ElMenu\",\"ElSubmenu\"].indexOf(e.$options.componentName))e=e.$parent;return e},paddingStyle:function(){if(\"vertical\"!==this.rootMenu.mode)return{};var e=20,t=this.$parent;if(this.rootMenu.collapse)e=20;else while(t&&\"ElMenu\"!==t.$options.componentName)\"ElSubmenu\"===t.$options.componentName&&(e+=20),t=t.$parent;return{paddingLeft:e+\"px\"}}}},Ge={props:{transformOrigin:{type:[Boolean,String],default:!1},offset:R.a.props.offset,boundariesPadding:R.a.props.boundariesPadding,popperOptions:R.a.props.popperOptions},data:R.a.data,methods:R.a.methods,beforeDestroy:R.a.beforeDestroy,deactivated:R.a.deactivated},Xe={name:\"ElSubmenu\",componentName:\"ElSubmenu\",mixins:[Ue,E.a,Ge],components:{ElCollapseTransition:Ye.a},props:{index:{type:String,required:!0},showTimeout:{type:Number,default:300},hideTimeout:{type:Number,default:300},popperClass:String,disabled:Boolean,popperAppendToBody:{type:Boolean,default:void 0}},data:function(){return{popperJS:null,timeout:null,items:{},submenus:{},mouseInChild:!1}},watch:{opened:function(e){var t=this;this.isMenuPopup&&this.$nextTick(function(e){t.updatePopper()})}},computed:{appendToBody:function(){return void 0===this.popperAppendToBody?this.isFirstLevel:this.popperAppendToBody},menuTransitionName:function(){return this.rootMenu.collapse?\"el-zoom-in-left\":\"el-zoom-in-top\"},opened:function(){return this.rootMenu.openedMenus.indexOf(this.index)>-1},active:function(){var e=!1,t=this.submenus,i=this.items;return Object.keys(i).forEach(function(t){i[t].active&&(e=!0)}),Object.keys(t).forEach(function(i){t[i].active&&(e=!0)}),e},hoverBackground:function(){return this.rootMenu.hoverBackground},backgroundColor:function(){return this.rootMenu.backgroundColor||\"\"},activeTextColor:function(){return this.rootMenu.activeTextColor||\"\"},textColor:function(){return this.rootMenu.textColor||\"\"},mode:function(){return this.rootMenu.mode},isMenuPopup:function(){return this.rootMenu.isMenuPopup},titleStyle:function(){return\"horizontal\"!==this.mode?{color:this.textColor}:{borderBottomColor:this.active?this.rootMenu.activeTextColor?this.activeTextColor:\"\":\"transparent\",color:this.active?this.activeTextColor:this.textColor}},isFirstLevel:function(){var e=!0,t=this.$parent;while(t&&t!==this.rootMenu){if([\"ElSubmenu\",\"ElMenuItemGroup\"].indexOf(t.$options.componentName)>-1){e=!1;break}t=t.$parent}return e}},methods:{handleCollapseToggle:function(e){e?this.initPopper():this.doDestroy()},addItem:function(e){this.$set(this.items,e.index,e)},removeItem:function(e){delete this.items[e.index]},addSubmenu:function(e){this.$set(this.submenus,e.index,e)},removeSubmenu:function(e){delete this.submenus[e.index]},handleClick:function(){var e=this.rootMenu,t=this.disabled;\"hover\"===e.menuTrigger&&\"horizontal\"===e.mode||e.collapse&&\"vertical\"===e.mode||t||this.dispatch(\"ElMenu\",\"submenu-click\",this)},handleMouseenter:function(e){var t=this,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.showTimeout;if(\"ActiveXObject\"in window||\"focus\"!==e.type||e.relatedTarget){var n=this.rootMenu,s=this.disabled;\"click\"===n.menuTrigger&&\"horizontal\"===n.mode||!n.collapse&&\"vertical\"===n.mode||s||(this.dispatch(\"ElSubmenu\",\"mouse-enter-child\"),clearTimeout(this.timeout),this.timeout=setTimeout(function(){t.rootMenu.openMenu(t.index,t.indexPath)},i))}},handleMouseleave:function(){var e=this,t=this.rootMenu;\"click\"===t.menuTrigger&&\"horizontal\"===t.mode||!t.collapse&&\"vertical\"===t.mode||(this.dispatch(\"ElSubmenu\",\"mouse-leave-child\"),clearTimeout(this.timeout),this.timeout=setTimeout(function(){!e.mouseInChild&&e.rootMenu.closeMenu(e.index)},this.hideTimeout))},handleTitleMouseenter:function(){if(\"horizontal\"!==this.mode||this.rootMenu.backgroundColor){var e=this.$refs[\"submenu-title\"];e&&(e.style.backgroundColor=this.rootMenu.hoverBackground)}},handleTitleMouseleave:function(){if(\"horizontal\"!==this.mode||this.rootMenu.backgroundColor){var e=this.$refs[\"submenu-title\"];e&&(e.style.backgroundColor=this.rootMenu.backgroundColor||\"\")}},updatePlacement:function(){this.currentPlacement=\"horizontal\"===this.mode&&this.isFirstLevel?\"bottom-start\":\"right-start\"},initPopper:function(){this.referenceElm=this.$el,this.popperElm=this.$refs.menu,this.updatePlacement()}},created:function(){var e=this;this.$on(\"toggle-collapse\",this.handleCollapseToggle),this.$on(\"mouse-enter-child\",function(){e.mouseInChild=!0,clearTimeout(e.timeout)}),this.$on(\"mouse-leave-child\",function(){e.mouseInChild=!1,clearTimeout(e.timeout)})},mounted:function(){this.parentMenu.addSubmenu(this),this.rootMenu.addSubmenu(this),this.initPopper()},beforeDestroy:function(){this.parentMenu.removeSubmenu(this),this.rootMenu.removeSubmenu(this)},render:function(e){var t=this,i=this.active,n=this.opened,s=this.paddingStyle,r=this.titleStyle,o=this.backgroundColor,a=this.rootMenu,l=this.currentPlacement,u=this.menuTransitionName,c=this.mode,h=this.disabled,d=this.popperClass,p=this.$slots,f=this.isFirstLevel,m=e(\"transition\",{attrs:{name:u}},[e(\"div\",{ref:\"menu\",directives:[{name:\"show\",value:n}],class:[\"el-menu--\"+c,d],on:{mouseenter:function(e){return t.handleMouseenter(e,100)},mouseleave:this.handleMouseleave,focus:function(e){return t.handleMouseenter(e,100)}}},[e(\"ul\",{attrs:{role:\"menu\"},class:[\"el-menu el-menu--popup\",\"el-menu--popup-\"+l],style:{backgroundColor:a.backgroundColor||\"\"}},[p.default])])]),v=e(\"el-collapse-transition\",[e(\"ul\",{attrs:{role:\"menu\"},class:\"el-menu el-menu--inline\",directives:[{name:\"show\",value:n}],style:{backgroundColor:a.backgroundColor||\"\"}},[p.default])]),g=\"horizontal\"===a.mode&&f||\"vertical\"===a.mode&&!a.collapse?\"el-icon-arrow-down\":\"el-icon-arrow-right\";return e(\"li\",{class:{\"el-submenu\":!0,\"is-active\":i,\"is-opened\":n,\"is-disabled\":h},attrs:{role:\"menuitem\",\"aria-haspopup\":\"true\",\"aria-expanded\":n},on:{mouseenter:this.handleMouseenter,mouseleave:this.handleMouseleave,focus:this.handleMouseenter}},[e(\"div\",{class:\"el-submenu__title\",ref:\"submenu-title\",on:{click:this.handleClick,mouseenter:this.handleTitleMouseenter,mouseleave:this.handleTitleMouseleave},style:[s,r,{backgroundColor:o}]},[p.title,e(\"i\",{class:[\"el-submenu__icon-arrow\",g]})]),this.isMenuPopup?m:v])}},Qe=Xe,Je=a(Qe,Re,We,!1,null,null,null);Je.options.__file=\"packages/menu/src/submenu.vue\";var Ze=Je.exports;Ze.install=function(e){e.component(Ze.name,Ze)};var et=Ze,tt=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"li\",{staticClass:\"el-menu-item\",class:{\"is-active\":e.active,\"is-disabled\":e.disabled},style:[e.paddingStyle,e.itemStyle,{backgroundColor:e.backgroundColor}],attrs:{role:\"menuitem\",tabindex:\"-1\"},on:{click:e.handleClick,mouseenter:e.onMouseEnter,focus:e.onMouseEnter,blur:e.onMouseLeave,mouseleave:e.onMouseLeave}},[\"ElMenu\"===e.parentMenu.$options.componentName&&e.rootMenu.collapse&&e.$slots.title?i(\"el-tooltip\",{attrs:{effect:\"dark\",placement:\"right\"}},[i(\"div\",{attrs:{slot:\"content\"},slot:\"content\"},[e._t(\"title\")],2),i(\"div\",{staticStyle:{position:\"absolute\",left:\"0\",top:\"0\",height:\"100%\",width:\"100%\",display:\"inline-block\",\"box-sizing\":\"border-box\",padding:\"0 20px\"}},[e._t(\"default\")],2)]):[e._t(\"default\"),e._t(\"title\")]],2)},it=[];tt._withStripped=!0;var nt=i(20),st=i.n(nt),rt={name:\"ElMenuItem\",componentName:\"ElMenuItem\",mixins:[Ue,E.a],components:{ElTooltip:st.a},props:{index:{default:null,validator:function(e){return\"string\"===typeof e||null===e}},route:[String,Object],disabled:Boolean},computed:{active:function(){return this.index===this.rootMenu.activeIndex},hoverBackground:function(){return this.rootMenu.hoverBackground},backgroundColor:function(){return this.rootMenu.backgroundColor||\"\"},activeTextColor:function(){return this.rootMenu.activeTextColor||\"\"},textColor:function(){return this.rootMenu.textColor||\"\"},mode:function(){return this.rootMenu.mode},itemStyle:function(){var e={color:this.active?this.activeTextColor:this.textColor};return\"horizontal\"!==this.mode||this.isNested||(e.borderBottomColor=this.active?this.rootMenu.activeTextColor?this.activeTextColor:\"\":\"transparent\"),e},isNested:function(){return this.parentMenu!==this.rootMenu}},methods:{onMouseEnter:function(){(\"horizontal\"!==this.mode||this.rootMenu.backgroundColor)&&(this.$el.style.backgroundColor=this.hoverBackground)},onMouseLeave:function(){(\"horizontal\"!==this.mode||this.rootMenu.backgroundColor)&&(this.$el.style.backgroundColor=this.backgroundColor)},handleClick:function(){this.disabled||(this.dispatch(\"ElMenu\",\"item-click\",this),this.$emit(\"click\",this))}},mounted:function(){this.parentMenu.addItem(this),this.rootMenu.addItem(this)},beforeDestroy:function(){this.parentMenu.removeItem(this),this.rootMenu.removeItem(this)}},ot=rt,at=a(ot,tt,it,!1,null,null,null);at.options.__file=\"packages/menu/src/menu-item.vue\";var lt=at.exports;lt.install=function(e){e.component(lt.name,lt)};var ut=lt,ct=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"li\",{staticClass:\"el-menu-item-group\"},[i(\"div\",{staticClass:\"el-menu-item-group__title\",style:{paddingLeft:e.levelPadding+\"px\"}},[e.$slots.title?e._t(\"title\"):[e._v(e._s(e.title))]],2),i(\"ul\",[e._t(\"default\")],2)])},ht=[];ct._withStripped=!0;var dt={name:\"ElMenuItemGroup\",componentName:\"ElMenuItemGroup\",inject:[\"rootMenu\"],props:{title:{type:String}},data:function(){return{paddingLeft:20}},computed:{levelPadding:function(){var e=20,t=this.$parent;if(this.rootMenu.collapse)return 20;while(t&&\"ElMenu\"!==t.$options.componentName)\"ElSubmenu\"===t.$options.componentName&&(e+=20),t=t.$parent;return e}}},pt=dt,ft=a(pt,ct,ht,!1,null,null,null);ft.options.__file=\"packages/menu/src/menu-item-group.vue\";var mt=ft.exports;mt.install=function(e){e.component(mt.name,mt)};var vt=mt,gt=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{class:[\"textarea\"===e.type?\"el-textarea\":\"el-input\",e.inputSize?\"el-input--\"+e.inputSize:\"\",{\"is-disabled\":e.inputDisabled,\"el-input-group\":e.$slots.prepend||e.$slots.append,\"el-input-group--append\":e.$slots.append,\"el-input-group--prepend\":e.$slots.prepend,\"el-input--prefix\":e.$slots.prefix||e.prefixIcon,\"el-input--suffix\":e.$slots.suffix||e.suffixIcon||e.clearable||e.showPassword}],on:{mouseenter:function(t){e.hovering=!0},mouseleave:function(t){e.hovering=!1}}},[\"textarea\"!==e.type?[e.$slots.prepend?i(\"div\",{staticClass:\"el-input-group__prepend\"},[e._t(\"prepend\")],2):e._e(),\"textarea\"!==e.type?i(\"input\",e._b({ref:\"input\",staticClass:\"el-input__inner\",attrs:{tabindex:e.tabindex,type:e.showPassword?e.passwordVisible?\"text\":\"password\":e.type,disabled:e.inputDisabled,readonly:e.readonly,autocomplete:e.autoComplete||e.autocomplete,\"aria-label\":e.label},on:{compositionstart:e.handleCompositionStart,compositionend:e.handleCompositionEnd,input:e.handleInput,focus:e.handleFocus,blur:e.handleBlur,change:e.handleChange}},\"input\",e.$attrs,!1)):e._e(),e.$slots.prefix||e.prefixIcon?i(\"span\",{staticClass:\"el-input__prefix\"},[e._t(\"prefix\"),e.prefixIcon?i(\"i\",{staticClass:\"el-input__icon\",class:e.prefixIcon}):e._e()],2):e._e(),e.$slots.suffix||e.suffixIcon||e.showClear||e.showPassword||e.validateState&&e.needStatusIcon?i(\"span\",{staticClass:\"el-input__suffix\"},[i(\"span\",{staticClass:\"el-input__suffix-inner\"},[e.showClear&&e.showPwdVisible?e._e():[e._t(\"suffix\"),e.suffixIcon?i(\"i\",{staticClass:\"el-input__icon\",class:e.suffixIcon}):e._e()],e.showClear?i(\"i\",{staticClass:\"el-input__icon el-icon-circle-close el-input__clear\",on:{click:e.clear}}):e._e(),e.showPwdVisible?i(\"i\",{staticClass:\"el-input__icon el-icon-view el-input__clear\",on:{click:e.handlePasswordVisible}}):e._e()],2),e.validateState?i(\"i\",{staticClass:\"el-input__icon\",class:[\"el-input__validateIcon\",e.validateIcon]}):e._e()]):e._e(),e.$slots.append?i(\"div\",{staticClass:\"el-input-group__append\"},[e._t(\"append\")],2):e._e()]:i(\"textarea\",e._b({ref:\"textarea\",staticClass:\"el-textarea__inner\",style:e.textareaStyle,attrs:{tabindex:e.tabindex,disabled:e.inputDisabled,readonly:e.readonly,autocomplete:e.autoComplete||e.autocomplete,\"aria-label\":e.label},on:{compositionstart:e.handleCompositionStart,compositionend:e.handleCompositionEnd,input:e.handleInput,focus:e.handleFocus,blur:e.handleBlur,change:e.handleChange}},\"textarea\",e.$attrs,!1))],2)},bt=[];gt._withStripped=!0;var yt=void 0,_t=\"\\n  height:0 !important;\\n  visibility:hidden !important;\\n  overflow:hidden !important;\\n  position:absolute !important;\\n  z-index:-1000 !important;\\n  top:0 !important;\\n  right:0 !important\\n\",xt=[\"letter-spacing\",\"line-height\",\"padding-top\",\"padding-bottom\",\"font-family\",\"font-weight\",\"font-size\",\"text-rendering\",\"text-transform\",\"width\",\"text-indent\",\"padding-left\",\"padding-right\",\"border-width\",\"box-sizing\"];function Ct(e){var t=window.getComputedStyle(e),i=t.getPropertyValue(\"box-sizing\"),n=parseFloat(t.getPropertyValue(\"padding-bottom\"))+parseFloat(t.getPropertyValue(\"padding-top\")),s=parseFloat(t.getPropertyValue(\"border-bottom-width\"))+parseFloat(t.getPropertyValue(\"border-top-width\")),r=xt.map(function(e){return e+\":\"+t.getPropertyValue(e)}).join(\";\");return{contextStyle:r,paddingSize:n,borderSize:s,boxSizing:i}}function wt(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;yt||(yt=document.createElement(\"textarea\"),document.body.appendChild(yt));var n=Ct(e),s=n.paddingSize,r=n.borderSize,o=n.boxSizing,a=n.contextStyle;yt.setAttribute(\"style\",a+\";\"+_t),yt.value=e.value||e.placeholder||\"\";var l=yt.scrollHeight,u={};\"border-box\"===o?l+=r:\"content-box\"===o&&(l-=s),yt.value=\"\";var c=yt.scrollHeight-s;if(null!==t){var h=c*t;\"border-box\"===o&&(h=h+s+r),l=Math.max(h,l),u.minHeight=h+\"px\"}if(null!==i){var d=c*i;\"border-box\"===o&&(d=d+s+r),l=Math.min(d,l)}return u.height=l+\"px\",yt.parentNode&&yt.parentNode.removeChild(yt),yt=null,u}var kt=i(6),St=i.n(kt),$t={name:\"ElInput\",componentName:\"ElInput\",mixins:[E.a,$.a],inheritAttrs:!1,inject:{elForm:{default:\"\"},elFormItem:{default:\"\"}},data:function(){return{textareaCalcStyle:{},hovering:!1,focused:!1,isComposing:!1,passwordVisible:!1}},props:{value:[String,Number],size:String,resize:String,form:String,disabled:Boolean,readonly:Boolean,type:{type:String,default:\"text\"},autosize:{type:[Boolean,Object],default:!1},autocomplete:{type:String,default:\"off\"},autoComplete:{type:String,validator:function(e){return!0}},validateEvent:{type:Boolean,default:!0},suffixIcon:String,prefixIcon:String,label:String,clearable:{type:Boolean,default:!1},showPassword:{type:Boolean,default:!1},tabindex:String},computed:{_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},validateState:function(){return this.elFormItem?this.elFormItem.validateState:\"\"},needStatusIcon:function(){return!!this.elForm&&this.elForm.statusIcon},validateIcon:function(){return{validating:\"el-icon-loading\",success:\"el-icon-circle-check\",error:\"el-icon-circle-close\"}[this.validateState]},textareaStyle:function(){return St()({},this.textareaCalcStyle,{resize:this.resize})},inputSize:function(){return this.size||this._elFormItemSize||(this.$ELEMENT||{}).size},inputDisabled:function(){return this.disabled||(this.elForm||{}).disabled},nativeInputValue:function(){return null===this.value||void 0===this.value?\"\":String(this.value)},showClear:function(){return this.clearable&&!this.inputDisabled&&!this.readonly&&this.nativeInputValue&&(this.focused||this.hovering)},showPwdVisible:function(){return this.showPassword&&!this.inputDisabled&&!this.readonly&&(!!this.nativeInputValue||this.focused)}},watch:{value:function(e){this.$nextTick(this.resizeTextarea),this.validateEvent&&this.dispatch(\"ElFormItem\",\"el.form.change\",[e])},nativeInputValue:function(){this.setNativeInputValue()},type:function(){var e=this;this.$nextTick(function(){e.setNativeInputValue(),e.resizeTextarea(),e.updateIconOffset()})}},methods:{focus:function(){this.getInput().focus()},blur:function(){this.getInput().blur()},getMigratingConfig:function(){return{props:{icon:\"icon is removed, use suffix-icon / prefix-icon instead.\",\"on-icon-click\":\"on-icon-click is removed.\"},events:{click:\"click is removed.\"}}},handleBlur:function(e){this.focused=!1,this.$emit(\"blur\",e),this.validateEvent&&this.dispatch(\"ElFormItem\",\"el.form.blur\",[this.value])},select:function(){this.getInput().select()},resizeTextarea:function(){if(!this.$isServer){var e=this.autosize,t=this.type;if(\"textarea\"===t)if(e){var i=e.minRows,n=e.maxRows;this.textareaCalcStyle=wt(this.$refs.textarea,i,n)}else this.textareaCalcStyle={minHeight:wt(this.$refs.textarea).minHeight}}},setNativeInputValue:function(){var e=this.getInput();e&&e.value!==this.nativeInputValue&&(e.value=this.nativeInputValue)},handleFocus:function(e){this.focused=!0,this.$emit(\"focus\",e)},handleCompositionStart:function(){this.isComposing=!0},handleCompositionEnd:function(e){this.isComposing=!1,this.handleInput(e)},handleInput:function(e){this.isComposing||e.target.value!==this.nativeInputValue&&(this.$emit(\"input\",e.target.value),this.$nextTick(this.setNativeInputValue))},handleChange:function(e){this.$emit(\"change\",e.target.value)},calcIconOffset:function(e){var t=[].slice.call(this.$el.querySelectorAll(\".el-input__\"+e)||[]);if(t.length){for(var i=null,n=0;n<t.length;n++)if(t[n].parentNode===this.$el){i=t[n];break}if(i){var s={suffix:\"append\",prefix:\"prepend\"},r=s[e];this.$slots[r]?i.style.transform=\"translateX(\"+(\"suffix\"===e?\"-\":\"\")+this.$el.querySelector(\".el-input-group__\"+r).offsetWidth+\"px)\":i.removeAttribute(\"style\")}}},updateIconOffset:function(){this.calcIconOffset(\"prefix\"),this.calcIconOffset(\"suffix\")},clear:function(){this.$emit(\"input\",\"\"),this.$emit(\"change\",\"\"),this.$emit(\"clear\")},handlePasswordVisible:function(){this.passwordVisible=!this.passwordVisible,this.focus()},getInput:function(){return this.$refs.input||this.$refs.textarea}},created:function(){this.$on(\"inputSelect\",this.select)},mounted:function(){this.setNativeInputValue(),this.resizeTextarea(),this.updateIconOffset()},updated:function(){this.$nextTick(this.updateIconOffset)}},Dt=$t,Et=a(Dt,gt,bt,!1,null,null,null);Et.options.__file=\"packages/input/src/input.vue\";var Tt=Et.exports;Tt.install=function(e){e.component(Tt.name,Tt)};var Ot=Tt,It=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{class:[\"el-input-number\",e.inputNumberSize?\"el-input-number--\"+e.inputNumberSize:\"\",{\"is-disabled\":e.inputNumberDisabled},{\"is-without-controls\":!e.controls},{\"is-controls-right\":e.controlsAtRight}],on:{dragstart:function(e){e.preventDefault()}}},[e.controls?i(\"span\",{directives:[{name:\"repeat-click\",rawName:\"v-repeat-click\",value:e.decrease,expression:\"decrease\"}],staticClass:\"el-input-number__decrease\",class:{\"is-disabled\":e.minDisabled},attrs:{role:\"button\"},on:{keydown:function(t){return\"button\"in t||!e._k(t.keyCode,\"enter\",13,t.key,\"Enter\")?e.decrease(t):null}}},[i(\"i\",{class:\"el-icon-\"+(e.controlsAtRight?\"arrow-down\":\"minus\")})]):e._e(),e.controls?i(\"span\",{directives:[{name:\"repeat-click\",rawName:\"v-repeat-click\",value:e.increase,expression:\"increase\"}],staticClass:\"el-input-number__increase\",class:{\"is-disabled\":e.maxDisabled},attrs:{role:\"button\"},on:{keydown:function(t){return\"button\"in t||!e._k(t.keyCode,\"enter\",13,t.key,\"Enter\")?e.increase(t):null}}},[i(\"i\",{class:\"el-icon-\"+(e.controlsAtRight?\"arrow-up\":\"plus\")})]):e._e(),i(\"el-input\",{ref:\"input\",attrs:{value:e.displayValue,placeholder:e.placeholder,disabled:e.inputNumberDisabled,size:e.inputNumberSize,max:e.max,min:e.min,name:e.name,label:e.label},on:{blur:e.handleBlur,focus:e.handleFocus,input:e.handleInput,change:e.handleInputChange},nativeOn:{keydown:[function(t){return\"button\"in t||!e._k(t.keyCode,\"up\",38,t.key,[\"Up\",\"ArrowUp\"])?(t.preventDefault(),e.increase(t)):null},function(t){return\"button\"in t||!e._k(t.keyCode,\"down\",40,t.key,[\"Down\",\"ArrowDown\"])?(t.preventDefault(),e.decrease(t)):null}]}})],1)},Pt=[];It._withStripped=!0;var Mt={bind:function(e,t,i){var n=null,s=void 0,r=function(){return i.context[t.expression].apply()},o=function(){new Date-s<100&&r(),clearInterval(n),n=null};Object(Ve[\"on\"])(e,\"mousedown\",function(e){0===e.button&&(s=new Date,Object(Ve[\"once\"])(document,\"mouseup\",o),clearInterval(n),n=setInterval(r,100))})}},Nt={name:\"ElInputNumber\",mixins:[Q()(\"input\")],inject:{elForm:{default:\"\"},elFormItem:{default:\"\"}},directives:{repeatClick:Mt},components:{ElInput:m.a},props:{step:{type:Number,default:1},max:{type:Number,default:1/0},min:{type:Number,default:-1/0},value:{},disabled:Boolean,size:String,controls:{type:Boolean,default:!0},controlsPosition:{type:String,default:\"\"},name:String,label:String,placeholder:String,precision:{type:Number,validator:function(e){return e>=0&&e===parseInt(e,10)}}},data:function(){return{currentValue:0,userInput:null}},watch:{value:{immediate:!0,handler:function(e){var t=void 0===e?e:Number(e);if(void 0!==t){if(isNaN(t))return;void 0!==this.precision&&(t=this.toPrecision(t,this.precision))}t>=this.max&&(t=this.max),t<=this.min&&(t=this.min),this.currentValue=t,this.userInput=null,this.$emit(\"input\",t)}}},computed:{minDisabled:function(){return this._decrease(this.value,this.step)<this.min},maxDisabled:function(){return this._increase(this.value,this.step)>this.max},numPrecision:function(){var e=this.value,t=this.step,i=this.getPrecision,n=this.precision,s=i(t);return void 0!==n?(s>n&&console.warn(\"[Element Warn][InputNumber]precision should not be less than the decimal places of step\"),n):Math.max(i(e),s)},controlsAtRight:function(){return this.controls&&\"right\"===this.controlsPosition},_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},inputNumberSize:function(){return this.size||this._elFormItemSize||(this.$ELEMENT||{}).size},inputNumberDisabled:function(){return this.disabled||(this.elForm||{}).disabled},displayValue:function(){if(null!==this.userInput)return this.userInput;var e=this.currentValue;return\"number\"===typeof e&&void 0!==this.precision?e.toFixed(this.precision):e}},methods:{toPrecision:function(e,t){return void 0===t&&(t=this.numPrecision),parseFloat(Number(e).toFixed(t))},getPrecision:function(e){if(void 0===e)return 0;var t=e.toString(),i=t.indexOf(\".\"),n=0;return-1!==i&&(n=t.length-i-1),n},_increase:function(e,t){if(\"number\"!==typeof e&&void 0!==e)return this.currentValue;var i=Math.pow(10,this.numPrecision);return this.toPrecision((i*e+i*t)/i)},_decrease:function(e,t){if(\"number\"!==typeof e&&void 0!==e)return this.currentValue;var i=Math.pow(10,this.numPrecision);return this.toPrecision((i*e-i*t)/i)},increase:function(){if(!this.inputNumberDisabled&&!this.maxDisabled){var e=this.value||0,t=this._increase(e,this.step);this.setCurrentValue(t)}},decrease:function(){if(!this.inputNumberDisabled&&!this.minDisabled){var e=this.value||0,t=this._decrease(e,this.step);this.setCurrentValue(t)}},handleBlur:function(e){this.$emit(\"blur\",e)},handleFocus:function(e){this.$emit(\"focus\",e)},setCurrentValue:function(e){var t=this.currentValue;\"number\"===typeof e&&void 0!==this.precision&&(e=this.toPrecision(e,this.precision)),e>=this.max&&(e=this.max),e<=this.min&&(e=this.min),t!==e&&(this.userInput=null,this.$emit(\"input\",e),this.$emit(\"change\",e,t),this.currentValue=e)},handleInput:function(e){this.userInput=e},handleInputChange:function(e){var t=\"\"===e?void 0:Number(e);isNaN(t)&&\"\"!==e||this.setCurrentValue(t),this.userInput=null},select:function(){this.$refs.input.select()}},mounted:function(){var e=this.$refs.input.$refs.input;e.setAttribute(\"role\",\"spinbutton\"),e.setAttribute(\"aria-valuemax\",this.max),e.setAttribute(\"aria-valuemin\",this.min),e.setAttribute(\"aria-valuenow\",this.currentValue),e.setAttribute(\"aria-disabled\",this.inputNumberDisabled)},updated:function(){if(this.$refs&&this.$refs.input){var e=this.$refs.input.$refs.input;e.setAttribute(\"aria-valuenow\",this.currentValue)}}},Ft=Nt,At=a(Ft,It,Pt,!1,null,null,null);At.options.__file=\"packages/input-number/src/input-number.vue\";var Lt=At.exports;Lt.install=function(e){e.component(Lt.name,Lt)};var Vt=Lt,Bt=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"label\",{staticClass:\"el-radio\",class:[e.border&&e.radioSize?\"el-radio--\"+e.radioSize:\"\",{\"is-disabled\":e.isDisabled},{\"is-focus\":e.focus},{\"is-bordered\":e.border},{\"is-checked\":e.model===e.label}],attrs:{role:\"radio\",\"aria-checked\":e.model===e.label,\"aria-disabled\":e.isDisabled,tabindex:e.tabIndex},on:{keydown:function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"space\",32,t.key,[\" \",\"Spacebar\"]))return null;t.stopPropagation(),t.preventDefault(),e.model=e.isDisabled?e.model:e.label}}},[i(\"span\",{staticClass:\"el-radio__input\",class:{\"is-disabled\":e.isDisabled,\"is-checked\":e.model===e.label}},[i(\"span\",{staticClass:\"el-radio__inner\"}),i(\"input\",{directives:[{name:\"model\",rawName:\"v-model\",value:e.model,expression:\"model\"}],staticClass:\"el-radio__original\",attrs:{type:\"radio\",\"aria-hidden\":\"true\",name:e.name,disabled:e.isDisabled,tabindex:\"-1\"},domProps:{value:e.label,checked:e._q(e.model,e.label)},on:{focus:function(t){e.focus=!0},blur:function(t){e.focus=!1},change:[function(t){e.model=e.label},e.handleChange]}})]),i(\"span\",{staticClass:\"el-radio__label\",on:{keydown:function(e){e.stopPropagation()}}},[e._t(\"default\"),e.$slots.default?e._e():[e._v(e._s(e.label))]],2)])},zt=[];Bt._withStripped=!0;var jt={name:\"ElRadio\",mixins:[E.a],inject:{elForm:{default:\"\"},elFormItem:{default:\"\"}},componentName:\"ElRadio\",props:{value:{},label:{},disabled:Boolean,name:String,border:Boolean,size:String},data:function(){return{focus:!1}},computed:{isGroup:function(){var e=this.$parent;while(e){if(\"ElRadioGroup\"===e.$options.componentName)return this._radioGroup=e,!0;e=e.$parent}return!1},model:{get:function(){return this.isGroup?this._radioGroup.value:this.value},set:function(e){this.isGroup?this.dispatch(\"ElRadioGroup\",\"input\",[e]):this.$emit(\"input\",e)}},_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},radioSize:function(){var e=this.size||this._elFormItemSize||(this.$ELEMENT||{}).size;return this.isGroup&&this._radioGroup.radioGroupSize||e},isDisabled:function(){return this.isGroup?this._radioGroup.disabled||this.disabled||(this.elForm||{}).disabled:this.disabled||(this.elForm||{}).disabled},tabIndex:function(){return this.isDisabled||this.isGroup&&this.model!==this.label?-1:0}},methods:{handleChange:function(){var e=this;this.$nextTick(function(){e.$emit(\"change\",e.model),e.isGroup&&e.dispatch(\"ElRadioGroup\",\"handleChange\",e.model)})}}},Ht=jt,Rt=a(Ht,Bt,zt,!1,null,null,null);Rt.options.__file=\"packages/radio/src/radio.vue\";var Wt=Rt.exports;Wt.install=function(e){e.component(Wt.name,Wt)};var qt=Wt,Kt=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-radio-group\",attrs:{role:\"radiogroup\"},on:{keydown:e.handleKeydown}},[e._t(\"default\")],2)},Yt=[];Kt._withStripped=!0;var Ut=Object.freeze({LEFT:37,UP:38,RIGHT:39,DOWN:40}),Gt={name:\"ElRadioGroup\",componentName:\"ElRadioGroup\",inject:{elFormItem:{default:\"\"}},mixins:[E.a],props:{value:{},size:String,fill:String,textColor:String,disabled:Boolean},computed:{_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},radioGroupSize:function(){return this.size||this._elFormItemSize||(this.$ELEMENT||{}).size}},created:function(){var e=this;this.$on(\"handleChange\",function(t){e.$emit(\"change\",t)})},mounted:function(){var e=this.$el.querySelectorAll(\"[type=radio]\"),t=this.$el.querySelectorAll(\"[role=radio]\")[0];![].some.call(e,function(e){return e.checked})&&t&&(t.tabIndex=0)},methods:{handleKeydown:function(e){var t=e.target,i=\"INPUT\"===t.nodeName?\"[type=radio]\":\"[role=radio]\",n=this.$el.querySelectorAll(i),s=n.length,r=[].indexOf.call(n,t),o=this.$el.querySelectorAll(\"[role=radio]\");switch(e.keyCode){case Ut.LEFT:case Ut.UP:e.stopPropagation(),e.preventDefault(),0===r?(o[s-1].click(),o[s-1].focus()):(o[r-1].click(),o[r-1].focus());break;case Ut.RIGHT:case Ut.DOWN:r===s-1?(e.stopPropagation(),e.preventDefault(),o[0].click(),o[0].focus()):(o[r+1].click(),o[r+1].focus());break;default:break}}},watch:{value:function(e){this.dispatch(\"ElFormItem\",\"el.form.change\",[this.value])}}},Xt=Gt,Qt=a(Xt,Kt,Yt,!1,null,null,null);Qt.options.__file=\"packages/radio/src/radio-group.vue\";var Jt=Qt.exports;Jt.install=function(e){e.component(Jt.name,Jt)};var Zt=Jt,ei=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"label\",{staticClass:\"el-radio-button\",class:[e.size?\"el-radio-button--\"+e.size:\"\",{\"is-active\":e.value===e.label},{\"is-disabled\":e.isDisabled},{\"is-focus\":e.focus}],attrs:{role:\"radio\",\"aria-checked\":e.value===e.label,\"aria-disabled\":e.isDisabled,tabindex:e.tabIndex},on:{keydown:function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"space\",32,t.key,[\" \",\"Spacebar\"]))return null;t.stopPropagation(),t.preventDefault(),e.value=e.isDisabled?e.value:e.label}}},[i(\"input\",{directives:[{name:\"model\",rawName:\"v-model\",value:e.value,expression:\"value\"}],staticClass:\"el-radio-button__orig-radio\",attrs:{type:\"radio\",name:e.name,disabled:e.isDisabled,tabindex:\"-1\"},domProps:{value:e.label,checked:e._q(e.value,e.label)},on:{change:[function(t){e.value=e.label},e.handleChange],focus:function(t){e.focus=!0},blur:function(t){e.focus=!1}}}),i(\"span\",{staticClass:\"el-radio-button__inner\",style:e.value===e.label?e.activeStyle:null,on:{keydown:function(e){e.stopPropagation()}}},[e._t(\"default\"),e.$slots.default?e._e():[e._v(e._s(e.label))]],2)])},ti=[];ei._withStripped=!0;var ii={name:\"ElRadioButton\",mixins:[E.a],inject:{elForm:{default:\"\"},elFormItem:{default:\"\"}},props:{label:{},disabled:Boolean,name:String},data:function(){return{focus:!1}},computed:{value:{get:function(){return this._radioGroup.value},set:function(e){this._radioGroup.$emit(\"input\",e)}},_radioGroup:function(){var e=this.$parent;while(e){if(\"ElRadioGroup\"===e.$options.componentName)return e;e=e.$parent}return!1},activeStyle:function(){return{backgroundColor:this._radioGroup.fill||\"\",borderColor:this._radioGroup.fill||\"\",boxShadow:this._radioGroup.fill?\"-1px 0 0 0 \"+this._radioGroup.fill:\"\",color:this._radioGroup.textColor||\"\"}},_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},size:function(){return this._radioGroup.radioGroupSize||this._elFormItemSize||(this.$ELEMENT||{}).size},isDisabled:function(){return this.disabled||this._radioGroup.disabled||(this.elForm||{}).disabled},tabIndex:function(){return this.isDisabled||this._radioGroup&&this.value!==this.label?-1:0}},methods:{handleChange:function(){var e=this;this.$nextTick(function(){e.dispatch(\"ElRadioGroup\",\"handleChange\",e.value)})}}},ni=ii,si=a(ni,ei,ti,!1,null,null,null);si.options.__file=\"packages/radio/src/radio-button.vue\";var ri=si.exports;ri.install=function(e){e.component(ri.name,ri)};var oi=ri,ai=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"label\",{staticClass:\"el-checkbox\",class:[e.border&&e.checkboxSize?\"el-checkbox--\"+e.checkboxSize:\"\",{\"is-disabled\":e.isDisabled},{\"is-bordered\":e.border},{\"is-checked\":e.isChecked}],attrs:{role:\"checkbox\",\"aria-checked\":e.indeterminate?\"mixed\":e.isChecked,\"aria-disabled\":e.isDisabled,id:e.id}},[i(\"span\",{staticClass:\"el-checkbox__input\",class:{\"is-disabled\":e.isDisabled,\"is-checked\":e.isChecked,\"is-indeterminate\":e.indeterminate,\"is-focus\":e.focus},attrs:{\"aria-checked\":\"mixed\"}},[i(\"span\",{staticClass:\"el-checkbox__inner\"}),e.trueLabel||e.falseLabel?i(\"input\",{directives:[{name:\"model\",rawName:\"v-model\",value:e.model,expression:\"model\"}],staticClass:\"el-checkbox__original\",attrs:{type:\"checkbox\",\"aria-hidden\":\"true\",name:e.name,disabled:e.isDisabled,\"true-value\":e.trueLabel,\"false-value\":e.falseLabel},domProps:{checked:Array.isArray(e.model)?e._i(e.model,null)>-1:e._q(e.model,e.trueLabel)},on:{change:[function(t){var i=e.model,n=t.target,s=n.checked?e.trueLabel:e.falseLabel;if(Array.isArray(i)){var r=null,o=e._i(i,r);n.checked?o<0&&(e.model=i.concat([r])):o>-1&&(e.model=i.slice(0,o).concat(i.slice(o+1)))}else e.model=s},e.handleChange],focus:function(t){e.focus=!0},blur:function(t){e.focus=!1}}}):i(\"input\",{directives:[{name:\"model\",rawName:\"v-model\",value:e.model,expression:\"model\"}],staticClass:\"el-checkbox__original\",attrs:{type:\"checkbox\",\"aria-hidden\":\"true\",disabled:e.isDisabled,name:e.name},domProps:{value:e.label,checked:Array.isArray(e.model)?e._i(e.model,e.label)>-1:e.model},on:{change:[function(t){var i=e.model,n=t.target,s=!!n.checked;if(Array.isArray(i)){var r=e.label,o=e._i(i,r);n.checked?o<0&&(e.model=i.concat([r])):o>-1&&(e.model=i.slice(0,o).concat(i.slice(o+1)))}else e.model=s},e.handleChange],focus:function(t){e.focus=!0},blur:function(t){e.focus=!1}}})]),e.$slots.default||e.label?i(\"span\",{staticClass:\"el-checkbox__label\"},[e._t(\"default\"),e.$slots.default?e._e():[e._v(e._s(e.label))]],2):e._e()])},li=[];ai._withStripped=!0;var ui={name:\"ElCheckbox\",mixins:[E.a],inject:{elForm:{default:\"\"},elFormItem:{default:\"\"}},componentName:\"ElCheckbox\",data:function(){return{selfModel:!1,focus:!1,isLimitExceeded:!1}},computed:{model:{get:function(){return this.isGroup?this.store:void 0!==this.value?this.value:this.selfModel},set:function(e){this.isGroup?(this.isLimitExceeded=!1,void 0!==this._checkboxGroup.min&&e.length<this._checkboxGroup.min&&(this.isLimitExceeded=!0),void 0!==this._checkboxGroup.max&&e.length>this._checkboxGroup.max&&(this.isLimitExceeded=!0),!1===this.isLimitExceeded&&this.dispatch(\"ElCheckboxGroup\",\"input\",[e])):(this.$emit(\"input\",e),this.selfModel=e)}},isChecked:function(){return\"[object Boolean]\"==={}.toString.call(this.model)?this.model:Array.isArray(this.model)?this.model.indexOf(this.label)>-1:null!==this.model&&void 0!==this.model?this.model===this.trueLabel:void 0},isGroup:function(){var e=this.$parent;while(e){if(\"ElCheckboxGroup\"===e.$options.componentName)return this._checkboxGroup=e,!0;e=e.$parent}return!1},store:function(){return this._checkboxGroup?this._checkboxGroup.value:this.value},isDisabled:function(){return this.isGroup?this._checkboxGroup.disabled||this.disabled||(this.elForm||{}).disabled:this.disabled||(this.elForm||{}).disabled},_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},checkboxSize:function(){var e=this.size||this._elFormItemSize||(this.$ELEMENT||{}).size;return this.isGroup&&this._checkboxGroup.checkboxGroupSize||e}},props:{value:{},label:{},indeterminate:Boolean,disabled:Boolean,checked:Boolean,name:String,trueLabel:[String,Number],falseLabel:[String,Number],id:String,controls:String,border:Boolean,size:String},methods:{addToStore:function(){Array.isArray(this.model)&&-1===this.model.indexOf(this.label)?this.model.push(this.label):this.model=this.trueLabel||!0},handleChange:function(e){var t=this;if(!this.isLimitExceeded){var i=void 0;i=e.target.checked?void 0===this.trueLabel||this.trueLabel:void 0!==this.falseLabel&&this.falseLabel,this.$emit(\"change\",i,e),this.$nextTick(function(){t.isGroup&&t.dispatch(\"ElCheckboxGroup\",\"change\",[t._checkboxGroup.value])})}}},created:function(){this.checked&&this.addToStore()},mounted:function(){this.indeterminate&&this.$el.setAttribute(\"aria-controls\",this.controls)},watch:{value:function(e){this.dispatch(\"ElFormItem\",\"el.form.change\",e)}}},ci=ui,hi=a(ci,ai,li,!1,null,null,null);hi.options.__file=\"packages/checkbox/src/checkbox.vue\";var di=hi.exports;di.install=function(e){e.component(di.name,di)};var pi=di,fi=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"label\",{staticClass:\"el-checkbox-button\",class:[e.size?\"el-checkbox-button--\"+e.size:\"\",{\"is-disabled\":e.isDisabled},{\"is-checked\":e.isChecked},{\"is-focus\":e.focus}],attrs:{role:\"checkbox\",\"aria-checked\":e.isChecked,\"aria-disabled\":e.isDisabled}},[e.trueLabel||e.falseLabel?i(\"input\",{directives:[{name:\"model\",rawName:\"v-model\",value:e.model,expression:\"model\"}],staticClass:\"el-checkbox-button__original\",attrs:{type:\"checkbox\",name:e.name,disabled:e.isDisabled,\"true-value\":e.trueLabel,\"false-value\":e.falseLabel},domProps:{checked:Array.isArray(e.model)?e._i(e.model,null)>-1:e._q(e.model,e.trueLabel)},on:{change:[function(t){var i=e.model,n=t.target,s=n.checked?e.trueLabel:e.falseLabel;if(Array.isArray(i)){var r=null,o=e._i(i,r);n.checked?o<0&&(e.model=i.concat([r])):o>-1&&(e.model=i.slice(0,o).concat(i.slice(o+1)))}else e.model=s},e.handleChange],focus:function(t){e.focus=!0},blur:function(t){e.focus=!1}}}):i(\"input\",{directives:[{name:\"model\",rawName:\"v-model\",value:e.model,expression:\"model\"}],staticClass:\"el-checkbox-button__original\",attrs:{type:\"checkbox\",name:e.name,disabled:e.isDisabled},domProps:{value:e.label,checked:Array.isArray(e.model)?e._i(e.model,e.label)>-1:e.model},on:{change:[function(t){var i=e.model,n=t.target,s=!!n.checked;if(Array.isArray(i)){var r=e.label,o=e._i(i,r);n.checked?o<0&&(e.model=i.concat([r])):o>-1&&(e.model=i.slice(0,o).concat(i.slice(o+1)))}else e.model=s},e.handleChange],focus:function(t){e.focus=!0},blur:function(t){e.focus=!1}}}),e.$slots.default||e.label?i(\"span\",{staticClass:\"el-checkbox-button__inner\",style:e.isChecked?e.activeStyle:null},[e._t(\"default\",[e._v(e._s(e.label))])],2):e._e()])},mi=[];fi._withStripped=!0;var vi={name:\"ElCheckboxButton\",mixins:[E.a],inject:{elForm:{default:\"\"},elFormItem:{default:\"\"}},data:function(){return{selfModel:!1,focus:!1,isLimitExceeded:!1}},props:{value:{},label:{},disabled:Boolean,checked:Boolean,name:String,trueLabel:[String,Number],falseLabel:[String,Number]},computed:{model:{get:function(){return this._checkboxGroup?this.store:void 0!==this.value?this.value:this.selfModel},set:function(e){this._checkboxGroup?(this.isLimitExceeded=!1,void 0!==this._checkboxGroup.min&&e.length<this._checkboxGroup.min&&(this.isLimitExceeded=!0),void 0!==this._checkboxGroup.max&&e.length>this._checkboxGroup.max&&(this.isLimitExceeded=!0),!1===this.isLimitExceeded&&this.dispatch(\"ElCheckboxGroup\",\"input\",[e])):void 0!==this.value?this.$emit(\"input\",e):this.selfModel=e}},isChecked:function(){return\"[object Boolean]\"==={}.toString.call(this.model)?this.model:Array.isArray(this.model)?this.model.indexOf(this.label)>-1:null!==this.model&&void 0!==this.model?this.model===this.trueLabel:void 0},_checkboxGroup:function(){var e=this.$parent;while(e){if(\"ElCheckboxGroup\"===e.$options.componentName)return e;e=e.$parent}return!1},store:function(){return this._checkboxGroup?this._checkboxGroup.value:this.value},activeStyle:function(){return{backgroundColor:this._checkboxGroup.fill||\"\",borderColor:this._checkboxGroup.fill||\"\",color:this._checkboxGroup.textColor||\"\",\"box-shadow\":\"-1px 0 0 0 \"+this._checkboxGroup.fill}},_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},size:function(){return this._checkboxGroup.checkboxGroupSize||this._elFormItemSize||(this.$ELEMENT||{}).size},isDisabled:function(){return this._checkboxGroup?this._checkboxGroup.disabled||this.disabled||(this.elForm||{}).disabled:this.disabled||(this.elForm||{}).disabled}},methods:{addToStore:function(){Array.isArray(this.model)&&-1===this.model.indexOf(this.label)?this.model.push(this.label):this.model=this.trueLabel||!0},handleChange:function(e){var t=this;if(!this.isLimitExceeded){var i=void 0;i=e.target.checked?void 0===this.trueLabel||this.trueLabel:void 0!==this.falseLabel&&this.falseLabel,this.$emit(\"change\",i,e),this.$nextTick(function(){t._checkboxGroup&&t.dispatch(\"ElCheckboxGroup\",\"change\",[t._checkboxGroup.value])})}}},created:function(){this.checked&&this.addToStore()}},gi=vi,bi=a(gi,fi,mi,!1,null,null,null);bi.options.__file=\"packages/checkbox/src/checkbox-button.vue\";var yi=bi.exports;yi.install=function(e){e.component(yi.name,yi)};var _i=yi,xi=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-checkbox-group\",attrs:{role:\"group\",\"aria-label\":\"checkbox-group\"}},[e._t(\"default\")],2)},Ci=[];xi._withStripped=!0;var wi={name:\"ElCheckboxGroup\",componentName:\"ElCheckboxGroup\",mixins:[E.a],inject:{elFormItem:{default:\"\"}},props:{value:{},disabled:Boolean,min:Number,max:Number,size:String,fill:String,textColor:String},computed:{_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},checkboxGroupSize:function(){return this.size||this._elFormItemSize||(this.$ELEMENT||{}).size}},watch:{value:function(e){this.dispatch(\"ElFormItem\",\"el.form.change\",[e])}}},ki=wi,Si=a(ki,xi,Ci,!1,null,null,null);Si.options.__file=\"packages/checkbox/src/checkbox-group.vue\";var $i=Si.exports;$i.install=function(e){e.component($i.name,$i)};var Di=$i,Ei=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-switch\",class:{\"is-disabled\":e.switchDisabled,\"is-checked\":e.checked},attrs:{role:\"switch\",\"aria-checked\":e.checked,\"aria-disabled\":e.switchDisabled},on:{click:e.switchValue}},[i(\"input\",{ref:\"input\",staticClass:\"el-switch__input\",attrs:{type:\"checkbox\",id:e.id,name:e.name,\"true-value\":e.activeValue,\"false-value\":e.inactiveValue,disabled:e.switchDisabled},on:{change:e.handleChange,keydown:function(t){return\"button\"in t||!e._k(t.keyCode,\"enter\",13,t.key,\"Enter\")?e.switchValue(t):null}}}),e.inactiveIconClass||e.inactiveText?i(\"span\",{class:[\"el-switch__label\",\"el-switch__label--left\",e.checked?\"\":\"is-active\"]},[e.inactiveIconClass?i(\"i\",{class:[e.inactiveIconClass]}):e._e(),!e.inactiveIconClass&&e.inactiveText?i(\"span\",{attrs:{\"aria-hidden\":e.checked}},[e._v(e._s(e.inactiveText))]):e._e()]):e._e(),i(\"span\",{ref:\"core\",staticClass:\"el-switch__core\",style:{width:e.coreWidth+\"px\"}}),e.activeIconClass||e.activeText?i(\"span\",{class:[\"el-switch__label\",\"el-switch__label--right\",e.checked?\"is-active\":\"\"]},[e.activeIconClass?i(\"i\",{class:[e.activeIconClass]}):e._e(),!e.activeIconClass&&e.activeText?i(\"span\",{attrs:{\"aria-hidden\":!e.checked}},[e._v(e._s(e.activeText))]):e._e()]):e._e()])},Ti=[];Ei._withStripped=!0;var Oi={name:\"ElSwitch\",mixins:[Q()(\"input\"),$.a,E.a],inject:{elForm:{default:\"\"}},props:{value:{type:[Boolean,String,Number],default:!1},disabled:{type:Boolean,default:!1},width:{type:Number,default:40},activeIconClass:{type:String,default:\"\"},inactiveIconClass:{type:String,default:\"\"},activeText:String,inactiveText:String,activeColor:{type:String,default:\"\"},inactiveColor:{type:String,default:\"\"},activeValue:{type:[Boolean,String,Number],default:!0},inactiveValue:{type:[Boolean,String,Number],default:!1},name:{type:String,default:\"\"},validateEvent:{type:Boolean,default:!0},id:String},data:function(){return{coreWidth:this.width}},created:function(){~[this.activeValue,this.inactiveValue].indexOf(this.value)||this.$emit(\"input\",this.inactiveValue)},computed:{checked:function(){return this.value===this.activeValue},switchDisabled:function(){return this.disabled||(this.elForm||{}).disabled}},watch:{checked:function(){this.$refs.input.checked=this.checked,(this.activeColor||this.inactiveColor)&&this.setBackgroundColor(),this.validateEvent&&this.dispatch(\"ElFormItem\",\"el.form.change\",[this.value])}},methods:{handleChange:function(e){var t=this,i=this.checked?this.inactiveValue:this.activeValue;this.$emit(\"input\",i),this.$emit(\"change\",i),this.$nextTick(function(){t.$refs.input.checked=t.checked})},setBackgroundColor:function(){var e=this.checked?this.activeColor:this.inactiveColor;this.$refs.core.style.borderColor=e,this.$refs.core.style.backgroundColor=e},switchValue:function(){!this.switchDisabled&&this.handleChange()},getMigratingConfig:function(){return{props:{\"on-color\":\"on-color is renamed to active-color.\",\"off-color\":\"off-color is renamed to inactive-color.\",\"on-text\":\"on-text is renamed to active-text.\",\"off-text\":\"off-text is renamed to inactive-text.\",\"on-value\":\"on-value is renamed to active-value.\",\"off-value\":\"off-value is renamed to inactive-value.\",\"on-icon-class\":\"on-icon-class is renamed to active-icon-class.\",\"off-icon-class\":\"off-icon-class is renamed to inactive-icon-class.\"}}}},mounted:function(){this.coreWidth=this.width||40,(this.activeColor||this.inactiveColor)&&this.setBackgroundColor(),this.$refs.input.checked=this.checked}},Ii=Oi,Pi=a(Ii,Ei,Ti,!1,null,null,null);Pi.options.__file=\"packages/switch/src/component.vue\";var Mi=Pi.exports;Mi.install=function(e){e.component(Mi.name,Mi)};var Ni=Mi,Fi=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{directives:[{name:\"clickoutside\",rawName:\"v-clickoutside\",value:e.handleClose,expression:\"handleClose\"}],staticClass:\"el-select\",class:[e.selectSize?\"el-select--\"+e.selectSize:\"\"],on:{click:function(t){return t.stopPropagation(),e.toggleMenu(t)}}},[e.multiple?i(\"div\",{ref:\"tags\",staticClass:\"el-select__tags\",style:{\"max-width\":e.inputWidth-32+\"px\",width:\"100%\"}},[e.collapseTags&&e.selected.length?i(\"span\",[i(\"el-tag\",{attrs:{closable:!e.selectDisabled,size:e.collapseTagSize,hit:e.selected[0].hitState,type:\"info\",\"disable-transitions\":\"\"},on:{close:function(t){e.deleteTag(t,e.selected[0])}}},[i(\"span\",{staticClass:\"el-select__tags-text\"},[e._v(e._s(e.selected[0].currentLabel))])]),e.selected.length>1?i(\"el-tag\",{attrs:{closable:!1,size:e.collapseTagSize,type:\"info\",\"disable-transitions\":\"\"}},[i(\"span\",{staticClass:\"el-select__tags-text\"},[e._v(\"+ \"+e._s(e.selected.length-1))])]):e._e()],1):e._e(),e.collapseTags?e._e():i(\"transition-group\",{on:{\"after-leave\":e.resetInputHeight}},e._l(e.selected,function(t){return i(\"el-tag\",{key:e.getValueKey(t),attrs:{closable:!e.selectDisabled,size:e.collapseTagSize,hit:t.hitState,type:\"info\",\"disable-transitions\":\"\"},on:{close:function(i){e.deleteTag(i,t)}}},[i(\"span\",{staticClass:\"el-select__tags-text\"},[e._v(e._s(t.currentLabel))])])}),1),e.filterable?i(\"input\",{directives:[{name:\"model\",rawName:\"v-model\",value:e.query,expression:\"query\"}],ref:\"input\",staticClass:\"el-select__input\",class:[e.selectSize?\"is-\"+e.selectSize:\"\"],style:{\"flex-grow\":\"1\",width:e.inputLength/(e.inputWidth-32)+\"%\",\"max-width\":e.inputWidth-42+\"px\"},attrs:{type:\"text\",disabled:e.selectDisabled,autocomplete:e.autoComplete||e.autocomplete},domProps:{value:e.query},on:{focus:e.handleFocus,blur:function(t){e.softFocus=!1},click:function(e){e.stopPropagation()},keyup:e.managePlaceholder,keydown:[e.resetInputState,function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"down\",40,t.key,[\"Down\",\"ArrowDown\"]))return null;t.preventDefault(),e.navigateOptions(\"next\")},function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"up\",38,t.key,[\"Up\",\"ArrowUp\"]))return null;t.preventDefault(),e.navigateOptions(\"prev\")},function(t){return\"button\"in t||!e._k(t.keyCode,\"enter\",13,t.key,\"Enter\")?(t.preventDefault(),e.selectOption(t)):null},function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"esc\",27,t.key,[\"Esc\",\"Escape\"]))return null;t.stopPropagation(),t.preventDefault(),e.visible=!1},function(t){return\"button\"in t||!e._k(t.keyCode,\"delete\",[8,46],t.key,[\"Backspace\",\"Delete\",\"Del\"])?e.deletePrevTag(t):null}],compositionstart:e.handleComposition,compositionupdate:e.handleComposition,compositionend:e.handleComposition,input:[function(t){t.target.composing||(e.query=t.target.value)},e.debouncedQueryChange]}}):e._e()],1):e._e(),i(\"el-input\",{ref:\"reference\",class:{\"is-focus\":e.visible},attrs:{type:\"text\",placeholder:e.currentPlaceholder,name:e.name,id:e.id,autocomplete:e.autoComplete||e.autocomplete,size:e.selectSize,disabled:e.selectDisabled,readonly:e.readonly,\"validate-event\":!1},on:{focus:e.handleFocus,blur:e.handleBlur},nativeOn:{keyup:function(t){return e.debouncedOnInputChange(t)},keydown:[function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"down\",40,t.key,[\"Down\",\"ArrowDown\"]))return null;t.stopPropagation(),t.preventDefault(),e.navigateOptions(\"next\")},function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"up\",38,t.key,[\"Up\",\"ArrowUp\"]))return null;t.stopPropagation(),t.preventDefault(),e.navigateOptions(\"prev\")},function(t){return\"button\"in t||!e._k(t.keyCode,\"enter\",13,t.key,\"Enter\")?(t.preventDefault(),e.selectOption(t)):null},function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"esc\",27,t.key,[\"Esc\",\"Escape\"]))return null;t.stopPropagation(),t.preventDefault(),e.visible=!1},function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"tab\",9,t.key,\"Tab\"))return null;e.visible=!1}],paste:function(t){return e.debouncedOnInputChange(t)},mouseenter:function(t){e.inputHovering=!0},mouseleave:function(t){e.inputHovering=!1}},model:{value:e.selectedLabel,callback:function(t){e.selectedLabel=t},expression:\"selectedLabel\"}},[e.$slots.prefix?i(\"template\",{slot:\"prefix\"},[e._t(\"prefix\")],2):e._e(),i(\"template\",{slot:\"suffix\"},[i(\"i\",{directives:[{name:\"show\",rawName:\"v-show\",value:!e.showClose,expression:\"!showClose\"}],class:[\"el-select__caret\",\"el-input__icon\",\"el-icon-\"+e.iconClass]}),e.showClose?i(\"i\",{staticClass:\"el-select__caret el-input__icon el-icon-circle-close\",on:{click:e.handleClearClick}}):e._e()])],2),i(\"transition\",{attrs:{name:\"el-zoom-in-top\"},on:{\"before-enter\":e.handleMenuEnter,\"after-leave\":e.doDestroy}},[i(\"el-select-menu\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible&&!1!==e.emptyText,expression:\"visible && emptyText !== false\"}],ref:\"popper\",attrs:{\"append-to-body\":e.popperAppendToBody}},[i(\"el-scrollbar\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.options.length>0&&!e.loading,expression:\"options.length > 0 && !loading\"}],ref:\"scrollbar\",class:{\"is-empty\":!e.allowCreate&&e.query&&0===e.filteredOptionsCount},attrs:{tag:\"ul\",\"wrap-class\":\"el-select-dropdown__wrap\",\"view-class\":\"el-select-dropdown__list\"}},[e.showNewOption?i(\"el-option\",{attrs:{value:e.query,created:\"\"}}):e._e(),e._t(\"default\")],2),e.emptyText&&(!e.allowCreate||e.loading||e.allowCreate&&0===e.options.length)?[e.$slots.empty?e._t(\"empty\"):i(\"p\",{staticClass:\"el-select-dropdown__empty\"},[e._v(\"\\n          \"+e._s(e.emptyText)+\"\\n        \")])]:e._e()],2)],1)],1)},Ai=[];Fi._withStripped=!0;var Li=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-select-dropdown el-popper\",class:[{\"is-multiple\":e.$parent.multiple},e.popperClass],style:{minWidth:e.minWidth}},[e._t(\"default\")],2)},Vi=[];Li._withStripped=!0;var Bi={name:\"ElSelectDropdown\",componentName:\"ElSelectDropdown\",mixins:[R.a],props:{placement:{default:\"bottom-start\"},boundariesPadding:{default:0},popperOptions:{default:function(){return{gpuAcceleration:!1}}},visibleArrow:{default:!0},appendToBody:{type:Boolean,default:!0}},data:function(){return{minWidth:\"\"}},computed:{popperClass:function(){return this.$parent.popperClass}},watch:{\"$parent.inputWidth\":function(){this.minWidth=this.$parent.$el.getBoundingClientRect().width+\"px\"}},mounted:function(){var e=this;this.referenceElm=this.$parent.$refs.reference.$el,this.$parent.popperElm=this.popperElm=this.$el,this.$on(\"updatePopper\",function(){e.$parent.visible&&e.updatePopper()}),this.$on(\"destroyPopper\",this.destroyPopper)}},zi=Bi,ji=a(zi,Li,Vi,!1,null,null,null);ji.options.__file=\"packages/select/src/select-dropdown.vue\";var Hi=ji.exports,Ri=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"li\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible,expression:\"visible\"}],staticClass:\"el-select-dropdown__item\",class:{selected:e.itemSelected,\"is-disabled\":e.disabled||e.groupDisabled||e.limitReached,hover:e.hover},on:{mouseenter:e.hoverItem,click:function(t){return t.stopPropagation(),e.selectOptionClick(t)}}},[e._t(\"default\",[i(\"span\",[e._v(e._s(e.currentLabel))])])],2)},Wi=[];Ri._withStripped=!0;var qi=\"function\"===typeof Symbol&&\"symbol\"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},Ki={mixins:[E.a],name:\"ElOption\",componentName:\"ElOption\",inject:[\"select\"],props:{value:{required:!0},label:[String,Number],created:Boolean,disabled:{type:Boolean,default:!1}},data:function(){return{index:-1,groupDisabled:!1,visible:!0,hitState:!1,hover:!1}},computed:{isObject:function(){return\"[object object]\"===Object.prototype.toString.call(this.value).toLowerCase()},currentLabel:function(){return this.label||(this.isObject?\"\":this.value)},currentValue:function(){return this.value||this.label||\"\"},itemSelected:function(){return this.select.multiple?this.contains(this.select.value,this.value):this.isEqual(this.value,this.select.value)},limitReached:function(){return!!this.select.multiple&&(!this.itemSelected&&(this.select.value||[]).length>=this.select.multipleLimit&&this.select.multipleLimit>0)}},watch:{currentLabel:function(){this.created||this.select.remote||this.dispatch(\"ElSelect\",\"setSelected\")},value:function(e,t){var i=this.select,n=i.remote,s=i.valueKey;if(!this.created&&!n){if(s&&\"object\"===(\"undefined\"===typeof e?\"undefined\":qi(e))&&\"object\"===(\"undefined\"===typeof t?\"undefined\":qi(t))&&e[s]===t[s])return;this.dispatch(\"ElSelect\",\"setSelected\")}}},methods:{isEqual:function(e,t){if(this.isObject){var i=this.select.valueKey;return Object(b[\"getValueByPath\"])(e,i)===Object(b[\"getValueByPath\"])(t,i)}return e===t},contains:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments[1];if(this.isObject){var i=this.select.valueKey;return e.some(function(e){return Object(b[\"getValueByPath\"])(e,i)===Object(b[\"getValueByPath\"])(t,i)})}return e.indexOf(t)>-1},handleGroupDisabled:function(e){this.groupDisabled=e},hoverItem:function(){this.disabled||this.groupDisabled||(this.select.hoverIndex=this.select.options.indexOf(this))},selectOptionClick:function(){!0!==this.disabled&&!0!==this.groupDisabled&&this.dispatch(\"ElSelect\",\"handleOptionClick\",[this,!0])},queryChange:function(e){this.visible=new RegExp(Object(b[\"escapeRegexpString\"])(e),\"i\").test(this.currentLabel)||this.created,this.visible||this.select.filteredOptionsCount--}},created:function(){this.select.options.push(this),this.select.cachedOptions.push(this),this.select.optionsCount++,this.select.filteredOptionsCount++,this.$on(\"queryChange\",this.queryChange),this.$on(\"handleGroupDisabled\",this.handleGroupDisabled)},beforeDestroy:function(){this.select.onOptionDestroy(this.select.options.indexOf(this))}},Yi=Ki,Ui=a(Yi,Ri,Wi,!1,null,null,null);Ui.options.__file=\"packages/select/src/option.vue\";var Gi=Ui.exports,Xi=i(21),Qi=i.n(Xi),Ji=i(13),Zi=i(10),en=i.n(Zi),tn=i(22),nn=i.n(tn),sn={data:function(){return{hoverOption:-1}},computed:{optionsAllDisabled:function(){return this.options.filter(function(e){return e.visible}).every(function(e){return e.disabled})}},watch:{hoverIndex:function(e){var t=this;\"number\"===typeof e&&e>-1&&(this.hoverOption=this.options[e]||{}),this.options.forEach(function(e){e.hover=t.hoverOption===e})}},methods:{navigateOptions:function(e){var t=this;if(this.visible){if(0!==this.options.length&&0!==this.filteredOptionsCount&&!this.optionsAllDisabled){\"next\"===e?(this.hoverIndex++,this.hoverIndex===this.options.length&&(this.hoverIndex=0)):\"prev\"===e&&(this.hoverIndex--,this.hoverIndex<0&&(this.hoverIndex=this.options.length-1));var i=this.options[this.hoverIndex];!0!==i.disabled&&!0!==i.groupDisabled&&i.visible||this.navigateOptions(e),this.$nextTick(function(){return t.scrollToOption(t.hoverOption)})}}else this.visible=!0}}},rn=i(25),on={mixins:[E.a,g.a,Q()(\"reference\"),sn],name:\"ElSelect\",componentName:\"ElSelect\",inject:{elForm:{default:\"\"},elFormItem:{default:\"\"}},provide:function(){return{select:this}},computed:{_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},readonly:function(){return!this.filterable||this.multiple||!Object(b[\"isIE\"])()&&!Object(b[\"isEdge\"])()&&!this.visible},showClose:function(){var e=this.multiple?Array.isArray(this.value)&&this.value.length>0:void 0!==this.value&&null!==this.value&&\"\"!==this.value,t=this.clearable&&!this.selectDisabled&&this.inputHovering&&e;return t},iconClass:function(){return this.remote&&this.filterable?\"\":this.visible?\"arrow-up is-reverse\":\"arrow-up\"},debounce:function(){return this.remote?300:0},emptyText:function(){return this.loading?this.loadingText||this.t(\"el.select.loading\"):(!this.remote||\"\"!==this.query||0!==this.options.length)&&(this.filterable&&this.query&&this.options.length>0&&0===this.filteredOptionsCount?this.noMatchText||this.t(\"el.select.noMatch\"):0===this.options.length?this.noDataText||this.t(\"el.select.noData\"):null)},showNewOption:function(){var e=this,t=this.options.filter(function(e){return!e.created}).some(function(t){return t.currentLabel===e.query});return this.filterable&&this.allowCreate&&\"\"!==this.query&&!t},selectSize:function(){return this.size||this._elFormItemSize||(this.$ELEMENT||{}).size},selectDisabled:function(){return this.disabled||(this.elForm||{}).disabled},collapseTagSize:function(){return[\"small\",\"mini\"].indexOf(this.selectSize)>-1?\"mini\":\"small\"}},components:{ElInput:m.a,ElSelectMenu:Hi,ElOption:Gi,ElTag:Qi.a,ElScrollbar:q.a},directives:{Clickoutside:B.a},props:{name:String,id:String,value:{required:!0},autocomplete:{type:String,default:\"off\"},autoComplete:{type:String,validator:function(e){return!0}},automaticDropdown:Boolean,size:String,disabled:Boolean,clearable:Boolean,filterable:Boolean,allowCreate:Boolean,loading:Boolean,popperClass:String,remote:Boolean,loadingText:String,noMatchText:String,noDataText:String,remoteMethod:Function,filterMethod:Function,multiple:Boolean,multipleLimit:{type:Number,default:0},placeholder:{type:String,default:function(){return Object(Zi[\"t\"])(\"el.select.placeholder\")}},defaultFirstOption:Boolean,reserveKeyword:Boolean,valueKey:{type:String,default:\"value\"},collapseTags:Boolean,popperAppendToBody:{type:Boolean,default:!0}},data:function(){return{options:[],cachedOptions:[],createdLabel:null,createdSelected:!1,selected:this.multiple?[]:{},inputLength:20,inputWidth:0,initialInputHeight:0,cachedPlaceHolder:\"\",optionsCount:0,filteredOptionsCount:0,visible:!1,softFocus:!1,selectedLabel:\"\",hoverIndex:-1,query:\"\",previousQuery:null,inputHovering:!1,currentPlaceholder:\"\",menuVisibleOnFocus:!1,isOnComposition:!1,isSilentBlur:!1}},watch:{selectDisabled:function(){var e=this;this.$nextTick(function(){e.resetInputHeight()})},placeholder:function(e){this.cachedPlaceHolder=this.currentPlaceholder=e},value:function(e,t){this.multiple&&(this.resetInputHeight(),e.length>0||this.$refs.input&&\"\"!==this.query?this.currentPlaceholder=\"\":this.currentPlaceholder=this.cachedPlaceHolder,this.filterable&&!this.reserveKeyword&&(this.query=\"\",this.handleQueryChange(this.query))),this.setSelected(),this.filterable&&!this.multiple&&(this.inputLength=20),Object(b[\"valueEquals\"])(e,t)||this.dispatch(\"ElFormItem\",\"el.form.change\",e)},visible:function(e){var t=this;e?(this.broadcast(\"ElSelectDropdown\",\"updatePopper\"),this.filterable&&(this.query=this.remote?\"\":this.selectedLabel,this.handleQueryChange(this.query),this.multiple?this.$refs.input.focus():(this.remote||(this.broadcast(\"ElOption\",\"queryChange\",\"\"),this.broadcast(\"ElOptionGroup\",\"queryChange\")),this.broadcast(\"ElInput\",\"inputSelect\")))):(this.broadcast(\"ElSelectDropdown\",\"destroyPopper\"),this.$refs.input&&this.$refs.input.blur(),this.query=\"\",this.previousQuery=null,this.selectedLabel=\"\",this.inputLength=20,this.menuVisibleOnFocus=!1,this.resetHoverIndex(),this.$nextTick(function(){t.$refs.input&&\"\"===t.$refs.input.value&&0===t.selected.length&&(t.currentPlaceholder=t.cachedPlaceHolder)}),this.multiple||this.selected&&(this.filterable&&this.allowCreate&&this.createdSelected&&this.createdLabel?this.selectedLabel=this.createdLabel:this.selectedLabel=this.selected.currentLabel,this.filterable&&(this.query=this.selectedLabel))),this.$emit(\"visible-change\",e)},options:function(){var e=this;if(!this.$isServer){this.$nextTick(function(){e.broadcast(\"ElSelectDropdown\",\"updatePopper\")}),this.multiple&&this.resetInputHeight();var t=this.$el.querySelectorAll(\"input\");-1===[].indexOf.call(t,document.activeElement)&&this.setSelected(),this.defaultFirstOption&&(this.filterable||this.remote)&&this.filteredOptionsCount&&this.checkDefaultFirstOption()}}},methods:{handleComposition:function(e){var t=e.target.value;if(\"compositionend\"===e.type)this.isOnComposition=!1,this.handleQueryChange(t);else{var i=t[t.length-1]||\"\";this.isOnComposition=!Object(rn[\"isKorean\"])(i)}},handleQueryChange:function(e){var t=this;if(this.previousQuery!==e&&!this.isOnComposition)if(null!==this.previousQuery||\"function\"!==typeof this.filterMethod&&\"function\"!==typeof this.remoteMethod){if(this.previousQuery=e,this.$nextTick(function(){t.visible&&t.broadcast(\"ElSelectDropdown\",\"updatePopper\")}),this.hoverIndex=-1,this.multiple&&this.filterable){var i=15*this.$refs.input.value.length+20;this.inputLength=this.collapseTags?Math.min(50,i):i,this.managePlaceholder(),this.resetInputHeight()}this.remote&&\"function\"===typeof this.remoteMethod?(this.hoverIndex=-1,this.remoteMethod(e)):\"function\"===typeof this.filterMethod?(this.filterMethod(e),this.broadcast(\"ElOptionGroup\",\"queryChange\")):(this.filteredOptionsCount=this.optionsCount,this.broadcast(\"ElOption\",\"queryChange\",e),this.broadcast(\"ElOptionGroup\",\"queryChange\")),this.defaultFirstOption&&(this.filterable||this.remote)&&this.filteredOptionsCount&&this.checkDefaultFirstOption()}else this.previousQuery=e},scrollToOption:function(e){var t=Array.isArray(e)&&e[0]?e[0].$el:e.$el;if(this.$refs.popper&&t){var i=this.$refs.popper.$el.querySelector(\".el-select-dropdown__wrap\");nn()(i,t)}this.$refs.scrollbar&&this.$refs.scrollbar.handleScroll()},handleMenuEnter:function(){var e=this;this.$nextTick(function(){return e.scrollToOption(e.selected)})},emitChange:function(e){Object(b[\"valueEquals\"])(this.value,e)||this.$emit(\"change\",e)},getOption:function(e){for(var t=void 0,i=\"[object object]\"===Object.prototype.toString.call(e).toLowerCase(),n=\"[object null]\"===Object.prototype.toString.call(e).toLowerCase(),s=this.cachedOptions.length-1;s>=0;s--){var r=this.cachedOptions[s],o=i?Object(b[\"getValueByPath\"])(r.value,this.valueKey)===Object(b[\"getValueByPath\"])(e,this.valueKey):r.value===e;if(o){t=r;break}}if(t)return t;var a=i||n?\"\":e,l={value:e,currentLabel:a};return this.multiple&&(l.hitState=!1),l},setSelected:function(){var e=this;if(!this.multiple){var t=this.getOption(this.value);return t.created?(this.createdLabel=t.currentLabel,this.createdSelected=!0):this.createdSelected=!1,this.selectedLabel=t.currentLabel,this.selected=t,void(this.filterable&&(this.query=this.selectedLabel))}var i=[];Array.isArray(this.value)&&this.value.forEach(function(t){i.push(e.getOption(t))}),this.selected=i,this.$nextTick(function(){e.resetInputHeight()})},handleFocus:function(e){this.softFocus?this.softFocus=!1:((this.automaticDropdown||this.filterable)&&(this.visible=!0,this.menuVisibleOnFocus=!0),this.$emit(\"focus\",e))},blur:function(){this.visible=!1,this.$refs.reference.blur()},handleBlur:function(e){var t=this;setTimeout(function(){t.isSilentBlur?t.isSilentBlur=!1:t.$emit(\"blur\",e)},50),this.softFocus=!1},handleClearClick:function(e){this.deleteSelected(e)},doDestroy:function(){this.$refs.popper&&this.$refs.popper.doDestroy()},handleClose:function(){this.visible=!1},toggleLastOptionHitState:function(e){if(Array.isArray(this.selected)){var t=this.selected[this.selected.length-1];if(t)return!0===e||!1===e?(t.hitState=e,e):(t.hitState=!t.hitState,t.hitState)}},deletePrevTag:function(e){if(e.target.value.length<=0&&!this.toggleLastOptionHitState()){var t=this.value.slice();t.pop(),this.$emit(\"input\",t),this.emitChange(t)}},managePlaceholder:function(){\"\"!==this.currentPlaceholder&&(this.currentPlaceholder=this.$refs.input.value?\"\":this.cachedPlaceHolder)},resetInputState:function(e){8!==e.keyCode&&this.toggleLastOptionHitState(!1),this.inputLength=15*this.$refs.input.value.length+20,this.resetInputHeight()},resetInputHeight:function(){var e=this;this.collapseTags&&!this.filterable||this.$nextTick(function(){if(e.$refs.reference){var t=e.$refs.reference.$el.childNodes,i=[].filter.call(t,function(e){return\"INPUT\"===e.tagName})[0],n=e.$refs.tags,s=e.initialInputHeight||40;i.style.height=0===e.selected.length?s+\"px\":Math.max(n?n.clientHeight+(n.clientHeight>s?6:0):0,s)+\"px\",e.visible&&!1!==e.emptyText&&e.broadcast(\"ElSelectDropdown\",\"updatePopper\")}})},resetHoverIndex:function(){var e=this;setTimeout(function(){e.multiple?e.selected.length>0?e.hoverIndex=Math.min.apply(null,e.selected.map(function(t){return e.options.indexOf(t)})):e.hoverIndex=-1:e.hoverIndex=e.options.indexOf(e.selected)},300)},handleOptionSelect:function(e,t){var i=this;if(this.multiple){var n=this.value.slice(),s=this.getValueIndex(n,e.value);s>-1?n.splice(s,1):(this.multipleLimit<=0||n.length<this.multipleLimit)&&n.push(e.value),this.$emit(\"input\",n),this.emitChange(n),e.created&&(this.query=\"\",this.handleQueryChange(\"\"),this.inputLength=20),this.filterable&&this.$refs.input.focus()}else this.$emit(\"input\",e.value),this.emitChange(e.value),this.visible=!1;this.isSilentBlur=t,this.setSoftFocus(),this.visible||this.$nextTick(function(){i.scrollToOption(e)})},setSoftFocus:function(){this.softFocus=!0;var e=this.$refs.input||this.$refs.reference;e&&e.focus()},getValueIndex:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments[1],i=\"[object object]\"===Object.prototype.toString.call(t).toLowerCase();if(i){var n=this.valueKey,s=-1;return e.some(function(e,i){return Object(b[\"getValueByPath\"])(e,n)===Object(b[\"getValueByPath\"])(t,n)&&(s=i,!0)}),s}return e.indexOf(t)},toggleMenu:function(){this.selectDisabled||(this.menuVisibleOnFocus?this.menuVisibleOnFocus=!1:this.visible=!this.visible,this.visible&&(this.$refs.input||this.$refs.reference).focus())},selectOption:function(){this.visible?this.options[this.hoverIndex]&&this.handleOptionSelect(this.options[this.hoverIndex]):this.toggleMenu()},deleteSelected:function(e){e.stopPropagation();var t=this.multiple?[]:null;this.$emit(\"input\",t),this.emitChange(t),this.visible=!1,this.$emit(\"clear\")},deleteTag:function(e,t){var i=this.selected.indexOf(t);if(i>-1&&!this.selectDisabled){var n=this.value.slice();n.splice(i,1),this.$emit(\"input\",n),this.emitChange(n),this.$emit(\"remove-tag\",t.value)}e.stopPropagation()},onInputChange:function(){this.filterable&&this.query!==this.selectedLabel&&(this.query=this.selectedLabel,this.handleQueryChange(this.query))},onOptionDestroy:function(e){e>-1&&(this.optionsCount--,this.filteredOptionsCount--,this.options.splice(e,1))},resetInputWidth:function(){this.inputWidth=this.$refs.reference.$el.getBoundingClientRect().width},handleResize:function(){this.resetInputWidth(),this.multiple&&this.resetInputHeight()},checkDefaultFirstOption:function(){this.hoverIndex=-1;for(var e=!1,t=this.options.length-1;t>=0;t--)if(this.options[t].created){e=!0,this.hoverIndex=t;break}if(!e)for(var i=0;i!==this.options.length;++i){var n=this.options[i];if(this.query){if(!n.disabled&&!n.groupDisabled&&n.visible){this.hoverIndex=i;break}}else if(n.itemSelected){this.hoverIndex=i;break}}},getValueKey:function(e){return\"[object object]\"!==Object.prototype.toString.call(e.value).toLowerCase()?e.value:Object(b[\"getValueByPath\"])(e.value,this.valueKey)}},created:function(){var e=this;this.cachedPlaceHolder=this.currentPlaceholder=this.placeholder,this.multiple&&!Array.isArray(this.value)&&this.$emit(\"input\",[]),!this.multiple&&Array.isArray(this.value)&&this.$emit(\"input\",\"\"),this.debouncedOnInputChange=L()(this.debounce,function(){e.onInputChange()}),this.debouncedQueryChange=L()(this.debounce,function(t){e.handleQueryChange(t.target.value)}),this.$on(\"handleOptionClick\",this.handleOptionSelect),this.$on(\"setSelected\",this.setSelected)},mounted:function(){var e=this;this.multiple&&Array.isArray(this.value)&&this.value.length>0&&(this.currentPlaceholder=\"\"),Object(Ji[\"addResizeListener\"])(this.$el,this.handleResize);var t=this.$refs.reference;if(t&&t.$el){var i={medium:36,small:32,mini:28};this.initialInputHeight=t.$el.getBoundingClientRect().height||i[this.selectSize]}this.remote&&this.multiple&&this.resetInputHeight(),this.$nextTick(function(){t&&t.$el&&(e.inputWidth=t.$el.getBoundingClientRect().width)}),this.setSelected()},beforeDestroy:function(){this.$el&&this.handleResize&&Object(Ji[\"removeResizeListener\"])(this.$el,this.handleResize)}},an=on,ln=a(an,Fi,Ai,!1,null,null,null);ln.options.__file=\"packages/select/src/select.vue\";var un=ln.exports;un.install=function(e){e.component(un.name,un)};var cn=un;Gi.install=function(e){e.component(Gi.name,Gi)};var hn=Gi,dn=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"ul\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible,expression:\"visible\"}],staticClass:\"el-select-group__wrap\"},[i(\"li\",{staticClass:\"el-select-group__title\"},[e._v(e._s(e.label))]),i(\"li\",[i(\"ul\",{staticClass:\"el-select-group\"},[e._t(\"default\")],2)])])},pn=[];dn._withStripped=!0;var fn={mixins:[E.a],name:\"ElOptionGroup\",componentName:\"ElOptionGroup\",props:{label:String,disabled:{type:Boolean,default:!1}},data:function(){return{visible:!0}},watch:{disabled:function(e){this.broadcast(\"ElOption\",\"handleGroupDisabled\",e)}},methods:{queryChange:function(){this.visible=this.$children&&Array.isArray(this.$children)&&this.$children.some(function(e){return!0===e.visible})}},created:function(){this.$on(\"queryChange\",this.queryChange)},mounted:function(){this.disabled&&this.broadcast(\"ElOption\",\"handleGroupDisabled\",this.disabled)}},mn=fn,vn=a(mn,dn,pn,!1,null,null,null);vn.options.__file=\"packages/select/src/option-group.vue\";var gn=vn.exports;gn.install=function(e){e.component(gn.name,gn)};var bn=gn,yn=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"button\",{staticClass:\"el-button\",class:[e.type?\"el-button--\"+e.type:\"\",e.buttonSize?\"el-button--\"+e.buttonSize:\"\",{\"is-disabled\":e.buttonDisabled,\"is-loading\":e.loading,\"is-plain\":e.plain,\"is-round\":e.round,\"is-circle\":e.circle}],attrs:{disabled:e.buttonDisabled||e.loading,autofocus:e.autofocus,type:e.nativeType},on:{click:e.handleClick}},[e.loading?i(\"i\",{staticClass:\"el-icon-loading\"}):e._e(),e.icon&&!e.loading?i(\"i\",{class:e.icon}):e._e(),e.$slots.default?i(\"span\",[e._t(\"default\")],2):e._e()])},_n=[];yn._withStripped=!0;var xn={name:\"ElButton\",inject:{elForm:{default:\"\"},elFormItem:{default:\"\"}},props:{type:{type:String,default:\"default\"},size:String,icon:{type:String,default:\"\"},nativeType:{type:String,default:\"button\"},loading:Boolean,disabled:Boolean,plain:Boolean,autofocus:Boolean,round:Boolean,circle:Boolean},computed:{_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},buttonSize:function(){return this.size||this._elFormItemSize||(this.$ELEMENT||{}).size},buttonDisabled:function(){return this.disabled||(this.elForm||{}).disabled}},methods:{handleClick:function(e){this.$emit(\"click\",e)}}},Cn=xn,wn=a(Cn,yn,_n,!1,null,null,null);wn.options.__file=\"packages/button/src/button.vue\";var kn=wn.exports;kn.install=function(e){e.component(kn.name,kn)};var Sn=kn,$n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-button-group\"},[e._t(\"default\")],2)},Dn=[];$n._withStripped=!0;var En={name:\"ElButtonGroup\"},Tn=En,On=a(Tn,$n,Dn,!1,null,null,null);On.options.__file=\"packages/button/src/button-group.vue\";var In=On.exports;In.install=function(e){e.component(In.name,In)};var Pn=In,Mn=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-table\",class:[{\"el-table--fit\":e.fit,\"el-table--striped\":e.stripe,\"el-table--border\":e.border||e.isGroup,\"el-table--hidden\":e.isHidden,\"el-table--group\":e.isGroup,\"el-table--fluid-height\":e.maxHeight,\"el-table--scrollable-x\":e.layout.scrollX,\"el-table--scrollable-y\":e.layout.scrollY,\"el-table--enable-row-hover\":!e.store.states.isComplex,\"el-table--enable-row-transition\":0!==(e.store.states.data||[]).length&&(e.store.states.data||[]).length<100},e.tableSize?\"el-table--\"+e.tableSize:\"\"],on:{mouseleave:function(t){e.handleMouseLeave(t)}}},[i(\"div\",{ref:\"hiddenColumns\",staticClass:\"hidden-columns\"},[e._t(\"default\")],2),e.showHeader?i(\"div\",{directives:[{name:\"mousewheel\",rawName:\"v-mousewheel\",value:e.handleHeaderFooterMousewheel,expression:\"handleHeaderFooterMousewheel\"}],ref:\"headerWrapper\",staticClass:\"el-table__header-wrapper\"},[i(\"table-header\",{ref:\"tableHeader\",style:{width:e.layout.bodyWidth?e.layout.bodyWidth+\"px\":\"\"},attrs:{store:e.store,border:e.border,\"default-sort\":e.defaultSort}})],1):e._e(),i(\"div\",{ref:\"bodyWrapper\",staticClass:\"el-table__body-wrapper\",class:[e.layout.scrollX?\"is-scrolling-\"+e.scrollPosition:\"is-scrolling-none\"],style:[e.bodyHeight]},[i(\"table-body\",{style:{width:e.bodyWidth},attrs:{context:e.context,store:e.store,stripe:e.stripe,\"row-class-name\":e.rowClassName,\"row-style\":e.rowStyle,highlight:e.highlightCurrentRow}}),e.data&&0!==e.data.length?e._e():i(\"div\",{ref:\"emptyBlock\",staticClass:\"el-table__empty-block\",style:{width:e.bodyWidth}},[i(\"span\",{staticClass:\"el-table__empty-text\"},[e._t(\"empty\",[e._v(e._s(e.emptyText||e.t(\"el.table.emptyText\")))])],2)]),e.$slots.append?i(\"div\",{ref:\"appendWrapper\",staticClass:\"el-table__append-wrapper\"},[e._t(\"append\")],2):e._e()],1),e.showSummary?i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.data&&e.data.length>0,expression:\"data && data.length > 0\"},{name:\"mousewheel\",rawName:\"v-mousewheel\",value:e.handleHeaderFooterMousewheel,expression:\"handleHeaderFooterMousewheel\"}],ref:\"footerWrapper\",staticClass:\"el-table__footer-wrapper\"},[i(\"table-footer\",{style:{width:e.layout.bodyWidth?e.layout.bodyWidth+\"px\":\"\"},attrs:{store:e.store,border:e.border,\"sum-text\":e.sumText||e.t(\"el.table.sumText\"),\"summary-method\":e.summaryMethod,\"default-sort\":e.defaultSort}})],1):e._e(),e.fixedColumns.length>0?i(\"div\",{directives:[{name:\"mousewheel\",rawName:\"v-mousewheel\",value:e.handleFixedMousewheel,expression:\"handleFixedMousewheel\"}],ref:\"fixedWrapper\",staticClass:\"el-table__fixed\",style:[{width:e.layout.fixedWidth?e.layout.fixedWidth+\"px\":\"\"},e.fixedHeight]},[e.showHeader?i(\"div\",{ref:\"fixedHeaderWrapper\",staticClass:\"el-table__fixed-header-wrapper\"},[i(\"table-header\",{ref:\"fixedTableHeader\",style:{width:e.bodyWidth},attrs:{fixed:\"left\",border:e.border,store:e.store}})],1):e._e(),i(\"div\",{ref:\"fixedBodyWrapper\",staticClass:\"el-table__fixed-body-wrapper\",style:[{top:e.layout.headerHeight+\"px\"},e.fixedBodyHeight]},[i(\"table-body\",{style:{width:e.bodyWidth},attrs:{fixed:\"left\",store:e.store,stripe:e.stripe,highlight:e.highlightCurrentRow,\"row-class-name\":e.rowClassName,\"row-style\":e.rowStyle}}),e.$slots.append?i(\"div\",{staticClass:\"el-table__append-gutter\",style:{height:e.layout.appendHeight+\"px\"}}):e._e()],1),e.showSummary?i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.data&&e.data.length>0,expression:\"data && data.length > 0\"}],ref:\"fixedFooterWrapper\",staticClass:\"el-table__fixed-footer-wrapper\"},[i(\"table-footer\",{style:{width:e.bodyWidth},attrs:{fixed:\"left\",border:e.border,\"sum-text\":e.sumText||e.t(\"el.table.sumText\"),\"summary-method\":e.summaryMethod,store:e.store}})],1):e._e()]):e._e(),e.rightFixedColumns.length>0?i(\"div\",{directives:[{name:\"mousewheel\",rawName:\"v-mousewheel\",value:e.handleFixedMousewheel,expression:\"handleFixedMousewheel\"}],ref:\"rightFixedWrapper\",staticClass:\"el-table__fixed-right\",style:[{width:e.layout.rightFixedWidth?e.layout.rightFixedWidth+\"px\":\"\",right:e.layout.scrollY?(e.border?e.layout.gutterWidth:e.layout.gutterWidth||0)+\"px\":\"\"},e.fixedHeight]},[e.showHeader?i(\"div\",{ref:\"rightFixedHeaderWrapper\",staticClass:\"el-table__fixed-header-wrapper\"},[i(\"table-header\",{ref:\"rightFixedTableHeader\",style:{width:e.bodyWidth},attrs:{fixed:\"right\",border:e.border,store:e.store}})],1):e._e(),i(\"div\",{ref:\"rightFixedBodyWrapper\",staticClass:\"el-table__fixed-body-wrapper\",style:[{top:e.layout.headerHeight+\"px\"},e.fixedBodyHeight]},[i(\"table-body\",{style:{width:e.bodyWidth},attrs:{fixed:\"right\",store:e.store,stripe:e.stripe,\"row-class-name\":e.rowClassName,\"row-style\":e.rowStyle,highlight:e.highlightCurrentRow}})],1),e.showSummary?i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.data&&e.data.length>0,expression:\"data && data.length > 0\"}],ref:\"rightFixedFooterWrapper\",staticClass:\"el-table__fixed-footer-wrapper\"},[i(\"table-footer\",{style:{width:e.bodyWidth},attrs:{fixed:\"right\",border:e.border,\"sum-text\":e.sumText||e.t(\"el.table.sumText\"),\"summary-method\":e.summaryMethod,store:e.store}})],1):e._e()]):e._e(),e.rightFixedColumns.length>0?i(\"div\",{ref:\"rightFixedPatch\",staticClass:\"el-table__fixed-right-patch\",style:{width:e.layout.scrollY?e.layout.gutterWidth+\"px\":\"0\",height:e.layout.headerHeight+\"px\"}}):e._e(),i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.resizeProxyVisible,expression:\"resizeProxyVisible\"}],ref:\"resizeProxy\",staticClass:\"el-table__column-resize-proxy\"})])},Nn=[];Mn._withStripped=!0;var Fn=i(15),An=i.n(Fn),Ln=i(34),Vn=i.n(Ln),Bn=\"undefined\"!==typeof navigator&&navigator.userAgent.toLowerCase().indexOf(\"firefox\")>-1,zn=function(e,t){e&&e.addEventListener&&e.addEventListener(Bn?\"DOMMouseScroll\":\"mousewheel\",function(e){var i=Vn()(e);t&&t.apply(this,[e,i])})},jn={bind:function(e,t){zn(e,t.value)}},Hn=i(3),Rn=i.n(Hn),Wn=\"function\"===typeof Symbol&&\"symbol\"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},qn=function(e){var t=e.target;while(t&&\"HTML\"!==t.tagName.toUpperCase()){if(\"TD\"===t.tagName.toUpperCase())return t;t=t.parentNode}return null},Kn=function(e){return null!==e&&\"object\"===(\"undefined\"===typeof e?\"undefined\":Wn(e))},Yn=function(e,t,i,n,s){if(!t&&!n&&(!s||Array.isArray(s)&&!s.length))return e;i=\"string\"===typeof i?\"descending\"===i?-1:1:i&&i<0?-1:1;var r=n?null:function(i,n){return s?(Array.isArray(s)||(s=[s]),s.map(function(t){return\"string\"===typeof t?Object(b[\"getValueByPath\"])(i,t):t(i,n,e)})):(\"$key\"!==t&&Kn(i)&&\"$value\"in i&&(i=i.$value),[Kn(i)?Object(b[\"getValueByPath\"])(i,t):i])},o=function(e,t){if(n)return n(e.value,t.value);for(var i=0,s=e.key.length;i<s;i++){if(e.key[i]<t.key[i])return-1;if(e.key[i]>t.key[i])return 1}return 0};return e.map(function(e,t){return{value:e,index:t,key:r?r(e,t):null}}).sort(function(e,t){var n=o(e,t);return n||(n=e.index-t.index),n*i}).map(function(e){return e.value})},Un=function(e,t){var i=null;return e.columns.forEach(function(e){e.id===t&&(i=e)}),i},Gn=function(e,t){for(var i=null,n=0;n<e.columns.length;n++){var s=e.columns[n];if(s.columnKey===t){i=s;break}}return i},Xn=function(e,t){var i=(t.className||\"\").match(/el-table_[^\\s]+/gm);return i?Un(e,i[0]):null},Qn=function(e,t){if(!e)throw new Error(\"row is required when get row identity\");if(\"string\"===typeof t){if(t.indexOf(\".\")<0)return e[t];for(var i=t.split(\".\"),n=e,s=0;s<i.length;s++)n=n[i[s]];return n}if(\"function\"===typeof t)return t.call(null,e)},Jn=function(e,t){var i=t.sortingColumn;if(!i||\"string\"===typeof i.sortable)return e;if(0===Object.keys(t.treeData).length)return Yn(e,t.sortProp,t.sortOrder,i.sortMethod,i.sortBy);var n=t.rowKey,s=[],r={},o=0;while(o<e.length){var a=e[o],l=a[n],u=t.treeData[l];if(s.push(a),o++,u){r[l]=[];while(o<e.length){if(a=e[o],u=t.treeData[a[n]],o++,!u||0===u.level){s.push(a);break}r[l].push(a)}}}var c=Yn(s,t.sortProp,t.sortOrder,i.sortMethod,i.sortBy);return c.reduce(function(e,t){var i=r[t[n]]||[];return e.concat(t,i)},[])},Zn=function(e,t){var i={};return(e||[]).forEach(function(e,n){i[Qn(e,t)]={row:e,index:n}}),i},es=function(e,t,i){var n=!1,s=e.selection,r=s.indexOf(t);return\"undefined\"===typeof i?-1===r?(s.push(t),n=!0):(s.splice(r,1),n=!0):i&&-1===r?(s.push(t),n=!0):!i&&r>-1&&(s.splice(r,1),n=!0),n},ts=function(e,t,i){var n=!1,s=e.expandRows;if(\"undefined\"!==typeof i){var r=s.indexOf(t);i?-1===r&&(s.push(t),n=!0):-1!==r&&(s.splice(r,1),n=!0)}else{var o=s.indexOf(t);-1===o?(s.push(t),n=!0):(s.splice(o,1),n=!0)}return n},is=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(!e)throw new Error(\"Table is required.\");for(var i in this.table=e,this.states={rowKey:null,_columns:[],originColumns:[],columns:[],fixedColumns:[],rightFixedColumns:[],leafColumns:[],fixedLeafColumns:[],rightFixedLeafColumns:[],leafColumnsLength:0,fixedLeafColumnsLength:0,rightFixedLeafColumnsLength:0,isComplex:!1,filteredData:null,data:null,sortingColumn:null,sortProp:null,sortOrder:null,isAllSelected:!1,selection:[],reserveSelection:!1,selectable:null,currentRow:null,hoverRow:null,filters:{},expandRows:[],defaultExpandAll:!1,selectOnIndeterminate:!1,treeData:{},indent:16,lazy:!1,lazyTreeNodeMap:{}},this._toggleAllSelection=L()(10,function(e){var t=e.data||[];if(0!==t.length){var i=this.states.selection,n=e.selectOnIndeterminate?!e.isAllSelected:!(e.isAllSelected||i.length),s=!1;t.forEach(function(t,i){e.selectable?e.selectable.call(null,t,i)&&es(e,t,n)&&(s=!0):es(e,t,n)&&(s=!0)});var r=this.table;s&&r.$emit(\"selection-change\",i?i.slice():[]),r.$emit(\"select-all\",i),e.isAllSelected=n}}),t)t.hasOwnProperty(i)&&this.states.hasOwnProperty(i)&&(this.states[i]=t[i])};is.prototype.mutations={setData:function(e,t){var i=this,n=e._data!==t;e._data=t,Object.keys(e.filters).forEach(function(n){var s=e.filters[n];if(s&&0!==s.length){var r=Un(i.states,n);r&&r.filterMethod&&(t=t.filter(function(e){return s.some(function(t){return r.filterMethod.call(null,t,e,r)})}))}}),e.filteredData=t,e.data=Jn(t||[],e),this.updateCurrentRow();var s=e.rowKey;if(e.reserveSelection)if(s){var r=e.selection,o=Zn(r,s);e.data.forEach(function(e){var t=Qn(e,s),i=o[t];i&&(r[i.index]=e)}),this.updateAllSelected()}else console.warn(\"WARN: rowKey is required when reserve-selection is enabled.\");else n?this.clearSelection():this.cleanSelection(),this.updateAllSelected();var a=e.defaultExpandAll;if(a)this.states.expandRows=(e.data||[]).slice(0);else if(s){var l=Zn(this.states.expandRows,s),u=[],c=e.data,h=Array.isArray(c),d=0;for(c=h?c:c[Symbol.iterator]();;){var p;if(h){if(d>=c.length)break;p=c[d++]}else{if(d=c.next(),d.done)break;p=d.value}var f=p,m=Qn(f,s);l[m]&&u.push(f)}this.states.expandRows=u}else this.states.expandRows=[];Rn.a.nextTick(function(){return i.table.updateScrollY()})},changeSortCondition:function(e,t){var i=this;e.data=Jn(e.filteredData||e._data||[],e),t&&t.silent||this.table.$emit(\"sort-change\",{column:this.states.sortingColumn,prop:this.states.sortProp,order:this.states.sortOrder}),Rn.a.nextTick(function(){return i.table.updateScrollY()})},sort:function(e,t){var i=this,n=t.prop,s=t.order;n&&(e.sortProp=n,e.sortOrder=s||\"ascending\",Rn.a.nextTick(function(){for(var t=0,n=e.columns.length;t<n;t++){var s=e.columns[t];if(s.property===e.sortProp){s.order=e.sortOrder,e.sortingColumn=s;break}}e.sortingColumn&&i.commit(\"changeSortCondition\")}))},filterChange:function(e,t){var i=this,n=t.column,s=t.values,r=t.silent,o=t.multi;s&&!Array.isArray(s)&&(s=[s]);var a={};if(o)n.forEach(function(t){e.filters[t.id]=s,a[t.columnKey||t.id]=s});else{var l=n.property;l&&(e.filters[n.id]=s,a[n.columnKey||n.id]=s)}var u=e._data;Object.keys(e.filters).forEach(function(t){var n=e.filters[t];if(n&&0!==n.length){var s=Un(i.states,t);s&&s.filterMethod&&(u=u.filter(function(e){return n.some(function(t){return s.filterMethod.call(null,t,e,s)})}))}}),e.filteredData=u,e.data=Jn(u,e),r||this.table.$emit(\"filter-change\",a),Rn.a.nextTick(function(){return i.table.updateScrollY()})},insertColumn:function(e,t,i,n){var s=e._columns;n&&(s=n.children,s||(s=n.children=[])),\"undefined\"!==typeof i?s.splice(i,0,t):s.push(t),\"selection\"===t.type&&(e.selectable=t.selectable,e.reserveSelection=t.reserveSelection),this.table.$ready&&(this.updateColumns(),this.scheduleLayout())},removeColumn:function(e,t,i){var n=e._columns;i&&(n=i.children,n||(n=i.children=[])),n&&n.splice(n.indexOf(t),1),this.table.$ready&&(this.updateColumns(),this.scheduleLayout())},setHoverRow:function(e,t){e.hoverRow=t},setCurrentRow:function(e,t){var i=e.currentRow;e.currentRow=t,i!==t&&this.table.$emit(\"current-change\",t,i)},rowSelectedChanged:function(e,t){var i=es(e,t),n=e.selection;if(i){var s=this.table;s.$emit(\"selection-change\",n?n.slice():[]),s.$emit(\"select\",n,t)}this.updateAllSelected()},toggleAllSelection:function(e){this._toggleAllSelection(e)}};var ns=function e(t){var i=[];return t.forEach(function(t){t.children?i.push.apply(i,e(t.children)):i.push(t)}),i};is.prototype.updateColumns=function(){var e=this.states,t=e._columns||[];e.fixedColumns=t.filter(function(e){return!0===e.fixed||\"left\"===e.fixed}),e.rightFixedColumns=t.filter(function(e){return\"right\"===e.fixed}),e.fixedColumns.length>0&&t[0]&&\"selection\"===t[0].type&&!t[0].fixed&&(t[0].fixed=!0,e.fixedColumns.unshift(t[0]));var i=t.filter(function(e){return!e.fixed});e.originColumns=[].concat(e.fixedColumns).concat(i).concat(e.rightFixedColumns);var n=ns(i),s=ns(e.fixedColumns),r=ns(e.rightFixedColumns);e.leafColumnsLength=n.length,e.fixedLeafColumnsLength=s.length,e.rightFixedLeafColumnsLength=r.length,e.columns=[].concat(s).concat(n).concat(r),e.isComplex=e.fixedColumns.length>0||e.rightFixedColumns.length>0},is.prototype.isSelected=function(e){return(this.states.selection||[]).indexOf(e)>-1},is.prototype.clearSelection=function(){var e=this.states;e.isAllSelected=!1;var t=e.selection;e.selection.length&&(e.selection=[]),t.length>0&&this.table.$emit(\"selection-change\",e.selection?e.selection.slice():[])},is.prototype.setExpandRowKeys=function(e){var t=[],i=this.states.data,n=this.states.rowKey;if(!n)throw new Error(\"[Table] prop row-key should not be empty.\");var s=Zn(i,n);e.forEach(function(e){var i=s[e];i&&t.push(i.row)}),this.states.expandRows=t},is.prototype.toggleRowSelection=function(e,t){var i=es(this.states,e,t);i&&this.table.$emit(\"selection-change\",this.states.selection?this.states.selection.slice():[])},is.prototype.toggleRowExpansion=function(e,t){var i=ts(this.states,e,t);i&&(this.table.$emit(\"expand-change\",e,this.states.expandRows),this.scheduleLayout())},is.prototype.isRowExpanded=function(e){var t=this.states,i=t.expandRows,n=void 0===i?[]:i,s=t.rowKey;if(s){var r=Zn(n,s);return!!r[Qn(e,s)]}return-1!==n.indexOf(e)},is.prototype.cleanSelection=function(){var e=this.states.selection||[],t=this.states.data,i=this.states.rowKey,n=void 0;if(i){n=[];var s=Zn(e,i),r=Zn(t,i);for(var o in s)s.hasOwnProperty(o)&&!r[o]&&n.push(s[o].row)}else n=e.filter(function(e){return-1===t.indexOf(e)});n.forEach(function(t){e.splice(e.indexOf(t),1)}),n.length&&this.table.$emit(\"selection-change\",e?e.slice():[])},is.prototype.clearFilter=function(e){var t=this.states,i=this.table.$refs,n=i.tableHeader,s=i.fixedTableHeader,r=i.rightFixedTableHeader,o={};n&&(o=St()(o,n.filterPanels)),s&&(o=St()(o,s.filterPanels)),r&&(o=St()(o,r.filterPanels));var a=Object.keys(o);if(a.length)if(\"string\"===typeof e&&(e=[e]),Array.isArray(e)){var l=e.map(function(e){return Gn(t,e)});a.forEach(function(e){var t=l.find(function(t){return t.id===e});t&&(o[e].filteredValue=[])}),this.commit(\"filterChange\",{column:l,value:[],silent:!0,multi:!0})}else a.forEach(function(e){o[e].filteredValue=[]}),t.filters={},this.commit(\"filterChange\",{column:{},values:[],silent:!0})},is.prototype.clearSort=function(){var e=this.states;e.sortingColumn&&(e.sortingColumn.order=null,e.sortProp=null,e.sortOrder=null,this.commit(\"changeSortCondition\",{silent:!0}))},is.prototype.updateAllSelected=function(){var e=this.states,t=e.selection,i=e.rowKey,n=e.selectable,s=e.data;if(s&&0!==s.length){var r=void 0;i&&(r=Zn(e.selection,i));for(var o=function(e){return r?!!r[Qn(e,i)]:-1!==t.indexOf(e)},a=!0,l=0,u=0,c=s.length;u<c;u++){var h=s[u],d=n&&n.call(null,h,u);if(o(h))l++;else if(!n||d){a=!1;break}}0===l&&(a=!1),e.isAllSelected=a}else e.isAllSelected=!1},is.prototype.scheduleLayout=function(e){e&&this.updateColumns(),this.table.debouncedUpdateLayout()},is.prototype.setCurrentRowKey=function(e){var t=this.states,i=t.rowKey;if(!i)throw new Error(\"[Table] row-key should not be empty.\");var n=t.data||[],s=Zn(n,i),r=s[e];t.currentRow=r?r.row:null},is.prototype.updateCurrentRow=function(){var e=this.states,t=this.table,i=e.data||[],n=e.currentRow;if(-1===i.indexOf(n)){if(e.rowKey&&n){for(var s=null,r=0;r<i.length;r++){var o=i[r];if(o&&o[e.rowKey]===n[e.rowKey]){s=o;break}}if(s)return void(e.currentRow=s)}e.currentRow=null,e.currentRow!==n&&t.$emit(\"current-change\",null,n)}},is.prototype.commit=function(e){var t=this.mutations;if(!t[e])throw new Error(\"Action not found: \"+e);for(var i=arguments.length,n=Array(i>1?i-1:0),s=1;s<i;s++)n[s-1]=arguments[s];t[e].apply(this,[this.states].concat(n))},is.prototype.toggleTreeExpansion=function(e){var t=this.states.treeData,i=t[e];if(i){if(\"boolean\"!==typeof i.expanded)throw new Error(\"a leaf must have expanded property\");i.expanded=!i.expanded;var n=null;if(i.expanded)n=function(e,i){e&&i.expanded&&e.forEach(function(e){t[e].display=!0,n(t[e].children,t[e])})},i.children.forEach(function(e){t[e].display=!0,n(t[e].children,t[e])});else{var s=function e(i){i&&i.forEach(function(i){t[i].display=!1,e(t[i].children)})};s(i.children)}}},is.prototype.loadData=function(e,t){var i=this,n=this.table,s=t.rowKey;n.lazy&&n.load&&n.load(e,t,function(e){if(!Array.isArray(e))throw new Error(\"data must be an array\");var t=i.states.treeData;e.forEach(function(e){var r=n.getRowKey(e),o=t[s];o.loaded=!0,o.children.push(r);var a={display:!0,level:o.level+1};e.hasChildren&&(a.expanded=!1,a.hasChildren=!0,a.children=[]),Rn.a.set(t,r,a),Rn.a.set(i.states.lazyTreeNodeMap,r,e)}),i.toggleTreeExpansion(s)})};var ss=is,rs=i(26),os=i.n(rs);function as(e,t){if(!(e instanceof t))throw new TypeError(\"Cannot call a class as a function\")}var ls=function(){function e(t){for(var i in as(this,e),this.observers=[],this.table=null,this.store=null,this.columns=null,this.fit=!0,this.showHeader=!0,this.height=null,this.scrollX=!1,this.scrollY=!1,this.bodyWidth=null,this.fixedWidth=null,this.rightFixedWidth=null,this.tableHeight=null,this.headerHeight=44,this.appendHeight=0,this.footerHeight=44,this.viewportHeight=null,this.bodyHeight=null,this.fixedBodyHeight=null,this.gutterWidth=os()(),t)t.hasOwnProperty(i)&&(this[i]=t[i]);if(!this.table)throw new Error(\"table is required for Table Layout\");if(!this.store)throw new Error(\"store is required for Table Layout\")}return e.prototype.updateScrollY=function(){var e=this.height;if(\"string\"===typeof e||\"number\"===typeof e){var t=this.table.bodyWrapper;if(this.table.$el&&t){var i=t.querySelector(\".el-table__body\");this.scrollY=i.offsetHeight>this.bodyHeight}}},e.prototype.setHeight=function(e){var t=this,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:\"height\";if(!Rn.a.prototype.$isServer){var n=this.table.$el;if(\"string\"===typeof e&&/^\\d+$/.test(e)&&(e=Number(e)),this.height=e,!n&&(e||0===e))return Rn.a.nextTick(function(){return t.setHeight(e,i)});\"number\"===typeof e?(n.style[i]=e+\"px\",this.updateElsHeight()):\"string\"===typeof e&&(n.style[i]=e,this.updateElsHeight())}},e.prototype.setMaxHeight=function(e){return this.setHeight(e,\"max-height\")},e.prototype.updateElsHeight=function(){var e=this;if(!this.table.$ready)return Rn.a.nextTick(function(){return e.updateElsHeight()});var t=this.table.$refs,i=t.headerWrapper,n=t.appendWrapper,s=t.footerWrapper;if(this.appendHeight=n?n.offsetHeight:0,!this.showHeader||i){var r=this.headerHeight=this.showHeader?i.offsetHeight:0;if(this.showHeader&&i.offsetWidth>0&&(this.table.columns||[]).length>0&&r<2)return Rn.a.nextTick(function(){return e.updateElsHeight()});var o=this.tableHeight=this.table.$el.clientHeight;if(null!==this.height&&(!isNaN(this.height)||\"string\"===typeof this.height)){var a=this.footerHeight=s?s.offsetHeight:0;this.bodyHeight=o-r-a+(s?1:0)}this.fixedBodyHeight=this.scrollX?this.bodyHeight-this.gutterWidth:this.bodyHeight;var l=!this.table.data||0===this.table.data.length;this.viewportHeight=this.scrollX?o-(l?0:this.gutterWidth):o,this.updateScrollY(),this.notifyObservers(\"scrollable\")}},e.prototype.getFlattenColumns=function(){var e=[],t=this.table.columns;return t.forEach(function(t){t.isColumnGroup?e.push.apply(e,t.columns):e.push(t)}),e},e.prototype.updateColumnsWidth=function(){if(!Rn.a.prototype.$isServer){var e=this.fit,t=this.table.$el.clientWidth,i=0,n=this.getFlattenColumns(),s=n.filter(function(e){return\"number\"!==typeof e.width});if(n.forEach(function(e){\"number\"===typeof e.width&&e.realWidth&&(e.realWidth=null)}),s.length>0&&e){n.forEach(function(e){i+=e.width||e.minWidth||80});var r=this.scrollY?this.gutterWidth:0;if(i<=t-r){this.scrollX=!1;var o=t-r-i;if(1===s.length)s[0].realWidth=(s[0].minWidth||80)+o;else{var a=s.reduce(function(e,t){return e+(t.minWidth||80)},0),l=o/a,u=0;s.forEach(function(e,t){if(0!==t){var i=Math.floor((e.minWidth||80)*l);u+=i,e.realWidth=(e.minWidth||80)+i}}),s[0].realWidth=(s[0].minWidth||80)+o-u}}else this.scrollX=!0,s.forEach(function(e){e.realWidth=e.minWidth});this.bodyWidth=Math.max(i,t),this.table.resizeState.width=this.bodyWidth}else n.forEach(function(e){e.width||e.minWidth?e.realWidth=e.width||e.minWidth:e.realWidth=80,i+=e.realWidth}),this.scrollX=i>t,this.bodyWidth=i;var c=this.store.states.fixedColumns;if(c.length>0){var h=0;c.forEach(function(e){h+=e.realWidth||e.width}),this.fixedWidth=h}var d=this.store.states.rightFixedColumns;if(d.length>0){var p=0;d.forEach(function(e){p+=e.realWidth||e.width}),this.rightFixedWidth=p}this.notifyObservers(\"columns\")}},e.prototype.addObserver=function(e){this.observers.push(e)},e.prototype.removeObserver=function(e){var t=this.observers.indexOf(e);-1!==t&&this.observers.splice(t,1)},e.prototype.notifyObservers=function(e){var t=this,i=this.observers;i.forEach(function(i){switch(e){case\"columns\":i.onColumnsChange(t);break;case\"scrollable\":i.onScrollableChange(t);break;default:throw new Error(\"Table Layout don't have event \"+e+\".\")}})},e}(),us=ls,cs={created:function(){this.tableLayout.addObserver(this)},destroyed:function(){this.tableLayout.removeObserver(this)},computed:{tableLayout:function(){var e=this.layout;if(!e&&this.table&&(e=this.table.layout),!e)throw new Error(\"Can not find table layout.\");return e}},mounted:function(){this.onColumnsChange(this.tableLayout),this.onScrollableChange(this.tableLayout)},updated:function(){this.__updated__||(this.onColumnsChange(this.tableLayout),this.onScrollableChange(this.tableLayout),this.__updated__=!0)},methods:{onColumnsChange:function(){var e=this.$el.querySelectorAll(\"colgroup > col\");if(e.length){var t=this.tableLayout.getFlattenColumns(),i={};t.forEach(function(e){i[e.id]=e});for(var n=0,s=e.length;n<s;n++){var r=e[n],o=r.getAttribute(\"name\"),a=i[o];a&&r.setAttribute(\"width\",a.realWidth||a.width)}}},onScrollableChange:function(e){for(var t=this.$el.querySelectorAll(\"colgroup > col[name=gutter]\"),i=0,n=t.length;i<n;i++){var s=t[i];s.setAttribute(\"width\",e.scrollY?e.gutterWidth:\"0\")}for(var r=this.$el.querySelectorAll(\"th.gutter\"),o=0,a=r.length;o<a;o++){var l=r[o];l.style.width=e.scrollY?e.gutterWidth+\"px\":\"0\",l.style.display=e.scrollY?\"\":\"none\"}}}},hs=\"function\"===typeof Symbol&&\"symbol\"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},ds={name:\"ElTableBody\",mixins:[cs],components:{ElCheckbox:An.a,ElTooltip:st.a},props:{store:{required:!0},stripe:Boolean,context:{},rowClassName:[String,Function],rowStyle:[Object,Function],fixed:String,highlight:Boolean},render:function(e){var t=this,i=this.columns.map(function(e,i){return t.isColumnHidden(i)}),n=this.data;return this.store.states.lazy&&Object.keys(this.store.states.lazyTreeNodeMap).length&&(n=n.reduce(function(e,i){e.push(i);var n=t.store.table.getRowKey(i),s=t.store.states.treeData[n];if(s&&s.children){var r=[],o=function e(i){i&&i.forEach(function(i){r.push(t.store.states.lazyTreeNodeMap[i]),t.store.states.treeData[i]&&e(t.store.states.treeData[i].children)})};o(s.children),e=e.concat(r)}return e},[])),e(\"table\",{class:\"el-table__body\",attrs:{cellspacing:\"0\",cellpadding:\"0\",border:\"0\"}},[e(\"colgroup\",[this._l(this.columns,function(t){return e(\"col\",{attrs:{name:t.id}})})]),e(\"tbody\",[this._l(n,function(n,s){var r=t.table.rowKey?t.getKeyOfRow(n,s):s,o=t.treeData[r],a=t.getRowClass(n,s);o&&a.push(\"el-table__row--level-\"+o.level);var l=e(\"tr\",{directives:[{name:\"show\",value:!o||o.display}],style:t.rowStyle?t.getRowStyle(n,s):null,key:r,on:{dblclick:function(e){return t.handleDoubleClick(e,n)},click:function(e){return t.handleClick(e,n)},contextmenu:function(e){return t.handleContextMenu(e,n)},mouseenter:function(e){return t.handleMouseEnter(s)},mouseleave:function(e){return t.handleMouseLeave()}},class:a},[t._l(t.columns,function(a,l){var u=t.getSpan(n,a,s,l),c=u.rowspan,h=u.colspan;if(c&&h){var d={store:t.store,_self:t.context||t.table.$vnode.context,row:n,column:a,$index:s};return l===t.firstDefaultColumnIndex&&o&&(d.treeNode={hasChildren:o.hasChildren||o.children&&o.children.length,expanded:o.expanded,indent:o.level*t.treeIndent,level:o.level,loaded:o.loaded,rowKey:r}),e(\"td\",{style:t.getCellStyle(s,l,n,a),class:t.getCellClass(s,l,n,a),attrs:{rowspan:c,colspan:h},on:{mouseenter:function(e){return t.handleCellMouseEnter(e,n)},mouseleave:t.handleCellMouseLeave}},[a.renderCell.call(t._renderProxy,e,d,i[l])])}return\"\"})]);return t.hasExpandColumn&&t.store.isRowExpanded(n)?[l,e(\"tr\",[e(\"td\",{attrs:{colspan:t.columns.length},class:\"el-table__expanded-cell\"},[t.table.renderExpanded?t.table.renderExpanded(e,{row:n,$index:s,store:t.store}):\"\"])])]:l}).concat(e(\"el-tooltip\",{attrs:{effect:this.table.tooltipEffect,placement:\"top\",content:this.tooltipContent},ref:\"tooltip\"}))])])},computed:{table:function(){return this.$parent},data:function(){return this.store.states.data},treeData:function(){return this.store.states.treeData},columnsCount:function(){return this.store.states.columns.length},leftFixedLeafCount:function(){return this.store.states.fixedLeafColumnsLength},rightFixedLeafCount:function(){return this.store.states.rightFixedLeafColumnsLength},leftFixedCount:function(){return this.store.states.fixedColumns.length},rightFixedCount:function(){return this.store.states.rightFixedColumns.length},columns:function(){return this.store.states.columns},hasExpandColumn:function(){return this.columns.some(function(e){var t=e.type;return\"expand\"===t})},firstDefaultColumnIndex:function(){for(var e=0;e<this.columns.length;e++)if(\"default\"===this.columns[e].type)return e;return 0},treeIndent:function(){return this.store.states.indent}},data:function(){return{tooltipContent:\"\"}},created:function(){this.activateTooltip=L()(50,function(e){return e.handleShowPopper()})},methods:{getKeyOfRow:function(e,t){var i=this.table.rowKey;return i?Qn(e,i):t},isColumnHidden:function(e){return!0===this.fixed||\"left\"===this.fixed?e>=this.leftFixedLeafCount:\"right\"===this.fixed?e<this.columnsCount-this.rightFixedLeafCount:e<this.leftFixedLeafCount||e>=this.columnsCount-this.rightFixedLeafCount},getSpan:function(e,t,i,n){var s=1,r=1,o=this.table.spanMethod;if(\"function\"===typeof o){var a=o({row:e,column:t,rowIndex:i,columnIndex:n});Array.isArray(a)?(s=a[0],r=a[1]):\"object\"===(\"undefined\"===typeof a?\"undefined\":hs(a))&&(s=a.rowspan,r=a.colspan)}return{rowspan:s,colspan:r}},getRowStyle:function(e,t){var i=this.table.rowStyle;return\"function\"===typeof i?i.call(null,{row:e,rowIndex:t}):i},getRowClass:function(e,t){var i=[\"el-table__row\"];this.table.highlightCurrentRow&&e===this.store.states.currentRow&&i.push(\"current-row\"),t===this.store.states.hoverRow&&i.push(\"hover-row\"),this.stripe&&t%2===1&&i.push(\"el-table__row--striped\");var n=this.table.rowClassName;return\"string\"===typeof n?i.push(n):\"function\"===typeof n&&i.push(n.call(null,{row:e,rowIndex:t})),this.store.states.expandRows.indexOf(e)>-1&&i.push(\"expanded\"),i},getCellStyle:function(e,t,i,n){var s=this.table.cellStyle;return\"function\"===typeof s?s.call(null,{rowIndex:e,columnIndex:t,row:i,column:n}):s},getCellClass:function(e,t,i,n){var s=[n.id,n.align,n.className];this.isColumnHidden(t)&&s.push(\"is-hidden\");var r=this.table.cellClassName;return\"string\"===typeof r?s.push(r):\"function\"===typeof r&&s.push(r.call(null,{rowIndex:e,columnIndex:t,row:i,column:n})),s.join(\" \")},handleCellMouseEnter:function(e,t){var i=this.table,n=qn(e);if(n){var s=Xn(i,n),r=i.hoverState={cell:n,column:s,row:t};i.$emit(\"cell-mouse-enter\",r.row,r.column,r.cell,e)}var o=e.target.querySelector(\".cell\");if(Object(Ve[\"hasClass\"])(o,\"el-tooltip\")&&o.childNodes.length){var a=document.createRange();a.setStart(o,0),a.setEnd(o,o.childNodes.length);var l=a.getBoundingClientRect().width,u=(parseInt(Object(Ve[\"getStyle\"])(o,\"paddingLeft\"),10)||0)+(parseInt(Object(Ve[\"getStyle\"])(o,\"paddingRight\"),10)||0);if((l+u>o.offsetWidth||o.scrollWidth>o.offsetWidth)&&this.$refs.tooltip){var c=this.$refs.tooltip;this.tooltipContent=n.innerText||n.textContent,c.referenceElm=n,c.$refs.popper&&(c.$refs.popper.style.display=\"none\"),c.doDestroy(),c.setExpectedState(!0),this.activateTooltip(c)}}},handleCellMouseLeave:function(e){var t=this.$refs.tooltip;t&&(t.setExpectedState(!1),t.handleClosePopper());var i=qn(e);if(i){var n=this.table.hoverState||{};this.table.$emit(\"cell-mouse-leave\",n.row,n.column,n.cell,e)}},handleMouseEnter:function(e){this.store.commit(\"setHoverRow\",e)},handleMouseLeave:function(){this.store.commit(\"setHoverRow\",null)},handleContextMenu:function(e,t){this.handleEvent(e,t,\"contextmenu\")},handleDoubleClick:function(e,t){this.handleEvent(e,t,\"dblclick\")},handleClick:function(e,t){this.store.commit(\"setCurrentRow\",t),this.handleEvent(e,t,\"click\")},handleEvent:function(e,t,i){var n=this.table,s=qn(e),r=void 0;s&&(r=Xn(n,s),r&&n.$emit(\"cell-\"+i,t,r,s,e)),n.$emit(\"row-\"+i,t,r,e)},handleExpandClick:function(e,t){t.stopPropagation(),this.store.toggleRowExpansion(e)}}},ps=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"el-zoom-in-top\"}},[e.multiple?i(\"div\",{directives:[{name:\"clickoutside\",rawName:\"v-clickoutside\",value:e.handleOutsideClick,expression:\"handleOutsideClick\"},{name:\"show\",rawName:\"v-show\",value:e.showPopper,expression:\"showPopper\"}],staticClass:\"el-table-filter\"},[i(\"div\",{staticClass:\"el-table-filter__content\"},[i(\"el-scrollbar\",{attrs:{\"wrap-class\":\"el-table-filter__wrap\"}},[i(\"el-checkbox-group\",{staticClass:\"el-table-filter__checkbox-group\",model:{value:e.filteredValue,callback:function(t){e.filteredValue=t},expression:\"filteredValue\"}},e._l(e.filters,function(t){return i(\"el-checkbox\",{key:t.value,attrs:{label:t.value}},[e._v(e._s(t.text))])}),1)],1)],1),i(\"div\",{staticClass:\"el-table-filter__bottom\"},[i(\"button\",{class:{\"is-disabled\":0===e.filteredValue.length},attrs:{disabled:0===e.filteredValue.length},on:{click:e.handleConfirm}},[e._v(e._s(e.t(\"el.table.confirmFilter\")))]),i(\"button\",{on:{click:e.handleReset}},[e._v(e._s(e.t(\"el.table.resetFilter\")))])])]):i(\"div\",{directives:[{name:\"clickoutside\",rawName:\"v-clickoutside\",value:e.handleOutsideClick,expression:\"handleOutsideClick\"},{name:\"show\",rawName:\"v-show\",value:e.showPopper,expression:\"showPopper\"}],staticClass:\"el-table-filter\"},[i(\"ul\",{staticClass:\"el-table-filter__list\"},[i(\"li\",{staticClass:\"el-table-filter__list-item\",class:{\"is-active\":void 0===e.filterValue||null===e.filterValue},on:{click:function(t){e.handleSelect(null)}}},[e._v(e._s(e.t(\"el.table.clearFilter\")))]),e._l(e.filters,function(t){return i(\"li\",{key:t.value,staticClass:\"el-table-filter__list-item\",class:{\"is-active\":e.isActive(t)},attrs:{label:t.value},on:{click:function(i){e.handleSelect(t.value)}}},[e._v(e._s(t.text))])})],2)])])},fs=[];ps._withStripped=!0;var ms=[];!Rn.a.prototype.$isServer&&document.addEventListener(\"click\",function(e){ms.forEach(function(t){var i=e.target;t&&t.$el&&(i===t.$el||t.$el.contains(i)||t.handleOutsideClick&&t.handleOutsideClick(e))})});var vs={open:function(e){e&&ms.push(e)},close:function(e){var t=ms.indexOf(e);-1!==t&&ms.splice(e,1)}},gs=i(27),bs=i.n(gs),ys={name:\"ElTableFilterPanel\",mixins:[R.a,g.a],directives:{Clickoutside:B.a},components:{ElCheckbox:An.a,ElCheckboxGroup:bs.a},props:{placement:{type:String,default:\"bottom-end\"}},customRender:function(e){return e(\"div\",{class:\"el-table-filter\"},[e(\"div\",{class:\"el-table-filter__content\"}),e(\"div\",{class:\"el-table-filter__bottom\"},[e(\"button\",{on:{click:this.handleConfirm}},[this.t(\"el.table.confirmFilter\")]),e(\"button\",{on:{click:this.handleReset}},[this.t(\"el.table.resetFilter\")])])])},methods:{isActive:function(e){return e.value===this.filterValue},handleOutsideClick:function(){var e=this;setTimeout(function(){e.showPopper=!1},16)},handleConfirm:function(){this.confirmFilter(this.filteredValue),this.handleOutsideClick()},handleReset:function(){this.filteredValue=[],this.confirmFilter(this.filteredValue),this.handleOutsideClick()},handleSelect:function(e){this.filterValue=e,\"undefined\"!==typeof e&&null!==e?this.confirmFilter(this.filteredValue):this.confirmFilter([]),this.handleOutsideClick()},confirmFilter:function(e){this.table.store.commit(\"filterChange\",{column:this.column,values:e}),this.table.store.updateAllSelected()}},data:function(){return{table:null,cell:null,column:null}},computed:{filters:function(){return this.column&&this.column.filters},filterValue:{get:function(){return(this.column.filteredValue||[])[0]},set:function(e){this.filteredValue&&(\"undefined\"!==typeof e&&null!==e?this.filteredValue.splice(0,1,e):this.filteredValue.splice(0,1))}},filteredValue:{get:function(){return this.column&&this.column.filteredValue||[]},set:function(e){this.column&&(this.column.filteredValue=e)}},multiple:function(){return!this.column||this.column.filterMultiple}},mounted:function(){var e=this;this.popperElm=this.$el,this.referenceElm=this.cell,this.table.bodyWrapper.addEventListener(\"scroll\",function(){e.updatePopper()}),this.$watch(\"showPopper\",function(t){e.column&&(e.column.filterOpened=t),t?vs.open(e):vs.close(e)})},watch:{showPopper:function(e){!0===e&&parseInt(this.popperJS._popper.style.zIndex,10)<w[\"PopupManager\"].zIndex&&(this.popperJS._popper.style.zIndex=w[\"PopupManager\"].nextZIndex())}}},_s=ys,xs=a(_s,ps,fs,!1,null,null,null);xs.options.__file=\"packages/table/src/filter-panel.vue\";var Cs=xs.exports,ws=function e(t){var i=[];return t.forEach(function(t){t.children?(i.push(t),i.push.apply(i,e(t.children))):i.push(t)}),i},ks=function(e){var t=1,i=function e(i,n){if(n&&(i.level=n.level+1,t<i.level&&(t=i.level)),i.children){var s=0;i.children.forEach(function(t){e(t,i),s+=t.colSpan}),i.colSpan=s}else i.colSpan=1};e.forEach(function(e){e.level=1,i(e)});for(var n=[],s=0;s<t;s++)n.push([]);var r=ws(e);return r.forEach(function(e){e.children?e.rowSpan=1:e.rowSpan=t-e.level+1,n[e.level-1].push(e)}),n},Ss={name:\"ElTableHeader\",mixins:[cs],render:function(e){var t=this,i=this.store.states.originColumns,n=ks(i,this.columns),s=n.length>1;return s&&(this.$parent.isGroup=!0),e(\"table\",{class:\"el-table__header\",attrs:{cellspacing:\"0\",cellpadding:\"0\",border:\"0\"}},[e(\"colgroup\",[this._l(this.columns,function(t){return e(\"col\",{attrs:{name:t.id}})}),this.hasGutter?e(\"col\",{attrs:{name:\"gutter\"}}):\"\"]),e(\"thead\",{class:[{\"is-group\":s,\"has-gutter\":this.hasGutter}]},[this._l(n,function(i,n){return e(\"tr\",{style:t.getHeaderRowStyle(n),class:t.getHeaderRowClass(n)},[t._l(i,function(s,r){return e(\"th\",{attrs:{colspan:s.colSpan,rowspan:s.rowSpan},on:{mousemove:function(e){return t.handleMouseMove(e,s)},mouseout:t.handleMouseOut,mousedown:function(e){return t.handleMouseDown(e,s)},click:function(e){return t.handleHeaderClick(e,s)},contextmenu:function(e){return t.handleHeaderContextMenu(e,s)}},style:t.getHeaderCellStyle(n,r,i,s),class:t.getHeaderCellClass(n,r,i,s),key:s.id},[e(\"div\",{class:[\"cell\",s.filteredValue&&s.filteredValue.length>0?\"highlight\":\"\",s.labelClassName]},[s.renderHeader?s.renderHeader.call(t._renderProxy,e,{column:s,$index:r,store:t.store,_self:t.$parent.$vnode.context}):s.label,s.sortable?e(\"span\",{class:\"caret-wrapper\",on:{click:function(e){return t.handleSortClick(e,s)}}},[e(\"i\",{class:\"sort-caret ascending\",on:{click:function(e){return t.handleSortClick(e,s,\"ascending\")}}}),e(\"i\",{class:\"sort-caret descending\",on:{click:function(e){return t.handleSortClick(e,s,\"descending\")}}})]):\"\",s.filterable?e(\"span\",{class:\"el-table__column-filter-trigger\",on:{click:function(e){return t.handleFilterClick(e,s)}}},[e(\"i\",{class:[\"el-icon-arrow-down\",s.filterOpened?\"el-icon-arrow-up\":\"\"]})]):\"\"])])}),t.hasGutter?e(\"th\",{class:\"gutter\"}):\"\"])})])])},props:{fixed:String,store:{required:!0},border:Boolean,defaultSort:{type:Object,default:function(){return{prop:\"\",order:\"\"}}}},components:{ElCheckbox:An.a,ElTag:Qi.a},computed:{table:function(){return this.$parent},isAllSelected:function(){return this.store.states.isAllSelected},columnsCount:function(){return this.store.states.columns.length},leftFixedCount:function(){return this.store.states.fixedColumns.length},rightFixedCount:function(){return this.store.states.rightFixedColumns.length},leftFixedLeafCount:function(){return this.store.states.fixedLeafColumnsLength},rightFixedLeafCount:function(){return this.store.states.rightFixedLeafColumnsLength},columns:function(){return this.store.states.columns},hasGutter:function(){return!this.fixed&&this.tableLayout.gutterWidth}},created:function(){this.filterPanels={}},mounted:function(){var e=this.defaultSort,t=e.prop,i=e.order;this.store.commit(\"sort\",{prop:t,order:i})},beforeDestroy:function(){var e=this.filterPanels;for(var t in e)e.hasOwnProperty(t)&&e[t]&&e[t].$destroy(!0)},methods:{isCellHidden:function(e,t){for(var i=0,n=0;n<e;n++)i+=t[n].colSpan;var s=i+t[e].colSpan-1;return!0===this.fixed||\"left\"===this.fixed?s>=this.leftFixedLeafCount:\"right\"===this.fixed?i<this.columnsCount-this.rightFixedLeafCount:s<this.leftFixedLeafCount||i>=this.columnsCount-this.rightFixedLeafCount},getHeaderRowStyle:function(e){var t=this.table.headerRowStyle;return\"function\"===typeof t?t.call(null,{rowIndex:e}):t},getHeaderRowClass:function(e){var t=[],i=this.table.headerRowClassName;return\"string\"===typeof i?t.push(i):\"function\"===typeof i&&t.push(i.call(null,{rowIndex:e})),t.join(\" \")},getHeaderCellStyle:function(e,t,i,n){var s=this.table.headerCellStyle;return\"function\"===typeof s?s.call(null,{rowIndex:e,columnIndex:t,row:i,column:n}):s},getHeaderCellClass:function(e,t,i,n){var s=[n.id,n.order,n.headerAlign,n.className,n.labelClassName];0===e&&this.isCellHidden(t,i)&&s.push(\"is-hidden\"),n.children||s.push(\"is-leaf\"),n.sortable&&s.push(\"is-sortable\");var r=this.table.headerCellClassName;return\"string\"===typeof r?s.push(r):\"function\"===typeof r&&s.push(r.call(null,{rowIndex:e,columnIndex:t,row:i,column:n})),s.join(\" \")},toggleAllSelection:function(e){e.stopPropagation(),this.store.commit(\"toggleAllSelection\")},handleFilterClick:function(e,t){e.stopPropagation();var i=e.target,n=\"TH\"===i.tagName?i:i.parentNode;n=n.querySelector(\".el-table__column-filter-trigger\")||n;var s=this.$parent,r=this.filterPanels[t.id];r&&t.filterOpened?r.showPopper=!1:(r||(r=new Rn.a(Cs),this.filterPanels[t.id]=r,t.filterPlacement&&(r.placement=t.filterPlacement),r.table=s,r.cell=n,r.column=t,!this.$isServer&&r.$mount(document.createElement(\"div\"))),setTimeout(function(){r.showPopper=!0},16))},handleHeaderClick:function(e,t){!t.filters&&t.sortable?this.handleSortClick(e,t):t.filterable&&!t.sortable&&this.handleFilterClick(e,t),this.$parent.$emit(\"header-click\",t,e)},handleHeaderContextMenu:function(e,t){this.$parent.$emit(\"header-contextmenu\",t,e)},handleMouseDown:function(e,t){var i=this;if(!this.$isServer&&!(t.children&&t.children.length>0)&&this.draggingColumn&&this.border){this.dragging=!0,this.$parent.resizeProxyVisible=!0;var n=this.$parent,s=n.$el,r=s.getBoundingClientRect().left,o=this.$el.querySelector(\"th.\"+t.id),a=o.getBoundingClientRect(),l=a.left-r+30;Object(Ve[\"addClass\"])(o,\"noclick\"),this.dragState={startMouseLeft:e.clientX,startLeft:a.right-r,startColumnLeft:a.left-r,tableLeft:r};var u=n.$refs.resizeProxy;u.style.left=this.dragState.startLeft+\"px\",document.onselectstart=function(){return!1},document.ondragstart=function(){return!1};var c=function(e){var t=e.clientX-i.dragState.startMouseLeft,n=i.dragState.startLeft+t;u.style.left=Math.max(l,n)+\"px\"},h=function s(){if(i.dragging){var r=i.dragState,a=r.startColumnLeft,l=r.startLeft,h=parseInt(u.style.left,10),d=h-a;t.width=t.realWidth=d,n.$emit(\"header-dragend\",t.width,l-a,t,e),i.store.scheduleLayout(),document.body.style.cursor=\"\",i.dragging=!1,i.draggingColumn=null,i.dragState={},n.resizeProxyVisible=!1}document.removeEventListener(\"mousemove\",c),document.removeEventListener(\"mouseup\",s),document.onselectstart=null,document.ondragstart=null,setTimeout(function(){Object(Ve[\"removeClass\"])(o,\"noclick\")},0)};document.addEventListener(\"mousemove\",c),document.addEventListener(\"mouseup\",h)}},handleMouseMove:function(e,t){if(!(t.children&&t.children.length>0)){var i=e.target;while(i&&\"TH\"!==i.tagName)i=i.parentNode;if(t&&t.resizable&&!this.dragging&&this.border){var n=i.getBoundingClientRect(),s=document.body.style;n.width>12&&n.right-e.pageX<8?(s.cursor=\"col-resize\",Object(Ve[\"hasClass\"])(i,\"is-sortable\")&&(i.style.cursor=\"col-resize\"),this.draggingColumn=t):this.dragging||(s.cursor=\"\",Object(Ve[\"hasClass\"])(i,\"is-sortable\")&&(i.style.cursor=\"pointer\"),this.draggingColumn=null)}}},handleMouseOut:function(){this.$isServer||(document.body.style.cursor=\"\")},toggleOrder:function(e){var t=e.order,i=e.sortOrders;if(\"\"===t)return i[0];var n=i.indexOf(t||null);return i[n>i.length-2?0:n+1]},handleSortClick:function(e,t,i){e.stopPropagation();var n=t.order===i?null:i||this.toggleOrder(t),s=e.target;while(s&&\"TH\"!==s.tagName)s=s.parentNode;if(s&&\"TH\"===s.tagName&&Object(Ve[\"hasClass\"])(s,\"noclick\"))Object(Ve[\"removeClass\"])(s,\"noclick\");else if(t.sortable){var r=this.store.states,o=r.sortProp,a=void 0,l=r.sortingColumn;(l!==t||l===t&&null===l.order)&&(l&&(l.order=null),r.sortingColumn=t,o=t.property),n?a=t.order=n:(a=t.order=null,r.sortingColumn=null,o=null),r.sortProp=o,r.sortOrder=a,this.store.commit(\"changeSortCondition\")}}},data:function(){return{draggingColumn:null,dragging:!1,dragState:{}}}},$s={name:\"ElTableFooter\",mixins:[cs],render:function(e){var t=this,i=[];return this.summaryMethod?i=this.summaryMethod({columns:this.columns,data:this.store.states.data}):this.columns.forEach(function(e,n){if(0!==n){var s=t.store.states.data.map(function(t){return Number(t[e.property])}),r=[],o=!0;s.forEach(function(e){if(!isNaN(e)){o=!1;var t=(\"\"+e).split(\".\")[1];r.push(t?t.length:0)}});var a=Math.max.apply(null,r);i[n]=o?\"\":s.reduce(function(e,t){var i=Number(t);return isNaN(i)?e:parseFloat((e+t).toFixed(Math.min(a,20)))},0)}else i[n]=t.sumText}),e(\"table\",{class:\"el-table__footer\",attrs:{cellspacing:\"0\",cellpadding:\"0\",border:\"0\"}},[e(\"colgroup\",[this._l(this.columns,function(t){return e(\"col\",{attrs:{name:t.id}})}),this.hasGutter?e(\"col\",{attrs:{name:\"gutter\"}}):\"\"]),e(\"tbody\",{class:[{\"has-gutter\":this.hasGutter}]},[e(\"tr\",[this._l(this.columns,function(n,s){return e(\"td\",{attrs:{colspan:n.colSpan,rowspan:n.rowSpan},class:t.getRowClasses(n,s)},[e(\"div\",{class:[\"cell\",n.labelClassName]},[i[s]])])}),this.hasGutter?e(\"th\",{class:\"gutter\"}):\"\"])])])},props:{fixed:String,store:{required:!0},summaryMethod:Function,sumText:String,border:Boolean,defaultSort:{type:Object,default:function(){return{prop:\"\",order:\"\"}}}},computed:{table:function(){return this.$parent},isAllSelected:function(){return this.store.states.isAllSelected},columnsCount:function(){return this.store.states.columns.length},leftFixedCount:function(){return this.store.states.fixedColumns.length},leftFixedLeafCount:function(){return this.store.states.fixedLeafColumnsLength},rightFixedLeafCount:function(){return this.store.states.rightFixedLeafColumnsLength},rightFixedCount:function(){return this.store.states.rightFixedColumns.length},columns:function(){return this.store.states.columns},hasGutter:function(){return!this.fixed&&this.tableLayout.gutterWidth}},methods:{isCellHidden:function(e,t,i){if(!0===this.fixed||\"left\"===this.fixed)return e>=this.leftFixedLeafCount;if(\"right\"===this.fixed){for(var n=0,s=0;s<e;s++)n+=t[s].colSpan;return n<this.columnsCount-this.rightFixedLeafCount}return!(this.fixed||!i.fixed)||(e<this.leftFixedCount||e>=this.columnsCount-this.rightFixedCount)},getRowClasses:function(e,t){var i=[e.id,e.align,e.labelClassName];return e.className&&i.push(e.className),this.isCellHidden(t,this.columns,e)&&i.push(\"is-hidden\"),e.children||i.push(\"is-leaf\"),i}}},Ds=function(e){if(!e)return e;var t=[],i=function e(i){i.forEach(function(i){t.push(i),Array.isArray(i.children)&&e(i.children)})};return i(e),e.length===t.length?e:t},Es=1,Ts={name:\"ElTable\",mixins:[g.a,$.a],directives:{Mousewheel:jn},props:{data:{type:Array,default:function(){return[]}},size:String,width:[String,Number],height:[String,Number],maxHeight:[String,Number],fit:{type:Boolean,default:!0},stripe:Boolean,border:Boolean,rowKey:[String,Function],context:{},showHeader:{type:Boolean,default:!0},showSummary:Boolean,sumText:String,summaryMethod:Function,rowClassName:[String,Function],rowStyle:[Object,Function],cellClassName:[String,Function],cellStyle:[Object,Function],headerRowClassName:[String,Function],headerRowStyle:[Object,Function],headerCellClassName:[String,Function],headerCellStyle:[Object,Function],highlightCurrentRow:Boolean,currentRowKey:[String,Number],emptyText:String,expandRowKeys:Array,defaultExpandAll:Boolean,defaultSort:Object,tooltipEffect:String,spanMethod:Function,selectOnIndeterminate:{type:Boolean,default:!0},indent:{type:Number,default:16},lazy:Boolean,load:Function},components:{TableHeader:Ss,TableFooter:$s,TableBody:ds,ElCheckbox:An.a},methods:{getMigratingConfig:function(){return{events:{expand:\"expand is renamed to expand-change\"}}},setCurrentRow:function(e){this.store.commit(\"setCurrentRow\",e)},toggleRowSelection:function(e,t){this.store.toggleRowSelection(e,t),this.store.updateAllSelected()},toggleRowExpansion:function(e,t){this.store.toggleRowExpansion(e,t)},clearSelection:function(){this.store.clearSelection()},clearFilter:function(e){this.store.clearFilter(e)},clearSort:function(){this.store.clearSort()},handleMouseLeave:function(){this.store.commit(\"setHoverRow\",null),this.hoverState&&(this.hoverState=null)},updateScrollY:function(){this.layout.updateScrollY(),this.layout.updateColumnsWidth()},handleFixedMousewheel:function(e,t){var i=this.bodyWrapper;if(Math.abs(t.spinY)>0){var n=i.scrollTop;t.pixelY<0&&0!==n&&e.preventDefault(),t.pixelY>0&&i.scrollHeight-i.clientHeight>n&&e.preventDefault(),i.scrollTop+=Math.ceil(t.pixelY/5)}else i.scrollLeft+=Math.ceil(t.pixelX/5)},handleHeaderFooterMousewheel:function(e,t){var i=t.pixelX,n=t.pixelY;Math.abs(i)>=Math.abs(n)&&(e.preventDefault(),this.bodyWrapper.scrollLeft+=t.pixelX/5)},bindEvents:function(){var e=this.$refs,t=e.headerWrapper,i=e.footerWrapper,n=this.$refs,s=this;this.bodyWrapper.addEventListener(\"scroll\",function(){t&&(t.scrollLeft=this.scrollLeft),i&&(i.scrollLeft=this.scrollLeft),n.fixedBodyWrapper&&(n.fixedBodyWrapper.scrollTop=this.scrollTop),n.rightFixedBodyWrapper&&(n.rightFixedBodyWrapper.scrollTop=this.scrollTop);var e=this.scrollWidth-this.offsetWidth-1,r=this.scrollLeft;s.scrollPosition=r>=e?\"right\":0===r?\"left\":\"middle\"}),this.fit&&Object(Ji[\"addResizeListener\"])(this.$el,this.resizeListener)},resizeListener:function(){if(this.$ready){var e=!1,t=this.$el,i=this.resizeState,n=i.width,s=i.height,r=t.offsetWidth;n!==r&&(e=!0);var o=t.offsetHeight;(this.height||this.shouldUpdateHeight)&&s!==o&&(e=!0),e&&(this.resizeState.width=r,this.resizeState.height=o,this.doLayout())}},doLayout:function(){this.layout.updateColumnsWidth(),this.shouldUpdateHeight&&this.layout.updateElsHeight()},sort:function(e,t){this.store.commit(\"sort\",{prop:e,order:t})},toggleAllSelection:function(){this.store.commit(\"toggleAllSelection\")},getRowKey:function(e){var t=Qn(e,this.store.states.rowKey);if(!t)throw new Error(\"if there's nested data, rowKey is required.\");return t},getTableTreeData:function(e){var t=this,i={},n=function e(n,s,r){n.forEach(function(n){var o=t.getRowKey(n);i[o]={display:!1,level:r},s.children.push(o),Array.isArray(n.children)&&n.children.length&&(i[o].children=[],i[o].expanded=!1,e(n.children,i[o],r+1))})};return e&&e.forEach(function(e){var s=Array.isArray(e.children)&&e.children.length;if(s||e.hasChildren){var r=t.getRowKey(e),o={level:0,expanded:!1,display:!0,children:[]};s?(i[r]=o,n(e.children,i[r],1)):e.hasChildren&&t.lazy&&(o.hasChildren=!0,o.loaded=!1,i[r]=o)}}),i}},created:function(){var e=this;this.tableId=\"el-table_\"+Es++,this.debouncedUpdateLayout=L()(50,function(){return e.doLayout()})},computed:{tableSize:function(){return this.size||(this.$ELEMENT||{}).size},bodyWrapper:function(){return this.$refs.bodyWrapper},shouldUpdateHeight:function(){return this.height||this.maxHeight||this.fixedColumns.length>0||this.rightFixedColumns.length>0},selection:function(){return this.store.states.selection},columns:function(){return this.store.states.columns},tableData:function(){return this.store.states.data},fixedColumns:function(){return this.store.states.fixedColumns},rightFixedColumns:function(){return this.store.states.rightFixedColumns},bodyWidth:function(){var e=this.layout,t=e.bodyWidth,i=e.scrollY,n=e.gutterWidth;return t?t-(i?n:0)+\"px\":\"\"},bodyHeight:function(){return this.height?{height:this.layout.bodyHeight?this.layout.bodyHeight+\"px\":\"\"}:this.maxHeight?{\"max-height\":(this.showHeader?this.maxHeight-this.layout.headerHeight-this.layout.footerHeight:this.maxHeight-this.layout.footerHeight)+\"px\"}:{}},fixedBodyHeight:function(){if(this.height)return{height:this.layout.fixedBodyHeight?this.layout.fixedBodyHeight+\"px\":\"\"};if(this.maxHeight){var e=this.layout.scrollX?this.maxHeight-this.layout.gutterWidth:this.maxHeight;return this.showHeader&&(e-=this.layout.headerHeight),e-=this.layout.footerHeight,{\"max-height\":e+\"px\"}}return{}},fixedHeight:function(){return this.maxHeight?this.showSummary?{bottom:0}:{bottom:this.layout.scrollX&&this.data.length?this.layout.gutterWidth+\"px\":\"\"}:this.showSummary?{height:this.layout.tableHeight?this.layout.tableHeight+\"px\":\"\"}:{height:this.layout.viewportHeight?this.layout.viewportHeight+\"px\":\"\"}}},watch:{height:{immediate:!0,handler:function(e){this.layout.setHeight(e)}},maxHeight:{immediate:!0,handler:function(e){this.layout.setMaxHeight(e)}},currentRowKey:function(e){this.store.setCurrentRowKey(e)},data:{immediate:!0,handler:function(e){var t=this;this.store.states.treeData=this.getTableTreeData(e),e=Ds(e),this.store.commit(\"setData\",e),this.$ready&&this.$nextTick(function(){t.doLayout()})}},expandRowKeys:{immediate:!0,handler:function(e){e&&this.store.setExpandRowKeys(e)}}},destroyed:function(){this.resizeListener&&Object(Ji[\"removeResizeListener\"])(this.$el,this.resizeListener)},mounted:function(){var e=this;this.bindEvents(),this.store.updateColumns(),this.doLayout(),this.resizeState={width:this.$el.offsetWidth,height:this.$el.offsetHeight},this.store.states.columns.forEach(function(t){t.filteredValue&&t.filteredValue.length&&e.store.commit(\"filterChange\",{column:t,values:t.filteredValue,silent:!0})}),this.$ready=!0},data:function(){var e=new ss(this,{rowKey:this.rowKey,defaultExpandAll:this.defaultExpandAll,selectOnIndeterminate:this.selectOnIndeterminate,indent:this.indent,lazy:this.lazy}),t=new us({store:e,table:this,fit:this.fit,showHeader:this.showHeader});return{layout:t,store:e,isHidden:!1,renderExpanded:null,resizeProxyVisible:!1,resizeState:{width:null,height:null},isGroup:!1,scrollPosition:\"left\"}}},Os=Ts,Is=a(Os,Mn,Nn,!1,null,null,null);Is.options.__file=\"packages/table/src/table.vue\";var Ps=Is.exports;Ps.install=function(e){e.component(Ps.name,Ps)};var Ms=Ps,Ns=1,Fs={default:{order:\"\"},selection:{width:48,minWidth:48,realWidth:48,order:\"\",className:\"el-table-column--selection\"},expand:{width:48,minWidth:48,realWidth:48,order:\"\"},index:{width:48,minWidth:48,realWidth:48,order:\"\"}},As={selection:{renderHeader:function(e,t){var i=t.store;return e(\"el-checkbox\",{attrs:{disabled:i.states.data&&0===i.states.data.length,indeterminate:i.states.selection.length>0&&!this.isAllSelected,value:this.isAllSelected},nativeOn:{click:this.toggleAllSelection}})},renderCell:function(e,t){var i=t.row,n=t.column,s=t.store,r=t.$index;return e(\"el-checkbox\",{nativeOn:{click:function(e){return e.stopPropagation()}},attrs:{value:s.isSelected(i),disabled:!!n.selectable&&!n.selectable.call(null,i,r)},on:{input:function(){s.commit(\"rowSelectedChanged\",i)}}})},sortable:!1,resizable:!1},index:{renderHeader:function(e,t){var i=t.column;return i.label||\"#\"},renderCell:function(e,t){var i=t.$index,n=t.column,s=i+1,r=n.index;return\"number\"===typeof r?s=i+r:\"function\"===typeof r&&(s=r(i)),e(\"div\",[s])},sortable:!1},expand:{renderHeader:function(e,t){var i=t.column;return i.label||\"\"},renderCell:function(e,t,i){var n=t.row,s=t.store,r=s.states.expandRows.indexOf(n)>-1;return e(\"div\",{class:\"el-table__expand-icon \"+(r?\"el-table__expand-icon--expanded\":\"\"),on:{click:function(e){return i.handleExpandClick(n,e)}}},[e(\"i\",{class:\"el-icon el-icon-arrow-right\"})])},sortable:!1,resizable:!1,className:\"el-table__expand-column\"}},Ls=function(e,t){var i={};for(var n in St()(i,Fs[e||\"default\"]),t)if(t.hasOwnProperty(n)){var s=t[n];\"undefined\"!==typeof s&&(i[n]=s)}return i.minWidth||(i.minWidth=80),i.realWidth=void 0===i.width?i.minWidth:i.width,i},Vs=function(e,t){var i=t.row,n=t.column,s=t.$index,r=n.property,o=r&&Object(b[\"getPropByPath\"])(i,r).v;return n&&n.formatter?n.formatter(i,n,o,s):o},Bs=function(e){return void 0!==e&&(e=parseInt(e,10),isNaN(e)&&(e=null)),e},zs=function(e){return void 0!==e&&(e=parseInt(e,10),isNaN(e)&&(e=80)),e},js={name:\"ElTableColumn\",props:{type:{type:String,default:\"default\"},label:String,className:String,labelClassName:String,property:String,prop:String,width:{},minWidth:{},renderHeader:Function,sortable:{type:[String,Boolean],default:!1},sortMethod:Function,sortBy:[String,Function,Array],resizable:{type:Boolean,default:!0},context:{},columnKey:String,align:String,headerAlign:String,showTooltipWhenOverflow:Boolean,showOverflowTooltip:Boolean,fixed:[Boolean,String],formatter:Function,selectable:Function,reserveSelection:Boolean,filterMethod:Function,filteredValue:Array,filters:Array,filterPlacement:String,filterMultiple:{type:Boolean,default:!0},index:[Number,Function],sortOrders:{type:Array,default:function(){return[\"ascending\",\"descending\",null]},validator:function(e){return e.every(function(e){return[\"ascending\",\"descending\",null].indexOf(e)>-1})}}},data:function(){return{isSubColumn:!1,columns:[]}},beforeCreate:function(){this.row={},this.column={},this.$index=0},components:{ElCheckbox:An.a,ElTag:Qi.a},computed:{owner:function(){var e=this.$parent;while(e&&!e.tableId)e=e.$parent;return e},columnOrTableParent:function(){var e=this.$parent;while(e&&!e.tableId&&!e.columnId)e=e.$parent;return e}},created:function(){var e=this;this.$createElement;this.customRender=this.$options.render,this.$options.render=function(t){return t(\"div\",e.$slots.default)};var t=this.columnOrTableParent,i=this.owner;this.isSubColumn=i!==t,this.columnId=(t.tableId||t.columnId)+\"_column_\"+Ns++;var n=this.type,s=Bs(this.width),r=zs(this.minWidth),o=!1,a=Ls(n,{id:this.columnId,columnKey:this.columnKey,label:this.label,className:this.className,labelClassName:this.labelClassName,property:this.prop||this.property,type:n,renderCell:null,renderHeader:this.renderHeader,minWidth:r,width:s,isColumnGroup:o,context:this.context,align:this.align?\"is-\"+this.align:null,headerAlign:this.headerAlign?\"is-\"+this.headerAlign:this.align?\"is-\"+this.align:null,sortable:\"\"===this.sortable||this.sortable,sortMethod:this.sortMethod,sortBy:this.sortBy,resizable:this.resizable,showOverflowTooltip:this.showOverflowTooltip||this.showTooltipWhenOverflow,formatter:this.formatter,selectable:this.selectable,reserveSelection:this.reserveSelection,fixed:\"\"===this.fixed||this.fixed,filterMethod:this.filterMethod,filters:this.filters,filterable:this.filters||this.filterMethod,filterMultiple:this.filterMultiple,filterOpened:!1,filteredValue:this.filteredValue||[],filterPlacement:this.filterPlacement||\"\",index:this.index,sortOrders:this.sortOrders}),l=As[n]||{};Object.keys(l).forEach(function(e){var t=l[e];void 0!==t&&(\"renderHeader\"===e&&(\"selection\"===n&&a[e]?console.warn(\"[Element Warn][TableColumn]Selection column doesn't allow to set render-header function.\"):t=a[e]||t),a[e]=\"className\"===e?a[e]+\" \"+t:t)}),this.renderHeader&&console.warn(\"[Element Warn][TableColumn]Comparing to render-header, scoped-slot header is easier to use. We recommend users to use scoped-slot header.\"),this.columnConfig=a;var u=a.renderCell,c=this;if(\"expand\"===n)return i.renderExpanded=function(e,t){return c.$scopedSlots.default?c.$scopedSlots.default(t):c.$slots.default},void(a.renderCell=function(e,t){return e(\"div\",{class:\"cell\"},[u(e,t,this._renderProxy)])});a.renderCell=function(e,t){c.$scopedSlots.default&&(u=function(){return c.$scopedSlots.default(t)}),u||(u=Vs);var i=[c.renderTreeCell(t),u(e,t)];return c.showOverflowTooltip||c.showTooltipWhenOverflow?e(\"div\",{class:\"cell el-tooltip\",style:{width:(t.column.realWidth||t.column.width)-1+\"px\"}},[i]):e(\"div\",{class:\"cell\"},[i])}},destroyed:function(){if(this.$parent){var e=this.$parent;this.owner.store.commit(\"removeColumn\",this.columnConfig,this.isSubColumn?e.columnConfig:null)}},watch:{label:function(e){this.columnConfig&&(this.columnConfig.label=e)},prop:function(e){this.columnConfig&&(this.columnConfig.property=e)},property:function(e){this.columnConfig&&(this.columnConfig.property=e)},filters:function(e){this.columnConfig&&(this.columnConfig.filters=e)},filterMultiple:function(e){this.columnConfig&&(this.columnConfig.filterMultiple=e)},align:function(e){this.columnConfig&&(this.columnConfig.align=e?\"is-\"+e:null,this.headerAlign||(this.columnConfig.headerAlign=e?\"is-\"+e:null))},headerAlign:function(e){this.columnConfig&&(this.columnConfig.headerAlign=\"is-\"+(e||this.align))},width:function(e){this.columnConfig&&(this.columnConfig.width=Bs(e),this.owner.store.scheduleLayout())},minWidth:function(e){this.columnConfig&&(this.columnConfig.minWidth=zs(e),this.owner.store.scheduleLayout())},fixed:function(e){this.columnConfig&&(this.columnConfig.fixed=e,this.owner.store.scheduleLayout(!0))},sortable:function(e){this.columnConfig&&(this.columnConfig.sortable=e)},index:function(e){this.columnConfig&&(this.columnConfig.index=e)},formatter:function(e){this.columnConfig&&(this.columnConfig.formatter=e)},className:function(e){this.columnConfig&&(this.columnConfig.className=e)},labelClassName:function(e){this.columnConfig&&(this.columnConfig.labelClassName=e)}},methods:{renderTreeCell:function(e){var t=this.$createElement;if(!e.treeNode)return null;var i=[];return i.push(t(\"span\",{class:\"el-table__indent\",style:{\"padding-left\":e.treeNode.indent+\"px\"}})),e.treeNode.hasChildren?i.push(t(\"div\",{class:[\"el-table__expand-icon\",e.treeNode.expanded?\"el-table__expand-icon--expanded\":\"\"],on:{click:this.handleTreeExpandIconClick.bind(this,e)}},[t(\"i\",{class:\"el-icon el-icon-arrow-right\"})])):i.push(t(\"span\",{class:\"el-table__placeholder\"})),i},handleTreeExpandIconClick:function(e,t){t.stopPropagation(),e.store.states.lazy&&!e.treeNode.loaded?e.store.loadData(e.row,e.treeNode):e.store.toggleTreeExpansion(e.treeNode.rowKey)}},mounted:function(){var e=this,t=this.owner,i=this.columnOrTableParent,n=void 0;n=this.isSubColumn?[].indexOf.call(i.$el.children,this.$el):[].indexOf.call(i.$refs.hiddenColumns.children,this.$el),this.$scopedSlots.header&&(\"selection\"===this.type?console.warn(\"[Element Warn][TableColumn]Selection column doesn't allow to set scoped-slot header.\"):this.columnConfig.renderHeader=function(t,i){return e.$scopedSlots.header(i)}),t.store.commit(\"insertColumn\",this.columnConfig,n,this.isSubColumn?i.columnConfig:null)},install:function(e){e.component(js.name,js)}},Hs=js,Rs=function(){var e=this,t=e.$createElement,i=e._self._c||t;return e.ranged?i(\"div\",{directives:[{name:\"clickoutside\",rawName:\"v-clickoutside\",value:e.handleClose,expression:\"handleClose\"}],ref:\"reference\",staticClass:\"el-date-editor el-range-editor el-input__inner\",class:[\"el-date-editor--\"+e.type,e.pickerSize?\"el-range-editor--\"+e.pickerSize:\"\",e.pickerDisabled?\"is-disabled\":\"\",e.pickerVisible?\"is-active\":\"\"],on:{click:e.handleRangeClick,mouseenter:e.handleMouseEnter,mouseleave:function(t){e.showClose=!1},keydown:e.handleKeydown}},[i(\"i\",{class:[\"el-input__icon\",\"el-range__icon\",e.triggerClass]}),i(\"input\",e._b({staticClass:\"el-range-input\",attrs:{autocomplete:\"off\",placeholder:e.startPlaceholder,disabled:e.pickerDisabled,readonly:!e.editable||e.readonly,name:e.name&&e.name[0]},domProps:{value:e.displayValue&&e.displayValue[0]},on:{input:e.handleStartInput,change:e.handleStartChange,focus:e.handleFocus}},\"input\",e.firstInputId,!1)),e._t(\"range-separator\",[i(\"span\",{staticClass:\"el-range-separator\"},[e._v(e._s(e.rangeSeparator))])]),i(\"input\",e._b({staticClass:\"el-range-input\",attrs:{autocomplete:\"off\",placeholder:e.endPlaceholder,disabled:e.pickerDisabled,readonly:!e.editable||e.readonly,name:e.name&&e.name[1]},domProps:{value:e.displayValue&&e.displayValue[1]},on:{input:e.handleEndInput,change:e.handleEndChange,focus:e.handleFocus}},\"input\",e.secondInputId,!1)),e.haveTrigger?i(\"i\",{staticClass:\"el-input__icon el-range__close-icon\",class:[e.showClose?\"\"+e.clearIcon:\"\"],on:{click:e.handleClickIcon}}):e._e()],2):i(\"el-input\",e._b({directives:[{name:\"clickoutside\",rawName:\"v-clickoutside\",value:e.handleClose,expression:\"handleClose\"}],ref:\"reference\",staticClass:\"el-date-editor\",class:\"el-date-editor--\"+e.type,attrs:{readonly:!e.editable||e.readonly||\"dates\"===e.type||\"week\"===e.type,disabled:e.pickerDisabled,size:e.pickerSize,name:e.name,placeholder:e.placeholder,value:e.displayValue,validateEvent:!1},on:{focus:e.handleFocus,input:function(t){return e.userInput=t},change:e.handleChange},nativeOn:{keydown:function(t){return e.handleKeydown(t)},mouseenter:function(t){return e.handleMouseEnter(t)},mouseleave:function(t){e.showClose=!1}}},\"el-input\",e.firstInputId,!1),[i(\"i\",{staticClass:\"el-input__icon\",class:e.triggerClass,attrs:{slot:\"prefix\"},on:{click:e.handleFocus},slot:\"prefix\"}),e.haveTrigger?i(\"i\",{staticClass:\"el-input__icon\",class:[e.showClose?\"\"+e.clearIcon:\"\"],attrs:{slot:\"suffix\"},on:{click:e.handleClickIcon},slot:\"suffix\"}):e._e()])},Ws=[];Rs._withStripped=!0;var qs=i(24),Ks=i.n(qs),Ys=[\"sun\",\"mon\",\"tue\",\"wed\",\"thu\",\"fri\",\"sat\"],Us=[\"jan\",\"feb\",\"mar\",\"apr\",\"may\",\"jun\",\"jul\",\"aug\",\"sep\",\"oct\",\"nov\",\"dec\"],Gs=function(){return{dayNamesShort:Ys.map(function(e){return Object(Zi[\"t\"])(\"el.datepicker.weeks.\"+e)}),dayNames:Ys.map(function(e){return Object(Zi[\"t\"])(\"el.datepicker.weeks.\"+e)}),monthNamesShort:Us.map(function(e){return Object(Zi[\"t\"])(\"el.datepicker.months.\"+e)}),monthNames:Us.map(function(e,t){return Object(Zi[\"t\"])(\"el.datepicker.month\"+(t+1))}),amPm:[\"am\",\"pm\"]}},Xs=function(e,t){for(var i=[],n=e;n<=t;n++)i.push(n);return i},Qs=function(e){return Js(e)?new Date(e):null},Js=function(e){return null!==e&&void 0!==e&&(!isNaN(new Date(e).getTime())&&!Array.isArray(e))},Zs=function(e){return e instanceof Date},er=function(e,t){return e=Qs(e),e?Ks.a.format(e,t||\"yyyy-MM-dd\",Gs()):\"\"},tr=function(e,t){return Ks.a.parse(e,t||\"yyyy-MM-dd\",Gs())},ir=function(e,t){return 3===t||5===t||8===t||10===t?30:1===t?e%4===0&&e%100!==0||e%400===0?29:28:31},nr=function(e){var t=e%400===0||e%100!==0&&e%4===0;return t?366:365},sr=function(e){var t=new Date(e.getTime());return t.setDate(1),t.getDay()},rr=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1;return new Date(e.getFullYear(),e.getMonth(),e.getDate()-t)},or=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1;return new Date(e.getFullYear(),e.getMonth(),e.getDate()+t)},ar=function(e,t){var i=new Date(e,t,1),n=i.getDay();return rr(i,0===n?7:n)},lr=function(e){if(!Js(e))return null;var t=new Date(e.getTime());t.setHours(0,0,0,0),t.setDate(t.getDate()+3-(t.getDay()+6)%7);var i=new Date(t.getFullYear(),0,4);return 1+Math.round(((t.getTime()-i.getTime())/864e5-3+(i.getDay()+6)%7)/7)},ur=function(e){var t=[],i=[];if((e||[]).forEach(function(e){var t=e.map(function(e){return e.getHours()});i=i.concat(Xs(t[0],t[1]))}),i.length)for(var n=0;n<24;n++)t[n]=-1===i.indexOf(n);else for(var s=0;s<24;s++)t[s]=!1;return t};function cr(e,t,i,n){for(var s=t;s<i;s++)e[s]=n}var hr=function(e,t){var i=new Array(60);return e.length>0?e.forEach(function(e){var n=e[0],s=e[1],r=n.getHours(),o=n.getMinutes(),a=s.getHours(),l=s.getMinutes();r===t&&a!==t?cr(i,o,60,!0):r===t&&a===t?cr(i,o,l+1,!0):r!==t&&a===t?cr(i,0,l+1,!0):r<t&&a>t&&cr(i,0,60,!0)}):cr(i,0,60,!0),i},dr=function(e){return Array.apply(null,{length:e}).map(function(e,t){return t})},pr=function(e,t,i,n){return new Date(t,i,n,e.getHours(),e.getMinutes(),e.getSeconds(),e.getMilliseconds())},fr=function(e,t,i,n){return new Date(e.getFullYear(),e.getMonth(),e.getDate(),t,i,n,e.getMilliseconds())},mr=function(e,t){return null!=e&&t?(t=tr(t,\"HH:mm:ss\"),fr(e,t.getHours(),t.getMinutes(),t.getSeconds())):e},vr=function(e){return new Date(e.getFullYear(),e.getMonth(),e.getDate())},gr=function(e){return new Date(e.getFullYear(),e.getMonth(),e.getDate(),e.getHours(),e.getMinutes(),e.getSeconds(),0)},br=function(e,t){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:\"HH:mm:ss\";if(0===t.length)return e;var n=function(e){return Ks.a.parse(Ks.a.format(e,i),i)},s=n(e),r=t.map(function(e){return e.map(n)});if(r.some(function(e){return s>=e[0]&&s<=e[1]}))return e;var o=r[0][0],a=r[0][0];r.forEach(function(e){o=new Date(Math.min(e[0],o)),a=new Date(Math.max(e[1],o))});var l=s<o?o:a;return pr(l,e.getFullYear(),e.getMonth(),e.getDate())},yr=function(e,t,i){var n=br(e,t,i);return n.getTime()===e.getTime()},_r=function(e,t,i){var n=Math.min(e.getDate(),ir(t,i));return pr(e,t,i,n)},xr=function(e){var t=e.getFullYear(),i=e.getMonth();return 0===i?_r(e,t-1,11):_r(e,t,i-1)},Cr=function(e){var t=e.getFullYear(),i=e.getMonth();return 11===i?_r(e,t+1,0):_r(e,t,i+1)},wr=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,i=e.getFullYear(),n=e.getMonth();return _r(e,i-t,n)},kr=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,i=e.getFullYear(),n=e.getMonth();return _r(e,i+t,n)},Sr=function(e){return e.replace(/\\W?m{1,2}|\\W?ZZ/g,\"\").replace(/\\W?h{1,2}|\\W?s{1,3}|\\W?a/gi,\"\").trim()},$r=function(e){return e.replace(/\\W?D{1,2}|\\W?Do|\\W?d{1,4}|\\W?M{1,4}|\\W?y{2,4}/g,\"\").trim()},Dr={props:{appendToBody:R.a.props.appendToBody,offset:R.a.props.offset,boundariesPadding:R.a.props.boundariesPadding,arrowOffset:R.a.props.arrowOffset},methods:R.a.methods,data:function(){return St()({visibleArrow:!0},R.a.data)},beforeDestroy:R.a.beforeDestroy},Er={date:\"yyyy-MM-dd\",month:\"yyyy-MM\",datetime:\"yyyy-MM-dd HH:mm:ss\",time:\"HH:mm:ss\",week:\"yyyywWW\",timerange:\"HH:mm:ss\",daterange:\"yyyy-MM-dd\",monthrange:\"yyyy-MM\",datetimerange:\"yyyy-MM-dd HH:mm:ss\",year:\"yyyy\"},Tr=[\"date\",\"datetime\",\"time\",\"time-select\",\"week\",\"month\",\"year\",\"daterange\",\"monthrange\",\"timerange\",\"datetimerange\",\"dates\"],Or=function(e,t){return\"timestamp\"===t?e.getTime():er(e,t)},Ir=function(e,t){return\"timestamp\"===t?new Date(Number(e)):tr(e,t)},Pr=function(e,t){if(Array.isArray(e)&&2===e.length){var i=e[0],n=e[1];if(i&&n)return[Or(i,t),Or(n,t)]}return\"\"},Mr=function(e,t,i){if(Array.isArray(e)||(e=e.split(i)),2===e.length){var n=e[0],s=e[1];return[Ir(n,t),Ir(s,t)]}return[]},Nr={default:{formatter:function(e){return e?\"\"+e:\"\"},parser:function(e){return void 0===e||\"\"===e?null:e}},week:{formatter:function(e,t){var i=lr(e),n=e.getMonth(),s=new Date(e);1===i&&11===n&&(s.setHours(0,0,0,0),s.setDate(s.getDate()+3-(s.getDay()+6)%7));var r=er(s,t);return r=/WW/.test(r)?r.replace(/WW/,i<10?\"0\"+i:i):r.replace(/W/,i),r},parser:function(e,t){return Nr.date.parser(e,t)}},date:{formatter:Or,parser:Ir},datetime:{formatter:Or,parser:Ir},daterange:{formatter:Pr,parser:Mr},monthrange:{formatter:Pr,parser:Mr},datetimerange:{formatter:Pr,parser:Mr},timerange:{formatter:Pr,parser:Mr},time:{formatter:Or,parser:Ir},month:{formatter:Or,parser:Ir},year:{formatter:Or,parser:Ir},number:{formatter:function(e){return e?\"\"+e:\"\"},parser:function(e){var t=Number(e);return isNaN(e)?null:t}},dates:{formatter:function(e,t){return e.map(function(e){return Or(e,t)})},parser:function(e,t){return(\"string\"===typeof e?e.split(\", \"):e).map(function(e){return e instanceof Date?e:Ir(e,t)})}}},Fr={left:\"bottom-start\",center:\"bottom\",right:\"bottom-end\"},Ar=function(e,t,i){var n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:\"-\";if(!e)return null;var s=(Nr[i]||Nr[\"default\"]).parser,r=t||Er[i];return s(e,r,n)},Lr=function(e,t,i){if(!e)return null;var n=(Nr[i]||Nr[\"default\"]).formatter,s=t||Er[i];return n(e,s)},Vr=function(e,t){var i=function(e,t){var i=e instanceof Date,n=t instanceof Date;return i&&n?e.getTime()===t.getTime():!i&&!n&&e===t},n=e instanceof Array,s=t instanceof Array;return n&&s?e.length===t.length&&e.every(function(e,n){return i(e,t[n])}):!n&&!s&&i(e,t)},Br=function(e){return\"string\"===typeof e||e instanceof String},zr=function(e){return null===e||void 0===e||Br(e)||Array.isArray(e)&&2===e.length&&e.every(Br)},jr={mixins:[E.a,Dr],inject:{elForm:{default:\"\"},elFormItem:{default:\"\"}},props:{size:String,format:String,valueFormat:String,readonly:Boolean,placeholder:String,startPlaceholder:String,endPlaceholder:String,prefixIcon:String,clearIcon:{type:String,default:\"el-icon-circle-close\"},name:{default:\"\",validator:zr},disabled:Boolean,clearable:{type:Boolean,default:!0},id:{default:\"\",validator:zr},popperClass:String,editable:{type:Boolean,default:!0},align:{type:String,default:\"left\"},value:{},defaultValue:{},defaultTime:{},rangeSeparator:{default:\"-\"},pickerOptions:{},unlinkPanels:Boolean,validateEvent:{type:Boolean,default:!0}},components:{ElInput:m.a},directives:{Clickoutside:B.a},data:function(){return{pickerVisible:!1,showClose:!1,userInput:null,valueOnOpen:null,unwatchPickerOptions:null}},watch:{pickerVisible:function(e){this.readonly||this.pickerDisabled||(e?(this.showPicker(),this.valueOnOpen=Array.isArray(this.value)?[].concat(this.value):this.value):(this.hidePicker(),this.emitChange(this.value),this.userInput=null,this.validateEvent&&this.dispatch(\"ElFormItem\",\"el.form.blur\"),this.$emit(\"blur\",this),this.blur()))},parsedValue:{immediate:!0,handler:function(e){this.picker&&(this.picker.value=e)}},defaultValue:function(e){this.picker&&(this.picker.defaultValue=e)},value:function(e,t){Vr(e,t)||this.pickerVisible||!this.validateEvent||this.dispatch(\"ElFormItem\",\"el.form.change\",e)}},computed:{ranged:function(){return this.type.indexOf(\"range\")>-1},reference:function(){var e=this.$refs.reference;return e.$el||e},refInput:function(){return this.reference?[].slice.call(this.reference.querySelectorAll(\"input\")):[]},valueIsEmpty:function(){var e=this.value;if(Array.isArray(e)){for(var t=0,i=e.length;t<i;t++)if(e[t])return!1}else if(e)return!1;return!0},triggerClass:function(){return this.prefixIcon||(-1!==this.type.indexOf(\"time\")?\"el-icon-time\":\"el-icon-date\")},selectionMode:function(){return\"week\"===this.type?\"week\":\"month\"===this.type?\"month\":\"year\"===this.type?\"year\":\"dates\"===this.type?\"dates\":\"day\"},haveTrigger:function(){return\"undefined\"!==typeof this.showTrigger?this.showTrigger:-1!==Tr.indexOf(this.type)},displayValue:function(){var e=Lr(this.parsedValue,this.format,this.type,this.rangeSeparator);return Array.isArray(this.userInput)?[this.userInput[0]||e&&e[0]||\"\",this.userInput[1]||e&&e[1]||\"\"]:null!==this.userInput?this.userInput:e?\"dates\"===this.type?e.join(\", \"):e:\"\"},parsedValue:function(){if(!this.value)return this.value;if(\"time-select\"===this.type)return this.value;var e=Zs(this.value)||Array.isArray(this.value)&&this.value.every(Zs);return e?this.value:this.valueFormat?Ar(this.value,this.valueFormat,this.type,this.rangeSeparator)||this.value:Array.isArray(this.value)?this.value.map(function(e){return new Date(e)}):new Date(this.value)},_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},pickerSize:function(){return this.size||this._elFormItemSize||(this.$ELEMENT||{}).size},pickerDisabled:function(){return this.disabled||(this.elForm||{}).disabled},firstInputId:function(){var e={},t=void 0;return t=this.ranged?this.id&&this.id[0]:this.id,t&&(e.id=t),e},secondInputId:function(){var e={},t=void 0;return this.ranged&&(t=this.id&&this.id[1]),t&&(e.id=t),e}},created:function(){this.popperOptions={boundariesPadding:0,gpuAcceleration:!1},this.placement=Fr[this.align]||Fr.left,this.$on(\"fieldReset\",this.handleFieldReset)},methods:{focus:function(){this.ranged?this.handleFocus():this.$refs.reference.focus()},blur:function(){this.refInput.forEach(function(e){return e.blur()})},parseValue:function(e){var t=Zs(e)||Array.isArray(e)&&e.every(Zs);return this.valueFormat&&!t&&Ar(e,this.valueFormat,this.type,this.rangeSeparator)||e},formatToValue:function(e){var t=Zs(e)||Array.isArray(e)&&e.every(Zs);return this.valueFormat&&t?Lr(e,this.valueFormat,this.type,this.rangeSeparator):e},parseString:function(e){var t=Array.isArray(e)?this.type:this.type.replace(\"range\",\"\");return Ar(e,this.format,t)},formatToString:function(e){var t=Array.isArray(e)?this.type:this.type.replace(\"range\",\"\");return Lr(e,this.format,t)},handleMouseEnter:function(){this.readonly||this.pickerDisabled||!this.valueIsEmpty&&this.clearable&&(this.showClose=!0)},handleChange:function(){if(this.userInput){var e=this.parseString(this.displayValue);e&&(this.picker.value=e,this.isValidValue(e)&&(this.emitInput(e),this.userInput=null))}\"\"===this.userInput&&(this.emitInput(null),this.emitChange(null),this.userInput=null)},handleStartInput:function(e){this.userInput?this.userInput=[e.target.value,this.userInput[1]]:this.userInput=[e.target.value,null]},handleEndInput:function(e){this.userInput?this.userInput=[this.userInput[0],e.target.value]:this.userInput=[null,e.target.value]},handleStartChange:function(e){var t=this.parseString(this.userInput&&this.userInput[0]);if(t){this.userInput=[this.formatToString(t),this.displayValue[1]];var i=[t,this.picker.value&&this.picker.value[1]];this.picker.value=i,this.isValidValue(i)&&(this.emitInput(i),this.userInput=null)}},handleEndChange:function(e){var t=this.parseString(this.userInput&&this.userInput[1]);if(t){this.userInput=[this.displayValue[0],this.formatToString(t)];var i=[this.picker.value&&this.picker.value[0],t];this.picker.value=i,this.isValidValue(i)&&(this.emitInput(i),this.userInput=null)}},handleClickIcon:function(e){this.readonly||this.pickerDisabled||(this.showClose?(this.valueOnOpen=this.value,e.stopPropagation(),this.emitInput(null),this.emitChange(null),this.showClose=!1,this.picker&&\"function\"===typeof this.picker.handleClear&&this.picker.handleClear()):this.pickerVisible=!this.pickerVisible)},handleClose:function(){if(this.pickerVisible&&(this.pickerVisible=!1,\"dates\"===this.type)){var e=Ar(this.valueOnOpen,this.valueFormat,this.type,this.rangeSeparator)||this.valueOnOpen;this.emitInput(e)}},handleFieldReset:function(e){this.userInput=\"\"===e?null:e},handleFocus:function(){var e=this.type;-1===Tr.indexOf(e)||this.pickerVisible||(this.pickerVisible=!0),this.$emit(\"focus\",this)},handleKeydown:function(e){var t=this,i=e.keyCode;return 27===i?(this.pickerVisible=!1,void e.stopPropagation()):9!==i?13===i?((\"\"===this.userInput||this.isValidValue(this.parseString(this.displayValue)))&&(this.handleChange(),this.pickerVisible=this.picker.visible=!1,this.blur()),void e.stopPropagation()):void(this.userInput?e.stopPropagation():this.picker&&this.picker.handleKeydown&&this.picker.handleKeydown(e)):void(this.ranged?setTimeout(function(){-1===t.refInput.indexOf(document.activeElement)&&(t.pickerVisible=!1,t.blur(),e.stopPropagation())},0):(this.handleChange(),this.pickerVisible=this.picker.visible=!1,this.blur(),e.stopPropagation()))},handleRangeClick:function(){var e=this.type;-1===Tr.indexOf(e)||this.pickerVisible||(this.pickerVisible=!0),this.$emit(\"focus\",this)},hidePicker:function(){this.picker&&(this.picker.resetView&&this.picker.resetView(),this.pickerVisible=this.picker.visible=!1,this.destroyPopper())},showPicker:function(){var e=this;this.$isServer||(this.picker||this.mountPicker(),this.pickerVisible=this.picker.visible=!0,this.updatePopper(),this.picker.value=this.parsedValue,this.picker.resetView&&this.picker.resetView(),this.$nextTick(function(){e.picker.adjustSpinners&&e.picker.adjustSpinners()}))},mountPicker:function(){var e=this;this.picker=new Rn.a(this.panel).$mount(),this.picker.defaultValue=this.defaultValue,this.picker.defaultTime=this.defaultTime,this.picker.popperClass=this.popperClass,this.popperElm=this.picker.$el,this.picker.width=this.reference.getBoundingClientRect().width,this.picker.showTime=\"datetime\"===this.type||\"datetimerange\"===this.type,this.picker.selectionMode=this.selectionMode,this.picker.unlinkPanels=this.unlinkPanels,this.picker.arrowControl=this.arrowControl||this.timeArrowControl||!1,this.$watch(\"format\",function(t){e.picker.format=t});var t=function(){var t=e.pickerOptions;if(t&&t.selectableRange){var i=t.selectableRange,n=Nr.datetimerange.parser,s=Er.timerange;i=Array.isArray(i)?i:[i],e.picker.selectableRange=i.map(function(t){return n(t,s,e.rangeSeparator)})}for(var r in t)t.hasOwnProperty(r)&&\"selectableRange\"!==r&&(e.picker[r]=t[r]);e.format&&(e.picker.format=e.format)};t(),this.unwatchPickerOptions=this.$watch(\"pickerOptions\",function(){return t()},{deep:!0}),this.$el.appendChild(this.picker.$el),this.picker.resetView&&this.picker.resetView(),this.picker.$on(\"dodestroy\",this.doDestroy),this.picker.$on(\"pick\",function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:\"\",i=arguments.length>1&&void 0!==arguments[1]&&arguments[1];e.userInput=null,e.pickerVisible=e.picker.visible=i,e.emitInput(t),e.picker.resetView&&e.picker.resetView()}),this.picker.$on(\"select-range\",function(t,i,n){0!==e.refInput.length&&(n&&\"min\"!==n?\"max\"===n&&(e.refInput[1].setSelectionRange(t,i),e.refInput[1].focus()):(e.refInput[0].setSelectionRange(t,i),e.refInput[0].focus()))})},unmountPicker:function(){this.picker&&(this.picker.$destroy(),this.picker.$off(),\"function\"===typeof this.unwatchPickerOptions&&this.unwatchPickerOptions(),this.picker.$el.parentNode.removeChild(this.picker.$el))},emitChange:function(e){Vr(e,this.valueOnOpen)||(this.$emit(\"change\",e),this.valueOnOpen=e,this.validateEvent&&this.dispatch(\"ElFormItem\",\"el.form.change\",e))},emitInput:function(e){var t=this.formatToValue(e);Vr(this.value,t)||this.$emit(\"input\",t)},isValidValue:function(e){return this.picker||this.mountPicker(),!this.picker.isValidValue||e&&this.picker.isValidValue(e)}}},Hr=jr,Rr=a(Hr,Rs,Ws,!1,null,null,null);Rr.options.__file=\"packages/date-picker/src/picker.vue\";var Wr=Rr.exports,qr=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"el-zoom-in-top\"},on:{\"after-enter\":e.handleEnter,\"after-leave\":e.handleLeave}},[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible,expression:\"visible\"}],staticClass:\"el-picker-panel el-date-picker el-popper\",class:[{\"has-sidebar\":e.$slots.sidebar||e.shortcuts,\"has-time\":e.showTime},e.popperClass]},[i(\"div\",{staticClass:\"el-picker-panel__body-wrapper\"},[e._t(\"sidebar\"),e.shortcuts?i(\"div\",{staticClass:\"el-picker-panel__sidebar\"},e._l(e.shortcuts,function(t,n){return i(\"button\",{key:n,staticClass:\"el-picker-panel__shortcut\",attrs:{type:\"button\"},on:{click:function(i){e.handleShortcutClick(t)}}},[e._v(e._s(t.text))])}),0):e._e(),i(\"div\",{staticClass:\"el-picker-panel__body\"},[e.showTime?i(\"div\",{staticClass:\"el-date-picker__time-header\"},[i(\"span\",{staticClass:\"el-date-picker__editor-wrap\"},[i(\"el-input\",{attrs:{placeholder:e.t(\"el.datepicker.selectDate\"),value:e.visibleDate,size:\"small\"},on:{input:function(t){return e.userInputDate=t},change:e.handleVisibleDateChange}})],1),i(\"span\",{directives:[{name:\"clickoutside\",rawName:\"v-clickoutside\",value:e.handleTimePickClose,expression:\"handleTimePickClose\"}],staticClass:\"el-date-picker__editor-wrap\"},[i(\"el-input\",{ref:\"input\",attrs:{placeholder:e.t(\"el.datepicker.selectTime\"),value:e.visibleTime,size:\"small\"},on:{focus:function(t){e.timePickerVisible=!0},input:function(t){return e.userInputTime=t},change:e.handleVisibleTimeChange}}),i(\"time-picker\",{ref:\"timepicker\",attrs:{\"time-arrow-control\":e.arrowControl,visible:e.timePickerVisible},on:{pick:e.handleTimePick,mounted:e.proxyTimePickerDataProperties}})],1)]):e._e(),i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:\"time\"!==e.currentView,expression:\"currentView !== 'time'\"}],staticClass:\"el-date-picker__header\",class:{\"el-date-picker__header--bordered\":\"year\"===e.currentView||\"month\"===e.currentView}},[i(\"button\",{staticClass:\"el-picker-panel__icon-btn el-date-picker__prev-btn el-icon-d-arrow-left\",attrs:{type:\"button\",\"aria-label\":e.t(\"el.datepicker.prevYear\")},on:{click:e.prevYear}}),i(\"button\",{directives:[{name:\"show\",rawName:\"v-show\",value:\"date\"===e.currentView,expression:\"currentView === 'date'\"}],staticClass:\"el-picker-panel__icon-btn el-date-picker__prev-btn el-icon-arrow-left\",attrs:{type:\"button\",\"aria-label\":e.t(\"el.datepicker.prevMonth\")},on:{click:e.prevMonth}}),i(\"span\",{staticClass:\"el-date-picker__header-label\",attrs:{role:\"button\"},on:{click:e.showYearPicker}},[e._v(e._s(e.yearLabel))]),i(\"span\",{directives:[{name:\"show\",rawName:\"v-show\",value:\"date\"===e.currentView,expression:\"currentView === 'date'\"}],staticClass:\"el-date-picker__header-label\",class:{active:\"month\"===e.currentView},attrs:{role:\"button\"},on:{click:e.showMonthPicker}},[e._v(e._s(e.t(\"el.datepicker.month\"+(e.month+1))))]),i(\"button\",{staticClass:\"el-picker-panel__icon-btn el-date-picker__next-btn el-icon-d-arrow-right\",attrs:{type:\"button\",\"aria-label\":e.t(\"el.datepicker.nextYear\")},on:{click:e.nextYear}}),i(\"button\",{directives:[{name:\"show\",rawName:\"v-show\",value:\"date\"===e.currentView,expression:\"currentView === 'date'\"}],staticClass:\"el-picker-panel__icon-btn el-date-picker__next-btn el-icon-arrow-right\",attrs:{type:\"button\",\"aria-label\":e.t(\"el.datepicker.nextMonth\")},on:{click:e.nextMonth}})]),i(\"div\",{staticClass:\"el-picker-panel__content\"},[i(\"date-table\",{directives:[{name:\"show\",rawName:\"v-show\",value:\"date\"===e.currentView,expression:\"currentView === 'date'\"}],attrs:{\"selection-mode\":e.selectionMode,\"first-day-of-week\":e.firstDayOfWeek,value:e.value,\"default-value\":e.defaultValue?new Date(e.defaultValue):null,date:e.date,\"disabled-date\":e.disabledDate},on:{pick:e.handleDatePick}}),i(\"year-table\",{directives:[{name:\"show\",rawName:\"v-show\",value:\"year\"===e.currentView,expression:\"currentView === 'year'\"}],attrs:{value:e.value,\"default-value\":e.defaultValue?new Date(e.defaultValue):null,date:e.date,\"disabled-date\":e.disabledDate},on:{pick:e.handleYearPick}}),i(\"month-table\",{directives:[{name:\"show\",rawName:\"v-show\",value:\"month\"===e.currentView,expression:\"currentView === 'month'\"}],attrs:{value:e.value,\"default-value\":e.defaultValue?new Date(e.defaultValue):null,date:e.date,\"disabled-date\":e.disabledDate},on:{pick:e.handleMonthPick}})],1)])],2),i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.footerVisible&&\"date\"===e.currentView,expression:\"footerVisible && currentView === 'date'\"}],staticClass:\"el-picker-panel__footer\"},[i(\"el-button\",{directives:[{name:\"show\",rawName:\"v-show\",value:\"dates\"!==e.selectionMode,expression:\"selectionMode !== 'dates'\"}],staticClass:\"el-picker-panel__link-btn\",attrs:{size:\"mini\",type:\"text\"},on:{click:e.changeToNow}},[e._v(\"\\n        \"+e._s(e.t(\"el.datepicker.now\"))+\"\\n      \")]),i(\"el-button\",{staticClass:\"el-picker-panel__link-btn\",attrs:{plain:\"\",size:\"mini\"},on:{click:e.confirm}},[e._v(\"\\n        \"+e._s(e.t(\"el.datepicker.confirm\"))+\"\\n      \")])],1)])])},Kr=[];qr._withStripped=!0;var Yr=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"el-zoom-in-top\"},on:{\"after-leave\":function(t){e.$emit(\"dodestroy\")}}},[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible,expression:\"visible\"}],staticClass:\"el-time-panel el-popper\",class:e.popperClass},[i(\"div\",{staticClass:\"el-time-panel__content\",class:{\"has-seconds\":e.showSeconds}},[i(\"time-spinner\",{ref:\"spinner\",attrs:{\"arrow-control\":e.useArrow,\"show-seconds\":e.showSeconds,\"am-pm-mode\":e.amPmMode,date:e.date},on:{change:e.handleChange,\"select-range\":e.setSelectionRange}})],1),i(\"div\",{staticClass:\"el-time-panel__footer\"},[i(\"button\",{staticClass:\"el-time-panel__btn cancel\",attrs:{type:\"button\"},on:{click:e.handleCancel}},[e._v(e._s(e.t(\"el.datepicker.cancel\")))]),i(\"button\",{staticClass:\"el-time-panel__btn\",class:{confirm:!e.disabled},attrs:{type:\"button\"},on:{click:function(t){e.handleConfirm()}}},[e._v(e._s(e.t(\"el.datepicker.confirm\")))])])])])},Ur=[];Yr._withStripped=!0;var Gr=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-time-spinner\",class:{\"has-seconds\":e.showSeconds}},[e.arrowControl?e._e():[i(\"el-scrollbar\",{ref:\"hours\",staticClass:\"el-time-spinner__wrapper\",attrs:{\"wrap-style\":\"max-height: inherit;\",\"view-class\":\"el-time-spinner__list\",noresize:\"\",tag:\"ul\"},nativeOn:{mouseenter:function(t){e.emitSelectRange(\"hours\")},mousemove:function(t){e.adjustCurrentSpinner(\"hours\")}}},e._l(e.hoursList,function(t,n){return i(\"li\",{key:n,staticClass:\"el-time-spinner__item\",class:{active:n===e.hours,disabled:t},on:{click:function(i){e.handleClick(\"hours\",{value:n,disabled:t})}}},[e._v(e._s((\"0\"+(e.amPmMode?n%12||12:n)).slice(-2))+e._s(e.amPm(n)))])}),0),i(\"el-scrollbar\",{ref:\"minutes\",staticClass:\"el-time-spinner__wrapper\",attrs:{\"wrap-style\":\"max-height: inherit;\",\"view-class\":\"el-time-spinner__list\",noresize:\"\",tag:\"ul\"},nativeOn:{mouseenter:function(t){e.emitSelectRange(\"minutes\")},mousemove:function(t){e.adjustCurrentSpinner(\"minutes\")}}},e._l(e.minutesList,function(t,n){return i(\"li\",{key:n,staticClass:\"el-time-spinner__item\",class:{active:n===e.minutes,disabled:!t},on:{click:function(t){e.handleClick(\"minutes\",{value:n,disabled:!1})}}},[e._v(e._s((\"0\"+n).slice(-2)))])}),0),i(\"el-scrollbar\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.showSeconds,expression:\"showSeconds\"}],ref:\"seconds\",staticClass:\"el-time-spinner__wrapper\",attrs:{\"wrap-style\":\"max-height: inherit;\",\"view-class\":\"el-time-spinner__list\",noresize:\"\",tag:\"ul\"},nativeOn:{mouseenter:function(t){e.emitSelectRange(\"seconds\")},mousemove:function(t){e.adjustCurrentSpinner(\"seconds\")}}},e._l(60,function(t,n){return i(\"li\",{key:n,staticClass:\"el-time-spinner__item\",class:{active:n===e.seconds},on:{click:function(t){e.handleClick(\"seconds\",{value:n,disabled:!1})}}},[e._v(e._s((\"0\"+n).slice(-2)))])}),0)],e.arrowControl?[i(\"div\",{staticClass:\"el-time-spinner__wrapper is-arrow\",on:{mouseenter:function(t){e.emitSelectRange(\"hours\")}}},[i(\"i\",{directives:[{name:\"repeat-click\",rawName:\"v-repeat-click\",value:e.decrease,expression:\"decrease\"}],staticClass:\"el-time-spinner__arrow el-icon-arrow-up\"}),i(\"i\",{directives:[{name:\"repeat-click\",rawName:\"v-repeat-click\",value:e.increase,expression:\"increase\"}],staticClass:\"el-time-spinner__arrow el-icon-arrow-down\"}),i(\"ul\",{ref:\"hours\",staticClass:\"el-time-spinner__list\"},e._l(e.arrowHourList,function(t,n){return i(\"li\",{key:n,staticClass:\"el-time-spinner__item\",class:{active:t===e.hours,disabled:e.hoursList[t]}},[e._v(e._s(void 0===t?\"\":(\"0\"+(e.amPmMode?t%12||12:t)).slice(-2)+e.amPm(t)))])}),0)]),i(\"div\",{staticClass:\"el-time-spinner__wrapper is-arrow\",on:{mouseenter:function(t){e.emitSelectRange(\"minutes\")}}},[i(\"i\",{directives:[{name:\"repeat-click\",rawName:\"v-repeat-click\",value:e.decrease,expression:\"decrease\"}],staticClass:\"el-time-spinner__arrow el-icon-arrow-up\"}),i(\"i\",{directives:[{name:\"repeat-click\",rawName:\"v-repeat-click\",value:e.increase,expression:\"increase\"}],staticClass:\"el-time-spinner__arrow el-icon-arrow-down\"}),i(\"ul\",{ref:\"minutes\",staticClass:\"el-time-spinner__list\"},e._l(e.arrowMinuteList,function(t,n){return i(\"li\",{key:n,staticClass:\"el-time-spinner__item\",class:{active:t===e.minutes}},[e._v(\"\\n          \"+e._s(void 0===t?\"\":(\"0\"+t).slice(-2))+\"\\n        \")])}),0)]),e.showSeconds?i(\"div\",{staticClass:\"el-time-spinner__wrapper is-arrow\",on:{mouseenter:function(t){e.emitSelectRange(\"seconds\")}}},[i(\"i\",{directives:[{name:\"repeat-click\",rawName:\"v-repeat-click\",value:e.decrease,expression:\"decrease\"}],staticClass:\"el-time-spinner__arrow el-icon-arrow-up\"}),i(\"i\",{directives:[{name:\"repeat-click\",rawName:\"v-repeat-click\",value:e.increase,expression:\"increase\"}],staticClass:\"el-time-spinner__arrow el-icon-arrow-down\"}),i(\"ul\",{ref:\"seconds\",staticClass:\"el-time-spinner__list\"},e._l(e.arrowSecondList,function(t,n){return i(\"li\",{key:n,staticClass:\"el-time-spinner__item\",class:{active:t===e.seconds}},[e._v(\"\\n          \"+e._s(void 0===t?\"\":(\"0\"+t).slice(-2))+\"\\n        \")])}),0)]):e._e()]:e._e()],2)},Xr=[];Gr._withStripped=!0;var Qr={components:{ElScrollbar:q.a},directives:{repeatClick:Mt},props:{date:{},defaultValue:{},showSeconds:{type:Boolean,default:!0},arrowControl:Boolean,amPmMode:{type:String,default:\"\"}},computed:{hours:function(){return this.date.getHours()},minutes:function(){return this.date.getMinutes()},seconds:function(){return this.date.getSeconds()},hoursList:function(){return ur(this.selectableRange)},minutesList:function(){return hr(this.selectableRange,this.hours)},arrowHourList:function(){var e=this.hours;return[e>0?e-1:void 0,e,e<23?e+1:void 0]},arrowMinuteList:function(){var e=this.minutes;return[e>0?e-1:void 0,e,e<59?e+1:void 0]},arrowSecondList:function(){var e=this.seconds;return[e>0?e-1:void 0,e,e<59?e+1:void 0]}},data:function(){return{selectableRange:[],currentScrollbar:null}},mounted:function(){var e=this;this.$nextTick(function(){!e.arrowControl&&e.bindScrollEvent()})},methods:{increase:function(){this.scrollDown(1)},decrease:function(){this.scrollDown(-1)},modifyDateField:function(e,t){switch(e){case\"hours\":this.$emit(\"change\",fr(this.date,t,this.minutes,this.seconds));break;case\"minutes\":this.$emit(\"change\",fr(this.date,this.hours,t,this.seconds));break;case\"seconds\":this.$emit(\"change\",fr(this.date,this.hours,this.minutes,t));break}},handleClick:function(e,t){var i=t.value,n=t.disabled;n||(this.modifyDateField(e,i),this.emitSelectRange(e),this.adjustSpinner(e,i))},emitSelectRange:function(e){\"hours\"===e?this.$emit(\"select-range\",0,2):\"minutes\"===e?this.$emit(\"select-range\",3,5):\"seconds\"===e&&this.$emit(\"select-range\",6,8),this.currentScrollbar=e},bindScrollEvent:function(){var e=this,t=function(t){e.$refs[t].wrap.onscroll=function(i){e.handleScroll(t,i)}};t(\"hours\"),t(\"minutes\"),t(\"seconds\")},handleScroll:function(e){var t=Math.min(Math.floor((this.$refs[e].wrap.scrollTop-(.5*this.scrollBarHeight(e)-10)/this.typeItemHeight(e)+3)/this.typeItemHeight(e)),\"hours\"===e?23:59);this.modifyDateField(e,t)},adjustSpinners:function(){this.adjustSpinner(\"hours\",this.hours),this.adjustSpinner(\"minutes\",this.minutes),this.adjustSpinner(\"seconds\",this.seconds)},adjustCurrentSpinner:function(e){this.adjustSpinner(e,this[e])},adjustSpinner:function(e,t){if(!this.arrowControl){var i=this.$refs[e].wrap;i&&(i.scrollTop=Math.max(0,t*this.typeItemHeight(e)))}},scrollDown:function(e){this.currentScrollbar||this.emitSelectRange(\"hours\");var t=this.currentScrollbar,i=this.hoursList,n=this[t];if(\"hours\"===this.currentScrollbar){var s=Math.abs(e);e=e>0?1:-1;var r=i.length;while(r--&&s)n=(n+e+i.length)%i.length,i[n]||s--;if(i[n])return}else n=(n+e+60)%60;this.modifyDateField(t,n),this.adjustSpinner(t,n)},amPm:function(e){var t=\"a\"===this.amPmMode.toLowerCase();if(!t)return\"\";var i=\"A\"===this.amPmMode,n=e<12?\" am\":\" pm\";return i&&(n=n.toUpperCase()),n},typeItemHeight:function(e){return this.$refs[e].$el.querySelector(\"li\").offsetHeight},scrollBarHeight:function(e){return this.$refs[e].$el.offsetHeight}}},Jr=Qr,Zr=a(Jr,Gr,Xr,!1,null,null,null);Zr.options.__file=\"packages/date-picker/src/basic/time-spinner.vue\";var eo=Zr.exports,to={mixins:[g.a],components:{TimeSpinner:eo},props:{visible:Boolean,timeArrowControl:Boolean},watch:{visible:function(e){var t=this;e?(this.oldValue=this.value,this.$nextTick(function(){return t.$refs.spinner.emitSelectRange(\"hours\")})):this.needInitAdjust=!0},value:function(e){var t=this,i=void 0;e instanceof Date?i=br(e,this.selectableRange,this.format):e||(i=this.defaultValue?new Date(this.defaultValue):new Date),this.date=i,this.visible&&this.needInitAdjust&&(this.$nextTick(function(e){return t.adjustSpinners()}),this.needInitAdjust=!1)},selectableRange:function(e){this.$refs.spinner.selectableRange=e},defaultValue:function(e){Js(this.value)||(this.date=e?new Date(e):new Date)}},data:function(){return{popperClass:\"\",format:\"HH:mm:ss\",value:\"\",defaultValue:null,date:new Date,oldValue:new Date,selectableRange:[],selectionRange:[0,2],disabled:!1,arrowControl:!1,needInitAdjust:!0}},computed:{showSeconds:function(){return-1!==(this.format||\"\").indexOf(\"ss\")},useArrow:function(){return this.arrowControl||this.timeArrowControl||!1},amPmMode:function(){return-1!==(this.format||\"\").indexOf(\"A\")?\"A\":-1!==(this.format||\"\").indexOf(\"a\")?\"a\":\"\"}},methods:{handleCancel:function(){this.$emit(\"pick\",this.oldValue,!1)},handleChange:function(e){this.visible&&(this.date=gr(e),this.isValidValue(this.date)&&this.$emit(\"pick\",this.date,!0))},setSelectionRange:function(e,t){this.$emit(\"select-range\",e,t),this.selectionRange=[e,t]},handleConfirm:function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0],t=arguments[1];if(!t){var i=gr(br(this.date,this.selectableRange,this.format));this.$emit(\"pick\",i,e,t)}},handleKeydown:function(e){var t=e.keyCode,i={38:-1,40:1,37:-1,39:1};if(37===t||39===t){var n=i[t];return this.changeSelectionRange(n),void e.preventDefault()}if(38===t||40===t){var s=i[t];return this.$refs.spinner.scrollDown(s),void e.preventDefault()}},isValidValue:function(e){return yr(e,this.selectableRange,this.format)},adjustSpinners:function(){return this.$refs.spinner.adjustSpinners()},changeSelectionRange:function(e){var t=[0,3].concat(this.showSeconds?[6]:[]),i=[\"hours\",\"minutes\"].concat(this.showSeconds?[\"seconds\"]:[]),n=t.indexOf(this.selectionRange[0]),s=(n+e+t.length)%t.length;this.$refs.spinner.emitSelectRange(i[s])}},mounted:function(){var e=this;this.$nextTick(function(){return e.handleConfirm(!0,!0)}),this.$emit(\"mounted\")}},io=to,no=a(io,Yr,Ur,!1,null,null,null);no.options.__file=\"packages/date-picker/src/panel/time.vue\";var so=no.exports,ro=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"table\",{staticClass:\"el-year-table\",on:{click:e.handleYearTableClick}},[i(\"tbody\",[i(\"tr\",[i(\"td\",{staticClass:\"available\",class:e.getCellStyle(e.startYear+0)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.startYear))])]),i(\"td\",{staticClass:\"available\",class:e.getCellStyle(e.startYear+1)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.startYear+1))])]),i(\"td\",{staticClass:\"available\",class:e.getCellStyle(e.startYear+2)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.startYear+2))])]),i(\"td\",{staticClass:\"available\",class:e.getCellStyle(e.startYear+3)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.startYear+3))])])]),i(\"tr\",[i(\"td\",{staticClass:\"available\",class:e.getCellStyle(e.startYear+4)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.startYear+4))])]),i(\"td\",{staticClass:\"available\",class:e.getCellStyle(e.startYear+5)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.startYear+5))])]),i(\"td\",{staticClass:\"available\",class:e.getCellStyle(e.startYear+6)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.startYear+6))])]),i(\"td\",{staticClass:\"available\",class:e.getCellStyle(e.startYear+7)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.startYear+7))])])]),i(\"tr\",[i(\"td\",{staticClass:\"available\",class:e.getCellStyle(e.startYear+8)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.startYear+8))])]),i(\"td\",{staticClass:\"available\",class:e.getCellStyle(e.startYear+9)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.startYear+9))])]),i(\"td\"),i(\"td\")])])])},oo=[];ro._withStripped=!0;var ao=function(e){var t=nr(e),i=new Date(e,0,1);return dr(t).map(function(e){return or(i,e)})},lo={props:{disabledDate:{},value:{},defaultValue:{validator:function(e){return null===e||e instanceof Date&&Js(e)}},date:{}},computed:{startYear:function(){return 10*Math.floor(this.date.getFullYear()/10)}},methods:{getCellStyle:function(e){var t={},i=new Date;return t.disabled=\"function\"===typeof this.disabledDate&&ao(e).every(this.disabledDate),t.current=Object(b[\"arrayFindIndex\"])(Object(b[\"coerceTruthyValueToArray\"])(this.value),function(t){return t.getFullYear()===e})>=0,t.today=i.getFullYear()===e,t.default=this.defaultValue&&this.defaultValue.getFullYear()===e,t},handleYearTableClick:function(e){var t=e.target;if(\"A\"===t.tagName){if(Object(Ve[\"hasClass\"])(t.parentNode,\"disabled\"))return;var i=t.textContent||t.innerText;this.$emit(\"pick\",Number(i))}}}},uo=lo,co=a(uo,ro,oo,!1,null,null,null);co.options.__file=\"packages/date-picker/src/basic/year-table.vue\";var ho=co.exports,po=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"table\",{staticClass:\"el-month-table\",on:{click:e.handleMonthTableClick,mousemove:e.handleMouseMove}},[i(\"tbody\",e._l(e.rows,function(t,n){return i(\"tr\",{key:n},e._l(t,function(t,n){return i(\"td\",{key:n,class:e.getCellStyle(t)},[i(\"div\",[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.t(\"el.datepicker.months.\"+e.months[t.text])))])])])}),0)}),0)])},fo=[];po._withStripped=!0;var mo=function(e,t){var i=ir(e,t),n=new Date(e,t,1);return dr(i).map(function(e){return or(n,e)})},vo=function(e){return new Date(e.getFullYear(),e.getMonth())},go=function(e){return\"number\"===typeof e||\"string\"===typeof e?vo(new Date(e)).getTime():e instanceof Date?vo(e).getTime():NaN},bo={props:{disabledDate:{},value:{},selectionMode:{default:\"month\"},minDate:{},maxDate:{},defaultValue:{validator:function(e){return null===e||Js(e)||Array.isArray(e)&&e.every(Js)}},date:{},rangeState:{default:function(){return{endDate:null,selecting:!1}}}},mixins:[g.a],watch:{\"rangeState.endDate\":function(e){this.markRange(this.minDate,e)},minDate:function(e,t){go(e)!==go(t)&&this.markRange(this.minDate,this.maxDate)},maxDate:function(e,t){go(e)!==go(t)&&this.markRange(this.minDate,this.maxDate)}},data:function(){return{months:[\"jan\",\"feb\",\"mar\",\"apr\",\"may\",\"jun\",\"jul\",\"aug\",\"sep\",\"oct\",\"nov\",\"dec\"],tableRows:[[],[],[]],lastRow:null,lastColumn:null}},methods:{cellMatchesDate:function(e,t){var i=new Date(t);return this.date.getFullYear()===i.getFullYear()&&Number(e.text)===i.getMonth()},getCellStyle:function(e){var t=this,i={},n=this.date.getFullYear(),s=new Date,r=e.text,o=this.defaultValue?Array.isArray(this.defaultValue)?this.defaultValue:[this.defaultValue]:[];return i.disabled=\"function\"===typeof this.disabledDate&&mo(n,r).every(this.disabledDate),i.current=Object(b[\"arrayFindIndex\"])(Object(b[\"coerceTruthyValueToArray\"])(this.value),function(e){return e.getFullYear()===n&&e.getMonth()===r})>=0,i.today=s.getFullYear()===n&&s.getMonth()===r,i.default=o.some(function(i){return t.cellMatchesDate(e,i)}),e.inRange&&(i[\"in-range\"]=!0,e.start&&(i[\"start-date\"]=!0),e.end&&(i[\"end-date\"]=!0)),i},getMonthOfCell:function(e){var t=this.date.getFullYear();return new Date(t,e,1)},markRange:function(e,t){e=go(e),t=go(t)||e;var i=[Math.min(e,t),Math.max(e,t)];e=i[0],t=i[1];for(var n=this.rows,s=0,r=n.length;s<r;s++)for(var o=n[s],a=0,l=o.length;a<l;a++){var u=o[a],c=4*s+a,h=new Date(this.date.getFullYear(),c).getTime();u.inRange=e&&h>=e&&h<=t,u.start=e&&h===e,u.end=t&&h===t}},handleMouseMove:function(e){if(this.rangeState.selecting){var t=e.target;if(\"A\"===t.tagName&&(t=t.parentNode.parentNode),\"DIV\"===t.tagName&&(t=t.parentNode),\"TD\"===t.tagName){var i=t.parentNode.rowIndex,n=t.cellIndex;this.rows[i][n].disabled||i===this.lastRow&&n===this.lastColumn||(this.lastRow=i,this.lastColumn=n,this.$emit(\"changerange\",{minDate:this.minDate,maxDate:this.maxDate,rangeState:{selecting:!0,endDate:this.getMonthOfCell(4*i+n)}}))}}},handleMonthTableClick:function(e){var t=e.target;if(\"A\"===t.tagName&&(t=t.parentNode.parentNode),\"DIV\"===t.tagName&&(t=t.parentNode),\"TD\"===t.tagName&&!Object(Ve[\"hasClass\"])(t,\"disabled\")){var i=t.cellIndex,n=t.parentNode.rowIndex,s=4*n+i,r=this.getMonthOfCell(s);\"range\"===this.selectionMode?this.rangeState.selecting?(r>=this.minDate?this.$emit(\"pick\",{minDate:this.minDate,maxDate:r}):this.$emit(\"pick\",{minDate:r,maxDate:this.minDate}),this.rangeState.selecting=!1):(this.$emit(\"pick\",{minDate:r,maxDate:null}),this.rangeState.selecting=!0):this.$emit(\"pick\",s)}}},computed:{rows:function(){for(var e=this,t=this.tableRows,i=this.disabledDate,n=[],s=go(new Date),r=0;r<3;r++)for(var o=t[r],a=function(t){var a=o[t];a||(a={row:r,column:t,type:\"normal\",inRange:!1,start:!1,end:!1}),a.type=\"normal\";var l=4*r+t,u=new Date(e.date.getFullYear(),l).getTime();a.inRange=u>=go(e.minDate)&&u<=go(e.maxDate),a.start=e.minDate&&u===go(e.minDate),a.end=e.maxDate&&u===go(e.maxDate);var c=u===s;c&&(a.type=\"today\"),a.text=l;var h=new Date(u);a.disabled=\"function\"===typeof i&&i(h),a.selected=Object(b[\"arrayFind\"])(n,function(e){return e.getTime()===h.getTime()}),e.$set(o,t,a)},l=0;l<4;l++)a(l);return t}}},yo=bo,_o=a(yo,po,fo,!1,null,null,null);_o.options.__file=\"packages/date-picker/src/basic/month-table.vue\";var xo=_o.exports,Co=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"table\",{staticClass:\"el-date-table\",class:{\"is-week-mode\":\"week\"===e.selectionMode},attrs:{cellspacing:\"0\",cellpadding:\"0\"},on:{click:e.handleClick,mousemove:e.handleMouseMove}},[i(\"tbody\",[i(\"tr\",[e.showWeekNumber?i(\"th\",[e._v(e._s(e.t(\"el.datepicker.week\")))]):e._e(),e._l(e.WEEKS,function(t,n){return i(\"th\",{key:n},[e._v(e._s(e.t(\"el.datepicker.weeks.\"+t)))])})],2),e._l(e.rows,function(t,n){return i(\"tr\",{key:n,staticClass:\"el-date-table__row\",class:{current:e.isWeekActive(t[1])}},e._l(t,function(t,n){return i(\"td\",{key:n,class:e.getCellClasses(t)},[i(\"div\",[i(\"span\",[e._v(\"\\n          \"+e._s(t.text)+\"\\n        \")])])])}),0)})],2)])},wo=[];Co._withStripped=!0;var ko=[\"sun\",\"mon\",\"tue\",\"wed\",\"thu\",\"fri\",\"sat\"],So=function(e){return\"number\"===typeof e||\"string\"===typeof e?vr(new Date(e)).getTime():e instanceof Date?vr(e).getTime():NaN},$o=function(e,t){var i=\"function\"===typeof t?Object(b[\"arrayFindIndex\"])(e,t):e.indexOf(t);return i>=0?[].concat(e.slice(0,i),e.slice(i+1)):e},Do={mixins:[g.a],props:{firstDayOfWeek:{default:7,type:Number,validator:function(e){return e>=1&&e<=7}},value:{},defaultValue:{validator:function(e){return null===e||Js(e)||Array.isArray(e)&&e.every(Js)}},date:{},selectionMode:{default:\"day\"},showWeekNumber:{type:Boolean,default:!1},disabledDate:{},minDate:{},maxDate:{},rangeState:{default:function(){return{endDate:null,selecting:!1}}}},computed:{offsetDay:function(){var e=this.firstDayOfWeek;return e>3?7-e:-e},WEEKS:function(){var e=this.firstDayOfWeek;return ko.concat(ko).slice(e,e+7)},year:function(){return this.date.getFullYear()},month:function(){return this.date.getMonth()},startDate:function(){return ar(this.year,this.month)},rows:function(){var e=this,t=new Date(this.year,this.month,1),i=sr(t),n=ir(t.getFullYear(),t.getMonth()),s=ir(t.getFullYear(),0===t.getMonth()?11:t.getMonth()-1);i=0===i?7:i;for(var r=this.offsetDay,o=this.tableRows,a=1,l=this.startDate,u=this.disabledDate,c=\"dates\"===this.selectionMode?Object(b[\"coerceTruthyValueToArray\"])(this.value):[],h=So(new Date),d=0;d<6;d++){var p=o[d];this.showWeekNumber&&(p[0]||(p[0]={type:\"week\",text:lr(or(l,7*d+1))}));for(var f=function(t){var o=p[e.showWeekNumber?t+1:t];o||(o={row:d,column:t,type:\"normal\",inRange:!1,start:!1,end:!1}),o.type=\"normal\";var f=7*d+t,m=or(l,f-r).getTime();o.inRange=m>=So(e.minDate)&&m<=So(e.maxDate),o.start=e.minDate&&m===So(e.minDate),o.end=e.maxDate&&m===So(e.maxDate);var v=m===h;if(v&&(o.type=\"today\"),d>=0&&d<=1){var g=i+r<0?7+i+r:i+r;t+7*d>=g?o.text=a++:(o.text=s-(g-t%7)+1+7*d,o.type=\"prev-month\")}else a<=n?o.text=a++:(o.text=a++-n,o.type=\"next-month\");var y=new Date(m);o.disabled=\"function\"===typeof u&&u(y),o.selected=Object(b[\"arrayFind\"])(c,function(e){return e.getTime()===y.getTime()}),e.$set(p,e.showWeekNumber?t+1:t,o)},m=0;m<7;m++)f(m);if(\"week\"===this.selectionMode){var v=this.showWeekNumber?1:0,g=this.showWeekNumber?7:6,y=this.isWeekActive(p[v+1]);p[v].inRange=y,p[v].start=y,p[g].inRange=y,p[g].end=y}}return o}},watch:{\"rangeState.endDate\":function(e){this.markRange(this.minDate,e)},minDate:function(e,t){So(e)!==So(t)&&this.markRange(this.minDate,this.maxDate)},maxDate:function(e,t){So(e)!==So(t)&&this.markRange(this.minDate,this.maxDate)}},data:function(){return{tableRows:[[],[],[],[],[],[]],lastRow:null,lastColumn:null}},methods:{cellMatchesDate:function(e,t){var i=new Date(t);return this.year===i.getFullYear()&&this.month===i.getMonth()&&Number(e.text)===i.getDate()},getCellClasses:function(e){var t=this,i=this.selectionMode,n=this.defaultValue?Array.isArray(this.defaultValue)?this.defaultValue:[this.defaultValue]:[],s=[];return\"normal\"!==e.type&&\"today\"!==e.type||e.disabled?s.push(e.type):(s.push(\"available\"),\"today\"===e.type&&s.push(\"today\")),\"normal\"===e.type&&n.some(function(i){return t.cellMatchesDate(e,i)})&&s.push(\"default\"),\"day\"!==i||\"normal\"!==e.type&&\"today\"!==e.type||!this.cellMatchesDate(e,this.value)||s.push(\"current\"),!e.inRange||\"normal\"!==e.type&&\"today\"!==e.type&&\"week\"!==this.selectionMode||(s.push(\"in-range\"),e.start&&s.push(\"start-date\"),e.end&&s.push(\"end-date\")),e.disabled&&s.push(\"disabled\"),e.selected&&s.push(\"selected\"),s.join(\" \")},getDateOfCell:function(e,t){var i=7*e+(t-(this.showWeekNumber?1:0))-this.offsetDay;return or(this.startDate,i)},isWeekActive:function(e){if(\"week\"!==this.selectionMode)return!1;var t=new Date(this.year,this.month,1),i=t.getFullYear(),n=t.getMonth();if(\"prev-month\"===e.type&&(t.setMonth(0===n?11:n-1),t.setFullYear(0===n?i-1:i)),\"next-month\"===e.type&&(t.setMonth(11===n?0:n+1),t.setFullYear(11===n?i+1:i)),t.setDate(parseInt(e.text,10)),Js(this.value)){var s=(this.value.getDay()-this.firstDayOfWeek+7)%7-1,r=rr(this.value,s);return r.getTime()===t.getTime()}return!1},markRange:function(e,t){e=So(e),t=So(t)||e;var i=[Math.min(e,t),Math.max(e,t)];e=i[0],t=i[1];for(var n=this.startDate,s=this.rows,r=0,o=s.length;r<o;r++)for(var a=s[r],l=0,u=a.length;l<u;l++)if(!this.showWeekNumber||0!==l){var c=a[l],h=7*r+l+(this.showWeekNumber?-1:0),d=or(n,h-this.offsetDay).getTime();c.inRange=e&&d>=e&&d<=t,c.start=e&&d===e,c.end=t&&d===t}},handleMouseMove:function(e){if(this.rangeState.selecting){var t=e.target;if(\"SPAN\"===t.tagName&&(t=t.parentNode.parentNode),\"DIV\"===t.tagName&&(t=t.parentNode),\"TD\"===t.tagName){var i=t.parentNode.rowIndex-1,n=t.cellIndex;this.rows[i][n].disabled||i===this.lastRow&&n===this.lastColumn||(this.lastRow=i,this.lastColumn=n,this.$emit(\"changerange\",{minDate:this.minDate,maxDate:this.maxDate,rangeState:{selecting:!0,endDate:this.getDateOfCell(i,n)}}))}}},handleClick:function(e){var t=e.target;if(\"SPAN\"===t.tagName&&(t=t.parentNode.parentNode),\"DIV\"===t.tagName&&(t=t.parentNode),\"TD\"===t.tagName){var i=t.parentNode.rowIndex-1,n=\"week\"===this.selectionMode?1:t.cellIndex,s=this.rows[i][n];if(!s.disabled&&\"week\"!==s.type){var r=this.getDateOfCell(i,n);if(\"range\"===this.selectionMode)this.rangeState.selecting?(r>=this.minDate?this.$emit(\"pick\",{minDate:this.minDate,maxDate:r}):this.$emit(\"pick\",{minDate:r,maxDate:this.minDate}),this.rangeState.selecting=!1):(this.$emit(\"pick\",{minDate:r,maxDate:null}),this.rangeState.selecting=!0);else if(\"day\"===this.selectionMode)this.$emit(\"pick\",r);else if(\"week\"===this.selectionMode){var o=lr(r),a=r.getFullYear()+\"w\"+o;this.$emit(\"pick\",{year:r.getFullYear(),week:o,value:a,date:r})}else if(\"dates\"===this.selectionMode){var l=this.value||[],u=s.selected?$o(l,function(e){return e.getTime()===r.getTime()}):[].concat(l,[r]);this.$emit(\"pick\",u)}}}}}},Eo=Do,To=a(Eo,Co,wo,!1,null,null,null);To.options.__file=\"packages/date-picker/src/basic/date-table.vue\";var Oo=To.exports,Io={mixins:[g.a],directives:{Clickoutside:B.a},watch:{showTime:function(e){var t=this;e&&this.$nextTick(function(e){var i=t.$refs.input.$el;i&&(t.pickerWidth=i.getBoundingClientRect().width+10)})},value:function(e){\"dates\"===this.selectionMode&&this.value||(Js(e)?this.date=new Date(e):this.date=this.getDefaultValue())},defaultValue:function(e){Js(this.value)||(this.date=e?new Date(e):new Date)},timePickerVisible:function(e){var t=this;e&&this.$nextTick(function(){return t.$refs.timepicker.adjustSpinners()})},selectionMode:function(e){\"month\"===e?\"year\"===this.currentView&&\"month\"===this.currentView||(this.currentView=\"month\"):\"dates\"===e&&(this.currentView=\"date\")}},methods:{proxyTimePickerDataProperties:function(){var e=this,t=function(t){e.$refs.timepicker.format=t},i=function(t){e.$refs.timepicker.value=t},n=function(t){e.$refs.timepicker.date=t},s=function(t){e.$refs.timepicker.selectableRange=t};this.$watch(\"value\",i),this.$watch(\"date\",n),this.$watch(\"selectableRange\",s),t(this.timeFormat),i(this.value),n(this.date),s(this.selectableRange)},handleClear:function(){this.date=this.getDefaultValue(),this.$emit(\"pick\",null)},emit:function(e){for(var t=this,i=arguments.length,n=Array(i>1?i-1:0),s=1;s<i;s++)n[s-1]=arguments[s];if(e)if(Array.isArray(e)){var r=e.map(function(e){return t.showTime?gr(e):vr(e)});this.$emit.apply(this,[\"pick\",r].concat(n))}else this.$emit.apply(this,[\"pick\",this.showTime?gr(e):vr(e)].concat(n));else this.$emit.apply(this,[\"pick\",e].concat(n));this.userInputDate=null,this.userInputTime=null},showMonthPicker:function(){this.currentView=\"month\"},showYearPicker:function(){this.currentView=\"year\"},prevMonth:function(){this.date=xr(this.date)},nextMonth:function(){this.date=Cr(this.date)},prevYear:function(){\"year\"===this.currentView?this.date=wr(this.date,10):this.date=wr(this.date)},nextYear:function(){\"year\"===this.currentView?this.date=kr(this.date,10):this.date=kr(this.date)},handleShortcutClick:function(e){e.onClick&&e.onClick(this)},handleTimePick:function(e,t,i){if(Js(e)){var n=this.value?fr(this.value,e.getHours(),e.getMinutes(),e.getSeconds()):mr(this.getDefaultValue(),this.defaultTime);this.date=n,this.emit(this.date,!0)}else this.emit(e,!0);i||(this.timePickerVisible=t)},handleTimePickClose:function(){this.timePickerVisible=!1},handleMonthPick:function(e){\"month\"===this.selectionMode?(this.date=pr(this.date,this.year,e,1),this.emit(this.date)):(this.date=_r(this.date,this.year,e),this.currentView=\"date\")},handleDatePick:function(e){if(\"day\"===this.selectionMode){var t=this.value?pr(this.value,e.getFullYear(),e.getMonth(),e.getDate()):mr(e,this.defaultTime);this.checkDateWithinRange(t)||(t=pr(this.selectableRange[0][0],e.getFullYear(),e.getMonth(),e.getDate())),this.date=t,this.emit(this.date,this.showTime)}else\"week\"===this.selectionMode?this.emit(e.date):\"dates\"===this.selectionMode&&this.emit(e,!0)},handleYearPick:function(e){\"year\"===this.selectionMode?(this.date=pr(this.date,e,0,1),this.emit(this.date)):(this.date=_r(this.date,e,this.month),this.currentView=\"month\")},changeToNow:function(){this.disabledDate&&this.disabledDate(new Date)||!this.checkDateWithinRange(new Date)||(this.date=new Date,this.emit(this.date))},confirm:function(){if(\"dates\"===this.selectionMode)this.emit(this.value);else{var e=this.value?this.value:mr(this.getDefaultValue(),this.defaultTime);this.date=new Date(e),this.emit(e)}},resetView:function(){\"month\"===this.selectionMode?this.currentView=\"month\":\"year\"===this.selectionMode?this.currentView=\"year\":this.currentView=\"date\"},handleEnter:function(){document.body.addEventListener(\"keydown\",this.handleKeydown)},handleLeave:function(){this.$emit(\"dodestroy\"),document.body.removeEventListener(\"keydown\",this.handleKeydown)},handleKeydown:function(e){var t=e.keyCode,i=[38,40,37,39];this.visible&&!this.timePickerVisible&&(-1!==i.indexOf(t)&&(this.handleKeyControl(t),e.stopPropagation(),e.preventDefault()),13===t&&null===this.userInputDate&&null===this.userInputTime&&this.emit(this.date,!1))},handleKeyControl:function(e){var t={year:{38:-4,40:4,37:-1,39:1,offset:function(e,t){return e.setFullYear(e.getFullYear()+t)}},month:{38:-4,40:4,37:-1,39:1,offset:function(e,t){return e.setMonth(e.getMonth()+t)}},week:{38:-1,40:1,37:-1,39:1,offset:function(e,t){return e.setDate(e.getDate()+7*t)}},day:{38:-7,40:7,37:-1,39:1,offset:function(e,t){return e.setDate(e.getDate()+t)}}},i=this.selectionMode,n=31536e6,s=this.date.getTime(),r=new Date(this.date.getTime());while(Math.abs(s-r.getTime())<=n){var o=t[i];if(o.offset(r,o[e]),\"function\"!==typeof this.disabledDate||!this.disabledDate(r)){this.date=r,this.$emit(\"pick\",r,!0);break}}},handleVisibleTimeChange:function(e){var t=tr(e,this.timeFormat);t&&this.checkDateWithinRange(t)&&(this.date=pr(t,this.year,this.month,this.monthDate),this.userInputTime=null,this.$refs.timepicker.value=this.date,this.timePickerVisible=!1,this.emit(this.date,!0))},handleVisibleDateChange:function(e){var t=tr(e,this.dateFormat);if(t){if(\"function\"===typeof this.disabledDate&&this.disabledDate(t))return;this.date=fr(t,this.date.getHours(),this.date.getMinutes(),this.date.getSeconds()),this.userInputDate=null,this.resetView(),this.emit(this.date,!0)}},isValidValue:function(e){return e&&!isNaN(e)&&(\"function\"!==typeof this.disabledDate||!this.disabledDate(e))&&this.checkDateWithinRange(e)},getDefaultValue:function(){return this.defaultValue?new Date(this.defaultValue):new Date},checkDateWithinRange:function(e){return!(this.selectableRange.length>0)||yr(e,this.selectableRange,this.format||\"HH:mm:ss\")}},components:{TimePicker:so,YearTable:ho,MonthTable:xo,DateTable:Oo,ElInput:m.a,ElButton:oe.a},data:function(){return{popperClass:\"\",date:new Date,value:\"\",defaultValue:null,defaultTime:null,showTime:!1,selectionMode:\"day\",shortcuts:\"\",visible:!1,currentView:\"date\",disabledDate:\"\",selectableRange:[],firstDayOfWeek:7,showWeekNumber:!1,timePickerVisible:!1,format:\"\",arrowControl:!1,userInputDate:null,userInputTime:null}},computed:{year:function(){return this.date.getFullYear()},month:function(){return this.date.getMonth()},week:function(){return lr(this.date)},monthDate:function(){return this.date.getDate()},footerVisible:function(){return this.showTime||\"dates\"===this.selectionMode},visibleTime:function(){return null!==this.userInputTime?this.userInputTime:er(this.value||this.defaultValue,this.timeFormat)},visibleDate:function(){return null!==this.userInputDate?this.userInputDate:er(this.value||this.defaultValue,this.dateFormat)},yearLabel:function(){var e=this.t(\"el.datepicker.year\");if(\"year\"===this.currentView){var t=10*Math.floor(this.year/10);return e?t+\" \"+e+\" - \"+(t+9)+\" \"+e:t+\" - \"+(t+9)}return this.year+\" \"+e},timeFormat:function(){return this.format?$r(this.format):\"HH:mm:ss\"},dateFormat:function(){return this.format?Sr(this.format):\"yyyy-MM-dd\"}}},Po=Io,Mo=a(Po,qr,Kr,!1,null,null,null);Mo.options.__file=\"packages/date-picker/src/panel/date.vue\";var No=Mo.exports,Fo=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"el-zoom-in-top\"},on:{\"after-leave\":function(t){e.$emit(\"dodestroy\")}}},[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible,expression:\"visible\"}],staticClass:\"el-picker-panel el-date-range-picker el-popper\",class:[{\"has-sidebar\":e.$slots.sidebar||e.shortcuts,\"has-time\":e.showTime},e.popperClass]},[i(\"div\",{staticClass:\"el-picker-panel__body-wrapper\"},[e._t(\"sidebar\"),e.shortcuts?i(\"div\",{staticClass:\"el-picker-panel__sidebar\"},e._l(e.shortcuts,function(t,n){return i(\"button\",{key:n,staticClass:\"el-picker-panel__shortcut\",attrs:{type:\"button\"},on:{click:function(i){e.handleShortcutClick(t)}}},[e._v(e._s(t.text))])}),0):e._e(),i(\"div\",{staticClass:\"el-picker-panel__body\"},[e.showTime?i(\"div\",{staticClass:\"el-date-range-picker__time-header\"},[i(\"span\",{staticClass:\"el-date-range-picker__editors-wrap\"},[i(\"span\",{staticClass:\"el-date-range-picker__time-picker-wrap\"},[i(\"el-input\",{ref:\"minInput\",staticClass:\"el-date-range-picker__editor\",attrs:{size:\"small\",disabled:e.rangeState.selecting,placeholder:e.t(\"el.datepicker.startDate\"),value:e.minVisibleDate},on:{input:function(t){return e.handleDateInput(t,\"min\")},change:function(t){return e.handleDateChange(t,\"min\")}}})],1),i(\"span\",{directives:[{name:\"clickoutside\",rawName:\"v-clickoutside\",value:e.handleMinTimeClose,expression:\"handleMinTimeClose\"}],staticClass:\"el-date-range-picker__time-picker-wrap\"},[i(\"el-input\",{staticClass:\"el-date-range-picker__editor\",attrs:{size:\"small\",disabled:e.rangeState.selecting,placeholder:e.t(\"el.datepicker.startTime\"),value:e.minVisibleTime},on:{focus:function(t){e.minTimePickerVisible=!0},input:function(t){return e.handleTimeInput(t,\"min\")},change:function(t){return e.handleTimeChange(t,\"min\")}}}),i(\"time-picker\",{ref:\"minTimePicker\",attrs:{\"time-arrow-control\":e.arrowControl,visible:e.minTimePickerVisible},on:{pick:e.handleMinTimePick,mounted:function(t){e.$refs.minTimePicker.format=e.timeFormat}}})],1)]),i(\"span\",{staticClass:\"el-icon-arrow-right\"}),i(\"span\",{staticClass:\"el-date-range-picker__editors-wrap is-right\"},[i(\"span\",{staticClass:\"el-date-range-picker__time-picker-wrap\"},[i(\"el-input\",{staticClass:\"el-date-range-picker__editor\",attrs:{size:\"small\",disabled:e.rangeState.selecting,placeholder:e.t(\"el.datepicker.endDate\"),value:e.maxVisibleDate,readonly:!e.minDate},on:{input:function(t){return e.handleDateInput(t,\"max\")},change:function(t){return e.handleDateChange(t,\"max\")}}})],1),i(\"span\",{directives:[{name:\"clickoutside\",rawName:\"v-clickoutside\",value:e.handleMaxTimeClose,expression:\"handleMaxTimeClose\"}],staticClass:\"el-date-range-picker__time-picker-wrap\"},[i(\"el-input\",{staticClass:\"el-date-range-picker__editor\",attrs:{size:\"small\",disabled:e.rangeState.selecting,placeholder:e.t(\"el.datepicker.endTime\"),value:e.maxVisibleTime,readonly:!e.minDate},on:{focus:function(t){e.minDate&&(e.maxTimePickerVisible=!0)},input:function(t){return e.handleTimeInput(t,\"max\")},change:function(t){return e.handleTimeChange(t,\"max\")}}}),i(\"time-picker\",{ref:\"maxTimePicker\",attrs:{\"time-arrow-control\":e.arrowControl,visible:e.maxTimePickerVisible},on:{pick:e.handleMaxTimePick,mounted:function(t){e.$refs.maxTimePicker.format=e.timeFormat}}})],1)])]):e._e(),i(\"div\",{staticClass:\"el-picker-panel__content el-date-range-picker__content is-left\"},[i(\"div\",{staticClass:\"el-date-range-picker__header\"},[i(\"button\",{staticClass:\"el-picker-panel__icon-btn el-icon-d-arrow-left\",attrs:{type:\"button\"},on:{click:e.leftPrevYear}}),i(\"button\",{staticClass:\"el-picker-panel__icon-btn el-icon-arrow-left\",attrs:{type:\"button\"},on:{click:e.leftPrevMonth}}),e.unlinkPanels?i(\"button\",{staticClass:\"el-picker-panel__icon-btn el-icon-d-arrow-right\",class:{\"is-disabled\":!e.enableYearArrow},attrs:{type:\"button\",disabled:!e.enableYearArrow},on:{click:e.leftNextYear}}):e._e(),e.unlinkPanels?i(\"button\",{staticClass:\"el-picker-panel__icon-btn el-icon-arrow-right\",class:{\"is-disabled\":!e.enableMonthArrow},attrs:{type:\"button\",disabled:!e.enableMonthArrow},on:{click:e.leftNextMonth}}):e._e(),i(\"div\",[e._v(e._s(e.leftLabel))])]),i(\"date-table\",{attrs:{\"selection-mode\":\"range\",date:e.leftDate,\"default-value\":e.defaultValue,\"min-date\":e.minDate,\"max-date\":e.maxDate,\"range-state\":e.rangeState,\"disabled-date\":e.disabledDate,\"first-day-of-week\":e.firstDayOfWeek},on:{changerange:e.handleChangeRange,pick:e.handleRangePick}})],1),i(\"div\",{staticClass:\"el-picker-panel__content el-date-range-picker__content is-right\"},[i(\"div\",{staticClass:\"el-date-range-picker__header\"},[e.unlinkPanels?i(\"button\",{staticClass:\"el-picker-panel__icon-btn el-icon-d-arrow-left\",class:{\"is-disabled\":!e.enableYearArrow},attrs:{type:\"button\",disabled:!e.enableYearArrow},on:{click:e.rightPrevYear}}):e._e(),e.unlinkPanels?i(\"button\",{staticClass:\"el-picker-panel__icon-btn el-icon-arrow-left\",class:{\"is-disabled\":!e.enableMonthArrow},attrs:{type:\"button\",disabled:!e.enableMonthArrow},on:{click:e.rightPrevMonth}}):e._e(),i(\"button\",{staticClass:\"el-picker-panel__icon-btn el-icon-d-arrow-right\",attrs:{type:\"button\"},on:{click:e.rightNextYear}}),i(\"button\",{staticClass:\"el-picker-panel__icon-btn el-icon-arrow-right\",attrs:{type:\"button\"},on:{click:e.rightNextMonth}}),i(\"div\",[e._v(e._s(e.rightLabel))])]),i(\"date-table\",{attrs:{\"selection-mode\":\"range\",date:e.rightDate,\"default-value\":e.defaultValue,\"min-date\":e.minDate,\"max-date\":e.maxDate,\"range-state\":e.rangeState,\"disabled-date\":e.disabledDate,\"first-day-of-week\":e.firstDayOfWeek},on:{changerange:e.handleChangeRange,pick:e.handleRangePick}})],1)])],2),e.showTime?i(\"div\",{staticClass:\"el-picker-panel__footer\"},[i(\"el-button\",{staticClass:\"el-picker-panel__link-btn\",attrs:{size:\"mini\",type:\"text\"},on:{click:e.handleClear}},[e._v(\"\\n        \"+e._s(e.t(\"el.datepicker.clear\"))+\"\\n      \")]),i(\"el-button\",{staticClass:\"el-picker-panel__link-btn\",attrs:{plain:\"\",size:\"mini\",disabled:e.btnDisabled},on:{click:function(t){e.handleConfirm(!1)}}},[e._v(\"\\n        \"+e._s(e.t(\"el.datepicker.confirm\"))+\"\\n      \")])],1):e._e()])])},Ao=[];Fo._withStripped=!0;var Lo=function(e){return Array.isArray(e)?[new Date(e[0]),new Date(e[1])]:e?[new Date(e),or(new Date(e),1)]:[new Date,or(new Date,1)]},Vo={mixins:[g.a],directives:{Clickoutside:B.a},computed:{btnDisabled:function(){return!(this.minDate&&this.maxDate&&!this.selecting&&this.isValidValue([this.minDate,this.maxDate]))},leftLabel:function(){return this.leftDate.getFullYear()+\" \"+this.t(\"el.datepicker.year\")+\" \"+this.t(\"el.datepicker.month\"+(this.leftDate.getMonth()+1))},rightLabel:function(){return this.rightDate.getFullYear()+\" \"+this.t(\"el.datepicker.year\")+\" \"+this.t(\"el.datepicker.month\"+(this.rightDate.getMonth()+1))},leftYear:function(){return this.leftDate.getFullYear()},leftMonth:function(){return this.leftDate.getMonth()},leftMonthDate:function(){return this.leftDate.getDate()},rightYear:function(){return this.rightDate.getFullYear()},rightMonth:function(){return this.rightDate.getMonth()},rightMonthDate:function(){return this.rightDate.getDate()},minVisibleDate:function(){return null!==this.dateUserInput.min?this.dateUserInput.min:this.minDate?er(this.minDate,this.dateFormat):\"\"},maxVisibleDate:function(){return null!==this.dateUserInput.max?this.dateUserInput.max:this.maxDate||this.minDate?er(this.maxDate||this.minDate,this.dateFormat):\"\"},minVisibleTime:function(){return null!==this.timeUserInput.min?this.timeUserInput.min:this.minDate?er(this.minDate,this.timeFormat):\"\"},maxVisibleTime:function(){return null!==this.timeUserInput.max?this.timeUserInput.max:this.maxDate||this.minDate?er(this.maxDate||this.minDate,this.timeFormat):\"\"},timeFormat:function(){return this.format?$r(this.format):\"HH:mm:ss\"},dateFormat:function(){return this.format?Sr(this.format):\"yyyy-MM-dd\"},enableMonthArrow:function(){var e=(this.leftMonth+1)%12,t=this.leftMonth+1>=12?1:0;return this.unlinkPanels&&new Date(this.leftYear+t,e)<new Date(this.rightYear,this.rightMonth)},enableYearArrow:function(){return this.unlinkPanels&&12*this.rightYear+this.rightMonth-(12*this.leftYear+this.leftMonth+1)>=12}},data:function(){return{popperClass:\"\",value:[],defaultValue:null,defaultTime:null,minDate:\"\",maxDate:\"\",leftDate:new Date,rightDate:Cr(new Date),rangeState:{endDate:null,selecting:!1,row:null,column:null},showTime:!1,shortcuts:\"\",visible:\"\",disabledDate:\"\",firstDayOfWeek:7,minTimePickerVisible:!1,maxTimePickerVisible:!1,format:\"\",arrowControl:!1,unlinkPanels:!1,dateUserInput:{min:null,max:null},timeUserInput:{min:null,max:null}}},watch:{minDate:function(e){var t=this;this.dateUserInput.min=null,this.timeUserInput.min=null,this.$nextTick(function(){if(t.$refs.maxTimePicker&&t.maxDate&&t.maxDate<t.minDate){var e=\"HH:mm:ss\";t.$refs.maxTimePicker.selectableRange=[[tr(er(t.minDate,e),e),tr(\"23:59:59\",e)]]}}),e&&this.$refs.minTimePicker&&(this.$refs.minTimePicker.date=e,this.$refs.minTimePicker.value=e)},maxDate:function(e){this.dateUserInput.max=null,this.timeUserInput.max=null,e&&this.$refs.maxTimePicker&&(this.$refs.maxTimePicker.date=e,this.$refs.maxTimePicker.value=e)},minTimePickerVisible:function(e){var t=this;e&&this.$nextTick(function(){t.$refs.minTimePicker.date=t.minDate,t.$refs.minTimePicker.value=t.minDate,t.$refs.minTimePicker.adjustSpinners()})},maxTimePickerVisible:function(e){var t=this;e&&this.$nextTick(function(){t.$refs.maxTimePicker.date=t.maxDate,t.$refs.maxTimePicker.value=t.maxDate,t.$refs.maxTimePicker.adjustSpinners()})},value:function(e){if(e){if(Array.isArray(e))if(this.minDate=Js(e[0])?new Date(e[0]):null,this.maxDate=Js(e[1])?new Date(e[1]):null,this.minDate)if(this.leftDate=this.minDate,this.unlinkPanels&&this.maxDate){var t=this.minDate.getFullYear(),i=this.minDate.getMonth(),n=this.maxDate.getFullYear(),s=this.maxDate.getMonth();this.rightDate=t===n&&i===s?Cr(this.maxDate):this.maxDate}else this.rightDate=Cr(this.leftDate);else this.leftDate=Lo(this.defaultValue)[0],this.rightDate=Cr(this.leftDate)}else this.minDate=null,this.maxDate=null},defaultValue:function(e){if(!Array.isArray(this.value)){var t=Lo(e),i=t[0],n=t[1];this.leftDate=i,this.rightDate=e&&e[1]&&this.unlinkPanels?n:Cr(this.leftDate)}}},methods:{handleClear:function(){this.minDate=null,this.maxDate=null,this.leftDate=Lo(this.defaultValue)[0],this.rightDate=Cr(this.leftDate),this.$emit(\"pick\",null)},handleChangeRange:function(e){this.minDate=e.minDate,this.maxDate=e.maxDate,this.rangeState=e.rangeState},handleDateInput:function(e,t){if(this.dateUserInput[t]=e,e.length===this.dateFormat.length){var i=tr(e,this.dateFormat);if(i){if(\"function\"===typeof this.disabledDate&&this.disabledDate(new Date(i)))return;\"min\"===t?(this.minDate=pr(this.minDate||new Date,i.getFullYear(),i.getMonth(),i.getDate()),this.leftDate=new Date(i),this.unlinkPanels||(this.rightDate=Cr(this.leftDate))):(this.maxDate=pr(this.maxDate||new Date,i.getFullYear(),i.getMonth(),i.getDate()),this.rightDate=new Date(i),this.unlinkPanels||(this.leftDate=xr(i)))}}},handleDateChange:function(e,t){var i=tr(e,this.dateFormat);i&&(\"min\"===t?(this.minDate=pr(this.minDate,i.getFullYear(),i.getMonth(),i.getDate()),this.minDate>this.maxDate&&(this.maxDate=this.minDate)):(this.maxDate=pr(this.maxDate,i.getFullYear(),i.getMonth(),i.getDate()),this.maxDate<this.minDate&&(this.minDate=this.maxDate)))},handleTimeInput:function(e,t){var i=this;if(this.timeUserInput[t]=e,e.length===this.timeFormat.length){var n=tr(e,this.timeFormat);n&&(\"min\"===t?(this.minDate=fr(this.minDate,n.getHours(),n.getMinutes(),n.getSeconds()),this.$nextTick(function(e){return i.$refs.minTimePicker.adjustSpinners()})):(this.maxDate=fr(this.maxDate,n.getHours(),n.getMinutes(),n.getSeconds()),this.$nextTick(function(e){return i.$refs.maxTimePicker.adjustSpinners()})))}},handleTimeChange:function(e,t){var i=tr(e,this.timeFormat);i&&(\"min\"===t?(this.minDate=fr(this.minDate,i.getHours(),i.getMinutes(),i.getSeconds()),this.minDate>this.maxDate&&(this.maxDate=this.minDate),this.$refs.minTimePicker.value=this.minDate,this.minTimePickerVisible=!1):(this.maxDate=fr(this.maxDate,i.getHours(),i.getMinutes(),i.getSeconds()),this.maxDate<this.minDate&&(this.minDate=this.maxDate),this.$refs.maxTimePicker.value=this.minDate,this.maxTimePickerVisible=!1))},handleRangePick:function(e){var t=this,i=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],n=this.defaultTime||[],s=mr(e.minDate,n[0]),r=mr(e.maxDate,n[1]);this.maxDate===r&&this.minDate===s||(this.onPick&&this.onPick(e),this.maxDate=r,this.minDate=s,setTimeout(function(){t.maxDate=r,t.minDate=s},10),i&&!this.showTime&&this.handleConfirm())},handleShortcutClick:function(e){e.onClick&&e.onClick(this)},handleMinTimePick:function(e,t,i){this.minDate=this.minDate||new Date,e&&(this.minDate=fr(this.minDate,e.getHours(),e.getMinutes(),e.getSeconds())),i||(this.minTimePickerVisible=t),(!this.maxDate||this.maxDate&&this.maxDate.getTime()<this.minDate.getTime())&&(this.maxDate=new Date(this.minDate))},handleMinTimeClose:function(){this.minTimePickerVisible=!1},handleMaxTimePick:function(e,t,i){this.maxDate&&e&&(this.maxDate=fr(this.maxDate,e.getHours(),e.getMinutes(),e.getSeconds())),i||(this.maxTimePickerVisible=t),this.maxDate&&this.minDate&&this.minDate.getTime()>this.maxDate.getTime()&&(this.minDate=new Date(this.maxDate))},handleMaxTimeClose:function(){this.maxTimePickerVisible=!1},leftPrevYear:function(){this.leftDate=wr(this.leftDate),this.unlinkPanels||(this.rightDate=Cr(this.leftDate))},leftPrevMonth:function(){this.leftDate=xr(this.leftDate),this.unlinkPanels||(this.rightDate=Cr(this.leftDate))},rightNextYear:function(){this.unlinkPanels?this.rightDate=kr(this.rightDate):(this.leftDate=kr(this.leftDate),this.rightDate=Cr(this.leftDate))},rightNextMonth:function(){this.unlinkPanels?this.rightDate=Cr(this.rightDate):(this.leftDate=Cr(this.leftDate),this.rightDate=Cr(this.leftDate))},leftNextYear:function(){this.leftDate=kr(this.leftDate)},leftNextMonth:function(){this.leftDate=Cr(this.leftDate)},rightPrevYear:function(){this.rightDate=wr(this.rightDate)},rightPrevMonth:function(){this.rightDate=xr(this.rightDate)},handleConfirm:function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];this.isValidValue([this.minDate,this.maxDate])&&this.$emit(\"pick\",[this.minDate,this.maxDate],e)},isValidValue:function(e){return Array.isArray(e)&&e&&e[0]&&e[1]&&Js(e[0])&&Js(e[1])&&e[0].getTime()<=e[1].getTime()&&(\"function\"!==typeof this.disabledDate||!this.disabledDate(e[0])&&!this.disabledDate(e[1]))},resetView:function(){this.minDate=this.value&&Js(this.value[0])?new Date(this.value[0]):null,this.maxDate=this.value&&Js(this.value[0])?new Date(this.value[1]):null}},components:{TimePicker:so,DateTable:Oo,ElInput:m.a,ElButton:oe.a}},Bo=Vo,zo=a(Bo,Fo,Ao,!1,null,null,null);zo.options.__file=\"packages/date-picker/src/panel/date-range.vue\";var jo=zo.exports,Ho=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"el-zoom-in-top\"},on:{\"after-leave\":function(t){e.$emit(\"dodestroy\")}}},[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible,expression:\"visible\"}],staticClass:\"el-picker-panel el-date-range-picker el-popper\",class:[{\"has-sidebar\":e.$slots.sidebar||e.shortcuts},e.popperClass]},[i(\"div\",{staticClass:\"el-picker-panel__body-wrapper\"},[e._t(\"sidebar\"),e.shortcuts?i(\"div\",{staticClass:\"el-picker-panel__sidebar\"},e._l(e.shortcuts,function(t,n){return i(\"button\",{key:n,staticClass:\"el-picker-panel__shortcut\",attrs:{type:\"button\"},on:{click:function(i){e.handleShortcutClick(t)}}},[e._v(e._s(t.text))])}),0):e._e(),i(\"div\",{staticClass:\"el-picker-panel__body\"},[i(\"div\",{staticClass:\"el-picker-panel__content el-date-range-picker__content is-left\"},[i(\"div\",{staticClass:\"el-date-range-picker__header\"},[i(\"button\",{staticClass:\"el-picker-panel__icon-btn el-icon-d-arrow-left\",attrs:{type:\"button\"},on:{click:e.leftPrevYear}}),e.unlinkPanels?i(\"button\",{staticClass:\"el-picker-panel__icon-btn el-icon-d-arrow-right\",class:{\"is-disabled\":!e.enableYearArrow},attrs:{type:\"button\",disabled:!e.enableYearArrow},on:{click:e.leftNextYear}}):e._e(),i(\"div\",[e._v(e._s(e.leftLabel))])]),i(\"month-table\",{attrs:{\"selection-mode\":\"range\",date:e.leftDate,\"default-value\":e.defaultValue,\"min-date\":e.minDate,\"max-date\":e.maxDate,\"range-state\":e.rangeState,\"disabled-date\":e.disabledDate},on:{changerange:e.handleChangeRange,pick:e.handleRangePick}})],1),i(\"div\",{staticClass:\"el-picker-panel__content el-date-range-picker__content is-right\"},[i(\"div\",{staticClass:\"el-date-range-picker__header\"},[e.unlinkPanels?i(\"button\",{staticClass:\"el-picker-panel__icon-btn el-icon-d-arrow-left\",class:{\"is-disabled\":!e.enableYearArrow},attrs:{type:\"button\",disabled:!e.enableYearArrow},on:{click:e.rightPrevYear}}):e._e(),i(\"button\",{staticClass:\"el-picker-panel__icon-btn el-icon-d-arrow-right\",attrs:{type:\"button\"},on:{click:e.rightNextYear}}),i(\"div\",[e._v(e._s(e.rightLabel))])]),i(\"month-table\",{attrs:{\"selection-mode\":\"range\",date:e.rightDate,\"default-value\":e.defaultValue,\"min-date\":e.minDate,\"max-date\":e.maxDate,\"range-state\":e.rangeState,\"disabled-date\":e.disabledDate},on:{changerange:e.handleChangeRange,pick:e.handleRangePick}})],1)])],2)])])},Ro=[];Ho._withStripped=!0;var Wo=function(e){return Array.isArray(e)?[new Date(e[0]),new Date(e[1])]:e?[new Date(e),Cr(new Date(e))]:[new Date,Cr(new Date)]},qo={mixins:[g.a],directives:{Clickoutside:B.a},computed:{btnDisabled:function(){return!(this.minDate&&this.maxDate&&!this.selecting&&this.isValidValue([this.minDate,this.maxDate]))},leftLabel:function(){return this.leftDate.getFullYear()+\" \"+this.t(\"el.datepicker.year\")},rightLabel:function(){return this.rightDate.getFullYear()+\" \"+this.t(\"el.datepicker.year\")},leftYear:function(){return this.leftDate.getFullYear()},rightYear:function(){return this.rightDate.getFullYear()===this.leftDate.getFullYear()?this.leftDate.getFullYear()+1:this.rightDate.getFullYear()},enableYearArrow:function(){return this.unlinkPanels&&this.rightYear>this.leftYear+1}},data:function(){return{popperClass:\"\",value:[],defaultValue:null,defaultTime:null,minDate:\"\",maxDate:\"\",leftDate:new Date,rightDate:kr(new Date),rangeState:{endDate:null,selecting:!1,row:null,column:null},shortcuts:\"\",visible:\"\",disabledDate:\"\",format:\"\",arrowControl:!1,unlinkPanels:!1}},watch:{value:function(e){if(e){if(Array.isArray(e))if(this.minDate=Js(e[0])?new Date(e[0]):null,this.maxDate=Js(e[1])?new Date(e[1]):null,this.minDate)if(this.leftDate=this.minDate,this.unlinkPanels&&this.maxDate){var t=this.minDate.getFullYear(),i=this.maxDate.getFullYear();this.rightDate=t===i?kr(this.maxDate):this.maxDate}else this.rightDate=kr(this.leftDate);else this.leftDate=Wo(this.defaultValue)[0],this.rightDate=kr(this.leftDate)}else this.minDate=null,this.maxDate=null},defaultValue:function(e){if(!Array.isArray(this.value)){var t=Wo(e),i=t[0],n=t[1];this.leftDate=i,this.rightDate=e&&e[1]&&i.getFullYear()!==n.getFullYear()&&this.unlinkPanels?n:kr(this.leftDate)}}},methods:{handleClear:function(){this.minDate=null,this.maxDate=null,this.leftDate=Wo(this.defaultValue)[0],this.rightDate=kr(this.leftDate),this.$emit(\"pick\",null)},handleChangeRange:function(e){this.minDate=e.minDate,this.maxDate=e.maxDate,this.rangeState=e.rangeState},handleRangePick:function(e){var t=this,i=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],n=this.defaultTime||[],s=mr(e.minDate,n[0]),r=mr(e.maxDate,n[1]);this.maxDate===r&&this.minDate===s||(this.onPick&&this.onPick(e),this.maxDate=r,this.minDate=s,setTimeout(function(){t.maxDate=r,t.minDate=s},10),i&&this.handleConfirm())},handleShortcutClick:function(e){e.onClick&&e.onClick(this)},leftPrevYear:function(){this.leftDate=wr(this.leftDate),this.unlinkPanels||(this.rightDate=wr(this.rightDate))},rightNextYear:function(){this.unlinkPanels||(this.leftDate=kr(this.leftDate)),this.rightDate=kr(this.rightDate)},leftNextYear:function(){this.leftDate=kr(this.leftDate)},rightPrevYear:function(){this.rightDate=wr(this.rightDate)},handleConfirm:function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];this.isValidValue([this.minDate,this.maxDate])&&this.$emit(\"pick\",[this.minDate,this.maxDate],e)},isValidValue:function(e){return Array.isArray(e)&&e&&e[0]&&e[1]&&Js(e[0])&&Js(e[1])&&e[0].getTime()<=e[1].getTime()&&(\"function\"!==typeof this.disabledDate||!this.disabledDate(e[0])&&!this.disabledDate(e[1]))},resetView:function(){this.minDate=this.value&&Js(this.value[0])?new Date(this.value[0]):null,this.maxDate=this.value&&Js(this.value[0])?new Date(this.value[1]):null}},components:{MonthTable:xo,ElInput:m.a,ElButton:oe.a}},Ko=qo,Yo=a(Ko,Ho,Ro,!1,null,null,null);Yo.options.__file=\"packages/date-picker/src/panel/month-range.vue\";var Uo=Yo.exports,Go=function(e){return\"daterange\"===e||\"datetimerange\"===e?jo:\"monthrange\"===e?Uo:No},Xo={mixins:[Wr],name:\"ElDatePicker\",props:{type:{type:String,default:\"date\"},timeArrowControl:Boolean},watch:{type:function(e){this.picker?(this.unmountPicker(),this.panel=Go(e),this.mountPicker()):this.panel=Go(e)}},created:function(){this.panel=Go(this.type)},install:function(e){e.component(Xo.name,Xo)}},Qo=Xo,Jo=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"el-zoom-in-top\"},on:{\"before-enter\":e.handleMenuEnter,\"after-leave\":function(t){e.$emit(\"dodestroy\")}}},[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible,expression:\"visible\"}],ref:\"popper\",staticClass:\"el-picker-panel time-select el-popper\",class:e.popperClass,style:{width:e.width+\"px\"}},[i(\"el-scrollbar\",{attrs:{noresize:\"\",\"wrap-class\":\"el-picker-panel__content\"}},e._l(e.items,function(t){return i(\"div\",{key:t.value,staticClass:\"time-select-item\",class:{selected:e.value===t.value,disabled:t.disabled,default:t.value===e.defaultValue},attrs:{disabled:t.disabled},on:{click:function(i){e.handleClick(t)}}},[e._v(e._s(t.value))])}),0)],1)])},Zo=[];Jo._withStripped=!0;var ea=function(e){var t=(e||\"\").split(\":\");if(t.length>=2){var i=parseInt(t[0],10),n=parseInt(t[1],10);return{hours:i,minutes:n}}return null},ta=function(e,t){var i=ea(e),n=ea(t),s=i.minutes+60*i.hours,r=n.minutes+60*n.hours;return s===r?0:s>r?1:-1},ia=function(e){return(e.hours<10?\"0\"+e.hours:e.hours)+\":\"+(e.minutes<10?\"0\"+e.minutes:e.minutes)},na=function(e,t){var i=ea(e),n=ea(t),s={hours:i.hours,minutes:i.minutes};return s.minutes+=n.minutes,s.hours+=n.hours,s.hours+=Math.floor(s.minutes/60),s.minutes=s.minutes%60,ia(s)},sa={components:{ElScrollbar:q.a},watch:{value:function(e){var t=this;e&&this.$nextTick(function(){return t.scrollToOption()})}},methods:{handleClick:function(e){e.disabled||this.$emit(\"pick\",e.value)},handleClear:function(){this.$emit(\"pick\",null)},scrollToOption:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:\".selected\",t=this.$refs.popper.querySelector(\".el-picker-panel__content\");nn()(t,t.querySelector(e))},handleMenuEnter:function(){var e=this,t=-1!==this.items.map(function(e){return e.value}).indexOf(this.value),i=-1!==this.items.map(function(e){return e.value}).indexOf(this.defaultValue),n=(t?\".selected\":i&&\".default\")||\".time-select-item:not(.disabled)\";this.$nextTick(function(){return e.scrollToOption(n)})},scrollDown:function(e){var t=this.items,i=t.length,n=t.length,s=t.map(function(e){return e.value}).indexOf(this.value);while(n--)if(s=(s+e+i)%i,!t[s].disabled)return void this.$emit(\"pick\",t[s].value,!0)},isValidValue:function(e){return-1!==this.items.filter(function(e){return!e.disabled}).map(function(e){return e.value}).indexOf(e)},handleKeydown:function(e){var t=e.keyCode;if(38===t||40===t){var i={40:1,38:-1},n=i[t.toString()];return this.scrollDown(n),void e.stopPropagation()}}},data:function(){return{popperClass:\"\",start:\"09:00\",end:\"18:00\",step:\"00:30\",value:\"\",defaultValue:\"\",visible:!1,minTime:\"\",maxTime:\"\",width:0}},computed:{items:function(){var e=this.start,t=this.end,i=this.step,n=[];if(e&&t&&i){var s=e;while(ta(s,t)<=0)n.push({value:s,disabled:ta(s,this.minTime||\"-1:-1\")<=0||ta(s,this.maxTime||\"100:100\")>=0}),s=na(s,i)}return n}}},ra=sa,oa=a(ra,Jo,Zo,!1,null,null,null);oa.options.__file=\"packages/date-picker/src/panel/time-select.vue\";var aa=oa.exports,la={mixins:[Wr],name:\"ElTimeSelect\",componentName:\"ElTimeSelect\",props:{type:{type:String,default:\"time-select\"}},beforeCreate:function(){this.panel=aa},install:function(e){e.component(la.name,la)}},ua=la,ca=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"el-zoom-in-top\"},on:{\"after-leave\":function(t){e.$emit(\"dodestroy\")}}},[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible,expression:\"visible\"}],staticClass:\"el-time-range-picker el-picker-panel el-popper\",class:e.popperClass},[i(\"div\",{staticClass:\"el-time-range-picker__content\"},[i(\"div\",{staticClass:\"el-time-range-picker__cell\"},[i(\"div\",{staticClass:\"el-time-range-picker__header\"},[e._v(e._s(e.t(\"el.datepicker.startTime\")))]),i(\"div\",{staticClass:\"el-time-range-picker__body el-time-panel__content\",class:{\"has-seconds\":e.showSeconds,\"is-arrow\":e.arrowControl}},[i(\"time-spinner\",{ref:\"minSpinner\",attrs:{\"show-seconds\":e.showSeconds,\"am-pm-mode\":e.amPmMode,\"arrow-control\":e.arrowControl,date:e.minDate},on:{change:e.handleMinChange,\"select-range\":e.setMinSelectionRange}})],1)]),i(\"div\",{staticClass:\"el-time-range-picker__cell\"},[i(\"div\",{staticClass:\"el-time-range-picker__header\"},[e._v(e._s(e.t(\"el.datepicker.endTime\")))]),i(\"div\",{staticClass:\"el-time-range-picker__body el-time-panel__content\",class:{\"has-seconds\":e.showSeconds,\"is-arrow\":e.arrowControl}},[i(\"time-spinner\",{ref:\"maxSpinner\",attrs:{\"show-seconds\":e.showSeconds,\"am-pm-mode\":e.amPmMode,\"arrow-control\":e.arrowControl,date:e.maxDate},on:{change:e.handleMaxChange,\"select-range\":e.setMaxSelectionRange}})],1)])]),i(\"div\",{staticClass:\"el-time-panel__footer\"},[i(\"button\",{staticClass:\"el-time-panel__btn cancel\",attrs:{type:\"button\"},on:{click:function(t){e.handleCancel()}}},[e._v(e._s(e.t(\"el.datepicker.cancel\")))]),i(\"button\",{staticClass:\"el-time-panel__btn confirm\",attrs:{type:\"button\",disabled:e.btnDisabled},on:{click:function(t){e.handleConfirm()}}},[e._v(e._s(e.t(\"el.datepicker.confirm\")))])])])])},ha=[];ca._withStripped=!0;var da=tr(\"00:00:00\",\"HH:mm:ss\"),pa=tr(\"23:59:59\",\"HH:mm:ss\"),fa=function(e){return pr(da,e.getFullYear(),e.getMonth(),e.getDate())},ma=function(e){return pr(pa,e.getFullYear(),e.getMonth(),e.getDate())},va=function(e,t){return new Date(Math.min(e.getTime()+t,ma(e).getTime()))},ga={mixins:[g.a],components:{TimeSpinner:eo},computed:{showSeconds:function(){return-1!==(this.format||\"\").indexOf(\"ss\")},offset:function(){return this.showSeconds?11:8},spinner:function(){return this.selectionRange[0]<this.offset?this.$refs.minSpinner:this.$refs.maxSpinner},btnDisabled:function(){return this.minDate.getTime()>this.maxDate.getTime()},amPmMode:function(){return-1!==(this.format||\"\").indexOf(\"A\")?\"A\":-1!==(this.format||\"\").indexOf(\"a\")?\"a\":\"\"}},data:function(){return{popperClass:\"\",minDate:new Date,maxDate:new Date,value:[],oldValue:[new Date,new Date],defaultValue:null,format:\"HH:mm:ss\",visible:!1,selectionRange:[0,2],arrowControl:!1}},watch:{value:function(e){Array.isArray(e)?(this.minDate=new Date(e[0]),this.maxDate=new Date(e[1])):Array.isArray(this.defaultValue)?(this.minDate=new Date(this.defaultValue[0]),this.maxDate=new Date(this.defaultValue[1])):this.defaultValue?(this.minDate=new Date(this.defaultValue),this.maxDate=va(new Date(this.defaultValue),36e5)):(this.minDate=new Date,this.maxDate=va(new Date,36e5))},visible:function(e){var t=this;e&&(this.oldValue=this.value,this.$nextTick(function(){return t.$refs.minSpinner.emitSelectRange(\"hours\")}))}},methods:{handleClear:function(){this.$emit(\"pick\",null)},handleCancel:function(){this.$emit(\"pick\",this.oldValue)},handleMinChange:function(e){this.minDate=gr(e),this.handleChange()},handleMaxChange:function(e){this.maxDate=gr(e),this.handleChange()},handleChange:function(){this.isValidValue([this.minDate,this.maxDate])&&(this.$refs.minSpinner.selectableRange=[[fa(this.minDate),this.maxDate]],this.$refs.maxSpinner.selectableRange=[[this.minDate,ma(this.maxDate)]],this.$emit(\"pick\",[this.minDate,this.maxDate],!0))},setMinSelectionRange:function(e,t){this.$emit(\"select-range\",e,t,\"min\"),this.selectionRange=[e,t]},setMaxSelectionRange:function(e,t){this.$emit(\"select-range\",e,t,\"max\"),this.selectionRange=[e+this.offset,t+this.offset]},handleConfirm:function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0],t=this.$refs.minSpinner.selectableRange,i=this.$refs.maxSpinner.selectableRange;this.minDate=br(this.minDate,t,this.format),this.maxDate=br(this.maxDate,i,this.format),this.$emit(\"pick\",[this.minDate,this.maxDate],e)},adjustSpinners:function(){this.$refs.minSpinner.adjustSpinners(),this.$refs.maxSpinner.adjustSpinners()},changeSelectionRange:function(e){var t=this.showSeconds?[0,3,6,11,14,17]:[0,3,8,11],i=[\"hours\",\"minutes\"].concat(this.showSeconds?[\"seconds\"]:[]),n=t.indexOf(this.selectionRange[0]),s=(n+e+t.length)%t.length,r=t.length/2;s<r?this.$refs.minSpinner.emitSelectRange(i[s]):this.$refs.maxSpinner.emitSelectRange(i[s-r])},isValidValue:function(e){return Array.isArray(e)&&yr(this.minDate,this.$refs.minSpinner.selectableRange)&&yr(this.maxDate,this.$refs.maxSpinner.selectableRange)},handleKeydown:function(e){var t=e.keyCode,i={38:-1,40:1,37:-1,39:1};if(37===t||39===t){var n=i[t];return this.changeSelectionRange(n),void e.preventDefault()}if(38===t||40===t){var s=i[t];return this.spinner.scrollDown(s),void e.preventDefault()}}}},ba=ga,ya=a(ba,ca,ha,!1,null,null,null);ya.options.__file=\"packages/date-picker/src/panel/time-range.vue\";var _a=ya.exports,xa={mixins:[Wr],name:\"ElTimePicker\",props:{isRange:Boolean,arrowControl:Boolean},data:function(){return{type:\"\"}},watch:{isRange:function(e){this.picker?(this.unmountPicker(),this.type=e?\"timerange\":\"time\",this.panel=e?_a:so,this.mountPicker()):(this.type=e?\"timerange\":\"time\",this.panel=e?_a:so)}},created:function(){this.type=this.isRange?\"timerange\":\"time\",this.panel=this.isRange?_a:so},install:function(e){e.component(xa.name,xa)}},Ca=xa,wa=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"span\",[i(\"transition\",{attrs:{name:e.transition},on:{\"after-enter\":e.handleAfterEnter,\"after-leave\":e.handleAfterLeave}},[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:!e.disabled&&e.showPopper,expression:\"!disabled && showPopper\"}],ref:\"popper\",staticClass:\"el-popover el-popper\",class:[e.popperClass,e.content&&\"el-popover--plain\"],style:{width:e.width+\"px\"},attrs:{role:\"tooltip\",id:e.tooltipId,\"aria-hidden\":e.disabled||!e.showPopper?\"true\":\"false\"}},[e.title?i(\"div\",{staticClass:\"el-popover__title\",domProps:{textContent:e._s(e.title)}}):e._e(),e._t(\"default\",[e._v(e._s(e.content))])],2)]),e._t(\"reference\")],2)},ka=[];wa._withStripped=!0;var Sa={name:\"ElPopover\",mixins:[R.a],props:{trigger:{type:String,default:\"click\",validator:function(e){return[\"click\",\"focus\",\"hover\",\"manual\"].indexOf(e)>-1}},openDelay:{type:Number,default:0},title:String,disabled:Boolean,content:String,reference:{},popperClass:String,width:{},visibleArrow:{default:!0},arrowOffset:{type:Number,default:0},transition:{type:String,default:\"fade-in-linear\"}},computed:{tooltipId:function(){return\"el-popover-\"+Object(b[\"generateId\"])()}},watch:{showPopper:function(e){this.disabled||(e?this.$emit(\"show\"):this.$emit(\"hide\"))}},mounted:function(){var e=this,t=this.referenceElm=this.reference||this.$refs.reference,i=this.popper||this.$refs.popper;!t&&this.$slots.reference&&this.$slots.reference[0]&&(t=this.referenceElm=this.$slots.reference[0].elm),t&&(Object(Ve[\"addClass\"])(t,\"el-popover__reference\"),t.setAttribute(\"aria-describedby\",this.tooltipId),t.setAttribute(\"tabindex\",0),i.setAttribute(\"tabindex\",0),\"click\"!==this.trigger&&(Object(Ve[\"on\"])(t,\"focusin\",function(){e.handleFocus();var i=t.__vue__;i&&\"function\"===typeof i.focus&&i.focus()}),Object(Ve[\"on\"])(i,\"focusin\",this.handleFocus),Object(Ve[\"on\"])(t,\"focusout\",this.handleBlur),Object(Ve[\"on\"])(i,\"focusout\",this.handleBlur)),Object(Ve[\"on\"])(t,\"keydown\",this.handleKeydown),Object(Ve[\"on\"])(t,\"click\",this.handleClick)),\"click\"===this.trigger?(Object(Ve[\"on\"])(t,\"click\",this.doToggle),Object(Ve[\"on\"])(document,\"click\",this.handleDocumentClick)):\"hover\"===this.trigger?(Object(Ve[\"on\"])(t,\"mouseenter\",this.handleMouseEnter),Object(Ve[\"on\"])(i,\"mouseenter\",this.handleMouseEnter),Object(Ve[\"on\"])(t,\"mouseleave\",this.handleMouseLeave),Object(Ve[\"on\"])(i,\"mouseleave\",this.handleMouseLeave)):\"focus\"===this.trigger&&(t.querySelector(\"input, textarea\")?(Object(Ve[\"on\"])(t,\"focusin\",this.doShow),Object(Ve[\"on\"])(t,\"focusout\",this.doClose)):(Object(Ve[\"on\"])(t,\"mousedown\",this.doShow),Object(Ve[\"on\"])(t,\"mouseup\",this.doClose)))},beforeDestroy:function(){this.cleanup()},deactivated:function(){this.cleanup()},methods:{doToggle:function(){this.showPopper=!this.showPopper},doShow:function(){this.showPopper=!0},doClose:function(){this.showPopper=!1},handleFocus:function(){Object(Ve[\"addClass\"])(this.referenceElm,\"focusing\"),\"click\"!==this.trigger&&\"focus\"!==this.trigger||(this.showPopper=!0)},handleClick:function(){Object(Ve[\"removeClass\"])(this.referenceElm,\"focusing\")},handleBlur:function(){Object(Ve[\"removeClass\"])(this.referenceElm,\"focusing\"),\"click\"!==this.trigger&&\"focus\"!==this.trigger||(this.showPopper=!1)},handleMouseEnter:function(){var e=this;clearTimeout(this._timer),this.openDelay?this._timer=setTimeout(function(){e.showPopper=!0},this.openDelay):this.showPopper=!0},handleKeydown:function(e){27===e.keyCode&&\"manual\"!==this.trigger&&this.doClose()},handleMouseLeave:function(){var e=this;clearTimeout(this._timer),this._timer=setTimeout(function(){e.showPopper=!1},200)},handleDocumentClick:function(e){var t=this.reference||this.$refs.reference,i=this.popper||this.$refs.popper;!t&&this.$slots.reference&&this.$slots.reference[0]&&(t=this.referenceElm=this.$slots.reference[0].elm),this.$el&&t&&!this.$el.contains(e.target)&&!t.contains(e.target)&&i&&!i.contains(e.target)&&(this.showPopper=!1)},handleAfterEnter:function(){this.$emit(\"after-enter\")},handleAfterLeave:function(){this.$emit(\"after-leave\"),this.doDestroy()},cleanup:function(){this.openDelay&&clearTimeout(this._timer)}},destroyed:function(){var e=this.reference;Object(Ve[\"off\"])(e,\"click\",this.doToggle),Object(Ve[\"off\"])(e,\"mouseup\",this.doClose),Object(Ve[\"off\"])(e,\"mousedown\",this.doShow),Object(Ve[\"off\"])(e,\"focusin\",this.doShow),Object(Ve[\"off\"])(e,\"focusout\",this.doClose),Object(Ve[\"off\"])(e,\"mousedown\",this.doShow),Object(Ve[\"off\"])(e,\"mouseup\",this.doClose),Object(Ve[\"off\"])(e,\"mouseleave\",this.handleMouseLeave),Object(Ve[\"off\"])(e,\"mouseenter\",this.handleMouseEnter),Object(Ve[\"off\"])(document,\"click\",this.handleDocumentClick)}},$a=Sa,Da=a($a,wa,ka,!1,null,null,null);Da.options.__file=\"packages/popover/src/main.vue\";var Ea=Da.exports,Ta=function(e,t,i){var n=t.expression?t.value:t.arg,s=i.context.$refs[n];s&&(Array.isArray(s)?s[0].$refs.reference=e:s.$refs.reference=e)},Oa={bind:function(e,t,i){Ta(e,t,i)},inserted:function(e,t,i){Ta(e,t,i)}};Rn.a.directive(\"popover\",Oa),Ea.install=function(e){e.directive(\"popover\",Oa),e.component(Ea.name,Ea)},Ea.directive=Oa;var Ia=Ea,Pa={name:\"ElTooltip\",mixins:[R.a],props:{openDelay:{type:Number,default:0},disabled:Boolean,manual:Boolean,effect:{type:String,default:\"dark\"},arrowOffset:{type:Number,default:0},popperClass:String,content:String,visibleArrow:{default:!0},transition:{type:String,default:\"el-fade-in-linear\"},popperOptions:{default:function(){return{boundariesPadding:10,gpuAcceleration:!1}}},enterable:{type:Boolean,default:!0},hideAfter:{type:Number,default:0}},data:function(){return{tooltipId:\"el-tooltip-\"+Object(b[\"generateId\"])(),timeoutPending:null,focusing:!1}},beforeCreate:function(){var e=this;this.$isServer||(this.popperVM=new Rn.a({data:{node:\"\"},render:function(e){return this.node}}).$mount(),this.debounceClose=L()(200,function(){return e.handleClosePopper()}))},render:function(e){var t=this;this.popperVM&&(this.popperVM.node=e(\"transition\",{attrs:{name:this.transition},on:{afterLeave:this.doDestroy}},[e(\"div\",{on:{mouseleave:function(){t.setExpectedState(!1),t.debounceClose()},mouseenter:function(){t.setExpectedState(!0)}},ref:\"popper\",attrs:{role:\"tooltip\",id:this.tooltipId,\"aria-hidden\":this.disabled||!this.showPopper?\"true\":\"false\"},directives:[{name:\"show\",value:!this.disabled&&this.showPopper}],class:[\"el-tooltip__popper\",\"is-\"+this.effect,this.popperClass]},[this.$slots.content||this.content])]));var i=this.getFirstElement();if(!i)return null;var n=i.data=i.data||{};return n.staticClass=this.addTooltipClass(n.staticClass),i},mounted:function(){var e=this;this.referenceElm=this.$el,1===this.$el.nodeType&&(this.$el.setAttribute(\"aria-describedby\",this.tooltipId),this.$el.setAttribute(\"tabindex\",0),Object(Ve[\"on\"])(this.referenceElm,\"mouseenter\",this.show),Object(Ve[\"on\"])(this.referenceElm,\"mouseleave\",this.hide),Object(Ve[\"on\"])(this.referenceElm,\"focus\",function(){if(e.$slots.default&&e.$slots.default.length){var t=e.$slots.default[0].componentInstance;t&&t.focus?t.focus():e.handleFocus()}else e.handleFocus()}),Object(Ve[\"on\"])(this.referenceElm,\"blur\",this.handleBlur),Object(Ve[\"on\"])(this.referenceElm,\"click\",this.removeFocusing)),this.value&&this.popperVM&&this.popperVM.$nextTick(function(){e.value&&e.updatePopper()})},watch:{focusing:function(e){e?Object(Ve[\"addClass\"])(this.referenceElm,\"focusing\"):Object(Ve[\"removeClass\"])(this.referenceElm,\"focusing\")}},methods:{show:function(){this.setExpectedState(!0),this.handleShowPopper()},hide:function(){this.setExpectedState(!1),this.debounceClose()},handleFocus:function(){this.focusing=!0,this.show()},handleBlur:function(){this.focusing=!1,this.hide()},removeFocusing:function(){this.focusing=!1},addTooltipClass:function(e){return e?\"el-tooltip \"+e.replace(\"el-tooltip\",\"\"):\"el-tooltip\"},handleShowPopper:function(){var e=this;this.expectedState&&!this.manual&&(clearTimeout(this.timeout),this.timeout=setTimeout(function(){e.showPopper=!0},this.openDelay),this.hideAfter>0&&(this.timeoutPending=setTimeout(function(){e.showPopper=!1},this.hideAfter)))},handleClosePopper:function(){this.enterable&&this.expectedState||this.manual||(clearTimeout(this.timeout),this.timeoutPending&&clearTimeout(this.timeoutPending),this.showPopper=!1,this.disabled&&this.doDestroy())},setExpectedState:function(e){!1===e&&clearTimeout(this.timeoutPending),this.expectedState=e},getFirstElement:function(){var e=this.$slots.default;if(!Array.isArray(e))return null;for(var t=null,i=0;i<e.length;i++)e[i]&&e[i].tag&&(t=e[i]);return t}},beforeDestroy:function(){this.popperVM&&this.popperVM.$destroy()},destroyed:function(){var e=this.referenceElm;Object(Ve[\"off\"])(e,\"mouseenter\",this.show),Object(Ve[\"off\"])(e,\"mouseleave\",this.hide),Object(Ve[\"off\"])(e,\"focus\",this.handleFocus),Object(Ve[\"off\"])(e,\"blur\",this.handleBlur),Object(Ve[\"off\"])(e,\"click\",this.removeFocusing)},install:function(e){e.component(Pa.name,Pa)}},Ma=Pa,Na=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"msgbox-fade\"}},[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible,expression:\"visible\"}],staticClass:\"el-message-box__wrapper\",attrs:{tabindex:\"-1\",role:\"dialog\",\"aria-modal\":\"true\",\"aria-label\":e.title||\"dialog\"},on:{click:function(t){return t.target!==t.currentTarget?null:e.handleWrapperClick(t)}}},[i(\"div\",{staticClass:\"el-message-box\",class:[e.customClass,e.center&&\"el-message-box--center\"]},[null!==e.title?i(\"div\",{staticClass:\"el-message-box__header\"},[i(\"div\",{staticClass:\"el-message-box__title\"},[e.icon&&e.center?i(\"div\",{class:[\"el-message-box__status\",e.icon]}):e._e(),i(\"span\",[e._v(e._s(e.title))])]),e.showClose?i(\"button\",{staticClass:\"el-message-box__headerbtn\",attrs:{type:\"button\",\"aria-label\":\"Close\"},on:{click:function(t){e.handleAction(e.distinguishCancelAndClose?\"close\":\"cancel\")},keydown:function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"enter\",13,t.key,\"Enter\"))return null;e.handleAction(e.distinguishCancelAndClose?\"close\":\"cancel\")}}},[i(\"i\",{staticClass:\"el-message-box__close el-icon-close\"})]):e._e()]):e._e(),i(\"div\",{staticClass:\"el-message-box__content\"},[e.icon&&!e.center&&\"\"!==e.message?i(\"div\",{class:[\"el-message-box__status\",e.icon]}):e._e(),\"\"!==e.message?i(\"div\",{staticClass:\"el-message-box__message\"},[e._t(\"default\",[e.dangerouslyUseHTMLString?i(\"p\",{domProps:{innerHTML:e._s(e.message)}}):i(\"p\",[e._v(e._s(e.message))])])],2):e._e(),i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.showInput,expression:\"showInput\"}],staticClass:\"el-message-box__input\"},[i(\"el-input\",{ref:\"input\",attrs:{type:e.inputType,placeholder:e.inputPlaceholder},nativeOn:{keydown:function(t){return\"button\"in t||!e._k(t.keyCode,\"enter\",13,t.key,\"Enter\")?e.handleInputEnter(t):null}},model:{value:e.inputValue,callback:function(t){e.inputValue=t},expression:\"inputValue\"}}),i(\"div\",{staticClass:\"el-message-box__errormsg\",style:{visibility:e.editorErrorMessage?\"visible\":\"hidden\"}},[e._v(e._s(e.editorErrorMessage))])],1)]),i(\"div\",{staticClass:\"el-message-box__btns\"},[e.showCancelButton?i(\"el-button\",{class:[e.cancelButtonClasses],attrs:{loading:e.cancelButtonLoading,round:e.roundButton,size:\"small\"},on:{keydown:function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"enter\",13,t.key,\"Enter\"))return null;e.handleAction(\"cancel\")}},nativeOn:{click:function(t){e.handleAction(\"cancel\")}}},[e._v(\"\\n          \"+e._s(e.cancelButtonText||e.t(\"el.messagebox.cancel\"))+\"\\n        \")]):e._e(),i(\"el-button\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.showConfirmButton,expression:\"showConfirmButton\"}],ref:\"confirm\",class:[e.confirmButtonClasses],attrs:{loading:e.confirmButtonLoading,round:e.roundButton,size:\"small\"},on:{keydown:function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"enter\",13,t.key,\"Enter\"))return null;e.handleAction(\"confirm\")}},nativeOn:{click:function(t){e.handleAction(\"confirm\")}}},[e._v(\"\\n          \"+e._s(e.confirmButtonText||e.t(\"el.messagebox.confirm\"))+\"\\n        \")])],1)])])])},Fa=[];Na._withStripped=!0;var Aa=i(35),La=i.n(Aa),Va=void 0,Ba={success:\"success\",info:\"info\",warning:\"warning\",error:\"error\"},za={mixins:[k.a,g.a],props:{modal:{default:!0},lockScroll:{default:!0},showClose:{type:Boolean,default:!0},closeOnClickModal:{default:!0},closeOnPressEscape:{default:!0},closeOnHashChange:{default:!0},center:{default:!1,type:Boolean},roundButton:{default:!1,type:Boolean}},components:{ElInput:m.a,ElButton:oe.a},computed:{icon:function(){var e=this.type,t=this.iconClass;return t||(e&&Ba[e]?\"el-icon-\"+Ba[e]:\"\")},confirmButtonClasses:function(){return\"el-button--primary \"+this.confirmButtonClass},cancelButtonClasses:function(){return\"\"+this.cancelButtonClass}},methods:{getSafeClose:function(){var e=this,t=this.uid;return function(){e.$nextTick(function(){t===e.uid&&e.doClose()})}},doClose:function(){var e=this;this.visible&&(this.visible=!1,this._closing=!0,this.onClose&&this.onClose(),Va.closeDialog(),this.lockScroll&&setTimeout(this.restoreBodyStyle,200),this.opened=!1,this.doAfterClose(),setTimeout(function(){e.action&&e.callback(e.action,e)}))},handleWrapperClick:function(){this.closeOnClickModal&&this.handleAction(this.distinguishCancelAndClose?\"close\":\"cancel\")},handleInputEnter:function(){if(\"textarea\"!==this.inputType)return this.handleAction(\"confirm\")},handleAction:function(e){(\"prompt\"!==this.$type||\"confirm\"!==e||this.validate())&&(this.action=e,\"function\"===typeof this.beforeClose?(this.close=this.getSafeClose(),this.beforeClose(e,this,this.close)):this.doClose())},validate:function(){if(\"prompt\"===this.$type){var e=this.inputPattern;if(e&&!e.test(this.inputValue||\"\"))return this.editorErrorMessage=this.inputErrorMessage||Object(Zi[\"t\"])(\"el.messagebox.error\"),Object(Ve[\"addClass\"])(this.getInputElement(),\"invalid\"),!1;var t=this.inputValidator;if(\"function\"===typeof t){var i=t(this.inputValue);if(!1===i)return this.editorErrorMessage=this.inputErrorMessage||Object(Zi[\"t\"])(\"el.messagebox.error\"),Object(Ve[\"addClass\"])(this.getInputElement(),\"invalid\"),!1;if(\"string\"===typeof i)return this.editorErrorMessage=i,Object(Ve[\"addClass\"])(this.getInputElement(),\"invalid\"),!1}}return this.editorErrorMessage=\"\",Object(Ve[\"removeClass\"])(this.getInputElement(),\"invalid\"),!0},getFirstFocus:function(){var e=this.$el.querySelector(\".el-message-box__btns .el-button\"),t=this.$el.querySelector(\".el-message-box__btns .el-message-box__title\");return e||t},getInputElement:function(){var e=this.$refs.input.$refs;return e.input||e.textarea}},watch:{inputValue:{immediate:!0,handler:function(e){var t=this;this.$nextTick(function(i){\"prompt\"===t.$type&&null!==e&&t.validate()})}},visible:function(e){var t=this;e&&(this.uid++,\"alert\"!==this.$type&&\"confirm\"!==this.$type||this.$nextTick(function(){t.$refs.confirm.$el.focus()}),this.focusAfterClosed=document.activeElement,Va=new La.a(this.$el,this.focusAfterClosed,this.getFirstFocus())),\"prompt\"===this.$type&&(e?setTimeout(function(){t.$refs.input&&t.$refs.input.$el&&t.getInputElement().focus()},500):(this.editorErrorMessage=\"\",Object(Ve[\"removeClass\"])(this.getInputElement(),\"invalid\")))}},mounted:function(){var e=this;this.$nextTick(function(){e.closeOnHashChange&&window.addEventListener(\"hashchange\",e.close)})},beforeDestroy:function(){this.closeOnHashChange&&window.removeEventListener(\"hashchange\",this.close),setTimeout(function(){Va.closeDialog()})},data:function(){return{uid:1,title:void 0,message:\"\",type:\"\",iconClass:\"\",customClass:\"\",showInput:!1,inputValue:null,inputPlaceholder:\"\",inputType:\"text\",inputPattern:null,inputValidator:null,inputErrorMessage:\"\",showConfirmButton:!0,showCancelButton:!1,action:\"\",confirmButtonText:\"\",cancelButtonText:\"\",confirmButtonLoading:!1,cancelButtonLoading:!1,confirmButtonClass:\"\",confirmButtonDisabled:!1,cancelButtonClass:\"\",editorErrorMessage:null,callback:null,dangerouslyUseHTMLString:!1,focusAfterClosed:null,isOnComposition:!1,distinguishCancelAndClose:!1}}},ja=za,Ha=a(ja,Na,Fa,!1,null,null,null);Ha.options.__file=\"packages/message-box/src/main.vue\";var Ra=Ha.exports,Wa=i(19),qa=\"function\"===typeof Symbol&&\"symbol\"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},Ka={title:null,message:\"\",type:\"\",iconClass:\"\",showInput:!1,showClose:!0,modalFade:!0,lockScroll:!0,closeOnClickModal:!0,closeOnPressEscape:!0,closeOnHashChange:!0,inputValue:null,inputPlaceholder:\"\",inputType:\"text\",inputPattern:null,inputValidator:null,inputErrorMessage:\"\",showConfirmButton:!0,showCancelButton:!1,confirmButtonPosition:\"right\",confirmButtonHighlight:!1,cancelButtonHighlight:!1,confirmButtonText:\"\",cancelButtonText:\"\",confirmButtonClass:\"\",cancelButtonClass:\"\",customClass:\"\",beforeClose:null,dangerouslyUseHTMLString:!1,center:!1,roundButton:!1,distinguishCancelAndClose:!1},Ya=Rn.a.extend(Ra),Ua=void 0,Ga=void 0,Xa=[],Qa=function(e){if(Ua){var t=Ua.callback;\"function\"===typeof t&&(Ga.showInput?t(Ga.inputValue,e):t(e)),Ua.resolve&&(\"confirm\"===e?Ga.showInput?Ua.resolve({value:Ga.inputValue,action:e}):Ua.resolve(e):!Ua.reject||\"cancel\"!==e&&\"close\"!==e||Ua.reject(e))}},Ja=function(){Ga=new Ya({el:document.createElement(\"div\")}),Ga.callback=Qa},Za=function e(){if(Ga||Ja(),Ga.action=\"\",(!Ga.visible||Ga.closeTimer)&&Xa.length>0){Ua=Xa.shift();var t=Ua.options;for(var i in t)t.hasOwnProperty(i)&&(Ga[i]=t[i]);void 0===t.callback&&(Ga.callback=Qa);var n=Ga.callback;Ga.callback=function(t,i){n(t,i),e()},Object(Wa[\"isVNode\"])(Ga.message)?(Ga.$slots.default=[Ga.message],Ga.message=null):delete Ga.$slots.default,[\"modal\",\"showClose\",\"closeOnClickModal\",\"closeOnPressEscape\",\"closeOnHashChange\"].forEach(function(e){void 0===Ga[e]&&(Ga[e]=!0)}),document.body.appendChild(Ga.$el),Rn.a.nextTick(function(){Ga.visible=!0})}},el=function e(t,i){if(!Rn.a.prototype.$isServer){if(\"string\"===typeof t||Object(Wa[\"isVNode\"])(t)?(t={message:t},\"string\"===typeof arguments[1]&&(t.title=arguments[1])):t.callback&&!i&&(i=t.callback),\"undefined\"!==typeof Promise)return new Promise(function(n,s){Xa.push({options:St()({},Ka,e.defaults,t),callback:i,resolve:n,reject:s}),Za()});Xa.push({options:St()({},Ka,e.defaults,t),callback:i}),Za()}};el.setDefaults=function(e){el.defaults=e},el.alert=function(e,t,i){return\"object\"===(\"undefined\"===typeof t?\"undefined\":qa(t))?(i=t,t=\"\"):void 0===t&&(t=\"\"),el(St()({title:t,message:e,$type:\"alert\",closeOnPressEscape:!1,closeOnClickModal:!1},i))},el.confirm=function(e,t,i){return\"object\"===(\"undefined\"===typeof t?\"undefined\":qa(t))?(i=t,t=\"\"):void 0===t&&(t=\"\"),el(St()({title:t,message:e,$type:\"confirm\",showCancelButton:!0},i))},el.prompt=function(e,t,i){return\"object\"===(\"undefined\"===typeof t?\"undefined\":qa(t))?(i=t,t=\"\"):void 0===t&&(t=\"\"),el(St()({title:t,message:e,showCancelButton:!0,showInput:!0,$type:\"prompt\"},i))},el.close=function(){Ga.doClose(),Ga.visible=!1,Xa=[],Ua=null};var tl=el,il=tl,nl=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-breadcrumb\",attrs:{\"aria-label\":\"Breadcrumb\",role:\"navigation\"}},[e._t(\"default\")],2)},sl=[];nl._withStripped=!0;var rl={name:\"ElBreadcrumb\",props:{separator:{type:String,default:\"/\"},separatorClass:{type:String,default:\"\"}},provide:function(){return{elBreadcrumb:this}},mounted:function(){var e=this.$el.querySelectorAll(\".el-breadcrumb__item\");e.length&&e[e.length-1].setAttribute(\"aria-current\",\"page\")}},ol=rl,al=a(ol,nl,sl,!1,null,null,null);al.options.__file=\"packages/breadcrumb/src/breadcrumb.vue\";var ll=al.exports;ll.install=function(e){e.component(ll.name,ll)};var ul=ll,cl=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"span\",{staticClass:\"el-breadcrumb__item\"},[i(\"span\",{ref:\"link\",class:[\"el-breadcrumb__inner\",e.to?\"is-link\":\"\"],attrs:{role:\"link\"}},[e._t(\"default\")],2),e.separatorClass?i(\"i\",{staticClass:\"el-breadcrumb__separator\",class:e.separatorClass}):i(\"span\",{staticClass:\"el-breadcrumb__separator\",attrs:{role:\"presentation\"}},[e._v(e._s(e.separator))])])},hl=[];cl._withStripped=!0;var dl={name:\"ElBreadcrumbItem\",props:{to:{},replace:Boolean},data:function(){return{separator:\"\",separatorClass:\"\"}},inject:[\"elBreadcrumb\"],mounted:function(){var e=this;this.separator=this.elBreadcrumb.separator,this.separatorClass=this.elBreadcrumb.separatorClass;var t=this.$refs.link;t.setAttribute(\"role\",\"link\"),t.addEventListener(\"click\",function(t){var i=e.to,n=e.$router;i&&n&&(e.replace?n.replace(i):n.push(i))})}},pl=dl,fl=a(pl,cl,hl,!1,null,null,null);fl.options.__file=\"packages/breadcrumb/src/breadcrumb-item.vue\";var ml=fl.exports;ml.install=function(e){e.component(ml.name,ml)};var vl=ml,gl=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"form\",{staticClass:\"el-form\",class:[e.labelPosition?\"el-form--label-\"+e.labelPosition:\"\",{\"el-form--inline\":e.inline}]},[e._t(\"default\")],2)},bl=[];gl._withStripped=!0;var yl={name:\"ElForm\",componentName:\"ElForm\",provide:function(){return{elForm:this}},props:{model:Object,rules:Object,labelPosition:String,labelWidth:String,labelSuffix:{type:String,default:\"\"},inline:Boolean,inlineMessage:Boolean,statusIcon:Boolean,showMessage:{type:Boolean,default:!0},size:String,disabled:Boolean,validateOnRuleChange:{type:Boolean,default:!0},hideRequiredAsterisk:{type:Boolean,default:!1}},watch:{rules:function(){this.validateOnRuleChange&&this.validate(function(){})}},computed:{autoLabelWidth:function(){var e=Math.max.apply(Math,this.potentialLabelWidthArr);return e?e+\"px\":\"\"}},data:function(){return{fields:[],potentialLabelWidthArr:[]}},created:function(){var e=this;this.$on(\"el.form.addField\",function(t){t&&e.fields.push(t)}),this.$on(\"el.form.removeField\",function(t){t.prop&&e.fields.splice(e.fields.indexOf(t),1)})},methods:{resetFields:function(){this.model?this.fields.forEach(function(e){e.resetField()}):console.warn(\"[Element Warn][Form]model is required for resetFields to work.\")},clearValidate:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=e.length?\"string\"===typeof e?this.fields.filter(function(t){return e===t.prop}):this.fields.filter(function(t){return e.indexOf(t.prop)>-1}):this.fields;t.forEach(function(e){e.clearValidate()})},validate:function(e){var t=this;if(this.model){var i=void 0;\"function\"!==typeof e&&window.Promise&&(i=new window.Promise(function(t,i){e=function(e){e?t(e):i(e)}}));var n=!0,s=0;0===this.fields.length&&e&&e(!0);var r={};return this.fields.forEach(function(i){i.validate(\"\",function(i,o){i&&(n=!1),r=St()({},r,o),\"function\"===typeof e&&++s===t.fields.length&&e(n,r)})}),i||void 0}console.warn(\"[Element Warn][Form]model is required for validate to work!\")},validateField:function(e,t){e=[].concat(e);var i=this.fields.filter(function(t){return-1!==e.indexOf(t.prop)});i.length?i.forEach(function(e){e.validate(\"\",t)}):console.warn(\"[Element Warn]please pass correct props!\")},getLabelWidthIndex:function(e){var t=this.potentialLabelWidthArr.indexOf(e);if(-1===t)throw new Error(\"[ElementForm]unpected width \",e);return t},registerLabelWidth:function(e,t){if(e&&t){var i=this.getLabelWidthIndex(t);this.potentialLabelWidthArr.splice(i,1,e)}else e&&this.potentialLabelWidthArr.push(e)},deregisterLabelWidth:function(e){var t=this.getLabelWidthIndex(e);this.potentialLabelWidthArr.splice(t,1)}}},_l=yl,xl=a(_l,gl,bl,!1,null,null,null);xl.options.__file=\"packages/form/src/form.vue\";var Cl=xl.exports;Cl.install=function(e){e.component(Cl.name,Cl)};var wl=Cl,kl=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-form-item\",class:[{\"el-form-item--feedback\":e.elForm&&e.elForm.statusIcon,\"is-error\":\"error\"===e.validateState,\"is-validating\":\"validating\"===e.validateState,\"is-success\":\"success\"===e.validateState,\"is-required\":e.isRequired||e.required,\"is-no-asterisk\":e.elForm&&e.elForm.hideRequiredAsterisk},e.sizeClass?\"el-form-item--\"+e.sizeClass:\"\"]},[i(\"label-wrap\",{attrs:{\"is-auto-width\":e.labelStyle&&\"auto\"===e.labelStyle.width,\"update-all\":\"auto\"===e.form.labelWidth}},[e.label||e.$slots.label?i(\"label\",{staticClass:\"el-form-item__label\",style:e.labelStyle,attrs:{for:e.labelFor}},[e._t(\"label\",[e._v(e._s(e.label+e.form.labelSuffix))])],2):e._e()]),i(\"div\",{staticClass:\"el-form-item__content\",style:e.contentStyle},[e._t(\"default\"),i(\"transition\",{attrs:{name:\"el-zoom-in-top\"}},[\"error\"===e.validateState&&e.showMessage&&e.form.showMessage?e._t(\"error\",[i(\"div\",{staticClass:\"el-form-item__error\",class:{\"el-form-item__error--inline\":\"boolean\"===typeof e.inlineMessage?e.inlineMessage:e.elForm&&e.elForm.inlineMessage||!1}},[e._v(\"\\n          \"+e._s(e.validateMessage)+\"\\n        \")])],{error:e.validateMessage}):e._e()],2)],2)],1)},Sl=[];kl._withStripped=!0;var $l,Dl,El=i(36),Tl=i.n(El),Ol={props:{isAutoWidth:Boolean,updateAll:Boolean},inject:[\"elForm\",\"elFormItem\"],render:function(){var e=arguments[0],t=this.$slots.default;if(!t)return null;if(this.isAutoWidth){var i=this.elForm.autoLabelWidth,n={};return i&&\"auto\"!==i&&(n.width=i),e(\"div\",{class:\"el-form-item__label-wrap\",style:n},[t])}return t[0]},methods:{getLabelWidth:function(){if(this.$el&&this.$el.firstElementChild){var e=window.getComputedStyle(this.$el.firstElementChild).width;return Math.ceil(parseFloat(e))}return 0},updateLabelWidth:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:\"update\";this.$slots.default&&this.isAutoWidth&&this.$el.firstElementChild&&(\"update\"===e?this.computedWidth=this.getLabelWidth():\"remove\"===e&&this.elForm.deregisterLabelWidth(this.computedWidth))}},watch:{computedWidth:function(e,t){this.updateAll&&(this.elForm.registerLabelWidth(e,t),this.elFormItem.updateComputedLabelWidth(e))}},data:function(){return{computedWidth:0}},mounted:function(){this.updateLabelWidth(\"update\")},beforeDestroy:function(){this.updateLabelWidth(\"remove\")}},Il=Ol,Pl=a(Il,$l,Dl,!1,null,null,null);Pl.options.__file=\"packages/form/src/label-wrap.vue\";var Ml=Pl.exports,Nl={name:\"ElFormItem\",componentName:\"ElFormItem\",mixins:[E.a],provide:function(){return{elFormItem:this}},inject:[\"elForm\"],props:{label:String,labelWidth:String,prop:String,required:{type:Boolean,default:void 0},rules:[Object,Array],error:String,validateStatus:String,for:String,inlineMessage:{type:[String,Boolean],default:\"\"},showMessage:{type:Boolean,default:!0},size:String},components:{LabelWrap:Ml},watch:{error:{immediate:!0,handler:function(e){this.validateMessage=e,this.validateState=e?\"error\":\"\"}},validateStatus:function(e){this.validateState=e}},computed:{labelFor:function(){return this.for||this.prop},labelStyle:function(){var e={};if(\"top\"===this.form.labelPosition)return e;var t=this.labelWidth||this.form.labelWidth;return t&&(e.width=t),e},contentStyle:function(){var e={},t=this.label;if(\"top\"===this.form.labelPosition||this.form.inline)return e;if(!t&&!this.labelWidth&&this.isNested)return e;var i=this.labelWidth||this.form.labelWidth;return\"auto\"===i?\"auto\"===this.labelWidth?e.marginLeft=this.computedLabelWidth:\"auto\"===this.form.labelWidth&&(e.marginLeft=this.elForm.autoLabelWidth):e.marginLeft=i,e},form:function(){var e=this.$parent,t=e.$options.componentName;while(\"ElForm\"!==t)\"ElFormItem\"===t&&(this.isNested=!0),e=e.$parent,t=e.$options.componentName;return e},fieldValue:function(){var e=this.form.model;if(e&&this.prop){var t=this.prop;return-1!==t.indexOf(\":\")&&(t=t.replace(/:/,\".\")),Object(b[\"getPropByPath\"])(e,t,!0).v}},isRequired:function(){var e=this.getRules(),t=!1;return e&&e.length&&e.every(function(e){return!e.required||(t=!0,!1)}),t},_formSize:function(){return this.elForm.size},elFormItemSize:function(){return this.size||this._formSize},sizeClass:function(){return this.elFormItemSize||(this.$ELEMENT||{}).size}},data:function(){return{validateState:\"\",validateMessage:\"\",validateDisabled:!1,validator:{},isNested:!1,computedLabelWidth:\"\"}},methods:{validate:function(e){var t=this,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:b[\"noop\"];this.validateDisabled=!1;var n=this.getFilteredRule(e);if((!n||0===n.length)&&void 0===this.required)return i(),!0;this.validateState=\"validating\";var s={};n&&n.length>0&&n.forEach(function(e){delete e.trigger}),s[this.prop]=n;var r=new Tl.a(s),o={};o[this.prop]=this.fieldValue,r.validate(o,{firstFields:!0},function(e,n){t.validateState=e?\"error\":\"success\",t.validateMessage=e?e[0].message:\"\",i(t.validateMessage,n),t.elForm&&t.elForm.$emit(\"validate\",t.prop,!e,t.validateMessage||null)})},clearValidate:function(){this.validateState=\"\",this.validateMessage=\"\",this.validateDisabled=!1},resetField:function(){this.validateState=\"\",this.validateMessage=\"\";var e=this.form.model,t=this.fieldValue,i=this.prop;-1!==i.indexOf(\":\")&&(i=i.replace(/:/,\".\"));var n=Object(b[\"getPropByPath\"])(e,i,!0);this.validateDisabled=!0,Array.isArray(t)?n.o[n.k]=[].concat(this.initialValue):n.o[n.k]=this.initialValue,this.broadcast(\"ElTimeSelect\",\"fieldReset\",this.initialValue)},getRules:function(){var e=this.form.rules,t=this.rules,i=void 0!==this.required?{required:!!this.required}:[],n=Object(b[\"getPropByPath\"])(e,this.prop||\"\");return e=e?n.o[this.prop||\"\"]||n.v:[],[].concat(t||e||[]).concat(i)},getFilteredRule:function(e){var t=this.getRules();return t.filter(function(t){return!t.trigger||\"\"===e||(Array.isArray(t.trigger)?t.trigger.indexOf(e)>-1:t.trigger===e)}).map(function(e){return St()({},e)})},onFieldBlur:function(){this.validate(\"blur\")},onFieldChange:function(){this.validateDisabled?this.validateDisabled=!1:this.validate(\"change\")},updateComputedLabelWidth:function(e){this.computedLabelWidth=e?e+\"px\":\"\"}},mounted:function(){if(this.prop){this.dispatch(\"ElForm\",\"el.form.addField\",[this]);var e=this.fieldValue;Array.isArray(e)&&(e=[].concat(e)),Object.defineProperty(this,\"initialValue\",{value:e});var t=this.getRules();(t.length||void 0!==this.required)&&(this.$on(\"el.form.blur\",this.onFieldBlur),this.$on(\"el.form.change\",this.onFieldChange))}},beforeDestroy:function(){this.dispatch(\"ElForm\",\"el.form.removeField\",[this])}},Fl=Nl,Al=a(Fl,kl,Sl,!1,null,null,null);Al.options.__file=\"packages/form/src/form-item.vue\";var Ll=Al.exports;Ll.install=function(e){e.component(Ll.name,Ll)};var Vl=Ll,Bl=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-tabs__active-bar\",class:\"is-\"+e.rootTabs.tabPosition,style:e.barStyle})},zl=[];Bl._withStripped=!0;var jl={name:\"TabBar\",props:{tabs:Array},inject:[\"rootTabs\"],computed:{barStyle:{get:function(){var e=this,t={},i=0,n=0,s=-1!==[\"top\",\"bottom\"].indexOf(this.rootTabs.tabPosition)?\"width\":\"height\",r=\"width\"===s?\"x\":\"y\",o=function(e){return e.toLowerCase().replace(/( |^)[a-z]/g,function(e){return e.toUpperCase()})};this.tabs.every(function(t,r){var a=Object(b[\"arrayFind\"])(e.$parent.$refs.tabs||[],function(e){return e.id.replace(\"tab-\",\"\")===t.paneName});return!!a&&(t.active?(n=a[\"client\"+o(s)],\"width\"===s&&e.tabs.length>1&&(n-=0===r||r===e.tabs.length-1?20:40),!1):(i+=a[\"client\"+o(s)],!0))}),\"width\"===s&&0!==i&&(i+=20);var a=\"translate\"+o(r)+\"(\"+i+\"px)\";return t[s]=n+\"px\",t.transform=a,t.msTransform=a,t.webkitTransform=a,t}}}},Hl=jl,Rl=a(Hl,Bl,zl,!1,null,null,null);Rl.options.__file=\"packages/tabs/src/tab-bar.vue\";var Wl=Rl.exports;function ql(){}var Kl,Yl,Ul=function(e){return e.toLowerCase().replace(/( |^)[a-z]/g,function(e){return e.toUpperCase()})},Gl={name:\"TabNav\",components:{TabBar:Wl},inject:[\"rootTabs\"],props:{panes:Array,currentName:String,editable:Boolean,onTabClick:{type:Function,default:ql},onTabRemove:{type:Function,default:ql},type:String,stretch:Boolean},data:function(){return{scrollable:!1,navOffset:0,isFocus:!1,focusable:!0}},computed:{navStyle:function(){var e=-1!==[\"top\",\"bottom\"].indexOf(this.rootTabs.tabPosition)?\"X\":\"Y\";return{transform:\"translate\"+e+\"(-\"+this.navOffset+\"px)\"}},sizeName:function(){return-1!==[\"top\",\"bottom\"].indexOf(this.rootTabs.tabPosition)?\"width\":\"height\"}},methods:{scrollPrev:function(){var e=this.$refs.navScroll[\"offset\"+Ul(this.sizeName)],t=this.navOffset;if(t){var i=t>e?t-e:0;this.navOffset=i}},scrollNext:function(){var e=this.$refs.nav[\"offset\"+Ul(this.sizeName)],t=this.$refs.navScroll[\"offset\"+Ul(this.sizeName)],i=this.navOffset;if(!(e-i<=t)){var n=e-i>2*t?i+t:e-t;this.navOffset=n}},scrollToActiveTab:function(){if(this.scrollable){var e=this.$refs.nav,t=this.$el.querySelector(\".is-active\");if(t){var i=this.$refs.navScroll,n=t.getBoundingClientRect(),s=i.getBoundingClientRect(),r=e.offsetWidth-s.width,o=this.navOffset,a=o;n.left<s.left&&(a=o-(s.left-n.left)),n.right>s.right&&(a=o+n.right-s.right),a=Math.max(a,0),this.navOffset=Math.min(a,r)}}},update:function(){if(this.$refs.nav){var e=this.sizeName,t=this.$refs.nav[\"offset\"+Ul(e)],i=this.$refs.navScroll[\"offset\"+Ul(e)],n=this.navOffset;if(i<t){var s=this.navOffset;this.scrollable=this.scrollable||{},this.scrollable.prev=s,this.scrollable.next=s+i<t,t-s<i&&(this.navOffset=t-i)}else this.scrollable=!1,n>0&&(this.navOffset=0)}},changeTab:function(e){var t=e.keyCode,i=void 0,n=void 0,s=void 0;-1!==[37,38,39,40].indexOf(t)&&(s=e.currentTarget.querySelectorAll(\"[role=tab]\"),n=Array.prototype.indexOf.call(s,e.target),i=37===t||38===t?0===n?s.length-1:n-1:n<s.length-1?n+1:0,s[i].focus(),s[i].click(),this.setFocus())},setFocus:function(){this.focusable&&(this.isFocus=!0)},removeFocus:function(){this.isFocus=!1},visibilityChangeHandler:function(){var e=this,t=document.visibilityState;\"hidden\"===t?this.focusable=!1:\"visible\"===t&&setTimeout(function(){e.focusable=!0},50)},windowBlurHandler:function(){this.focusable=!1},windowFocusHandler:function(){var e=this;setTimeout(function(){e.focusable=!0},50)}},updated:function(){this.update()},render:function(e){var t=this,i=this.type,n=this.panes,s=this.editable,r=this.stretch,o=this.onTabClick,a=this.onTabRemove,l=this.navStyle,u=this.scrollable,c=this.scrollNext,h=this.scrollPrev,d=this.changeTab,p=this.setFocus,f=this.removeFocus,m=u?[e(\"span\",{class:[\"el-tabs__nav-prev\",u.prev?\"\":\"is-disabled\"],on:{click:h}},[e(\"i\",{class:\"el-icon-arrow-left\"})]),e(\"span\",{class:[\"el-tabs__nav-next\",u.next?\"\":\"is-disabled\"],on:{click:c}},[e(\"i\",{class:\"el-icon-arrow-right\"})])]:null,v=this._l(n,function(i,n){var r,l=i.name||i.index||n,u=i.isClosable||s;i.index=\"\"+n;var c=u?e(\"span\",{class:\"el-icon-close\",on:{click:function(e){a(i,e)}}}):null,h=i.$slots.label||i.label,d=i.active?0:-1;return e(\"div\",{class:(r={\"el-tabs__item\":!0},r[\"is-\"+t.rootTabs.tabPosition]=!0,r[\"is-active\"]=i.active,r[\"is-disabled\"]=i.disabled,r[\"is-closable\"]=u,r[\"is-focus\"]=t.isFocus,r),attrs:{id:\"tab-\"+l,\"aria-controls\":\"pane-\"+l,role:\"tab\",\"aria-selected\":i.active,tabindex:d},key:\"tab-\"+l,ref:\"tabs\",refInFor:!0,on:{focus:function(){p()},blur:function(){f()},click:function(e){f(),o(i,l,e)},keydown:function(e){!u||46!==e.keyCode&&8!==e.keyCode||a(i,e)}}},[h,c])});return e(\"div\",{class:[\"el-tabs__nav-wrap\",u?\"is-scrollable\":\"\",\"is-\"+this.rootTabs.tabPosition]},[m,e(\"div\",{class:[\"el-tabs__nav-scroll\"],ref:\"navScroll\"},[e(\"div\",{class:[\"el-tabs__nav\",\"is-\"+this.rootTabs.tabPosition,r&&-1!==[\"top\",\"bottom\"].indexOf(this.rootTabs.tabPosition)?\"is-stretch\":\"\"],ref:\"nav\",style:l,attrs:{role:\"tablist\"},on:{keydown:d}},[i?null:e(\"tab-bar\",{attrs:{tabs:n}}),v])])])},mounted:function(){var e=this;Object(Ji[\"addResizeListener\"])(this.$el,this.update),document.addEventListener(\"visibilitychange\",this.visibilityChangeHandler),window.addEventListener(\"blur\",this.windowBlurHandler),window.addEventListener(\"focus\",this.windowFocusHandler),setTimeout(function(){e.scrollToActiveTab()},0)},beforeDestroy:function(){this.$el&&this.update&&Object(Ji[\"removeResizeListener\"])(this.$el,this.update),document.removeEventListener(\"visibilitychange\",this.visibilityChangeHandler),window.removeEventListener(\"blur\",this.windowBlurHandler),window.removeEventListener(\"focus\",this.windowFocusHandler)}},Xl=Gl,Ql=a(Xl,Kl,Yl,!1,null,null,null);Ql.options.__file=\"packages/tabs/src/tab-nav.vue\";var Jl,Zl,eu=Ql.exports,tu={name:\"ElTabs\",components:{TabNav:eu},props:{type:String,activeName:String,closable:Boolean,addable:Boolean,value:{},editable:Boolean,tabPosition:{type:String,default:\"top\"},beforeLeave:Function,stretch:Boolean},provide:function(){return{rootTabs:this}},data:function(){return{currentName:this.value||this.activeName,panes:[]}},watch:{activeName:function(e){this.setCurrentName(e)},value:function(e){this.setCurrentName(e)},currentName:function(e){var t=this;this.$refs.nav&&this.$nextTick(function(){t.$refs.nav.$nextTick(function(e){t.$refs.nav.scrollToActiveTab()})})}},methods:{calcPaneInstances:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]&&arguments[0];if(this.$slots.default){var i=this.$slots.default.filter(function(e){return e.tag&&e.componentOptions&&\"ElTabPane\"===e.componentOptions.Ctor.options.name}),n=i.map(function(e){var t=e.componentInstance;return t}),s=!(n.length===this.panes.length&&n.every(function(t,i){return t===e.panes[i]}));(t||s)&&(this.panes=n)}else 0!==this.panes.length&&(this.panes=[])},handleTabClick:function(e,t,i){e.disabled||(this.setCurrentName(t),this.$emit(\"tab-click\",e,i))},handleTabRemove:function(e,t){e.disabled||(t.stopPropagation(),this.$emit(\"edit\",e.name,\"remove\"),this.$emit(\"tab-remove\",e.name))},handleTabAdd:function(){this.$emit(\"edit\",null,\"add\"),this.$emit(\"tab-add\")},setCurrentName:function(e){var t=this,i=function(){t.currentName=e,t.$emit(\"input\",e)};if(this.currentName!==e&&this.beforeLeave){var n=this.beforeLeave(e,this.currentName);n&&n.then?n.then(function(){i(),t.$refs.nav&&t.$refs.nav.removeFocus()}):!1!==n&&i()}else i()}},render:function(e){var t,i=this.type,n=this.handleTabClick,s=this.handleTabRemove,r=this.handleTabAdd,o=this.currentName,a=this.panes,l=this.editable,u=this.addable,c=this.tabPosition,h=this.stretch,d=l||u?e(\"span\",{class:\"el-tabs__new-tab\",on:{click:r,keydown:function(e){13===e.keyCode&&r()}},attrs:{tabindex:\"0\"}},[e(\"i\",{class:\"el-icon-plus\"})]):null,p={props:{currentName:o,onTabClick:n,onTabRemove:s,editable:l,type:i,panes:a,stretch:h},ref:\"nav\"},f=e(\"div\",{class:[\"el-tabs__header\",\"is-\"+c]},[d,e(\"tab-nav\",p)]),m=e(\"div\",{class:\"el-tabs__content\"},[this.$slots.default]);return e(\"div\",{class:(t={\"el-tabs\":!0,\"el-tabs--card\":\"card\"===i},t[\"el-tabs--\"+c]=!0,t[\"el-tabs--border-card\"]=\"border-card\"===i,t)},[\"bottom\"!==c?[f,m]:[m,f]])},created:function(){this.currentName||this.setCurrentName(\"0\"),this.$on(\"tabLabelChanged\",this.calcPaneInstances.bind(null,!0))},mounted:function(){this.calcPaneInstances()},updated:function(){this.calcPaneInstances()}},iu=tu,nu=a(iu,Jl,Zl,!1,null,null,null);nu.options.__file=\"packages/tabs/src/tabs.vue\";var su=nu.exports;su.install=function(e){e.component(su.name,su)};var ru=su,ou=function(){var e=this,t=e.$createElement,i=e._self._c||t;return!e.lazy||e.loaded||e.active?i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.active,expression:\"active\"}],staticClass:\"el-tab-pane\",attrs:{role:\"tabpanel\",\"aria-hidden\":!e.active,id:\"pane-\"+e.paneName,\"aria-labelledby\":\"tab-\"+e.paneName}},[e._t(\"default\")],2):e._e()},au=[];ou._withStripped=!0;var lu={name:\"ElTabPane\",componentName:\"ElTabPane\",props:{label:String,labelContent:Function,name:String,closable:Boolean,disabled:Boolean,lazy:Boolean},data:function(){return{index:null,loaded:!1}},computed:{isClosable:function(){return this.closable||this.$parent.closable},active:function(){var e=this.$parent.currentName===(this.name||this.index);return e&&(this.loaded=!0),e},paneName:function(){return this.name||this.index}},watch:{label:function(){this.$parent.$emit(\"tabLabelChanged\")}}},uu=lu,cu=a(uu,ou,au,!1,null,null,null);cu.options.__file=\"packages/tabs/src/tab-pane.vue\";var hu=cu.exports;hu.install=function(e){e.component(hu.name,hu)};var du,pu,fu=hu,mu={name:\"ElTag\",props:{text:String,closable:Boolean,type:String,hit:Boolean,disableTransitions:Boolean,color:String,size:String},methods:{handleClose:function(e){e.stopPropagation(),this.$emit(\"close\",e)},handleClick:function(e){e.stopPropagation(),this.$emit(\"click\",e)}},computed:{tagSize:function(){return this.size||(this.$ELEMENT||{}).size}},render:function(e){var t=[\"el-tag\",this.type?\"el-tag--\"+this.type:\"\",this.tagSize?\"el-tag--\"+this.tagSize:\"\",{\"is-hit\":this.hit}],i=e(\"span\",{class:t,style:{backgroundColor:this.color},on:{click:this.handleClick}},[this.$slots.default,this.closable&&e(\"i\",{class:\"el-tag__close el-icon-close\",on:{click:this.handleClose}})]);return this.disableTransitions?i:e(\"transition\",{attrs:{name:\"el-zoom-in-center\"}},[i])}},vu=mu,gu=a(vu,du,pu,!1,null,null,null);gu.options.__file=\"packages/tag/src/tag.vue\";var bu=gu.exports;bu.install=function(e){e.component(bu.name,bu)};var yu=bu,_u=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-tree\",class:{\"el-tree--highlight-current\":e.highlightCurrent,\"is-dragging\":!!e.dragState.draggingNode,\"is-drop-not-allow\":!e.dragState.allowDrop,\"is-drop-inner\":\"inner\"===e.dragState.dropType},attrs:{role:\"tree\"}},[e._l(e.root.childNodes,function(t){return i(\"el-tree-node\",{key:e.getNodeKey(t),attrs:{node:t,props:e.props,\"render-after-expand\":e.renderAfterExpand,\"show-checkbox\":e.showCheckbox,\"render-content\":e.renderContent},on:{\"node-expand\":e.handleNodeExpand}})}),e.isEmpty?i(\"div\",{staticClass:\"el-tree__empty-block\"},[i(\"span\",{staticClass:\"el-tree__empty-text\"},[e._v(e._s(e.emptyText))])]):e._e(),i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.dragState.showDropIndicator,expression:\"dragState.showDropIndicator\"}],ref:\"dropIndicator\",staticClass:\"el-tree__drop-indicator\"})],2)},xu=[];_u._withStripped=!0;var Cu=\"$treeNodeId\",wu=function(e,t){t&&!t[Cu]&&Object.defineProperty(t,Cu,{value:e.id,enumerable:!1,configurable:!1,writable:!1})},ku=function(e,t){return e?t[e]:t[Cu]},Su=function(e,t){var i=e;while(i&&\"BODY\"!==i.tagName){if(i.__vue__&&i.__vue__.$options.name===t)return i.__vue__;i=i.parentNode}return null},$u=function(){function e(e,t){for(var i=0;i<t.length;i++){var n=t[i];n.enumerable=n.enumerable||!1,n.configurable=!0,\"value\"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}return function(t,i,n){return i&&e(t.prototype,i),n&&e(t,n),t}}();function Du(e,t){if(!(e instanceof t))throw new TypeError(\"Cannot call a class as a function\")}var Eu=function(e){for(var t=!0,i=!0,n=!0,s=0,r=e.length;s<r;s++){var o=e[s];(!0!==o.checked||o.indeterminate)&&(t=!1,o.disabled||(n=!1)),(!1!==o.checked||o.indeterminate)&&(i=!1)}return{all:t,none:i,allWithoutDisable:n,half:!t&&!i}},Tu=function e(t){if(0!==t.childNodes.length){var i=Eu(t.childNodes),n=i.all,s=i.none,r=i.half;n?(t.checked=!0,t.indeterminate=!1):r?(t.checked=!1,t.indeterminate=!0):s&&(t.checked=!1,t.indeterminate=!1);var o=t.parent;o&&0!==o.level&&(t.store.checkStrictly||e(o))}},Ou=function(e,t){var i=e.store.props,n=e.data||{},s=i[t];if(\"function\"===typeof s)return s(n,e);if(\"string\"===typeof s)return n[s];if(\"undefined\"===typeof s){var r=n[t];return void 0===r?\"\":r}},Iu=0,Pu=function(){function e(t){for(var i in Du(this,e),this.id=Iu++,this.text=null,this.checked=!1,this.indeterminate=!1,this.data=null,this.expanded=!1,this.parent=null,this.visible=!0,t)t.hasOwnProperty(i)&&(this[i]=t[i]);this.level=0,this.loaded=!1,this.childNodes=[],this.loading=!1,this.parent&&(this.level=this.parent.level+1);var n=this.store;if(!n)throw new Error(\"[Node]store is required!\");n.registerNode(this);var s=n.props;if(s&&\"undefined\"!==typeof s.isLeaf){var r=Ou(this,\"isLeaf\");\"boolean\"===typeof r&&(this.isLeafByUser=r)}if(!0!==n.lazy&&this.data?(this.setData(this.data),n.defaultExpandAll&&(this.expanded=!0)):this.level>0&&n.lazy&&n.defaultExpandAll&&this.expand(),Array.isArray(this.data)||wu(this,this.data),this.data){var o=n.defaultExpandedKeys,a=n.key;a&&o&&-1!==o.indexOf(this.key)&&this.expand(null,n.autoExpandParent),a&&void 0!==n.currentNodeKey&&this.key===n.currentNodeKey&&(n.currentNode=this),n.lazy&&n._initDefaultCheckedNode(this),this.updateLeafState()}}return e.prototype.setData=function(e){Array.isArray(e)||wu(this,e),this.data=e,this.childNodes=[];var t=void 0;t=0===this.level&&this.data instanceof Array?this.data:Ou(this,\"children\")||[];for(var i=0,n=t.length;i<n;i++)this.insertChild({data:t[i]})},e.prototype.contains=function(e){var t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],i=function i(n){for(var s=n.childNodes||[],r=!1,o=0,a=s.length;o<a;o++){var l=s[o];if(l===e||t&&i(l)){r=!0;break}}return r};return i(this)},e.prototype.remove=function(){var e=this.parent;e&&e.removeChild(this)},e.prototype.insertChild=function(t,i,n){if(!t)throw new Error(\"insertChild error: child is required.\");if(!(t instanceof e)){if(!n){var s=this.getChildren(!0);-1===s.indexOf(t.data)&&(\"undefined\"===typeof i||i<0?s.push(t.data):s.splice(i,0,t.data))}St()(t,{parent:this,store:this.store}),t=new e(t)}t.level=this.level+1,\"undefined\"===typeof i||i<0?this.childNodes.push(t):this.childNodes.splice(i,0,t),this.updateLeafState()},e.prototype.insertBefore=function(e,t){var i=void 0;t&&(i=this.childNodes.indexOf(t)),this.insertChild(e,i)},e.prototype.insertAfter=function(e,t){var i=void 0;t&&(i=this.childNodes.indexOf(t),-1!==i&&(i+=1)),this.insertChild(e,i)},e.prototype.removeChild=function(e){var t=this.getChildren()||[],i=t.indexOf(e.data);i>-1&&t.splice(i,1);var n=this.childNodes.indexOf(e);n>-1&&(this.store&&this.store.deregisterNode(e),e.parent=null,this.childNodes.splice(n,1)),this.updateLeafState()},e.prototype.removeChildByData=function(e){for(var t=null,i=0;i<this.childNodes.length;i++)if(this.childNodes[i].data===e){t=this.childNodes[i];break}t&&this.removeChild(t)},e.prototype.expand=function(e,t){var i=this,n=function(){if(t){var n=i.parent;while(n.level>0)n.expanded=!0,n=n.parent}i.expanded=!0,e&&e()};this.shouldLoadData()?this.loadData(function(e){e instanceof Array&&(i.checked?i.setChecked(!0,!0):i.store.checkStrictly||Tu(i),n())}):n()},e.prototype.doCreateChildren=function(e){var t=this,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};e.forEach(function(e){t.insertChild(St()({data:e},i),void 0,!0)})},e.prototype.collapse=function(){this.expanded=!1},e.prototype.shouldLoadData=function(){return!0===this.store.lazy&&this.store.load&&!this.loaded},e.prototype.updateLeafState=function(){if(!0!==this.store.lazy||!0===this.loaded||\"undefined\"===typeof this.isLeafByUser){var e=this.childNodes;!this.store.lazy||!0===this.store.lazy&&!0===this.loaded?this.isLeaf=!e||0===e.length:this.isLeaf=!1}else this.isLeaf=this.isLeafByUser},e.prototype.setChecked=function(e,t,i,n){var s=this;if(this.indeterminate=\"half\"===e,this.checked=!0===e,!this.store.checkStrictly){if(!this.shouldLoadData()||this.store.checkDescendants){var r=Eu(this.childNodes),o=r.all,a=r.allWithoutDisable;this.isLeaf||o||!a||(this.checked=!1,e=!1);var l=function(){if(t){for(var i=s.childNodes,r=0,o=i.length;r<o;r++){var a=i[r];n=n||!1!==e;var l=a.disabled?a.checked:n;a.setChecked(l,t,!0,n)}var u=Eu(i),c=u.half,h=u.all;h||(s.checked=h,s.indeterminate=c)}};if(this.shouldLoadData())return void this.loadData(function(){l(),Tu(s)},{checked:!1!==e});l()}var u=this.parent;u&&0!==u.level&&(i||Tu(u))}},e.prototype.getChildren=function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];if(0===this.level)return this.data;var t=this.data;if(!t)return null;var i=this.store.props,n=\"children\";return i&&(n=i.children||\"children\"),void 0===t[n]&&(t[n]=null),e&&!t[n]&&(t[n]=[]),t[n]},e.prototype.updateChildren=function(){var e=this,t=this.getChildren()||[],i=this.childNodes.map(function(e){return e.data}),n={},s=[];t.forEach(function(e,t){e[Cu]?n[e[Cu]]={index:t,data:e}:s.push({index:t,data:e})}),this.store.lazy||i.forEach(function(t){n[t[Cu]]||e.removeChildByData(t)}),s.forEach(function(t){var i=t.index,n=t.data;e.insertChild({data:n},i)}),this.updateLeafState()},e.prototype.loadData=function(e){var t=this,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(!0!==this.store.lazy||!this.store.load||this.loaded||this.loading&&!Object.keys(i).length)e&&e.call(this);else{this.loading=!0;var n=function(n){t.loaded=!0,t.loading=!1,t.childNodes=[],t.doCreateChildren(n,i),t.updateLeafState(),e&&e.call(t,n)};this.store.load(this,n)}},$u(e,[{key:\"label\",get:function(){return Ou(this,\"label\")}},{key:\"key\",get:function(){var e=this.store.key;return this.data?this.data[e]:null}},{key:\"disabled\",get:function(){return Ou(this,\"disabled\")}},{key:\"nextSibling\",get:function(){var e=this.parent;if(e){var t=e.childNodes.indexOf(this);if(t>-1)return e.childNodes[t+1]}return null}},{key:\"previousSibling\",get:function(){var e=this.parent;if(e){var t=e.childNodes.indexOf(this);if(t>-1)return t>0?e.childNodes[t-1]:null}return null}}]),e}(),Mu=Pu,Nu=\"function\"===typeof Symbol&&\"symbol\"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e};function Fu(e,t){if(!(e instanceof t))throw new TypeError(\"Cannot call a class as a function\")}var Au=function(){function e(t){var i=this;for(var n in Fu(this,e),this.currentNode=null,this.currentNodeKey=null,t)t.hasOwnProperty(n)&&(this[n]=t[n]);if(this.nodesMap={},this.root=new Mu({data:this.data,store:this}),this.lazy&&this.load){var s=this.load;s(this.root,function(e){i.root.doCreateChildren(e),i._initDefaultCheckedNodes()})}else this._initDefaultCheckedNodes()}return e.prototype.filter=function(e){var t=this.filterNodeMethod,i=this.lazy,n=function n(s){var r=s.root?s.root.childNodes:s.childNodes;if(r.forEach(function(i){i.visible=t.call(i,e,i.data,i),n(i)}),!s.visible&&r.length){var o=!0;r.forEach(function(e){e.visible&&(o=!1)}),s.root?s.root.visible=!1===o:s.visible=!1===o}e&&(!s.visible||s.isLeaf||i||s.expand())};n(this)},e.prototype.setData=function(e){var t=e!==this.root.data;t?(this.root.setData(e),this._initDefaultCheckedNodes()):this.root.updateChildren()},e.prototype.getNode=function(e){if(e instanceof Mu)return e;var t=\"object\"!==(\"undefined\"===typeof e?\"undefined\":Nu(e))?e:ku(this.key,e);return this.nodesMap[t]||null},e.prototype.insertBefore=function(e,t){var i=this.getNode(t);i.parent.insertBefore({data:e},i)},e.prototype.insertAfter=function(e,t){var i=this.getNode(t);i.parent.insertAfter({data:e},i)},e.prototype.remove=function(e){var t=this.getNode(e);t&&t.parent&&t.parent.removeChild(t)},e.prototype.append=function(e,t){var i=t?this.getNode(t):this.root;i&&i.insertChild({data:e})},e.prototype._initDefaultCheckedNodes=function(){var e=this,t=this.defaultCheckedKeys||[],i=this.nodesMap;t.forEach(function(t){var n=i[t];n&&n.setChecked(!0,!e.checkStrictly)})},e.prototype._initDefaultCheckedNode=function(e){var t=this.defaultCheckedKeys||[];-1!==t.indexOf(e.key)&&e.setChecked(!0,!this.checkStrictly)},e.prototype.setDefaultCheckedKey=function(e){e!==this.defaultCheckedKeys&&(this.defaultCheckedKeys=e,this._initDefaultCheckedNodes())},e.prototype.registerNode=function(e){var t=this.key;if(t&&e&&e.data){var i=e.key;void 0!==i&&(this.nodesMap[e.key]=e)}},e.prototype.deregisterNode=function(e){var t=this,i=this.key;i&&e&&e.data&&(e.childNodes.forEach(function(e){t.deregisterNode(e)}),delete this.nodesMap[e.key])},e.prototype.getCheckedNodes=function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0],t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],i=[],n=function n(s){var r=s.root?s.root.childNodes:s.childNodes;r.forEach(function(s){(s.checked||t&&s.indeterminate)&&(!e||e&&s.isLeaf)&&i.push(s.data),n(s)})};return n(this),i},e.prototype.getCheckedKeys=function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]&&arguments[0];return this.getCheckedNodes(t).map(function(t){return(t||{})[e.key]})},e.prototype.getHalfCheckedNodes=function(){var e=[],t=function t(i){var n=i.root?i.root.childNodes:i.childNodes;n.forEach(function(i){i.indeterminate&&e.push(i.data),t(i)})};return t(this),e},e.prototype.getHalfCheckedKeys=function(){var e=this;return this.getHalfCheckedNodes().map(function(t){return(t||{})[e.key]})},e.prototype._getAllNodes=function(){var e=[],t=this.nodesMap;for(var i in t)t.hasOwnProperty(i)&&e.push(t[i]);return e},e.prototype.updateChildren=function(e,t){var i=this.nodesMap[e];if(i){for(var n=i.childNodes,s=n.length-1;s>=0;s--){var r=n[s];this.remove(r.data)}for(var o=0,a=t.length;o<a;o++){var l=t[o];this.append(l,i.data)}}},e.prototype._setCheckedKeys=function(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],i=arguments[2],n=this._getAllNodes().sort(function(e,t){return t.level-e.level}),s=Object.create(null),r=Object.keys(i);n.forEach(function(e){return e.setChecked(!1,!1)});for(var o=0,a=n.length;o<a;o++){var l=n[o],u=l.data[e].toString(),c=r.indexOf(u)>-1;if(c){var h=l.parent;while(h&&h.level>0)s[h.data[e]]=!0,h=h.parent;l.isLeaf||this.checkStrictly?l.setChecked(!0,!1):(l.setChecked(!0,!0),t&&function(){l.setChecked(!1,!1);var e=function e(t){var i=t.childNodes;i.forEach(function(t){t.isLeaf||t.setChecked(!1,!1),e(t)})};e(l)}())}else l.checked&&!s[u]&&l.setChecked(!1,!1)}},e.prototype.setCheckedNodes=function(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],i=this.key,n={};e.forEach(function(e){n[(e||{})[i]]=!0}),this._setCheckedKeys(i,t,n)},e.prototype.setCheckedKeys=function(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1];this.defaultCheckedKeys=e;var i=this.key,n={};e.forEach(function(e){n[e]=!0}),this._setCheckedKeys(i,t,n)},e.prototype.setDefaultExpandedKeys=function(e){var t=this;e=e||[],this.defaultExpandedKeys=e,e.forEach(function(e){var i=t.getNode(e);i&&i.expand(null,t.autoExpandParent)})},e.prototype.setChecked=function(e,t,i){var n=this.getNode(e);n&&n.setChecked(!!t,i)},e.prototype.getCurrentNode=function(){return this.currentNode},e.prototype.setCurrentNode=function(e){this.currentNode=e},e.prototype.setUserCurrentNode=function(e){var t=e[this.key],i=this.nodesMap[t];this.setCurrentNode(i)},e.prototype.setCurrentNodeKey=function(e){if(null!==e){var t=this.getNode(e);t&&(this.currentNode=t)}else this.currentNode=null},e}(),Lu=Au,Vu=function(){var e=this,t=this,i=t.$createElement,n=t._self._c||i;return n(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:t.node.visible,expression:\"node.visible\"}],ref:\"node\",staticClass:\"el-tree-node\",class:{\"is-expanded\":t.expanded,\"is-current\":t.tree.store.currentNode===t.node,\"is-hidden\":!t.node.visible,\"is-focusable\":!t.node.disabled,\"is-checked\":!t.node.disabled&&t.node.checked},attrs:{role:\"treeitem\",tabindex:\"-1\",\"aria-expanded\":t.expanded,\"aria-disabled\":t.node.disabled,\"aria-checked\":t.node.checked,draggable:t.tree.draggable},on:{click:function(e){return e.stopPropagation(),t.handleClick(e)},contextmenu:function(t){return e.handleContextMenu(t)},dragstart:function(e){return e.stopPropagation(),t.handleDragStart(e)},dragover:function(e){return e.stopPropagation(),t.handleDragOver(e)},dragend:function(e){return e.stopPropagation(),t.handleDragEnd(e)},drop:function(e){return e.stopPropagation(),t.handleDrop(e)}}},[n(\"div\",{staticClass:\"el-tree-node__content\",style:{\"padding-left\":(t.node.level-1)*t.tree.indent+\"px\"}},[n(\"span\",{class:[{\"is-leaf\":t.node.isLeaf,expanded:!t.node.isLeaf&&t.expanded},\"el-tree-node__expand-icon\",t.tree.iconClass?t.tree.iconClass:\"el-icon-caret-right\"],on:{click:function(e){return e.stopPropagation(),t.handleExpandIconClick(e)}}}),t.showCheckbox?n(\"el-checkbox\",{attrs:{indeterminate:t.node.indeterminate,disabled:!!t.node.disabled},on:{change:t.handleCheckChange},nativeOn:{click:function(e){e.stopPropagation()}},model:{value:t.node.checked,callback:function(e){t.$set(t.node,\"checked\",e)},expression:\"node.checked\"}}):t._e(),t.node.loading?n(\"span\",{staticClass:\"el-tree-node__loading-icon el-icon-loading\"}):t._e(),n(\"node-content\",{attrs:{node:t.node}})],1),n(\"el-collapse-transition\",[!t.renderAfterExpand||t.childNodeRendered?n(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:t.expanded,expression:\"expanded\"}],staticClass:\"el-tree-node__children\",attrs:{role:\"group\",\"aria-expanded\":t.expanded}},t._l(t.node.childNodes,function(e){return n(\"el-tree-node\",{key:t.getNodeKey(e),attrs:{\"render-content\":t.renderContent,\"render-after-expand\":t.renderAfterExpand,\"show-checkbox\":t.showCheckbox,node:e},on:{\"node-expand\":t.handleChildNodeExpand}})}),1):t._e()])],1)},Bu=[];Vu._withStripped=!0;var zu={name:\"ElTreeNode\",componentName:\"ElTreeNode\",mixins:[E.a],props:{node:{default:function(){return{}}},props:{},renderContent:Function,renderAfterExpand:{type:Boolean,default:!0},showCheckbox:{type:Boolean,default:!1}},components:{ElCollapseTransition:Ye.a,ElCheckbox:An.a,NodeContent:{props:{node:{required:!0}},render:function(e){var t=this.$parent,i=t.tree,n=this.node,s=n.data,r=n.store;return t.renderContent?t.renderContent.call(t._renderProxy,e,{_self:i.$vnode.context,node:n,data:s,store:r}):i.$scopedSlots.default?i.$scopedSlots.default({node:n,data:s}):e(\"span\",{class:\"el-tree-node__label\"},[n.label])}}},data:function(){return{tree:null,expanded:!1,childNodeRendered:!1,oldChecked:null,oldIndeterminate:null}},watch:{\"node.indeterminate\":function(e){this.handleSelectChange(this.node.checked,e)},\"node.checked\":function(e){this.handleSelectChange(e,this.node.indeterminate)},\"node.expanded\":function(e){var t=this;this.$nextTick(function(){return t.expanded=e}),e&&(this.childNodeRendered=!0)}},methods:{getNodeKey:function(e){return ku(this.tree.nodeKey,e.data)},handleSelectChange:function(e,t){this.oldChecked!==e&&this.oldIndeterminate!==t&&this.tree.$emit(\"check-change\",this.node.data,e,t),this.oldChecked=e,this.indeterminate=t},handleClick:function(){var e=this.tree.store;e.setCurrentNode(this.node),this.tree.$emit(\"current-change\",e.currentNode?e.currentNode.data:null,e.currentNode),this.tree.currentNode=this,this.tree.expandOnClickNode&&this.handleExpandIconClick(),this.tree.checkOnClickNode&&!this.node.disabled&&this.handleCheckChange(null,{target:{checked:!this.node.checked}}),this.tree.$emit(\"node-click\",this.node.data,this.node,this)},handleContextMenu:function(e){this.tree._events[\"node-contextmenu\"]&&this.tree._events[\"node-contextmenu\"].length>0&&(e.stopPropagation(),e.preventDefault()),this.tree.$emit(\"node-contextmenu\",e,this.node.data,this.node,this)},handleExpandIconClick:function(){this.node.isLeaf||(this.expanded?(this.tree.$emit(\"node-collapse\",this.node.data,this.node,this),this.node.collapse()):(this.node.expand(),this.$emit(\"node-expand\",this.node.data,this.node,this)))},handleCheckChange:function(e,t){var i=this;this.node.setChecked(t.target.checked,!this.tree.checkStrictly),this.$nextTick(function(){var e=i.tree.store;i.tree.$emit(\"check\",i.node.data,{checkedNodes:e.getCheckedNodes(),checkedKeys:e.getCheckedKeys(),halfCheckedNodes:e.getHalfCheckedNodes(),halfCheckedKeys:e.getHalfCheckedKeys()})})},handleChildNodeExpand:function(e,t,i){this.broadcast(\"ElTreeNode\",\"tree-node-expand\",t),this.tree.$emit(\"node-expand\",e,t,i)},handleDragStart:function(e){this.tree.draggable&&this.tree.$emit(\"tree-node-drag-start\",e,this)},handleDragOver:function(e){this.tree.draggable&&(this.tree.$emit(\"tree-node-drag-over\",e,this),e.preventDefault())},handleDrop:function(e){e.preventDefault()},handleDragEnd:function(e){this.tree.draggable&&this.tree.$emit(\"tree-node-drag-end\",e,this)}},created:function(){var e=this,t=this.$parent;t.isTree?this.tree=t:this.tree=t.tree;var i=this.tree;i||console.warn(\"Can not find node's tree.\");var n=i.props||{},s=n[\"children\"]||\"children\";this.$watch(\"node.data.\"+s,function(){e.node.updateChildren()}),this.node.expanded&&(this.expanded=!0,this.childNodeRendered=!0),this.tree.accordion&&this.$on(\"tree-node-expand\",function(t){e.node!==t&&e.node.collapse()})}},ju=zu,Hu=a(ju,Vu,Bu,!1,null,null,null);Hu.options.__file=\"packages/tree/src/tree-node.vue\";var Ru=Hu.exports,Wu={name:\"ElTree\",mixins:[E.a],components:{ElTreeNode:Ru},data:function(){return{store:null,root:null,currentNode:null,treeItems:null,checkboxItems:[],dragState:{showDropIndicator:!1,draggingNode:null,dropNode:null,allowDrop:!0}}},props:{data:{type:Array},emptyText:{type:String,default:function(){return Object(Zi[\"t\"])(\"el.tree.emptyText\")}},renderAfterExpand:{type:Boolean,default:!0},nodeKey:String,checkStrictly:Boolean,defaultExpandAll:Boolean,expandOnClickNode:{type:Boolean,default:!0},checkOnClickNode:Boolean,checkDescendants:{type:Boolean,default:!1},autoExpandParent:{type:Boolean,default:!0},defaultCheckedKeys:Array,defaultExpandedKeys:Array,currentNodeKey:[String,Number],renderContent:Function,showCheckbox:{type:Boolean,default:!1},draggable:{type:Boolean,default:!1},allowDrag:Function,allowDrop:Function,props:{default:function(){return{children:\"children\",label:\"label\",disabled:\"disabled\"}}},lazy:{type:Boolean,default:!1},highlightCurrent:Boolean,load:Function,filterNodeMethod:Function,accordion:Boolean,indent:{type:Number,default:18},iconClass:String},computed:{children:{set:function(e){this.data=e},get:function(){return this.data}},treeItemArray:function(){return Array.prototype.slice.call(this.treeItems)},isEmpty:function(){var e=this.root.childNodes;return!e||0===e.length||e.every(function(e){var t=e.visible;return!t})}},watch:{defaultCheckedKeys:function(e){this.store.setDefaultCheckedKey(e)},defaultExpandedKeys:function(e){this.store.defaultExpandedKeys=e,this.store.setDefaultExpandedKeys(e)},data:function(e){this.store.setData(e)},checkboxItems:function(e){Array.prototype.forEach.call(e,function(e){e.setAttribute(\"tabindex\",-1)})},checkStrictly:function(e){this.store.checkStrictly=e}},methods:{filter:function(e){if(!this.filterNodeMethod)throw new Error(\"[Tree] filterNodeMethod is required when filter\");this.store.filter(e)},getNodeKey:function(e){return ku(this.nodeKey,e.data)},getNodePath:function(e){if(!this.nodeKey)throw new Error(\"[Tree] nodeKey is required in getNodePath\");var t=this.store.getNode(e);if(!t)return[];var i=[t.data],n=t.parent;while(n&&n!==this.root)i.push(n.data),n=n.parent;return i.reverse()},getCheckedNodes:function(e,t){return this.store.getCheckedNodes(e,t)},getCheckedKeys:function(e){return this.store.getCheckedKeys(e)},getCurrentNode:function(){var e=this.store.getCurrentNode();return e?e.data:null},getCurrentKey:function(){if(!this.nodeKey)throw new Error(\"[Tree] nodeKey is required in getCurrentKey\");var e=this.getCurrentNode();return e?e[this.nodeKey]:null},setCheckedNodes:function(e,t){if(!this.nodeKey)throw new Error(\"[Tree] nodeKey is required in setCheckedNodes\");this.store.setCheckedNodes(e,t)},setCheckedKeys:function(e,t){if(!this.nodeKey)throw new Error(\"[Tree] nodeKey is required in setCheckedKeys\");this.store.setCheckedKeys(e,t)},setChecked:function(e,t,i){this.store.setChecked(e,t,i)},getHalfCheckedNodes:function(){return this.store.getHalfCheckedNodes()},getHalfCheckedKeys:function(){return this.store.getHalfCheckedKeys()},setCurrentNode:function(e){if(!this.nodeKey)throw new Error(\"[Tree] nodeKey is required in setCurrentNode\");this.store.setUserCurrentNode(e)},setCurrentKey:function(e){if(!this.nodeKey)throw new Error(\"[Tree] nodeKey is required in setCurrentKey\");this.store.setCurrentNodeKey(e)},getNode:function(e){return this.store.getNode(e)},remove:function(e){this.store.remove(e)},append:function(e,t){this.store.append(e,t)},insertBefore:function(e,t){this.store.insertBefore(e,t)},insertAfter:function(e,t){this.store.insertAfter(e,t)},handleNodeExpand:function(e,t,i){this.broadcast(\"ElTreeNode\",\"tree-node-expand\",t),this.$emit(\"node-expand\",e,t,i)},updateKeyChildren:function(e,t){if(!this.nodeKey)throw new Error(\"[Tree] nodeKey is required in updateKeyChild\");this.store.updateChildren(e,t)},initTabIndex:function(){this.treeItems=this.$el.querySelectorAll(\".is-focusable[role=treeitem]\"),this.checkboxItems=this.$el.querySelectorAll(\"input[type=checkbox]\");var e=this.$el.querySelectorAll(\".is-checked[role=treeitem]\");e.length?e[0].setAttribute(\"tabindex\",0):this.treeItems[0]&&this.treeItems[0].setAttribute(\"tabindex\",0)},handleKeydown:function(e){var t=e.target;if(-1!==t.className.indexOf(\"el-tree-node\")){var i=e.keyCode;this.treeItems=this.$el.querySelectorAll(\".is-focusable[role=treeitem]\");var n=this.treeItemArray.indexOf(t),s=void 0;[38,40].indexOf(i)>-1&&(e.preventDefault(),s=38===i?0!==n?n-1:0:n<this.treeItemArray.length-1?n+1:0,this.treeItemArray[s].focus()),[37,39].indexOf(i)>-1&&(e.preventDefault(),t.click());var r=t.querySelector('[type=\"checkbox\"]');[13,32].indexOf(i)>-1&&r&&(e.preventDefault(),r.click())}}},created:function(){var e=this;this.isTree=!0,this.store=new Lu({key:this.nodeKey,data:this.data,lazy:this.lazy,props:this.props,load:this.load,currentNodeKey:this.currentNodeKey,checkStrictly:this.checkStrictly,checkDescendants:this.checkDescendants,defaultCheckedKeys:this.defaultCheckedKeys,defaultExpandedKeys:this.defaultExpandedKeys,autoExpandParent:this.autoExpandParent,defaultExpandAll:this.defaultExpandAll,filterNodeMethod:this.filterNodeMethod}),this.root=this.store.root;var t=this.dragState;this.$on(\"tree-node-drag-start\",function(i,n){if(\"function\"===typeof e.allowDrag&&!e.allowDrag(n.node))return i.preventDefault(),!1;i.dataTransfer.effectAllowed=\"move\";try{i.dataTransfer.setData(\"text/plain\",\"\")}catch(s){}t.draggingNode=n,e.$emit(\"node-drag-start\",n.node,i)}),this.$on(\"tree-node-drag-over\",function(i,n){var s=Su(i.target,\"ElTreeNode\"),r=t.dropNode;r&&r!==s&&Object(Ve[\"removeClass\"])(r.$el,\"is-drop-inner\");var o=t.draggingNode;if(o&&s){var a=!0,l=!0,u=!0,c=!0;\"function\"===typeof e.allowDrop&&(a=e.allowDrop(o.node,s.node,\"prev\"),c=l=e.allowDrop(o.node,s.node,\"inner\"),u=e.allowDrop(o.node,s.node,\"next\")),i.dataTransfer.dropEffect=l?\"move\":\"none\",(a||l||u)&&r!==s&&(r&&e.$emit(\"node-drag-leave\",o.node,r.node,i),e.$emit(\"node-drag-enter\",o.node,s.node,i)),(a||l||u)&&(t.dropNode=s),s.node.nextSibling===o.node&&(u=!1),s.node.previousSibling===o.node&&(a=!1),s.node.contains(o.node,!1)&&(l=!1),(o.node===s.node||o.node.contains(s.node))&&(a=!1,l=!1,u=!1);var h=s.$el.getBoundingClientRect(),d=e.$el.getBoundingClientRect(),p=void 0,f=a?l?.25:u?.45:1:-1,m=u?l?.75:a?.55:0:1,v=-9999,g=i.clientY-h.top;p=g<h.height*f?\"before\":g>h.height*m?\"after\":l?\"inner\":\"none\";var b=s.$el.querySelector(\".el-tree-node__expand-icon\").getBoundingClientRect(),y=e.$refs.dropIndicator;\"before\"===p?v=b.top-d.top:\"after\"===p&&(v=b.bottom-d.top),y.style.top=v+\"px\",y.style.left=b.right-d.left+\"px\",\"inner\"===p?Object(Ve[\"addClass\"])(s.$el,\"is-drop-inner\"):Object(Ve[\"removeClass\"])(s.$el,\"is-drop-inner\"),t.showDropIndicator=\"before\"===p||\"after\"===p,t.allowDrop=t.showDropIndicator||c,t.dropType=p,e.$emit(\"node-drag-over\",o.node,s.node,i)}}),this.$on(\"tree-node-drag-end\",function(i){var n=t.draggingNode,s=t.dropType,r=t.dropNode;if(i.preventDefault(),i.dataTransfer.dropEffect=\"move\",n&&r){var o={data:n.node.data};\"none\"!==s&&n.node.remove(),\"before\"===s?r.node.parent.insertBefore(o,r.node):\"after\"===s?r.node.parent.insertAfter(o,r.node):\"inner\"===s&&r.node.insertChild(o),\"none\"!==s&&e.store.registerNode(o),Object(Ve[\"removeClass\"])(r.$el,\"is-drop-inner\"),e.$emit(\"node-drag-end\",n.node,r.node,s,i),\"none\"!==s&&e.$emit(\"node-drop\",n.node,r.node,s,i)}n&&!r&&e.$emit(\"node-drag-end\",n.node,null,s,i),t.showDropIndicator=!1,t.draggingNode=null,t.dropNode=null,t.allowDrop=!0})},mounted:function(){this.initTabIndex(),this.$el.addEventListener(\"keydown\",this.handleKeydown)},updated:function(){this.treeItems=this.$el.querySelectorAll(\"[role=treeitem]\"),this.checkboxItems=this.$el.querySelectorAll(\"input[type=checkbox]\")}},qu=Wu,Ku=a(qu,_u,xu,!1,null,null,null);Ku.options.__file=\"packages/tree/src/tree.vue\";var Yu=Ku.exports;Yu.install=function(e){e.component(Yu.name,Yu)};var Uu=Yu,Gu=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"el-alert-fade\"}},[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible,expression:\"visible\"}],staticClass:\"el-alert\",class:[e.typeClass,e.center?\"is-center\":\"\"],attrs:{role:\"alert\"}},[e.showIcon?i(\"i\",{staticClass:\"el-alert__icon\",class:[e.iconClass,e.isBigIcon]}):e._e(),i(\"div\",{staticClass:\"el-alert__content\"},[e.title||e.$slots.title?i(\"span\",{staticClass:\"el-alert__title\",class:[e.isBoldTitle]},[e._t(\"title\",[e._v(e._s(e.title))])],2):e._e(),e.$slots.default&&!e.description?i(\"p\",{staticClass:\"el-alert__description\"},[e._t(\"default\")],2):e._e(),e.description&&!e.$slots.default?i(\"p\",{staticClass:\"el-alert__description\"},[e._v(e._s(e.description))]):e._e(),i(\"i\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.closable,expression:\"closable\"}],staticClass:\"el-alert__closebtn\",class:{\"is-customed\":\"\"!==e.closeText,\"el-icon-close\":\"\"===e.closeText},on:{click:function(t){e.close()}}},[e._v(e._s(e.closeText))])])])])},Xu=[];Gu._withStripped=!0;var Qu={success:\"el-icon-success\",warning:\"el-icon-warning\",error:\"el-icon-error\"},Ju={name:\"ElAlert\",props:{title:{type:String,default:\"\"},description:{type:String,default:\"\"},type:{type:String,default:\"info\"},closable:{type:Boolean,default:!0},closeText:{type:String,default:\"\"},showIcon:Boolean,center:Boolean},data:function(){return{visible:!0}},methods:{close:function(){this.visible=!1,this.$emit(\"close\")}},computed:{typeClass:function(){return\"el-alert--\"+this.type},iconClass:function(){return Qu[this.type]||\"el-icon-info\"},isBigIcon:function(){return this.description||this.$slots.default?\"is-big\":\"\"},isBoldTitle:function(){return this.description||this.$slots.default?\"is-bold\":\"\"}}},Zu=Ju,ec=a(Zu,Gu,Xu,!1,null,null,null);ec.options.__file=\"packages/alert/src/main.vue\";var tc=ec.exports;tc.install=function(e){e.component(tc.name,tc)};var ic=tc,nc=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"el-notification-fade\"}},[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible,expression:\"visible\"}],class:[\"el-notification\",e.customClass,e.horizontalClass],style:e.positionStyle,attrs:{role:\"alert\"},on:{mouseenter:function(t){e.clearTimer()},mouseleave:function(t){e.startTimer()},click:e.click}},[e.type||e.iconClass?i(\"i\",{staticClass:\"el-notification__icon\",class:[e.typeClass,e.iconClass]}):e._e(),i(\"div\",{staticClass:\"el-notification__group\",class:{\"is-with-icon\":e.typeClass||e.iconClass}},[i(\"h2\",{staticClass:\"el-notification__title\",domProps:{textContent:e._s(e.title)}}),i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.message,expression:\"message\"}],staticClass:\"el-notification__content\"},[e._t(\"default\",[e.dangerouslyUseHTMLString?i(\"p\",{domProps:{innerHTML:e._s(e.message)}}):i(\"p\",[e._v(e._s(e.message))])])],2),e.showClose?i(\"div\",{staticClass:\"el-notification__closeBtn el-icon-close\",on:{click:function(t){return t.stopPropagation(),e.close(t)}}}):e._e()])])])},sc=[];nc._withStripped=!0;var rc={success:\"success\",info:\"info\",warning:\"warning\",error:\"error\"},oc={data:function(){return{visible:!1,title:\"\",message:\"\",duration:4500,type:\"\",showClose:!0,customClass:\"\",iconClass:\"\",onClose:null,onClick:null,closed:!1,verticalOffset:0,timer:null,dangerouslyUseHTMLString:!1,position:\"top-right\"}},computed:{typeClass:function(){return this.type&&rc[this.type]?\"el-icon-\"+rc[this.type]:\"\"},horizontalClass:function(){return this.position.indexOf(\"right\")>-1?\"right\":\"left\"},verticalProperty:function(){return/^top-/.test(this.position)?\"top\":\"bottom\"},positionStyle:function(){var e;return e={},e[this.verticalProperty]=this.verticalOffset+\"px\",e}},watch:{closed:function(e){e&&(this.visible=!1,this.$el.addEventListener(\"transitionend\",this.destroyElement))}},methods:{destroyElement:function(){this.$el.removeEventListener(\"transitionend\",this.destroyElement),this.$destroy(!0),this.$el.parentNode.removeChild(this.$el)},click:function(){\"function\"===typeof this.onClick&&this.onClick()},close:function(){this.closed=!0,\"function\"===typeof this.onClose&&this.onClose()},clearTimer:function(){clearTimeout(this.timer)},startTimer:function(){var e=this;this.duration>0&&(this.timer=setTimeout(function(){e.closed||e.close()},this.duration))},keydown:function(e){46===e.keyCode||8===e.keyCode?this.clearTimer():27===e.keyCode?this.closed||this.close():this.startTimer()}},mounted:function(){var e=this;this.duration>0&&(this.timer=setTimeout(function(){e.closed||e.close()},this.duration)),document.addEventListener(\"keydown\",this.keydown)},beforeDestroy:function(){document.removeEventListener(\"keydown\",this.keydown)}},ac=oc,lc=a(ac,nc,sc,!1,null,null,null);lc.options.__file=\"packages/notification/src/main.vue\";var uc=lc.exports,cc=Rn.a.extend(uc),hc=void 0,dc=[],pc=1,fc=function e(t){if(!Rn.a.prototype.$isServer){t=t||{};var i=t.onClose,n=\"notification_\"+pc++,s=t.position||\"top-right\";t.onClose=function(){e.close(n,i)},hc=new cc({data:t}),Object(Wa[\"isVNode\"])(t.message)&&(hc.$slots.default=[t.message],t.message=\"REPLACED_BY_VNODE\"),hc.id=n,hc.$mount(),document.body.appendChild(hc.$el),hc.visible=!0,hc.dom=hc.$el,hc.dom.style.zIndex=w[\"PopupManager\"].nextZIndex();var r=t.offset||0;return dc.filter(function(e){return e.position===s}).forEach(function(e){r+=e.$el.offsetHeight+16}),r+=16,hc.verticalOffset=r,dc.push(hc),hc}};[\"success\",\"warning\",\"info\",\"error\"].forEach(function(e){fc[e]=function(t){return(\"string\"===typeof t||Object(Wa[\"isVNode\"])(t))&&(t={message:t}),t.type=e,fc(t)}}),fc.close=function(e,t){var i=-1,n=dc.length,s=dc.filter(function(t,n){return t.id===e&&(i=n,!0)})[0];if(s&&(\"function\"===typeof t&&t(s),dc.splice(i,1),!(n<=1)))for(var r=s.position,o=s.dom.offsetHeight,a=i;a<n-1;a++)dc[a].position===r&&(dc[a].dom.style[s.verticalProperty]=parseInt(dc[a].dom.style[s.verticalProperty],10)-o-16+\"px\")},fc.closeAll=function(){for(var e=dc.length-1;e>=0;e--)dc[e].close()};var mc=fc,vc=mc,gc=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-slider\",class:{\"is-vertical\":e.vertical,\"el-slider--with-input\":e.showInput},attrs:{role:\"slider\",\"aria-valuemin\":e.min,\"aria-valuemax\":e.max,\"aria-orientation\":e.vertical?\"vertical\":\"horizontal\",\"aria-disabled\":e.sliderDisabled}},[e.showInput&&!e.range?i(\"el-input-number\",{ref:\"input\",staticClass:\"el-slider__input\",attrs:{step:e.step,disabled:e.sliderDisabled,controls:e.showInputControls,min:e.min,max:e.max,debounce:e.debounce,size:e.inputSize},on:{change:function(t){e.$nextTick(e.emitChange)}},model:{value:e.firstValue,callback:function(t){e.firstValue=t},expression:\"firstValue\"}}):e._e(),i(\"div\",{ref:\"slider\",staticClass:\"el-slider__runway\",class:{\"show-input\":e.showInput,disabled:e.sliderDisabled},style:e.runwayStyle,on:{click:e.onSliderClick}},[i(\"div\",{staticClass:\"el-slider__bar\",style:e.barStyle}),i(\"slider-button\",{ref:\"button1\",attrs:{vertical:e.vertical,\"tooltip-class\":e.tooltipClass},model:{value:e.firstValue,callback:function(t){e.firstValue=t},expression:\"firstValue\"}}),e.range?i(\"slider-button\",{ref:\"button2\",attrs:{vertical:e.vertical,\"tooltip-class\":e.tooltipClass},model:{value:e.secondValue,callback:function(t){e.secondValue=t},expression:\"secondValue\"}}):e._e(),e._l(e.stops,function(t,n){return e.showStops?i(\"div\",{key:n,staticClass:\"el-slider__stop\",style:e.vertical?{bottom:t+\"%\"}:{left:t+\"%\"}}):e._e()})],2)],1)},bc=[];gc._withStripped=!0;var yc=i(37),_c=i.n(yc),xc=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{ref:\"button\",staticClass:\"el-slider__button-wrapper\",class:{hover:e.hovering,dragging:e.dragging},style:e.wrapperStyle,attrs:{tabindex:\"0\"},on:{mouseenter:e.handleMouseEnter,mouseleave:e.handleMouseLeave,mousedown:e.onButtonDown,touchstart:e.onButtonDown,focus:e.handleMouseEnter,blur:e.handleMouseLeave,keydown:[function(t){return\"button\"in t||!e._k(t.keyCode,\"left\",37,t.key,[\"Left\",\"ArrowLeft\"])?\"button\"in t&&0!==t.button?null:e.onLeftKeyDown(t):null},function(t){return\"button\"in t||!e._k(t.keyCode,\"right\",39,t.key,[\"Right\",\"ArrowRight\"])?\"button\"in t&&2!==t.button?null:e.onRightKeyDown(t):null},function(t){return\"button\"in t||!e._k(t.keyCode,\"down\",40,t.key,[\"Down\",\"ArrowDown\"])?(t.preventDefault(),e.onLeftKeyDown(t)):null},function(t){return\"button\"in t||!e._k(t.keyCode,\"up\",38,t.key,[\"Up\",\"ArrowUp\"])?(t.preventDefault(),e.onRightKeyDown(t)):null}]}},[i(\"el-tooltip\",{ref:\"tooltip\",attrs:{placement:\"top\",\"popper-class\":e.tooltipClass,disabled:!e.showTooltip}},[i(\"span\",{attrs:{slot:\"content\"},slot:\"content\"},[e._v(e._s(e.formatValue))]),i(\"div\",{staticClass:\"el-slider__button\",class:{hover:e.hovering,dragging:e.dragging}})])],1)},Cc=[];xc._withStripped=!0;var wc={name:\"ElSliderButton\",components:{ElTooltip:st.a},props:{value:{type:Number,default:0},vertical:{type:Boolean,default:!1},tooltipClass:String},data:function(){return{hovering:!1,dragging:!1,isClick:!1,startX:0,currentX:0,startY:0,currentY:0,startPosition:0,newPosition:null,oldValue:this.value}},computed:{disabled:function(){return this.$parent.sliderDisabled},max:function(){return this.$parent.max},min:function(){return this.$parent.min},step:function(){return this.$parent.step},showTooltip:function(){return this.$parent.showTooltip},precision:function(){return this.$parent.precision},currentPosition:function(){return(this.value-this.min)/(this.max-this.min)*100+\"%\"},enableFormat:function(){return this.$parent.formatTooltip instanceof Function},formatValue:function(){return this.enableFormat&&this.$parent.formatTooltip(this.value)||this.value},wrapperStyle:function(){return this.vertical?{bottom:this.currentPosition}:{left:this.currentPosition}}},watch:{dragging:function(e){this.$parent.dragging=e}},methods:{displayTooltip:function(){this.$refs.tooltip&&(this.$refs.tooltip.showPopper=!0)},hideTooltip:function(){this.$refs.tooltip&&(this.$refs.tooltip.showPopper=!1)},handleMouseEnter:function(){this.hovering=!0,this.displayTooltip()},handleMouseLeave:function(){this.hovering=!1,this.hideTooltip()},onButtonDown:function(e){this.disabled||(e.preventDefault(),this.onDragStart(e),window.addEventListener(\"mousemove\",this.onDragging),window.addEventListener(\"touchmove\",this.onDragging),window.addEventListener(\"mouseup\",this.onDragEnd),window.addEventListener(\"touchend\",this.onDragEnd),window.addEventListener(\"contextmenu\",this.onDragEnd))},onLeftKeyDown:function(){this.disabled||(this.newPosition=parseFloat(this.currentPosition)-this.step/(this.max-this.min)*100,this.setPosition(this.newPosition))},onRightKeyDown:function(){this.disabled||(this.newPosition=parseFloat(this.currentPosition)+this.step/(this.max-this.min)*100,this.setPosition(this.newPosition))},onDragStart:function(e){this.dragging=!0,this.isClick=!0,\"touchstart\"===e.type&&(e.clientY=e.touches[0].clientY,e.clientX=e.touches[0].clientX),this.vertical?this.startY=e.clientY:this.startX=e.clientX,this.startPosition=parseFloat(this.currentPosition),this.newPosition=this.startPosition},onDragging:function(e){if(this.dragging){this.isClick=!1,this.displayTooltip(),this.$parent.resetSize();var t=0;\"touchmove\"===e.type&&(e.clientY=e.touches[0].clientY,e.clientX=e.touches[0].clientX),this.vertical?(this.currentY=e.clientY,t=(this.startY-this.currentY)/this.$parent.sliderSize*100):(this.currentX=e.clientX,t=(this.currentX-this.startX)/this.$parent.sliderSize*100),this.newPosition=this.startPosition+t,this.setPosition(this.newPosition)}},onDragEnd:function(){var e=this;this.dragging&&(setTimeout(function(){e.dragging=!1,e.hideTooltip(),e.isClick||(e.setPosition(e.newPosition),e.$parent.emitChange())},0),window.removeEventListener(\"mousemove\",this.onDragging),window.removeEventListener(\"touchmove\",this.onDragging),window.removeEventListener(\"mouseup\",this.onDragEnd),window.removeEventListener(\"touchend\",this.onDragEnd),window.removeEventListener(\"contextmenu\",this.onDragEnd))},setPosition:function(e){var t=this;if(null!==e&&!isNaN(e)){e<0?e=0:e>100&&(e=100);var i=100/((this.max-this.min)/this.step),n=Math.round(e/i),s=n*i*(this.max-this.min)*.01+this.min;s=parseFloat(s.toFixed(this.precision)),this.$emit(\"input\",s),this.$nextTick(function(){t.$refs.tooltip&&t.$refs.tooltip.updatePopper()}),this.dragging||this.value===this.oldValue||(this.oldValue=this.value)}}}},kc=wc,Sc=a(kc,xc,Cc,!1,null,null,null);Sc.options.__file=\"packages/slider/src/button.vue\";var $c=Sc.exports,Dc={name:\"ElSlider\",mixins:[E.a],inject:{elForm:{default:\"\"}},props:{min:{type:Number,default:0},max:{type:Number,default:100},step:{type:Number,default:1},value:{type:[Number,Array],default:0},showInput:{type:Boolean,default:!1},showInputControls:{type:Boolean,default:!0},inputSize:{type:String,default:\"small\"},showStops:{type:Boolean,default:!1},showTooltip:{type:Boolean,default:!0},formatTooltip:Function,disabled:{type:Boolean,default:!1},range:{type:Boolean,default:!1},vertical:{type:Boolean,default:!1},height:{type:String},debounce:{type:Number,default:300},label:{type:String},tooltipClass:String},components:{ElInputNumber:_c.a,SliderButton:$c},data:function(){return{firstValue:null,secondValue:null,oldValue:null,dragging:!1,sliderSize:1}},watch:{value:function(e,t){this.dragging||Array.isArray(e)&&Array.isArray(t)&&e.every(function(e,i){return e===t[i]})||this.setValues()},dragging:function(e){e||this.setValues()},firstValue:function(e){this.range?this.$emit(\"input\",[this.minValue,this.maxValue]):this.$emit(\"input\",e)},secondValue:function(){this.range&&this.$emit(\"input\",[this.minValue,this.maxValue])},min:function(){this.setValues()},max:function(){this.setValues()}},methods:{valueChanged:function(){var e=this;return this.range?![this.minValue,this.maxValue].every(function(t,i){return t===e.oldValue[i]}):this.value!==this.oldValue},setValues:function(){if(this.min>this.max)console.error(\"[Element Error][Slider]min should not be greater than max.\");else{var e=this.value;this.range&&Array.isArray(e)?e[1]<this.min?this.$emit(\"input\",[this.min,this.min]):e[0]>this.max?this.$emit(\"input\",[this.max,this.max]):e[0]<this.min?this.$emit(\"input\",[this.min,e[1]]):e[1]>this.max?this.$emit(\"input\",[e[0],this.max]):(this.firstValue=e[0],this.secondValue=e[1],this.valueChanged()&&(this.dispatch(\"ElFormItem\",\"el.form.change\",[this.minValue,this.maxValue]),this.oldValue=e.slice())):this.range||\"number\"!==typeof e||isNaN(e)||(e<this.min?this.$emit(\"input\",this.min):e>this.max?this.$emit(\"input\",this.max):(this.firstValue=e,this.valueChanged()&&(this.dispatch(\"ElFormItem\",\"el.form.change\",e),this.oldValue=e)))}},setPosition:function(e){var t=this.min+e*(this.max-this.min)/100;if(this.range){var i=void 0;i=Math.abs(this.minValue-t)<Math.abs(this.maxValue-t)?this.firstValue<this.secondValue?\"button1\":\"button2\":this.firstValue>this.secondValue?\"button1\":\"button2\",this.$refs[i].setPosition(e)}else this.$refs.button1.setPosition(e)},onSliderClick:function(e){if(!this.sliderDisabled&&!this.dragging){if(this.resetSize(),this.vertical){var t=this.$refs.slider.getBoundingClientRect().bottom;this.setPosition((t-e.clientY)/this.sliderSize*100)}else{var i=this.$refs.slider.getBoundingClientRect().left;this.setPosition((e.clientX-i)/this.sliderSize*100)}this.emitChange()}},resetSize:function(){this.$refs.slider&&(this.sliderSize=this.$refs.slider[\"client\"+(this.vertical?\"Height\":\"Width\")])},emitChange:function(){var e=this;this.$nextTick(function(){e.$emit(\"change\",e.range?[e.minValue,e.maxValue]:e.value)})}},computed:{stops:function(){var e=this;if(!this.showStops||this.min>this.max)return[];if(0===this.step)return[];for(var t=(this.max-this.min)/this.step,i=100*this.step/(this.max-this.min),n=[],s=1;s<t;s++)n.push(s*i);return this.range?n.filter(function(t){return t<100*(e.minValue-e.min)/(e.max-e.min)||t>100*(e.maxValue-e.min)/(e.max-e.min)}):n.filter(function(t){return t>100*(e.firstValue-e.min)/(e.max-e.min)})},minValue:function(){return Math.min(this.firstValue,this.secondValue)},maxValue:function(){return Math.max(this.firstValue,this.secondValue)},barSize:function(){return this.range?100*(this.maxValue-this.minValue)/(this.max-this.min)+\"%\":100*(this.firstValue-this.min)/(this.max-this.min)+\"%\"},barStart:function(){return this.range?100*(this.minValue-this.min)/(this.max-this.min)+\"%\":\"0%\"},precision:function(){var e=[this.min,this.max,this.step].map(function(e){var t=(\"\"+e).split(\".\")[1];return t?t.length:0});return Math.max.apply(null,e)},runwayStyle:function(){return this.vertical?{height:this.height}:{}},barStyle:function(){return this.vertical?{height:this.barSize,bottom:this.barStart}:{width:this.barSize,left:this.barStart}},sliderDisabled:function(){return this.disabled||(this.elForm||{}).disabled}},mounted:function(){var e=void 0;this.range?(Array.isArray(this.value)?(this.firstValue=Math.max(this.min,this.value[0]),this.secondValue=Math.min(this.max,this.value[1])):(this.firstValue=this.min,this.secondValue=this.max),this.oldValue=[this.firstValue,this.secondValue],e=this.firstValue+\"-\"+this.secondValue):(\"number\"!==typeof this.value||isNaN(this.value)?this.firstValue=this.min:this.firstValue=Math.min(this.max,Math.max(this.min,this.value)),this.oldValue=this.firstValue,e=this.firstValue),this.$el.setAttribute(\"aria-valuetext\",e),this.$el.setAttribute(\"aria-label\",this.label?this.label:\"slider between \"+this.min+\" and \"+this.max),this.resetSize(),window.addEventListener(\"resize\",this.resetSize)},beforeDestroy:function(){window.removeEventListener(\"resize\",this.resetSize)}},Ec=Dc,Tc=a(Ec,gc,bc,!1,null,null,null);Tc.options.__file=\"packages/slider/src/main.vue\";var Oc=Tc.exports;Oc.install=function(e){e.component(Oc.name,Oc)};var Ic=Oc,Pc=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"el-loading-fade\"},on:{\"after-leave\":e.handleAfterLeave}},[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible,expression:\"visible\"}],staticClass:\"el-loading-mask\",class:[e.customClass,{\"is-fullscreen\":e.fullscreen}],style:{backgroundColor:e.background||\"\"}},[i(\"div\",{staticClass:\"el-loading-spinner\"},[e.spinner?i(\"i\",{class:e.spinner}):i(\"svg\",{staticClass:\"circular\",attrs:{viewBox:\"25 25 50 50\"}},[i(\"circle\",{staticClass:\"path\",attrs:{cx:\"50\",cy:\"50\",r:\"20\",fill:\"none\"}})]),e.text?i(\"p\",{staticClass:\"el-loading-text\"},[e._v(e._s(e.text))]):e._e()])])])},Mc=[];Pc._withStripped=!0;var Nc={data:function(){return{text:null,spinner:null,background:null,fullscreen:!0,visible:!1,customClass:\"\"}},methods:{handleAfterLeave:function(){this.$emit(\"after-leave\")},setText:function(e){this.text=e}}},Fc=Nc,Ac=a(Fc,Pc,Mc,!1,null,null,null);Ac.options.__file=\"packages/loading/src/loading.vue\";var Lc=Ac.exports,Vc=i(28),Bc=i.n(Vc),zc=Rn.a.extend(Lc),jc={install:function(e){if(!e.prototype.$isServer){var t=function(t,n){n.value?e.nextTick(function(){n.modifiers.fullscreen?(t.originalPosition=Object(Ve[\"getStyle\"])(document.body,\"position\"),t.originalOverflow=Object(Ve[\"getStyle\"])(document.body,\"overflow\"),t.maskStyle.zIndex=w[\"PopupManager\"].nextZIndex(),Object(Ve[\"addClass\"])(t.mask,\"is-fullscreen\"),i(document.body,t,n)):(Object(Ve[\"removeClass\"])(t.mask,\"is-fullscreen\"),n.modifiers.body?(t.originalPosition=Object(Ve[\"getStyle\"])(document.body,\"position\"),[\"top\",\"left\"].forEach(function(e){var i=\"top\"===e?\"scrollTop\":\"scrollLeft\";t.maskStyle[e]=t.getBoundingClientRect()[e]+document.body[i]+document.documentElement[i]-parseInt(Object(Ve[\"getStyle\"])(document.body,\"margin-\"+e),10)+\"px\"}),[\"height\",\"width\"].forEach(function(e){t.maskStyle[e]=t.getBoundingClientRect()[e]+\"px\"}),i(document.body,t,n)):(t.originalPosition=Object(Ve[\"getStyle\"])(t,\"position\"),i(t,t,n)))}):(Bc()(t.instance,function(e){t.domVisible=!1;var i=n.modifiers.fullscreen||n.modifiers.body?document.body:t;Object(Ve[\"removeClass\"])(i,\"el-loading-parent--relative\"),Object(Ve[\"removeClass\"])(i,\"el-loading-parent--hidden\"),t.instance.hiding=!1},300,!0),t.instance.visible=!1,t.instance.hiding=!0)},i=function(t,i,n){i.domVisible||\"none\"===Object(Ve[\"getStyle\"])(i,\"display\")||\"hidden\"===Object(Ve[\"getStyle\"])(i,\"visibility\")||(Object.keys(i.maskStyle).forEach(function(e){i.mask.style[e]=i.maskStyle[e]}),\"absolute\"!==i.originalPosition&&\"fixed\"!==i.originalPosition&&Object(Ve[\"addClass\"])(t,\"el-loading-parent--relative\"),n.modifiers.fullscreen&&n.modifiers.lock&&Object(Ve[\"addClass\"])(t,\"el-loading-parent--hidden\"),i.domVisible=!0,t.appendChild(i.mask),e.nextTick(function(){i.instance.hiding?i.instance.$emit(\"after-leave\"):i.instance.visible=!0}),i.domInserted=!0)};e.directive(\"loading\",{bind:function(e,i,n){var s=e.getAttribute(\"element-loading-text\"),r=e.getAttribute(\"element-loading-spinner\"),o=e.getAttribute(\"element-loading-background\"),a=e.getAttribute(\"element-loading-custom-class\"),l=n.context,u=new zc({el:document.createElement(\"div\"),data:{text:l&&l[s]||s,spinner:l&&l[r]||r,background:l&&l[o]||o,customClass:l&&l[a]||a,fullscreen:!!i.modifiers.fullscreen}});e.instance=u,e.mask=u.$el,e.maskStyle={},i.value&&t(e,i)},update:function(e,i){e.instance.setText(e.getAttribute(\"element-loading-text\")),i.oldValue!==i.value&&t(e,i)},unbind:function(e,i){e.domInserted&&(e.mask&&e.mask.parentNode&&e.mask.parentNode.removeChild(e.mask),t(e,{value:!1,modifiers:i.modifiers})),e.instance&&e.instance.$destroy()}})}}},Hc=jc,Rc=Rn.a.extend(Lc),Wc={text:null,fullscreen:!0,body:!1,lock:!1,customClass:\"\"},qc=void 0;Rc.prototype.originalPosition=\"\",Rc.prototype.originalOverflow=\"\",Rc.prototype.close=function(){var e=this;this.fullscreen&&(qc=void 0),Bc()(this,function(t){var i=e.fullscreen||e.body?document.body:e.target;Object(Ve[\"removeClass\"])(i,\"el-loading-parent--relative\"),Object(Ve[\"removeClass\"])(i,\"el-loading-parent--hidden\"),e.$el&&e.$el.parentNode&&e.$el.parentNode.removeChild(e.$el),e.$destroy()},300),this.visible=!1};var Kc=function(e,t,i){var n={};e.fullscreen?(i.originalPosition=Object(Ve[\"getStyle\"])(document.body,\"position\"),i.originalOverflow=Object(Ve[\"getStyle\"])(document.body,\"overflow\"),n.zIndex=w[\"PopupManager\"].nextZIndex()):e.body?(i.originalPosition=Object(Ve[\"getStyle\"])(document.body,\"position\"),[\"top\",\"left\"].forEach(function(t){var i=\"top\"===t?\"scrollTop\":\"scrollLeft\";n[t]=e.target.getBoundingClientRect()[t]+document.body[i]+document.documentElement[i]+\"px\"}),[\"height\",\"width\"].forEach(function(t){n[t]=e.target.getBoundingClientRect()[t]+\"px\"})):i.originalPosition=Object(Ve[\"getStyle\"])(t,\"position\"),Object.keys(n).forEach(function(e){i.$el.style[e]=n[e]})},Yc=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(!Rn.a.prototype.$isServer){if(e=St()({},Wc,e),\"string\"===typeof e.target&&(e.target=document.querySelector(e.target)),e.target=e.target||document.body,e.target!==document.body?e.fullscreen=!1:e.body=!0,e.fullscreen&&qc)return qc;var t=e.body?document.body:e.target,i=new Rc({el:document.createElement(\"div\"),data:e});return Kc(e,t,i),\"absolute\"!==i.originalPosition&&\"fixed\"!==i.originalPosition&&Object(Ve[\"addClass\"])(t,\"el-loading-parent--relative\"),e.fullscreen&&e.lock&&Object(Ve[\"addClass\"])(t,\"el-loading-parent--hidden\"),t.appendChild(i.$el),Rn.a.nextTick(function(){i.visible=!0}),e.fullscreen&&(qc=i),i}},Uc=Yc,Gc={install:function(e){e.use(Hc),e.prototype.$loading=Uc},directive:Hc,service:Uc},Xc=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"i\",{class:\"el-icon-\"+e.name})},Qc=[];Xc._withStripped=!0;var Jc={name:\"ElIcon\",props:{name:String}},Zc=Jc,eh=a(Zc,Xc,Qc,!1,null,null,null);eh.options.__file=\"packages/icon/src/icon.vue\";var th=eh.exports;th.install=function(e){e.component(th.name,th)};var ih=th,nh={name:\"ElRow\",componentName:\"ElRow\",props:{tag:{type:String,default:\"div\"},gutter:Number,type:String,justify:{type:String,default:\"start\"},align:{type:String,default:\"top\"}},computed:{style:function(){var e={};return this.gutter&&(e.marginLeft=\"-\"+this.gutter/2+\"px\",e.marginRight=e.marginLeft),e}},render:function(e){return e(this.tag,{class:[\"el-row\",\"start\"!==this.justify?\"is-justify-\"+this.justify:\"\",\"top\"!==this.align?\"is-align-\"+this.align:\"\",{\"el-row--flex\":\"flex\"===this.type}],style:this.style},this.$slots.default)},install:function(e){e.component(nh.name,nh)}},sh=nh,rh=\"function\"===typeof Symbol&&\"symbol\"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},oh={name:\"ElCol\",props:{span:{type:Number,default:24},tag:{type:String,default:\"div\"},offset:Number,pull:Number,push:Number,xs:[Number,Object],sm:[Number,Object],md:[Number,Object],lg:[Number,Object],xl:[Number,Object]},computed:{gutter:function(){var e=this.$parent;while(e&&\"ElRow\"!==e.$options.componentName)e=e.$parent;return e?e.gutter:0}},render:function(e){var t=this,i=[],n={};return this.gutter&&(n.paddingLeft=this.gutter/2+\"px\",n.paddingRight=n.paddingLeft),[\"span\",\"offset\",\"pull\",\"push\"].forEach(function(e){(t[e]||0===t[e])&&i.push(\"span\"!==e?\"el-col-\"+e+\"-\"+t[e]:\"el-col-\"+t[e])}),[\"xs\",\"sm\",\"md\",\"lg\",\"xl\"].forEach(function(e){if(\"number\"===typeof t[e])i.push(\"el-col-\"+e+\"-\"+t[e]);else if(\"object\"===rh(t[e])){var n=t[e];Object.keys(n).forEach(function(t){i.push(\"span\"!==t?\"el-col-\"+e+\"-\"+t+\"-\"+n[t]:\"el-col-\"+e+\"-\"+n[t])})}}),e(this.tag,{class:[\"el-col\",i],style:n},this.$slots.default)},install:function(e){e.component(oh.name,oh)}},ah=oh,lh=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition-group\",{class:[\"el-upload-list\",\"el-upload-list--\"+e.listType,{\"is-disabled\":e.disabled}],attrs:{tag:\"ul\",name:\"el-list\"}},e._l(e.files,function(t){return i(\"li\",{key:t.uid,class:[\"el-upload-list__item\",\"is-\"+t.status,e.focusing?\"focusing\":\"\"],attrs:{tabindex:\"0\"},on:{keydown:function(i){if(!(\"button\"in i)&&e._k(i.keyCode,\"delete\",[8,46],i.key,[\"Backspace\",\"Delete\",\"Del\"]))return null;!e.disabled&&e.$emit(\"remove\",t)},focus:function(t){e.focusing=!0},blur:function(t){e.focusing=!1},click:function(t){e.focusing=!1}}},[\"uploading\"!==t.status&&[\"picture-card\",\"picture\"].indexOf(e.listType)>-1?i(\"img\",{staticClass:\"el-upload-list__item-thumbnail\",attrs:{src:t.url,alt:\"\"}}):e._e(),i(\"a\",{staticClass:\"el-upload-list__item-name\",on:{click:function(i){e.handleClick(t)}}},[i(\"i\",{staticClass:\"el-icon-document\"}),e._v(e._s(t.name)+\"\\n    \")]),i(\"label\",{staticClass:\"el-upload-list__item-status-label\"},[i(\"i\",{class:{\"el-icon-upload-success\":!0,\"el-icon-circle-check\":\"text\"===e.listType,\"el-icon-check\":[\"picture-card\",\"picture\"].indexOf(e.listType)>-1}})]),e.disabled?e._e():i(\"i\",{staticClass:\"el-icon-close\",on:{click:function(i){e.$emit(\"remove\",t)}}}),e.disabled?e._e():i(\"i\",{staticClass:\"el-icon-close-tip\"},[e._v(e._s(e.t(\"el.upload.deleteTip\")))]),\"uploading\"===t.status?i(\"el-progress\",{attrs:{type:\"picture-card\"===e.listType?\"circle\":\"line\",\"stroke-width\":\"picture-card\"===e.listType?6:2,percentage:e.parsePercentage(t.percentage)}}):e._e(),\"picture-card\"===e.listType?i(\"span\",{staticClass:\"el-upload-list__item-actions\"},[e.handlePreview&&\"picture-card\"===e.listType?i(\"span\",{staticClass:\"el-upload-list__item-preview\",on:{click:function(i){e.handlePreview(t)}}},[i(\"i\",{staticClass:\"el-icon-zoom-in\"})]):e._e(),e.disabled?e._e():i(\"span\",{staticClass:\"el-upload-list__item-delete\",on:{click:function(i){e.$emit(\"remove\",t)}}},[i(\"i\",{staticClass:\"el-icon-delete\"})])]):e._e()],1)}),0)},uh=[];lh._withStripped=!0;var ch=i(29),hh=i.n(ch),dh={name:\"ElUploadList\",mixins:[g.a],data:function(){return{focusing:!1}},components:{ElProgress:hh.a},props:{files:{type:Array,default:function(){return[]}},disabled:{type:Boolean,default:!1},handlePreview:Function,listType:String},methods:{parsePercentage:function(e){return parseInt(e,10)},handleClick:function(e){this.handlePreview&&this.handlePreview(e)}}},ph=dh,fh=a(ph,lh,uh,!1,null,null,null);fh.options.__file=\"packages/upload/src/upload-list.vue\";var mh=fh.exports,vh=i(23),gh=i.n(vh);function bh(e,t,i){var n=void 0;n=i.response?\"\"+(i.response.error||i.response):i.responseText?\"\"+i.responseText:\"fail to post \"+e+\" \"+i.status;var s=new Error(n);return s.status=i.status,s.method=\"post\",s.url=e,s}function yh(e){var t=e.responseText||e.response;if(!t)return t;try{return JSON.parse(t)}catch(i){return t}}function _h(e){if(\"undefined\"!==typeof XMLHttpRequest){var t=new XMLHttpRequest,i=e.action;t.upload&&(t.upload.onprogress=function(t){t.total>0&&(t.percent=t.loaded/t.total*100),e.onProgress(t)});var n=new FormData;e.data&&Object.keys(e.data).forEach(function(t){n.append(t,e.data[t])}),n.append(e.filename,e.file,e.file.name),t.onerror=function(t){e.onError(t)},t.onload=function(){if(t.status<200||t.status>=300)return e.onError(bh(i,e,t));e.onSuccess(yh(t))},t.open(\"post\",i,!0),e.withCredentials&&\"withCredentials\"in t&&(t.withCredentials=!0);var s=e.headers||{};for(var r in s)s.hasOwnProperty(r)&&null!==s[r]&&t.setRequestHeader(r,s[r]);return t.send(n),t}}var xh=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-upload-dragger\",class:{\"is-dragover\":e.dragover},on:{drop:function(t){return t.preventDefault(),e.onDrop(t)},dragover:function(t){return t.preventDefault(),e.onDragover(t)},dragleave:function(t){t.preventDefault(),e.dragover=!1}}},[e._t(\"default\")],2)},Ch=[];xh._withStripped=!0;var wh={name:\"ElUploadDrag\",props:{disabled:Boolean},inject:{uploader:{default:\"\"}},data:function(){return{dragover:!1}},methods:{onDragover:function(){this.disabled||(this.dragover=!0)},onDrop:function(e){if(!this.disabled&&this.uploader){var t=this.uploader.accept;this.dragover=!1,t?this.$emit(\"file\",[].slice.call(e.dataTransfer.files).filter(function(e){var i=e.type,n=e.name,s=n.indexOf(\".\")>-1?\".\"+n.split(\".\").pop():\"\",r=i.replace(/\\/.*$/,\"\");return t.split(\",\").map(function(e){return e.trim()}).filter(function(e){return e}).some(function(e){return/\\..+$/.test(e)?s===e:/\\/\\*$/.test(e)?r===e.replace(/\\/\\*$/,\"\"):!!/^[^\\/]+\\/[^\\/]+$/.test(e)&&i===e})})):this.$emit(\"file\",e.dataTransfer.files)}}}},kh=wh,Sh=a(kh,xh,Ch,!1,null,null,null);Sh.options.__file=\"packages/upload/src/upload-dragger.vue\";var $h,Dh,Eh=Sh.exports,Th={inject:[\"uploader\"],components:{UploadDragger:Eh},props:{type:String,action:{type:String,required:!0},name:{type:String,default:\"file\"},data:Object,headers:Object,withCredentials:Boolean,multiple:Boolean,accept:String,onStart:Function,onProgress:Function,onSuccess:Function,onError:Function,beforeUpload:Function,drag:Boolean,onPreview:{type:Function,default:function(){}},onRemove:{type:Function,default:function(){}},fileList:Array,autoUpload:Boolean,listType:String,httpRequest:{type:Function,default:_h},disabled:Boolean,limit:Number,onExceed:Function},data:function(){return{mouseover:!1,reqs:{}}},methods:{isImage:function(e){return-1!==e.indexOf(\"image\")},handleChange:function(e){var t=e.target.files;t&&this.uploadFiles(t)},uploadFiles:function(e){var t=this;if(this.limit&&this.fileList.length+e.length>this.limit)this.onExceed&&this.onExceed(e,this.fileList);else{var i=Array.prototype.slice.call(e);this.multiple||(i=i.slice(0,1)),0!==i.length&&i.forEach(function(e){t.onStart(e),t.autoUpload&&t.upload(e)})}},upload:function(e){var t=this;if(this.$refs.input.value=null,!this.beforeUpload)return this.post(e);var i=this.beforeUpload(e);i&&i.then?i.then(function(i){var n=Object.prototype.toString.call(i);if(\"[object File]\"===n||\"[object Blob]\"===n){for(var s in\"[object Blob]\"===n&&(i=new File([i],e.name,{type:e.type})),e)e.hasOwnProperty(s)&&(i[s]=e[s]);t.post(i)}else t.post(e)},function(){t.onRemove(null,e)}):!1!==i?this.post(e):this.onRemove(null,e)},abort:function(e){var t=this.reqs;if(e){var i=e;e.uid&&(i=e.uid),t[i]&&t[i].abort()}else Object.keys(t).forEach(function(e){t[e]&&t[e].abort(),delete t[e]})},post:function(e){var t=this,i=e.uid,n={headers:this.headers,withCredentials:this.withCredentials,file:e,data:this.data,filename:this.name,action:this.action,onProgress:function(i){t.onProgress(i,e)},onSuccess:function(n){t.onSuccess(n,e),delete t.reqs[i]},onError:function(n){t.onError(n,e),delete t.reqs[i]}},s=this.httpRequest(n);this.reqs[i]=s,s&&s.then&&s.then(n.onSuccess,n.onError)},handleClick:function(){this.disabled||(this.$refs.input.value=null,this.$refs.input.click())},handleKeydown:function(e){e.target===e.currentTarget&&(13!==e.keyCode&&32!==e.keyCode||this.handleClick())}},render:function(e){var t=this.handleClick,i=this.drag,n=this.name,s=this.handleChange,r=this.multiple,o=this.accept,a=this.listType,l=this.uploadFiles,u=this.disabled,c=this.handleKeydown,h={class:{\"el-upload\":!0},on:{click:t,keydown:c}};return h.class[\"el-upload--\"+a]=!0,e(\"div\",gh()([h,{attrs:{tabindex:\"0\"}}]),[i?e(\"upload-dragger\",{attrs:{disabled:u},on:{file:l}},[this.$slots.default]):this.$slots.default,e(\"input\",{class:\"el-upload__input\",attrs:{type:\"file\",name:n,multiple:r,accept:o},ref:\"input\",on:{change:s}})])}},Oh=Th,Ih=a(Oh,$h,Dh,!1,null,null,null);Ih.options.__file=\"packages/upload/src/upload.vue\";var Ph=Ih.exports;function Mh(){}var Nh,Fh,Ah={name:\"ElUpload\",mixins:[$.a],components:{ElProgress:hh.a,UploadList:mh,Upload:Ph},provide:function(){return{uploader:this}},inject:{elForm:{default:\"\"}},props:{action:{type:String,required:!0},headers:{type:Object,default:function(){return{}}},data:Object,multiple:Boolean,name:{type:String,default:\"file\"},drag:Boolean,dragger:Boolean,withCredentials:Boolean,showFileList:{type:Boolean,default:!0},accept:String,type:{type:String,default:\"select\"},beforeUpload:Function,beforeRemove:Function,onRemove:{type:Function,default:Mh},onChange:{type:Function,default:Mh},onPreview:{type:Function},onSuccess:{type:Function,default:Mh},onProgress:{type:Function,default:Mh},onError:{type:Function,default:Mh},fileList:{type:Array,default:function(){return[]}},autoUpload:{type:Boolean,default:!0},listType:{type:String,default:\"text\"},httpRequest:Function,disabled:Boolean,limit:Number,onExceed:{type:Function,default:Mh}},data:function(){return{uploadFiles:[],dragOver:!1,draging:!1,tempIndex:1}},computed:{uploadDisabled:function(){return this.disabled||(this.elForm||{}).disabled}},watch:{listType:function(e){\"picture-card\"!==e&&\"picture\"!==e||(this.uploadFiles=this.uploadFiles.map(function(e){if(!e.url&&e.raw)try{e.url=URL.createObjectURL(e.raw)}catch(t){console.error(\"[Element Error][Upload]\",t)}return e}))},fileList:{immediate:!0,handler:function(e){var t=this;this.uploadFiles=e.map(function(e){return e.uid=e.uid||Date.now()+t.tempIndex++,e.status=e.status||\"success\",e})}}},methods:{handleStart:function(e){e.uid=Date.now()+this.tempIndex++;var t={status:\"ready\",name:e.name,size:e.size,percentage:0,uid:e.uid,raw:e};if(\"picture-card\"===this.listType||\"picture\"===this.listType)try{t.url=URL.createObjectURL(e)}catch(i){return void console.error(\"[Element Error][Upload]\",i)}this.uploadFiles.push(t),this.onChange(t,this.uploadFiles)},handleProgress:function(e,t){var i=this.getFile(t);this.onProgress(e,i,this.uploadFiles),i.status=\"uploading\",i.percentage=e.percent||0},handleSuccess:function(e,t){var i=this.getFile(t);i&&(i.status=\"success\",i.response=e,this.onSuccess(e,i,this.uploadFiles),this.onChange(i,this.uploadFiles))},handleError:function(e,t){var i=this.getFile(t),n=this.uploadFiles;i.status=\"fail\",n.splice(n.indexOf(i),1),this.onError(e,i,this.uploadFiles),this.onChange(i,this.uploadFiles)},handleRemove:function(e,t){var i=this;t&&(e=this.getFile(t));var n=function(){i.abort(e);var t=i.uploadFiles;t.splice(t.indexOf(e),1),i.onRemove(e,t)};if(this.beforeRemove){if(\"function\"===typeof this.beforeRemove){var s=this.beforeRemove(e,this.uploadFiles);s&&s.then?s.then(function(){n()},Mh):!1!==s&&n()}}else n()},getFile:function(e){var t=this.uploadFiles,i=void 0;return t.every(function(t){return i=e.uid===t.uid?t:null,!i}),i},abort:function(e){this.$refs[\"upload-inner\"].abort(e)},clearFiles:function(){this.uploadFiles=[]},submit:function(){var e=this;this.uploadFiles.filter(function(e){return\"ready\"===e.status}).forEach(function(t){e.$refs[\"upload-inner\"].upload(t.raw)})},getMigratingConfig:function(){return{props:{\"default-file-list\":\"default-file-list is renamed to file-list.\",\"show-upload-list\":\"show-upload-list is renamed to show-file-list.\",\"thumbnail-mode\":\"thumbnail-mode has been deprecated, you can implement the same effect according to this case: http://element.eleme.io/#/zh-CN/component/upload#yong-hu-tou-xiang-shang-chuan\"}}}},beforeDestroy:function(){this.uploadFiles.forEach(function(e){e.url&&0===e.url.indexOf(\"blob:\")&&URL.revokeObjectURL(e.url)})},render:function(e){var t=void 0;this.showFileList&&(t=e(mh,{attrs:{disabled:this.uploadDisabled,listType:this.listType,files:this.uploadFiles,handlePreview:this.onPreview},on:{remove:this.handleRemove}}));var i={props:{type:this.type,drag:this.drag,action:this.action,multiple:this.multiple,\"before-upload\":this.beforeUpload,\"with-credentials\":this.withCredentials,headers:this.headers,name:this.name,data:this.data,accept:this.accept,fileList:this.uploadFiles,autoUpload:this.autoUpload,listType:this.listType,disabled:this.uploadDisabled,limit:this.limit,\"on-exceed\":this.onExceed,\"on-start\":this.handleStart,\"on-progress\":this.handleProgress,\"on-success\":this.handleSuccess,\"on-error\":this.handleError,\"on-preview\":this.onPreview,\"on-remove\":this.handleRemove,\"http-request\":this.httpRequest},ref:\"upload-inner\"},n=this.$slots.trigger||this.$slots.default,s=e(\"upload\",i,[n]);return e(\"div\",[\"picture-card\"===this.listType?t:\"\",this.$slots.trigger?[s,this.$slots.default]:s,this.$slots.tip,\"picture-card\"!==this.listType?t:\"\"])}},Lh=Ah,Vh=a(Lh,Nh,Fh,!1,null,null,null);Vh.options.__file=\"packages/upload/src/index.vue\";var Bh=Vh.exports;Bh.install=function(e){e.component(Bh.name,Bh)};var zh=Bh,jh=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-progress\",class:[\"el-progress--\"+e.type,e.status?\"is-\"+e.status:\"\",{\"el-progress--without-text\":!e.showText,\"el-progress--text-inside\":e.textInside}],attrs:{role:\"progressbar\",\"aria-valuenow\":e.percentage,\"aria-valuemin\":\"0\",\"aria-valuemax\":\"100\"}},[\"line\"===e.type?i(\"div\",{staticClass:\"el-progress-bar\"},[i(\"div\",{staticClass:\"el-progress-bar__outer\",style:{height:e.strokeWidth+\"px\"}},[i(\"div\",{staticClass:\"el-progress-bar__inner\",style:e.barStyle},[e.showText&&e.textInside?i(\"div\",{staticClass:\"el-progress-bar__innerText\"},[e._v(e._s(e.percentage)+\"%\")]):e._e()])])]):i(\"div\",{staticClass:\"el-progress-circle\",style:{height:e.width+\"px\",width:e.width+\"px\"}},[i(\"svg\",{attrs:{viewBox:\"0 0 100 100\"}},[i(\"path\",{staticClass:\"el-progress-circle__track\",attrs:{d:e.trackPath,stroke:\"#e5e9f2\",\"stroke-width\":e.relativeStrokeWidth,fill:\"none\"}}),i(\"path\",{staticClass:\"el-progress-circle__path\",style:e.circlePathStyle,attrs:{d:e.trackPath,\"stroke-linecap\":\"round\",stroke:e.stroke,\"stroke-width\":e.relativeStrokeWidth,fill:\"none\"}})])]),e.showText&&!e.textInside?i(\"div\",{staticClass:\"el-progress__text\",style:{fontSize:e.progressTextSize+\"px\"}},[e.status?[\"text\"===e.status?e._t(\"default\"):i(\"i\",{class:e.iconClass})]:[e._v(e._s(e.percentage)+\"%\")]],2):e._e()])},Hh=[];jh._withStripped=!0;var Rh={name:\"ElProgress\",props:{type:{type:String,default:\"line\",validator:function(e){return[\"line\",\"circle\"].indexOf(e)>-1}},percentage:{type:Number,default:0,required:!0,validator:function(e){return e>=0&&e<=100}},status:{type:String,validator:function(e){return[\"text\",\"success\",\"exception\"].indexOf(e)>-1}},strokeWidth:{type:Number,default:6},textInside:{type:Boolean,default:!1},width:{type:Number,default:126},showText:{type:Boolean,default:!0},color:{type:String,default:\"\"}},computed:{barStyle:function(){var e={};return e.width=this.percentage+\"%\",e.backgroundColor=this.color,e},relativeStrokeWidth:function(){return(this.strokeWidth/this.width*100).toFixed(1)},trackPath:function(){var e=parseInt(50-parseFloat(this.relativeStrokeWidth)/2,10);return\"M 50 50 m 0 -\"+e+\" a \"+e+\" \"+e+\" 0 1 1 0 \"+2*e+\" a \"+e+\" \"+e+\" 0 1 1 0 -\"+2*e},perimeter:function(){var e=50-parseFloat(this.relativeStrokeWidth)/2;return 2*Math.PI*e},circlePathStyle:function(){var e=this.perimeter;return{strokeDasharray:e+\"px,\"+e+\"px\",strokeDashoffset:(1-this.percentage/100)*e+\"px\",transition:\"stroke-dashoffset 0.6s ease 0s, stroke 0.6s ease\"}},stroke:function(){var e=void 0;if(this.color)e=this.color;else switch(this.status){case\"success\":e=\"#13ce66\";break;case\"exception\":e=\"#ff4949\";break;default:e=\"#20a0ff\"}return e},iconClass:function(){return\"line\"===this.type?\"success\"===this.status?\"el-icon-circle-check\":\"el-icon-circle-close\":\"success\"===this.status?\"el-icon-check\":\"el-icon-close\"},progressTextSize:function(){return\"line\"===this.type?12+.4*this.strokeWidth:.111111*this.width+2}}},Wh=Rh,qh=a(Wh,jh,Hh,!1,null,null,null);qh.options.__file=\"packages/progress/src/progress.vue\";var Kh=qh.exports;Kh.install=function(e){e.component(Kh.name,Kh)};var Yh=Kh,Uh=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"span\",{staticClass:\"el-spinner\"},[i(\"svg\",{staticClass:\"el-spinner-inner\",style:{width:e.radius/2+\"px\",height:e.radius/2+\"px\"},attrs:{viewBox:\"0 0 50 50\"}},[i(\"circle\",{staticClass:\"path\",attrs:{cx:\"25\",cy:\"25\",r:\"20\",fill:\"none\",stroke:e.strokeColor,\"stroke-width\":e.strokeWidth}})])])},Gh=[];Uh._withStripped=!0;var Xh={name:\"ElSpinner\",props:{type:String,radius:{type:Number,default:100},strokeWidth:{type:Number,default:5},strokeColor:{type:String,default:\"#efefef\"}}},Qh=Xh,Jh=a(Qh,Uh,Gh,!1,null,null,null);Jh.options.__file=\"packages/spinner/src/spinner.vue\";var Zh=Jh.exports;Zh.install=function(e){e.component(Zh.name,Zh)};var ed=Zh,td=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"el-message-fade\"},on:{\"after-leave\":e.handleAfterLeave}},[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible,expression:\"visible\"}],class:[\"el-message\",e.type&&!e.iconClass?\"el-message--\"+e.type:\"\",e.center?\"is-center\":\"\",e.showClose?\"is-closable\":\"\",e.customClass],attrs:{role:\"alert\"},on:{mouseenter:e.clearTimer,mouseleave:e.startTimer}},[e.iconClass?i(\"i\",{class:e.iconClass}):i(\"i\",{class:e.typeClass}),e._t(\"default\",[e.dangerouslyUseHTMLString?i(\"p\",{staticClass:\"el-message__content\",domProps:{innerHTML:e._s(e.message)}}):i(\"p\",{staticClass:\"el-message__content\"},[e._v(e._s(e.message))])]),e.showClose?i(\"i\",{staticClass:\"el-message__closeBtn el-icon-close\",on:{click:e.close}}):e._e()],2)])},id=[];td._withStripped=!0;var nd={success:\"success\",info:\"info\",warning:\"warning\",error:\"error\"},sd={data:function(){return{visible:!1,message:\"\",duration:3e3,type:\"info\",iconClass:\"\",customClass:\"\",onClose:null,showClose:!1,closed:!1,timer:null,dangerouslyUseHTMLString:!1,center:!1}},computed:{typeClass:function(){return this.type&&!this.iconClass?\"el-message__icon el-icon-\"+nd[this.type]:\"\"}},watch:{closed:function(e){e&&(this.visible=!1)}},methods:{handleAfterLeave:function(){this.$destroy(!0),this.$el.parentNode.removeChild(this.$el)},close:function(){this.closed=!0,\"function\"===typeof this.onClose&&this.onClose(this)},clearTimer:function(){clearTimeout(this.timer)},startTimer:function(){var e=this;this.duration>0&&(this.timer=setTimeout(function(){e.closed||e.close()},this.duration))},keydown:function(e){27===e.keyCode&&(this.closed||this.close())}},mounted:function(){this.startTimer(),document.addEventListener(\"keydown\",this.keydown)},beforeDestroy:function(){document.removeEventListener(\"keydown\",this.keydown)}},rd=sd,od=a(rd,td,id,!1,null,null,null);od.options.__file=\"packages/message/src/main.vue\";var ad=od.exports,ld=Rn.a.extend(ad),ud=void 0,cd=[],hd=1,dd=function e(t){if(!Rn.a.prototype.$isServer){t=t||{},\"string\"===typeof t&&(t={message:t});var i=t.onClose,n=\"message_\"+hd++;return t.onClose=function(){e.close(n,i)},ud=new ld({data:t}),ud.id=n,Object(Wa[\"isVNode\"])(ud.message)&&(ud.$slots.default=[ud.message],ud.message=null),ud.vm=ud.$mount(),document.body.appendChild(ud.vm.$el),ud.vm.visible=!0,ud.dom=ud.vm.$el,ud.dom.style.zIndex=w[\"PopupManager\"].nextZIndex(),cd.push(ud),ud.vm}};[\"success\",\"warning\",\"info\",\"error\"].forEach(function(e){dd[e]=function(t){return\"string\"===typeof t&&(t={message:t}),t.type=e,dd(t)}}),dd.close=function(e,t){for(var i=0,n=cd.length;i<n;i++)if(e===cd[i].id){\"function\"===typeof t&&t(cd[i]),cd.splice(i,1);break}},dd.closeAll=function(){for(var e=cd.length-1;e>=0;e--)cd[e].close()};var pd=dd,fd=pd,md=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-badge\"},[e._t(\"default\"),i(\"transition\",{attrs:{name:\"el-zoom-in-center\"}},[i(\"sup\",{directives:[{name:\"show\",rawName:\"v-show\",value:!e.hidden&&(e.content||0===e.content||e.isDot),expression:\"!hidden && (content || content === 0 || isDot)\"}],staticClass:\"el-badge__content\",class:[\"el-badge__content--\"+e.type,{\"is-fixed\":e.$slots.default,\"is-dot\":e.isDot}],domProps:{textContent:e._s(e.content)}})])],2)},vd=[];md._withStripped=!0;var gd={name:\"ElBadge\",props:{value:{},max:Number,isDot:Boolean,hidden:Boolean,type:{type:String,validator:function(e){return[\"primary\",\"success\",\"warning\",\"info\",\"danger\"].indexOf(e)>-1}}},computed:{content:function(){if(!this.isDot){var e=this.value,t=this.max;return\"number\"===typeof e&&\"number\"===typeof t&&t<e?t+\"+\":e}}}},bd=gd,yd=a(bd,md,vd,!1,null,null,null);yd.options.__file=\"packages/badge/src/main.vue\";var _d=yd.exports;_d.install=function(e){e.component(_d.name,_d)};var xd=_d,Cd=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-card\",class:e.shadow?\"is-\"+e.shadow+\"-shadow\":\"is-always-shadow\"},[e.$slots.header||e.header?i(\"div\",{staticClass:\"el-card__header\"},[e._t(\"header\",[e._v(e._s(e.header))])],2):e._e(),i(\"div\",{staticClass:\"el-card__body\",style:e.bodyStyle},[e._t(\"default\")],2)])},wd=[];Cd._withStripped=!0;var kd={name:\"ElCard\",props:{header:{},bodyStyle:{},shadow:{type:String}}},Sd=kd,$d=a(Sd,Cd,wd,!1,null,null,null);$d.options.__file=\"packages/card/src/main.vue\";var Dd=$d.exports;Dd.install=function(e){e.component(Dd.name,Dd)};var Ed=Dd,Td=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-rate\",attrs:{role:\"slider\",\"aria-valuenow\":e.currentValue,\"aria-valuetext\":e.text,\"aria-valuemin\":\"0\",\"aria-valuemax\":e.max,tabindex:\"0\"},on:{keydown:e.handleKey}},[e._l(e.max,function(t,n){return i(\"span\",{key:n,staticClass:\"el-rate__item\",style:{cursor:e.rateDisabled?\"auto\":\"pointer\"},on:{mousemove:function(i){e.setCurrentValue(t,i)},mouseleave:e.resetCurrentValue,click:function(i){e.selectValue(t)}}},[i(\"i\",{staticClass:\"el-rate__icon\",class:[e.classes[t-1],{hover:e.hoverIndex===t}],style:e.getIconStyle(t)},[e.showDecimalIcon(t)?i(\"i\",{staticClass:\"el-rate__decimal\",class:e.decimalIconClass,style:e.decimalStyle}):e._e()])])}),e.showText||e.showScore?i(\"span\",{staticClass:\"el-rate__text\",style:{color:e.textColor}},[e._v(e._s(e.text))]):e._e()],2)},Od=[];Td._withStripped=!0;var Id={name:\"ElRate\",mixins:[$.a],inject:{elForm:{default:\"\"}},data:function(){return{pointerAtLeftHalf:!0,currentValue:this.value,hoverIndex:-1}},props:{value:{type:Number,default:0},lowThreshold:{type:Number,default:2},highThreshold:{type:Number,default:4},max:{type:Number,default:5},colors:{type:Array,default:function(){return[\"#F7BA2A\",\"#F7BA2A\",\"#F7BA2A\"]}},voidColor:{type:String,default:\"#C6D1DE\"},disabledVoidColor:{type:String,default:\"#EFF2F7\"},iconClasses:{type:Array,default:function(){return[\"el-icon-star-on\",\"el-icon-star-on\",\"el-icon-star-on\"]}},voidIconClass:{type:String,default:\"el-icon-star-off\"},disabledVoidIconClass:{type:String,default:\"el-icon-star-on\"},disabled:{type:Boolean,default:!1},allowHalf:{type:Boolean,default:!1},showText:{type:Boolean,default:!1},showScore:{type:Boolean,default:!1},textColor:{type:String,default:\"#1f2d3d\"},texts:{type:Array,default:function(){return[\"极差\",\"失望\",\"一般\",\"满意\",\"惊喜\"]}},scoreTemplate:{type:String,default:\"{value}\"}},computed:{text:function(){var e=\"\";return this.showScore?e=this.scoreTemplate.replace(/\\{\\s*value\\s*\\}/,this.rateDisabled?this.value:this.currentValue):this.showText&&(e=this.texts[Math.ceil(this.currentValue)-1]),e},decimalStyle:function(){var e=\"\";return this.rateDisabled&&(e=(this.valueDecimal<50?0:50)+\"%\"),this.allowHalf&&(e=\"50%\"),{color:this.activeColor,width:e}},valueDecimal:function(){return 100*this.value-100*Math.floor(this.value)},decimalIconClass:function(){return this.getValueFromMap(this.value,this.classMap)},voidClass:function(){return this.rateDisabled?this.classMap.disabledVoidClass:this.classMap.voidClass},activeClass:function(){return this.getValueFromMap(this.currentValue,this.classMap)},colorMap:function(){return{lowColor:this.colors[0],mediumColor:this.colors[1],highColor:this.colors[2],voidColor:this.voidColor,disabledVoidColor:this.disabledVoidColor}},activeColor:function(){return this.getValueFromMap(this.currentValue,this.colorMap)},classes:function(){var e=[],t=0,i=this.currentValue;for(this.allowHalf&&this.currentValue!==Math.floor(this.currentValue)&&i--;t<i;t++)e.push(this.activeClass);for(;t<this.max;t++)e.push(this.voidClass);return e},classMap:function(){return{lowClass:this.iconClasses[0],mediumClass:this.iconClasses[1],highClass:this.iconClasses[2],voidClass:this.voidIconClass,disabledVoidClass:this.disabledVoidIconClass}},rateDisabled:function(){return this.disabled||(this.elForm||{}).disabled}},watch:{value:function(e){this.currentValue=e,this.pointerAtLeftHalf=this.value!==Math.floor(this.value)}},methods:{getMigratingConfig:function(){return{props:{\"text-template\":\"text-template is renamed to score-template.\"}}},getValueFromMap:function(e,t){var i=\"\";return i=e<=this.lowThreshold?t.lowColor||t.lowClass:e>=this.highThreshold?t.highColor||t.highClass:t.mediumColor||t.mediumClass,i},showDecimalIcon:function(e){var t=this.rateDisabled&&this.valueDecimal>0&&e-1<this.value&&e>this.value,i=this.allowHalf&&this.pointerAtLeftHalf&&e-.5<=this.currentValue&&e>this.currentValue;return t||i},getIconStyle:function(e){var t=this.rateDisabled?this.colorMap.disabledVoidColor:this.colorMap.voidColor;return{color:e<=this.currentValue?this.activeColor:t}},selectValue:function(e){this.rateDisabled||(this.allowHalf&&this.pointerAtLeftHalf?(this.$emit(\"input\",this.currentValue),this.$emit(\"change\",this.currentValue)):(this.$emit(\"input\",e),this.$emit(\"change\",e)))},handleKey:function(e){if(!this.rateDisabled){var t=this.currentValue,i=e.keyCode;38===i||39===i?(this.allowHalf?t+=.5:t+=1,e.stopPropagation(),e.preventDefault()):37!==i&&40!==i||(this.allowHalf?t-=.5:t-=1,e.stopPropagation(),e.preventDefault()),t=t<0?0:t,t=t>this.max?this.max:t,this.$emit(\"input\",t),this.$emit(\"change\",t)}},setCurrentValue:function(e,t){if(!this.rateDisabled){if(this.allowHalf){var i=t.target;Object(Ve[\"hasClass\"])(i,\"el-rate__item\")&&(i=i.querySelector(\".el-rate__icon\")),Object(Ve[\"hasClass\"])(i,\"el-rate__decimal\")&&(i=i.parentNode),this.pointerAtLeftHalf=2*t.offsetX<=i.clientWidth,this.currentValue=this.pointerAtLeftHalf?e-.5:e}else this.currentValue=e;this.hoverIndex=e}},resetCurrentValue:function(){this.rateDisabled||(this.allowHalf&&(this.pointerAtLeftHalf=this.value!==Math.floor(this.value)),this.currentValue=this.value,this.hoverIndex=-1)}},created:function(){this.value||this.$emit(\"input\",0)}},Pd=Id,Md=a(Pd,Td,Od,!1,null,null,null);Md.options.__file=\"packages/rate/src/main.vue\";var Nd=Md.exports;Nd.install=function(e){e.component(Nd.name,Nd)};var Fd=Nd,Ad=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-steps\",class:[!e.simple&&\"el-steps--\"+e.direction,e.simple&&\"el-steps--simple\"]},[e._t(\"default\")],2)},Ld=[];Ad._withStripped=!0;var Vd={name:\"ElSteps\",mixins:[$.a],props:{space:[Number,String],active:Number,direction:{type:String,default:\"horizontal\"},alignCenter:Boolean,simple:Boolean,finishStatus:{type:String,default:\"finish\"},processStatus:{type:String,default:\"process\"}},data:function(){return{steps:[],stepOffset:0}},methods:{getMigratingConfig:function(){return{props:{center:\"center is removed.\"}}}},watch:{active:function(e,t){this.$emit(\"change\",e,t)},steps:function(e){e.forEach(function(e,t){e.index=t})}}},Bd=Vd,zd=a(Bd,Ad,Ld,!1,null,null,null);zd.options.__file=\"packages/steps/src/steps.vue\";var jd=zd.exports;jd.install=function(e){e.component(jd.name,jd)};var Hd=jd,Rd=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-step\",class:[!e.isSimple&&\"is-\"+e.$parent.direction,e.isSimple&&\"is-simple\",e.isLast&&!e.space&&!e.isCenter&&\"is-flex\",e.isCenter&&!e.isVertical&&!e.isSimple&&\"is-center\"],style:e.style},[i(\"div\",{staticClass:\"el-step__head\",class:\"is-\"+e.currentStatus},[i(\"div\",{staticClass:\"el-step__line\",style:e.isLast?\"\":{marginRight:e.$parent.stepOffset+\"px\"}},[i(\"i\",{staticClass:\"el-step__line-inner\",style:e.lineStyle})]),i(\"div\",{staticClass:\"el-step__icon\",class:\"is-\"+(e.icon?\"icon\":\"text\")},[\"success\"!==e.currentStatus&&\"error\"!==e.currentStatus?e._t(\"icon\",[e.icon?i(\"i\",{staticClass:\"el-step__icon-inner\",class:[e.icon]}):e._e(),e.icon||e.isSimple?e._e():i(\"div\",{staticClass:\"el-step__icon-inner\"},[e._v(e._s(e.index+1))])]):i(\"i\",{staticClass:\"el-step__icon-inner is-status\",class:[\"el-icon-\"+(\"success\"===e.currentStatus?\"check\":\"close\")]})],2)]),i(\"div\",{staticClass:\"el-step__main\"},[i(\"div\",{ref:\"title\",staticClass:\"el-step__title\",class:[\"is-\"+e.currentStatus]},[e._t(\"title\",[e._v(e._s(e.title))])],2),e.isSimple?i(\"div\",{staticClass:\"el-step__arrow\"}):i(\"div\",{staticClass:\"el-step__description\",class:[\"is-\"+e.currentStatus]},[e._t(\"description\",[e._v(e._s(e.description))])],2)])])},Wd=[];Rd._withStripped=!0;var qd={name:\"ElStep\",props:{title:String,icon:String,description:String,status:String},data:function(){return{index:-1,lineStyle:{},internalStatus:\"\"}},beforeCreate:function(){this.$parent.steps.push(this)},beforeDestroy:function(){var e=this.$parent.steps,t=e.indexOf(this);t>=0&&e.splice(t,1)},computed:{currentStatus:function(){return this.status||this.internalStatus},prevStatus:function(){var e=this.$parent.steps[this.index-1];return e?e.currentStatus:\"wait\"},isCenter:function(){return this.$parent.alignCenter},isVertical:function(){return\"vertical\"===this.$parent.direction},isSimple:function(){return this.$parent.simple},isLast:function(){var e=this.$parent;return e.steps[e.steps.length-1]===this},stepsCount:function(){return this.$parent.steps.length},space:function(){var e=this.isSimple,t=this.$parent.space;return e?\"\":t},style:function(){var e={},t=this.$parent,i=t.steps.length,n=\"number\"===typeof this.space?this.space+\"px\":this.space?this.space:100/(i-(this.isCenter?0:1))+\"%\";return e.flexBasis=n,this.isVertical?e:(this.isLast?e.maxWidth=100/this.stepsCount+\"%\":e.marginRight=-this.$parent.stepOffset+\"px\",e)}},methods:{updateStatus:function(e){var t=this.$parent.$children[this.index-1];e>this.index?this.internalStatus=this.$parent.finishStatus:e===this.index&&\"error\"!==this.prevStatus?this.internalStatus=this.$parent.processStatus:this.internalStatus=\"wait\",t&&t.calcProgress(this.internalStatus)},calcProgress:function(e){var t=100,i={};i.transitionDelay=150*this.index+\"ms\",e===this.$parent.processStatus?(this.currentStatus,t=0):\"wait\"===e&&(t=0,i.transitionDelay=-150*this.index+\"ms\"),i.borderWidth=t&&!this.isSimple?\"1px\":0,\"vertical\"===this.$parent.direction?i.height=t+\"%\":i.width=t+\"%\",this.lineStyle=i}},mounted:function(){var e=this,t=this.$watch(\"index\",function(i){e.$watch(\"$parent.active\",e.updateStatus,{immediate:!0}),e.$watch(\"$parent.processStatus\",function(){var t=e.$parent.active;e.updateStatus(t)},{immediate:!0}),t()})}},Kd=qd,Yd=a(Kd,Rd,Wd,!1,null,null,null);Yd.options.__file=\"packages/steps/src/step.vue\";var Ud=Yd.exports;Ud.install=function(e){e.component(Ud.name,Ud)};var Gd=Ud,Xd=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-carousel\",class:{\"el-carousel--card\":\"card\"===e.type},on:{mouseenter:function(t){return t.stopPropagation(),e.handleMouseEnter(t)},mouseleave:function(t){return t.stopPropagation(),e.handleMouseLeave(t)}}},[i(\"div\",{staticClass:\"el-carousel__container\",style:{height:e.height}},[i(\"transition\",{attrs:{name:\"carousel-arrow-left\"}},[\"never\"!==e.arrow?i(\"button\",{directives:[{name:\"show\",rawName:\"v-show\",value:(\"always\"===e.arrow||e.hover)&&(e.loop||e.activeIndex>0),expression:\"(arrow === 'always' || hover) && (loop || activeIndex > 0)\"}],staticClass:\"el-carousel__arrow el-carousel__arrow--left\",attrs:{type:\"button\"},on:{mouseenter:function(t){e.handleButtonEnter(\"left\")},mouseleave:e.handleButtonLeave,click:function(t){t.stopPropagation(),e.throttledArrowClick(e.activeIndex-1)}}},[i(\"i\",{staticClass:\"el-icon-arrow-left\"})]):e._e()]),i(\"transition\",{attrs:{name:\"carousel-arrow-right\"}},[\"never\"!==e.arrow?i(\"button\",{directives:[{name:\"show\",rawName:\"v-show\",value:(\"always\"===e.arrow||e.hover)&&(e.loop||e.activeIndex<e.items.length-1),expression:\"(arrow === 'always' || hover) && (loop || activeIndex < items.length - 1)\"}],staticClass:\"el-carousel__arrow el-carousel__arrow--right\",attrs:{type:\"button\"},on:{mouseenter:function(t){e.handleButtonEnter(\"right\")},mouseleave:e.handleButtonLeave,click:function(t){t.stopPropagation(),e.throttledArrowClick(e.activeIndex+1)}}},[i(\"i\",{staticClass:\"el-icon-arrow-right\"})]):e._e()]),e._t(\"default\")],2),\"none\"!==e.indicatorPosition?i(\"ul\",{staticClass:\"el-carousel__indicators\",class:{\"el-carousel__indicators--labels\":e.hasLabel,\"el-carousel__indicators--outside\":\"outside\"===e.indicatorPosition||\"card\"===e.type}},e._l(e.items,function(t,n){return i(\"li\",{staticClass:\"el-carousel__indicator\",class:{\"is-active\":n===e.activeIndex},on:{mouseenter:function(t){e.throttledIndicatorHover(n)},click:function(t){t.stopPropagation(),e.handleIndicatorClick(n)}}},[i(\"button\",{staticClass:\"el-carousel__button\"},[e.hasLabel?i(\"span\",[e._v(e._s(t.label))]):e._e()])])}),0):e._e()])},Qd=[];Xd._withStripped=!0;var Jd=i(30),Zd=i.n(Jd),ep={name:\"ElCarousel\",props:{initialIndex:{type:Number,default:0},height:String,trigger:{type:String,default:\"hover\"},autoplay:{type:Boolean,default:!0},interval:{type:Number,default:3e3},indicatorPosition:String,indicator:{type:Boolean,default:!0},arrow:{type:String,default:\"hover\"},type:String,loop:{type:Boolean,default:!0}},data:function(){return{items:[],activeIndex:-1,containerWidth:0,timer:null,hover:!1}},computed:{hasLabel:function(){return this.items.some(function(e){return e.label.toString().length>0})}},watch:{items:function(e){e.length>0&&this.setActiveItem(this.initialIndex)},activeIndex:function(e,t){this.resetItemPosition(t),this.$emit(\"change\",e,t)},autoplay:function(e){e?this.startTimer():this.pauseTimer()},loop:function(){this.setActiveItem(this.activeIndex)}},methods:{handleMouseEnter:function(){this.hover=!0,this.pauseTimer()},handleMouseLeave:function(){this.hover=!1,this.startTimer()},itemInStage:function(e,t){var i=this.items.length;return t===i-1&&e.inStage&&this.items[0].active||e.inStage&&this.items[t+1]&&this.items[t+1].active?\"left\":!!(0===t&&e.inStage&&this.items[i-1].active||e.inStage&&this.items[t-1]&&this.items[t-1].active)&&\"right\"},handleButtonEnter:function(e){var t=this;this.items.forEach(function(i,n){e===t.itemInStage(i,n)&&(i.hover=!0)})},handleButtonLeave:function(){this.items.forEach(function(e){e.hover=!1})},updateItems:function(){this.items=this.$children.filter(function(e){return\"ElCarouselItem\"===e.$options.name})},resetItemPosition:function(e){var t=this;this.items.forEach(function(i,n){i.translateItem(n,t.activeIndex,e)})},playSlides:function(){this.activeIndex<this.items.length-1?this.activeIndex++:this.loop&&(this.activeIndex=0)},pauseTimer:function(){this.timer&&(clearInterval(this.timer),this.timer=null)},startTimer:function(){this.interval<=0||!this.autoplay||this.timer||(this.timer=setInterval(this.playSlides,this.interval))},setActiveItem:function(e){if(\"string\"===typeof e){var t=this.items.filter(function(t){return t.name===e});t.length>0&&(e=this.items.indexOf(t[0]))}if(e=Number(e),!isNaN(e)&&e===Math.floor(e)){var i=this.items.length,n=this.activeIndex;this.activeIndex=e<0?this.loop?i-1:0:e>=i?this.loop?0:i-1:e,n===this.activeIndex&&this.resetItemPosition(n)}},prev:function(){this.setActiveItem(this.activeIndex-1)},next:function(){this.setActiveItem(this.activeIndex+1)},handleIndicatorClick:function(e){this.activeIndex=e},handleIndicatorHover:function(e){\"hover\"===this.trigger&&e!==this.activeIndex&&(this.activeIndex=e)}},created:function(){var e=this;this.throttledArrowClick=Zd()(300,!0,function(t){e.setActiveItem(t)}),this.throttledIndicatorHover=Zd()(300,function(t){e.handleIndicatorHover(t)})},mounted:function(){var e=this;this.updateItems(),this.$nextTick(function(){Object(Ji[\"addResizeListener\"])(e.$el,e.resetItemPosition),e.initialIndex<e.items.length&&e.initialIndex>=0&&(e.activeIndex=e.initialIndex),e.startTimer()})},beforeDestroy:function(){this.$el&&Object(Ji[\"removeResizeListener\"])(this.$el,this.resetItemPosition),this.pauseTimer()}},tp=ep,ip=a(tp,Xd,Qd,!1,null,null,null);ip.options.__file=\"packages/carousel/src/main.vue\";var np=ip.exports;np.install=function(e){e.component(np.name,np)};var sp=np,rp={vertical:{offset:\"offsetHeight\",scroll:\"scrollTop\",scrollSize:\"scrollHeight\",size:\"height\",key:\"vertical\",axis:\"Y\",client:\"clientY\",direction:\"top\"},horizontal:{offset:\"offsetWidth\",scroll:\"scrollLeft\",scrollSize:\"scrollWidth\",size:\"width\",key:\"horizontal\",axis:\"X\",client:\"clientX\",direction:\"left\"}};function op(e){var t=e.move,i=e.size,n=e.bar,s={},r=\"translate\"+n.axis+\"(\"+t+\"%)\";return s[n.size]=i,s.transform=r,s.msTransform=r,s.webkitTransform=r,s}var ap={name:\"Bar\",props:{vertical:Boolean,size:String,move:Number},computed:{bar:function(){return rp[this.vertical?\"vertical\":\"horizontal\"]},wrap:function(){return this.$parent.wrap}},render:function(e){var t=this.size,i=this.move,n=this.bar;return e(\"div\",{class:[\"el-scrollbar__bar\",\"is-\"+n.key],on:{mousedown:this.clickTrackHandler}},[e(\"div\",{ref:\"thumb\",class:\"el-scrollbar__thumb\",on:{mousedown:this.clickThumbHandler},style:op({size:t,move:i,bar:n})})])},methods:{clickThumbHandler:function(e){e.ctrlKey||2===e.button||(this.startDrag(e),this[this.bar.axis]=e.currentTarget[this.bar.offset]-(e[this.bar.client]-e.currentTarget.getBoundingClientRect()[this.bar.direction]))},clickTrackHandler:function(e){var t=Math.abs(e.target.getBoundingClientRect()[this.bar.direction]-e[this.bar.client]),i=this.$refs.thumb[this.bar.offset]/2,n=100*(t-i)/this.$el[this.bar.offset];this.wrap[this.bar.scroll]=n*this.wrap[this.bar.scrollSize]/100},startDrag:function(e){e.stopImmediatePropagation(),this.cursorDown=!0,Object(Ve[\"on\"])(document,\"mousemove\",this.mouseMoveDocumentHandler),Object(Ve[\"on\"])(document,\"mouseup\",this.mouseUpDocumentHandler),document.onselectstart=function(){return!1}},mouseMoveDocumentHandler:function(e){if(!1!==this.cursorDown){var t=this[this.bar.axis];if(t){var i=-1*(this.$el.getBoundingClientRect()[this.bar.direction]-e[this.bar.client]),n=this.$refs.thumb[this.bar.offset]-t,s=100*(i-n)/this.$el[this.bar.offset];this.wrap[this.bar.scroll]=s*this.wrap[this.bar.scrollSize]/100}}},mouseUpDocumentHandler:function(e){this.cursorDown=!1,this[this.bar.axis]=0,Object(Ve[\"off\"])(document,\"mousemove\",this.mouseMoveDocumentHandler),document.onselectstart=null}},destroyed:function(){Object(Ve[\"off\"])(document,\"mouseup\",this.mouseUpDocumentHandler)}},lp={name:\"ElScrollbar\",components:{Bar:ap},props:{native:Boolean,wrapStyle:{},wrapClass:{},viewClass:{},viewStyle:{},noresize:Boolean,tag:{type:String,default:\"div\"}},data:function(){return{sizeWidth:\"0\",sizeHeight:\"0\",moveX:0,moveY:0}},computed:{wrap:function(){return this.$refs.wrap}},render:function(e){var t=os()(),i=this.wrapStyle;if(t){var n=\"-\"+t+\"px\",s=\"margin-bottom: \"+n+\"; margin-right: \"+n+\";\";Array.isArray(this.wrapStyle)?(i=Object(b[\"toObject\"])(this.wrapStyle),i.marginRight=i.marginBottom=n):\"string\"===typeof this.wrapStyle?i+=s:i=s}var r=e(this.tag,{class:[\"el-scrollbar__view\",this.viewClass],style:this.viewStyle,ref:\"resize\"},this.$slots.default),o=e(\"div\",{ref:\"wrap\",style:i,on:{scroll:this.handleScroll},class:[this.wrapClass,\"el-scrollbar__wrap\",t?\"\":\"el-scrollbar__wrap--hidden-default\"]},[[r]]),a=void 0;return a=this.native?[e(\"div\",{ref:\"wrap\",class:[this.wrapClass,\"el-scrollbar__wrap\"],style:i},[[r]])]:[o,e(ap,{attrs:{move:this.moveX,size:this.sizeWidth}}),e(ap,{attrs:{vertical:!0,move:this.moveY,size:this.sizeHeight}})],e(\"div\",{class:\"el-scrollbar\"},a)},methods:{handleScroll:function(){var e=this.wrap;this.moveY=100*e.scrollTop/e.clientHeight,this.moveX=100*e.scrollLeft/e.clientWidth},update:function(){var e=void 0,t=void 0,i=this.wrap;i&&(e=100*i.clientHeight/i.scrollHeight,t=100*i.clientWidth/i.scrollWidth,this.sizeHeight=e<100?e+\"%\":\"\",this.sizeWidth=t<100?t+\"%\":\"\")}},mounted:function(){this.native||(this.$nextTick(this.update),!this.noresize&&Object(Ji[\"addResizeListener\"])(this.$refs.resize,this.update))},beforeDestroy:function(){this.native||!this.noresize&&Object(Ji[\"removeResizeListener\"])(this.$refs.resize,this.update)},install:function(e){e.component(lp.name,lp)}},up=lp,cp=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.ready,expression:\"ready\"}],staticClass:\"el-carousel__item\",class:{\"is-active\":e.active,\"el-carousel__item--card\":\"card\"===e.$parent.type,\"is-in-stage\":e.inStage,\"is-hover\":e.hover,\"is-animating\":e.animating},style:{msTransform:\"translateX(\"+e.translate+\"px) scale(\"+e.scale+\")\",webkitTransform:\"translateX(\"+e.translate+\"px) scale(\"+e.scale+\")\",transform:\"translateX(\"+e.translate+\"px) scale(\"+e.scale+\")\"},on:{click:e.handleItemClick}},[\"card\"===e.$parent.type?i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:!e.active,expression:\"!active\"}],staticClass:\"el-carousel__mask\"}):e._e(),e._t(\"default\")],2)},hp=[];cp._withStripped=!0;var dp=.83,pp={name:\"ElCarouselItem\",props:{name:String,label:{type:[String,Number],default:\"\"}},data:function(){return{hover:!1,translate:0,scale:1,active:!1,ready:!1,inStage:!1,animating:!1}},methods:{processIndex:function(e,t,i){return 0===t&&e===i-1?-1:t===i-1&&0===e?i:e<t-1&&t-e>=i/2?i+1:e>t+1&&e-t>=i/2?-2:e},calculateTranslate:function(e,t,i){return this.inStage?i*((2-dp)*(e-t)+1)/4:e<t?-(1+dp)*i/4:(3+dp)*i/4},translateItem:function(e,t,i){var n=this.$parent.$el.offsetWidth,s=this.$parent.items.length;\"card\"!==this.$parent.type&&void 0!==i&&(this.animating=e===t||e===i),e!==t&&s>2&&this.$parent.loop&&(e=this.processIndex(e,t,s)),\"card\"===this.$parent.type?(this.inStage=Math.round(Math.abs(e-t))<=1,this.active=e===t,this.translate=this.calculateTranslate(e,t,n),this.scale=this.active?1:dp):(this.active=e===t,this.translate=n*(e-t)),this.ready=!0},handleItemClick:function(){var e=this.$parent;if(e&&\"card\"===e.type){var t=e.items.indexOf(this);e.setActiveItem(t)}}},created:function(){this.$parent&&this.$parent.updateItems()},destroyed:function(){this.$parent&&this.$parent.updateItems()}},fp=pp,mp=a(fp,cp,hp,!1,null,null,null);mp.options.__file=\"packages/carousel/src/item.vue\";var vp=mp.exports;vp.install=function(e){e.component(vp.name,vp)};var gp=vp,bp=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-collapse\",attrs:{role:\"tablist\",\"aria-multiselectable\":\"true\"}},[e._t(\"default\")],2)},yp=[];bp._withStripped=!0;var _p={name:\"ElCollapse\",componentName:\"ElCollapse\",props:{accordion:Boolean,value:{type:[Array,String,Number],default:function(){return[]}}},data:function(){return{activeNames:[].concat(this.value)}},provide:function(){return{collapse:this}},watch:{value:function(e){this.activeNames=[].concat(e)}},methods:{setActiveNames:function(e){e=[].concat(e);var t=this.accordion?e[0]:e;this.activeNames=e,this.$emit(\"input\",t),this.$emit(\"change\",t)},handleItemClick:function(e){if(this.accordion)this.setActiveNames(!this.activeNames[0]&&0!==this.activeNames[0]||this.activeNames[0]!==e.name?e.name:\"\");else{var t=this.activeNames.slice(0),i=t.indexOf(e.name);i>-1?t.splice(i,1):t.push(e.name),this.setActiveNames(t)}}},created:function(){this.$on(\"item-click\",this.handleItemClick)}},xp=_p,Cp=a(xp,bp,yp,!1,null,null,null);Cp.options.__file=\"packages/collapse/src/collapse.vue\";var wp=Cp.exports;wp.install=function(e){e.component(wp.name,wp)};var kp=wp,Sp=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-collapse-item\",class:{\"is-active\":e.isActive}},[i(\"div\",{attrs:{role:\"tab\",\"aria-expanded\":e.isActive,\"aria-controls\":\"el-collapse-content-\"+e.id,\"aria-describedby\":\"el-collapse-content-\"+e.id}},[i(\"div\",{staticClass:\"el-collapse-item__header\",class:{focusing:e.focusing,\"is-active\":e.isActive},attrs:{role:\"button\",id:\"el-collapse-head-\"+e.id,tabindex:\"0\"},on:{click:e.handleHeaderClick,keyup:function(t){return\"button\"in t||!e._k(t.keyCode,\"space\",32,t.key,[\" \",\"Spacebar\"])||!e._k(t.keyCode,\"enter\",13,t.key,\"Enter\")?(t.stopPropagation(),e.handleEnterClick(t)):null},focus:e.handleFocus,blur:function(t){e.focusing=!1}}},[e._t(\"title\",[e._v(e._s(e.title))]),i(\"i\",{staticClass:\"el-collapse-item__arrow el-icon-arrow-right\",class:{\"is-active\":e.isActive}})],2)]),i(\"el-collapse-transition\",[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.isActive,expression:\"isActive\"}],staticClass:\"el-collapse-item__wrap\",attrs:{role:\"tabpanel\",\"aria-hidden\":!e.isActive,\"aria-labelledby\":\"el-collapse-head-\"+e.id,id:\"el-collapse-content-\"+e.id}},[i(\"div\",{staticClass:\"el-collapse-item__content\"},[e._t(\"default\")],2)])])],1)},$p=[];Sp._withStripped=!0;var Dp={name:\"ElCollapseItem\",componentName:\"ElCollapseItem\",mixins:[E.a],components:{ElCollapseTransition:Ye.a},data:function(){return{contentWrapStyle:{height:\"auto\",display:\"block\"},contentHeight:0,focusing:!1,isClick:!1}},inject:[\"collapse\"],props:{title:String,name:{type:[String,Number],default:function(){return this._uid}}},computed:{isActive:function(){return this.collapse.activeNames.indexOf(this.name)>-1},id:function(){return Object(b[\"generateId\"])()}},methods:{handleFocus:function(){var e=this;setTimeout(function(){e.isClick?e.isClick=!1:e.focusing=!0},50)},handleHeaderClick:function(){this.dispatch(\"ElCollapse\",\"item-click\",this),this.focusing=!1,this.isClick=!0},handleEnterClick:function(){this.dispatch(\"ElCollapse\",\"item-click\",this)}}},Ep=Dp,Tp=a(Ep,Sp,$p,!1,null,null,null);Tp.options.__file=\"packages/collapse/src/collapse-item.vue\";var Op=Tp.exports;Op.install=function(e){e.component(Op.name,Op)};var Ip=Op,Pp=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"span\",{directives:[{name:\"clickoutside\",rawName:\"v-clickoutside\",value:e.handleClickoutside,expression:\"handleClickoutside\"}],ref:\"reference\",staticClass:\"el-cascader\",class:[{\"is-opened\":e.menuVisible,\"is-disabled\":e.cascaderDisabled},e.cascaderSize?\"el-cascader--\"+e.cascaderSize:\"\"],on:{click:e.handleClick,mouseenter:function(t){e.inputHover=!0},focus:function(t){e.inputHover=!0},mouseleave:function(t){e.inputHover=!1},blur:function(t){e.inputHover=!1},keydown:e.handleKeydown}},[i(\"el-input\",{ref:\"input\",class:{\"is-focus\":e.menuVisible},attrs:{readonly:e.readonly,placeholder:e.currentLabels.length?void 0:e.placeholder,\"validate-event\":!1,size:e.size,disabled:e.cascaderDisabled},on:{input:e.debouncedInputChange,focus:e.handleFocus,blur:e.handleBlur},nativeOn:{compositionstart:function(t){return e.handleComposition(t)},compositionend:function(t){return e.handleComposition(t)}},model:{value:e.inputValue,callback:function(t){e.inputValue=t},expression:\"inputValue\"}},[i(\"template\",{slot:\"suffix\"},[e.clearable&&e.inputHover&&e.currentLabels.length?i(\"i\",{key:\"1\",staticClass:\"el-input__icon el-icon-circle-close el-cascader__clearIcon\",on:{click:e.clearValue}}):i(\"i\",{key:\"2\",staticClass:\"el-input__icon el-icon-arrow-down\",class:{\"is-reverse\":e.menuVisible}})])],2),i(\"span\",{directives:[{name:\"show\",rawName:\"v-show\",value:\"\"===e.inputValue&&!e.isOnComposition,expression:\"inputValue === '' && !isOnComposition\"}],staticClass:\"el-cascader__label\"},[e.showAllLevels?[e._l(e.currentLabels,function(t,n){return[e._v(\"\\n        \"+e._s(t)+\"\\n        \"),n<e.currentLabels.length-1?i(\"span\",{key:n},[e._v(\" \"+e._s(e.separator)+\" \")]):e._e()]})]:[e._v(\"\\n      \"+e._s(e.currentLabels[e.currentLabels.length-1])+\"\\n    \")]],2)],1)},Mp=[];Pp._withStripped=!0;var Np,Fp,Ap=function e(t,i){if(!t||!Array.isArray(t)||!i)return t;var n=[],s=[\"__IS__FLAT__OPTIONS\",\"label\",\"value\",\"disabled\"],r=i.children||\"children\";return t.forEach(function(t){var o={};s.forEach(function(e){var n=i[e],s=t[n];void 0===s&&(n=e,s=t[n]),void 0!==s&&(o[n]=s)}),Array.isArray(t[r])&&(o[r]=e(t[r],i)),n.push(o)}),n},Lp={name:\"ElCascaderMenu\",data:function(){return{inputWidth:0,options:[],props:{},visible:!1,activeValue:[],value:[],expandTrigger:\"click\",changeOnSelect:!1,popperClass:\"\",hoverTimer:0,clicking:!1,id:Object(b[\"generateId\"])()}},watch:{visible:function(e){e&&(this.activeValue=this.value)},value:{immediate:!0,handler:function(e){this.activeValue=e}}},computed:{activeOptions:{get:function(){var e=this,t=this.activeValue,i=[\"label\",\"value\",\"children\",\"disabled\"],n=function t(n){n.forEach(function(n){n.__IS__FLAT__OPTIONS||(i.forEach(function(t){var i=n[e.props[t]||t];void 0!==i&&(n[t]=i)}),Array.isArray(n.children)&&t(n.children))})},s=function e(i){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],s=n.length;n[s]=i;var r=t[s];return Object(rn[\"isDef\"])(r)&&(i=i.filter(function(e){return e.value===r})[0],i&&i.children&&e(i.children,n)),n},r=Ap(this.options,this.props);return n(r),s(r)}}},methods:{select:function(e,t){e.__IS__FLAT__OPTIONS?this.activeValue=e.value:t?this.activeValue.splice(t,this.activeValue.length-1,e.value):this.activeValue=[e.value],this.$emit(\"pick\",this.activeValue.slice())},handleMenuLeave:function(){this.$emit(\"menuLeave\")},activeItem:function(e,t){var i=this.activeOptions.length;this.activeValue.splice(t,i,e.value),this.activeOptions.splice(t+1,i,e.children),this.changeOnSelect?this.$emit(\"pick\",this.activeValue.slice(),!1):this.$emit(\"activeItemChange\",this.activeValue)},scrollMenu:function(e){nn()(e,e.getElementsByClassName(\"is-active\")[0])},handleMenuEnter:function(){var e=this;this.$nextTick(function(){return e.$refs.menus.forEach(function(t){return e.scrollMenu(t)})})}},render:function(e){var t=this,i=this.activeValue,n=this.activeOptions,s=this.visible,r=this.expandTrigger,o=this.popperClass,a=this.hoverThreshold,l=null,u=0,c={},h=function(e){var i=c.activeMenu;if(i){var n=e.offsetX,s=i.offsetWidth,r=i.offsetHeight;if(e.target===c.activeItem){clearTimeout(t.hoverTimer);var o=c,l=o.activeItem,u=l.offsetTop,h=u+l.offsetHeight;c.hoverZone.innerHTML='\\n          <path style=\"pointer-events: auto;\" fill=\"transparent\" d=\"M'+n+\" \"+u+\" L\"+s+\" 0 V\"+u+' Z\" />\\n          <path style=\"pointer-events: auto;\" fill=\"transparent\" d=\"M'+n+\" \"+h+\" L\"+s+\" \"+r+\" V\"+h+' Z\" />\\n        '}else t.hoverTimer||(t.hoverTimer=setTimeout(function(){c.hoverZone.innerHTML=\"\"},a))}},d=this._l(n,function(n,s){var o=!1,a=\"menu-\"+t.id+\"-\"+s,c=\"menu-\"+t.id+\"-\"+(s+1),d=t._l(n,function(n){var h={on:{}};if(n.__IS__FLAT__OPTIONS&&(o=!0),!n.disabled)if(h.on.keydown=function(e){var i=e.keyCode;if(!([37,38,39,40,13,9,27].indexOf(i)<0)){var r=e.target,o=t.$refs.menus[s],a=o.querySelectorAll(\"[tabindex='-1']\"),l=Array.prototype.indexOf.call(a,r),u=void 0,c=void 0;if([38,40].indexOf(i)>-1)38===i?u=0!==l?l-1:l:40===i&&(u=l!==a.length-1?l+1:l),a[u].focus();else if(37===i){if(0!==s){var h=t.$refs.menus[s-1];h.querySelector(\"[aria-expanded=true]\").focus()}}else if(39===i)n.children&&(c=t.$refs.menus[s+1],c.querySelectorAll(\"[tabindex='-1']\")[0].focus());else if(13===i){if(!n.children){var d=r.getAttribute(\"id\");o.setAttribute(\"aria-activedescendant\",d),t.select(n,s),t.$nextTick(function(){return t.scrollMenu(t.$refs.menus[s])})}}else 9!==i&&27!==i||t.$emit(\"closeInside\")}},n.children){var d={click:\"click\",hover:\"mouseenter\"}[r],p=function(){t.visible&&(t.activeItem(n,s),t.$nextTick(function(){t.scrollMenu(t.$refs.menus[s]),t.scrollMenu(t.$refs.menus[s+1])}))};h.on[d]=p,\"mouseenter\"===d&&t.changeOnSelect&&(h.on.click=function(){-1!==t.activeValue.indexOf(n.value)&&t.$emit(\"closeInside\",!0)}),h.on[\"mousedown\"]=function(){t.clicking=!0},h.on[\"focus\"]=function(){t.clicking?t.clicking=!1:p()}}else h.on.click=function(){t.select(n,s),t.$nextTick(function(){return t.scrollMenu(t.$refs.menus[s])})};return n.disabled||n.children||(l=a+\"-\"+u,u++),e(\"li\",gh()([{class:{\"el-cascader-menu__item\":!0,\"el-cascader-menu__item--extensible\":n.children,\"is-active\":n.value===i[s],\"is-disabled\":n.disabled},ref:n.value===i[s]?\"activeItem\":null},h,{attrs:{tabindex:n.disabled?null:-1,role:\"menuitem\",\"aria-haspopup\":!!n.children,\"aria-expanded\":n.value===i[s],id:l,\"aria-owns\":n.children?c:null}}]),[e(\"span\",[n.label])])}),p={};o&&(p.minWidth=t.inputWidth+\"px\");var f=\"hover\"===r&&i.length-1===s,m={on:{}};return f&&(m.on.mousemove=h,p.position=\"relative\"),e(\"ul\",gh()([{class:{\"el-cascader-menu\":!0,\"el-cascader-menu--flexible\":o}},m,{style:p,refInFor:!0,ref:\"menus\",attrs:{role:\"menu\",id:a}}]),[d,f?e(\"svg\",{ref:\"hoverZone\",style:{position:\"absolute\",top:0,height:\"100%\",width:\"100%\",left:0,pointerEvents:\"none\"}}):null])});return\"hover\"===r&&this.$nextTick(function(){var e=t.$refs.activeItem;if(e){var i=e.parentElement,n=t.$refs.hoverZone;c={activeMenu:i,activeItem:e,hoverZone:n}}else c={}}),e(\"transition\",{attrs:{name:\"el-zoom-in-top\"},on:{\"before-enter\":this.handleMenuEnter,\"after-leave\":this.handleMenuLeave}},[e(\"div\",{directives:[{name:\"show\",value:s}],class:[\"el-cascader-menus el-popper\",o],ref:\"wrapper\"},[e(\"div\",{attrs:{\"x-arrow\":!0},class:\"popper__arrow\"}),d])])}},Vp=Lp,Bp=a(Vp,Np,Fp,!1,null,null,null);Bp.options.__file=\"packages/cascader/src/menu.vue\";var zp=Bp.exports,jp={props:{placement:{type:String,default:\"bottom-start\"},appendToBody:R.a.props.appendToBody,arrowOffset:R.a.props.arrowOffset,offset:R.a.props.offset,boundariesPadding:R.a.props.boundariesPadding,popperOptions:R.a.props.popperOptions},methods:R.a.methods,data:R.a.data,beforeDestroy:R.a.beforeDestroy},Hp={name:\"ElCascader\",directives:{Clickoutside:B.a},mixins:[jp,E.a,g.a],inject:{elForm:{default:\"\"},elFormItem:{default:\"\"}},components:{ElInput:m.a},props:{options:{type:Array,required:!0},props:{type:Object,default:function(){return{children:\"children\",label:\"label\",value:\"value\",disabled:\"disabled\"}}},value:{type:Array,default:function(){return[]}},separator:{type:String,default:\"/\"},placeholder:{type:String,default:function(){return Object(Zi[\"t\"])(\"el.cascader.placeholder\")}},disabled:Boolean,clearable:{type:Boolean,default:!1},changeOnSelect:Boolean,popperClass:String,expandTrigger:{type:String,default:\"click\"},filterable:Boolean,size:String,showAllLevels:{type:Boolean,default:!0},debounce:{type:Number,default:300},beforeFilter:{type:Function,default:function(){return function(){}}},hoverThreshold:{type:Number,default:500}},data:function(){return{currentValue:this.value||[],menu:null,debouncedInputChange:function(){},menuVisible:!1,inputHover:!1,inputValue:\"\",flatOptions:null,id:Object(b[\"generateId\"])(),needFocus:!0,isOnComposition:!1}},computed:{labelKey:function(){return this.props.label||\"label\"},valueKey:function(){return this.props.value||\"value\"},childrenKey:function(){return this.props.children||\"children\"},disabledKey:function(){return this.props.disabled||\"disabled\"},currentLabels:function(){var e=this,t=this.options,i=[];return this.currentValue.forEach(function(n){var s=t&&t.filter(function(t){return t[e.valueKey]===n})[0];s&&(i.push(s[e.labelKey]),t=s[e.childrenKey])}),i},_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},cascaderSize:function(){return this.size||this._elFormItemSize||(this.$ELEMENT||{}).size},cascaderDisabled:function(){return this.disabled||(this.elForm||{}).disabled},readonly:function(){return!this.filterable||!Object(b[\"isIE\"])()&&!Object(b[\"isEdge\"])()&&!this.menuVisible}},watch:{menuVisible:function(e){this.$refs.input.$refs.input.setAttribute(\"aria-expanded\",e),e?this.showMenu():this.hideMenu(),this.$emit(\"visible-change\",e)},value:function(e){this.currentValue=e},currentValue:function(e){this.dispatch(\"ElFormItem\",\"el.form.change\",[e])},options:{deep:!0,handler:function(e){this.menu||this.initMenu(),this.flatOptions=this.flattenOptions(this.options),this.menu.options=e}}},methods:{initMenu:function(){this.menu=new Rn.a(zp).$mount(),this.menu.options=this.options,this.menu.props=this.props,this.menu.expandTrigger=this.expandTrigger,this.menu.changeOnSelect=this.changeOnSelect,this.menu.popperClass=this.popperClass,this.menu.hoverThreshold=this.hoverThreshold,this.popperElm=this.menu.$el,this.menu.$refs.menus[0].setAttribute(\"id\",\"cascader-menu-\"+this.id),this.menu.$on(\"pick\",this.handlePick),this.menu.$on(\"activeItemChange\",this.handleActiveItemChange),this.menu.$on(\"menuLeave\",this.doDestroy),this.menu.$on(\"closeInside\",this.handleClickoutside)},showMenu:function(){var e=this;this.menu||this.initMenu(),this.menu.value=this.currentValue.slice(0),this.menu.visible=!0,this.menu.options=this.options,this.$nextTick(function(t){e.updatePopper(),e.menu.inputWidth=e.$refs.input.$el.offsetWidth-2})},hideMenu:function(){this.inputValue=\"\",this.menu.visible=!1,this.needFocus?this.$refs.input.focus():this.needFocus=!0},handleActiveItemChange:function(e){var t=this;this.$nextTick(function(e){t.updatePopper()}),this.$emit(\"active-item-change\",e)},handleKeydown:function(e){var t=this,i=e.keyCode;13===i?this.handleClick():40===i?(this.menuVisible=!0,setTimeout(function(){var e=t.popperElm.querySelectorAll(\".el-cascader-menu\")[0];e.querySelectorAll(\"[tabindex='-1']\")[0].focus()}),e.stopPropagation(),e.preventDefault()):27!==i&&9!==i||(this.inputValue=\"\",this.menu&&(this.menu.visible=!1))},handlePick:function(e){var t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];this.currentValue=e,this.$emit(\"input\",e),this.$emit(\"change\",e),t?this.menuVisible=!1:this.$nextTick(this.updatePopper)},handleInputChange:function(e){var t=this;if(this.menuVisible){var i=this.flatOptions;if(!e)return this.menu.options=this.options,void this.$nextTick(this.updatePopper);var n=i.filter(function(i){return i.some(function(i){return new RegExp(Object(b[\"escapeRegexpString\"])(e),\"i\").test(i[t.labelKey])})});n=n.length>0?n.map(function(i){return{__IS__FLAT__OPTIONS:!0,value:i.map(function(e){return e[t.valueKey]}),label:t.renderFilteredOptionLabel(e,i),disabled:i.some(function(e){return e[t.disabledKey]})}}):[{__IS__FLAT__OPTIONS:!0,label:this.t(\"el.cascader.noMatch\"),value:\"\",disabled:!0}],this.menu.options=n,this.$nextTick(this.updatePopper)}},renderFilteredOptionLabel:function(e,t){var i=this;return t.map(function(t,n){var s=t[i.labelKey],r=s.toLowerCase().indexOf(e.toLowerCase()),o=s.slice(r,e.length+r),a=r>-1?i.highlightKeyword(s,o):s;return 0===n?a:[\" \"+i.separator+\" \",a]})},highlightKeyword:function(e,t){var i=this,n=this._c;return e.split(t).map(function(e,s){return 0===s?e:[n(\"span\",{class:{\"el-cascader-menu__item__keyword\":!0}},[i._v(t)]),e]})},flattenOptions:function(e){var t=this,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=[];return e.forEach(function(e){var s=i.concat(e);e[t.childrenKey]?(t.changeOnSelect&&n.push(s),n=n.concat(t.flattenOptions(e[t.childrenKey],s))):n.push(s)}),n},clearValue:function(e){e.stopPropagation(),this.handlePick([],!0)},handleClickoutside:function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];this.menuVisible&&!e&&(this.needFocus=!1),this.menuVisible=!1},handleClick:function(){this.cascaderDisabled||(this.$refs.input.focus(),this.filterable?this.menuVisible=!0:this.menuVisible=!this.menuVisible)},handleFocus:function(e){this.$emit(\"focus\",e)},handleBlur:function(e){this.$emit(\"blur\",e)},handleComposition:function(e){this.isOnComposition=\"compositionend\"!==e.type}},created:function(){var e=this;this.debouncedInputChange=L()(this.debounce,function(t){var i=e.beforeFilter(t);i&&i.then?(e.menu.options=[{__IS__FLAT__OPTIONS:!0,label:e.t(\"el.cascader.loading\"),value:\"\",disabled:!0}],i.then(function(){e.$nextTick(function(){e.handleInputChange(t)})})):!1!==i&&e.$nextTick(function(){e.handleInputChange(t)})})},mounted:function(){this.flatOptions=this.flattenOptions(this.options)}},Rp=Hp,Wp=a(Rp,Pp,Mp,!1,null,null,null);Wp.options.__file=\"packages/cascader/src/main.vue\";var qp=Wp.exports;qp.install=function(e){e.component(qp.name,qp)};var Kp=qp,Yp=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{directives:[{name:\"clickoutside\",rawName:\"v-clickoutside\",value:e.hide,expression:\"hide\"}],class:[\"el-color-picker\",e.colorDisabled?\"is-disabled\":\"\",e.colorSize?\"el-color-picker--\"+e.colorSize:\"\"]},[e.colorDisabled?i(\"div\",{staticClass:\"el-color-picker__mask\"}):e._e(),i(\"div\",{staticClass:\"el-color-picker__trigger\",on:{click:e.handleTrigger}},[i(\"span\",{staticClass:\"el-color-picker__color\",class:{\"is-alpha\":e.showAlpha}},[i(\"span\",{staticClass:\"el-color-picker__color-inner\",style:{backgroundColor:e.displayedColor}}),e.value||e.showPanelColor?e._e():i(\"span\",{staticClass:\"el-color-picker__empty el-icon-close\"})]),i(\"span\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.value||e.showPanelColor,expression:\"value || showPanelColor\"}],staticClass:\"el-color-picker__icon el-icon-arrow-down\"})]),i(\"picker-dropdown\",{ref:\"dropdown\",class:[\"el-color-picker__panel\",e.popperClass||\"\"],attrs:{color:e.color,\"show-alpha\":e.showAlpha,predefine:e.predefine},on:{pick:e.confirmValue,clear:e.clearValue},model:{value:e.showPicker,callback:function(t){e.showPicker=t},expression:\"showPicker\"}})],1)},Up=[];Yp._withStripped=!0;var Gp=\"function\"===typeof Symbol&&\"symbol\"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e};function Xp(e,t){if(!(e instanceof t))throw new TypeError(\"Cannot call a class as a function\")}var Qp=function(e,t,i){return[e,t*i/((e=(2-t)*i)<1?e:2-e)||0,e/2]},Jp=function(e){return\"string\"===typeof e&&-1!==e.indexOf(\".\")&&1===parseFloat(e)},Zp=function(e){return\"string\"===typeof e&&-1!==e.indexOf(\"%\")},ef=function(e,t){Jp(e)&&(e=\"100%\");var i=Zp(e);return e=Math.min(t,Math.max(0,parseFloat(e))),i&&(e=parseInt(e*t,10)/100),Math.abs(e-t)<1e-6?1:e%t/parseFloat(t)},tf={10:\"A\",11:\"B\",12:\"C\",13:\"D\",14:\"E\",15:\"F\"},nf=function(e){var t=e.r,i=e.g,n=e.b,s=function(e){e=Math.min(Math.round(e),255);var t=Math.floor(e/16),i=e%16;return\"\"+(tf[t]||t)+(tf[i]||i)};return isNaN(t)||isNaN(i)||isNaN(n)?\"\":\"#\"+s(t)+s(i)+s(n)},sf={A:10,B:11,C:12,D:13,E:14,F:15},rf=function(e){return 2===e.length?16*(sf[e[0].toUpperCase()]||+e[0])+(sf[e[1].toUpperCase()]||+e[1]):sf[e[1].toUpperCase()]||+e[1]},of=function(e,t,i){t/=100,i/=100;var n=t,s=Math.max(i,.01),r=void 0,o=void 0;return i*=2,t*=i<=1?i:2-i,n*=s<=1?s:2-s,o=(i+t)/2,r=0===i?2*n/(s+n):2*t/(i+t),{h:e,s:100*r,v:100*o}},af=function(e,t,i){e=ef(e,255),t=ef(t,255),i=ef(i,255);var n=Math.max(e,t,i),s=Math.min(e,t,i),r=void 0,o=void 0,a=n,l=n-s;if(o=0===n?0:l/n,n===s)r=0;else{switch(n){case e:r=(t-i)/l+(t<i?6:0);break;case t:r=(i-e)/l+2;break;case i:r=(e-t)/l+4;break}r/=6}return{h:360*r,s:100*o,v:100*a}},lf=function(e,t,i){e=6*ef(e,360),t=ef(t,100),i=ef(i,100);var n=Math.floor(e),s=e-n,r=i*(1-t),o=i*(1-s*t),a=i*(1-(1-s)*t),l=n%6,u=[i,o,r,r,a,i][l],c=[a,i,i,o,r,r][l],h=[r,r,a,i,i,o][l];return{r:Math.round(255*u),g:Math.round(255*c),b:Math.round(255*h)}},uf=function(){function e(t){for(var i in Xp(this,e),this._hue=0,this._saturation=100,this._value=100,this._alpha=100,this.enableAlpha=!1,this.format=\"hex\",this.value=\"\",t=t||{},t)t.hasOwnProperty(i)&&(this[i]=t[i]);this.doOnChange()}return e.prototype.set=function(e,t){if(1!==arguments.length||\"object\"!==(\"undefined\"===typeof e?\"undefined\":Gp(e)))this[\"_\"+e]=t,this.doOnChange();else for(var i in e)e.hasOwnProperty(i)&&this.set(i,e[i])},e.prototype.get=function(e){return this[\"_\"+e]},e.prototype.toRgb=function(){return lf(this._hue,this._saturation,this._value)},e.prototype.fromString=function(e){var t=this;if(!e)return this._hue=0,this._saturation=100,this._value=100,void this.doOnChange();var i=function(e,i,n){t._hue=Math.max(0,Math.min(360,e)),t._saturation=Math.max(0,Math.min(100,i)),t._value=Math.max(0,Math.min(100,n)),t.doOnChange()};if(-1!==e.indexOf(\"hsl\")){var n=e.replace(/hsla|hsl|\\(|\\)/gm,\"\").split(/\\s|,/g).filter(function(e){return\"\"!==e}).map(function(e,t){return t>2?parseFloat(e):parseInt(e,10)});if(4===n.length?this._alpha=Math.floor(100*parseFloat(n[3])):3===n.length&&(this._alpha=100),n.length>=3){var s=of(n[0],n[1],n[2]),r=s.h,o=s.s,a=s.v;i(r,o,a)}}else if(-1!==e.indexOf(\"hsv\")){var l=e.replace(/hsva|hsv|\\(|\\)/gm,\"\").split(/\\s|,/g).filter(function(e){return\"\"!==e}).map(function(e,t){return t>2?parseFloat(e):parseInt(e,10)});4===l.length?this._alpha=Math.floor(100*parseFloat(l[3])):3===l.length&&(this._alpha=100),l.length>=3&&i(l[0],l[1],l[2])}else if(-1!==e.indexOf(\"rgb\")){var u=e.replace(/rgba|rgb|\\(|\\)/gm,\"\").split(/\\s|,/g).filter(function(e){return\"\"!==e}).map(function(e,t){return t>2?parseFloat(e):parseInt(e,10)});if(4===u.length?this._alpha=Math.floor(100*parseFloat(u[3])):3===u.length&&(this._alpha=100),u.length>=3){var c=af(u[0],u[1],u[2]),h=c.h,d=c.s,p=c.v;i(h,d,p)}}else if(-1!==e.indexOf(\"#\")){var f=e.replace(\"#\",\"\").trim();if(!/^(?:[0-9a-fA-F]{3}){1,2}$/.test(f))return;var m=void 0,v=void 0,g=void 0;3===f.length?(m=rf(f[0]+f[0]),v=rf(f[1]+f[1]),g=rf(f[2]+f[2])):6!==f.length&&8!==f.length||(m=rf(f.substring(0,2)),v=rf(f.substring(2,4)),g=rf(f.substring(4,6))),8===f.length?this._alpha=Math.floor(rf(f.substring(6))/255*100):3!==f.length&&6!==f.length||(this._alpha=100);var b=af(m,v,g),y=b.h,_=b.s,x=b.v;i(y,_,x)}},e.prototype.compare=function(e){return Math.abs(e._hue-this._hue)<2&&Math.abs(e._saturation-this._saturation)<1&&Math.abs(e._value-this._value)<1&&Math.abs(e._alpha-this._alpha)<1},e.prototype.doOnChange=function(){var e=this._hue,t=this._saturation,i=this._value,n=this._alpha,s=this.format;if(this.enableAlpha)switch(s){case\"hsl\":var r=Qp(e,t/100,i/100);this.value=\"hsla(\"+e+\", \"+Math.round(100*r[1])+\"%, \"+Math.round(100*r[2])+\"%, \"+n/100+\")\";break;case\"hsv\":this.value=\"hsva(\"+e+\", \"+Math.round(t)+\"%, \"+Math.round(i)+\"%, \"+n/100+\")\";break;default:var o=lf(e,t,i),a=o.r,l=o.g,u=o.b;this.value=\"rgba(\"+a+\", \"+l+\", \"+u+\", \"+n/100+\")\"}else switch(s){case\"hsl\":var c=Qp(e,t/100,i/100);this.value=\"hsl(\"+e+\", \"+Math.round(100*c[1])+\"%, \"+Math.round(100*c[2])+\"%)\";break;case\"hsv\":this.value=\"hsv(\"+e+\", \"+Math.round(t)+\"%, \"+Math.round(i)+\"%)\";break;case\"rgb\":var h=lf(e,t,i),d=h.r,p=h.g,f=h.b;this.value=\"rgb(\"+d+\", \"+p+\", \"+f+\")\";break;default:this.value=nf(lf(e,t,i))}},e}(),cf=uf,hf=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"el-zoom-in-top\"},on:{\"after-leave\":e.doDestroy}},[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.showPopper,expression:\"showPopper\"}],staticClass:\"el-color-dropdown\"},[i(\"div\",{staticClass:\"el-color-dropdown__main-wrapper\"},[i(\"hue-slider\",{ref:\"hue\",staticStyle:{float:\"right\"},attrs:{color:e.color,vertical:\"\"}}),i(\"sv-panel\",{ref:\"sl\",attrs:{color:e.color}})],1),e.showAlpha?i(\"alpha-slider\",{ref:\"alpha\",attrs:{color:e.color}}):e._e(),e.predefine?i(\"predefine\",{attrs:{color:e.color,colors:e.predefine}}):e._e(),i(\"div\",{staticClass:\"el-color-dropdown__btns\"},[i(\"span\",{staticClass:\"el-color-dropdown__value\"},[i(\"el-input\",{attrs:{\"validate-event\":!1,size:\"mini\"},on:{blur:e.handleConfirm},nativeOn:{keyup:function(t){return\"button\"in t||!e._k(t.keyCode,\"enter\",13,t.key,\"Enter\")?e.handleConfirm(t):null}},model:{value:e.customInput,callback:function(t){e.customInput=t},expression:\"customInput\"}})],1),i(\"el-button\",{staticClass:\"el-color-dropdown__link-btn\",attrs:{size:\"mini\",type:\"text\"},on:{click:function(t){e.$emit(\"clear\")}}},[e._v(\"\\n        \"+e._s(e.t(\"el.colorpicker.clear\"))+\"\\n      \")]),i(\"el-button\",{staticClass:\"el-color-dropdown__btn\",attrs:{plain:\"\",size:\"mini\"},on:{click:e.confirmValue}},[e._v(\"\\n        \"+e._s(e.t(\"el.colorpicker.confirm\"))+\"\\n      \")])],1)],1)])},df=[];hf._withStripped=!0;var pf=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-color-svpanel\",style:{backgroundColor:e.background}},[i(\"div\",{staticClass:\"el-color-svpanel__white\"}),i(\"div\",{staticClass:\"el-color-svpanel__black\"}),i(\"div\",{staticClass:\"el-color-svpanel__cursor\",style:{top:e.cursorTop+\"px\",left:e.cursorLeft+\"px\"}},[i(\"div\")])])},ff=[];pf._withStripped=!0;var mf=!1,vf=function(e,t){if(!Rn.a.prototype.$isServer){var i=function(e){t.drag&&t.drag(e)},n=function e(n){document.removeEventListener(\"mousemove\",i),document.removeEventListener(\"mouseup\",e),document.onselectstart=null,document.ondragstart=null,mf=!1,t.end&&t.end(n)};e.addEventListener(\"mousedown\",function(e){mf||(document.onselectstart=function(){return!1},document.ondragstart=function(){return!1},document.addEventListener(\"mousemove\",i),document.addEventListener(\"mouseup\",n),mf=!0,t.start&&t.start(e))})}},gf={name:\"el-sl-panel\",props:{color:{required:!0}},computed:{colorValue:function(){var e=this.color.get(\"hue\"),t=this.color.get(\"value\");return{hue:e,value:t}}},watch:{colorValue:function(){this.update()}},methods:{update:function(){var e=this.color.get(\"saturation\"),t=this.color.get(\"value\"),i=this.$el,n=i.clientWidth,s=i.clientHeight;this.cursorLeft=e*n/100,this.cursorTop=(100-t)*s/100,this.background=\"hsl(\"+this.color.get(\"hue\")+\", 100%, 50%)\"},handleDrag:function(e){var t=this.$el,i=t.getBoundingClientRect(),n=e.clientX-i.left,s=e.clientY-i.top;n=Math.max(0,n),n=Math.min(n,i.width),s=Math.max(0,s),s=Math.min(s,i.height),this.cursorLeft=n,this.cursorTop=s,this.color.set({saturation:n/i.width*100,value:100-s/i.height*100})}},mounted:function(){var e=this;vf(this.$el,{drag:function(t){e.handleDrag(t)},end:function(t){e.handleDrag(t)}}),this.update()},data:function(){return{cursorTop:0,cursorLeft:0,background:\"hsl(0, 100%, 50%)\"}}},bf=gf,yf=a(bf,pf,ff,!1,null,null,null);yf.options.__file=\"packages/color-picker/src/components/sv-panel.vue\";var _f=yf.exports,xf=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-color-hue-slider\",class:{\"is-vertical\":e.vertical}},[i(\"div\",{ref:\"bar\",staticClass:\"el-color-hue-slider__bar\",on:{click:e.handleClick}}),i(\"div\",{ref:\"thumb\",staticClass:\"el-color-hue-slider__thumb\",style:{left:e.thumbLeft+\"px\",top:e.thumbTop+\"px\"}})])},Cf=[];xf._withStripped=!0;var wf={name:\"el-color-hue-slider\",props:{color:{required:!0},vertical:Boolean},data:function(){return{thumbLeft:0,thumbTop:0}},computed:{hueValue:function(){var e=this.color.get(\"hue\");return e}},watch:{hueValue:function(){this.update()}},methods:{handleClick:function(e){var t=this.$refs.thumb,i=e.target;i!==t&&this.handleDrag(e)},handleDrag:function(e){var t=this.$el.getBoundingClientRect(),i=this.$refs.thumb,n=void 0;if(this.vertical){var s=e.clientY-t.top;s=Math.min(s,t.height-i.offsetHeight/2),s=Math.max(i.offsetHeight/2,s),n=Math.round((s-i.offsetHeight/2)/(t.height-i.offsetHeight)*360)}else{var r=e.clientX-t.left;r=Math.min(r,t.width-i.offsetWidth/2),r=Math.max(i.offsetWidth/2,r),n=Math.round((r-i.offsetWidth/2)/(t.width-i.offsetWidth)*360)}this.color.set(\"hue\",n)},getThumbLeft:function(){if(this.vertical)return 0;var e=this.$el,t=this.color.get(\"hue\");if(!e)return 0;var i=this.$refs.thumb;return Math.round(t*(e.offsetWidth-i.offsetWidth/2)/360)},getThumbTop:function(){if(!this.vertical)return 0;var e=this.$el,t=this.color.get(\"hue\");if(!e)return 0;var i=this.$refs.thumb;return Math.round(t*(e.offsetHeight-i.offsetHeight/2)/360)},update:function(){this.thumbLeft=this.getThumbLeft(),this.thumbTop=this.getThumbTop()}},mounted:function(){var e=this,t=this.$refs,i=t.bar,n=t.thumb,s={drag:function(t){e.handleDrag(t)},end:function(t){e.handleDrag(t)}};vf(i,s),vf(n,s),this.update()}},kf=wf,Sf=a(kf,xf,Cf,!1,null,null,null);Sf.options.__file=\"packages/color-picker/src/components/hue-slider.vue\";var $f=Sf.exports,Df=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-color-alpha-slider\",class:{\"is-vertical\":e.vertical}},[i(\"div\",{ref:\"bar\",staticClass:\"el-color-alpha-slider__bar\",style:{background:e.background},on:{click:e.handleClick}}),i(\"div\",{ref:\"thumb\",staticClass:\"el-color-alpha-slider__thumb\",style:{left:e.thumbLeft+\"px\",top:e.thumbTop+\"px\"}})])},Ef=[];Df._withStripped=!0;var Tf={name:\"el-color-alpha-slider\",props:{color:{required:!0},vertical:Boolean},watch:{\"color._alpha\":function(){this.update()},\"color.value\":function(){this.update()}},methods:{handleClick:function(e){var t=this.$refs.thumb,i=e.target;i!==t&&this.handleDrag(e)},handleDrag:function(e){var t=this.$el.getBoundingClientRect(),i=this.$refs.thumb;if(this.vertical){var n=e.clientY-t.top;n=Math.max(i.offsetHeight/2,n),n=Math.min(n,t.height-i.offsetHeight/2),this.color.set(\"alpha\",Math.round((n-i.offsetHeight/2)/(t.height-i.offsetHeight)*100))}else{var s=e.clientX-t.left;s=Math.max(i.offsetWidth/2,s),s=Math.min(s,t.width-i.offsetWidth/2),this.color.set(\"alpha\",Math.round((s-i.offsetWidth/2)/(t.width-i.offsetWidth)*100))}},getThumbLeft:function(){if(this.vertical)return 0;var e=this.$el,t=this.color._alpha;if(!e)return 0;var i=this.$refs.thumb;return Math.round(t*(e.offsetWidth-i.offsetWidth/2)/100)},getThumbTop:function(){if(!this.vertical)return 0;var e=this.$el,t=this.color._alpha;if(!e)return 0;var i=this.$refs.thumb;return Math.round(t*(e.offsetHeight-i.offsetHeight/2)/100)},getBackground:function(){if(this.color&&this.color.value){var e=this.color.toRgb(),t=e.r,i=e.g,n=e.b;return\"linear-gradient(to right, rgba(\"+t+\", \"+i+\", \"+n+\", 0) 0%, rgba(\"+t+\", \"+i+\", \"+n+\", 1) 100%)\"}return null},update:function(){this.thumbLeft=this.getThumbLeft(),this.thumbTop=this.getThumbTop(),this.background=this.getBackground()}},data:function(){return{thumbLeft:0,thumbTop:0,background:null}},mounted:function(){var e=this,t=this.$refs,i=t.bar,n=t.thumb,s={drag:function(t){e.handleDrag(t)},end:function(t){e.handleDrag(t)}};vf(i,s),vf(n,s),this.update()}},Of=Tf,If=a(Of,Df,Ef,!1,null,null,null);If.options.__file=\"packages/color-picker/src/components/alpha-slider.vue\";var Pf=If.exports,Mf=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-color-predefine\"},[i(\"div\",{staticClass:\"el-color-predefine__colors\"},e._l(e.rgbaColors,function(t,n){return i(\"div\",{key:e.colors[n],staticClass:\"el-color-predefine__color-selector\",class:{selected:t.selected,\"is-alpha\":t._alpha<100},on:{click:function(t){e.handleSelect(n)}}},[i(\"div\",{style:{\"background-color\":t.value}})])}),0)])},Nf=[];Mf._withStripped=!0;var Ff={props:{colors:{type:Array,required:!0},color:{required:!0}},data:function(){return{rgbaColors:this.parseColors(this.colors,this.color)}},methods:{handleSelect:function(e){this.color.fromString(this.colors[e])},parseColors:function(e,t){return e.map(function(e){var i=new cf;return i.enableAlpha=!0,i.format=\"rgba\",i.fromString(e),i.selected=i.value===t.value,i})}},watch:{\"$parent.currentColor\":function(e){var t=new cf;t.fromString(e),this.rgbaColors.forEach(function(e){e.selected=t.compare(e)})},colors:function(e){this.rgbaColors=this.parseColors(e,this.color)},color:function(e){this.rgbaColors=this.parseColors(this.colors,e)}}},Af=Ff,Lf=a(Af,Mf,Nf,!1,null,null,null);Lf.options.__file=\"packages/color-picker/src/components/predefine.vue\";var Vf=Lf.exports,Bf={name:\"el-color-picker-dropdown\",mixins:[R.a,g.a],components:{SvPanel:_f,HueSlider:$f,AlphaSlider:Pf,ElInput:m.a,ElButton:oe.a,Predefine:Vf},props:{color:{required:!0},showAlpha:Boolean,predefine:Array},data:function(){return{customInput:\"\"}},computed:{currentColor:function(){var e=this.$parent;return e.value||e.showPanelColor?e.color.value:\"\"}},methods:{confirmValue:function(){this.$emit(\"pick\")},handleConfirm:function(){this.color.fromString(this.customInput)}},mounted:function(){this.$parent.popperElm=this.popperElm=this.$el,this.referenceElm=this.$parent.$el},watch:{showPopper:function(e){var t=this;!0===e&&this.$nextTick(function(){var e=t.$refs,i=e.sl,n=e.hue,s=e.alpha;i&&i.update(),n&&n.update(),s&&s.update()})},currentColor:{immediate:!0,handler:function(e){this.customInput=e}}}},zf=Bf,jf=a(zf,hf,df,!1,null,null,null);jf.options.__file=\"packages/color-picker/src/components/picker-dropdown.vue\";var Hf=jf.exports,Rf={name:\"ElColorPicker\",mixins:[E.a],props:{value:String,showAlpha:Boolean,colorFormat:String,disabled:Boolean,size:String,popperClass:String,predefine:Array},inject:{elForm:{default:\"\"},elFormItem:{default:\"\"}},directives:{Clickoutside:B.a},computed:{displayedColor:function(){return this.value||this.showPanelColor?this.displayedRgb(this.color,this.showAlpha):\"transparent\"},_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},colorSize:function(){return this.size||this._elFormItemSize||(this.$ELEMENT||{}).size},colorDisabled:function(){return this.disabled||(this.elForm||{}).disabled}},watch:{value:function(e){e?e&&e!==this.color.value&&this.color.fromString(e):this.showPanelColor=!1},color:{deep:!0,handler:function(){this.showPanelColor=!0}},displayedColor:function(e){if(this.showPicker){var t=new cf({enableAlpha:this.showAlpha,format:this.colorFormat});t.fromString(this.value);var i=this.displayedRgb(t,this.showAlpha);e!==i&&this.$emit(\"active-change\",e)}}},methods:{handleTrigger:function(){this.colorDisabled||(this.showPicker=!this.showPicker)},confirmValue:function(){var e=this.color.value;this.$emit(\"input\",e),this.$emit(\"change\",e),this.dispatch(\"ElFormItem\",\"el.form.change\",e),this.showPicker=!1},clearValue:function(){this.$emit(\"input\",null),this.$emit(\"change\",null),null!==this.value&&this.dispatch(\"ElFormItem\",\"el.form.change\",null),this.showPanelColor=!1,this.showPicker=!1,this.resetColor()},hide:function(){this.showPicker=!1,this.resetColor()},resetColor:function(){var e=this;this.$nextTick(function(t){e.value?e.color.fromString(e.value):e.showPanelColor=!1})},displayedRgb:function(e,t){if(!(e instanceof cf))throw Error(\"color should be instance of Color Class\");var i=e.toRgb(),n=i.r,s=i.g,r=i.b;return t?\"rgba(\"+n+\", \"+s+\", \"+r+\", \"+e.get(\"alpha\")/100+\")\":\"rgb(\"+n+\", \"+s+\", \"+r+\")\"}},mounted:function(){var e=this.value;e&&this.color.fromString(e),this.popperElm=this.$refs.dropdown.$el},data:function(){var e=new cf({enableAlpha:this.showAlpha,format:this.colorFormat});return{color:e,showPicker:!1,showPanelColor:!1}},components:{PickerDropdown:Hf}},Wf=Rf,qf=a(Wf,Yp,Up,!1,null,null,null);qf.options.__file=\"packages/color-picker/src/main.vue\";var Kf=qf.exports;Kf.install=function(e){e.component(Kf.name,Kf)};var Yf=Kf,Uf=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-transfer\"},[i(\"transfer-panel\",e._b({ref:\"leftPanel\",attrs:{data:e.sourceData,title:e.titles[0]||e.t(\"el.transfer.titles.0\"),\"default-checked\":e.leftDefaultChecked,placeholder:e.filterPlaceholder||e.t(\"el.transfer.filterPlaceholder\")},on:{\"checked-change\":e.onSourceCheckedChange}},\"transfer-panel\",e.$props,!1),[e._t(\"left-footer\")],2),i(\"div\",{staticClass:\"el-transfer__buttons\"},[i(\"el-button\",{class:[\"el-transfer__button\",e.hasButtonTexts?\"is-with-texts\":\"\"],attrs:{type:\"primary\",disabled:0===e.rightChecked.length},nativeOn:{click:function(t){return e.addToLeft(t)}}},[i(\"i\",{staticClass:\"el-icon-arrow-left\"}),void 0!==e.buttonTexts[0]?i(\"span\",[e._v(e._s(e.buttonTexts[0]))]):e._e()]),i(\"el-button\",{class:[\"el-transfer__button\",e.hasButtonTexts?\"is-with-texts\":\"\"],attrs:{type:\"primary\",disabled:0===e.leftChecked.length},nativeOn:{click:function(t){return e.addToRight(t)}}},[void 0!==e.buttonTexts[1]?i(\"span\",[e._v(e._s(e.buttonTexts[1]))]):e._e(),i(\"i\",{staticClass:\"el-icon-arrow-right\"})])],1),i(\"transfer-panel\",e._b({ref:\"rightPanel\",attrs:{data:e.targetData,title:e.titles[1]||e.t(\"el.transfer.titles.1\"),\"default-checked\":e.rightDefaultChecked,placeholder:e.filterPlaceholder||e.t(\"el.transfer.filterPlaceholder\")},on:{\"checked-change\":e.onTargetCheckedChange}},\"transfer-panel\",e.$props,!1),[e._t(\"right-footer\")],2)],1)},Gf=[];Uf._withStripped=!0;var Xf=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-transfer-panel\"},[i(\"p\",{staticClass:\"el-transfer-panel__header\"},[i(\"el-checkbox\",{attrs:{indeterminate:e.isIndeterminate},on:{change:e.handleAllCheckedChange},model:{value:e.allChecked,callback:function(t){e.allChecked=t},expression:\"allChecked\"}},[e._v(\"\\n      \"+e._s(e.title)+\"\\n      \"),i(\"span\",[e._v(e._s(e.checkedSummary))])])],1),i(\"div\",{class:[\"el-transfer-panel__body\",e.hasFooter?\"is-with-footer\":\"\"]},[e.filterable?i(\"el-input\",{staticClass:\"el-transfer-panel__filter\",attrs:{size:\"small\",placeholder:e.placeholder},nativeOn:{mouseenter:function(t){e.inputHover=!0},mouseleave:function(t){e.inputHover=!1}},model:{value:e.query,callback:function(t){e.query=t},expression:\"query\"}},[i(\"i\",{class:[\"el-input__icon\",\"el-icon-\"+e.inputIcon],attrs:{slot:\"prefix\"},on:{click:e.clearQuery},slot:\"prefix\"})]):e._e(),i(\"el-checkbox-group\",{directives:[{name:\"show\",rawName:\"v-show\",value:!e.hasNoMatch&&e.data.length>0,expression:\"!hasNoMatch && data.length > 0\"}],staticClass:\"el-transfer-panel__list\",class:{\"is-filterable\":e.filterable},model:{value:e.checked,callback:function(t){e.checked=t},expression:\"checked\"}},e._l(e.filteredData,function(t){return i(\"el-checkbox\",{key:t[e.keyProp],staticClass:\"el-transfer-panel__item\",attrs:{label:t[e.keyProp],disabled:t[e.disabledProp]}},[i(\"option-content\",{attrs:{option:t}})],1)}),1),i(\"p\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.hasNoMatch,expression:\"hasNoMatch\"}],staticClass:\"el-transfer-panel__empty\"},[e._v(e._s(e.t(\"el.transfer.noMatch\")))]),i(\"p\",{directives:[{name:\"show\",rawName:\"v-show\",value:0===e.data.length&&!e.hasNoMatch,expression:\"data.length === 0 && !hasNoMatch\"}],staticClass:\"el-transfer-panel__empty\"},[e._v(e._s(e.t(\"el.transfer.noData\")))])],1),e.hasFooter?i(\"p\",{staticClass:\"el-transfer-panel__footer\"},[e._t(\"default\")],2):e._e()])},Qf=[];Xf._withStripped=!0;var Jf={mixins:[g.a],name:\"ElTransferPanel\",componentName:\"ElTransferPanel\",components:{ElCheckboxGroup:bs.a,ElCheckbox:An.a,ElInput:m.a,OptionContent:{props:{option:Object},render:function(e){var t=function e(t){return\"ElTransferPanel\"===t.$options.componentName?t:t.$parent?e(t.$parent):t},i=t(this),n=i.$parent||i;return i.renderContent?i.renderContent(e,this.option):n.$scopedSlots.default?n.$scopedSlots.default({option:this.option}):e(\"span\",[this.option[i.labelProp]||this.option[i.keyProp]])}}},props:{data:{type:Array,default:function(){return[]}},renderContent:Function,placeholder:String,title:String,filterable:Boolean,format:Object,filterMethod:Function,defaultChecked:Array,props:Object},data:function(){return{checked:[],allChecked:!1,query:\"\",inputHover:!1,checkChangeByUser:!0}},watch:{checked:function(e,t){if(this.updateAllChecked(),this.checkChangeByUser){var i=e.concat(t).filter(function(i){return-1===e.indexOf(i)||-1===t.indexOf(i)});this.$emit(\"checked-change\",e,i)}else this.$emit(\"checked-change\",e),this.checkChangeByUser=!0},data:function(){var e=this,t=[],i=this.filteredData.map(function(t){return t[e.keyProp]});this.checked.forEach(function(e){i.indexOf(e)>-1&&t.push(e)}),this.checkChangeByUser=!1,this.checked=t},checkableData:function(){this.updateAllChecked()},defaultChecked:{immediate:!0,handler:function(e,t){var i=this;if(!t||e.length!==t.length||!e.every(function(e){return t.indexOf(e)>-1})){var n=[],s=this.checkableData.map(function(e){return e[i.keyProp]});e.forEach(function(e){s.indexOf(e)>-1&&n.push(e)}),this.checkChangeByUser=!1,this.checked=n}}}},computed:{filteredData:function(){var e=this;return this.data.filter(function(t){if(\"function\"===typeof e.filterMethod)return e.filterMethod(e.query,t);var i=t[e.labelProp]||t[e.keyProp].toString();return i.toLowerCase().indexOf(e.query.toLowerCase())>-1})},checkableData:function(){var e=this;return this.filteredData.filter(function(t){return!t[e.disabledProp]})},checkedSummary:function(){var e=this.checked.length,t=this.data.length,i=this.format,n=i.noChecked,s=i.hasChecked;return n&&s?e>0?s.replace(/\\${checked}/g,e).replace(/\\${total}/g,t):n.replace(/\\${total}/g,t):e+\"/\"+t},isIndeterminate:function(){var e=this.checked.length;return e>0&&e<this.checkableData.length},hasNoMatch:function(){return this.query.length>0&&0===this.filteredData.length},inputIcon:function(){return this.query.length>0&&this.inputHover?\"circle-close\":\"search\"},labelProp:function(){return this.props.label||\"label\"},keyProp:function(){return this.props.key||\"key\"},disabledProp:function(){return this.props.disabled||\"disabled\"},hasFooter:function(){return!!this.$slots.default}},methods:{updateAllChecked:function(){var e=this,t=this.checkableData.map(function(t){return t[e.keyProp]});this.allChecked=t.length>0&&t.every(function(t){return e.checked.indexOf(t)>-1})},handleAllCheckedChange:function(e){var t=this;this.checked=e?this.checkableData.map(function(e){return e[t.keyProp]}):[]},clearQuery:function(){\"circle-close\"===this.inputIcon&&(this.query=\"\")}}},Zf=Jf,em=a(Zf,Xf,Qf,!1,null,null,null);em.options.__file=\"packages/transfer/src/transfer-panel.vue\";var tm=em.exports,im={name:\"ElTransfer\",mixins:[E.a,g.a,$.a],components:{TransferPanel:tm,ElButton:oe.a},props:{data:{type:Array,default:function(){return[]}},titles:{type:Array,default:function(){return[]}},buttonTexts:{type:Array,default:function(){return[]}},filterPlaceholder:{type:String,default:\"\"},filterMethod:Function,leftDefaultChecked:{type:Array,default:function(){return[]}},rightDefaultChecked:{type:Array,default:function(){return[]}},renderContent:Function,value:{type:Array,default:function(){return[]}},format:{type:Object,default:function(){return{}}},filterable:Boolean,props:{type:Object,default:function(){return{label:\"label\",key:\"key\",disabled:\"disabled\"}}},targetOrder:{type:String,default:\"original\"}},data:function(){return{leftChecked:[],rightChecked:[]}},computed:{dataObj:function(){var e=this.props.key;return this.data.reduce(function(t,i){return(t[i[e]]=i)&&t},{})},sourceData:function(){var e=this;return this.data.filter(function(t){return-1===e.value.indexOf(t[e.props.key])})},targetData:function(){var e=this;return\"original\"===this.targetOrder?this.data.filter(function(t){return e.value.indexOf(t[e.props.key])>-1}):this.value.reduce(function(t,i){var n=e.dataObj[i];return n&&t.push(n),t},[])},hasButtonTexts:function(){return 2===this.buttonTexts.length}},watch:{value:function(e){this.dispatch(\"ElFormItem\",\"el.form.change\",e)}},methods:{getMigratingConfig:function(){return{props:{\"footer-format\":\"footer-format is renamed to format.\"}}},onSourceCheckedChange:function(e,t){this.leftChecked=e,void 0!==t&&this.$emit(\"left-check-change\",e,t)},onTargetCheckedChange:function(e,t){this.rightChecked=e,void 0!==t&&this.$emit(\"right-check-change\",e,t)},addToLeft:function(){var e=this.value.slice();this.rightChecked.forEach(function(t){var i=e.indexOf(t);i>-1&&e.splice(i,1)}),this.$emit(\"input\",e),this.$emit(\"change\",e,\"left\",this.rightChecked)},addToRight:function(){var e=this,t=this.value.slice(),i=[],n=this.props.key;this.data.forEach(function(t){var s=t[n];e.leftChecked.indexOf(s)>-1&&-1===e.value.indexOf(s)&&i.push(s)}),t=\"unshift\"===this.targetOrder?i.concat(t):t.concat(i),this.$emit(\"input\",t),this.$emit(\"change\",t,\"right\",this.leftChecked)},clearQuery:function(e){\"left\"===e?this.$refs.leftPanel.query=\"\":\"right\"===e&&(this.$refs.rightPanel.query=\"\")}}},nm=im,sm=a(nm,Uf,Gf,!1,null,null,null);sm.options.__file=\"packages/transfer/src/main.vue\";var rm=sm.exports;rm.install=function(e){e.component(rm.name,rm)};var om=rm,am=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"section\",{staticClass:\"el-container\",class:{\"is-vertical\":e.isVertical}},[e._t(\"default\")],2)},lm=[];am._withStripped=!0;var um={name:\"ElContainer\",componentName:\"ElContainer\",props:{direction:String},computed:{isVertical:function(){return\"vertical\"===this.direction||\"horizontal\"!==this.direction&&(!(!this.$slots||!this.$slots.default)&&this.$slots.default.some(function(e){var t=e.componentOptions&&e.componentOptions.tag;return\"el-header\"===t||\"el-footer\"===t}))}}},cm=um,hm=a(cm,am,lm,!1,null,null,null);hm.options.__file=\"packages/container/src/main.vue\";var dm=hm.exports;dm.install=function(e){e.component(dm.name,dm)};var pm=dm,fm=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"header\",{staticClass:\"el-header\",style:{height:e.height}},[e._t(\"default\")],2)},mm=[];fm._withStripped=!0;var vm={name:\"ElHeader\",componentName:\"ElHeader\",props:{height:{type:String,default:\"60px\"}}},gm=vm,bm=a(gm,fm,mm,!1,null,null,null);bm.options.__file=\"packages/header/src/main.vue\";var ym=bm.exports;ym.install=function(e){e.component(ym.name,ym)};var _m=ym,xm=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"aside\",{staticClass:\"el-aside\",style:{width:e.width}},[e._t(\"default\")],2)},Cm=[];xm._withStripped=!0;var wm={name:\"ElAside\",componentName:\"ElAside\",props:{width:{type:String,default:\"300px\"}}},km=wm,Sm=a(km,xm,Cm,!1,null,null,null);Sm.options.__file=\"packages/aside/src/main.vue\";var $m=Sm.exports;$m.install=function(e){e.component($m.name,$m)};var Dm=$m,Em=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"main\",{staticClass:\"el-main\"},[e._t(\"default\")],2)},Tm=[];Em._withStripped=!0;var Om={name:\"ElMain\",componentName:\"ElMain\"},Im=Om,Pm=a(Im,Em,Tm,!1,null,null,null);Pm.options.__file=\"packages/main/src/main.vue\";var Mm=Pm.exports;Mm.install=function(e){e.component(Mm.name,Mm)};var Nm=Mm,Fm=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"footer\",{staticClass:\"el-footer\",style:{height:e.height}},[e._t(\"default\")],2)},Am=[];Fm._withStripped=!0;var Lm={name:\"ElFooter\",componentName:\"ElFooter\",props:{height:{type:String,default:\"60px\"}}},Vm=Lm,Bm=a(Vm,Fm,Am,!1,null,null,null);Bm.options.__file=\"packages/footer/src/main.vue\";var zm=Bm.exports;zm.install=function(e){e.component(zm.name,zm)};var jm=zm,Hm=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"ul\",{staticClass:\"el-timeline\",class:{\"is-reverse\":e.reverse}},[e._t(\"default\")],2)},Rm=[];Hm._withStripped=!0;var Wm={name:\"ElTimeline\",props:{reverse:{type:Boolean,default:!1}},provide:function(){return{timeline:this}},watch:{reverse:{handler:function(e){e&&(this.$slots.default=[].concat(this.$slots.default).reverse())},immediate:!0}}},qm=Wm,Km=a(qm,Hm,Rm,!1,null,null,null);Km.options.__file=\"packages/timeline/src/main.vue\";var Ym=Km.exports;Ym.install=function(e){e.component(Ym.name,Ym)};var Um=Ym,Gm=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"li\",{staticClass:\"el-timeline-item\"},[i(\"div\",{staticClass:\"el-timeline-item__tail\"}),e.$slots.dot?e._e():i(\"div\",{staticClass:\"el-timeline-item__node\",class:[\"el-timeline-item__node--\"+(e.size||\"\"),\"el-timeline-item__node--\"+(e.type||\"\")],style:{backgroundColor:e.color}},[e.icon?i(\"i\",{staticClass:\"el-timeline-item__icon\",class:e.icon}):e._e()]),e.$slots.dot?i(\"div\",{staticClass:\"el-timeline-item__dot\"},[e._t(\"dot\")],2):e._e(),i(\"div\",{staticClass:\"el-timeline-item__wrapper\"},[e.hideTimestamp||\"top\"!==e.placement?e._e():i(\"div\",{staticClass:\"el-timeline-item__timestamp is-top\"},[e._v(\"\\n      \"+e._s(e.timestamp)+\"\\n    \")]),i(\"div\",{staticClass:\"el-timeline-item__content\"},[e._t(\"default\")],2),e.hideTimestamp||\"bottom\"!==e.placement?e._e():i(\"div\",{staticClass:\"el-timeline-item__timestamp is-bottom\"},[e._v(\"\\n      \"+e._s(e.timestamp)+\"\\n    \")])])])},Xm=[];Gm._withStripped=!0;var Qm={name:\"ElTimelineItem\",inject:[\"timeline\"],props:{timestamp:String,hideTimestamp:{type:Boolean,default:!1},placement:{type:String,default:\"bottom\"},type:String,color:String,size:{type:String,default:\"normal\"},icon:String}},Jm=Qm,Zm=a(Jm,Gm,Xm,!1,null,null,null);Zm.options.__file=\"packages/timeline/src/item.vue\";var ev=Zm.exports;ev.install=function(e){e.component(ev.name,ev)};var tv=ev,iv=[_,M,se,pe,_e,De,qe,et,ut,vt,Ot,Vt,qt,Zt,oi,pi,_i,Di,Ni,cn,hn,bn,Sn,Pn,Ms,Hs,Qo,ua,Ca,Ia,Ma,ul,vl,wl,Vl,ru,fu,yu,Uu,ic,Ic,ih,sh,ah,zh,Yh,ed,xd,Ed,Fd,Hd,Gd,sp,up,gp,kp,Ip,Kp,Yf,om,pm,_m,Dm,Nm,jm,Um,tv,Ye.a],nv=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};en.a.use(t.locale),en.a.i18n(t.i18n),iv.forEach(function(t){e.component(t.name,t)}),e.use(Gc.directive),e.prototype.$ELEMENT={size:t.size||\"\",zIndex:t.zIndex||2e3},e.prototype.$loading=Gc.service,e.prototype.$msgbox=il,e.prototype.$alert=il.alert,e.prototype.$confirm=il.confirm,e.prototype.$prompt=il.prompt,e.prototype.$notify=vc,e.prototype.$message=fd};\"undefined\"!==typeof window&&window.Vue&&nv(window.Vue);t[\"default\"]={version:\"2.7.2\",locale:en.a.use,i18n:en.a.i18n,install:nv,CollapseTransition:Ye.a,Loading:Gc,Pagination:_,Dialog:M,Autocomplete:se,Dropdown:pe,DropdownMenu:_e,DropdownItem:De,Menu:qe,Submenu:et,MenuItem:ut,MenuItemGroup:vt,Input:Ot,InputNumber:Vt,Radio:qt,RadioGroup:Zt,RadioButton:oi,Checkbox:pi,CheckboxButton:_i,CheckboxGroup:Di,Switch:Ni,Select:cn,Option:hn,OptionGroup:bn,Button:Sn,ButtonGroup:Pn,Table:Ms,TableColumn:Hs,DatePicker:Qo,TimeSelect:ua,TimePicker:Ca,Popover:Ia,Tooltip:Ma,MessageBox:il,Breadcrumb:ul,BreadcrumbItem:vl,Form:wl,FormItem:Vl,Tabs:ru,TabPane:fu,Tag:yu,Tree:Uu,Alert:ic,Notification:vc,Slider:Ic,Icon:ih,Row:sh,Col:ah,Upload:zh,Progress:Yh,Spinner:ed,Message:fd,Badge:xd,Card:Ed,Rate:Fd,Steps:Hd,Step:Gd,Carousel:sp,Scrollbar:up,CarouselItem:gp,Collapse:kp,CollapseItem:Ip,Cascader:Kp,ColorPicker:Yf,Transfer:om,Container:pm,Header:_m,Aside:Dm,Main:Nm,Footer:jm,Timeline:Um,TimelineItem:tv}}])[\"default\"]},6167:function(e,t,i){\"use strict\";var n,s;\"function\"===typeof Symbol&&Symbol.iterator;(function(r,o){n=o,s=\"function\"===typeof n?n.call(t,i,t,e):n,void 0===s||(e.exports=s)})(0,function(){var e=window,t={placement:\"bottom\",gpuAcceleration:!0,offset:0,boundariesElement:\"viewport\",boundariesPadding:5,preventOverflowOrder:[\"left\",\"right\",\"top\",\"bottom\"],flipBehavior:\"flip\",arrowElement:\"[x-arrow]\",arrowOffset:0,modifiers:[\"shift\",\"offset\",\"preventOverflow\",\"keepTogether\",\"arrow\",\"flip\",\"applyStyle\"],modifiersIgnored:[],forceAbsolute:!1};function i(e,i,n){this._reference=e.jquery?e[0]:e,this.state={};var s=\"undefined\"===typeof i||null===i,r=i&&\"[object Object]\"===Object.prototype.toString.call(i);return this._popper=s||r?this.parse(r?i:{}):i.jquery?i[0]:i,this._options=Object.assign({},t,n),this._options.modifiers=this._options.modifiers.map(function(e){if(-1===this._options.modifiersIgnored.indexOf(e))return\"applyStyle\"===e&&this._popper.setAttribute(\"x-placement\",this._options.placement),this.modifiers[e]||e}.bind(this)),this.state.position=this._getPosition(this._popper,this._reference),h(this._popper,{position:this.state.position,top:0}),this.update(),this._setupEventListeners(),this}function n(t){var i=t.style.display,n=t.style.visibility;t.style.display=\"block\",t.style.visibility=\"hidden\";t.offsetWidth;var s=e.getComputedStyle(t),r=parseFloat(s.marginTop)+parseFloat(s.marginBottom),o=parseFloat(s.marginLeft)+parseFloat(s.marginRight),a={width:t.offsetWidth+o,height:t.offsetHeight+r};return t.style.display=i,t.style.visibility=n,a}function s(e){var t={left:\"right\",right:\"left\",bottom:\"top\",top:\"bottom\"};return e.replace(/left|right|bottom|top/g,function(e){return t[e]})}function r(e){var t=Object.assign({},e);return t.right=t.left+t.width,t.bottom=t.top+t.height,t}function o(e,t){var i,n=0;for(i in e){if(e[i]===t)return n;n++}return null}function a(t,i){var n=e.getComputedStyle(t,null);return n[i]}function l(t){var i=t.offsetParent;return i!==e.document.body&&i?i:e.document.documentElement}function u(t){var i=t.parentNode;return i?i===e.document?e.document.body.scrollTop||e.document.body.scrollLeft?e.document.body:e.document.documentElement:-1!==[\"scroll\",\"auto\"].indexOf(a(i,\"overflow\"))||-1!==[\"scroll\",\"auto\"].indexOf(a(i,\"overflow-x\"))||-1!==[\"scroll\",\"auto\"].indexOf(a(i,\"overflow-y\"))?i:u(t.parentNode):t}function c(t){return t!==e.document.body&&(\"fixed\"===a(t,\"position\")||(t.parentNode?c(t.parentNode):t))}function h(e,t){function i(e){return\"\"!==e&&!isNaN(parseFloat(e))&&isFinite(e)}Object.keys(t).forEach(function(n){var s=\"\";-1!==[\"width\",\"height\",\"top\",\"right\",\"bottom\",\"left\"].indexOf(n)&&i(t[n])&&(s=\"px\"),e.style[n]=t[n]+s})}function d(e){var t={};return e&&\"[object Function]\"===t.toString.call(e)}function p(e){var t={width:e.offsetWidth,height:e.offsetHeight,left:e.offsetLeft,top:e.offsetTop};return t.right=t.left+t.width,t.bottom=t.top+t.height,t}function f(e){var t=e.getBoundingClientRect(),i=-1!=navigator.userAgent.indexOf(\"MSIE\"),n=i&&\"HTML\"===e.tagName?-e.scrollTop:t.top;return{left:t.left,top:n,right:t.right,bottom:t.bottom,width:t.right-t.left,height:t.bottom-n}}function m(e,t,i){var n=f(e),s=f(t);if(i){var r=u(t);s.top+=r.scrollTop,s.bottom+=r.scrollTop,s.left+=r.scrollLeft,s.right+=r.scrollLeft}var o={top:n.top-s.top,left:n.left-s.left,bottom:n.top-s.top+n.height,right:n.left-s.left+n.width,width:n.width,height:n.height};return o}function v(t){for(var i=[\"\",\"ms\",\"webkit\",\"moz\",\"o\"],n=0;n<i.length;n++){var s=i[n]?i[n]+t.charAt(0).toUpperCase()+t.slice(1):t;if(\"undefined\"!==typeof e.document.body.style[s])return s}return null}return i.prototype.destroy=function(){return this._popper.removeAttribute(\"x-placement\"),this._popper.style.left=\"\",this._popper.style.position=\"\",this._popper.style.top=\"\",this._popper.style[v(\"transform\")]=\"\",this._removeEventListeners(),this._options.removeOnDestroy&&this._popper.remove(),this},i.prototype.update=function(){var e={instance:this,styles:{}};e.placement=this._options.placement,e._originalPlacement=this._options.placement,e.offsets=this._getOffsets(this._popper,this._reference,e.placement),e.boundaries=this._getBoundaries(e,this._options.boundariesPadding,this._options.boundariesElement),e=this.runModifiers(e,this._options.modifiers),\"function\"===typeof this.state.updateCallback&&this.state.updateCallback(e)},i.prototype.onCreate=function(e){return e(this),this},i.prototype.onUpdate=function(e){return this.state.updateCallback=e,this},i.prototype.parse=function(t){var i={tagName:\"div\",classNames:[\"popper\"],attributes:[],parent:e.document.body,content:\"\",contentType:\"text\",arrowTagName:\"div\",arrowClassNames:[\"popper__arrow\"],arrowAttributes:[\"x-arrow\"]};t=Object.assign({},i,t);var n=e.document,s=n.createElement(t.tagName);if(a(s,t.classNames),l(s,t.attributes),\"node\"===t.contentType?s.appendChild(t.content.jquery?t.content[0]:t.content):\"html\"===t.contentType?s.innerHTML=t.content:s.textContent=t.content,t.arrowTagName){var r=n.createElement(t.arrowTagName);a(r,t.arrowClassNames),l(r,t.arrowAttributes),s.appendChild(r)}var o=t.parent.jquery?t.parent[0]:t.parent;if(\"string\"===typeof o){if(o=n.querySelectorAll(t.parent),o.length>1&&console.warn(\"WARNING: the given `parent` query(\"+t.parent+\") matched more than one element, the first one will be used\"),0===o.length)throw\"ERROR: the given `parent` doesn't exists!\";o=o[0]}return o.length>1&&o instanceof Element===!1&&(console.warn(\"WARNING: you have passed as parent a list of elements, the first one will be used\"),o=o[0]),o.appendChild(s),s;function a(e,t){t.forEach(function(t){e.classList.add(t)})}function l(e,t){t.forEach(function(t){e.setAttribute(t.split(\":\")[0],t.split(\":\")[1]||\"\")})}},i.prototype._getPosition=function(e,t){var i=l(t);if(this._options.forceAbsolute)return\"absolute\";var n=c(t,i);return n?\"fixed\":\"absolute\"},i.prototype._getOffsets=function(e,t,i){i=i.split(\"-\")[0];var s={};s.position=this.state.position;var r=\"fixed\"===s.position,o=m(t,l(e),r),a=n(e);return-1!==[\"right\",\"left\"].indexOf(i)?(s.top=o.top+o.height/2-a.height/2,s.left=\"left\"===i?o.left-a.width:o.right):(s.left=o.left+o.width/2-a.width/2,s.top=\"top\"===i?o.top-a.height:o.bottom),s.width=a.width,s.height=a.height,{popper:s,reference:o}},i.prototype._setupEventListeners=function(){if(this.state.updateBound=this.update.bind(this),e.addEventListener(\"resize\",this.state.updateBound),\"window\"!==this._options.boundariesElement){var t=u(this._reference);t!==e.document.body&&t!==e.document.documentElement||(t=e),t.addEventListener(\"scroll\",this.state.updateBound),this.state.scrollTarget=t}},i.prototype._removeEventListeners=function(){e.removeEventListener(\"resize\",this.state.updateBound),\"window\"!==this._options.boundariesElement&&this.state.scrollTarget&&(this.state.scrollTarget.removeEventListener(\"scroll\",this.state.updateBound),this.state.scrollTarget=null),this.state.updateBound=null},i.prototype._getBoundaries=function(t,i,n){var s,r,o={};if(\"window\"===n){var a=e.document.body,c=e.document.documentElement;r=Math.max(a.scrollHeight,a.offsetHeight,c.clientHeight,c.scrollHeight,c.offsetHeight),s=Math.max(a.scrollWidth,a.offsetWidth,c.clientWidth,c.scrollWidth,c.offsetWidth),o={top:0,right:s,bottom:r,left:0}}else if(\"viewport\"===n){var h=l(this._popper),d=u(this._popper),f=p(h),m=function(e){return e==document.body?Math.max(document.documentElement.scrollTop,document.body.scrollTop):e.scrollTop},v=function(e){return e==document.body?Math.max(document.documentElement.scrollLeft,document.body.scrollLeft):e.scrollLeft},g=\"fixed\"===t.offsets.popper.position?0:m(d),b=\"fixed\"===t.offsets.popper.position?0:v(d);o={top:0-(f.top-g),right:e.document.documentElement.clientWidth-(f.left-b),bottom:e.document.documentElement.clientHeight-(f.top-g),left:0-(f.left-b)}}else o=l(this._popper)===n?{top:0,left:0,right:n.clientWidth,bottom:n.clientHeight}:p(n);return o.left+=i,o.right-=i,o.top=o.top+i,o.bottom=o.bottom-i,o},i.prototype.runModifiers=function(e,t,i){var n=t.slice();return void 0!==i&&(n=this._options.modifiers.slice(0,o(this._options.modifiers,i))),n.forEach(function(t){d(t)&&(e=t.call(this,e))}.bind(this)),e},i.prototype.isModifierRequired=function(e,t){var i=o(this._options.modifiers,e);return!!this._options.modifiers.slice(0,i).filter(function(e){return e===t}).length},i.prototype.modifiers={},i.prototype.modifiers.applyStyle=function(e){var t,i={position:e.offsets.popper.position},n=Math.round(e.offsets.popper.left),s=Math.round(e.offsets.popper.top);return this._options.gpuAcceleration&&(t=v(\"transform\"))?(i[t]=\"translate3d(\"+n+\"px, \"+s+\"px, 0)\",i.top=0,i.left=0):(i.left=n,i.top=s),Object.assign(i,e.styles),h(this._popper,i),this._popper.setAttribute(\"x-placement\",e.placement),this.isModifierRequired(this.modifiers.applyStyle,this.modifiers.arrow)&&e.offsets.arrow&&h(e.arrowElement,e.offsets.arrow),e},i.prototype.modifiers.shift=function(e){var t=e.placement,i=t.split(\"-\")[0],n=t.split(\"-\")[1];if(n){var s=e.offsets.reference,o=r(e.offsets.popper),a={y:{start:{top:s.top},end:{top:s.top+s.height-o.height}},x:{start:{left:s.left},end:{left:s.left+s.width-o.width}}},l=-1!==[\"bottom\",\"top\"].indexOf(i)?\"x\":\"y\";e.offsets.popper=Object.assign(o,a[l][n])}return e},i.prototype.modifiers.preventOverflow=function(e){var t=this._options.preventOverflowOrder,i=r(e.offsets.popper),n={left:function(){var t=i.left;return i.left<e.boundaries.left&&(t=Math.max(i.left,e.boundaries.left)),{left:t}},right:function(){var t=i.left;return i.right>e.boundaries.right&&(t=Math.min(i.left,e.boundaries.right-i.width)),{left:t}},top:function(){var t=i.top;return i.top<e.boundaries.top&&(t=Math.max(i.top,e.boundaries.top)),{top:t}},bottom:function(){var t=i.top;return i.bottom>e.boundaries.bottom&&(t=Math.min(i.top,e.boundaries.bottom-i.height)),{top:t}}};return t.forEach(function(t){e.offsets.popper=Object.assign(i,n[t]())}),e},i.prototype.modifiers.keepTogether=function(e){var t=r(e.offsets.popper),i=e.offsets.reference,n=Math.floor;return t.right<n(i.left)&&(e.offsets.popper.left=n(i.left)-t.width),t.left>n(i.right)&&(e.offsets.popper.left=n(i.right)),t.bottom<n(i.top)&&(e.offsets.popper.top=n(i.top)-t.height),t.top>n(i.bottom)&&(e.offsets.popper.top=n(i.bottom)),e},i.prototype.modifiers.flip=function(e){if(!this.isModifierRequired(this.modifiers.flip,this.modifiers.preventOverflow))return console.warn(\"WARNING: preventOverflow modifier is required by flip modifier in order to work, be sure to include it before flip!\"),e;if(e.flipped&&e.placement===e._originalPlacement)return e;var t=e.placement.split(\"-\")[0],i=s(t),n=e.placement.split(\"-\")[1]||\"\",o=[];return o=\"flip\"===this._options.flipBehavior?[t,i]:this._options.flipBehavior,o.forEach(function(a,l){if(t===a&&o.length!==l+1){t=e.placement.split(\"-\")[0],i=s(t);var u=r(e.offsets.popper),c=-1!==[\"right\",\"bottom\"].indexOf(t);(c&&Math.floor(e.offsets.reference[t])>Math.floor(u[i])||!c&&Math.floor(e.offsets.reference[t])<Math.floor(u[i]))&&(e.flipped=!0,e.placement=o[l+1],n&&(e.placement+=\"-\"+n),e.offsets.popper=this._getOffsets(this._popper,this._reference,e.placement).popper,e=this.runModifiers(e,this._options.modifiers,this._flip))}}.bind(this)),e},i.prototype.modifiers.offset=function(e){var t=this._options.offset,i=e.offsets.popper;return-1!==e.placement.indexOf(\"left\")?i.top-=t:-1!==e.placement.indexOf(\"right\")?i.top+=t:-1!==e.placement.indexOf(\"top\")?i.left-=t:-1!==e.placement.indexOf(\"bottom\")&&(i.left+=t),e},i.prototype.modifiers.arrow=function(e){var t=this._options.arrowElement,i=this._options.arrowOffset;if(\"string\"===typeof t&&(t=this._popper.querySelector(t)),!t)return e;if(!this._popper.contains(t))return console.warn(\"WARNING: `arrowElement` must be child of its popper element!\"),e;if(!this.isModifierRequired(this.modifiers.arrow,this.modifiers.keepTogether))return console.warn(\"WARNING: keepTogether modifier is required by arrow modifier in order to work, be sure to include it before arrow!\"),e;var s={},o=e.placement.split(\"-\")[0],a=r(e.offsets.popper),l=e.offsets.reference,u=-1!==[\"left\",\"right\"].indexOf(o),c=u?\"height\":\"width\",h=u?\"top\":\"left\",d=u?\"left\":\"top\",p=u?\"bottom\":\"right\",f=n(t)[c];l[p]-f<a[h]&&(e.offsets.popper[h]-=a[h]-(l[p]-f)),l[h]+f>a[p]&&(e.offsets.popper[h]+=l[h]+f-a[p]);var m=l[h]+(i||l[c]/2-f/2),v=m-a[h];return v=Math.max(Math.min(a[c]-f-8,v),8),s[h]=v,s[d]=\"\",e.offsets.arrow=s,e.arrowElement=t,e},Object.assign||Object.defineProperty(Object,\"assign\",{enumerable:!1,configurable:!0,writable:!0,value:function(e){if(void 0===e||null===e)throw new TypeError(\"Cannot convert first argument to object\");for(var t=Object(e),i=1;i<arguments.length;i++){var n=arguments[i];if(void 0!==n&&null!==n){n=Object(n);for(var s=Object.keys(n),r=0,o=s.length;r<o;r++){var a=s[r],l=Object.getOwnPropertyDescriptor(n,a);void 0!==l&&l.enumerable&&(t[a]=n[a])}}}return t}}),i})},\"6b7c\":function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(\"4897\");t.default={methods:{t:function(){for(var e=arguments.length,t=Array(e),i=0;i<e;i++)t[i]=arguments[i];return n.t.apply(this,t)}}}},\"722f\":function(e,t,i){\"use strict\";t.__esModule=!0;var n=\"function\"===typeof Symbol&&\"symbol\"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},s=i(\"e452\"),r=o(s);function o(e){return e&&e.__esModule?e:{default:e}}var a,l=l||{};l.Dialog=function(e,t,i){var s=this;if(this.dialogNode=e,null===this.dialogNode||\"dialog\"!==this.dialogNode.getAttribute(\"role\"))throw new Error(\"Dialog() requires a DOM element with ARIA role of dialog.\");\"string\"===typeof t?this.focusAfterClosed=document.getElementById(t):\"object\"===(\"undefined\"===typeof t?\"undefined\":n(t))?this.focusAfterClosed=t:this.focusAfterClosed=null,\"string\"===typeof i?this.focusFirst=document.getElementById(i):\"object\"===(\"undefined\"===typeof i?\"undefined\":n(i))?this.focusFirst=i:this.focusFirst=null,this.focusFirst?this.focusFirst.focus():r.default.focusFirstDescendant(this.dialogNode),this.lastFocus=document.activeElement,a=function(e){s.trapFocus(e)},this.addListeners()},l.Dialog.prototype.addListeners=function(){document.addEventListener(\"focus\",a,!0)},l.Dialog.prototype.removeListeners=function(){document.removeEventListener(\"focus\",a,!0)},l.Dialog.prototype.closeDialog=function(){var e=this;this.removeListeners(),this.focusAfterClosed&&setTimeout(function(){e.focusAfterClosed.focus()})},l.Dialog.prototype.trapFocus=function(e){r.default.IgnoreUtilFocusChanges||(this.dialogNode.contains(e.target)?this.lastFocus=e.target:(r.default.focusFirstDescendant(this.dialogNode),this.lastFocus===document.activeElement&&r.default.focusLastDescendant(this.dialogNode),this.lastFocus=document.activeElement))},t.default=l.Dialog},\"7f4d\":function(e,t,i){\"use strict\";t.__esModule=!0,t.default=function(e){for(var t=1,i=arguments.length;t<i;t++){var n=arguments[t]||{};for(var s in n)if(n.hasOwnProperty(s)){var r=n[s];void 0!==r&&(e[s]=r)}}return e}},\"7fc1\":function(e,t,i){e.exports=function(e){var t={};function i(n){if(t[n])return t[n].exports;var s=t[n]={i:n,l:!1,exports:{}};return e[n].call(s.exports,s,s.exports,i),s.l=!0,s.exports}return i.m=e,i.c=t,i.d=function(e,t,n){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},i.r=function(e){\"undefined\"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(e,\"__esModule\",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&\"object\"===typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,\"default\",{enumerable:!0,value:e}),2&t&&\"string\"!=typeof e)for(var s in e)i.d(n,s,function(t){return e[t]}.bind(null,s));return n},i.n=function(e){var t=e&&e.__esModule?function(){return e[\"default\"]}:function(){return e};return i.d(t,\"a\",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p=\"/dist/\",i(i.s=100)}({0:function(e,t,i){\"use strict\";function n(e,t,i,n,s,r,o,a){var l,u=\"function\"===typeof e?e.options:e;if(t&&(u.render=t,u.staticRenderFns=i,u._compiled=!0),n&&(u.functional=!0),r&&(u._scopeId=\"data-v-\"+r),o?(l=function(e){e=e||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext,e||\"undefined\"===typeof __VUE_SSR_CONTEXT__||(e=__VUE_SSR_CONTEXT__),s&&s.call(this,e),e&&e._registeredComponents&&e._registeredComponents.add(o)},u._ssrRegister=l):s&&(l=a?function(){s.call(this,this.$root.$options.shadowRoot)}:s),l)if(u.functional){u._injectStyles=l;var c=u.render;u.render=function(e,t){return l.call(t),c(e,t)}}else{var h=u.beforeCreate;u.beforeCreate=h?[].concat(h,l):[l]}return{exports:e,options:u}}i.d(t,\"a\",function(){return n})},100:function(e,t,i){\"use strict\";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-checkbox-group\",attrs:{role:\"group\",\"aria-label\":\"checkbox-group\"}},[e._t(\"default\")],2)},s=[];n._withStripped=!0;var r=i(3),o=i.n(r),a={name:\"ElCheckboxGroup\",componentName:\"ElCheckboxGroup\",mixins:[o.a],inject:{elFormItem:{default:\"\"}},props:{value:{},disabled:Boolean,min:Number,max:Number,size:String,fill:String,textColor:String},computed:{_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},checkboxGroupSize:function(){return this.size||this._elFormItemSize||(this.$ELEMENT||{}).size}},watch:{value:function(e){this.dispatch(\"ElFormItem\",\"el.form.change\",[e])}}},l=a,u=i(0),c=Object(u[\"a\"])(l,n,s,!1,null,null,null);c.options.__file=\"packages/checkbox/src/checkbox-group.vue\";var h=c.exports;h.install=function(e){e.component(h.name,h)};t[\"default\"]=h},3:function(e,t){e.exports=i(\"d010\")}})},8122:function(e,t,i){\"use strict\";t.__esModule=!0,t.isEdge=t.isIE=t.coerceTruthyValueToArray=t.arrayFind=t.arrayFindIndex=t.escapeRegexpString=t.valueEquals=t.generateId=t.getValueByPath=void 0,t.noop=a,t.hasOwn=l,t.toObject=c,t.getPropByPath=h;var n=i(\"2b0e\"),s=r(n);function r(e){return e&&e.__esModule?e:{default:e}}var o=Object.prototype.hasOwnProperty;function a(){}function l(e,t){return o.call(e,t)}function u(e,t){for(var i in t)e[i]=t[i];return e}function c(e){for(var t={},i=0;i<e.length;i++)e[i]&&u(t,e[i]);return t}t.getValueByPath=function(e,t){t=t||\"\";for(var i=t.split(\".\"),n=e,s=null,r=0,o=i.length;r<o;r++){var a=i[r];if(!n)break;if(r===o-1){s=n[a];break}n=n[a]}return s};function h(e,t,i){var n=e;t=t.replace(/\\[(\\w+)\\]/g,\".$1\"),t=t.replace(/^\\./,\"\");for(var s=t.split(\".\"),r=0,o=s.length;r<o-1;++r){if(!n&&!i)break;var a=s[r];if(!(a in n)){if(i)throw new Error(\"please transfer a valid prop path to form item!\");break}n=n[a]}return{o:n,k:s[r],v:n?n[s[r]]:null}}t.generateId=function(){return Math.floor(1e4*Math.random())},t.valueEquals=function(e,t){if(e===t)return!0;if(!(e instanceof Array))return!1;if(!(t instanceof Array))return!1;if(e.length!==t.length)return!1;for(var i=0;i!==e.length;++i)if(e[i]!==t[i])return!1;return!0},t.escapeRegexpString=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:\"\";return String(e).replace(/[|\\\\{}()[\\]^$+*?.]/g,\"\\\\$&\")};var d=t.arrayFindIndex=function(e,t){for(var i=0;i!==e.length;++i)if(t(e[i]))return i;return-1};t.arrayFind=function(e,t){var i=d(e,t);return-1!==i?e[i]:void 0},t.coerceTruthyValueToArray=function(e){return Array.isArray(e)?e:e?[e]:[]},t.isIE=function(){return!s.default.prototype.$isServer&&!isNaN(Number(document.documentMode))},t.isEdge=function(){return!s.default.prototype.$isServer&&navigator.userAgent.indexOf(\"Edge\")>-1}},\"845f\":function(e,t,i){e.exports=function(e){var t={};function i(n){if(t[n])return t[n].exports;var s=t[n]={i:n,l:!1,exports:{}};return e[n].call(s.exports,s,s.exports,i),s.l=!0,s.exports}return i.m=e,i.c=t,i.d=function(e,t,n){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},i.r=function(e){\"undefined\"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(e,\"__esModule\",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&\"object\"===typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,\"default\",{enumerable:!0,value:e}),2&t&&\"string\"!=typeof e)for(var s in e)i.d(n,s,function(t){return e[t]}.bind(null,s));return n},i.n=function(e){var t=e&&e.__esModule?function(){return e[\"default\"]}:function(){return e};return i.d(t,\"a\",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p=\"/dist/\",i(i.s=103)}({0:function(e,t,i){\"use strict\";function n(e,t,i,n,s,r,o,a){var l,u=\"function\"===typeof e?e.options:e;if(t&&(u.render=t,u.staticRenderFns=i,u._compiled=!0),n&&(u.functional=!0),r&&(u._scopeId=\"data-v-\"+r),o?(l=function(e){e=e||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext,e||\"undefined\"===typeof __VUE_SSR_CONTEXT__||(e=__VUE_SSR_CONTEXT__),s&&s.call(this,e),e&&e._registeredComponents&&e._registeredComponents.add(o)},u._ssrRegister=l):s&&(l=a?function(){s.call(this,this.$root.$options.shadowRoot)}:s),l)if(u.functional){u._injectStyles=l;var c=u.render;u.render=function(e,t){return l.call(t),c(e,t)}}else{var h=u.beforeCreate;u.beforeCreate=h?[].concat(h,l):[l]}return{exports:e,options:u}}i.d(t,\"a\",function(){return n})},103:function(e,t,i){\"use strict\";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-button-group\"},[e._t(\"default\")],2)},s=[];n._withStripped=!0;var r={name:\"ElButtonGroup\"},o=r,a=i(0),l=Object(a[\"a\"])(o,n,s,!1,null,null,null);l.options.__file=\"packages/button/src/button-group.vue\";var u=l.exports;u.install=function(e){e.component(u.name,u)};t[\"default\"]=u}})},\"8bbc\":function(e,t,i){e.exports=function(e){var t={};function i(n){if(t[n])return t[n].exports;var s=t[n]={i:n,l:!1,exports:{}};return e[n].call(s.exports,s,s.exports,i),s.l=!0,s.exports}return i.m=e,i.c=t,i.d=function(e,t,n){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},i.r=function(e){\"undefined\"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(e,\"__esModule\",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&\"object\"===typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,\"default\",{enumerable:!0,value:e}),2&t&&\"string\"!=typeof e)for(var s in e)i.d(n,s,function(t){return e[t]}.bind(null,s));return n},i.n=function(e){var t=e&&e.__esModule?function(){return e[\"default\"]}:function(){return e};return i.d(t,\"a\",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p=\"/dist/\",i(i.s=110)}({0:function(e,t,i){\"use strict\";function n(e,t,i,n,s,r,o,a){var l,u=\"function\"===typeof e?e.options:e;if(t&&(u.render=t,u.staticRenderFns=i,u._compiled=!0),n&&(u.functional=!0),r&&(u._scopeId=\"data-v-\"+r),o?(l=function(e){e=e||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext,e||\"undefined\"===typeof __VUE_SSR_CONTEXT__||(e=__VUE_SSR_CONTEXT__),s&&s.call(this,e),e&&e._registeredComponents&&e._registeredComponents.add(o)},u._ssrRegister=l):s&&(l=a?function(){s.call(this,this.$root.$options.shadowRoot)}:s),l)if(u.functional){u._injectStyles=l;var c=u.render;u.render=function(e,t){return l.call(t),c(e,t)}}else{var h=u.beforeCreate;u.beforeCreate=h?[].concat(h,l):[l]}return{exports:e,options:u}}i.d(t,\"a\",function(){return n})},110:function(e,t,i){\"use strict\";i.r(t);var n,s,r={name:\"ElTag\",props:{text:String,closable:Boolean,type:String,hit:Boolean,disableTransitions:Boolean,color:String,size:String},methods:{handleClose:function(e){e.stopPropagation(),this.$emit(\"close\",e)},handleClick:function(e){e.stopPropagation(),this.$emit(\"click\",e)}},computed:{tagSize:function(){return this.size||(this.$ELEMENT||{}).size}},render:function(e){var t=[\"el-tag\",this.type?\"el-tag--\"+this.type:\"\",this.tagSize?\"el-tag--\"+this.tagSize:\"\",{\"is-hit\":this.hit}],i=e(\"span\",{class:t,style:{backgroundColor:this.color},on:{click:this.handleClick}},[this.$slots.default,this.closable&&e(\"i\",{class:\"el-tag__close el-icon-close\",on:{click:this.handleClose}})]);return this.disableTransitions?i:e(\"transition\",{attrs:{name:\"el-zoom-in-center\"}},[i])}},o=r,a=i(0),l=Object(a[\"a\"])(o,n,s,!1,null,null,null);l.options.__file=\"packages/tag/src/tag.vue\";var u=l.exports;u.install=function(e){e.component(u.name,u)};t[\"default\"]=u}})},\"9d7e\":function(e,t,i){\"use strict\";t.__esModule=!0;var n=\"function\"===typeof Symbol&&\"symbol\"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e};t.default=function(e){function t(e){for(var t=arguments.length,i=Array(t>1?t-1:0),o=1;o<t;o++)i[o-1]=arguments[o];return 1===i.length&&\"object\"===n(i[0])&&(i=i[0]),i&&i.hasOwnProperty||(i={}),e.replace(r,function(t,n,r,o){var a=void 0;return\"{\"===e[o-1]&&\"}\"===e[o+t.length]?r:(a=(0,s.hasOwn)(i,r)?i[r]:null,null===a||void 0===a?\"\":a)})}return t};var s=i(\"8122\"),r=/(%|)\\{([0-9a-zA-Z_]+)\\}/g},b2d6:function(e,t,i){\"use strict\";t.__esModule=!0,t.default={el:{colorpicker:{confirm:\"OK\",clear:\"Clear\"},datepicker:{now:\"Now\",today:\"Today\",cancel:\"Cancel\",clear:\"Clear\",confirm:\"OK\",selectDate:\"Select date\",selectTime:\"Select time\",startDate:\"Start Date\",startTime:\"Start Time\",endDate:\"End Date\",endTime:\"End Time\",prevYear:\"Previous Year\",nextYear:\"Next Year\",prevMonth:\"Previous Month\",nextMonth:\"Next Month\",year:\"\",month1:\"January\",month2:\"February\",month3:\"March\",month4:\"April\",month5:\"May\",month6:\"June\",month7:\"July\",month8:\"August\",month9:\"September\",month10:\"October\",month11:\"November\",month12:\"December\",week:\"week\",weeks:{sun:\"Sun\",mon:\"Mon\",tue:\"Tue\",wed:\"Wed\",thu:\"Thu\",fri:\"Fri\",sat:\"Sat\"},months:{jan:\"Jan\",feb:\"Feb\",mar:\"Mar\",apr:\"Apr\",may:\"May\",jun:\"Jun\",jul:\"Jul\",aug:\"Aug\",sep:\"Sep\",oct:\"Oct\",nov:\"Nov\",dec:\"Dec\"}},select:{loading:\"Loading\",noMatch:\"No matching data\",noData:\"No data\",placeholder:\"Select\"},cascader:{noMatch:\"No matching data\",loading:\"Loading\",placeholder:\"Select\"},pagination:{goto:\"Go to\",pagesize:\"/page\",total:\"Total {total}\",pageClassifier:\"\"},messagebox:{title:\"Message\",confirm:\"OK\",cancel:\"Cancel\",error:\"Illegal input\"},upload:{deleteTip:\"press delete to remove\",delete:\"Delete\",preview:\"Preview\",continue:\"Continue\"},table:{emptyText:\"No Data\",confirmFilter:\"Confirm\",resetFilter:\"Reset\",clearFilter:\"All\",sumText:\"Sum\"},tree:{emptyText:\"No Data\"},transfer:{noMatch:\"No matching data\",noData:\"No data\",titles:[\"List 1\",\"List 2\"],filterPlaceholder:\"Enter keyword\",noCheckedFormat:\"{total} items\",hasCheckedFormat:\"{checked}/{total} checked\"}}}},c284:function(e,t,i){e.exports=function(e){var t={};function i(n){if(t[n])return t[n].exports;var s=t[n]={i:n,l:!1,exports:{}};return e[n].call(s.exports,s,s.exports,i),s.l=!0,s.exports}return i.m=e,i.c=t,i.d=function(e,t,n){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},i.r=function(e){\"undefined\"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(e,\"__esModule\",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&\"object\"===typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,\"default\",{enumerable:!0,value:e}),2&t&&\"string\"!=typeof e)for(var s in e)i.d(n,s,function(t){return e[t]}.bind(null,s));return n},i.n=function(e){var t=e&&e.__esModule?function(){return e[\"default\"]}:function(){return e};return i.d(t,\"a\",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p=\"/dist/\",i(i.s=74)}({0:function(e,t,i){\"use strict\";function n(e,t,i,n,s,r,o,a){var l,u=\"function\"===typeof e?e.options:e;if(t&&(u.render=t,u.staticRenderFns=i,u._compiled=!0),n&&(u.functional=!0),r&&(u._scopeId=\"data-v-\"+r),o?(l=function(e){e=e||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext,e||\"undefined\"===typeof __VUE_SSR_CONTEXT__||(e=__VUE_SSR_CONTEXT__),s&&s.call(this,e),e&&e._registeredComponents&&e._registeredComponents.add(o)},u._ssrRegister=l):s&&(l=a?function(){s.call(this,this.$root.$options.shadowRoot)}:s),l)if(u.functional){u._injectStyles=l;var c=u.render;u.render=function(e,t){return l.call(t),c(e,t)}}else{var h=u.beforeCreate;u.beforeCreate=h?[].concat(h,l):[l]}return{exports:e,options:u}}i.d(t,\"a\",function(){return n})},74:function(e,t,i){\"use strict\";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-progress\",class:[\"el-progress--\"+e.type,e.status?\"is-\"+e.status:\"\",{\"el-progress--without-text\":!e.showText,\"el-progress--text-inside\":e.textInside}],attrs:{role:\"progressbar\",\"aria-valuenow\":e.percentage,\"aria-valuemin\":\"0\",\"aria-valuemax\":\"100\"}},[\"line\"===e.type?i(\"div\",{staticClass:\"el-progress-bar\"},[i(\"div\",{staticClass:\"el-progress-bar__outer\",style:{height:e.strokeWidth+\"px\"}},[i(\"div\",{staticClass:\"el-progress-bar__inner\",style:e.barStyle},[e.showText&&e.textInside?i(\"div\",{staticClass:\"el-progress-bar__innerText\"},[e._v(e._s(e.percentage)+\"%\")]):e._e()])])]):i(\"div\",{staticClass:\"el-progress-circle\",style:{height:e.width+\"px\",width:e.width+\"px\"}},[i(\"svg\",{attrs:{viewBox:\"0 0 100 100\"}},[i(\"path\",{staticClass:\"el-progress-circle__track\",attrs:{d:e.trackPath,stroke:\"#e5e9f2\",\"stroke-width\":e.relativeStrokeWidth,fill:\"none\"}}),i(\"path\",{staticClass:\"el-progress-circle__path\",style:e.circlePathStyle,attrs:{d:e.trackPath,\"stroke-linecap\":\"round\",stroke:e.stroke,\"stroke-width\":e.relativeStrokeWidth,fill:\"none\"}})])]),e.showText&&!e.textInside?i(\"div\",{staticClass:\"el-progress__text\",style:{fontSize:e.progressTextSize+\"px\"}},[e.status?[\"text\"===e.status?e._t(\"default\"):i(\"i\",{class:e.iconClass})]:[e._v(e._s(e.percentage)+\"%\")]],2):e._e()])},s=[];n._withStripped=!0;var r={name:\"ElProgress\",props:{type:{type:String,default:\"line\",validator:function(e){return[\"line\",\"circle\"].indexOf(e)>-1}},percentage:{type:Number,default:0,required:!0,validator:function(e){return e>=0&&e<=100}},status:{type:String,validator:function(e){return[\"text\",\"success\",\"exception\"].indexOf(e)>-1}},strokeWidth:{type:Number,default:6},textInside:{type:Boolean,default:!1},width:{type:Number,default:126},showText:{type:Boolean,default:!0},color:{type:String,default:\"\"}},computed:{barStyle:function(){var e={};return e.width=this.percentage+\"%\",e.backgroundColor=this.color,e},relativeStrokeWidth:function(){return(this.strokeWidth/this.width*100).toFixed(1)},trackPath:function(){var e=parseInt(50-parseFloat(this.relativeStrokeWidth)/2,10);return\"M 50 50 m 0 -\"+e+\" a \"+e+\" \"+e+\" 0 1 1 0 \"+2*e+\" a \"+e+\" \"+e+\" 0 1 1 0 -\"+2*e},perimeter:function(){var e=50-parseFloat(this.relativeStrokeWidth)/2;return 2*Math.PI*e},circlePathStyle:function(){var e=this.perimeter;return{strokeDasharray:e+\"px,\"+e+\"px\",strokeDashoffset:(1-this.percentage/100)*e+\"px\",transition:\"stroke-dashoffset 0.6s ease 0s, stroke 0.6s ease\"}},stroke:function(){var e=void 0;if(this.color)e=this.color;else switch(this.status){case\"success\":e=\"#13ce66\";break;case\"exception\":e=\"#ff4949\";break;default:e=\"#20a0ff\"}return e},iconClass:function(){return\"line\"===this.type?\"success\"===this.status?\"el-icon-circle-check\":\"el-icon-circle-close\":\"success\"===this.status?\"el-icon-check\":\"el-icon-close\"},progressTextSize:function(){return\"line\"===this.type?12+.4*this.strokeWidth:.111111*this.width+2}}},o=r,a=i(0),l=Object(a[\"a\"])(o,n,s,!1,null,null,null);l.options.__file=\"packages/progress/src/progress.vue\";var u=l.exports;u.install=function(e){e.component(u.name,u)};t[\"default\"]=u}})},c56a:function(e,t,i){\"use strict\";t.__esModule=!0,t.default=function(e,t){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:300,n=arguments.length>3&&void 0!==arguments[3]&&arguments[3];if(!e||!t)throw new Error(\"instance & callback is required\");var s=!1,r=function(){s||(s=!0,t&&t.apply(null,arguments))};n?e.$once(\"after-leave\",r):e.$on(\"after-leave\",r),setTimeout(function(){r()},i+100)}},d010:function(e,t,i){\"use strict\";function n(e,t,i){this.$children.forEach(function(s){var r=s.$options.componentName;r===e?s.$emit.apply(s,[t].concat(i)):n.apply(s,[e,t].concat([i]))})}t.__esModule=!0,t.default={methods:{dispatch:function(e,t,i){var n=this.$parent||this.$root,s=n.$options.componentName;while(n&&(!s||s!==e))n=n.$parent,n&&(s=n.$options.componentName);n&&n.$emit.apply(n,[t].concat(i))},broadcast:function(e,t,i){n.call(this,e,t,i)}}}},d397:function(e,t,i){\"use strict\";function n(e){return void 0!==e&&null!==e}function s(e){var t=/([(\\uAC00-\\uD7AF)|(\\u3130-\\u318F)])+/gi;return t.test(e)}t.__esModule=!0,t.isDef=n,t.isKorean=s},d7d1:function(e,t,i){\"use strict\";var n;(function(s){var r={},o=/d{1,4}|M{1,4}|yy(?:yy)?|S{1,3}|Do|ZZ|([HhMsDm])\\1?|[aA]|\"[^\"]*\"|'[^']*'/g,a=/\\d\\d?/,l=/\\d{3}/,u=/\\d{4}/,c=/[0-9]*['a-z\\u00A0-\\u05FF\\u0700-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]+|[\\u0600-\\u06FF\\/]+(\\s*?[\\u0600-\\u06FF]+){1,2}/i,h=function(){};function d(e,t){for(var i=[],n=0,s=e.length;n<s;n++)i.push(e[n].substr(0,t));return i}function p(e){return function(t,i,n){var s=n[e].indexOf(i.charAt(0).toUpperCase()+i.substr(1).toLowerCase());~s&&(t.month=s)}}function f(e,t){e=String(e),t=t||2;while(e.length<t)e=\"0\"+e;return e}var m=[\"Sunday\",\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\"],v=[\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\"],g=d(v,3),b=d(m,3);r.i18n={dayNamesShort:b,dayNames:m,monthNamesShort:g,monthNames:v,amPm:[\"am\",\"pm\"],DoFn:function(e){return e+[\"th\",\"st\",\"nd\",\"rd\"][e%10>3?0:(e-e%10!==10)*e%10]}};var y={D:function(e){return e.getDay()},DD:function(e){return f(e.getDay())},Do:function(e,t){return t.DoFn(e.getDate())},d:function(e){return e.getDate()},dd:function(e){return f(e.getDate())},ddd:function(e,t){return t.dayNamesShort[e.getDay()]},dddd:function(e,t){return t.dayNames[e.getDay()]},M:function(e){return e.getMonth()+1},MM:function(e){return f(e.getMonth()+1)},MMM:function(e,t){return t.monthNamesShort[e.getMonth()]},MMMM:function(e,t){return t.monthNames[e.getMonth()]},yy:function(e){return String(e.getFullYear()).substr(2)},yyyy:function(e){return e.getFullYear()},h:function(e){return e.getHours()%12||12},hh:function(e){return f(e.getHours()%12||12)},H:function(e){return e.getHours()},HH:function(e){return f(e.getHours())},m:function(e){return e.getMinutes()},mm:function(e){return f(e.getMinutes())},s:function(e){return e.getSeconds()},ss:function(e){return f(e.getSeconds())},S:function(e){return Math.round(e.getMilliseconds()/100)},SS:function(e){return f(Math.round(e.getMilliseconds()/10),2)},SSS:function(e){return f(e.getMilliseconds(),3)},a:function(e,t){return e.getHours()<12?t.amPm[0]:t.amPm[1]},A:function(e,t){return e.getHours()<12?t.amPm[0].toUpperCase():t.amPm[1].toUpperCase()},ZZ:function(e){var t=e.getTimezoneOffset();return(t>0?\"-\":\"+\")+f(100*Math.floor(Math.abs(t)/60)+Math.abs(t)%60,4)}},_={d:[a,function(e,t){e.day=t}],M:[a,function(e,t){e.month=t-1}],yy:[a,function(e,t){var i=new Date,n=+(\"\"+i.getFullYear()).substr(0,2);e.year=\"\"+(t>68?n-1:n)+t}],h:[a,function(e,t){e.hour=t}],m:[a,function(e,t){e.minute=t}],s:[a,function(e,t){e.second=t}],yyyy:[u,function(e,t){e.year=t}],S:[/\\d/,function(e,t){e.millisecond=100*t}],SS:[/\\d{2}/,function(e,t){e.millisecond=10*t}],SSS:[l,function(e,t){e.millisecond=t}],D:[a,h],ddd:[c,h],MMM:[c,p(\"monthNamesShort\")],MMMM:[c,p(\"monthNames\")],a:[c,function(e,t,i){var n=t.toLowerCase();n===i.amPm[0]?e.isPm=!1:n===i.amPm[1]&&(e.isPm=!0)}],ZZ:[/[\\+\\-]\\d\\d:?\\d\\d/,function(e,t){var i,n=(t+\"\").match(/([\\+\\-]|\\d\\d)/gi);n&&(i=60*n[1]+parseInt(n[2],10),e.timezoneOffset=\"+\"===n[0]?i:-i)}]};_.DD=_.D,_.dddd=_.ddd,_.Do=_.dd=_.d,_.mm=_.m,_.hh=_.H=_.HH=_.h,_.MM=_.M,_.ss=_.s,_.A=_.a,r.masks={default:\"ddd MMM dd yyyy HH:mm:ss\",shortDate:\"M/D/yy\",mediumDate:\"MMM d, yyyy\",longDate:\"MMMM d, yyyy\",fullDate:\"dddd, MMMM d, yyyy\",shortTime:\"HH:mm\",mediumTime:\"HH:mm:ss\",longTime:\"HH:mm:ss.SSS\"},r.format=function(e,t,i){var n=i||r.i18n;if(\"number\"===typeof e&&(e=new Date(e)),\"[object Date]\"!==Object.prototype.toString.call(e)||isNaN(e.getTime()))throw new Error(\"Invalid Date in fecha.format\");return t=r.masks[t]||t||r.masks[\"default\"],t.replace(o,function(t){return t in y?y[t](e,n):t.slice(1,t.length-1)})},r.parse=function(e,t,i){var n=i||r.i18n;if(\"string\"!==typeof t)throw new Error(\"Invalid format in fecha.parse\");if(t=r.masks[t]||t,e.length>1e3)return!1;var s=!0,a={};if(t.replace(o,function(t){if(_[t]){var i=_[t],r=e.search(i[0]);~r?e.replace(i[0],function(t){return i[1](a,t,n),e=e.substr(r+t.length),t}):s=!1}return _[t]?\"\":t.slice(1,t.length-1)}),!s)return!1;var l,u=new Date;return!0===a.isPm&&null!=a.hour&&12!==+a.hour?a.hour=+a.hour+12:!1===a.isPm&&12===+a.hour&&(a.hour=0),null!=a.timezoneOffset?(a.minute=+(a.minute||0)-+a.timezoneOffset,l=new Date(Date.UTC(a.year||u.getFullYear(),a.month||0,a.day||1,a.hour||0,a.minute||0,a.second||0,a.millisecond||0))):l=new Date(a.year||u.getFullYear(),a.month||0,a.day||1,a.hour||0,a.minute||0,a.second||0,a.millisecond||0),l},e.exports?e.exports=r:(n=function(){return r}.call(t,i,t,e),void 0===n||(e.exports=n))})()},dcdc:function(e,t,i){e.exports=function(e){var t={};function i(n){if(t[n])return t[n].exports;var s=t[n]={i:n,l:!1,exports:{}};return e[n].call(s.exports,s,s.exports,i),s.l=!0,s.exports}return i.m=e,i.c=t,i.d=function(e,t,n){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},i.r=function(e){\"undefined\"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(e,\"__esModule\",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&\"object\"===typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,\"default\",{enumerable:!0,value:e}),2&t&&\"string\"!=typeof e)for(var s in e)i.d(n,s,function(t){return e[t]}.bind(null,s));return n},i.n=function(e){var t=e&&e.__esModule?function(){return e[\"default\"]}:function(){return e};return i.d(t,\"a\",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p=\"/dist/\",i(i.s=94)}({0:function(e,t,i){\"use strict\";function n(e,t,i,n,s,r,o,a){var l,u=\"function\"===typeof e?e.options:e;if(t&&(u.render=t,u.staticRenderFns=i,u._compiled=!0),n&&(u.functional=!0),r&&(u._scopeId=\"data-v-\"+r),o?(l=function(e){e=e||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext,e||\"undefined\"===typeof __VUE_SSR_CONTEXT__||(e=__VUE_SSR_CONTEXT__),s&&s.call(this,e),e&&e._registeredComponents&&e._registeredComponents.add(o)},u._ssrRegister=l):s&&(l=a?function(){s.call(this,this.$root.$options.shadowRoot)}:s),l)if(u.functional){u._injectStyles=l;var c=u.render;u.render=function(e,t){return l.call(t),c(e,t)}}else{var h=u.beforeCreate;u.beforeCreate=h?[].concat(h,l):[l]}return{exports:e,options:u}}i.d(t,\"a\",function(){return n})},3:function(e,t){e.exports=i(\"d010\")},94:function(e,t,i){\"use strict\";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"label\",{staticClass:\"el-checkbox\",class:[e.border&&e.checkboxSize?\"el-checkbox--\"+e.checkboxSize:\"\",{\"is-disabled\":e.isDisabled},{\"is-bordered\":e.border},{\"is-checked\":e.isChecked}],attrs:{role:\"checkbox\",\"aria-checked\":e.indeterminate?\"mixed\":e.isChecked,\"aria-disabled\":e.isDisabled,id:e.id}},[i(\"span\",{staticClass:\"el-checkbox__input\",class:{\"is-disabled\":e.isDisabled,\"is-checked\":e.isChecked,\"is-indeterminate\":e.indeterminate,\"is-focus\":e.focus},attrs:{\"aria-checked\":\"mixed\"}},[i(\"span\",{staticClass:\"el-checkbox__inner\"}),e.trueLabel||e.falseLabel?i(\"input\",{directives:[{name:\"model\",rawName:\"v-model\",value:e.model,expression:\"model\"}],staticClass:\"el-checkbox__original\",attrs:{type:\"checkbox\",\"aria-hidden\":\"true\",name:e.name,disabled:e.isDisabled,\"true-value\":e.trueLabel,\"false-value\":e.falseLabel},domProps:{checked:Array.isArray(e.model)?e._i(e.model,null)>-1:e._q(e.model,e.trueLabel)},on:{change:[function(t){var i=e.model,n=t.target,s=n.checked?e.trueLabel:e.falseLabel;if(Array.isArray(i)){var r=null,o=e._i(i,r);n.checked?o<0&&(e.model=i.concat([r])):o>-1&&(e.model=i.slice(0,o).concat(i.slice(o+1)))}else e.model=s},e.handleChange],focus:function(t){e.focus=!0},blur:function(t){e.focus=!1}}}):i(\"input\",{directives:[{name:\"model\",rawName:\"v-model\",value:e.model,expression:\"model\"}],staticClass:\"el-checkbox__original\",attrs:{type:\"checkbox\",\"aria-hidden\":\"true\",disabled:e.isDisabled,name:e.name},domProps:{value:e.label,checked:Array.isArray(e.model)?e._i(e.model,e.label)>-1:e.model},on:{change:[function(t){var i=e.model,n=t.target,s=!!n.checked;if(Array.isArray(i)){var r=e.label,o=e._i(i,r);n.checked?o<0&&(e.model=i.concat([r])):o>-1&&(e.model=i.slice(0,o).concat(i.slice(o+1)))}else e.model=s},e.handleChange],focus:function(t){e.focus=!0},blur:function(t){e.focus=!1}}})]),e.$slots.default||e.label?i(\"span\",{staticClass:\"el-checkbox__label\"},[e._t(\"default\"),e.$slots.default?e._e():[e._v(e._s(e.label))]],2):e._e()])},s=[];n._withStripped=!0;var r=i(3),o=i.n(r),a={name:\"ElCheckbox\",mixins:[o.a],inject:{elForm:{default:\"\"},elFormItem:{default:\"\"}},componentName:\"ElCheckbox\",data:function(){return{selfModel:!1,focus:!1,isLimitExceeded:!1}},computed:{model:{get:function(){return this.isGroup?this.store:void 0!==this.value?this.value:this.selfModel},set:function(e){this.isGroup?(this.isLimitExceeded=!1,void 0!==this._checkboxGroup.min&&e.length<this._checkboxGroup.min&&(this.isLimitExceeded=!0),void 0!==this._checkboxGroup.max&&e.length>this._checkboxGroup.max&&(this.isLimitExceeded=!0),!1===this.isLimitExceeded&&this.dispatch(\"ElCheckboxGroup\",\"input\",[e])):(this.$emit(\"input\",e),this.selfModel=e)}},isChecked:function(){return\"[object Boolean]\"==={}.toString.call(this.model)?this.model:Array.isArray(this.model)?this.model.indexOf(this.label)>-1:null!==this.model&&void 0!==this.model?this.model===this.trueLabel:void 0},isGroup:function(){var e=this.$parent;while(e){if(\"ElCheckboxGroup\"===e.$options.componentName)return this._checkboxGroup=e,!0;e=e.$parent}return!1},store:function(){return this._checkboxGroup?this._checkboxGroup.value:this.value},isDisabled:function(){return this.isGroup?this._checkboxGroup.disabled||this.disabled||(this.elForm||{}).disabled:this.disabled||(this.elForm||{}).disabled},_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},checkboxSize:function(){var e=this.size||this._elFormItemSize||(this.$ELEMENT||{}).size;return this.isGroup&&this._checkboxGroup.checkboxGroupSize||e}},props:{value:{},label:{},indeterminate:Boolean,disabled:Boolean,checked:Boolean,name:String,trueLabel:[String,Number],falseLabel:[String,Number],id:String,controls:String,border:Boolean,size:String},methods:{addToStore:function(){Array.isArray(this.model)&&-1===this.model.indexOf(this.label)?this.model.push(this.label):this.model=this.trueLabel||!0},handleChange:function(e){var t=this;if(!this.isLimitExceeded){var i=void 0;i=e.target.checked?void 0===this.trueLabel||this.trueLabel:void 0!==this.falseLabel&&this.falseLabel,this.$emit(\"change\",i,e),this.$nextTick(function(){t.isGroup&&t.dispatch(\"ElCheckboxGroup\",\"change\",[t._checkboxGroup.value])})}}},created:function(){this.checked&&this.addToStore()},mounted:function(){this.indeterminate&&this.$el.setAttribute(\"aria-controls\",this.controls)},watch:{value:function(e){this.dispatch(\"ElFormItem\",\"el.form.change\",e)}}},l=a,u=i(0),c=Object(u[\"a\"])(l,n,s,!1,null,null,null);c.options.__file=\"packages/checkbox/src/checkbox.vue\";var h=c.exports;h.install=function(e){e.component(h.name,h)};t[\"default\"]=h}})},e450:function(e,t,i){e.exports=function(e){var t={};function i(n){if(t[n])return t[n].exports;var s=t[n]={i:n,l:!1,exports:{}};return e[n].call(s.exports,s,s.exports,i),s.l=!0,s.exports}return i.m=e,i.c=t,i.d=function(e,t,n){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},i.r=function(e){\"undefined\"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(e,\"__esModule\",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&\"object\"===typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,\"default\",{enumerable:!0,value:e}),2&t&&\"string\"!=typeof e)for(var s in e)i.d(n,s,function(t){return e[t]}.bind(null,s));return n},i.n=function(e){var t=e&&e.__esModule?function(){return e[\"default\"]}:function(){return e};return i.d(t,\"a\",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p=\"/dist/\",i(i.s=97)}({0:function(e,t,i){\"use strict\";function n(e,t,i,n,s,r,o,a){var l,u=\"function\"===typeof e?e.options:e;if(t&&(u.render=t,u.staticRenderFns=i,u._compiled=!0),n&&(u.functional=!0),r&&(u._scopeId=\"data-v-\"+r),o?(l=function(e){e=e||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext,e||\"undefined\"===typeof __VUE_SSR_CONTEXT__||(e=__VUE_SSR_CONTEXT__),s&&s.call(this,e),e&&e._registeredComponents&&e._registeredComponents.add(o)},u._ssrRegister=l):s&&(l=a?function(){s.call(this,this.$root.$options.shadowRoot)}:s),l)if(u.functional){u._injectStyles=l;var c=u.render;u.render=function(e,t){return l.call(t),c(e,t)}}else{var h=u.beforeCreate;u.beforeCreate=h?[].concat(h,l):[l]}return{exports:e,options:u}}i.d(t,\"a\",function(){return n})},2:function(e,t){e.exports=i(\"5924\")},20:function(e,t){e.exports=i(\"12f2\")},25:function(e,t,i){\"use strict\";var n=i(2);t[\"a\"]={bind:function(e,t,i){var s=null,r=void 0,o=function(){return i.context[t.expression].apply()},a=function(){new Date-r<100&&o(),clearInterval(s),s=null};Object(n[\"on\"])(e,\"mousedown\",function(e){0===e.button&&(r=new Date,Object(n[\"once\"])(document,\"mouseup\",a),clearInterval(s),s=setInterval(o,100))})}}},9:function(e,t){e.exports=i(\"f3ad\")},97:function(e,t,i){\"use strict\";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{class:[\"el-input-number\",e.inputNumberSize?\"el-input-number--\"+e.inputNumberSize:\"\",{\"is-disabled\":e.inputNumberDisabled},{\"is-without-controls\":!e.controls},{\"is-controls-right\":e.controlsAtRight}],on:{dragstart:function(e){e.preventDefault()}}},[e.controls?i(\"span\",{directives:[{name:\"repeat-click\",rawName:\"v-repeat-click\",value:e.decrease,expression:\"decrease\"}],staticClass:\"el-input-number__decrease\",class:{\"is-disabled\":e.minDisabled},attrs:{role:\"button\"},on:{keydown:function(t){return\"button\"in t||!e._k(t.keyCode,\"enter\",13,t.key,\"Enter\")?e.decrease(t):null}}},[i(\"i\",{class:\"el-icon-\"+(e.controlsAtRight?\"arrow-down\":\"minus\")})]):e._e(),e.controls?i(\"span\",{directives:[{name:\"repeat-click\",rawName:\"v-repeat-click\",value:e.increase,expression:\"increase\"}],staticClass:\"el-input-number__increase\",class:{\"is-disabled\":e.maxDisabled},attrs:{role:\"button\"},on:{keydown:function(t){return\"button\"in t||!e._k(t.keyCode,\"enter\",13,t.key,\"Enter\")?e.increase(t):null}}},[i(\"i\",{class:\"el-icon-\"+(e.controlsAtRight?\"arrow-up\":\"plus\")})]):e._e(),i(\"el-input\",{ref:\"input\",attrs:{value:e.displayValue,placeholder:e.placeholder,disabled:e.inputNumberDisabled,size:e.inputNumberSize,max:e.max,min:e.min,name:e.name,label:e.label},on:{blur:e.handleBlur,focus:e.handleFocus,input:e.handleInput,change:e.handleInputChange},nativeOn:{keydown:[function(t){return\"button\"in t||!e._k(t.keyCode,\"up\",38,t.key,[\"Up\",\"ArrowUp\"])?(t.preventDefault(),e.increase(t)):null},function(t){return\"button\"in t||!e._k(t.keyCode,\"down\",40,t.key,[\"Down\",\"ArrowDown\"])?(t.preventDefault(),e.decrease(t)):null}]}})],1)},s=[];n._withStripped=!0;var r=i(9),o=i.n(r),a=i(20),l=i.n(a),u=i(25),c={name:\"ElInputNumber\",mixins:[l()(\"input\")],inject:{elForm:{default:\"\"},elFormItem:{default:\"\"}},directives:{repeatClick:u[\"a\"]},components:{ElInput:o.a},props:{step:{type:Number,default:1},max:{type:Number,default:1/0},min:{type:Number,default:-1/0},value:{},disabled:Boolean,size:String,controls:{type:Boolean,default:!0},controlsPosition:{type:String,default:\"\"},name:String,label:String,placeholder:String,precision:{type:Number,validator:function(e){return e>=0&&e===parseInt(e,10)}}},data:function(){return{currentValue:0,userInput:null}},watch:{value:{immediate:!0,handler:function(e){var t=void 0===e?e:Number(e);if(void 0!==t){if(isNaN(t))return;void 0!==this.precision&&(t=this.toPrecision(t,this.precision))}t>=this.max&&(t=this.max),t<=this.min&&(t=this.min),this.currentValue=t,this.userInput=null,this.$emit(\"input\",t)}}},computed:{minDisabled:function(){return this._decrease(this.value,this.step)<this.min},maxDisabled:function(){return this._increase(this.value,this.step)>this.max},numPrecision:function(){var e=this.value,t=this.step,i=this.getPrecision,n=this.precision,s=i(t);return void 0!==n?(s>n&&console.warn(\"[Element Warn][InputNumber]precision should not be less than the decimal places of step\"),n):Math.max(i(e),s)},controlsAtRight:function(){return this.controls&&\"right\"===this.controlsPosition},_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},inputNumberSize:function(){return this.size||this._elFormItemSize||(this.$ELEMENT||{}).size},inputNumberDisabled:function(){return this.disabled||(this.elForm||{}).disabled},displayValue:function(){if(null!==this.userInput)return this.userInput;var e=this.currentValue;return\"number\"===typeof e&&void 0!==this.precision?e.toFixed(this.precision):e}},methods:{toPrecision:function(e,t){return void 0===t&&(t=this.numPrecision),parseFloat(Number(e).toFixed(t))},getPrecision:function(e){if(void 0===e)return 0;var t=e.toString(),i=t.indexOf(\".\"),n=0;return-1!==i&&(n=t.length-i-1),n},_increase:function(e,t){if(\"number\"!==typeof e&&void 0!==e)return this.currentValue;var i=Math.pow(10,this.numPrecision);return this.toPrecision((i*e+i*t)/i)},_decrease:function(e,t){if(\"number\"!==typeof e&&void 0!==e)return this.currentValue;var i=Math.pow(10,this.numPrecision);return this.toPrecision((i*e-i*t)/i)},increase:function(){if(!this.inputNumberDisabled&&!this.maxDisabled){var e=this.value||0,t=this._increase(e,this.step);this.setCurrentValue(t)}},decrease:function(){if(!this.inputNumberDisabled&&!this.minDisabled){var e=this.value||0,t=this._decrease(e,this.step);this.setCurrentValue(t)}},handleBlur:function(e){this.$emit(\"blur\",e)},handleFocus:function(e){this.$emit(\"focus\",e)},setCurrentValue:function(e){var t=this.currentValue;\"number\"===typeof e&&void 0!==this.precision&&(e=this.toPrecision(e,this.precision)),e>=this.max&&(e=this.max),e<=this.min&&(e=this.min),t!==e&&(this.userInput=null,this.$emit(\"input\",e),this.$emit(\"change\",e,t),this.currentValue=e)},handleInput:function(e){this.userInput=e},handleInputChange:function(e){var t=\"\"===e?void 0:Number(e);isNaN(t)&&\"\"!==e||this.setCurrentValue(t),this.userInput=null},select:function(){this.$refs.input.select()}},mounted:function(){var e=this.$refs.input.$refs.input;e.setAttribute(\"role\",\"spinbutton\"),e.setAttribute(\"aria-valuemax\",this.max),e.setAttribute(\"aria-valuemin\",this.min),e.setAttribute(\"aria-valuenow\",this.currentValue),e.setAttribute(\"aria-disabled\",this.inputNumberDisabled)},updated:function(){if(this.$refs&&this.$refs.input){var e=this.$refs.input.$refs.input;e.setAttribute(\"aria-valuenow\",this.currentValue)}}},h=c,d=i(0),p=Object(d[\"a\"])(h,n,s,!1,null,null,null);p.options.__file=\"packages/input-number/src/input-number.vue\";var f=p.exports;f.install=function(e){e.component(f.name,f)};t[\"default\"]=f}})},e452:function(e,t,i){\"use strict\";t.__esModule=!0;var n=n||{};n.Utils=n.Utils||{},n.Utils.focusFirstDescendant=function(e){for(var t=0;t<e.childNodes.length;t++){var i=e.childNodes[t];if(n.Utils.attemptFocus(i)||n.Utils.focusFirstDescendant(i))return!0}return!1},n.Utils.focusLastDescendant=function(e){for(var t=e.childNodes.length-1;t>=0;t--){var i=e.childNodes[t];if(n.Utils.attemptFocus(i)||n.Utils.focusLastDescendant(i))return!0}return!1},n.Utils.attemptFocus=function(e){if(!n.Utils.isFocusable(e))return!1;n.Utils.IgnoreUtilFocusChanges=!0;try{e.focus()}catch(t){}return n.Utils.IgnoreUtilFocusChanges=!1,document.activeElement===e},n.Utils.isFocusable=function(e){if(e.tabIndex>0||0===e.tabIndex&&null!==e.getAttribute(\"tabIndex\"))return!0;if(e.disabled)return!1;switch(e.nodeName){case\"A\":return!!e.href&&\"ignore\"!==e.rel;case\"INPUT\":return\"hidden\"!==e.type&&\"file\"!==e.type;case\"BUTTON\":case\"SELECT\":case\"TEXTAREA\":return!0;default:return!1}},n.Utils.triggerEvent=function(e,t){var i=void 0;i=/^mouse|click/.test(t)?\"MouseEvents\":/^key/.test(t)?\"KeyboardEvent\":\"HTMLEvents\";for(var n=document.createEvent(i),s=arguments.length,r=Array(s>2?s-2:0),o=2;o<s;o++)r[o-2]=arguments[o];return n.initEvent.apply(n,[t].concat(r)),e.dispatchEvent?e.dispatchEvent(n):e.fireEvent(\"on\"+t,n),e},n.Utils.keys={tab:9,enter:13,space:32,left:37,up:38,right:39,down:40},t.default=n.Utils},e62d:function(e,t,i){\"use strict\";t.__esModule=!0,t.default=function(){if(s.default.prototype.$isServer)return 0;if(void 0!==o)return o;var e=document.createElement(\"div\");e.className=\"el-scrollbar__wrap\",e.style.visibility=\"hidden\",e.style.width=\"100px\",e.style.position=\"absolute\",e.style.top=\"-9999px\",document.body.appendChild(e);var t=e.offsetWidth;e.style.overflow=\"scroll\";var i=document.createElement(\"div\");i.style.width=\"100%\",e.appendChild(i);var n=i.offsetWidth;return e.parentNode.removeChild(e),o=t-n,o};var n=i(\"2b0e\"),s=r(n);function r(e){return e&&e.__esModule?e:{default:e}}var o=void 0},e772:function(e,t,i){e.exports=function(e){var t={};function i(n){if(t[n])return t[n].exports;var s=t[n]={i:n,l:!1,exports:{}};return e[n].call(s.exports,s,s.exports,i),s.l=!0,s.exports}return i.m=e,i.c=t,i.d=function(e,t,n){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},i.r=function(e){\"undefined\"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(e,\"__esModule\",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&\"object\"===typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,\"default\",{enumerable:!0,value:e}),2&t&&\"string\"!=typeof e)for(var s in e)i.d(n,s,function(t){return e[t]}.bind(null,s));return n},i.n=function(e){var t=e&&e.__esModule?function(){return e[\"default\"]}:function(){return e};return i.d(t,\"a\",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p=\"/dist/\",i(i.s=46)}({0:function(e,t,i){\"use strict\";function n(e,t,i,n,s,r,o,a){var l,u=\"function\"===typeof e?e.options:e;if(t&&(u.render=t,u.staticRenderFns=i,u._compiled=!0),n&&(u.functional=!0),r&&(u._scopeId=\"data-v-\"+r),o?(l=function(e){e=e||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext,e||\"undefined\"===typeof __VUE_SSR_CONTEXT__||(e=__VUE_SSR_CONTEXT__),s&&s.call(this,e),e&&e._registeredComponents&&e._registeredComponents.add(o)},u._ssrRegister=l):s&&(l=a?function(){s.call(this,this.$root.$options.shadowRoot)}:s),l)if(u.functional){u._injectStyles=l;var c=u.render;u.render=function(e,t){return l.call(t),c(e,t)}}else{var h=u.beforeCreate;u.beforeCreate=h?[].concat(h,l):[l]}return{exports:e,options:u}}i.d(t,\"a\",function(){return n})},29:function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"li\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible,expression:\"visible\"}],staticClass:\"el-select-dropdown__item\",class:{selected:e.itemSelected,\"is-disabled\":e.disabled||e.groupDisabled||e.limitReached,hover:e.hover},on:{mouseenter:e.hoverItem,click:function(t){return t.stopPropagation(),e.selectOptionClick(t)}}},[e._t(\"default\",[i(\"span\",[e._v(e._s(e.currentLabel))])])],2)},s=[];n._withStripped=!0;var r=i(3),o=i.n(r),a=i(4),l=\"function\"===typeof Symbol&&\"symbol\"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},u={mixins:[o.a],name:\"ElOption\",componentName:\"ElOption\",inject:[\"select\"],props:{value:{required:!0},label:[String,Number],created:Boolean,disabled:{type:Boolean,default:!1}},data:function(){return{index:-1,groupDisabled:!1,visible:!0,hitState:!1,hover:!1}},computed:{isObject:function(){return\"[object object]\"===Object.prototype.toString.call(this.value).toLowerCase()},currentLabel:function(){return this.label||(this.isObject?\"\":this.value)},currentValue:function(){return this.value||this.label||\"\"},itemSelected:function(){return this.select.multiple?this.contains(this.select.value,this.value):this.isEqual(this.value,this.select.value)},limitReached:function(){return!!this.select.multiple&&(!this.itemSelected&&(this.select.value||[]).length>=this.select.multipleLimit&&this.select.multipleLimit>0)}},watch:{currentLabel:function(){this.created||this.select.remote||this.dispatch(\"ElSelect\",\"setSelected\")},value:function(e,t){var i=this.select,n=i.remote,s=i.valueKey;if(!this.created&&!n){if(s&&\"object\"===(\"undefined\"===typeof e?\"undefined\":l(e))&&\"object\"===(\"undefined\"===typeof t?\"undefined\":l(t))&&e[s]===t[s])return;this.dispatch(\"ElSelect\",\"setSelected\")}}},methods:{isEqual:function(e,t){if(this.isObject){var i=this.select.valueKey;return Object(a[\"getValueByPath\"])(e,i)===Object(a[\"getValueByPath\"])(t,i)}return e===t},contains:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments[1];if(this.isObject){var i=this.select.valueKey;return e.some(function(e){return Object(a[\"getValueByPath\"])(e,i)===Object(a[\"getValueByPath\"])(t,i)})}return e.indexOf(t)>-1},handleGroupDisabled:function(e){this.groupDisabled=e},hoverItem:function(){this.disabled||this.groupDisabled||(this.select.hoverIndex=this.select.options.indexOf(this))},selectOptionClick:function(){!0!==this.disabled&&!0!==this.groupDisabled&&this.dispatch(\"ElSelect\",\"handleOptionClick\",[this,!0])},queryChange:function(e){this.visible=new RegExp(Object(a[\"escapeRegexpString\"])(e),\"i\").test(this.currentLabel)||this.created,this.visible||this.select.filteredOptionsCount--}},created:function(){this.select.options.push(this),this.select.cachedOptions.push(this),this.select.optionsCount++,this.select.filteredOptionsCount++,this.$on(\"queryChange\",this.queryChange),this.$on(\"handleGroupDisabled\",this.handleGroupDisabled)},beforeDestroy:function(){this.select.onOptionDestroy(this.select.options.indexOf(this))}},c=u,h=i(0),d=Object(h[\"a\"])(c,n,s,!1,null,null,null);d.options.__file=\"packages/select/src/option.vue\";t[\"a\"]=d.exports},3:function(e,t){e.exports=i(\"d010\")},4:function(e,t){e.exports=i(\"8122\")},46:function(e,t,i){\"use strict\";i.r(t);var n=i(29);n[\"a\"].install=function(e){e.component(n[\"a\"].name,n[\"a\"])},t[\"default\"]=n[\"a\"]}})},e974:function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(\"2b0e\"),s=o(n),r=i(\"5128\");function o(e){return e&&e.__esModule?e:{default:e}}var a=s.default.prototype.$isServer?function(){}:i(\"6167\"),l=function(e){return e.stopPropagation()};t.default={props:{transformOrigin:{type:[Boolean,String],default:!0},placement:{type:String,default:\"bottom\"},boundariesPadding:{type:Number,default:5},reference:{},popper:{},offset:{default:0},value:Boolean,visibleArrow:Boolean,arrowOffset:{type:Number,default:35},appendToBody:{type:Boolean,default:!0},popperOptions:{type:Object,default:function(){return{gpuAcceleration:!1}}}},data:function(){return{showPopper:!1,currentPlacement:\"\"}},watch:{value:{immediate:!0,handler:function(e){this.showPopper=e,this.$emit(\"input\",e)}},showPopper:function(e){this.disabled||(e?this.updatePopper():this.destroyPopper(),this.$emit(\"input\",e))}},methods:{createPopper:function(){var e=this;if(!this.$isServer&&(this.currentPlacement=this.currentPlacement||this.placement,/^(top|bottom|left|right)(-start|-end)?$/g.test(this.currentPlacement))){var t=this.popperOptions,i=this.popperElm=this.popperElm||this.popper||this.$refs.popper,n=this.referenceElm=this.referenceElm||this.reference||this.$refs.reference;!n&&this.$slots.reference&&this.$slots.reference[0]&&(n=this.referenceElm=this.$slots.reference[0].elm),i&&n&&(this.visibleArrow&&this.appendArrow(i),this.appendToBody&&document.body.appendChild(this.popperElm),this.popperJS&&this.popperJS.destroy&&this.popperJS.destroy(),t.placement=this.currentPlacement,t.offset=this.offset,t.arrowOffset=this.arrowOffset,this.popperJS=new a(n,i,t),this.popperJS.onCreate(function(t){e.$emit(\"created\",e),e.resetTransformOrigin(),e.$nextTick(e.updatePopper)}),\"function\"===typeof t.onUpdate&&this.popperJS.onUpdate(t.onUpdate),this.popperJS._popper.style.zIndex=r.PopupManager.nextZIndex(),this.popperElm.addEventListener(\"click\",l))}},updatePopper:function(){var e=this.popperJS;e?(e.update(),e._popper&&(e._popper.style.zIndex=r.PopupManager.nextZIndex())):this.createPopper()},doDestroy:function(e){!this.popperJS||this.showPopper&&!e||(this.popperJS.destroy(),this.popperJS=null)},destroyPopper:function(){this.popperJS&&this.resetTransformOrigin()},resetTransformOrigin:function(){if(this.transformOrigin){var e={top:\"bottom\",bottom:\"top\",left:\"right\",right:\"left\"},t=this.popperJS._popper.getAttribute(\"x-placement\").split(\"-\")[0],i=e[t];this.popperJS._popper.style.transformOrigin=\"string\"===typeof this.transformOrigin?this.transformOrigin:[\"top\",\"bottom\"].indexOf(t)>-1?\"center \"+i:i+\" center\"}},appendArrow:function(e){var t=void 0;if(!this.appended){for(var i in this.appended=!0,e.attributes)if(/^_v-/.test(e.attributes[i].name)){t=e.attributes[i].name;break}var n=document.createElement(\"div\");t&&n.setAttribute(t,\"\"),n.setAttribute(\"x-arrow\",\"\"),n.className=\"popper__arrow\",e.appendChild(n)}}},beforeDestroy:function(){this.doDestroy(!0),this.popperElm&&this.popperElm.parentNode===document.body&&(this.popperElm.removeEventListener(\"click\",l),document.body.removeChild(this.popperElm))},deactivated:function(){this.$options.beforeDestroy[0].call(this)}}},eedf:function(e,t,i){e.exports=function(e){var t={};function i(n){if(t[n])return t[n].exports;var s=t[n]={i:n,l:!1,exports:{}};return e[n].call(s.exports,s,s.exports,i),s.l=!0,s.exports}return i.m=e,i.c=t,i.d=function(e,t,n){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},i.r=function(e){\"undefined\"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(e,\"__esModule\",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&\"object\"===typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,\"default\",{enumerable:!0,value:e}),2&t&&\"string\"!=typeof e)for(var s in e)i.d(n,s,function(t){return e[t]}.bind(null,s));return n},i.n=function(e){var t=e&&e.__esModule?function(){return e[\"default\"]}:function(){return e};return i.d(t,\"a\",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p=\"/dist/\",i(i.s=104)}({0:function(e,t,i){\"use strict\";function n(e,t,i,n,s,r,o,a){var l,u=\"function\"===typeof e?e.options:e;if(t&&(u.render=t,u.staticRenderFns=i,u._compiled=!0),n&&(u.functional=!0),r&&(u._scopeId=\"data-v-\"+r),o?(l=function(e){e=e||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext,e||\"undefined\"===typeof __VUE_SSR_CONTEXT__||(e=__VUE_SSR_CONTEXT__),s&&s.call(this,e),e&&e._registeredComponents&&e._registeredComponents.add(o)},u._ssrRegister=l):s&&(l=a?function(){s.call(this,this.$root.$options.shadowRoot)}:s),l)if(u.functional){u._injectStyles=l;var c=u.render;u.render=function(e,t){return l.call(t),c(e,t)}}else{var h=u.beforeCreate;u.beforeCreate=h?[].concat(h,l):[l]}return{exports:e,options:u}}i.d(t,\"a\",function(){return n})},104:function(e,t,i){\"use strict\";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"button\",{staticClass:\"el-button\",class:[e.type?\"el-button--\"+e.type:\"\",e.buttonSize?\"el-button--\"+e.buttonSize:\"\",{\"is-disabled\":e.buttonDisabled,\"is-loading\":e.loading,\"is-plain\":e.plain,\"is-round\":e.round,\"is-circle\":e.circle}],attrs:{disabled:e.buttonDisabled||e.loading,autofocus:e.autofocus,type:e.nativeType},on:{click:e.handleClick}},[e.loading?i(\"i\",{staticClass:\"el-icon-loading\"}):e._e(),e.icon&&!e.loading?i(\"i\",{class:e.icon}):e._e(),e.$slots.default?i(\"span\",[e._t(\"default\")],2):e._e()])},s=[];n._withStripped=!0;var r={name:\"ElButton\",inject:{elForm:{default:\"\"},elFormItem:{default:\"\"}},props:{type:{type:String,default:\"default\"},size:String,icon:{type:String,default:\"\"},nativeType:{type:String,default:\"button\"},loading:Boolean,disabled:Boolean,plain:Boolean,autofocus:Boolean,round:Boolean,circle:Boolean},computed:{_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},buttonSize:function(){return this.size||this._elFormItemSize||(this.$ELEMENT||{}).size},buttonDisabled:function(){return this.disabled||(this.elForm||{}).disabled}},methods:{handleClick:function(e){this.$emit(\"click\",e)}}},o=r,a=i(0),l=Object(a[\"a\"])(o,n,s,!1,null,null,null);l.options.__file=\"packages/button/src/button.vue\";var u=l.exports;u.install=function(e){e.component(u.name,u)};t[\"default\"]=u}})},f0d9:function(e,t,i){\"use strict\";t.__esModule=!0,t.default={el:{colorpicker:{confirm:\"确定\",clear:\"清空\"},datepicker:{now:\"此刻\",today:\"今天\",cancel:\"取消\",clear:\"清空\",confirm:\"确定\",selectDate:\"选择日期\",selectTime:\"选择时间\",startDate:\"开始日期\",startTime:\"开始时间\",endDate:\"结束日期\",endTime:\"结束时间\",prevYear:\"前一年\",nextYear:\"后一年\",prevMonth:\"上个月\",nextMonth:\"下个月\",year:\"年\",month1:\"1 月\",month2:\"2 月\",month3:\"3 月\",month4:\"4 月\",month5:\"5 月\",month6:\"6 月\",month7:\"7 月\",month8:\"8 月\",month9:\"9 月\",month10:\"10 月\",month11:\"11 月\",month12:\"12 月\",weeks:{sun:\"日\",mon:\"一\",tue:\"二\",wed:\"三\",thu:\"四\",fri:\"五\",sat:\"六\"},months:{jan:\"一月\",feb:\"二月\",mar:\"三月\",apr:\"四月\",may:\"五月\",jun:\"六月\",jul:\"七月\",aug:\"八月\",sep:\"九月\",oct:\"十月\",nov:\"十一月\",dec:\"十二月\"}},select:{loading:\"加载中\",noMatch:\"无匹配数据\",noData:\"无数据\",placeholder:\"请选择\"},cascader:{noMatch:\"无匹配数据\",loading:\"加载中\",placeholder:\"请选择\"},pagination:{goto:\"前往\",pagesize:\"条/页\",total:\"共 {total} 条\",pageClassifier:\"页\"},messagebox:{title:\"提示\",confirm:\"确定\",cancel:\"取消\",error:\"输入的数据不合法!\"},upload:{deleteTip:\"按 delete 键可删除\",delete:\"删除\",preview:\"查看图片\",continue:\"继续上传\"},table:{emptyText:\"暂无数据\",confirmFilter:\"筛选\",resetFilter:\"重置\",clearFilter:\"全部\",sumText:\"合计\"},tree:{emptyText:\"暂无数据\"},transfer:{noMatch:\"无匹配数据\",noData:\"无数据\",titles:[\"列表 1\",\"列表 2\"],filterPlaceholder:\"请输入搜索内容\",noCheckedFormat:\"共 {total} 项\",hasCheckedFormat:\"已选 {checked}/{total} 项\"}}}},f3ad:function(e,t,i){e.exports=function(e){var t={};function i(n){if(t[n])return t[n].exports;var s=t[n]={i:n,l:!1,exports:{}};return e[n].call(s.exports,s,s.exports,i),s.l=!0,s.exports}return i.m=e,i.c=t,i.d=function(e,t,n){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},i.r=function(e){\"undefined\"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(e,\"__esModule\",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&\"object\"===typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,\"default\",{enumerable:!0,value:e}),2&t&&\"string\"!=typeof e)for(var s in e)i.d(n,s,function(t){return e[t]}.bind(null,s));return n},i.n=function(e){var t=e&&e.__esModule?function(){return e[\"default\"]}:function(){return e};return i.d(t,\"a\",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p=\"/dist/\",i(i.s=61)}({0:function(e,t,i){\"use strict\";function n(e,t,i,n,s,r,o,a){var l,u=\"function\"===typeof e?e.options:e;if(t&&(u.render=t,u.staticRenderFns=i,u._compiled=!0),n&&(u.functional=!0),r&&(u._scopeId=\"data-v-\"+r),o?(l=function(e){e=e||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext,e||\"undefined\"===typeof __VUE_SSR_CONTEXT__||(e=__VUE_SSR_CONTEXT__),s&&s.call(this,e),e&&e._registeredComponents&&e._registeredComponents.add(o)},u._ssrRegister=l):s&&(l=a?function(){s.call(this,this.$root.$options.shadowRoot)}:s),l)if(u.functional){u._injectStyles=l;var c=u.render;u.render=function(e,t){return l.call(t),c(e,t)}}else{var h=u.beforeCreate;u.beforeCreate=h?[].concat(h,l):[l]}return{exports:e,options:u}}i.d(t,\"a\",function(){return n})},10:function(e,t){e.exports=i(\"2bb5\")},3:function(e,t){e.exports=i(\"d010\")},61:function(e,t,i){\"use strict\";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{class:[\"textarea\"===e.type?\"el-textarea\":\"el-input\",e.inputSize?\"el-input--\"+e.inputSize:\"\",{\"is-disabled\":e.inputDisabled,\"el-input-group\":e.$slots.prepend||e.$slots.append,\"el-input-group--append\":e.$slots.append,\"el-input-group--prepend\":e.$slots.prepend,\"el-input--prefix\":e.$slots.prefix||e.prefixIcon,\"el-input--suffix\":e.$slots.suffix||e.suffixIcon||e.clearable||e.showPassword}],on:{mouseenter:function(t){e.hovering=!0},mouseleave:function(t){e.hovering=!1}}},[\"textarea\"!==e.type?[e.$slots.prepend?i(\"div\",{staticClass:\"el-input-group__prepend\"},[e._t(\"prepend\")],2):e._e(),\"textarea\"!==e.type?i(\"input\",e._b({ref:\"input\",staticClass:\"el-input__inner\",attrs:{tabindex:e.tabindex,type:e.showPassword?e.passwordVisible?\"text\":\"password\":e.type,disabled:e.inputDisabled,readonly:e.readonly,autocomplete:e.autoComplete||e.autocomplete,\"aria-label\":e.label},on:{compositionstart:e.handleCompositionStart,compositionend:e.handleCompositionEnd,input:e.handleInput,focus:e.handleFocus,blur:e.handleBlur,change:e.handleChange}},\"input\",e.$attrs,!1)):e._e(),e.$slots.prefix||e.prefixIcon?i(\"span\",{staticClass:\"el-input__prefix\"},[e._t(\"prefix\"),e.prefixIcon?i(\"i\",{staticClass:\"el-input__icon\",class:e.prefixIcon}):e._e()],2):e._e(),e.$slots.suffix||e.suffixIcon||e.showClear||e.showPassword||e.validateState&&e.needStatusIcon?i(\"span\",{staticClass:\"el-input__suffix\"},[i(\"span\",{staticClass:\"el-input__suffix-inner\"},[e.showClear&&e.showPwdVisible?e._e():[e._t(\"suffix\"),e.suffixIcon?i(\"i\",{staticClass:\"el-input__icon\",class:e.suffixIcon}):e._e()],e.showClear?i(\"i\",{staticClass:\"el-input__icon el-icon-circle-close el-input__clear\",on:{click:e.clear}}):e._e(),e.showPwdVisible?i(\"i\",{staticClass:\"el-input__icon el-icon-view el-input__clear\",on:{click:e.handlePasswordVisible}}):e._e()],2),e.validateState?i(\"i\",{staticClass:\"el-input__icon\",class:[\"el-input__validateIcon\",e.validateIcon]}):e._e()]):e._e(),e.$slots.append?i(\"div\",{staticClass:\"el-input-group__append\"},[e._t(\"append\")],2):e._e()]:i(\"textarea\",e._b({ref:\"textarea\",staticClass:\"el-textarea__inner\",style:e.textareaStyle,attrs:{tabindex:e.tabindex,disabled:e.inputDisabled,readonly:e.readonly,autocomplete:e.autoComplete||e.autocomplete,\"aria-label\":e.label},on:{compositionstart:e.handleCompositionStart,compositionend:e.handleCompositionEnd,input:e.handleInput,focus:e.handleFocus,blur:e.handleBlur,change:e.handleChange}},\"textarea\",e.$attrs,!1))],2)},s=[];n._withStripped=!0;var r=i(3),o=i.n(r),a=i(10),l=i.n(a),u=void 0,c=\"\\n  height:0 !important;\\n  visibility:hidden !important;\\n  overflow:hidden !important;\\n  position:absolute !important;\\n  z-index:-1000 !important;\\n  top:0 !important;\\n  right:0 !important\\n\",h=[\"letter-spacing\",\"line-height\",\"padding-top\",\"padding-bottom\",\"font-family\",\"font-weight\",\"font-size\",\"text-rendering\",\"text-transform\",\"width\",\"text-indent\",\"padding-left\",\"padding-right\",\"border-width\",\"box-sizing\"];function d(e){var t=window.getComputedStyle(e),i=t.getPropertyValue(\"box-sizing\"),n=parseFloat(t.getPropertyValue(\"padding-bottom\"))+parseFloat(t.getPropertyValue(\"padding-top\")),s=parseFloat(t.getPropertyValue(\"border-bottom-width\"))+parseFloat(t.getPropertyValue(\"border-top-width\")),r=h.map(function(e){return e+\":\"+t.getPropertyValue(e)}).join(\";\");return{contextStyle:r,paddingSize:n,borderSize:s,boxSizing:i}}function p(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;u||(u=document.createElement(\"textarea\"),document.body.appendChild(u));var n=d(e),s=n.paddingSize,r=n.borderSize,o=n.boxSizing,a=n.contextStyle;u.setAttribute(\"style\",a+\";\"+c),u.value=e.value||e.placeholder||\"\";var l=u.scrollHeight,h={};\"border-box\"===o?l+=r:\"content-box\"===o&&(l-=s),u.value=\"\";var p=u.scrollHeight-s;if(null!==t){var f=p*t;\"border-box\"===o&&(f=f+s+r),l=Math.max(f,l),h.minHeight=f+\"px\"}if(null!==i){var m=p*i;\"border-box\"===o&&(m=m+s+r),l=Math.min(m,l)}return h.height=l+\"px\",u.parentNode&&u.parentNode.removeChild(u),u=null,h}var f=i(8),m=i.n(f),v={name:\"ElInput\",componentName:\"ElInput\",mixins:[o.a,l.a],inheritAttrs:!1,inject:{elForm:{default:\"\"},elFormItem:{default:\"\"}},data:function(){return{textareaCalcStyle:{},hovering:!1,focused:!1,isComposing:!1,passwordVisible:!1}},props:{value:[String,Number],size:String,resize:String,form:String,disabled:Boolean,readonly:Boolean,type:{type:String,default:\"text\"},autosize:{type:[Boolean,Object],default:!1},autocomplete:{type:String,default:\"off\"},autoComplete:{type:String,validator:function(e){return!0}},validateEvent:{type:Boolean,default:!0},suffixIcon:String,prefixIcon:String,label:String,clearable:{type:Boolean,default:!1},showPassword:{type:Boolean,default:!1},tabindex:String},computed:{_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},validateState:function(){return this.elFormItem?this.elFormItem.validateState:\"\"},needStatusIcon:function(){return!!this.elForm&&this.elForm.statusIcon},validateIcon:function(){return{validating:\"el-icon-loading\",success:\"el-icon-circle-check\",error:\"el-icon-circle-close\"}[this.validateState]},textareaStyle:function(){return m()({},this.textareaCalcStyle,{resize:this.resize})},inputSize:function(){return this.size||this._elFormItemSize||(this.$ELEMENT||{}).size},inputDisabled:function(){return this.disabled||(this.elForm||{}).disabled},nativeInputValue:function(){return null===this.value||void 0===this.value?\"\":String(this.value)},showClear:function(){return this.clearable&&!this.inputDisabled&&!this.readonly&&this.nativeInputValue&&(this.focused||this.hovering)},showPwdVisible:function(){return this.showPassword&&!this.inputDisabled&&!this.readonly&&(!!this.nativeInputValue||this.focused)}},watch:{value:function(e){this.$nextTick(this.resizeTextarea),this.validateEvent&&this.dispatch(\"ElFormItem\",\"el.form.change\",[e])},nativeInputValue:function(){this.setNativeInputValue()},type:function(){var e=this;this.$nextTick(function(){e.setNativeInputValue(),e.resizeTextarea(),e.updateIconOffset()})}},methods:{focus:function(){this.getInput().focus()},blur:function(){this.getInput().blur()},getMigratingConfig:function(){return{props:{icon:\"icon is removed, use suffix-icon / prefix-icon instead.\",\"on-icon-click\":\"on-icon-click is removed.\"},events:{click:\"click is removed.\"}}},handleBlur:function(e){this.focused=!1,this.$emit(\"blur\",e),this.validateEvent&&this.dispatch(\"ElFormItem\",\"el.form.blur\",[this.value])},select:function(){this.getInput().select()},resizeTextarea:function(){if(!this.$isServer){var e=this.autosize,t=this.type;if(\"textarea\"===t)if(e){var i=e.minRows,n=e.maxRows;this.textareaCalcStyle=p(this.$refs.textarea,i,n)}else this.textareaCalcStyle={minHeight:p(this.$refs.textarea).minHeight}}},setNativeInputValue:function(){var e=this.getInput();e&&e.value!==this.nativeInputValue&&(e.value=this.nativeInputValue)},handleFocus:function(e){this.focused=!0,this.$emit(\"focus\",e)},handleCompositionStart:function(){this.isComposing=!0},handleCompositionEnd:function(e){this.isComposing=!1,this.handleInput(e)},handleInput:function(e){this.isComposing||e.target.value!==this.nativeInputValue&&(this.$emit(\"input\",e.target.value),this.$nextTick(this.setNativeInputValue))},handleChange:function(e){this.$emit(\"change\",e.target.value)},calcIconOffset:function(e){var t=[].slice.call(this.$el.querySelectorAll(\".el-input__\"+e)||[]);if(t.length){for(var i=null,n=0;n<t.length;n++)if(t[n].parentNode===this.$el){i=t[n];break}if(i){var s={suffix:\"append\",prefix:\"prepend\"},r=s[e];this.$slots[r]?i.style.transform=\"translateX(\"+(\"suffix\"===e?\"-\":\"\")+this.$el.querySelector(\".el-input-group__\"+r).offsetWidth+\"px)\":i.removeAttribute(\"style\")}}},updateIconOffset:function(){this.calcIconOffset(\"prefix\"),this.calcIconOffset(\"suffix\")},clear:function(){this.$emit(\"input\",\"\"),this.$emit(\"change\",\"\"),this.$emit(\"clear\")},handlePasswordVisible:function(){this.passwordVisible=!this.passwordVisible,this.focus()},getInput:function(){return this.$refs.input||this.$refs.textarea}},created:function(){this.$on(\"inputSelect\",this.select)},mounted:function(){this.setNativeInputValue(),this.resizeTextarea(),this.updateIconOffset()},updated:function(){this.$nextTick(this.updateIconOffset)}},g=v,b=i(0),y=Object(b[\"a\"])(g,n,s,!1,null,null,null);y.options.__file=\"packages/input/src/input.vue\";var _=y.exports;_.install=function(e){e.component(_.name,_)};t[\"default\"]=_},8:function(e,t){e.exports=i(\"7f4d\")}})}}]);"
  },
  {
    "path": "admin/admin-web/src/main/resources/public/static/js/chunk-libs.c04beefc.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[\"chunk-libs\"],{\"014b\":function(t,e,n){\"use strict\";var r=n(\"e53d\"),o=n(\"07e3\"),i=n(\"8e60\"),a=n(\"63b6\"),s=n(\"9138\"),c=n(\"ebfd\").KEY,u=n(\"294c\"),f=n(\"dbdb\"),l=n(\"45f2\"),p=n(\"62a0\"),d=n(\"5168\"),h=n(\"ccb9\"),v=n(\"6718\"),y=n(\"47ee\"),m=n(\"9003\"),g=n(\"e4ae\"),b=n(\"f772\"),_=n(\"241e\"),w=n(\"36c3\"),x=n(\"1bc3\"),O=n(\"aebd\"),E=n(\"a159\"),S=n(\"0395\"),A=n(\"bf0b\"),C=n(\"9aa9\"),k=n(\"d9f6\"),j=n(\"c3a1\"),T=A.f,$=k.f,M=S.f,P=r.Symbol,L=r.JSON,R=L&&L.stringify,N=\"prototype\",F=d(\"_hidden\"),I=d(\"toPrimitive\"),D={}.propertyIsEnumerable,q=f(\"symbol-registry\"),U=f(\"symbols\"),B=f(\"op-symbols\"),V=Object[N],H=\"function\"==typeof P&&!!C.f,z=r.QObject,G=!z||!z[N]||!z[N].findChild,W=i&&u(function(){return 7!=E($({},\"a\",{get:function(){return $(this,\"a\",{value:7}).a}})).a})?function(t,e,n){var r=T(V,e);r&&delete V[e],$(t,e,n),r&&t!==V&&$(V,e,r)}:$,K=function(t){var e=U[t]=E(P[N]);return e._k=t,e},X=H&&\"symbol\"==typeof P.iterator?function(t){return\"symbol\"==typeof t}:function(t){return t instanceof P},J=function(t,e,n){return t===V&&J(B,e,n),g(t),e=x(e,!0),g(n),o(U,e)?(n.enumerable?(o(t,F)&&t[F][e]&&(t[F][e]=!1),n=E(n,{enumerable:O(0,!1)})):(o(t,F)||$(t,F,O(1,{})),t[F][e]=!0),W(t,e,n)):$(t,e,n)},Y=function(t,e){g(t);var n,r=y(e=w(e)),o=0,i=r.length;while(i>o)J(t,n=r[o++],e[n]);return t},Z=function(t,e){return void 0===e?E(t):Y(E(t),e)},Q=function(t){var e=D.call(this,t=x(t,!0));return!(this===V&&o(U,t)&&!o(B,t))&&(!(e||!o(this,t)||!o(U,t)||o(this,F)&&this[F][t])||e)},tt=function(t,e){if(t=w(t),e=x(e,!0),t!==V||!o(U,e)||o(B,e)){var n=T(t,e);return!n||!o(U,e)||o(t,F)&&t[F][e]||(n.enumerable=!0),n}},et=function(t){var e,n=M(w(t)),r=[],i=0;while(n.length>i)o(U,e=n[i++])||e==F||e==c||r.push(e);return r},nt=function(t){var e,n=t===V,r=M(n?B:w(t)),i=[],a=0;while(r.length>a)!o(U,e=r[a++])||n&&!o(V,e)||i.push(U[e]);return i};H||(P=function(){if(this instanceof P)throw TypeError(\"Symbol is not a constructor!\");var t=p(arguments.length>0?arguments[0]:void 0),e=function(n){this===V&&e.call(B,n),o(this,F)&&o(this[F],t)&&(this[F][t]=!1),W(this,t,O(1,n))};return i&&G&&W(V,t,{configurable:!0,set:e}),K(t)},s(P[N],\"toString\",function(){return this._k}),A.f=tt,k.f=J,n(\"6abf\").f=S.f=et,n(\"355d\").f=Q,C.f=nt,i&&!n(\"b8e3\")&&s(V,\"propertyIsEnumerable\",Q,!0),h.f=function(t){return K(d(t))}),a(a.G+a.W+a.F*!H,{Symbol:P});for(var rt=\"hasInstance,isConcatSpreadable,iterator,match,replace,search,species,split,toPrimitive,toStringTag,unscopables\".split(\",\"),ot=0;rt.length>ot;)d(rt[ot++]);for(var it=j(d.store),at=0;it.length>at;)v(it[at++]);a(a.S+a.F*!H,\"Symbol\",{for:function(t){return o(q,t+=\"\")?q[t]:q[t]=P(t)},keyFor:function(t){if(!X(t))throw TypeError(t+\" is not a symbol!\");for(var e in q)if(q[e]===t)return e},useSetter:function(){G=!0},useSimple:function(){G=!1}}),a(a.S+a.F*!H,\"Object\",{create:Z,defineProperty:J,defineProperties:Y,getOwnPropertyDescriptor:tt,getOwnPropertyNames:et,getOwnPropertySymbols:nt});var st=u(function(){C.f(1)});a(a.S+a.F*st,\"Object\",{getOwnPropertySymbols:function(t){return C.f(_(t))}}),L&&a(a.S+a.F*(!H||u(function(){var t=P();return\"[null]\"!=R([t])||\"{}\"!=R({a:t})||\"{}\"!=R(Object(t))})),\"JSON\",{stringify:function(t){var e,n,r=[t],o=1;while(arguments.length>o)r.push(arguments[o++]);if(n=e=r[1],(b(e)||void 0!==t)&&!X(t))return m(e)||(e=function(t,e){if(\"function\"==typeof n&&(e=n.call(this,t,e)),!X(e))return e}),r[1]=e,R.apply(L,r)}}),P[N][I]||n(\"35e8\")(P[N],I,P[N].valueOf),l(P,\"Symbol\"),l(Math,\"Math\",!0),l(r.JSON,\"JSON\",!0)},\"01f9\":function(t,e,n){\"use strict\";var r=n(\"2d00\"),o=n(\"5ca1\"),i=n(\"2aba\"),a=n(\"32e9\"),s=n(\"84f2\"),c=n(\"41a0\"),u=n(\"7f20\"),f=n(\"38fd\"),l=n(\"2b4c\")(\"iterator\"),p=!([].keys&&\"next\"in[].keys()),d=\"@@iterator\",h=\"keys\",v=\"values\",y=function(){return this};t.exports=function(t,e,n,m,g,b,_){c(n,e,m);var w,x,O,E=function(t){if(!p&&t in k)return k[t];switch(t){case h:return function(){return new n(this,t)};case v:return function(){return new n(this,t)}}return function(){return new n(this,t)}},S=e+\" Iterator\",A=g==v,C=!1,k=t.prototype,j=k[l]||k[d]||g&&k[g],T=j||E(g),$=g?A?E(\"entries\"):T:void 0,M=\"Array\"==e&&k.entries||j;if(M&&(O=f(M.call(new t)),O!==Object.prototype&&O.next&&(u(O,S,!0),r||\"function\"==typeof O[l]||a(O,l,y))),A&&j&&j.name!==v&&(C=!0,T=function(){return j.call(this)}),r&&!_||!p&&!C&&k[l]||a(k,l,T),s[e]=T,s[S]=y,g)if(w={values:A?T:E(v),keys:b?T:E(h),entries:$},_)for(x in w)x in k||i(k,x,w[x]);else o(o.P+o.F*(p||C),e,w);return w}},\"0395\":function(t,e,n){var r=n(\"36c3\"),o=n(\"6abf\").f,i={}.toString,a=\"object\"==typeof window&&window&&Object.getOwnPropertyNames?Object.getOwnPropertyNames(window):[],s=function(t){try{return o(t)}catch(e){return a.slice()}};t.exports.f=function(t){return a&&\"[object Window]\"==i.call(t)?s(t):o(r(t))}},\"044b\":function(t,e){\n/*!\n * Determine if an object is a Buffer\n *\n * @author   Feross Aboukhadijeh <https://feross.org>\n * @license  MIT\n */\nt.exports=function(t){return null!=t&&null!=t.constructor&&\"function\"===typeof t.constructor.isBuffer&&t.constructor.isBuffer(t)}},\"07e3\":function(t,e){var n={}.hasOwnProperty;t.exports=function(t,e){return n.call(t,e)}},\"097d\":function(t,e,n){\"use strict\";var r=n(\"5ca1\"),o=n(\"8378\"),i=n(\"7726\"),a=n(\"ebd6\"),s=n(\"bcaa\");r(r.P+r.R,\"Promise\",{finally:function(t){var e=a(this,o.Promise||i.Promise),n=\"function\"==typeof t;return this.then(n?function(n){return s(e,t()).then(function(){return n})}:t,n?function(n){return s(e,t()).then(function(){throw n})}:t)}})},\"0a06\":function(t,e,n){\"use strict\";var r=n(\"2444\"),o=n(\"c532\"),i=n(\"f6b4\"),a=n(\"5270\");function s(t){this.defaults=t,this.interceptors={request:new i,response:new i}}s.prototype.request=function(t){\"string\"===typeof t&&(t=o.merge({url:arguments[0]},arguments[1])),t=o.merge(r,{method:\"get\"},this.defaults,t),t.method=t.method.toLowerCase();var e=[a,void 0],n=Promise.resolve(t);this.interceptors.request.forEach(function(t){e.unshift(t.fulfilled,t.rejected)}),this.interceptors.response.forEach(function(t){e.push(t.fulfilled,t.rejected)});while(e.length)n=n.then(e.shift(),e.shift());return n},o.forEach([\"delete\",\"get\",\"head\",\"options\"],function(t){s.prototype[t]=function(e,n){return this.request(o.merge(n||{},{method:t,url:e}))}}),o.forEach([\"post\",\"put\",\"patch\"],function(t){s.prototype[t]=function(e,n,r){return this.request(o.merge(r||{},{method:t,url:e,data:n}))}}),t.exports=s},\"0d58\":function(t,e,n){var r=n(\"ce10\"),o=n(\"e11e\");t.exports=Object.keys||function(t){return r(t,o)}},\"0df6\":function(t,e,n){\"use strict\";t.exports=function(t){return function(e){return t.apply(null,e)}}},\"0e15\":function(t,e,n){var r=n(\"597f\");t.exports=function(t,e,n){return void 0===n?r(t,e,!1):r(t,n,!1!==e)}},\"0fc9\":function(t,e,n){var r=n(\"3a38\"),o=Math.max,i=Math.min;t.exports=function(t,e){return t=r(t),t<0?o(t+e,0):i(t,e)}},1098:function(t,e,n){\"use strict\";e.__esModule=!0;var r=n(\"17ed\"),o=c(r),i=n(\"f893\"),a=c(i),s=\"function\"===typeof a.default&&\"symbol\"===typeof o.default?function(t){return typeof t}:function(t){return t&&\"function\"===typeof a.default&&t.constructor===a.default&&t!==a.default.prototype?\"symbol\":typeof t};function c(t){return t&&t.__esModule?t:{default:t}}e.default=\"function\"===typeof a.default&&\"symbol\"===s(o.default)?function(t){return\"undefined\"===typeof t?\"undefined\":s(t)}:function(t){return t&&\"function\"===typeof a.default&&t.constructor===a.default&&t!==a.default.prototype?\"symbol\":\"undefined\"===typeof t?\"undefined\":s(t)}},1173:function(t,e){t.exports=function(t,e,n,r){if(!(t instanceof e)||void 0!==r&&r in t)throw TypeError(n+\": incorrect invocation!\");return t}},1495:function(t,e,n){var r=n(\"86cc\"),o=n(\"cb7c\"),i=n(\"0d58\");t.exports=n(\"9e1e\")?Object.defineProperties:function(t,e){o(t);var n,a=i(e),s=a.length,c=0;while(s>c)r.f(t,n=a[c++],e[n]);return t}},1654:function(t,e,n){\"use strict\";var r=n(\"71c1\")(!0);n(\"30f1\")(String,\"String\",function(t){this._t=String(t),this._i=0},function(){var t,e=this._t,n=this._i;return n>=e.length?{value:void 0,done:!0}:(t=r(e,n),this._i+=t.length,{value:t,done:!1})})},1691:function(t,e){t.exports=\"constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf\".split(\",\")},\"17ed\":function(t,e,n){t.exports={default:n(\"d8d6\"),__esModule:!0}},1991:function(t,e,n){var r,o,i,a=n(\"9b43\"),s=n(\"31f4\"),c=n(\"fab2\"),u=n(\"230e\"),f=n(\"7726\"),l=f.process,p=f.setImmediate,d=f.clearImmediate,h=f.MessageChannel,v=f.Dispatch,y=0,m={},g=\"onreadystatechange\",b=function(){var t=+this;if(m.hasOwnProperty(t)){var e=m[t];delete m[t],e()}},_=function(t){b.call(t.data)};p&&d||(p=function(t){var e=[],n=1;while(arguments.length>n)e.push(arguments[n++]);return m[++y]=function(){s(\"function\"==typeof t?t:Function(t),e)},r(y),y},d=function(t){delete m[t]},\"process\"==n(\"2d95\")(l)?r=function(t){l.nextTick(a(b,t,1))}:v&&v.now?r=function(t){v.now(a(b,t,1))}:h?(o=new h,i=o.port2,o.port1.onmessage=_,r=a(i.postMessage,i,1)):f.addEventListener&&\"function\"==typeof postMessage&&!f.importScripts?(r=function(t){f.postMessage(t+\"\",\"*\")},f.addEventListener(\"message\",_,!1)):r=g in u(\"script\")?function(t){c.appendChild(u(\"script\"))[g]=function(){c.removeChild(this),b.call(t)}}:function(t){setTimeout(a(b,t,1),0)}),t.exports={set:p,clear:d}},\"1bc3\":function(t,e,n){var r=n(\"f772\");t.exports=function(t,e){if(!r(t))return t;var n,o;if(e&&\"function\"==typeof(n=t.toString)&&!r(o=n.call(t)))return o;if(\"function\"==typeof(n=t.valueOf)&&!r(o=n.call(t)))return o;if(!e&&\"function\"==typeof(n=t.toString)&&!r(o=n.call(t)))return o;throw TypeError(\"Can't convert object to primitive value\")}},\"1d2b\":function(t,e,n){\"use strict\";t.exports=function(t,e){return function(){for(var n=new Array(arguments.length),r=0;r<n.length;r++)n[r]=arguments[r];return t.apply(e,n)}}},\"1ec9\":function(t,e,n){var r=n(\"f772\"),o=n(\"e53d\").document,i=r(o)&&r(o.createElement);t.exports=function(t){return i?o.createElement(t):{}}},\"1fa8\":function(t,e,n){var r=n(\"cb7c\");t.exports=function(t,e,n,o){try{return o?e(r(n)[0],n[1]):e(n)}catch(a){var i=t[\"return\"];throw void 0!==i&&r(i.call(t)),a}}},\"20fd\":function(t,e,n){\"use strict\";var r=n(\"d9f6\"),o=n(\"aebd\");t.exports=function(t,e,n){e in t?r.f(t,e,o(0,n)):t[e]=n}},\"21a1\":function(t,e,n){(function(e){(function(e,n){t.exports=n()})(0,function(){\"use strict\";\"undefined\"!==typeof window?window:\"undefined\"!==typeof e||\"undefined\"!==typeof self&&self;function t(t,e){return e={exports:{}},t(e,e.exports),e.exports}var n=t(function(t,e){(function(e,n){t.exports=n()})(0,function(){function t(t){var e=t&&\"object\"===typeof t;return e&&\"[object RegExp]\"!==Object.prototype.toString.call(t)&&\"[object Date]\"!==Object.prototype.toString.call(t)}function e(t){return Array.isArray(t)?[]:{}}function n(n,r){var o=r&&!0===r.clone;return o&&t(n)?i(e(n),n,r):n}function r(e,r,o){var a=e.slice();return r.forEach(function(r,s){\"undefined\"===typeof a[s]?a[s]=n(r,o):t(r)?a[s]=i(e[s],r,o):-1===e.indexOf(r)&&a.push(n(r,o))}),a}function o(e,r,o){var a={};return t(e)&&Object.keys(e).forEach(function(t){a[t]=n(e[t],o)}),Object.keys(r).forEach(function(s){t(r[s])&&e[s]?a[s]=i(e[s],r[s],o):a[s]=n(r[s],o)}),a}function i(t,e,i){var a=Array.isArray(e),s=i||{arrayMerge:r},c=s.arrayMerge||r;return a?Array.isArray(t)?c(t,e,i):n(e,i):o(t,e,i)}return i.all=function(t,e){if(!Array.isArray(t)||t.length<2)throw new Error(\"first argument should be an array with at least two elements\");return t.reduce(function(t,n){return i(t,n,e)})},i})});function r(t){return t=t||Object.create(null),{on:function(e,n){(t[e]||(t[e]=[])).push(n)},off:function(e,n){t[e]&&t[e].splice(t[e].indexOf(n)>>>0,1)},emit:function(e,n){(t[e]||[]).map(function(t){t(n)}),(t[\"*\"]||[]).map(function(t){t(e,n)})}}}var o=t(function(t,e){var n={svg:{name:\"xmlns\",uri:\"http://www.w3.org/2000/svg\"},xlink:{name:\"xmlns:xlink\",uri:\"http://www.w3.org/1999/xlink\"}};e.default=n,t.exports=e.default}),i=function(t){return Object.keys(t).map(function(e){var n=t[e].toString().replace(/\"/g,\"&quot;\");return e+'=\"'+n+'\"'}).join(\" \")},a=o.svg,s=o.xlink,c={};c[a.name]=a.uri,c[s.name]=s.uri;var u,f=function(t,e){void 0===t&&(t=\"\");var r=n(c,e||{}),o=i(r);return\"<svg \"+o+\">\"+t+\"</svg>\"},l=o.svg,p=o.xlink,d={attrs:(u={style:[\"position: absolute\",\"width: 0\",\"height: 0\"].join(\"; \")},u[l.name]=l.uri,u[p.name]=p.uri,u)},h=function(t){this.config=n(d,t||{}),this.symbols=[]};h.prototype.add=function(t){var e=this,n=e.symbols,r=this.find(t.id);return r?(n[n.indexOf(r)]=t,!1):(n.push(t),!0)},h.prototype.remove=function(t){var e=this,n=e.symbols,r=this.find(t);return!!r&&(n.splice(n.indexOf(r),1),r.destroy(),!0)},h.prototype.find=function(t){return this.symbols.filter(function(e){return e.id===t})[0]||null},h.prototype.has=function(t){return null!==this.find(t)},h.prototype.stringify=function(){var t=this.config,e=t.attrs,n=this.symbols.map(function(t){return t.stringify()}).join(\"\");return f(n,e)},h.prototype.toString=function(){return this.stringify()},h.prototype.destroy=function(){this.symbols.forEach(function(t){return t.destroy()})};var v=function(t){var e=t.id,n=t.viewBox,r=t.content;this.id=e,this.viewBox=n,this.content=r};v.prototype.stringify=function(){return this.content},v.prototype.toString=function(){return this.stringify()},v.prototype.destroy=function(){var t=this;[\"id\",\"viewBox\",\"content\"].forEach(function(e){return delete t[e]})};var y=function(t){var e=!!document.importNode,n=(new DOMParser).parseFromString(t,\"image/svg+xml\").documentElement;return e?document.importNode(n,!0):n},m=function(t){function e(){t.apply(this,arguments)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var n={isMounted:{}};return n.isMounted.get=function(){return!!this.node},e.createFromExistingNode=function(t){return new e({id:t.getAttribute(\"id\"),viewBox:t.getAttribute(\"viewBox\"),content:t.outerHTML})},e.prototype.destroy=function(){this.isMounted&&this.unmount(),t.prototype.destroy.call(this)},e.prototype.mount=function(t){if(this.isMounted)return this.node;var e=\"string\"===typeof t?document.querySelector(t):t,n=this.render();return this.node=n,e.appendChild(n),n},e.prototype.render=function(){var t=this.stringify();return y(f(t)).childNodes[0]},e.prototype.unmount=function(){this.node.parentNode.removeChild(this.node)},Object.defineProperties(e.prototype,n),e}(v),g={autoConfigure:!0,mountTo:\"body\",syncUrlsWithBaseTag:!1,listenLocationChangeEvent:!0,locationChangeEvent:\"locationChange\",locationChangeAngularEmitter:!1,usagesToUpdate:\"use[*|href]\",moveGradientsOutsideSymbol:!1},b=function(t){return Array.prototype.slice.call(t,0)},_=navigator.userAgent,w={isChrome:/chrome/i.test(_),isFirefox:/firefox/i.test(_),isIE:/msie/i.test(_)||/trident/i.test(_),isEdge:/edge/i.test(_)},x=function(t,e){var n=document.createEvent(\"CustomEvent\");n.initCustomEvent(t,!1,!1,e),window.dispatchEvent(n)},O=function(t){var e=[];return b(t.querySelectorAll(\"style\")).forEach(function(t){t.textContent+=\"\",e.push(t)}),e},E=function(t){return(t||window.location.href).split(\"#\")[0]},S=function(t){angular.module(\"ng\").run([\"$rootScope\",function(e){e.$on(\"$locationChangeSuccess\",function(e,n,r){x(t,{oldUrl:r,newUrl:n})})}])},A=\"linearGradient, radialGradient, pattern\",C=function(t,e){return void 0===e&&(e=A),b(t.querySelectorAll(\"symbol\")).forEach(function(t){b(t.querySelectorAll(e)).forEach(function(e){t.parentNode.insertBefore(e,t)})}),t};function k(t,e){var n=b(t).reduce(function(t,n){if(!n.attributes)return t;var r=b(n.attributes),o=e?r.filter(e):r;return t.concat(o)},[]);return n}var j=o.xlink.uri,T=\"xlink:href\",$=/[{}|\\\\\\^\\[\\]`\"<>]/g;function M(t){return t.replace($,function(t){return\"%\"+t[0].charCodeAt(0).toString(16).toUpperCase()})}function P(t,e,n){return b(t).forEach(function(t){var r=t.getAttribute(T);if(r&&0===r.indexOf(e)){var o=r.replace(e,n);t.setAttributeNS(j,T,o)}}),t}var L,R=[\"clipPath\",\"colorProfile\",\"src\",\"cursor\",\"fill\",\"filter\",\"marker\",\"markerStart\",\"markerMid\",\"markerEnd\",\"mask\",\"stroke\",\"style\"],N=R.map(function(t){return\"[\"+t+\"]\"}).join(\",\"),F=function(t,e,n,r){var o=M(n),i=M(r),a=t.querySelectorAll(N),s=k(a,function(t){var e=t.localName,n=t.value;return-1!==R.indexOf(e)&&-1!==n.indexOf(\"url(\"+o)});s.forEach(function(t){return t.value=t.value.replace(o,i)}),P(e,o,i)},I={MOUNT:\"mount\",SYMBOL_MOUNT:\"symbol_mount\"},D=function(t){function e(e){var o=this;void 0===e&&(e={}),t.call(this,n(g,e));var i=r();this._emitter=i,this.node=null;var a=this,s=a.config;if(s.autoConfigure&&this._autoConfigure(e),s.syncUrlsWithBaseTag){var c=document.getElementsByTagName(\"base\")[0].getAttribute(\"href\");i.on(I.MOUNT,function(){return o.updateUrls(\"#\",c)})}var u=this._handleLocationChange.bind(this);this._handleLocationChange=u,s.listenLocationChangeEvent&&window.addEventListener(s.locationChangeEvent,u),s.locationChangeAngularEmitter&&S(s.locationChangeEvent),i.on(I.MOUNT,function(t){s.moveGradientsOutsideSymbol&&C(t)}),i.on(I.SYMBOL_MOUNT,function(t){s.moveGradientsOutsideSymbol&&C(t.parentNode),(w.isIE||w.isEdge)&&O(t)})}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var o={isMounted:{}};return o.isMounted.get=function(){return!!this.node},e.prototype._autoConfigure=function(t){var e=this,n=e.config;\"undefined\"===typeof t.syncUrlsWithBaseTag&&(n.syncUrlsWithBaseTag=\"undefined\"!==typeof document.getElementsByTagName(\"base\")[0]),\"undefined\"===typeof t.locationChangeAngularEmitter&&(n.locationChangeAngularEmitter=\"angular\"in window),\"undefined\"===typeof t.moveGradientsOutsideSymbol&&(n.moveGradientsOutsideSymbol=w.isFirefox)},e.prototype._handleLocationChange=function(t){var e=t.detail,n=e.oldUrl,r=e.newUrl;this.updateUrls(n,r)},e.prototype.add=function(e){var n=this,r=t.prototype.add.call(this,e);return this.isMounted&&r&&(e.mount(n.node),this._emitter.emit(I.SYMBOL_MOUNT,e.node)),r},e.prototype.attach=function(t){var e=this,n=this;if(n.isMounted)return n.node;var r=\"string\"===typeof t?document.querySelector(t):t;return n.node=r,this.symbols.forEach(function(t){t.mount(n.node),e._emitter.emit(I.SYMBOL_MOUNT,t.node)}),b(r.querySelectorAll(\"symbol\")).forEach(function(t){var e=m.createFromExistingNode(t);e.node=t,n.add(e)}),this._emitter.emit(I.MOUNT,r),r},e.prototype.destroy=function(){var t=this,e=t.config,n=t.symbols,r=t._emitter;n.forEach(function(t){return t.destroy()}),r.off(\"*\"),window.removeEventListener(e.locationChangeEvent,this._handleLocationChange),this.isMounted&&this.unmount()},e.prototype.mount=function(t,e){void 0===t&&(t=this.config.mountTo),void 0===e&&(e=!1);var n=this;if(n.isMounted)return n.node;var r=\"string\"===typeof t?document.querySelector(t):t,o=n.render();return this.node=o,e&&r.childNodes[0]?r.insertBefore(o,r.childNodes[0]):r.appendChild(o),this._emitter.emit(I.MOUNT,o),o},e.prototype.render=function(){return y(this.stringify())},e.prototype.unmount=function(){this.node.parentNode.removeChild(this.node)},e.prototype.updateUrls=function(t,e){if(!this.isMounted)return!1;var n=document.querySelectorAll(this.config.usagesToUpdate);return F(this.node,n,E(t)+\"#\",E(e)+\"#\"),!0},Object.defineProperties(e.prototype,o),e}(h),q=t(function(t){\n/*!\n  * domready (c) Dustin Diaz 2014 - License MIT\n  */\n!function(e,n){t.exports=n()}(0,function(){var t,e=[],n=document,r=n.documentElement.doScroll,o=\"DOMContentLoaded\",i=(r?/^loaded|^c/:/^loaded|^i|^c/).test(n.readyState);return i||n.addEventListener(o,t=function(){n.removeEventListener(o,t),i=1;while(t=e.shift())t()}),function(t){i?setTimeout(t,0):e.push(t)}})}),U=\"__SVG_SPRITE_NODE__\",B=\"__SVG_SPRITE__\",V=!!window[B];V?L=window[B]:(L=new D({attrs:{id:U}}),window[B]=L);var H=function(){var t=document.getElementById(U);t?L.attach(t):L.mount(document.body,!0)};document.body?H():q(H);var z=L;return z})}).call(this,n(\"c8ba\"))},\"230e\":function(t,e,n){var r=n(\"d3f4\"),o=n(\"7726\").document,i=r(o)&&r(o.createElement);t.exports=function(t){return i?o.createElement(t):{}}},\"23c6\":function(t,e,n){var r=n(\"2d95\"),o=n(\"2b4c\")(\"toStringTag\"),i=\"Arguments\"==r(function(){return arguments}()),a=function(t,e){try{return t[e]}catch(n){}};t.exports=function(t){var e,n,s;return void 0===t?\"Undefined\":null===t?\"Null\":\"string\"==typeof(n=a(e=Object(t),o))?n:i?r(e):\"Object\"==(s=r(e))&&\"function\"==typeof e.callee?\"Arguments\":s}},\"241e\":function(t,e,n){var r=n(\"25eb\");t.exports=function(t){return Object(r(t))}},2444:function(t,e,n){\"use strict\";(function(e){var r=n(\"c532\"),o=n(\"c8af\"),i={\"Content-Type\":\"application/x-www-form-urlencoded\"};function a(t,e){!r.isUndefined(t)&&r.isUndefined(t[\"Content-Type\"])&&(t[\"Content-Type\"]=e)}function s(){var t;return\"undefined\"!==typeof XMLHttpRequest?t=n(\"b50d\"):\"undefined\"!==typeof e&&(t=n(\"b50d\")),t}var c={adapter:s(),transformRequest:[function(t,e){return o(e,\"Content-Type\"),r.isFormData(t)||r.isArrayBuffer(t)||r.isBuffer(t)||r.isStream(t)||r.isFile(t)||r.isBlob(t)?t:r.isArrayBufferView(t)?t.buffer:r.isURLSearchParams(t)?(a(e,\"application/x-www-form-urlencoded;charset=utf-8\"),t.toString()):r.isObject(t)?(a(e,\"application/json;charset=utf-8\"),JSON.stringify(t)):t}],transformResponse:[function(t){if(\"string\"===typeof t)try{t=JSON.parse(t)}catch(e){}return t}],timeout:0,xsrfCookieName:\"XSRF-TOKEN\",xsrfHeaderName:\"X-XSRF-TOKEN\",maxContentLength:-1,validateStatus:function(t){return t>=200&&t<300},headers:{common:{Accept:\"application/json, text/plain, */*\"}}};r.forEach([\"delete\",\"get\",\"head\"],function(t){c.headers[t]={}}),r.forEach([\"post\",\"put\",\"patch\"],function(t){c.headers[t]=r.merge(i)}),t.exports=c}).call(this,n(\"4362\"))},\"24c5\":function(t,e,n){\"use strict\";var r,o,i,a,s=n(\"b8e3\"),c=n(\"e53d\"),u=n(\"d864\"),f=n(\"40c3\"),l=n(\"63b6\"),p=n(\"f772\"),d=n(\"79aa\"),h=n(\"1173\"),v=n(\"a22a\"),y=n(\"f201\"),m=n(\"4178\").set,g=n(\"aba2\")(),b=n(\"656e\"),_=n(\"4439\"),w=n(\"bc13\"),x=n(\"cd78\"),O=\"Promise\",E=c.TypeError,S=c.process,A=S&&S.versions,C=A&&A.v8||\"\",k=c[O],j=\"process\"==f(S),T=function(){},$=o=b.f,M=!!function(){try{var t=k.resolve(1),e=(t.constructor={})[n(\"5168\")(\"species\")]=function(t){t(T,T)};return(j||\"function\"==typeof PromiseRejectionEvent)&&t.then(T)instanceof e&&0!==C.indexOf(\"6.6\")&&-1===w.indexOf(\"Chrome/66\")}catch(r){}}(),P=function(t){var e;return!(!p(t)||\"function\"!=typeof(e=t.then))&&e},L=function(t,e){if(!t._n){t._n=!0;var n=t._c;g(function(){var r=t._v,o=1==t._s,i=0,a=function(e){var n,i,a,s=o?e.ok:e.fail,c=e.resolve,u=e.reject,f=e.domain;try{s?(o||(2==t._h&&F(t),t._h=1),!0===s?n=r:(f&&f.enter(),n=s(r),f&&(f.exit(),a=!0)),n===e.promise?u(E(\"Promise-chain cycle\")):(i=P(n))?i.call(n,c,u):c(n)):u(r)}catch(l){f&&!a&&f.exit(),u(l)}};while(n.length>i)a(n[i++]);t._c=[],t._n=!1,e&&!t._h&&R(t)})}},R=function(t){m.call(c,function(){var e,n,r,o=t._v,i=N(t);if(i&&(e=_(function(){j?S.emit(\"unhandledRejection\",o,t):(n=c.onunhandledrejection)?n({promise:t,reason:o}):(r=c.console)&&r.error&&r.error(\"Unhandled promise rejection\",o)}),t._h=j||N(t)?2:1),t._a=void 0,i&&e.e)throw e.v})},N=function(t){return 1!==t._h&&0===(t._a||t._c).length},F=function(t){m.call(c,function(){var e;j?S.emit(\"rejectionHandled\",t):(e=c.onrejectionhandled)&&e({promise:t,reason:t._v})})},I=function(t){var e=this;e._d||(e._d=!0,e=e._w||e,e._v=t,e._s=2,e._a||(e._a=e._c.slice()),L(e,!0))},D=function(t){var e,n=this;if(!n._d){n._d=!0,n=n._w||n;try{if(n===t)throw E(\"Promise can't be resolved itself\");(e=P(t))?g(function(){var r={_w:n,_d:!1};try{e.call(t,u(D,r,1),u(I,r,1))}catch(o){I.call(r,o)}}):(n._v=t,n._s=1,L(n,!1))}catch(r){I.call({_w:n,_d:!1},r)}}};M||(k=function(t){h(this,k,O,\"_h\"),d(t),r.call(this);try{t(u(D,this,1),u(I,this,1))}catch(e){I.call(this,e)}},r=function(t){this._c=[],this._a=void 0,this._s=0,this._d=!1,this._v=void 0,this._h=0,this._n=!1},r.prototype=n(\"5c95\")(k.prototype,{then:function(t,e){var n=$(y(this,k));return n.ok=\"function\"!=typeof t||t,n.fail=\"function\"==typeof e&&e,n.domain=j?S.domain:void 0,this._c.push(n),this._a&&this._a.push(n),this._s&&L(this,!1),n.promise},catch:function(t){return this.then(void 0,t)}}),i=function(){var t=new r;this.promise=t,this.resolve=u(D,t,1),this.reject=u(I,t,1)},b.f=$=function(t){return t===k||t===a?new i(t):o(t)}),l(l.G+l.W+l.F*!M,{Promise:k}),n(\"45f2\")(k,O),n(\"4c95\")(O),a=n(\"584a\")[O],l(l.S+l.F*!M,O,{reject:function(t){var e=$(this),n=e.reject;return n(t),e.promise}}),l(l.S+l.F*(s||!M),O,{resolve:function(t){return x(s&&this===a?k:this,t)}}),l(l.S+l.F*!(M&&n(\"4ee1\")(function(t){k.all(t)[\"catch\"](T)})),O,{all:function(t){var e=this,n=$(e),r=n.resolve,o=n.reject,i=_(function(){var n=[],i=0,a=1;v(t,!1,function(t){var s=i++,c=!1;n.push(void 0),a++,e.resolve(t).then(function(t){c||(c=!0,n[s]=t,--a||r(n))},o)}),--a||r(n)});return i.e&&o(i.v),n.promise},race:function(t){var e=this,n=$(e),r=n.reject,o=_(function(){v(t,!1,function(t){e.resolve(t).then(n.resolve,r)})});return o.e&&r(o.v),n.promise}})},\"25eb\":function(t,e){t.exports=function(t){if(void 0==t)throw TypeError(\"Can't call method on  \"+t);return t}},2621:function(t,e){e.f=Object.getOwnPropertySymbols},\"268f\":function(t,e,n){t.exports=n(\"fde4\")},\"27ee\":function(t,e,n){var r=n(\"23c6\"),o=n(\"2b4c\")(\"iterator\"),i=n(\"84f2\");t.exports=n(\"8378\").getIteratorMethod=function(t){if(void 0!=t)return t[o]||t[\"@@iterator\"]||i[r(t)]}},2877:function(t,e,n){\"use strict\";function r(t,e,n,r,o,i,a,s){var c,u=\"function\"===typeof t?t.options:t;if(e&&(u.render=e,u.staticRenderFns=n,u._compiled=!0),r&&(u.functional=!0),i&&(u._scopeId=\"data-v-\"+i),a?(c=function(t){t=t||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext,t||\"undefined\"===typeof __VUE_SSR_CONTEXT__||(t=__VUE_SSR_CONTEXT__),o&&o.call(this,t),t&&t._registeredComponents&&t._registeredComponents.add(a)},u._ssrRegister=c):o&&(c=s?function(){o.call(this,this.$root.$options.shadowRoot)}:o),c)if(u.functional){u._injectStyles=c;var f=u.render;u.render=function(t,e){return c.call(e),f(t,e)}}else{var l=u.beforeCreate;u.beforeCreate=l?[].concat(l,c):[c]}return{exports:t,options:u}}n.d(e,\"a\",function(){return r})},\"294c\":function(t,e){t.exports=function(t){try{return!!t()}catch(e){return!0}}},\"2aba\":function(t,e,n){var r=n(\"7726\"),o=n(\"32e9\"),i=n(\"69a8\"),a=n(\"ca5a\")(\"src\"),s=n(\"fa5b\"),c=\"toString\",u=(\"\"+s).split(c);n(\"8378\").inspectSource=function(t){return s.call(t)},(t.exports=function(t,e,n,s){var c=\"function\"==typeof n;c&&(i(n,\"name\")||o(n,\"name\",e)),t[e]!==n&&(c&&(i(n,a)||o(n,a,t[e]?\"\"+t[e]:u.join(String(e)))),t===r?t[e]=n:s?t[e]?t[e]=n:o(t,e,n):(delete t[e],o(t,e,n)))})(Function.prototype,c,function(){return\"function\"==typeof this&&this[a]||s.call(this)})},\"2aeb\":function(t,e,n){var r=n(\"cb7c\"),o=n(\"1495\"),i=n(\"e11e\"),a=n(\"613b\")(\"IE_PROTO\"),s=function(){},c=\"prototype\",u=function(){var t,e=n(\"230e\")(\"iframe\"),r=i.length,o=\"<\",a=\">\";e.style.display=\"none\",n(\"fab2\").appendChild(e),e.src=\"javascript:\",t=e.contentWindow.document,t.open(),t.write(o+\"script\"+a+\"document.F=Object\"+o+\"/script\"+a),t.close(),u=t.F;while(r--)delete u[c][i[r]];return u()};t.exports=Object.create||function(t,e){var n;return null!==t?(s[c]=r(t),n=new s,s[c]=null,n[a]=t):n=u(),void 0===e?n:o(n,e)}},\"2b0e\":function(t,e,n){\"use strict\";n.r(e),function(t){\n/*!\n * Vue.js v2.6.10\n * (c) 2014-2019 Evan You\n * Released under the MIT License.\n */\nvar n=Object.freeze({});function r(t){return void 0===t||null===t}function o(t){return void 0!==t&&null!==t}function i(t){return!0===t}function a(t){return!1===t}function s(t){return\"string\"===typeof t||\"number\"===typeof t||\"symbol\"===typeof t||\"boolean\"===typeof t}function c(t){return null!==t&&\"object\"===typeof t}var u=Object.prototype.toString;function f(t){return\"[object Object]\"===u.call(t)}function l(t){return\"[object RegExp]\"===u.call(t)}function p(t){var e=parseFloat(String(t));return e>=0&&Math.floor(e)===e&&isFinite(t)}function d(t){return o(t)&&\"function\"===typeof t.then&&\"function\"===typeof t.catch}function h(t){return null==t?\"\":Array.isArray(t)||f(t)&&t.toString===u?JSON.stringify(t,null,2):String(t)}function v(t){var e=parseFloat(t);return isNaN(e)?t:e}function y(t,e){for(var n=Object.create(null),r=t.split(\",\"),o=0;o<r.length;o++)n[r[o]]=!0;return e?function(t){return n[t.toLowerCase()]}:function(t){return n[t]}}y(\"slot,component\",!0);var m=y(\"key,ref,slot,slot-scope,is\");function g(t,e){if(t.length){var n=t.indexOf(e);if(n>-1)return t.splice(n,1)}}var b=Object.prototype.hasOwnProperty;function _(t,e){return b.call(t,e)}function w(t){var e=Object.create(null);return function(n){var r=e[n];return r||(e[n]=t(n))}}var x=/-(\\w)/g,O=w(function(t){return t.replace(x,function(t,e){return e?e.toUpperCase():\"\"})}),E=w(function(t){return t.charAt(0).toUpperCase()+t.slice(1)}),S=/\\B([A-Z])/g,A=w(function(t){return t.replace(S,\"-$1\").toLowerCase()});function C(t,e){function n(n){var r=arguments.length;return r?r>1?t.apply(e,arguments):t.call(e,n):t.call(e)}return n._length=t.length,n}function k(t,e){return t.bind(e)}var j=Function.prototype.bind?k:C;function T(t,e){e=e||0;var n=t.length-e,r=new Array(n);while(n--)r[n]=t[n+e];return r}function $(t,e){for(var n in e)t[n]=e[n];return t}function M(t){for(var e={},n=0;n<t.length;n++)t[n]&&$(e,t[n]);return e}function P(t,e,n){}var L=function(t,e,n){return!1},R=function(t){return t};function N(t,e){if(t===e)return!0;var n=c(t),r=c(e);if(!n||!r)return!n&&!r&&String(t)===String(e);try{var o=Array.isArray(t),i=Array.isArray(e);if(o&&i)return t.length===e.length&&t.every(function(t,n){return N(t,e[n])});if(t instanceof Date&&e instanceof Date)return t.getTime()===e.getTime();if(o||i)return!1;var a=Object.keys(t),s=Object.keys(e);return a.length===s.length&&a.every(function(n){return N(t[n],e[n])})}catch(u){return!1}}function F(t,e){for(var n=0;n<t.length;n++)if(N(t[n],e))return n;return-1}function I(t){var e=!1;return function(){e||(e=!0,t.apply(this,arguments))}}var D=\"data-server-rendered\",q=[\"component\",\"directive\",\"filter\"],U=[\"beforeCreate\",\"created\",\"beforeMount\",\"mounted\",\"beforeUpdate\",\"updated\",\"beforeDestroy\",\"destroyed\",\"activated\",\"deactivated\",\"errorCaptured\",\"serverPrefetch\"],B={optionMergeStrategies:Object.create(null),silent:!1,productionTip:!1,devtools:!1,performance:!1,errorHandler:null,warnHandler:null,ignoredElements:[],keyCodes:Object.create(null),isReservedTag:L,isReservedAttr:L,isUnknownElement:L,getTagNamespace:P,parsePlatformTagName:R,mustUseProp:L,async:!0,_lifecycleHooks:U},V=/a-zA-Z\\u00B7\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u203F-\\u2040\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD/;function H(t){var e=(t+\"\").charCodeAt(0);return 36===e||95===e}function z(t,e,n,r){Object.defineProperty(t,e,{value:n,enumerable:!!r,writable:!0,configurable:!0})}var G=new RegExp(\"[^\"+V.source+\".$_\\\\d]\");function W(t){if(!G.test(t)){var e=t.split(\".\");return function(t){for(var n=0;n<e.length;n++){if(!t)return;t=t[e[n]]}return t}}}var K,X=\"__proto__\"in{},J=\"undefined\"!==typeof window,Y=\"undefined\"!==typeof WXEnvironment&&!!WXEnvironment.platform,Z=Y&&WXEnvironment.platform.toLowerCase(),Q=J&&window.navigator.userAgent.toLowerCase(),tt=Q&&/msie|trident/.test(Q),et=Q&&Q.indexOf(\"msie 9.0\")>0,nt=Q&&Q.indexOf(\"edge/\")>0,rt=(Q&&Q.indexOf(\"android\"),Q&&/iphone|ipad|ipod|ios/.test(Q)||\"ios\"===Z),ot=(Q&&/chrome\\/\\d+/.test(Q),Q&&/phantomjs/.test(Q),Q&&Q.match(/firefox\\/(\\d+)/)),it={}.watch,at=!1;if(J)try{var st={};Object.defineProperty(st,\"passive\",{get:function(){at=!0}}),window.addEventListener(\"test-passive\",null,st)}catch(Oa){}var ct=function(){return void 0===K&&(K=!J&&!Y&&\"undefined\"!==typeof t&&(t[\"process\"]&&\"server\"===t[\"process\"].env.VUE_ENV)),K},ut=J&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__;function ft(t){return\"function\"===typeof t&&/native code/.test(t.toString())}var lt,pt=\"undefined\"!==typeof Symbol&&ft(Symbol)&&\"undefined\"!==typeof Reflect&&ft(Reflect.ownKeys);lt=\"undefined\"!==typeof Set&&ft(Set)?Set:function(){function t(){this.set=Object.create(null)}return t.prototype.has=function(t){return!0===this.set[t]},t.prototype.add=function(t){this.set[t]=!0},t.prototype.clear=function(){this.set=Object.create(null)},t}();var dt=P,ht=0,vt=function(){this.id=ht++,this.subs=[]};vt.prototype.addSub=function(t){this.subs.push(t)},vt.prototype.removeSub=function(t){g(this.subs,t)},vt.prototype.depend=function(){vt.target&&vt.target.addDep(this)},vt.prototype.notify=function(){var t=this.subs.slice();for(var e=0,n=t.length;e<n;e++)t[e].update()},vt.target=null;var yt=[];function mt(t){yt.push(t),vt.target=t}function gt(){yt.pop(),vt.target=yt[yt.length-1]}var bt=function(t,e,n,r,o,i,a,s){this.tag=t,this.data=e,this.children=n,this.text=r,this.elm=o,this.ns=void 0,this.context=i,this.fnContext=void 0,this.fnOptions=void 0,this.fnScopeId=void 0,this.key=e&&e.key,this.componentOptions=a,this.componentInstance=void 0,this.parent=void 0,this.raw=!1,this.isStatic=!1,this.isRootInsert=!0,this.isComment=!1,this.isCloned=!1,this.isOnce=!1,this.asyncFactory=s,this.asyncMeta=void 0,this.isAsyncPlaceholder=!1},_t={child:{configurable:!0}};_t.child.get=function(){return this.componentInstance},Object.defineProperties(bt.prototype,_t);var wt=function(t){void 0===t&&(t=\"\");var e=new bt;return e.text=t,e.isComment=!0,e};function xt(t){return new bt(void 0,void 0,void 0,String(t))}function Ot(t){var e=new bt(t.tag,t.data,t.children&&t.children.slice(),t.text,t.elm,t.context,t.componentOptions,t.asyncFactory);return e.ns=t.ns,e.isStatic=t.isStatic,e.key=t.key,e.isComment=t.isComment,e.fnContext=t.fnContext,e.fnOptions=t.fnOptions,e.fnScopeId=t.fnScopeId,e.asyncMeta=t.asyncMeta,e.isCloned=!0,e}var Et=Array.prototype,St=Object.create(Et),At=[\"push\",\"pop\",\"shift\",\"unshift\",\"splice\",\"sort\",\"reverse\"];At.forEach(function(t){var e=Et[t];z(St,t,function(){var n=[],r=arguments.length;while(r--)n[r]=arguments[r];var o,i=e.apply(this,n),a=this.__ob__;switch(t){case\"push\":case\"unshift\":o=n;break;case\"splice\":o=n.slice(2);break}return o&&a.observeArray(o),a.dep.notify(),i})});var Ct=Object.getOwnPropertyNames(St),kt=!0;function jt(t){kt=t}var Tt=function(t){this.value=t,this.dep=new vt,this.vmCount=0,z(t,\"__ob__\",this),Array.isArray(t)?(X?$t(t,St):Mt(t,St,Ct),this.observeArray(t)):this.walk(t)};function $t(t,e){t.__proto__=e}function Mt(t,e,n){for(var r=0,o=n.length;r<o;r++){var i=n[r];z(t,i,e[i])}}function Pt(t,e){var n;if(c(t)&&!(t instanceof bt))return _(t,\"__ob__\")&&t.__ob__ instanceof Tt?n=t.__ob__:kt&&!ct()&&(Array.isArray(t)||f(t))&&Object.isExtensible(t)&&!t._isVue&&(n=new Tt(t)),e&&n&&n.vmCount++,n}function Lt(t,e,n,r,o){var i=new vt,a=Object.getOwnPropertyDescriptor(t,e);if(!a||!1!==a.configurable){var s=a&&a.get,c=a&&a.set;s&&!c||2!==arguments.length||(n=t[e]);var u=!o&&Pt(n);Object.defineProperty(t,e,{enumerable:!0,configurable:!0,get:function(){var e=s?s.call(t):n;return vt.target&&(i.depend(),u&&(u.dep.depend(),Array.isArray(e)&&Ft(e))),e},set:function(e){var r=s?s.call(t):n;e===r||e!==e&&r!==r||s&&!c||(c?c.call(t,e):n=e,u=!o&&Pt(e),i.notify())}})}}function Rt(t,e,n){if(Array.isArray(t)&&p(e))return t.length=Math.max(t.length,e),t.splice(e,1,n),n;if(e in t&&!(e in Object.prototype))return t[e]=n,n;var r=t.__ob__;return t._isVue||r&&r.vmCount?n:r?(Lt(r.value,e,n),r.dep.notify(),n):(t[e]=n,n)}function Nt(t,e){if(Array.isArray(t)&&p(e))t.splice(e,1);else{var n=t.__ob__;t._isVue||n&&n.vmCount||_(t,e)&&(delete t[e],n&&n.dep.notify())}}function Ft(t){for(var e=void 0,n=0,r=t.length;n<r;n++)e=t[n],e&&e.__ob__&&e.__ob__.dep.depend(),Array.isArray(e)&&Ft(e)}Tt.prototype.walk=function(t){for(var e=Object.keys(t),n=0;n<e.length;n++)Lt(t,e[n])},Tt.prototype.observeArray=function(t){for(var e=0,n=t.length;e<n;e++)Pt(t[e])};var It=B.optionMergeStrategies;function Dt(t,e){if(!e)return t;for(var n,r,o,i=pt?Reflect.ownKeys(e):Object.keys(e),a=0;a<i.length;a++)n=i[a],\"__ob__\"!==n&&(r=t[n],o=e[n],_(t,n)?r!==o&&f(r)&&f(o)&&Dt(r,o):Rt(t,n,o));return t}function qt(t,e,n){return n?function(){var r=\"function\"===typeof e?e.call(n,n):e,o=\"function\"===typeof t?t.call(n,n):t;return r?Dt(r,o):o}:e?t?function(){return Dt(\"function\"===typeof e?e.call(this,this):e,\"function\"===typeof t?t.call(this,this):t)}:e:t}function Ut(t,e){var n=e?t?t.concat(e):Array.isArray(e)?e:[e]:t;return n?Bt(n):n}function Bt(t){for(var e=[],n=0;n<t.length;n++)-1===e.indexOf(t[n])&&e.push(t[n]);return e}function Vt(t,e,n,r){var o=Object.create(t||null);return e?$(o,e):o}It.data=function(t,e,n){return n?qt(t,e,n):e&&\"function\"!==typeof e?t:qt(t,e)},U.forEach(function(t){It[t]=Ut}),q.forEach(function(t){It[t+\"s\"]=Vt}),It.watch=function(t,e,n,r){if(t===it&&(t=void 0),e===it&&(e=void 0),!e)return Object.create(t||null);if(!t)return e;var o={};for(var i in $(o,t),e){var a=o[i],s=e[i];a&&!Array.isArray(a)&&(a=[a]),o[i]=a?a.concat(s):Array.isArray(s)?s:[s]}return o},It.props=It.methods=It.inject=It.computed=function(t,e,n,r){if(!t)return e;var o=Object.create(null);return $(o,t),e&&$(o,e),o},It.provide=qt;var Ht=function(t,e){return void 0===e?t:e};function zt(t,e){var n=t.props;if(n){var r,o,i,a={};if(Array.isArray(n)){r=n.length;while(r--)o=n[r],\"string\"===typeof o&&(i=O(o),a[i]={type:null})}else if(f(n))for(var s in n)o=n[s],i=O(s),a[i]=f(o)?o:{type:o};else 0;t.props=a}}function Gt(t,e){var n=t.inject;if(n){var r=t.inject={};if(Array.isArray(n))for(var o=0;o<n.length;o++)r[n[o]]={from:n[o]};else if(f(n))for(var i in n){var a=n[i];r[i]=f(a)?$({from:i},a):{from:a}}else 0}}function Wt(t){var e=t.directives;if(e)for(var n in e){var r=e[n];\"function\"===typeof r&&(e[n]={bind:r,update:r})}}function Kt(t,e,n){if(\"function\"===typeof e&&(e=e.options),zt(e,n),Gt(e,n),Wt(e),!e._base&&(e.extends&&(t=Kt(t,e.extends,n)),e.mixins))for(var r=0,o=e.mixins.length;r<o;r++)t=Kt(t,e.mixins[r],n);var i,a={};for(i in t)s(i);for(i in e)_(t,i)||s(i);function s(r){var o=It[r]||Ht;a[r]=o(t[r],e[r],n,r)}return a}function Xt(t,e,n,r){if(\"string\"===typeof n){var o=t[e];if(_(o,n))return o[n];var i=O(n);if(_(o,i))return o[i];var a=E(i);if(_(o,a))return o[a];var s=o[n]||o[i]||o[a];return s}}function Jt(t,e,n,r){var o=e[t],i=!_(n,t),a=n[t],s=te(Boolean,o.type);if(s>-1)if(i&&!_(o,\"default\"))a=!1;else if(\"\"===a||a===A(t)){var c=te(String,o.type);(c<0||s<c)&&(a=!0)}if(void 0===a){a=Yt(r,o,t);var u=kt;jt(!0),Pt(a),jt(u)}return a}function Yt(t,e,n){if(_(e,\"default\")){var r=e.default;return t&&t.$options.propsData&&void 0===t.$options.propsData[n]&&void 0!==t._props[n]?t._props[n]:\"function\"===typeof r&&\"Function\"!==Zt(e.type)?r.call(t):r}}function Zt(t){var e=t&&t.toString().match(/^\\s*function (\\w+)/);return e?e[1]:\"\"}function Qt(t,e){return Zt(t)===Zt(e)}function te(t,e){if(!Array.isArray(e))return Qt(e,t)?0:-1;for(var n=0,r=e.length;n<r;n++)if(Qt(e[n],t))return n;return-1}function ee(t,e,n){mt();try{if(e){var r=e;while(r=r.$parent){var o=r.$options.errorCaptured;if(o)for(var i=0;i<o.length;i++)try{var a=!1===o[i].call(r,t,e,n);if(a)return}catch(Oa){re(Oa,r,\"errorCaptured hook\")}}}re(t,e,n)}finally{gt()}}function ne(t,e,n,r,o){var i;try{i=n?t.apply(e,n):t.call(e),i&&!i._isVue&&d(i)&&!i._handled&&(i.catch(function(t){return ee(t,r,o+\" (Promise/async)\")}),i._handled=!0)}catch(Oa){ee(Oa,r,o)}return i}function re(t,e,n){if(B.errorHandler)try{return B.errorHandler.call(null,t,e,n)}catch(Oa){Oa!==t&&oe(Oa,null,\"config.errorHandler\")}oe(t,e,n)}function oe(t,e,n){if(!J&&!Y||\"undefined\"===typeof console)throw t;console.error(t)}var ie,ae=!1,se=[],ce=!1;function ue(){ce=!1;var t=se.slice(0);se.length=0;for(var e=0;e<t.length;e++)t[e]()}if(\"undefined\"!==typeof Promise&&ft(Promise)){var fe=Promise.resolve();ie=function(){fe.then(ue),rt&&setTimeout(P)},ae=!0}else if(tt||\"undefined\"===typeof MutationObserver||!ft(MutationObserver)&&\"[object MutationObserverConstructor]\"!==MutationObserver.toString())ie=\"undefined\"!==typeof setImmediate&&ft(setImmediate)?function(){setImmediate(ue)}:function(){setTimeout(ue,0)};else{var le=1,pe=new MutationObserver(ue),de=document.createTextNode(String(le));pe.observe(de,{characterData:!0}),ie=function(){le=(le+1)%2,de.data=String(le)},ae=!0}function he(t,e){var n;if(se.push(function(){if(t)try{t.call(e)}catch(Oa){ee(Oa,e,\"nextTick\")}else n&&n(e)}),ce||(ce=!0,ie()),!t&&\"undefined\"!==typeof Promise)return new Promise(function(t){n=t})}var ve=new lt;function ye(t){me(t,ve),ve.clear()}function me(t,e){var n,r,o=Array.isArray(t);if(!(!o&&!c(t)||Object.isFrozen(t)||t instanceof bt)){if(t.__ob__){var i=t.__ob__.dep.id;if(e.has(i))return;e.add(i)}if(o){n=t.length;while(n--)me(t[n],e)}else{r=Object.keys(t),n=r.length;while(n--)me(t[r[n]],e)}}}var ge=w(function(t){var e=\"&\"===t.charAt(0);t=e?t.slice(1):t;var n=\"~\"===t.charAt(0);t=n?t.slice(1):t;var r=\"!\"===t.charAt(0);return t=r?t.slice(1):t,{name:t,once:n,capture:r,passive:e}});function be(t,e){function n(){var t=arguments,r=n.fns;if(!Array.isArray(r))return ne(r,null,arguments,e,\"v-on handler\");for(var o=r.slice(),i=0;i<o.length;i++)ne(o[i],null,t,e,\"v-on handler\")}return n.fns=t,n}function _e(t,e,n,o,a,s){var c,u,f,l;for(c in t)u=t[c],f=e[c],l=ge(c),r(u)||(r(f)?(r(u.fns)&&(u=t[c]=be(u,s)),i(l.once)&&(u=t[c]=a(l.name,u,l.capture)),n(l.name,u,l.capture,l.passive,l.params)):u!==f&&(f.fns=u,t[c]=f));for(c in e)r(t[c])&&(l=ge(c),o(l.name,e[c],l.capture))}function we(t,e,n){var a;t instanceof bt&&(t=t.data.hook||(t.data.hook={}));var s=t[e];function c(){n.apply(this,arguments),g(a.fns,c)}r(s)?a=be([c]):o(s.fns)&&i(s.merged)?(a=s,a.fns.push(c)):a=be([s,c]),a.merged=!0,t[e]=a}function xe(t,e,n){var i=e.options.props;if(!r(i)){var a={},s=t.attrs,c=t.props;if(o(s)||o(c))for(var u in i){var f=A(u);Oe(a,c,u,f,!0)||Oe(a,s,u,f,!1)}return a}}function Oe(t,e,n,r,i){if(o(e)){if(_(e,n))return t[n]=e[n],i||delete e[n],!0;if(_(e,r))return t[n]=e[r],i||delete e[r],!0}return!1}function Ee(t){for(var e=0;e<t.length;e++)if(Array.isArray(t[e]))return Array.prototype.concat.apply([],t);return t}function Se(t){return s(t)?[xt(t)]:Array.isArray(t)?Ce(t):void 0}function Ae(t){return o(t)&&o(t.text)&&a(t.isComment)}function Ce(t,e){var n,a,c,u,f=[];for(n=0;n<t.length;n++)a=t[n],r(a)||\"boolean\"===typeof a||(c=f.length-1,u=f[c],Array.isArray(a)?a.length>0&&(a=Ce(a,(e||\"\")+\"_\"+n),Ae(a[0])&&Ae(u)&&(f[c]=xt(u.text+a[0].text),a.shift()),f.push.apply(f,a)):s(a)?Ae(u)?f[c]=xt(u.text+a):\"\"!==a&&f.push(xt(a)):Ae(a)&&Ae(u)?f[c]=xt(u.text+a.text):(i(t._isVList)&&o(a.tag)&&r(a.key)&&o(e)&&(a.key=\"__vlist\"+e+\"_\"+n+\"__\"),f.push(a)));return f}function ke(t){var e=t.$options.provide;e&&(t._provided=\"function\"===typeof e?e.call(t):e)}function je(t){var e=Te(t.$options.inject,t);e&&(jt(!1),Object.keys(e).forEach(function(n){Lt(t,n,e[n])}),jt(!0))}function Te(t,e){if(t){for(var n=Object.create(null),r=pt?Reflect.ownKeys(t):Object.keys(t),o=0;o<r.length;o++){var i=r[o];if(\"__ob__\"!==i){var a=t[i].from,s=e;while(s){if(s._provided&&_(s._provided,a)){n[i]=s._provided[a];break}s=s.$parent}if(!s)if(\"default\"in t[i]){var c=t[i].default;n[i]=\"function\"===typeof c?c.call(e):c}else 0}}return n}}function $e(t,e){if(!t||!t.length)return{};for(var n={},r=0,o=t.length;r<o;r++){var i=t[r],a=i.data;if(a&&a.attrs&&a.attrs.slot&&delete a.attrs.slot,i.context!==e&&i.fnContext!==e||!a||null==a.slot)(n.default||(n.default=[])).push(i);else{var s=a.slot,c=n[s]||(n[s]=[]);\"template\"===i.tag?c.push.apply(c,i.children||[]):c.push(i)}}for(var u in n)n[u].every(Me)&&delete n[u];return n}function Me(t){return t.isComment&&!t.asyncFactory||\" \"===t.text}function Pe(t,e,r){var o,i=Object.keys(e).length>0,a=t?!!t.$stable:!i,s=t&&t.$key;if(t){if(t._normalized)return t._normalized;if(a&&r&&r!==n&&s===r.$key&&!i&&!r.$hasNormal)return r;for(var c in o={},t)t[c]&&\"$\"!==c[0]&&(o[c]=Le(e,c,t[c]))}else o={};for(var u in e)u in o||(o[u]=Re(e,u));return t&&Object.isExtensible(t)&&(t._normalized=o),z(o,\"$stable\",a),z(o,\"$key\",s),z(o,\"$hasNormal\",i),o}function Le(t,e,n){var r=function(){var t=arguments.length?n.apply(null,arguments):n({});return t=t&&\"object\"===typeof t&&!Array.isArray(t)?[t]:Se(t),t&&(0===t.length||1===t.length&&t[0].isComment)?void 0:t};return n.proxy&&Object.defineProperty(t,e,{get:r,enumerable:!0,configurable:!0}),r}function Re(t,e){return function(){return t[e]}}function Ne(t,e){var n,r,i,a,s;if(Array.isArray(t)||\"string\"===typeof t)for(n=new Array(t.length),r=0,i=t.length;r<i;r++)n[r]=e(t[r],r);else if(\"number\"===typeof t)for(n=new Array(t),r=0;r<t;r++)n[r]=e(r+1,r);else if(c(t))if(pt&&t[Symbol.iterator]){n=[];var u=t[Symbol.iterator](),f=u.next();while(!f.done)n.push(e(f.value,n.length)),f=u.next()}else for(a=Object.keys(t),n=new Array(a.length),r=0,i=a.length;r<i;r++)s=a[r],n[r]=e(t[s],s,r);return o(n)||(n=[]),n._isVList=!0,n}function Fe(t,e,n,r){var o,i=this.$scopedSlots[t];i?(n=n||{},r&&(n=$($({},r),n)),o=i(n)||e):o=this.$slots[t]||e;var a=n&&n.slot;return a?this.$createElement(\"template\",{slot:a},o):o}function Ie(t){return Xt(this.$options,\"filters\",t,!0)||R}function De(t,e){return Array.isArray(t)?-1===t.indexOf(e):t!==e}function qe(t,e,n,r,o){var i=B.keyCodes[e]||n;return o&&r&&!B.keyCodes[e]?De(o,r):i?De(i,t):r?A(r)!==e:void 0}function Ue(t,e,n,r,o){if(n)if(c(n)){var i;Array.isArray(n)&&(n=M(n));var a=function(a){if(\"class\"===a||\"style\"===a||m(a))i=t;else{var s=t.attrs&&t.attrs.type;i=r||B.mustUseProp(e,s,a)?t.domProps||(t.domProps={}):t.attrs||(t.attrs={})}var c=O(a),u=A(a);if(!(c in i)&&!(u in i)&&(i[a]=n[a],o)){var f=t.on||(t.on={});f[\"update:\"+a]=function(t){n[a]=t}}};for(var s in n)a(s)}else;return t}function Be(t,e){var n=this._staticTrees||(this._staticTrees=[]),r=n[t];return r&&!e?r:(r=n[t]=this.$options.staticRenderFns[t].call(this._renderProxy,null,this),He(r,\"__static__\"+t,!1),r)}function Ve(t,e,n){return He(t,\"__once__\"+e+(n?\"_\"+n:\"\"),!0),t}function He(t,e,n){if(Array.isArray(t))for(var r=0;r<t.length;r++)t[r]&&\"string\"!==typeof t[r]&&ze(t[r],e+\"_\"+r,n);else ze(t,e,n)}function ze(t,e,n){t.isStatic=!0,t.key=e,t.isOnce=n}function Ge(t,e){if(e)if(f(e)){var n=t.on=t.on?$({},t.on):{};for(var r in e){var o=n[r],i=e[r];n[r]=o?[].concat(o,i):i}}else;return t}function We(t,e,n,r){e=e||{$stable:!n};for(var o=0;o<t.length;o++){var i=t[o];Array.isArray(i)?We(i,e,n):i&&(i.proxy&&(i.fn.proxy=!0),e[i.key]=i.fn)}return r&&(e.$key=r),e}function Ke(t,e){for(var n=0;n<e.length;n+=2){var r=e[n];\"string\"===typeof r&&r&&(t[e[n]]=e[n+1])}return t}function Xe(t,e){return\"string\"===typeof t?e+t:t}function Je(t){t._o=Ve,t._n=v,t._s=h,t._l=Ne,t._t=Fe,t._q=N,t._i=F,t._m=Be,t._f=Ie,t._k=qe,t._b=Ue,t._v=xt,t._e=wt,t._u=We,t._g=Ge,t._d=Ke,t._p=Xe}function Ye(t,e,r,o,a){var s,c=this,u=a.options;_(o,\"_uid\")?(s=Object.create(o),s._original=o):(s=o,o=o._original);var f=i(u._compiled),l=!f;this.data=t,this.props=e,this.children=r,this.parent=o,this.listeners=t.on||n,this.injections=Te(u.inject,o),this.slots=function(){return c.$slots||Pe(t.scopedSlots,c.$slots=$e(r,o)),c.$slots},Object.defineProperty(this,\"scopedSlots\",{enumerable:!0,get:function(){return Pe(t.scopedSlots,this.slots())}}),f&&(this.$options=u,this.$slots=this.slots(),this.$scopedSlots=Pe(t.scopedSlots,this.$slots)),u._scopeId?this._c=function(t,e,n,r){var i=ln(s,t,e,n,r,l);return i&&!Array.isArray(i)&&(i.fnScopeId=u._scopeId,i.fnContext=o),i}:this._c=function(t,e,n,r){return ln(s,t,e,n,r,l)}}function Ze(t,e,r,i,a){var s=t.options,c={},u=s.props;if(o(u))for(var f in u)c[f]=Jt(f,u,e||n);else o(r.attrs)&&tn(c,r.attrs),o(r.props)&&tn(c,r.props);var l=new Ye(r,c,a,i,t),p=s.render.call(null,l._c,l);if(p instanceof bt)return Qe(p,r,l.parent,s,l);if(Array.isArray(p)){for(var d=Se(p)||[],h=new Array(d.length),v=0;v<d.length;v++)h[v]=Qe(d[v],r,l.parent,s,l);return h}}function Qe(t,e,n,r,o){var i=Ot(t);return i.fnContext=n,i.fnOptions=r,e.slot&&((i.data||(i.data={})).slot=e.slot),i}function tn(t,e){for(var n in e)t[O(n)]=e[n]}Je(Ye.prototype);var en={init:function(t,e){if(t.componentInstance&&!t.componentInstance._isDestroyed&&t.data.keepAlive){var n=t;en.prepatch(n,n)}else{var r=t.componentInstance=on(t,Tn);r.$mount(e?t.elm:void 0,e)}},prepatch:function(t,e){var n=e.componentOptions,r=e.componentInstance=t.componentInstance;Rn(r,n.propsData,n.listeners,e,n.children)},insert:function(t){var e=t.context,n=t.componentInstance;n._isMounted||(n._isMounted=!0,Dn(n,\"mounted\")),t.data.keepAlive&&(e._isMounted?Zn(n):Fn(n,!0))},destroy:function(t){var e=t.componentInstance;e._isDestroyed||(t.data.keepAlive?In(e,!0):e.$destroy())}},nn=Object.keys(en);function rn(t,e,n,a,s){if(!r(t)){var u=n.$options._base;if(c(t)&&(t=u.extend(t)),\"function\"===typeof t){var f;if(r(t.cid)&&(f=t,t=wn(f,u),void 0===t))return _n(f,e,n,a,s);e=e||{},wr(t),o(e.model)&&cn(t.options,e);var l=xe(e,t,s);if(i(t.options.functional))return Ze(t,l,e,n,a);var p=e.on;if(e.on=e.nativeOn,i(t.options.abstract)){var d=e.slot;e={},d&&(e.slot=d)}an(e);var h=t.options.name||s,v=new bt(\"vue-component-\"+t.cid+(h?\"-\"+h:\"\"),e,void 0,void 0,void 0,n,{Ctor:t,propsData:l,listeners:p,tag:s,children:a},f);return v}}}function on(t,e){var n={_isComponent:!0,_parentVnode:t,parent:e},r=t.data.inlineTemplate;return o(r)&&(n.render=r.render,n.staticRenderFns=r.staticRenderFns),new t.componentOptions.Ctor(n)}function an(t){for(var e=t.hook||(t.hook={}),n=0;n<nn.length;n++){var r=nn[n],o=e[r],i=en[r];o===i||o&&o._merged||(e[r]=o?sn(i,o):i)}}function sn(t,e){var n=function(n,r){t(n,r),e(n,r)};return n._merged=!0,n}function cn(t,e){var n=t.model&&t.model.prop||\"value\",r=t.model&&t.model.event||\"input\";(e.attrs||(e.attrs={}))[n]=e.model.value;var i=e.on||(e.on={}),a=i[r],s=e.model.callback;o(a)?(Array.isArray(a)?-1===a.indexOf(s):a!==s)&&(i[r]=[s].concat(a)):i[r]=s}var un=1,fn=2;function ln(t,e,n,r,o,a){return(Array.isArray(n)||s(n))&&(o=r,r=n,n=void 0),i(a)&&(o=fn),pn(t,e,n,r,o)}function pn(t,e,n,r,i){if(o(n)&&o(n.__ob__))return wt();if(o(n)&&o(n.is)&&(e=n.is),!e)return wt();var a,s,c;(Array.isArray(r)&&\"function\"===typeof r[0]&&(n=n||{},n.scopedSlots={default:r[0]},r.length=0),i===fn?r=Se(r):i===un&&(r=Ee(r)),\"string\"===typeof e)?(s=t.$vnode&&t.$vnode.ns||B.getTagNamespace(e),a=B.isReservedTag(e)?new bt(B.parsePlatformTagName(e),n,r,void 0,void 0,t):n&&n.pre||!o(c=Xt(t.$options,\"components\",e))?new bt(e,n,r,void 0,void 0,t):rn(c,n,t,r,e)):a=rn(e,n,t,r);return Array.isArray(a)?a:o(a)?(o(s)&&dn(a,s),o(n)&&hn(n),a):wt()}function dn(t,e,n){if(t.ns=e,\"foreignObject\"===t.tag&&(e=void 0,n=!0),o(t.children))for(var a=0,s=t.children.length;a<s;a++){var c=t.children[a];o(c.tag)&&(r(c.ns)||i(n)&&\"svg\"!==c.tag)&&dn(c,e,n)}}function hn(t){c(t.style)&&ye(t.style),c(t.class)&&ye(t.class)}function vn(t){t._vnode=null,t._staticTrees=null;var e=t.$options,r=t.$vnode=e._parentVnode,o=r&&r.context;t.$slots=$e(e._renderChildren,o),t.$scopedSlots=n,t._c=function(e,n,r,o){return ln(t,e,n,r,o,!1)},t.$createElement=function(e,n,r,o){return ln(t,e,n,r,o,!0)};var i=r&&r.data;Lt(t,\"$attrs\",i&&i.attrs||n,null,!0),Lt(t,\"$listeners\",e._parentListeners||n,null,!0)}var yn,mn=null;function gn(t){Je(t.prototype),t.prototype.$nextTick=function(t){return he(t,this)},t.prototype._render=function(){var t,e=this,n=e.$options,r=n.render,o=n._parentVnode;o&&(e.$scopedSlots=Pe(o.data.scopedSlots,e.$slots,e.$scopedSlots)),e.$vnode=o;try{mn=e,t=r.call(e._renderProxy,e.$createElement)}catch(Oa){ee(Oa,e,\"render\"),t=e._vnode}finally{mn=null}return Array.isArray(t)&&1===t.length&&(t=t[0]),t instanceof bt||(t=wt()),t.parent=o,t}}function bn(t,e){return(t.__esModule||pt&&\"Module\"===t[Symbol.toStringTag])&&(t=t.default),c(t)?e.extend(t):t}function _n(t,e,n,r,o){var i=wt();return i.asyncFactory=t,i.asyncMeta={data:e,context:n,children:r,tag:o},i}function wn(t,e){if(i(t.error)&&o(t.errorComp))return t.errorComp;if(o(t.resolved))return t.resolved;var n=mn;if(n&&o(t.owners)&&-1===t.owners.indexOf(n)&&t.owners.push(n),i(t.loading)&&o(t.loadingComp))return t.loadingComp;if(n&&!o(t.owners)){var a=t.owners=[n],s=!0,u=null,f=null;n.$on(\"hook:destroyed\",function(){return g(a,n)});var l=function(t){for(var e=0,n=a.length;e<n;e++)a[e].$forceUpdate();t&&(a.length=0,null!==u&&(clearTimeout(u),u=null),null!==f&&(clearTimeout(f),f=null))},p=I(function(n){t.resolved=bn(n,e),s?a.length=0:l(!0)}),h=I(function(e){o(t.errorComp)&&(t.error=!0,l(!0))}),v=t(p,h);return c(v)&&(d(v)?r(t.resolved)&&v.then(p,h):d(v.component)&&(v.component.then(p,h),o(v.error)&&(t.errorComp=bn(v.error,e)),o(v.loading)&&(t.loadingComp=bn(v.loading,e),0===v.delay?t.loading=!0:u=setTimeout(function(){u=null,r(t.resolved)&&r(t.error)&&(t.loading=!0,l(!1))},v.delay||200)),o(v.timeout)&&(f=setTimeout(function(){f=null,r(t.resolved)&&h(null)},v.timeout)))),s=!1,t.loading?t.loadingComp:t.resolved}}function xn(t){return t.isComment&&t.asyncFactory}function On(t){if(Array.isArray(t))for(var e=0;e<t.length;e++){var n=t[e];if(o(n)&&(o(n.componentOptions)||xn(n)))return n}}function En(t){t._events=Object.create(null),t._hasHookEvent=!1;var e=t.$options._parentListeners;e&&kn(t,e)}function Sn(t,e){yn.$on(t,e)}function An(t,e){yn.$off(t,e)}function Cn(t,e){var n=yn;return function r(){var o=e.apply(null,arguments);null!==o&&n.$off(t,r)}}function kn(t,e,n){yn=t,_e(e,n||{},Sn,An,Cn,t),yn=void 0}function jn(t){var e=/^hook:/;t.prototype.$on=function(t,n){var r=this;if(Array.isArray(t))for(var o=0,i=t.length;o<i;o++)r.$on(t[o],n);else(r._events[t]||(r._events[t]=[])).push(n),e.test(t)&&(r._hasHookEvent=!0);return r},t.prototype.$once=function(t,e){var n=this;function r(){n.$off(t,r),e.apply(n,arguments)}return r.fn=e,n.$on(t,r),n},t.prototype.$off=function(t,e){var n=this;if(!arguments.length)return n._events=Object.create(null),n;if(Array.isArray(t)){for(var r=0,o=t.length;r<o;r++)n.$off(t[r],e);return n}var i,a=n._events[t];if(!a)return n;if(!e)return n._events[t]=null,n;var s=a.length;while(s--)if(i=a[s],i===e||i.fn===e){a.splice(s,1);break}return n},t.prototype.$emit=function(t){var e=this,n=e._events[t];if(n){n=n.length>1?T(n):n;for(var r=T(arguments,1),o='event handler for \"'+t+'\"',i=0,a=n.length;i<a;i++)ne(n[i],e,r,e,o)}return e}}var Tn=null;function $n(t){var e=Tn;return Tn=t,function(){Tn=e}}function Mn(t){var e=t.$options,n=e.parent;if(n&&!e.abstract){while(n.$options.abstract&&n.$parent)n=n.$parent;n.$children.push(t)}t.$parent=n,t.$root=n?n.$root:t,t.$children=[],t.$refs={},t._watcher=null,t._inactive=null,t._directInactive=!1,t._isMounted=!1,t._isDestroyed=!1,t._isBeingDestroyed=!1}function Pn(t){t.prototype._update=function(t,e){var n=this,r=n.$el,o=n._vnode,i=$n(n);n._vnode=t,n.$el=o?n.__patch__(o,t):n.__patch__(n.$el,t,e,!1),i(),r&&(r.__vue__=null),n.$el&&(n.$el.__vue__=n),n.$vnode&&n.$parent&&n.$vnode===n.$parent._vnode&&(n.$parent.$el=n.$el)},t.prototype.$forceUpdate=function(){var t=this;t._watcher&&t._watcher.update()},t.prototype.$destroy=function(){var t=this;if(!t._isBeingDestroyed){Dn(t,\"beforeDestroy\"),t._isBeingDestroyed=!0;var e=t.$parent;!e||e._isBeingDestroyed||t.$options.abstract||g(e.$children,t),t._watcher&&t._watcher.teardown();var n=t._watchers.length;while(n--)t._watchers[n].teardown();t._data.__ob__&&t._data.__ob__.vmCount--,t._isDestroyed=!0,t.__patch__(t._vnode,null),Dn(t,\"destroyed\"),t.$off(),t.$el&&(t.$el.__vue__=null),t.$vnode&&(t.$vnode.parent=null)}}}function Ln(t,e,n){var r;return t.$el=e,t.$options.render||(t.$options.render=wt),Dn(t,\"beforeMount\"),r=function(){t._update(t._render(),n)},new nr(t,r,P,{before:function(){t._isMounted&&!t._isDestroyed&&Dn(t,\"beforeUpdate\")}},!0),n=!1,null==t.$vnode&&(t._isMounted=!0,Dn(t,\"mounted\")),t}function Rn(t,e,r,o,i){var a=o.data.scopedSlots,s=t.$scopedSlots,c=!!(a&&!a.$stable||s!==n&&!s.$stable||a&&t.$scopedSlots.$key!==a.$key),u=!!(i||t.$options._renderChildren||c);if(t.$options._parentVnode=o,t.$vnode=o,t._vnode&&(t._vnode.parent=o),t.$options._renderChildren=i,t.$attrs=o.data.attrs||n,t.$listeners=r||n,e&&t.$options.props){jt(!1);for(var f=t._props,l=t.$options._propKeys||[],p=0;p<l.length;p++){var d=l[p],h=t.$options.props;f[d]=Jt(d,h,e,t)}jt(!0),t.$options.propsData=e}r=r||n;var v=t.$options._parentListeners;t.$options._parentListeners=r,kn(t,r,v),u&&(t.$slots=$e(i,o.context),t.$forceUpdate())}function Nn(t){while(t&&(t=t.$parent))if(t._inactive)return!0;return!1}function Fn(t,e){if(e){if(t._directInactive=!1,Nn(t))return}else if(t._directInactive)return;if(t._inactive||null===t._inactive){t._inactive=!1;for(var n=0;n<t.$children.length;n++)Fn(t.$children[n]);Dn(t,\"activated\")}}function In(t,e){if((!e||(t._directInactive=!0,!Nn(t)))&&!t._inactive){t._inactive=!0;for(var n=0;n<t.$children.length;n++)In(t.$children[n]);Dn(t,\"deactivated\")}}function Dn(t,e){mt();var n=t.$options[e],r=e+\" hook\";if(n)for(var o=0,i=n.length;o<i;o++)ne(n[o],t,null,t,r);t._hasHookEvent&&t.$emit(\"hook:\"+e),gt()}var qn=[],Un=[],Bn={},Vn=!1,Hn=!1,zn=0;function Gn(){zn=qn.length=Un.length=0,Bn={},Vn=Hn=!1}var Wn=0,Kn=Date.now;if(J&&!tt){var Xn=window.performance;Xn&&\"function\"===typeof Xn.now&&Kn()>document.createEvent(\"Event\").timeStamp&&(Kn=function(){return Xn.now()})}function Jn(){var t,e;for(Wn=Kn(),Hn=!0,qn.sort(function(t,e){return t.id-e.id}),zn=0;zn<qn.length;zn++)t=qn[zn],t.before&&t.before(),e=t.id,Bn[e]=null,t.run();var n=Un.slice(),r=qn.slice();Gn(),Qn(n),Yn(r),ut&&B.devtools&&ut.emit(\"flush\")}function Yn(t){var e=t.length;while(e--){var n=t[e],r=n.vm;r._watcher===n&&r._isMounted&&!r._isDestroyed&&Dn(r,\"updated\")}}function Zn(t){t._inactive=!1,Un.push(t)}function Qn(t){for(var e=0;e<t.length;e++)t[e]._inactive=!0,Fn(t[e],!0)}function tr(t){var e=t.id;if(null==Bn[e]){if(Bn[e]=!0,Hn){var n=qn.length-1;while(n>zn&&qn[n].id>t.id)n--;qn.splice(n+1,0,t)}else qn.push(t);Vn||(Vn=!0,he(Jn))}}var er=0,nr=function(t,e,n,r,o){this.vm=t,o&&(t._watcher=this),t._watchers.push(this),r?(this.deep=!!r.deep,this.user=!!r.user,this.lazy=!!r.lazy,this.sync=!!r.sync,this.before=r.before):this.deep=this.user=this.lazy=this.sync=!1,this.cb=n,this.id=++er,this.active=!0,this.dirty=this.lazy,this.deps=[],this.newDeps=[],this.depIds=new lt,this.newDepIds=new lt,this.expression=\"\",\"function\"===typeof e?this.getter=e:(this.getter=W(e),this.getter||(this.getter=P)),this.value=this.lazy?void 0:this.get()};nr.prototype.get=function(){var t;mt(this);var e=this.vm;try{t=this.getter.call(e,e)}catch(Oa){if(!this.user)throw Oa;ee(Oa,e,'getter for watcher \"'+this.expression+'\"')}finally{this.deep&&ye(t),gt(),this.cleanupDeps()}return t},nr.prototype.addDep=function(t){var e=t.id;this.newDepIds.has(e)||(this.newDepIds.add(e),this.newDeps.push(t),this.depIds.has(e)||t.addSub(this))},nr.prototype.cleanupDeps=function(){var t=this.deps.length;while(t--){var e=this.deps[t];this.newDepIds.has(e.id)||e.removeSub(this)}var n=this.depIds;this.depIds=this.newDepIds,this.newDepIds=n,this.newDepIds.clear(),n=this.deps,this.deps=this.newDeps,this.newDeps=n,this.newDeps.length=0},nr.prototype.update=function(){this.lazy?this.dirty=!0:this.sync?this.run():tr(this)},nr.prototype.run=function(){if(this.active){var t=this.get();if(t!==this.value||c(t)||this.deep){var e=this.value;if(this.value=t,this.user)try{this.cb.call(this.vm,t,e)}catch(Oa){ee(Oa,this.vm,'callback for watcher \"'+this.expression+'\"')}else this.cb.call(this.vm,t,e)}}},nr.prototype.evaluate=function(){this.value=this.get(),this.dirty=!1},nr.prototype.depend=function(){var t=this.deps.length;while(t--)this.deps[t].depend()},nr.prototype.teardown=function(){if(this.active){this.vm._isBeingDestroyed||g(this.vm._watchers,this);var t=this.deps.length;while(t--)this.deps[t].removeSub(this);this.active=!1}};var rr={enumerable:!0,configurable:!0,get:P,set:P};function or(t,e,n){rr.get=function(){return this[e][n]},rr.set=function(t){this[e][n]=t},Object.defineProperty(t,n,rr)}function ir(t){t._watchers=[];var e=t.$options;e.props&&ar(t,e.props),e.methods&&hr(t,e.methods),e.data?sr(t):Pt(t._data={},!0),e.computed&&fr(t,e.computed),e.watch&&e.watch!==it&&vr(t,e.watch)}function ar(t,e){var n=t.$options.propsData||{},r=t._props={},o=t.$options._propKeys=[],i=!t.$parent;i||jt(!1);var a=function(i){o.push(i);var a=Jt(i,e,n,t);Lt(r,i,a),i in t||or(t,\"_props\",i)};for(var s in e)a(s);jt(!0)}function sr(t){var e=t.$options.data;e=t._data=\"function\"===typeof e?cr(e,t):e||{},f(e)||(e={});var n=Object.keys(e),r=t.$options.props,o=(t.$options.methods,n.length);while(o--){var i=n[o];0,r&&_(r,i)||H(i)||or(t,\"_data\",i)}Pt(e,!0)}function cr(t,e){mt();try{return t.call(e,e)}catch(Oa){return ee(Oa,e,\"data()\"),{}}finally{gt()}}var ur={lazy:!0};function fr(t,e){var n=t._computedWatchers=Object.create(null),r=ct();for(var o in e){var i=e[o],a=\"function\"===typeof i?i:i.get;0,r||(n[o]=new nr(t,a||P,P,ur)),o in t||lr(t,o,i)}}function lr(t,e,n){var r=!ct();\"function\"===typeof n?(rr.get=r?pr(e):dr(n),rr.set=P):(rr.get=n.get?r&&!1!==n.cache?pr(e):dr(n.get):P,rr.set=n.set||P),Object.defineProperty(t,e,rr)}function pr(t){return function(){var e=this._computedWatchers&&this._computedWatchers[t];if(e)return e.dirty&&e.evaluate(),vt.target&&e.depend(),e.value}}function dr(t){return function(){return t.call(this,this)}}function hr(t,e){t.$options.props;for(var n in e)t[n]=\"function\"!==typeof e[n]?P:j(e[n],t)}function vr(t,e){for(var n in e){var r=e[n];if(Array.isArray(r))for(var o=0;o<r.length;o++)yr(t,n,r[o]);else yr(t,n,r)}}function yr(t,e,n,r){return f(n)&&(r=n,n=n.handler),\"string\"===typeof n&&(n=t[n]),t.$watch(e,n,r)}function mr(t){var e={get:function(){return this._data}},n={get:function(){return this._props}};Object.defineProperty(t.prototype,\"$data\",e),Object.defineProperty(t.prototype,\"$props\",n),t.prototype.$set=Rt,t.prototype.$delete=Nt,t.prototype.$watch=function(t,e,n){var r=this;if(f(e))return yr(r,t,e,n);n=n||{},n.user=!0;var o=new nr(r,t,e,n);if(n.immediate)try{e.call(r,o.value)}catch(i){ee(i,r,'callback for immediate watcher \"'+o.expression+'\"')}return function(){o.teardown()}}}var gr=0;function br(t){t.prototype._init=function(t){var e=this;e._uid=gr++,e._isVue=!0,t&&t._isComponent?_r(e,t):e.$options=Kt(wr(e.constructor),t||{},e),e._renderProxy=e,e._self=e,Mn(e),En(e),vn(e),Dn(e,\"beforeCreate\"),je(e),ir(e),ke(e),Dn(e,\"created\"),e.$options.el&&e.$mount(e.$options.el)}}function _r(t,e){var n=t.$options=Object.create(t.constructor.options),r=e._parentVnode;n.parent=e.parent,n._parentVnode=r;var o=r.componentOptions;n.propsData=o.propsData,n._parentListeners=o.listeners,n._renderChildren=o.children,n._componentTag=o.tag,e.render&&(n.render=e.render,n.staticRenderFns=e.staticRenderFns)}function wr(t){var e=t.options;if(t.super){var n=wr(t.super),r=t.superOptions;if(n!==r){t.superOptions=n;var o=xr(t);o&&$(t.extendOptions,o),e=t.options=Kt(n,t.extendOptions),e.name&&(e.components[e.name]=t)}}return e}function xr(t){var e,n=t.options,r=t.sealedOptions;for(var o in n)n[o]!==r[o]&&(e||(e={}),e[o]=n[o]);return e}function Or(t){this._init(t)}function Er(t){t.use=function(t){var e=this._installedPlugins||(this._installedPlugins=[]);if(e.indexOf(t)>-1)return this;var n=T(arguments,1);return n.unshift(this),\"function\"===typeof t.install?t.install.apply(t,n):\"function\"===typeof t&&t.apply(null,n),e.push(t),this}}function Sr(t){t.mixin=function(t){return this.options=Kt(this.options,t),this}}function Ar(t){t.cid=0;var e=1;t.extend=function(t){t=t||{};var n=this,r=n.cid,o=t._Ctor||(t._Ctor={});if(o[r])return o[r];var i=t.name||n.options.name;var a=function(t){this._init(t)};return a.prototype=Object.create(n.prototype),a.prototype.constructor=a,a.cid=e++,a.options=Kt(n.options,t),a[\"super\"]=n,a.options.props&&Cr(a),a.options.computed&&kr(a),a.extend=n.extend,a.mixin=n.mixin,a.use=n.use,q.forEach(function(t){a[t]=n[t]}),i&&(a.options.components[i]=a),a.superOptions=n.options,a.extendOptions=t,a.sealedOptions=$({},a.options),o[r]=a,a}}function Cr(t){var e=t.options.props;for(var n in e)or(t.prototype,\"_props\",n)}function kr(t){var e=t.options.computed;for(var n in e)lr(t.prototype,n,e[n])}function jr(t){q.forEach(function(e){t[e]=function(t,n){return n?(\"component\"===e&&f(n)&&(n.name=n.name||t,n=this.options._base.extend(n)),\"directive\"===e&&\"function\"===typeof n&&(n={bind:n,update:n}),this.options[e+\"s\"][t]=n,n):this.options[e+\"s\"][t]}})}function Tr(t){return t&&(t.Ctor.options.name||t.tag)}function $r(t,e){return Array.isArray(t)?t.indexOf(e)>-1:\"string\"===typeof t?t.split(\",\").indexOf(e)>-1:!!l(t)&&t.test(e)}function Mr(t,e){var n=t.cache,r=t.keys,o=t._vnode;for(var i in n){var a=n[i];if(a){var s=Tr(a.componentOptions);s&&!e(s)&&Pr(n,i,r,o)}}}function Pr(t,e,n,r){var o=t[e];!o||r&&o.tag===r.tag||o.componentInstance.$destroy(),t[e]=null,g(n,e)}br(Or),mr(Or),jn(Or),Pn(Or),gn(Or);var Lr=[String,RegExp,Array],Rr={name:\"keep-alive\",abstract:!0,props:{include:Lr,exclude:Lr,max:[String,Number]},created:function(){this.cache=Object.create(null),this.keys=[]},destroyed:function(){for(var t in this.cache)Pr(this.cache,t,this.keys)},mounted:function(){var t=this;this.$watch(\"include\",function(e){Mr(t,function(t){return $r(e,t)})}),this.$watch(\"exclude\",function(e){Mr(t,function(t){return!$r(e,t)})})},render:function(){var t=this.$slots.default,e=On(t),n=e&&e.componentOptions;if(n){var r=Tr(n),o=this,i=o.include,a=o.exclude;if(i&&(!r||!$r(i,r))||a&&r&&$r(a,r))return e;var s=this,c=s.cache,u=s.keys,f=null==e.key?n.Ctor.cid+(n.tag?\"::\"+n.tag:\"\"):e.key;c[f]?(e.componentInstance=c[f].componentInstance,g(u,f),u.push(f)):(c[f]=e,u.push(f),this.max&&u.length>parseInt(this.max)&&Pr(c,u[0],u,this._vnode)),e.data.keepAlive=!0}return e||t&&t[0]}},Nr={KeepAlive:Rr};function Fr(t){var e={get:function(){return B}};Object.defineProperty(t,\"config\",e),t.util={warn:dt,extend:$,mergeOptions:Kt,defineReactive:Lt},t.set=Rt,t.delete=Nt,t.nextTick=he,t.observable=function(t){return Pt(t),t},t.options=Object.create(null),q.forEach(function(e){t.options[e+\"s\"]=Object.create(null)}),t.options._base=t,$(t.options.components,Nr),Er(t),Sr(t),Ar(t),jr(t)}Fr(Or),Object.defineProperty(Or.prototype,\"$isServer\",{get:ct}),Object.defineProperty(Or.prototype,\"$ssrContext\",{get:function(){return this.$vnode&&this.$vnode.ssrContext}}),Object.defineProperty(Or,\"FunctionalRenderContext\",{value:Ye}),Or.version=\"2.6.10\";var Ir=y(\"style,class\"),Dr=y(\"input,textarea,option,select,progress\"),qr=function(t,e,n){return\"value\"===n&&Dr(t)&&\"button\"!==e||\"selected\"===n&&\"option\"===t||\"checked\"===n&&\"input\"===t||\"muted\"===n&&\"video\"===t},Ur=y(\"contenteditable,draggable,spellcheck\"),Br=y(\"events,caret,typing,plaintext-only\"),Vr=function(t,e){return Kr(e)||\"false\"===e?\"false\":\"contenteditable\"===t&&Br(e)?e:\"true\"},Hr=y(\"allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,default,defaultchecked,defaultmuted,defaultselected,defer,disabled,enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,required,reversed,scoped,seamless,selected,sortable,translate,truespeed,typemustmatch,visible\"),zr=\"http://www.w3.org/1999/xlink\",Gr=function(t){return\":\"===t.charAt(5)&&\"xlink\"===t.slice(0,5)},Wr=function(t){return Gr(t)?t.slice(6,t.length):\"\"},Kr=function(t){return null==t||!1===t};function Xr(t){var e=t.data,n=t,r=t;while(o(r.componentInstance))r=r.componentInstance._vnode,r&&r.data&&(e=Jr(r.data,e));while(o(n=n.parent))n&&n.data&&(e=Jr(e,n.data));return Yr(e.staticClass,e.class)}function Jr(t,e){return{staticClass:Zr(t.staticClass,e.staticClass),class:o(t.class)?[t.class,e.class]:e.class}}function Yr(t,e){return o(t)||o(e)?Zr(t,Qr(e)):\"\"}function Zr(t,e){return t?e?t+\" \"+e:t:e||\"\"}function Qr(t){return Array.isArray(t)?to(t):c(t)?eo(t):\"string\"===typeof t?t:\"\"}function to(t){for(var e,n=\"\",r=0,i=t.length;r<i;r++)o(e=Qr(t[r]))&&\"\"!==e&&(n&&(n+=\" \"),n+=e);return n}function eo(t){var e=\"\";for(var n in t)t[n]&&(e&&(e+=\" \"),e+=n);return e}var no={svg:\"http://www.w3.org/2000/svg\",math:\"http://www.w3.org/1998/Math/MathML\"},ro=y(\"html,body,base,head,link,meta,style,title,address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,s,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,output,progress,select,textarea,details,dialog,menu,menuitem,summary,content,element,shadow,template,blockquote,iframe,tfoot\"),oo=y(\"svg,animate,circle,clippath,cursor,defs,desc,ellipse,filter,font-face,foreignObject,g,glyph,image,line,marker,mask,missing-glyph,path,pattern,polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view\",!0),io=function(t){return ro(t)||oo(t)};function ao(t){return oo(t)?\"svg\":\"math\"===t?\"math\":void 0}var so=Object.create(null);function co(t){if(!J)return!0;if(io(t))return!1;if(t=t.toLowerCase(),null!=so[t])return so[t];var e=document.createElement(t);return t.indexOf(\"-\")>-1?so[t]=e.constructor===window.HTMLUnknownElement||e.constructor===window.HTMLElement:so[t]=/HTMLUnknownElement/.test(e.toString())}var uo=y(\"text,number,password,search,email,tel,url\");function fo(t){if(\"string\"===typeof t){var e=document.querySelector(t);return e||document.createElement(\"div\")}return t}function lo(t,e){var n=document.createElement(t);return\"select\"!==t?n:(e.data&&e.data.attrs&&void 0!==e.data.attrs.multiple&&n.setAttribute(\"multiple\",\"multiple\"),n)}function po(t,e){return document.createElementNS(no[t],e)}function ho(t){return document.createTextNode(t)}function vo(t){return document.createComment(t)}function yo(t,e,n){t.insertBefore(e,n)}function mo(t,e){t.removeChild(e)}function go(t,e){t.appendChild(e)}function bo(t){return t.parentNode}function _o(t){return t.nextSibling}function wo(t){return t.tagName}function xo(t,e){t.textContent=e}function Oo(t,e){t.setAttribute(e,\"\")}var Eo=Object.freeze({createElement:lo,createElementNS:po,createTextNode:ho,createComment:vo,insertBefore:yo,removeChild:mo,appendChild:go,parentNode:bo,nextSibling:_o,tagName:wo,setTextContent:xo,setStyleScope:Oo}),So={create:function(t,e){Ao(e)},update:function(t,e){t.data.ref!==e.data.ref&&(Ao(t,!0),Ao(e))},destroy:function(t){Ao(t,!0)}};function Ao(t,e){var n=t.data.ref;if(o(n)){var r=t.context,i=t.componentInstance||t.elm,a=r.$refs;e?Array.isArray(a[n])?g(a[n],i):a[n]===i&&(a[n]=void 0):t.data.refInFor?Array.isArray(a[n])?a[n].indexOf(i)<0&&a[n].push(i):a[n]=[i]:a[n]=i}}var Co=new bt(\"\",{},[]),ko=[\"create\",\"activate\",\"update\",\"remove\",\"destroy\"];function jo(t,e){return t.key===e.key&&(t.tag===e.tag&&t.isComment===e.isComment&&o(t.data)===o(e.data)&&To(t,e)||i(t.isAsyncPlaceholder)&&t.asyncFactory===e.asyncFactory&&r(e.asyncFactory.error))}function To(t,e){if(\"input\"!==t.tag)return!0;var n,r=o(n=t.data)&&o(n=n.attrs)&&n.type,i=o(n=e.data)&&o(n=n.attrs)&&n.type;return r===i||uo(r)&&uo(i)}function $o(t,e,n){var r,i,a={};for(r=e;r<=n;++r)i=t[r].key,o(i)&&(a[i]=r);return a}function Mo(t){var e,n,a={},c=t.modules,u=t.nodeOps;for(e=0;e<ko.length;++e)for(a[ko[e]]=[],n=0;n<c.length;++n)o(c[n][ko[e]])&&a[ko[e]].push(c[n][ko[e]]);function f(t){return new bt(u.tagName(t).toLowerCase(),{},[],void 0,t)}function l(t,e){function n(){0===--n.listeners&&p(t)}return n.listeners=e,n}function p(t){var e=u.parentNode(t);o(e)&&u.removeChild(e,t)}function d(t,e,n,r,a,s,c){if(o(t.elm)&&o(s)&&(t=s[c]=Ot(t)),t.isRootInsert=!a,!h(t,e,n,r)){var f=t.data,l=t.children,p=t.tag;o(p)?(t.elm=t.ns?u.createElementNS(t.ns,p):u.createElement(p,t),x(t),b(t,l,e),o(f)&&w(t,e),g(n,t.elm,r)):i(t.isComment)?(t.elm=u.createComment(t.text),g(n,t.elm,r)):(t.elm=u.createTextNode(t.text),g(n,t.elm,r))}}function h(t,e,n,r){var a=t.data;if(o(a)){var s=o(t.componentInstance)&&a.keepAlive;if(o(a=a.hook)&&o(a=a.init)&&a(t,!1),o(t.componentInstance))return v(t,e),g(n,t.elm,r),i(s)&&m(t,e,n,r),!0}}function v(t,e){o(t.data.pendingInsert)&&(e.push.apply(e,t.data.pendingInsert),t.data.pendingInsert=null),t.elm=t.componentInstance.$el,_(t)?(w(t,e),x(t)):(Ao(t),e.push(t))}function m(t,e,n,r){var i,s=t;while(s.componentInstance)if(s=s.componentInstance._vnode,o(i=s.data)&&o(i=i.transition)){for(i=0;i<a.activate.length;++i)a.activate[i](Co,s);e.push(s);break}g(n,t.elm,r)}function g(t,e,n){o(t)&&(o(n)?u.parentNode(n)===t&&u.insertBefore(t,e,n):u.appendChild(t,e))}function b(t,e,n){if(Array.isArray(e)){0;for(var r=0;r<e.length;++r)d(e[r],n,t.elm,null,!0,e,r)}else s(t.text)&&u.appendChild(t.elm,u.createTextNode(String(t.text)))}function _(t){while(t.componentInstance)t=t.componentInstance._vnode;return o(t.tag)}function w(t,n){for(var r=0;r<a.create.length;++r)a.create[r](Co,t);e=t.data.hook,o(e)&&(o(e.create)&&e.create(Co,t),o(e.insert)&&n.push(t))}function x(t){var e;if(o(e=t.fnScopeId))u.setStyleScope(t.elm,e);else{var n=t;while(n)o(e=n.context)&&o(e=e.$options._scopeId)&&u.setStyleScope(t.elm,e),n=n.parent}o(e=Tn)&&e!==t.context&&e!==t.fnContext&&o(e=e.$options._scopeId)&&u.setStyleScope(t.elm,e)}function O(t,e,n,r,o,i){for(;r<=o;++r)d(n[r],i,t,e,!1,n,r)}function E(t){var e,n,r=t.data;if(o(r))for(o(e=r.hook)&&o(e=e.destroy)&&e(t),e=0;e<a.destroy.length;++e)a.destroy[e](t);if(o(e=t.children))for(n=0;n<t.children.length;++n)E(t.children[n])}function S(t,e,n,r){for(;n<=r;++n){var i=e[n];o(i)&&(o(i.tag)?(A(i),E(i)):p(i.elm))}}function A(t,e){if(o(e)||o(t.data)){var n,r=a.remove.length+1;for(o(e)?e.listeners+=r:e=l(t.elm,r),o(n=t.componentInstance)&&o(n=n._vnode)&&o(n.data)&&A(n,e),n=0;n<a.remove.length;++n)a.remove[n](t,e);o(n=t.data.hook)&&o(n=n.remove)?n(t,e):e()}else p(t.elm)}function C(t,e,n,i,a){var s,c,f,l,p=0,h=0,v=e.length-1,y=e[0],m=e[v],g=n.length-1,b=n[0],_=n[g],w=!a;while(p<=v&&h<=g)r(y)?y=e[++p]:r(m)?m=e[--v]:jo(y,b)?(j(y,b,i,n,h),y=e[++p],b=n[++h]):jo(m,_)?(j(m,_,i,n,g),m=e[--v],_=n[--g]):jo(y,_)?(j(y,_,i,n,g),w&&u.insertBefore(t,y.elm,u.nextSibling(m.elm)),y=e[++p],_=n[--g]):jo(m,b)?(j(m,b,i,n,h),w&&u.insertBefore(t,m.elm,y.elm),m=e[--v],b=n[++h]):(r(s)&&(s=$o(e,p,v)),c=o(b.key)?s[b.key]:k(b,e,p,v),r(c)?d(b,i,t,y.elm,!1,n,h):(f=e[c],jo(f,b)?(j(f,b,i,n,h),e[c]=void 0,w&&u.insertBefore(t,f.elm,y.elm)):d(b,i,t,y.elm,!1,n,h)),b=n[++h]);p>v?(l=r(n[g+1])?null:n[g+1].elm,O(t,l,n,h,g,i)):h>g&&S(t,e,p,v)}function k(t,e,n,r){for(var i=n;i<r;i++){var a=e[i];if(o(a)&&jo(t,a))return i}}function j(t,e,n,s,c,f){if(t!==e){o(e.elm)&&o(s)&&(e=s[c]=Ot(e));var l=e.elm=t.elm;if(i(t.isAsyncPlaceholder))o(e.asyncFactory.resolved)?M(t.elm,e,n):e.isAsyncPlaceholder=!0;else if(i(e.isStatic)&&i(t.isStatic)&&e.key===t.key&&(i(e.isCloned)||i(e.isOnce)))e.componentInstance=t.componentInstance;else{var p,d=e.data;o(d)&&o(p=d.hook)&&o(p=p.prepatch)&&p(t,e);var h=t.children,v=e.children;if(o(d)&&_(e)){for(p=0;p<a.update.length;++p)a.update[p](t,e);o(p=d.hook)&&o(p=p.update)&&p(t,e)}r(e.text)?o(h)&&o(v)?h!==v&&C(l,h,v,n,f):o(v)?(o(t.text)&&u.setTextContent(l,\"\"),O(l,null,v,0,v.length-1,n)):o(h)?S(l,h,0,h.length-1):o(t.text)&&u.setTextContent(l,\"\"):t.text!==e.text&&u.setTextContent(l,e.text),o(d)&&o(p=d.hook)&&o(p=p.postpatch)&&p(t,e)}}}function T(t,e,n){if(i(n)&&o(t.parent))t.parent.data.pendingInsert=e;else for(var r=0;r<e.length;++r)e[r].data.hook.insert(e[r])}var $=y(\"attrs,class,staticClass,staticStyle,key\");function M(t,e,n,r){var a,s=e.tag,c=e.data,u=e.children;if(r=r||c&&c.pre,e.elm=t,i(e.isComment)&&o(e.asyncFactory))return e.isAsyncPlaceholder=!0,!0;if(o(c)&&(o(a=c.hook)&&o(a=a.init)&&a(e,!0),o(a=e.componentInstance)))return v(e,n),!0;if(o(s)){if(o(u))if(t.hasChildNodes())if(o(a=c)&&o(a=a.domProps)&&o(a=a.innerHTML)){if(a!==t.innerHTML)return!1}else{for(var f=!0,l=t.firstChild,p=0;p<u.length;p++){if(!l||!M(l,u[p],n,r)){f=!1;break}l=l.nextSibling}if(!f||l)return!1}else b(e,u,n);if(o(c)){var d=!1;for(var h in c)if(!$(h)){d=!0,w(e,n);break}!d&&c[\"class\"]&&ye(c[\"class\"])}}else t.data!==e.text&&(t.data=e.text);return!0}return function(t,e,n,s){if(!r(e)){var c=!1,l=[];if(r(t))c=!0,d(e,l);else{var p=o(t.nodeType);if(!p&&jo(t,e))j(t,e,l,null,null,s);else{if(p){if(1===t.nodeType&&t.hasAttribute(D)&&(t.removeAttribute(D),n=!0),i(n)&&M(t,e,l))return T(e,l,!0),t;t=f(t)}var h=t.elm,v=u.parentNode(h);if(d(e,l,h._leaveCb?null:v,u.nextSibling(h)),o(e.parent)){var y=e.parent,m=_(e);while(y){for(var g=0;g<a.destroy.length;++g)a.destroy[g](y);if(y.elm=e.elm,m){for(var b=0;b<a.create.length;++b)a.create[b](Co,y);var w=y.data.hook.insert;if(w.merged)for(var x=1;x<w.fns.length;x++)w.fns[x]()}else Ao(y);y=y.parent}}o(v)?S(v,[t],0,0):o(t.tag)&&E(t)}}return T(e,l,c),e.elm}o(t)&&E(t)}}var Po={create:Lo,update:Lo,destroy:function(t){Lo(t,Co)}};function Lo(t,e){(t.data.directives||e.data.directives)&&Ro(t,e)}function Ro(t,e){var n,r,o,i=t===Co,a=e===Co,s=Fo(t.data.directives,t.context),c=Fo(e.data.directives,e.context),u=[],f=[];for(n in c)r=s[n],o=c[n],r?(o.oldValue=r.value,o.oldArg=r.arg,Do(o,\"update\",e,t),o.def&&o.def.componentUpdated&&f.push(o)):(Do(o,\"bind\",e,t),o.def&&o.def.inserted&&u.push(o));if(u.length){var l=function(){for(var n=0;n<u.length;n++)Do(u[n],\"inserted\",e,t)};i?we(e,\"insert\",l):l()}if(f.length&&we(e,\"postpatch\",function(){for(var n=0;n<f.length;n++)Do(f[n],\"componentUpdated\",e,t)}),!i)for(n in s)c[n]||Do(s[n],\"unbind\",t,t,a)}var No=Object.create(null);function Fo(t,e){var n,r,o=Object.create(null);if(!t)return o;for(n=0;n<t.length;n++)r=t[n],r.modifiers||(r.modifiers=No),o[Io(r)]=r,r.def=Xt(e.$options,\"directives\",r.name,!0);return o}function Io(t){return t.rawName||t.name+\".\"+Object.keys(t.modifiers||{}).join(\".\")}function Do(t,e,n,r,o){var i=t.def&&t.def[e];if(i)try{i(n.elm,t,n,r,o)}catch(Oa){ee(Oa,n.context,\"directive \"+t.name+\" \"+e+\" hook\")}}var qo=[So,Po];function Uo(t,e){var n=e.componentOptions;if((!o(n)||!1!==n.Ctor.options.inheritAttrs)&&(!r(t.data.attrs)||!r(e.data.attrs))){var i,a,s,c=e.elm,u=t.data.attrs||{},f=e.data.attrs||{};for(i in o(f.__ob__)&&(f=e.data.attrs=$({},f)),f)a=f[i],s=u[i],s!==a&&Bo(c,i,a);for(i in(tt||nt)&&f.value!==u.value&&Bo(c,\"value\",f.value),u)r(f[i])&&(Gr(i)?c.removeAttributeNS(zr,Wr(i)):Ur(i)||c.removeAttribute(i))}}function Bo(t,e,n){t.tagName.indexOf(\"-\")>-1?Vo(t,e,n):Hr(e)?Kr(n)?t.removeAttribute(e):(n=\"allowfullscreen\"===e&&\"EMBED\"===t.tagName?\"true\":e,t.setAttribute(e,n)):Ur(e)?t.setAttribute(e,Vr(e,n)):Gr(e)?Kr(n)?t.removeAttributeNS(zr,Wr(e)):t.setAttributeNS(zr,e,n):Vo(t,e,n)}function Vo(t,e,n){if(Kr(n))t.removeAttribute(e);else{if(tt&&!et&&\"TEXTAREA\"===t.tagName&&\"placeholder\"===e&&\"\"!==n&&!t.__ieph){var r=function(e){e.stopImmediatePropagation(),t.removeEventListener(\"input\",r)};t.addEventListener(\"input\",r),t.__ieph=!0}t.setAttribute(e,n)}}var Ho={create:Uo,update:Uo};function zo(t,e){var n=e.elm,i=e.data,a=t.data;if(!(r(i.staticClass)&&r(i.class)&&(r(a)||r(a.staticClass)&&r(a.class)))){var s=Xr(e),c=n._transitionClasses;o(c)&&(s=Zr(s,Qr(c))),s!==n._prevClass&&(n.setAttribute(\"class\",s),n._prevClass=s)}}var Go,Wo={create:zo,update:zo},Ko=\"__r\",Xo=\"__c\";function Jo(t){if(o(t[Ko])){var e=tt?\"change\":\"input\";t[e]=[].concat(t[Ko],t[e]||[]),delete t[Ko]}o(t[Xo])&&(t.change=[].concat(t[Xo],t.change||[]),delete t[Xo])}function Yo(t,e,n){var r=Go;return function o(){var i=e.apply(null,arguments);null!==i&&ti(t,o,n,r)}}var Zo=ae&&!(ot&&Number(ot[1])<=53);function Qo(t,e,n,r){if(Zo){var o=Wn,i=e;e=i._wrapper=function(t){if(t.target===t.currentTarget||t.timeStamp>=o||t.timeStamp<=0||t.target.ownerDocument!==document)return i.apply(this,arguments)}}Go.addEventListener(t,e,at?{capture:n,passive:r}:n)}function ti(t,e,n,r){(r||Go).removeEventListener(t,e._wrapper||e,n)}function ei(t,e){if(!r(t.data.on)||!r(e.data.on)){var n=e.data.on||{},o=t.data.on||{};Go=e.elm,Jo(n),_e(n,o,Qo,ti,Yo,e.context),Go=void 0}}var ni,ri={create:ei,update:ei};function oi(t,e){if(!r(t.data.domProps)||!r(e.data.domProps)){var n,i,a=e.elm,s=t.data.domProps||{},c=e.data.domProps||{};for(n in o(c.__ob__)&&(c=e.data.domProps=$({},c)),s)n in c||(a[n]=\"\");for(n in c){if(i=c[n],\"textContent\"===n||\"innerHTML\"===n){if(e.children&&(e.children.length=0),i===s[n])continue;1===a.childNodes.length&&a.removeChild(a.childNodes[0])}if(\"value\"===n&&\"PROGRESS\"!==a.tagName){a._value=i;var u=r(i)?\"\":String(i);ii(a,u)&&(a.value=u)}else if(\"innerHTML\"===n&&oo(a.tagName)&&r(a.innerHTML)){ni=ni||document.createElement(\"div\"),ni.innerHTML=\"<svg>\"+i+\"</svg>\";var f=ni.firstChild;while(a.firstChild)a.removeChild(a.firstChild);while(f.firstChild)a.appendChild(f.firstChild)}else if(i!==s[n])try{a[n]=i}catch(Oa){}}}}function ii(t,e){return!t.composing&&(\"OPTION\"===t.tagName||ai(t,e)||si(t,e))}function ai(t,e){var n=!0;try{n=document.activeElement!==t}catch(Oa){}return n&&t.value!==e}function si(t,e){var n=t.value,r=t._vModifiers;if(o(r)){if(r.number)return v(n)!==v(e);if(r.trim)return n.trim()!==e.trim()}return n!==e}var ci={create:oi,update:oi},ui=w(function(t){var e={},n=/;(?![^(]*\\))/g,r=/:(.+)/;return t.split(n).forEach(function(t){if(t){var n=t.split(r);n.length>1&&(e[n[0].trim()]=n[1].trim())}}),e});function fi(t){var e=li(t.style);return t.staticStyle?$(t.staticStyle,e):e}function li(t){return Array.isArray(t)?M(t):\"string\"===typeof t?ui(t):t}function pi(t,e){var n,r={};if(e){var o=t;while(o.componentInstance)o=o.componentInstance._vnode,o&&o.data&&(n=fi(o.data))&&$(r,n)}(n=fi(t.data))&&$(r,n);var i=t;while(i=i.parent)i.data&&(n=fi(i.data))&&$(r,n);return r}var di,hi=/^--/,vi=/\\s*!important$/,yi=function(t,e,n){if(hi.test(e))t.style.setProperty(e,n);else if(vi.test(n))t.style.setProperty(A(e),n.replace(vi,\"\"),\"important\");else{var r=gi(e);if(Array.isArray(n))for(var o=0,i=n.length;o<i;o++)t.style[r]=n[o];else t.style[r]=n}},mi=[\"Webkit\",\"Moz\",\"ms\"],gi=w(function(t){if(di=di||document.createElement(\"div\").style,t=O(t),\"filter\"!==t&&t in di)return t;for(var e=t.charAt(0).toUpperCase()+t.slice(1),n=0;n<mi.length;n++){var r=mi[n]+e;if(r in di)return r}});function bi(t,e){var n=e.data,i=t.data;if(!(r(n.staticStyle)&&r(n.style)&&r(i.staticStyle)&&r(i.style))){var a,s,c=e.elm,u=i.staticStyle,f=i.normalizedStyle||i.style||{},l=u||f,p=li(e.data.style)||{};e.data.normalizedStyle=o(p.__ob__)?$({},p):p;var d=pi(e,!0);for(s in l)r(d[s])&&yi(c,s,\"\");for(s in d)a=d[s],a!==l[s]&&yi(c,s,null==a?\"\":a)}}var _i={create:bi,update:bi},wi=/\\s+/;function xi(t,e){if(e&&(e=e.trim()))if(t.classList)e.indexOf(\" \")>-1?e.split(wi).forEach(function(e){return t.classList.add(e)}):t.classList.add(e);else{var n=\" \"+(t.getAttribute(\"class\")||\"\")+\" \";n.indexOf(\" \"+e+\" \")<0&&t.setAttribute(\"class\",(n+e).trim())}}function Oi(t,e){if(e&&(e=e.trim()))if(t.classList)e.indexOf(\" \")>-1?e.split(wi).forEach(function(e){return t.classList.remove(e)}):t.classList.remove(e),t.classList.length||t.removeAttribute(\"class\");else{var n=\" \"+(t.getAttribute(\"class\")||\"\")+\" \",r=\" \"+e+\" \";while(n.indexOf(r)>=0)n=n.replace(r,\" \");n=n.trim(),n?t.setAttribute(\"class\",n):t.removeAttribute(\"class\")}}function Ei(t){if(t){if(\"object\"===typeof t){var e={};return!1!==t.css&&$(e,Si(t.name||\"v\")),$(e,t),e}return\"string\"===typeof t?Si(t):void 0}}var Si=w(function(t){return{enterClass:t+\"-enter\",enterToClass:t+\"-enter-to\",enterActiveClass:t+\"-enter-active\",leaveClass:t+\"-leave\",leaveToClass:t+\"-leave-to\",leaveActiveClass:t+\"-leave-active\"}}),Ai=J&&!et,Ci=\"transition\",ki=\"animation\",ji=\"transition\",Ti=\"transitionend\",$i=\"animation\",Mi=\"animationend\";Ai&&(void 0===window.ontransitionend&&void 0!==window.onwebkittransitionend&&(ji=\"WebkitTransition\",Ti=\"webkitTransitionEnd\"),void 0===window.onanimationend&&void 0!==window.onwebkitanimationend&&($i=\"WebkitAnimation\",Mi=\"webkitAnimationEnd\"));var Pi=J?window.requestAnimationFrame?window.requestAnimationFrame.bind(window):setTimeout:function(t){return t()};function Li(t){Pi(function(){Pi(t)})}function Ri(t,e){var n=t._transitionClasses||(t._transitionClasses=[]);n.indexOf(e)<0&&(n.push(e),xi(t,e))}function Ni(t,e){t._transitionClasses&&g(t._transitionClasses,e),Oi(t,e)}function Fi(t,e,n){var r=Di(t,e),o=r.type,i=r.timeout,a=r.propCount;if(!o)return n();var s=o===Ci?Ti:Mi,c=0,u=function(){t.removeEventListener(s,f),n()},f=function(e){e.target===t&&++c>=a&&u()};setTimeout(function(){c<a&&u()},i+1),t.addEventListener(s,f)}var Ii=/\\b(transform|all)(,|$)/;function Di(t,e){var n,r=window.getComputedStyle(t),o=(r[ji+\"Delay\"]||\"\").split(\", \"),i=(r[ji+\"Duration\"]||\"\").split(\", \"),a=qi(o,i),s=(r[$i+\"Delay\"]||\"\").split(\", \"),c=(r[$i+\"Duration\"]||\"\").split(\", \"),u=qi(s,c),f=0,l=0;e===Ci?a>0&&(n=Ci,f=a,l=i.length):e===ki?u>0&&(n=ki,f=u,l=c.length):(f=Math.max(a,u),n=f>0?a>u?Ci:ki:null,l=n?n===Ci?i.length:c.length:0);var p=n===Ci&&Ii.test(r[ji+\"Property\"]);return{type:n,timeout:f,propCount:l,hasTransform:p}}function qi(t,e){while(t.length<e.length)t=t.concat(t);return Math.max.apply(null,e.map(function(e,n){return Ui(e)+Ui(t[n])}))}function Ui(t){return 1e3*Number(t.slice(0,-1).replace(\",\",\".\"))}function Bi(t,e){var n=t.elm;o(n._leaveCb)&&(n._leaveCb.cancelled=!0,n._leaveCb());var i=Ei(t.data.transition);if(!r(i)&&!o(n._enterCb)&&1===n.nodeType){var a=i.css,s=i.type,u=i.enterClass,f=i.enterToClass,l=i.enterActiveClass,p=i.appearClass,d=i.appearToClass,h=i.appearActiveClass,y=i.beforeEnter,m=i.enter,g=i.afterEnter,b=i.enterCancelled,_=i.beforeAppear,w=i.appear,x=i.afterAppear,O=i.appearCancelled,E=i.duration,S=Tn,A=Tn.$vnode;while(A&&A.parent)S=A.context,A=A.parent;var C=!S._isMounted||!t.isRootInsert;if(!C||w||\"\"===w){var k=C&&p?p:u,j=C&&h?h:l,T=C&&d?d:f,$=C&&_||y,M=C&&\"function\"===typeof w?w:m,P=C&&x||g,L=C&&O||b,R=v(c(E)?E.enter:E);0;var N=!1!==a&&!et,F=zi(M),D=n._enterCb=I(function(){N&&(Ni(n,T),Ni(n,j)),D.cancelled?(N&&Ni(n,k),L&&L(n)):P&&P(n),n._enterCb=null});t.data.show||we(t,\"insert\",function(){var e=n.parentNode,r=e&&e._pending&&e._pending[t.key];r&&r.tag===t.tag&&r.elm._leaveCb&&r.elm._leaveCb(),M&&M(n,D)}),$&&$(n),N&&(Ri(n,k),Ri(n,j),Li(function(){Ni(n,k),D.cancelled||(Ri(n,T),F||(Hi(R)?setTimeout(D,R):Fi(n,s,D)))})),t.data.show&&(e&&e(),M&&M(n,D)),N||F||D()}}}function Vi(t,e){var n=t.elm;o(n._enterCb)&&(n._enterCb.cancelled=!0,n._enterCb());var i=Ei(t.data.transition);if(r(i)||1!==n.nodeType)return e();if(!o(n._leaveCb)){var a=i.css,s=i.type,u=i.leaveClass,f=i.leaveToClass,l=i.leaveActiveClass,p=i.beforeLeave,d=i.leave,h=i.afterLeave,y=i.leaveCancelled,m=i.delayLeave,g=i.duration,b=!1!==a&&!et,_=zi(d),w=v(c(g)?g.leave:g);0;var x=n._leaveCb=I(function(){n.parentNode&&n.parentNode._pending&&(n.parentNode._pending[t.key]=null),b&&(Ni(n,f),Ni(n,l)),x.cancelled?(b&&Ni(n,u),y&&y(n)):(e(),h&&h(n)),n._leaveCb=null});m?m(O):O()}function O(){x.cancelled||(!t.data.show&&n.parentNode&&((n.parentNode._pending||(n.parentNode._pending={}))[t.key]=t),p&&p(n),b&&(Ri(n,u),Ri(n,l),Li(function(){Ni(n,u),x.cancelled||(Ri(n,f),_||(Hi(w)?setTimeout(x,w):Fi(n,s,x)))})),d&&d(n,x),b||_||x())}}function Hi(t){return\"number\"===typeof t&&!isNaN(t)}function zi(t){if(r(t))return!1;var e=t.fns;return o(e)?zi(Array.isArray(e)?e[0]:e):(t._length||t.length)>1}function Gi(t,e){!0!==e.data.show&&Bi(e)}var Wi=J?{create:Gi,activate:Gi,remove:function(t,e){!0!==t.data.show?Vi(t,e):e()}}:{},Ki=[Ho,Wo,ri,ci,_i,Wi],Xi=Ki.concat(qo),Ji=Mo({nodeOps:Eo,modules:Xi});et&&document.addEventListener(\"selectionchange\",function(){var t=document.activeElement;t&&t.vmodel&&oa(t,\"input\")});var Yi={inserted:function(t,e,n,r){\"select\"===n.tag?(r.elm&&!r.elm._vOptions?we(n,\"postpatch\",function(){Yi.componentUpdated(t,e,n)}):Zi(t,e,n.context),t._vOptions=[].map.call(t.options,ea)):(\"textarea\"===n.tag||uo(t.type))&&(t._vModifiers=e.modifiers,e.modifiers.lazy||(t.addEventListener(\"compositionstart\",na),t.addEventListener(\"compositionend\",ra),t.addEventListener(\"change\",ra),et&&(t.vmodel=!0)))},componentUpdated:function(t,e,n){if(\"select\"===n.tag){Zi(t,e,n.context);var r=t._vOptions,o=t._vOptions=[].map.call(t.options,ea);if(o.some(function(t,e){return!N(t,r[e])})){var i=t.multiple?e.value.some(function(t){return ta(t,o)}):e.value!==e.oldValue&&ta(e.value,o);i&&oa(t,\"change\")}}}};function Zi(t,e,n){Qi(t,e,n),(tt||nt)&&setTimeout(function(){Qi(t,e,n)},0)}function Qi(t,e,n){var r=e.value,o=t.multiple;if(!o||Array.isArray(r)){for(var i,a,s=0,c=t.options.length;s<c;s++)if(a=t.options[s],o)i=F(r,ea(a))>-1,a.selected!==i&&(a.selected=i);else if(N(ea(a),r))return void(t.selectedIndex!==s&&(t.selectedIndex=s));o||(t.selectedIndex=-1)}}function ta(t,e){return e.every(function(e){return!N(e,t)})}function ea(t){return\"_value\"in t?t._value:t.value}function na(t){t.target.composing=!0}function ra(t){t.target.composing&&(t.target.composing=!1,oa(t.target,\"input\"))}function oa(t,e){var n=document.createEvent(\"HTMLEvents\");n.initEvent(e,!0,!0),t.dispatchEvent(n)}function ia(t){return!t.componentInstance||t.data&&t.data.transition?t:ia(t.componentInstance._vnode)}var aa={bind:function(t,e,n){var r=e.value;n=ia(n);var o=n.data&&n.data.transition,i=t.__vOriginalDisplay=\"none\"===t.style.display?\"\":t.style.display;r&&o?(n.data.show=!0,Bi(n,function(){t.style.display=i})):t.style.display=r?i:\"none\"},update:function(t,e,n){var r=e.value,o=e.oldValue;if(!r!==!o){n=ia(n);var i=n.data&&n.data.transition;i?(n.data.show=!0,r?Bi(n,function(){t.style.display=t.__vOriginalDisplay}):Vi(n,function(){t.style.display=\"none\"})):t.style.display=r?t.__vOriginalDisplay:\"none\"}},unbind:function(t,e,n,r,o){o||(t.style.display=t.__vOriginalDisplay)}},sa={model:Yi,show:aa},ca={name:String,appear:Boolean,css:Boolean,mode:String,type:String,enterClass:String,leaveClass:String,enterToClass:String,leaveToClass:String,enterActiveClass:String,leaveActiveClass:String,appearClass:String,appearActiveClass:String,appearToClass:String,duration:[Number,String,Object]};function ua(t){var e=t&&t.componentOptions;return e&&e.Ctor.options.abstract?ua(On(e.children)):t}function fa(t){var e={},n=t.$options;for(var r in n.propsData)e[r]=t[r];var o=n._parentListeners;for(var i in o)e[O(i)]=o[i];return e}function la(t,e){if(/\\d-keep-alive$/.test(e.tag))return t(\"keep-alive\",{props:e.componentOptions.propsData})}function pa(t){while(t=t.parent)if(t.data.transition)return!0}function da(t,e){return e.key===t.key&&e.tag===t.tag}var ha=function(t){return t.tag||xn(t)},va=function(t){return\"show\"===t.name},ya={name:\"transition\",props:ca,abstract:!0,render:function(t){var e=this,n=this.$slots.default;if(n&&(n=n.filter(ha),n.length)){0;var r=this.mode;0;var o=n[0];if(pa(this.$vnode))return o;var i=ua(o);if(!i)return o;if(this._leaving)return la(t,o);var a=\"__transition-\"+this._uid+\"-\";i.key=null==i.key?i.isComment?a+\"comment\":a+i.tag:s(i.key)?0===String(i.key).indexOf(a)?i.key:a+i.key:i.key;var c=(i.data||(i.data={})).transition=fa(this),u=this._vnode,f=ua(u);if(i.data.directives&&i.data.directives.some(va)&&(i.data.show=!0),f&&f.data&&!da(i,f)&&!xn(f)&&(!f.componentInstance||!f.componentInstance._vnode.isComment)){var l=f.data.transition=$({},c);if(\"out-in\"===r)return this._leaving=!0,we(l,\"afterLeave\",function(){e._leaving=!1,e.$forceUpdate()}),la(t,o);if(\"in-out\"===r){if(xn(i))return u;var p,d=function(){p()};we(c,\"afterEnter\",d),we(c,\"enterCancelled\",d),we(l,\"delayLeave\",function(t){p=t})}}return o}}},ma=$({tag:String,moveClass:String},ca);delete ma.mode;var ga={props:ma,beforeMount:function(){var t=this,e=this._update;this._update=function(n,r){var o=$n(t);t.__patch__(t._vnode,t.kept,!1,!0),t._vnode=t.kept,o(),e.call(t,n,r)}},render:function(t){for(var e=this.tag||this.$vnode.data.tag||\"span\",n=Object.create(null),r=this.prevChildren=this.children,o=this.$slots.default||[],i=this.children=[],a=fa(this),s=0;s<o.length;s++){var c=o[s];if(c.tag)if(null!=c.key&&0!==String(c.key).indexOf(\"__vlist\"))i.push(c),n[c.key]=c,(c.data||(c.data={})).transition=a;else;}if(r){for(var u=[],f=[],l=0;l<r.length;l++){var p=r[l];p.data.transition=a,p.data.pos=p.elm.getBoundingClientRect(),n[p.key]?u.push(p):f.push(p)}this.kept=t(e,null,u),this.removed=f}return t(e,null,i)},updated:function(){var t=this.prevChildren,e=this.moveClass||(this.name||\"v\")+\"-move\";t.length&&this.hasMove(t[0].elm,e)&&(t.forEach(ba),t.forEach(_a),t.forEach(wa),this._reflow=document.body.offsetHeight,t.forEach(function(t){if(t.data.moved){var n=t.elm,r=n.style;Ri(n,e),r.transform=r.WebkitTransform=r.transitionDuration=\"\",n.addEventListener(Ti,n._moveCb=function t(r){r&&r.target!==n||r&&!/transform$/.test(r.propertyName)||(n.removeEventListener(Ti,t),n._moveCb=null,Ni(n,e))})}}))},methods:{hasMove:function(t,e){if(!Ai)return!1;if(this._hasMove)return this._hasMove;var n=t.cloneNode();t._transitionClasses&&t._transitionClasses.forEach(function(t){Oi(n,t)}),xi(n,e),n.style.display=\"none\",this.$el.appendChild(n);var r=Di(n);return this.$el.removeChild(n),this._hasMove=r.hasTransform}}};function ba(t){t.elm._moveCb&&t.elm._moveCb(),t.elm._enterCb&&t.elm._enterCb()}function _a(t){t.data.newPos=t.elm.getBoundingClientRect()}function wa(t){var e=t.data.pos,n=t.data.newPos,r=e.left-n.left,o=e.top-n.top;if(r||o){t.data.moved=!0;var i=t.elm.style;i.transform=i.WebkitTransform=\"translate(\"+r+\"px,\"+o+\"px)\",i.transitionDuration=\"0s\"}}var xa={Transition:ya,TransitionGroup:ga};Or.config.mustUseProp=qr,Or.config.isReservedTag=io,Or.config.isReservedAttr=Ir,Or.config.getTagNamespace=ao,Or.config.isUnknownElement=co,$(Or.options.directives,sa),$(Or.options.components,xa),Or.prototype.__patch__=J?Ji:P,Or.prototype.$mount=function(t,e){return t=t&&J?fo(t):void 0,Ln(this,t,e)},J&&setTimeout(function(){B.devtools&&ut&&ut.emit(\"init\",Or)},0),e[\"default\"]=Or}.call(this,n(\"c8ba\"))},\"2b4c\":function(t,e,n){var r=n(\"5537\")(\"wks\"),o=n(\"ca5a\"),i=n(\"7726\").Symbol,a=\"function\"==typeof i,s=t.exports=function(t){return r[t]||(r[t]=a&&i[t]||(a?i:o)(\"Symbol.\"+t))};s.store=r},\"2d00\":function(t,e){t.exports=!1},\"2d83\":function(t,e,n){\"use strict\";var r=n(\"387f\");t.exports=function(t,e,n,o,i){var a=new Error(t);return r(a,e,n,o,i)}},\"2d95\":function(t,e){var n={}.toString;t.exports=function(t){return n.call(t).slice(8,-1)}},\"2e67\":function(t,e,n){\"use strict\";t.exports=function(t){return!(!t||!t.__CANCEL__)}},\"2f62\":function(t,e,n){\"use strict\";\n/**\n * vuex v3.1.0\n * (c) 2019 Evan You\n * @license MIT\n */\nfunction r(t){var e=Number(t.version.split(\".\")[0]);if(e>=2)t.mixin({beforeCreate:r});else{var n=t.prototype._init;t.prototype._init=function(t){void 0===t&&(t={}),t.init=t.init?[r].concat(t.init):r,n.call(this,t)}}function r(){var t=this.$options;t.store?this.$store=\"function\"===typeof t.store?t.store():t.store:t.parent&&t.parent.$store&&(this.$store=t.parent.$store)}}n.d(e,\"b\",function(){return $});var o=\"undefined\"!==typeof window&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__;function i(t){o&&(t._devtoolHook=o,o.emit(\"vuex:init\",t),o.on(\"vuex:travel-to-state\",function(e){t.replaceState(e)}),t.subscribe(function(t,e){o.emit(\"vuex:mutation\",t,e)}))}function a(t,e){Object.keys(t).forEach(function(n){return e(t[n],n)})}function s(t){return null!==t&&\"object\"===typeof t}function c(t){return t&&\"function\"===typeof t.then}var u=function(t,e){this.runtime=e,this._children=Object.create(null),this._rawModule=t;var n=t.state;this.state=(\"function\"===typeof n?n():n)||{}},f={namespaced:{configurable:!0}};f.namespaced.get=function(){return!!this._rawModule.namespaced},u.prototype.addChild=function(t,e){this._children[t]=e},u.prototype.removeChild=function(t){delete this._children[t]},u.prototype.getChild=function(t){return this._children[t]},u.prototype.update=function(t){this._rawModule.namespaced=t.namespaced,t.actions&&(this._rawModule.actions=t.actions),t.mutations&&(this._rawModule.mutations=t.mutations),t.getters&&(this._rawModule.getters=t.getters)},u.prototype.forEachChild=function(t){a(this._children,t)},u.prototype.forEachGetter=function(t){this._rawModule.getters&&a(this._rawModule.getters,t)},u.prototype.forEachAction=function(t){this._rawModule.actions&&a(this._rawModule.actions,t)},u.prototype.forEachMutation=function(t){this._rawModule.mutations&&a(this._rawModule.mutations,t)},Object.defineProperties(u.prototype,f);var l=function(t){this.register([],t,!1)};function p(t,e,n){if(e.update(n),n.modules)for(var r in n.modules){if(!e.getChild(r))return void 0;p(t.concat(r),e.getChild(r),n.modules[r])}}l.prototype.get=function(t){return t.reduce(function(t,e){return t.getChild(e)},this.root)},l.prototype.getNamespace=function(t){var e=this.root;return t.reduce(function(t,n){return e=e.getChild(n),t+(e.namespaced?n+\"/\":\"\")},\"\")},l.prototype.update=function(t){p([],this.root,t)},l.prototype.register=function(t,e,n){var r=this;void 0===n&&(n=!0);var o=new u(e,n);if(0===t.length)this.root=o;else{var i=this.get(t.slice(0,-1));i.addChild(t[t.length-1],o)}e.modules&&a(e.modules,function(e,o){r.register(t.concat(o),e,n)})},l.prototype.unregister=function(t){var e=this.get(t.slice(0,-1)),n=t[t.length-1];e.getChild(n).runtime&&e.removeChild(n)};var d;var h=function(t){var e=this;void 0===t&&(t={}),!d&&\"undefined\"!==typeof window&&window.Vue&&k(window.Vue);var n=t.plugins;void 0===n&&(n=[]);var r=t.strict;void 0===r&&(r=!1),this._committing=!1,this._actions=Object.create(null),this._actionSubscribers=[],this._mutations=Object.create(null),this._wrappedGetters=Object.create(null),this._modules=new l(t),this._modulesNamespaceMap=Object.create(null),this._subscribers=[],this._watcherVM=new d;var o=this,a=this,s=a.dispatch,c=a.commit;this.dispatch=function(t,e){return s.call(o,t,e)},this.commit=function(t,e,n){return c.call(o,t,e,n)},this.strict=r;var u=this._modules.root.state;b(this,u,[],this._modules.root),g(this,u),n.forEach(function(t){return t(e)});var f=void 0!==t.devtools?t.devtools:d.config.devtools;f&&i(this)},v={state:{configurable:!0}};function y(t,e){return e.indexOf(t)<0&&e.push(t),function(){var n=e.indexOf(t);n>-1&&e.splice(n,1)}}function m(t,e){t._actions=Object.create(null),t._mutations=Object.create(null),t._wrappedGetters=Object.create(null),t._modulesNamespaceMap=Object.create(null);var n=t.state;b(t,n,[],t._modules.root,!0),g(t,n,e)}function g(t,e,n){var r=t._vm;t.getters={};var o=t._wrappedGetters,i={};a(o,function(e,n){i[n]=function(){return e(t)},Object.defineProperty(t.getters,n,{get:function(){return t._vm[n]},enumerable:!0})});var s=d.config.silent;d.config.silent=!0,t._vm=new d({data:{$$state:e},computed:i}),d.config.silent=s,t.strict&&S(t),r&&(n&&t._withCommit(function(){r._data.$$state=null}),d.nextTick(function(){return r.$destroy()}))}function b(t,e,n,r,o){var i=!n.length,a=t._modules.getNamespace(n);if(r.namespaced&&(t._modulesNamespaceMap[a]=r),!i&&!o){var s=A(e,n.slice(0,-1)),c=n[n.length-1];t._withCommit(function(){d.set(s,c,r.state)})}var u=r.context=_(t,a,n);r.forEachMutation(function(e,n){var r=a+n;x(t,r,e,u)}),r.forEachAction(function(e,n){var r=e.root?n:a+n,o=e.handler||e;O(t,r,o,u)}),r.forEachGetter(function(e,n){var r=a+n;E(t,r,e,u)}),r.forEachChild(function(r,i){b(t,e,n.concat(i),r,o)})}function _(t,e,n){var r=\"\"===e,o={dispatch:r?t.dispatch:function(n,r,o){var i=C(n,r,o),a=i.payload,s=i.options,c=i.type;return s&&s.root||(c=e+c),t.dispatch(c,a)},commit:r?t.commit:function(n,r,o){var i=C(n,r,o),a=i.payload,s=i.options,c=i.type;s&&s.root||(c=e+c),t.commit(c,a,s)}};return Object.defineProperties(o,{getters:{get:r?function(){return t.getters}:function(){return w(t,e)}},state:{get:function(){return A(t.state,n)}}}),o}function w(t,e){var n={},r=e.length;return Object.keys(t.getters).forEach(function(o){if(o.slice(0,r)===e){var i=o.slice(r);Object.defineProperty(n,i,{get:function(){return t.getters[o]},enumerable:!0})}}),n}function x(t,e,n,r){var o=t._mutations[e]||(t._mutations[e]=[]);o.push(function(e){n.call(t,r.state,e)})}function O(t,e,n,r){var o=t._actions[e]||(t._actions[e]=[]);o.push(function(e,o){var i=n.call(t,{dispatch:r.dispatch,commit:r.commit,getters:r.getters,state:r.state,rootGetters:t.getters,rootState:t.state},e,o);return c(i)||(i=Promise.resolve(i)),t._devtoolHook?i.catch(function(e){throw t._devtoolHook.emit(\"vuex:error\",e),e}):i})}function E(t,e,n,r){t._wrappedGetters[e]||(t._wrappedGetters[e]=function(t){return n(r.state,r.getters,t.state,t.getters)})}function S(t){t._vm.$watch(function(){return this._data.$$state},function(){0},{deep:!0,sync:!0})}function A(t,e){return e.length?e.reduce(function(t,e){return t[e]},t):t}function C(t,e,n){return s(t)&&t.type&&(n=e,e=t,t=t.type),{type:t,payload:e,options:n}}function k(t){d&&t===d||(d=t,r(d))}v.state.get=function(){return this._vm._data.$$state},v.state.set=function(t){0},h.prototype.commit=function(t,e,n){var r=this,o=C(t,e,n),i=o.type,a=o.payload,s=(o.options,{type:i,payload:a}),c=this._mutations[i];c&&(this._withCommit(function(){c.forEach(function(t){t(a)})}),this._subscribers.forEach(function(t){return t(s,r.state)}))},h.prototype.dispatch=function(t,e){var n=this,r=C(t,e),o=r.type,i=r.payload,a={type:o,payload:i},s=this._actions[o];if(s){try{this._actionSubscribers.filter(function(t){return t.before}).forEach(function(t){return t.before(a,n.state)})}catch(u){0}var c=s.length>1?Promise.all(s.map(function(t){return t(i)})):s[0](i);return c.then(function(t){try{n._actionSubscribers.filter(function(t){return t.after}).forEach(function(t){return t.after(a,n.state)})}catch(u){0}return t})}},h.prototype.subscribe=function(t){return y(t,this._subscribers)},h.prototype.subscribeAction=function(t){var e=\"function\"===typeof t?{before:t}:t;return y(e,this._actionSubscribers)},h.prototype.watch=function(t,e,n){var r=this;return this._watcherVM.$watch(function(){return t(r.state,r.getters)},e,n)},h.prototype.replaceState=function(t){var e=this;this._withCommit(function(){e._vm._data.$$state=t})},h.prototype.registerModule=function(t,e,n){void 0===n&&(n={}),\"string\"===typeof t&&(t=[t]),this._modules.register(t,e),b(this,this.state,t,this._modules.get(t),n.preserveState),g(this,this.state)},h.prototype.unregisterModule=function(t){var e=this;\"string\"===typeof t&&(t=[t]),this._modules.unregister(t),this._withCommit(function(){var n=A(e.state,t.slice(0,-1));d.delete(n,t[t.length-1])}),m(this)},h.prototype.hotUpdate=function(t){this._modules.update(t),m(this,!0)},h.prototype._withCommit=function(t){var e=this._committing;this._committing=!0,t(),this._committing=e},Object.defineProperties(h.prototype,v);var j=R(function(t,e){var n={};return L(e).forEach(function(e){var r=e.key,o=e.val;n[r]=function(){var e=this.$store.state,n=this.$store.getters;if(t){var r=N(this.$store,\"mapState\",t);if(!r)return;e=r.context.state,n=r.context.getters}return\"function\"===typeof o?o.call(this,e,n):e[o]},n[r].vuex=!0}),n}),T=R(function(t,e){var n={};return L(e).forEach(function(e){var r=e.key,o=e.val;n[r]=function(){var e=[],n=arguments.length;while(n--)e[n]=arguments[n];var r=this.$store.commit;if(t){var i=N(this.$store,\"mapMutations\",t);if(!i)return;r=i.context.commit}return\"function\"===typeof o?o.apply(this,[r].concat(e)):r.apply(this.$store,[o].concat(e))}}),n}),$=R(function(t,e){var n={};return L(e).forEach(function(e){var r=e.key,o=e.val;o=t+o,n[r]=function(){if(!t||N(this.$store,\"mapGetters\",t))return this.$store.getters[o]},n[r].vuex=!0}),n}),M=R(function(t,e){var n={};return L(e).forEach(function(e){var r=e.key,o=e.val;n[r]=function(){var e=[],n=arguments.length;while(n--)e[n]=arguments[n];var r=this.$store.dispatch;if(t){var i=N(this.$store,\"mapActions\",t);if(!i)return;r=i.context.dispatch}return\"function\"===typeof o?o.apply(this,[r].concat(e)):r.apply(this.$store,[o].concat(e))}}),n}),P=function(t){return{mapState:j.bind(null,t),mapGetters:$.bind(null,t),mapMutations:T.bind(null,t),mapActions:M.bind(null,t)}};function L(t){return Array.isArray(t)?t.map(function(t){return{key:t,val:t}}):Object.keys(t).map(function(e){return{key:e,val:t[e]}})}function R(t){return function(e,n){return\"string\"!==typeof e?(n=e,e=\"\"):\"/\"!==e.charAt(e.length-1)&&(e+=\"/\"),t(e,n)}}function N(t,e,n){var r=t._modulesNamespaceMap[n];return r}var F={Store:h,install:k,version:\"3.1.0\",mapState:j,mapMutations:T,mapGetters:$,mapActions:M,createNamespacedHelpers:P};e[\"a\"]=F},3024:function(t,e){t.exports=function(t,e,n){var r=void 0===n;switch(e.length){case 0:return r?t():t.call(n);case 1:return r?t(e[0]):t.call(n,e[0]);case 2:return r?t(e[0],e[1]):t.call(n,e[0],e[1]);case 3:return r?t(e[0],e[1],e[2]):t.call(n,e[0],e[1],e[2]);case 4:return r?t(e[0],e[1],e[2],e[3]):t.call(n,e[0],e[1],e[2],e[3])}return t.apply(n,e)}},\"30b5\":function(t,e,n){\"use strict\";var r=n(\"c532\");function o(t){return encodeURIComponent(t).replace(/%40/gi,\"@\").replace(/%3A/gi,\":\").replace(/%24/g,\"$\").replace(/%2C/gi,\",\").replace(/%20/g,\"+\").replace(/%5B/gi,\"[\").replace(/%5D/gi,\"]\")}t.exports=function(t,e,n){if(!e)return t;var i;if(n)i=n(e);else if(r.isURLSearchParams(e))i=e.toString();else{var a=[];r.forEach(e,function(t,e){null!==t&&\"undefined\"!==typeof t&&(r.isArray(t)?e+=\"[]\":t=[t],r.forEach(t,function(t){r.isDate(t)?t=t.toISOString():r.isObject(t)&&(t=JSON.stringify(t)),a.push(o(e)+\"=\"+o(t))}))}),i=a.join(\"&\")}return i&&(t+=(-1===t.indexOf(\"?\")?\"?\":\"&\")+i),t}},\"30f1\":function(t,e,n){\"use strict\";var r=n(\"b8e3\"),o=n(\"63b6\"),i=n(\"9138\"),a=n(\"35e8\"),s=n(\"481b\"),c=n(\"8f60\"),u=n(\"45f2\"),f=n(\"53e2\"),l=n(\"5168\")(\"iterator\"),p=!([].keys&&\"next\"in[].keys()),d=\"@@iterator\",h=\"keys\",v=\"values\",y=function(){return this};t.exports=function(t,e,n,m,g,b,_){c(n,e,m);var w,x,O,E=function(t){if(!p&&t in k)return k[t];switch(t){case h:return function(){return new n(this,t)};case v:return function(){return new n(this,t)}}return function(){return new n(this,t)}},S=e+\" Iterator\",A=g==v,C=!1,k=t.prototype,j=k[l]||k[d]||g&&k[g],T=j||E(g),$=g?A?E(\"entries\"):T:void 0,M=\"Array\"==e&&k.entries||j;if(M&&(O=f(M.call(new t)),O!==Object.prototype&&O.next&&(u(O,S,!0),r||\"function\"==typeof O[l]||a(O,l,y))),A&&j&&j.name!==v&&(C=!0,T=function(){return j.call(this)}),r&&!_||!p&&!C&&k[l]||a(k,l,T),s[e]=T,s[S]=y,g)if(w={values:A?T:E(v),keys:b?T:E(h),entries:$},_)for(x in w)x in k||i(k,x,w[x]);else o(o.P+o.F*(p||C),e,w);return w}},\"31f4\":function(t,e){t.exports=function(t,e,n){var r=void 0===n;switch(e.length){case 0:return r?t():t.call(n);case 1:return r?t(e[0]):t.call(n,e[0]);case 2:return r?t(e[0],e[1]):t.call(n,e[0],e[1]);case 3:return r?t(e[0],e[1],e[2]):t.call(n,e[0],e[1],e[2]);case 4:return r?t(e[0],e[1],e[2],e[3]):t.call(n,e[0],e[1],e[2],e[3])}return t.apply(n,e)}},\"323e\":function(t,e,n){var r,o;\n/* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress\n * @license MIT */(function(i,a){r=a,o=\"function\"===typeof r?r.call(e,n,e,t):r,void 0===o||(t.exports=o)})(0,function(){var t={version:\"0.2.0\"},e=t.settings={minimum:.08,easing:\"ease\",positionUsing:\"\",speed:200,trickle:!0,trickleRate:.02,trickleSpeed:800,showSpinner:!0,barSelector:'[role=\"bar\"]',spinnerSelector:'[role=\"spinner\"]',parent:\"body\",template:'<div class=\"bar\" role=\"bar\"><div class=\"peg\"></div></div><div class=\"spinner\" role=\"spinner\"><div class=\"spinner-icon\"></div></div>'};function n(t,e,n){return t<e?e:t>n?n:t}function r(t){return 100*(-1+t)}function o(t,n,o){var i;return i=\"translate3d\"===e.positionUsing?{transform:\"translate3d(\"+r(t)+\"%,0,0)\"}:\"translate\"===e.positionUsing?{transform:\"translate(\"+r(t)+\"%,0)\"}:{\"margin-left\":r(t)+\"%\"},i.transition=\"all \"+n+\"ms \"+o,i}t.configure=function(t){var n,r;for(n in t)r=t[n],void 0!==r&&t.hasOwnProperty(n)&&(e[n]=r);return this},t.status=null,t.set=function(r){var s=t.isStarted();r=n(r,e.minimum,1),t.status=1===r?null:r;var c=t.render(!s),u=c.querySelector(e.barSelector),f=e.speed,l=e.easing;return c.offsetWidth,i(function(n){\"\"===e.positionUsing&&(e.positionUsing=t.getPositioningCSS()),a(u,o(r,f,l)),1===r?(a(c,{transition:\"none\",opacity:1}),c.offsetWidth,setTimeout(function(){a(c,{transition:\"all \"+f+\"ms linear\",opacity:0}),setTimeout(function(){t.remove(),n()},f)},f)):setTimeout(n,f)}),this},t.isStarted=function(){return\"number\"===typeof t.status},t.start=function(){t.status||t.set(0);var n=function(){setTimeout(function(){t.status&&(t.trickle(),n())},e.trickleSpeed)};return e.trickle&&n(),this},t.done=function(e){return e||t.status?t.inc(.3+.5*Math.random()).set(1):this},t.inc=function(e){var r=t.status;return r?(\"number\"!==typeof e&&(e=(1-r)*n(Math.random()*r,.1,.95)),r=n(r+e,0,.994),t.set(r)):t.start()},t.trickle=function(){return t.inc(Math.random()*e.trickleRate)},function(){var e=0,n=0;t.promise=function(r){return r&&\"resolved\"!==r.state()?(0===n&&t.start(),e++,n++,r.always(function(){n--,0===n?(e=0,t.done()):t.set((e-n)/e)}),this):this}}(),t.render=function(n){if(t.isRendered())return document.getElementById(\"nprogress\");c(document.documentElement,\"nprogress-busy\");var o=document.createElement(\"div\");o.id=\"nprogress\",o.innerHTML=e.template;var i,s=o.querySelector(e.barSelector),u=n?\"-100\":r(t.status||0),f=document.querySelector(e.parent);return a(s,{transition:\"all 0 linear\",transform:\"translate3d(\"+u+\"%,0,0)\"}),e.showSpinner||(i=o.querySelector(e.spinnerSelector),i&&l(i)),f!=document.body&&c(f,\"nprogress-custom-parent\"),f.appendChild(o),o},t.remove=function(){u(document.documentElement,\"nprogress-busy\"),u(document.querySelector(e.parent),\"nprogress-custom-parent\");var t=document.getElementById(\"nprogress\");t&&l(t)},t.isRendered=function(){return!!document.getElementById(\"nprogress\")},t.getPositioningCSS=function(){var t=document.body.style,e=\"WebkitTransform\"in t?\"Webkit\":\"MozTransform\"in t?\"Moz\":\"msTransform\"in t?\"ms\":\"OTransform\"in t?\"O\":\"\";return e+\"Perspective\"in t?\"translate3d\":e+\"Transform\"in t?\"translate\":\"margin\"};var i=function(){var t=[];function e(){var n=t.shift();n&&n(e)}return function(n){t.push(n),1==t.length&&e()}}(),a=function(){var t=[\"Webkit\",\"O\",\"Moz\",\"ms\"],e={};function n(t){return t.replace(/^-ms-/,\"ms-\").replace(/-([\\da-z])/gi,function(t,e){return e.toUpperCase()})}function r(e){var n=document.body.style;if(e in n)return e;var r,o=t.length,i=e.charAt(0).toUpperCase()+e.slice(1);while(o--)if(r=t[o]+i,r in n)return r;return e}function o(t){return t=n(t),e[t]||(e[t]=r(t))}function i(t,e,n){e=o(e),t.style[e]=n}return function(t,e){var n,r,o=arguments;if(2==o.length)for(n in e)r=e[n],void 0!==r&&e.hasOwnProperty(n)&&i(t,n,r);else i(t,o[1],o[2])}}();function s(t,e){var n=\"string\"==typeof t?t:f(t);return n.indexOf(\" \"+e+\" \")>=0}function c(t,e){var n=f(t),r=n+e;s(n,e)||(t.className=r.substring(1))}function u(t,e){var n,r=f(t);s(t,e)&&(n=r.replace(\" \"+e+\" \",\" \"),t.className=n.substring(1,n.length-1))}function f(t){return(\" \"+(t.className||\"\")+\" \").replace(/\\s+/gi,\" \")}function l(t){t&&t.parentNode&&t.parentNode.removeChild(t)}return t})},\"32a6\":function(t,e,n){var r=n(\"241e\"),o=n(\"c3a1\");n(\"ce7e\")(\"keys\",function(){return function(t){return o(r(t))}})},\"32e9\":function(t,e,n){var r=n(\"86cc\"),o=n(\"4630\");t.exports=n(\"9e1e\")?function(t,e,n){return r.f(t,e,o(1,n))}:function(t,e,n){return t[e]=n,t}},\"32fc\":function(t,e,n){var r=n(\"e53d\").document;t.exports=r&&r.documentElement},\"335c\":function(t,e,n){var r=n(\"6b4c\");t.exports=Object(\"z\").propertyIsEnumerable(0)?Object:function(t){return\"String\"==r(t)?t.split(\"\"):Object(t)}},\"33a4\":function(t,e,n){var r=n(\"84f2\"),o=n(\"2b4c\")(\"iterator\"),i=Array.prototype;t.exports=function(t){return void 0!==t&&(r.Array===t||i[o]===t)}},\"355d\":function(t,e){e.f={}.propertyIsEnumerable},\"35e8\":function(t,e,n){var r=n(\"d9f6\"),o=n(\"aebd\");t.exports=n(\"8e60\")?function(t,e,n){return r.f(t,e,o(1,n))}:function(t,e,n){return t[e]=n,t}},\"36c3\":function(t,e,n){var r=n(\"335c\"),o=n(\"25eb\");t.exports=function(t){return r(o(t))}},3702:function(t,e,n){var r=n(\"481b\"),o=n(\"5168\")(\"iterator\"),i=Array.prototype;t.exports=function(t){return void 0!==t&&(r.Array===t||i[o]===t)}},\"387f\":function(t,e,n){\"use strict\";t.exports=function(t,e,n,r,o){return t.config=e,n&&(t.code=n),t.request=r,t.response=o,t}},\"38fd\":function(t,e,n){var r=n(\"69a8\"),o=n(\"4bf8\"),i=n(\"613b\")(\"IE_PROTO\"),a=Object.prototype;t.exports=Object.getPrototypeOf||function(t){return t=o(t),r(t,i)?t[i]:\"function\"==typeof t.constructor&&t instanceof t.constructor?t.constructor.prototype:t instanceof Object?a:null}},3934:function(t,e,n){\"use strict\";var r=n(\"c532\");t.exports=r.isStandardBrowserEnv()?function(){var t,e=/(msie|trident)/i.test(navigator.userAgent),n=document.createElement(\"a\");function o(t){var r=t;return e&&(n.setAttribute(\"href\",r),r=n.href),n.setAttribute(\"href\",r),{href:n.href,protocol:n.protocol?n.protocol.replace(/:$/,\"\"):\"\",host:n.host,search:n.search?n.search.replace(/^\\?/,\"\"):\"\",hash:n.hash?n.hash.replace(/^#/,\"\"):\"\",hostname:n.hostname,port:n.port,pathname:\"/\"===n.pathname.charAt(0)?n.pathname:\"/\"+n.pathname}}return t=o(window.location.href),function(e){var n=r.isString(e)?o(e):e;return n.protocol===t.protocol&&n.host===t.host}}():function(){return function(){return!0}}()},\"3a38\":function(t,e){var n=Math.ceil,r=Math.floor;t.exports=function(t){return isNaN(t=+t)?0:(t>0?r:n)(t)}},\"3b8d\":function(t,e,n){\"use strict\";n.d(e,\"a\",function(){return a});var r=n(\"795b\"),o=n.n(r);function i(t,e,n,r,i,a,s){try{var c=t[a](s),u=c.value}catch(f){return void n(f)}c.done?e(u):o.a.resolve(u).then(r,i)}function a(t){return function(){var e=this,n=arguments;return new o.a(function(r,o){var a=t.apply(e,n);function s(t){i(a,r,o,s,c,\"next\",t)}function c(t){i(a,r,o,s,c,\"throw\",t)}s(void 0)})}}},\"3c11\":function(t,e,n){\"use strict\";var r=n(\"63b6\"),o=n(\"584a\"),i=n(\"e53d\"),a=n(\"f201\"),s=n(\"cd78\");r(r.P+r.R,\"Promise\",{finally:function(t){var e=a(this,o.Promise||i.Promise),n=\"function\"==typeof t;return this.then(n?function(n){return s(e,t()).then(function(){return n})}:t,n?function(n){return s(e,t()).then(function(){throw n})}:t)}})},\"3c4e\":function(t,e,n){\"use strict\";var r=function(t){return o(t)&&!i(t)};function o(t){return!!t&&\"object\"===typeof t}function i(t){var e=Object.prototype.toString.call(t);return\"[object RegExp]\"===e||\"[object Date]\"===e||c(t)}var a=\"function\"===typeof Symbol&&Symbol.for,s=a?Symbol.for(\"react.element\"):60103;function c(t){return t.$$typeof===s}function u(t){return Array.isArray(t)?[]:{}}function f(t,e){var n=e&&!0===e.clone;return n&&r(t)?d(u(t),t,e):t}function l(t,e,n){var o=t.slice();return e.forEach(function(e,i){\"undefined\"===typeof o[i]?o[i]=f(e,n):r(e)?o[i]=d(t[i],e,n):-1===t.indexOf(e)&&o.push(f(e,n))}),o}function p(t,e,n){var o={};return r(t)&&Object.keys(t).forEach(function(e){o[e]=f(t[e],n)}),Object.keys(e).forEach(function(i){r(e[i])&&t[i]?o[i]=d(t[i],e[i],n):o[i]=f(e[i],n)}),o}function d(t,e,n){var r=Array.isArray(e),o=Array.isArray(t),i=n||{arrayMerge:l},a=r===o;if(a){if(r){var s=i.arrayMerge||l;return s(t,e,n)}return p(t,e,n)}return f(e,n)}d.all=function(t,e){if(!Array.isArray(t)||t.length<2)throw new Error(\"first argument should be an array with at least two elements\");return t.reduce(function(t,n){return d(t,n,e)})};var h=d;t.exports=h},\"3f6b\":function(t,e,n){t.exports={default:n(\"51b6\"),__esModule:!0}},\"40c3\":function(t,e,n){var r=n(\"6b4c\"),o=n(\"5168\")(\"toStringTag\"),i=\"Arguments\"==r(function(){return arguments}()),a=function(t,e){try{return t[e]}catch(n){}};t.exports=function(t){var e,n,s;return void 0===t?\"Undefined\":null===t?\"Null\":\"string\"==typeof(n=a(e=Object(t),o))?n:i?r(e):\"Object\"==(s=r(e))&&\"function\"==typeof e.callee?\"Arguments\":s}},4178:function(t,e,n){var r,o,i,a=n(\"d864\"),s=n(\"3024\"),c=n(\"32fc\"),u=n(\"1ec9\"),f=n(\"e53d\"),l=f.process,p=f.setImmediate,d=f.clearImmediate,h=f.MessageChannel,v=f.Dispatch,y=0,m={},g=\"onreadystatechange\",b=function(){var t=+this;if(m.hasOwnProperty(t)){var e=m[t];delete m[t],e()}},_=function(t){b.call(t.data)};p&&d||(p=function(t){var e=[],n=1;while(arguments.length>n)e.push(arguments[n++]);return m[++y]=function(){s(\"function\"==typeof t?t:Function(t),e)},r(y),y},d=function(t){delete m[t]},\"process\"==n(\"6b4c\")(l)?r=function(t){l.nextTick(a(b,t,1))}:v&&v.now?r=function(t){v.now(a(b,t,1))}:h?(o=new h,i=o.port2,o.port1.onmessage=_,r=a(i.postMessage,i,1)):f.addEventListener&&\"function\"==typeof postMessage&&!f.importScripts?(r=function(t){f.postMessage(t+\"\",\"*\")},f.addEventListener(\"message\",_,!1)):r=g in u(\"script\")?function(t){c.appendChild(u(\"script\"))[g]=function(){c.removeChild(this),b.call(t)}}:function(t){setTimeout(a(b,t,1),0)}),t.exports={set:p,clear:d}},\"41a0\":function(t,e,n){\"use strict\";var r=n(\"2aeb\"),o=n(\"4630\"),i=n(\"7f20\"),a={};n(\"32e9\")(a,n(\"2b4c\")(\"iterator\"),function(){return this}),t.exports=function(t,e,n){t.prototype=r(a,{next:o(1,n)}),i(t,e+\" Iterator\")}},\"41b2\":function(t,e,n){\"use strict\";e.__esModule=!0;var r=n(\"3f6b\"),o=i(r);function i(t){return t&&t.__esModule?t:{default:t}}e.default=o.default||function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(t[r]=n[r])}return t}},4362:function(t,e,n){e.nextTick=function(t){var e=Array.prototype.slice.call(arguments);e.shift(),setTimeout(function(){t.apply(null,e)},0)},e.platform=e.arch=e.execPath=e.title=\"browser\",e.pid=1,e.browser=!0,e.env={},e.argv=[],e.binding=function(t){throw new Error(\"No such module. (Possibly not yet loaded)\")},function(){var t,r=\"/\";e.cwd=function(){return r},e.chdir=function(e){t||(t=n(\"df7c\")),r=t.resolve(e,r)}}(),e.exit=e.kill=e.umask=e.dlopen=e.uptime=e.memoryUsage=e.uvCounters=function(){},e.features={}},\"43fc\":function(t,e,n){\"use strict\";var r=n(\"63b6\"),o=n(\"656e\"),i=n(\"4439\");r(r.S,\"Promise\",{try:function(t){var e=o.f(this),n=i(t);return(n.e?e.reject:e.resolve)(n.v),e.promise}})},4439:function(t,e){t.exports=function(t){try{return{e:!1,v:t()}}catch(e){return{e:!0,v:e}}}},\"454f\":function(t,e,n){n(\"46a7\");var r=n(\"584a\").Object;t.exports=function(t,e,n){return r.defineProperty(t,e,n)}},4588:function(t,e){var n=Math.ceil,r=Math.floor;t.exports=function(t){return isNaN(t=+t)?0:(t>0?r:n)(t)}},\"45f2\":function(t,e,n){var r=n(\"d9f6\").f,o=n(\"07e3\"),i=n(\"5168\")(\"toStringTag\");t.exports=function(t,e,n){t&&!o(t=n?t:t.prototype,i)&&r(t,i,{configurable:!0,value:e})}},4630:function(t,e){t.exports=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}}},\"467f\":function(t,e,n){\"use strict\";var r=n(\"2d83\");t.exports=function(t,e,n){var o=n.config.validateStatus;n.status&&o&&!o(n.status)?e(r(\"Request failed with status code \"+n.status,n.config,null,n.request,n)):t(n)}},\"46a7\":function(t,e,n){var r=n(\"63b6\");r(r.S+r.F*!n(\"8e60\"),\"Object\",{defineProperty:n(\"d9f6\").f})},\"47ee\":function(t,e,n){var r=n(\"c3a1\"),o=n(\"9aa9\"),i=n(\"355d\");t.exports=function(t){var e=r(t),n=o.f;if(n){var a,s=n(t),c=i.f,u=0;while(s.length>u)c.call(t,a=s[u++])&&e.push(a)}return e}},\"481b\":function(t,e){t.exports={}},\"4a59\":function(t,e,n){var r=n(\"9b43\"),o=n(\"1fa8\"),i=n(\"33a4\"),a=n(\"cb7c\"),s=n(\"9def\"),c=n(\"27ee\"),u={},f={};e=t.exports=function(t,e,n,l,p){var d,h,v,y,m=p?function(){return t}:c(t),g=r(n,l,e?2:1),b=0;if(\"function\"!=typeof m)throw TypeError(t+\" is not iterable!\");if(i(m)){for(d=s(t.length);d>b;b++)if(y=e?g(a(h=t[b])[0],h[1]):g(t[b]),y===u||y===f)return y}else for(v=m.call(t);!(h=v.next()).done;)if(y=o(v,g,h.value,e),y===u||y===f)return y};e.BREAK=u,e.RETURN=f},\"4bf8\":function(t,e,n){var r=n(\"be13\");t.exports=function(t){return Object(r(t))}},\"4c95\":function(t,e,n){\"use strict\";var r=n(\"e53d\"),o=n(\"584a\"),i=n(\"d9f6\"),a=n(\"8e60\"),s=n(\"5168\")(\"species\");t.exports=function(t){var e=\"function\"==typeof o[t]?o[t]:r[t];a&&e&&!e[s]&&i.f(e,s,{configurable:!0,get:function(){return this}})}},\"4ee1\":function(t,e,n){var r=n(\"5168\")(\"iterator\"),o=!1;try{var i=[7][r]();i[\"return\"]=function(){o=!0},Array.from(i,function(){throw 2})}catch(a){}t.exports=function(t,e){if(!e&&!o)return!1;var n=!1;try{var i=[7],s=i[r]();s.next=function(){return{done:n=!0}},i[r]=function(){return s},t(i)}catch(a){}return n}},\"50ed\":function(t,e){t.exports=function(t,e){return{value:e,done:!!t}}},5168:function(t,e,n){var r=n(\"dbdb\")(\"wks\"),o=n(\"62a0\"),i=n(\"e53d\").Symbol,a=\"function\"==typeof i,s=t.exports=function(t){return r[t]||(r[t]=a&&i[t]||(a?i:o)(\"Symbol.\"+t))};s.store=r},\"51b6\":function(t,e,n){n(\"a3c3\"),t.exports=n(\"584a\").Object.assign},5270:function(t,e,n){\"use strict\";var r=n(\"c532\"),o=n(\"c401\"),i=n(\"2e67\"),a=n(\"2444\"),s=n(\"d925\"),c=n(\"e683\");function u(t){t.cancelToken&&t.cancelToken.throwIfRequested()}t.exports=function(t){u(t),t.baseURL&&!s(t.url)&&(t.url=c(t.baseURL,t.url)),t.headers=t.headers||{},t.data=o(t.data,t.headers,t.transformRequest),t.headers=r.merge(t.headers.common||{},t.headers[t.method]||{},t.headers||{}),r.forEach([\"delete\",\"get\",\"head\",\"post\",\"put\",\"patch\",\"common\"],function(e){delete t.headers[e]});var e=t.adapter||a.adapter;return e(t).then(function(e){return u(t),e.data=o(e.data,e.headers,t.transformResponse),e},function(e){return i(e)||(u(t),e&&e.response&&(e.response.data=o(e.response.data,e.response.headers,t.transformResponse))),Promise.reject(e)})}},\"52a7\":function(t,e){e.f={}.propertyIsEnumerable},\"53e2\":function(t,e,n){var r=n(\"07e3\"),o=n(\"241e\"),i=n(\"5559\")(\"IE_PROTO\"),a=Object.prototype;t.exports=Object.getPrototypeOf||function(t){return t=o(t),r(t,i)?t[i]:\"function\"==typeof t.constructor&&t instanceof t.constructor?t.constructor.prototype:t instanceof Object?a:null}},\"551c\":function(t,e,n){\"use strict\";var r,o,i,a,s=n(\"2d00\"),c=n(\"7726\"),u=n(\"9b43\"),f=n(\"23c6\"),l=n(\"5ca1\"),p=n(\"d3f4\"),d=n(\"d8e8\"),h=n(\"f605\"),v=n(\"4a59\"),y=n(\"ebd6\"),m=n(\"1991\").set,g=n(\"8079\")(),b=n(\"a5b8\"),_=n(\"9c80\"),w=n(\"a25f\"),x=n(\"bcaa\"),O=\"Promise\",E=c.TypeError,S=c.process,A=S&&S.versions,C=A&&A.v8||\"\",k=c[O],j=\"process\"==f(S),T=function(){},$=o=b.f,M=!!function(){try{var t=k.resolve(1),e=(t.constructor={})[n(\"2b4c\")(\"species\")]=function(t){t(T,T)};return(j||\"function\"==typeof PromiseRejectionEvent)&&t.then(T)instanceof e&&0!==C.indexOf(\"6.6\")&&-1===w.indexOf(\"Chrome/66\")}catch(r){}}(),P=function(t){var e;return!(!p(t)||\"function\"!=typeof(e=t.then))&&e},L=function(t,e){if(!t._n){t._n=!0;var n=t._c;g(function(){var r=t._v,o=1==t._s,i=0,a=function(e){var n,i,a,s=o?e.ok:e.fail,c=e.resolve,u=e.reject,f=e.domain;try{s?(o||(2==t._h&&F(t),t._h=1),!0===s?n=r:(f&&f.enter(),n=s(r),f&&(f.exit(),a=!0)),n===e.promise?u(E(\"Promise-chain cycle\")):(i=P(n))?i.call(n,c,u):c(n)):u(r)}catch(l){f&&!a&&f.exit(),u(l)}};while(n.length>i)a(n[i++]);t._c=[],t._n=!1,e&&!t._h&&R(t)})}},R=function(t){m.call(c,function(){var e,n,r,o=t._v,i=N(t);if(i&&(e=_(function(){j?S.emit(\"unhandledRejection\",o,t):(n=c.onunhandledrejection)?n({promise:t,reason:o}):(r=c.console)&&r.error&&r.error(\"Unhandled promise rejection\",o)}),t._h=j||N(t)?2:1),t._a=void 0,i&&e.e)throw e.v})},N=function(t){return 1!==t._h&&0===(t._a||t._c).length},F=function(t){m.call(c,function(){var e;j?S.emit(\"rejectionHandled\",t):(e=c.onrejectionhandled)&&e({promise:t,reason:t._v})})},I=function(t){var e=this;e._d||(e._d=!0,e=e._w||e,e._v=t,e._s=2,e._a||(e._a=e._c.slice()),L(e,!0))},D=function(t){var e,n=this;if(!n._d){n._d=!0,n=n._w||n;try{if(n===t)throw E(\"Promise can't be resolved itself\");(e=P(t))?g(function(){var r={_w:n,_d:!1};try{e.call(t,u(D,r,1),u(I,r,1))}catch(o){I.call(r,o)}}):(n._v=t,n._s=1,L(n,!1))}catch(r){I.call({_w:n,_d:!1},r)}}};M||(k=function(t){h(this,k,O,\"_h\"),d(t),r.call(this);try{t(u(D,this,1),u(I,this,1))}catch(e){I.call(this,e)}},r=function(t){this._c=[],this._a=void 0,this._s=0,this._d=!1,this._v=void 0,this._h=0,this._n=!1},r.prototype=n(\"dcbc\")(k.prototype,{then:function(t,e){var n=$(y(this,k));return n.ok=\"function\"!=typeof t||t,n.fail=\"function\"==typeof e&&e,n.domain=j?S.domain:void 0,this._c.push(n),this._a&&this._a.push(n),this._s&&L(this,!1),n.promise},catch:function(t){return this.then(void 0,t)}}),i=function(){var t=new r;this.promise=t,this.resolve=u(D,t,1),this.reject=u(I,t,1)},b.f=$=function(t){return t===k||t===a?new i(t):o(t)}),l(l.G+l.W+l.F*!M,{Promise:k}),n(\"7f20\")(k,O),n(\"7a56\")(O),a=n(\"8378\")[O],l(l.S+l.F*!M,O,{reject:function(t){var e=$(this),n=e.reject;return n(t),e.promise}}),l(l.S+l.F*(s||!M),O,{resolve:function(t){return x(s&&this===a?k:this,t)}}),l(l.S+l.F*!(M&&n(\"5cc5\")(function(t){k.all(t)[\"catch\"](T)})),O,{all:function(t){var e=this,n=$(e),r=n.resolve,o=n.reject,i=_(function(){var n=[],i=0,a=1;v(t,!1,function(t){var s=i++,c=!1;n.push(void 0),a++,e.resolve(t).then(function(t){c||(c=!0,n[s]=t,--a||r(n))},o)}),--a||r(n)});return i.e&&o(i.v),n.promise},race:function(t){var e=this,n=$(e),r=n.reject,o=_(function(){v(t,!1,function(t){e.resolve(t).then(n.resolve,r)})});return o.e&&r(o.v),n.promise}})},5537:function(t,e,n){var r=n(\"8378\"),o=n(\"7726\"),i=\"__core-js_shared__\",a=o[i]||(o[i]={});(t.exports=function(t,e){return a[t]||(a[t]=void 0!==e?e:{})})(\"versions\",[]).push({version:r.version,mode:n(\"2d00\")?\"pure\":\"global\",copyright:\"© 2019 Denis Pushkarev (zloirock.ru)\"})},5559:function(t,e,n){var r=n(\"dbdb\")(\"keys\"),o=n(\"62a0\");t.exports=function(t){return r[t]||(r[t]=o(t))}},\"584a\":function(t,e){var n=t.exports={version:\"2.6.9\"};\"number\"==typeof __e&&(__e=n)},\"597f\":function(t,e){t.exports=function(t,e,n,r){var o,i=0;function a(){var a=this,s=Number(new Date)-i,c=arguments;function u(){i=Number(new Date),n.apply(a,c)}function f(){o=void 0}r&&!o&&u(),o&&clearTimeout(o),void 0===r&&s>t?u():!0!==e&&(o=setTimeout(r?f:u,void 0===r?t-s:t))}return\"boolean\"!==typeof e&&(r=n,n=e,e=void 0),a}},\"5b4e\":function(t,e,n){var r=n(\"36c3\"),o=n(\"b447\"),i=n(\"0fc9\");t.exports=function(t){return function(e,n,a){var s,c=r(e),u=o(c.length),f=i(a,u);if(t&&n!=n){while(u>f)if(s=c[f++],s!=s)return!0}else for(;u>f;f++)if((t||f in c)&&c[f]===n)return t||f||0;return!t&&-1}}},\"5bba\":function(t,e,n){n(\"9d98\");var r=n(\"584a\").Object;t.exports=function(t,e){return r.defineProperties(t,e)}},\"5c95\":function(t,e,n){var r=n(\"35e8\");t.exports=function(t,e,n){for(var o in e)n&&t[o]?t[o]=e[o]:r(t,o,e[o]);return t}},\"5ca1\":function(t,e,n){var r=n(\"7726\"),o=n(\"8378\"),i=n(\"32e9\"),a=n(\"2aba\"),s=n(\"9b43\"),c=\"prototype\",u=function(t,e,n){var f,l,p,d,h=t&u.F,v=t&u.G,y=t&u.S,m=t&u.P,g=t&u.B,b=v?r:y?r[e]||(r[e]={}):(r[e]||{})[c],_=v?o:o[e]||(o[e]={}),w=_[c]||(_[c]={});for(f in v&&(n=e),n)l=!h&&b&&void 0!==b[f],p=(l?b:n)[f],d=g&&l?s(p,r):m&&\"function\"==typeof p?s(Function.call,p):p,b&&a(b,f,p,t&u.U),_[f]!=p&&i(_,f,d),m&&w[f]!=p&&(w[f]=p)};r.core=o,u.F=1,u.G=2,u.S=4,u.P=8,u.B=16,u.W=32,u.U=64,u.R=128,t.exports=u},\"5cc5\":function(t,e,n){var r=n(\"2b4c\")(\"iterator\"),o=!1;try{var i=[7][r]();i[\"return\"]=function(){o=!0},Array.from(i,function(){throw 2})}catch(a){}t.exports=function(t,e){if(!e&&!o)return!1;var n=!1;try{var i=[7],s=i[r]();s.next=function(){return{done:n=!0}},i[r]=function(){return s},t(i)}catch(a){}return n}},\"5e83\":function(t,e,n){t.exports=n(\"8580\")},\"613b\":function(t,e,n){var r=n(\"5537\")(\"keys\"),o=n(\"ca5a\");t.exports=function(t){return r[t]||(r[t]=o(t))}},\"626a\":function(t,e,n){var r=n(\"2d95\");t.exports=Object(\"z\").propertyIsEnumerable(0)?Object:function(t){return\"String\"==r(t)?t.split(\"\"):Object(t)}},\"62a0\":function(t,e){var n=0,r=Math.random();t.exports=function(t){return\"Symbol(\".concat(void 0===t?\"\":t,\")_\",(++n+r).toString(36))}},\"63b6\":function(t,e,n){var r=n(\"e53d\"),o=n(\"584a\"),i=n(\"d864\"),a=n(\"35e8\"),s=n(\"07e3\"),c=\"prototype\",u=function(t,e,n){var f,l,p,d=t&u.F,h=t&u.G,v=t&u.S,y=t&u.P,m=t&u.B,g=t&u.W,b=h?o:o[e]||(o[e]={}),_=b[c],w=h?r:v?r[e]:(r[e]||{})[c];for(f in h&&(n=e),n)l=!d&&w&&void 0!==w[f],l&&s(b,f)||(p=l?w[f]:n[f],b[f]=h&&\"function\"!=typeof w[f]?n[f]:m&&l?i(p,r):g&&w[f]==p?function(t){var e=function(e,n,r){if(this instanceof t){switch(arguments.length){case 0:return new t;case 1:return new t(e);case 2:return new t(e,n)}return new t(e,n,r)}return t.apply(this,arguments)};return e[c]=t[c],e}(p):y&&\"function\"==typeof p?i(Function.call,p):p,y&&((b.virtual||(b.virtual={}))[f]=p,t&u.R&&_&&!_[f]&&a(_,f,p)))};u.F=1,u.G=2,u.S=4,u.P=8,u.B=16,u.W=32,u.U=64,u.R=128,t.exports=u},\"656e\":function(t,e,n){\"use strict\";var r=n(\"79aa\");function o(t){var e,n;this.promise=new t(function(t,r){if(void 0!==e||void 0!==n)throw TypeError(\"Bad Promise constructor\");e=t,n=r}),this.resolve=r(e),this.reject=r(n)}t.exports.f=function(t){return new o(t)}},6718:function(t,e,n){var r=n(\"e53d\"),o=n(\"584a\"),i=n(\"b8e3\"),a=n(\"ccb9\"),s=n(\"d9f6\").f;t.exports=function(t){var e=o.Symbol||(o.Symbol=i?{}:r.Symbol||{});\"_\"==t.charAt(0)||t in e||s(e,t,{value:a.f(t)})}},6821:function(t,e,n){var r=n(\"626a\"),o=n(\"be13\");t.exports=function(t){return r(o(t))}},\"696e\":function(t,e,n){n(\"c207\"),n(\"1654\"),n(\"6c1c\"),n(\"24c5\"),n(\"3c11\"),n(\"43fc\"),t.exports=n(\"584a\").Promise},\"69a8\":function(t,e){var n={}.hasOwnProperty;t.exports=function(t,e){return n.call(t,e)}},\"69d3\":function(t,e,n){n(\"6718\")(\"asyncIterator\")},\"6a99\":function(t,e,n){var r=n(\"d3f4\");t.exports=function(t,e){if(!r(t))return t;var n,o;if(e&&\"function\"==typeof(n=t.toString)&&!r(o=n.call(t)))return o;if(\"function\"==typeof(n=t.valueOf)&&!r(o=n.call(t)))return o;if(!e&&\"function\"==typeof(n=t.toString)&&!r(o=n.call(t)))return o;throw TypeError(\"Can't convert object to primitive value\")}},\"6abf\":function(t,e,n){var r=n(\"e6f3\"),o=n(\"1691\").concat(\"length\",\"prototype\");e.f=Object.getOwnPropertyNames||function(t){return r(t,o)}},\"6b4c\":function(t,e){var n={}.toString;t.exports=function(t){return n.call(t).slice(8,-1)}},\"6c1c\":function(t,e,n){n(\"c367\");for(var r=n(\"e53d\"),o=n(\"35e8\"),i=n(\"481b\"),a=n(\"5168\")(\"toStringTag\"),s=\"CSSRuleList,CSSStyleDeclaration,CSSValueList,ClientRectList,DOMRectList,DOMStringList,DOMTokenList,DataTransferItemList,FileList,HTMLAllCollection,HTMLCollection,HTMLFormElement,HTMLSelectElement,MediaList,MimeTypeArray,NamedNodeMap,NodeList,PaintRequestList,Plugin,PluginArray,SVGLengthList,SVGNumberList,SVGPathSegList,SVGPointList,SVGStringList,SVGTransformList,SourceBufferList,StyleSheetList,TextTrackCueList,TextTrackList,TouchList\".split(\",\"),c=0;c<s.length;c++){var u=s[c],f=r[u],l=f&&f.prototype;l&&!l[a]&&o(l,a,u),i[u]=i.Array}},\"6dd8\":function(t,e,n){\"use strict\";n.r(e),function(t){var n=function(){if(\"undefined\"!==typeof Map)return Map;function t(t,e){var n=-1;return t.some(function(t,r){return t[0]===e&&(n=r,!0)}),n}return function(){function e(){this.__entries__=[]}return Object.defineProperty(e.prototype,\"size\",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),e.prototype.get=function(e){var n=t(this.__entries__,e),r=this.__entries__[n];return r&&r[1]},e.prototype.set=function(e,n){var r=t(this.__entries__,e);~r?this.__entries__[r][1]=n:this.__entries__.push([e,n])},e.prototype.delete=function(e){var n=this.__entries__,r=t(n,e);~r&&n.splice(r,1)},e.prototype.has=function(e){return!!~t(this.__entries__,e)},e.prototype.clear=function(){this.__entries__.splice(0)},e.prototype.forEach=function(t,e){void 0===e&&(e=null);for(var n=0,r=this.__entries__;n<r.length;n++){var o=r[n];t.call(e,o[1],o[0])}},e}()}(),r=\"undefined\"!==typeof window&&\"undefined\"!==typeof document&&window.document===document,o=function(){return\"undefined\"!==typeof t&&t.Math===Math?t:\"undefined\"!==typeof self&&self.Math===Math?self:\"undefined\"!==typeof window&&window.Math===Math?window:Function(\"return this\")()}(),i=function(){return\"function\"===typeof requestAnimationFrame?requestAnimationFrame.bind(o):function(t){return setTimeout(function(){return t(Date.now())},1e3/60)}}(),a=2;function s(t,e){var n=!1,r=!1,o=0;function s(){n&&(n=!1,t()),r&&u()}function c(){i(s)}function u(){var t=Date.now();if(n){if(t-o<a)return;r=!0}else n=!0,r=!1,setTimeout(c,e);o=t}return u}var c=20,u=[\"top\",\"right\",\"bottom\",\"left\",\"width\",\"height\",\"size\",\"weight\"],f=\"undefined\"!==typeof MutationObserver,l=function(){function t(){this.connected_=!1,this.mutationEventsAdded_=!1,this.mutationsObserver_=null,this.observers_=[],this.onTransitionEnd_=this.onTransitionEnd_.bind(this),this.refresh=s(this.refresh.bind(this),c)}return t.prototype.addObserver=function(t){~this.observers_.indexOf(t)||this.observers_.push(t),this.connected_||this.connect_()},t.prototype.removeObserver=function(t){var e=this.observers_,n=e.indexOf(t);~n&&e.splice(n,1),!e.length&&this.connected_&&this.disconnect_()},t.prototype.refresh=function(){var t=this.updateObservers_();t&&this.refresh()},t.prototype.updateObservers_=function(){var t=this.observers_.filter(function(t){return t.gatherActive(),t.hasActive()});return t.forEach(function(t){return t.broadcastActive()}),t.length>0},t.prototype.connect_=function(){r&&!this.connected_&&(document.addEventListener(\"transitionend\",this.onTransitionEnd_),window.addEventListener(\"resize\",this.refresh),f?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener(\"DOMSubtreeModified\",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},t.prototype.disconnect_=function(){r&&this.connected_&&(document.removeEventListener(\"transitionend\",this.onTransitionEnd_),window.removeEventListener(\"resize\",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener(\"DOMSubtreeModified\",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},t.prototype.onTransitionEnd_=function(t){var e=t.propertyName,n=void 0===e?\"\":e,r=u.some(function(t){return!!~n.indexOf(t)});r&&this.refresh()},t.getInstance=function(){return this.instance_||(this.instance_=new t),this.instance_},t.instance_=null,t}(),p=function(t,e){for(var n=0,r=Object.keys(e);n<r.length;n++){var o=r[n];Object.defineProperty(t,o,{value:e[o],enumerable:!1,writable:!1,configurable:!0})}return t},d=function(t){var e=t&&t.ownerDocument&&t.ownerDocument.defaultView;return e||o},h=E(0,0,0,0);function v(t){return parseFloat(t)||0}function y(t){for(var e=[],n=1;n<arguments.length;n++)e[n-1]=arguments[n];return e.reduce(function(e,n){var r=t[\"border-\"+n+\"-width\"];return e+v(r)},0)}function m(t){for(var e=[\"top\",\"right\",\"bottom\",\"left\"],n={},r=0,o=e;r<o.length;r++){var i=o[r],a=t[\"padding-\"+i];n[i]=v(a)}return n}function g(t){var e=t.getBBox();return E(0,0,e.width,e.height)}function b(t){var e=t.clientWidth,n=t.clientHeight;if(!e&&!n)return h;var r=d(t).getComputedStyle(t),o=m(r),i=o.left+o.right,a=o.top+o.bottom,s=v(r.width),c=v(r.height);if(\"border-box\"===r.boxSizing&&(Math.round(s+i)!==e&&(s-=y(r,\"left\",\"right\")+i),Math.round(c+a)!==n&&(c-=y(r,\"top\",\"bottom\")+a)),!w(t)){var u=Math.round(s+i)-e,f=Math.round(c+a)-n;1!==Math.abs(u)&&(s-=u),1!==Math.abs(f)&&(c-=f)}return E(o.left,o.top,s,c)}var _=function(){return\"undefined\"!==typeof SVGGraphicsElement?function(t){return t instanceof d(t).SVGGraphicsElement}:function(t){return t instanceof d(t).SVGElement&&\"function\"===typeof t.getBBox}}();function w(t){return t===d(t).document.documentElement}function x(t){return r?_(t)?g(t):b(t):h}function O(t){var e=t.x,n=t.y,r=t.width,o=t.height,i=\"undefined\"!==typeof DOMRectReadOnly?DOMRectReadOnly:Object,a=Object.create(i.prototype);return p(a,{x:e,y:n,width:r,height:o,top:n,right:e+r,bottom:o+n,left:e}),a}function E(t,e,n,r){return{x:t,y:e,width:n,height:r}}var S=function(){function t(t){this.broadcastWidth=0,this.broadcastHeight=0,this.contentRect_=E(0,0,0,0),this.target=t}return t.prototype.isActive=function(){var t=x(this.target);return this.contentRect_=t,t.width!==this.broadcastWidth||t.height!==this.broadcastHeight},t.prototype.broadcastRect=function(){var t=this.contentRect_;return this.broadcastWidth=t.width,this.broadcastHeight=t.height,t},t}(),A=function(){function t(t,e){var n=O(e);p(this,{target:t,contentRect:n})}return t}(),C=function(){function t(t,e,r){if(this.activeObservations_=[],this.observations_=new n,\"function\"!==typeof t)throw new TypeError(\"The callback provided as parameter 1 is not a function.\");this.callback_=t,this.controller_=e,this.callbackCtx_=r}return t.prototype.observe=function(t){if(!arguments.length)throw new TypeError(\"1 argument required, but only 0 present.\");if(\"undefined\"!==typeof Element&&Element instanceof Object){if(!(t instanceof d(t).Element))throw new TypeError('parameter 1 is not of type \"Element\".');var e=this.observations_;e.has(t)||(e.set(t,new S(t)),this.controller_.addObserver(this),this.controller_.refresh())}},t.prototype.unobserve=function(t){if(!arguments.length)throw new TypeError(\"1 argument required, but only 0 present.\");if(\"undefined\"!==typeof Element&&Element instanceof Object){if(!(t instanceof d(t).Element))throw new TypeError('parameter 1 is not of type \"Element\".');var e=this.observations_;e.has(t)&&(e.delete(t),e.size||this.controller_.removeObserver(this))}},t.prototype.disconnect=function(){this.clearActive(),this.observations_.clear(),this.controller_.removeObserver(this)},t.prototype.gatherActive=function(){var t=this;this.clearActive(),this.observations_.forEach(function(e){e.isActive()&&t.activeObservations_.push(e)})},t.prototype.broadcastActive=function(){if(this.hasActive()){var t=this.callbackCtx_,e=this.activeObservations_.map(function(t){return new A(t.target,t.broadcastRect())});this.callback_.call(t,e,t),this.clearActive()}},t.prototype.clearActive=function(){this.activeObservations_.splice(0)},t.prototype.hasActive=function(){return this.activeObservations_.length>0},t}(),k=\"undefined\"!==typeof WeakMap?new WeakMap:new n,j=function(){function t(e){if(!(this instanceof t))throw new TypeError(\"Cannot call a class as a function.\");if(!arguments.length)throw new TypeError(\"1 argument required, but only 0 present.\");var n=l.getInstance(),r=new C(e,n,this);k.set(this,r)}return t}();[\"observe\",\"unobserve\",\"disconnect\"].forEach(function(t){j.prototype[t]=function(){var e;return(e=k.get(this))[t].apply(e,arguments)}});var T=function(){return\"undefined\"!==typeof o.ResizeObserver?o.ResizeObserver:j}();e[\"default\"]=T}.call(this,n(\"c8ba\"))},\"71c1\":function(t,e,n){var r=n(\"3a38\"),o=n(\"25eb\");t.exports=function(t){return function(e,n){var i,a,s=String(o(e)),c=r(n),u=s.length;return c<0||c>=u?t?\"\":void 0:(i=s.charCodeAt(c),i<55296||i>56319||c+1===u||(a=s.charCodeAt(c+1))<56320||a>57343?t?s.charAt(c):i:t?s.slice(c,c+2):a-56320+(i-55296<<10)+65536)}}},7333:function(t,e,n){\"use strict\";var r=n(\"9e1e\"),o=n(\"0d58\"),i=n(\"2621\"),a=n(\"52a7\"),s=n(\"4bf8\"),c=n(\"626a\"),u=Object.assign;t.exports=!u||n(\"79e5\")(function(){var t={},e={},n=Symbol(),r=\"abcdefghijklmnopqrst\";return t[n]=7,r.split(\"\").forEach(function(t){e[t]=t}),7!=u({},t)[n]||Object.keys(u({},e)).join(\"\")!=r})?function(t,e){var n=s(t),u=arguments.length,f=1,l=i.f,p=a.f;while(u>f){var d,h=c(arguments[f++]),v=l?o(h).concat(l(h)):o(h),y=v.length,m=0;while(y>m)d=v[m++],r&&!p.call(h,d)||(n[d]=h[d])}return n}:u},\"765d\":function(t,e,n){n(\"6718\")(\"observable\")},7726:function(t,e){var n=t.exports=\"undefined\"!=typeof window&&window.Math==Math?window:\"undefined\"!=typeof self&&self.Math==Math?self:Function(\"return this\")();\"number\"==typeof __g&&(__g=n)},\"77f1\":function(t,e,n){var r=n(\"4588\"),o=Math.max,i=Math.min;t.exports=function(t,e){return t=r(t),t<0?o(t+e,0):i(t,e)}},\"794b\":function(t,e,n){t.exports=!n(\"8e60\")&&!n(\"294c\")(function(){return 7!=Object.defineProperty(n(\"1ec9\")(\"div\"),\"a\",{get:function(){return 7}}).a})},\"795b\":function(t,e,n){t.exports=n(\"696e\")},\"79aa\":function(t,e){t.exports=function(t){if(\"function\"!=typeof t)throw TypeError(t+\" is not a function!\");return t}},\"79e5\":function(t,e){t.exports=function(t){try{return!!t()}catch(e){return!0}}},\"7a56\":function(t,e,n){\"use strict\";var r=n(\"7726\"),o=n(\"86cc\"),i=n(\"9e1e\"),a=n(\"2b4c\")(\"species\");t.exports=function(t){var e=r[t];i&&e&&!e[a]&&o.f(e,a,{configurable:!0,get:function(){return this}})}},\"7a77\":function(t,e,n){\"use strict\";function r(t){this.message=t}r.prototype.toString=function(){return\"Cancel\"+(this.message?\": \"+this.message:\"\")},r.prototype.__CANCEL__=!0,t.exports=r},\"7aac\":function(t,e,n){\"use strict\";var r=n(\"c532\");t.exports=r.isStandardBrowserEnv()?function(){return{write:function(t,e,n,o,i,a){var s=[];s.push(t+\"=\"+encodeURIComponent(e)),r.isNumber(n)&&s.push(\"expires=\"+new Date(n).toGMTString()),r.isString(o)&&s.push(\"path=\"+o),r.isString(i)&&s.push(\"domain=\"+i),!0===a&&s.push(\"secure\"),document.cookie=s.join(\"; \")},read:function(t){var e=document.cookie.match(new RegExp(\"(^|;\\\\s*)(\"+t+\")=([^;]*)\"));return e?decodeURIComponent(e[3]):null},remove:function(t){this.write(t,\"\",Date.now()-864e5)}}}():function(){return{write:function(){},read:function(){return null},remove:function(){}}}()},\"7b3e\":function(t,e,n){\"use strict\";var r,o=n(\"a3de\");\n/**\n * Checks if an event is supported in the current execution environment.\n *\n * NOTE: This will not work correctly for non-generic events such as `change`,\n * `reset`, `load`, `error`, and `select`.\n *\n * Borrows from Modernizr.\n *\n * @param {string} eventNameSuffix Event name, e.g. \"click\".\n * @param {?boolean} capture Check if the capture phase is supported.\n * @return {boolean} True if the event is supported.\n * @internal\n * @license Modernizr 3.0.0pre (Custom Build) | MIT\n */\nfunction i(t,e){if(!o.canUseDOM||e&&!(\"addEventListener\"in document))return!1;var n=\"on\"+t,i=n in document;if(!i){var a=document.createElement(\"div\");a.setAttribute(n,\"return;\"),i=\"function\"===typeof a[n]}return!i&&r&&\"wheel\"===t&&(i=document.implementation.hasFeature(\"Events.wheel\",\"3.0\")),i}o.canUseDOM&&(r=document.implementation&&document.implementation.hasFeature&&!0!==document.implementation.hasFeature(\"\",\"\")),t.exports=i},\"7cd6\":function(t,e,n){var r=n(\"40c3\"),o=n(\"5168\")(\"iterator\"),i=n(\"481b\");t.exports=n(\"584a\").getIteratorMethod=function(t){if(void 0!=t)return t[o]||t[\"@@iterator\"]||i[r(t)]}},\"7e90\":function(t,e,n){var r=n(\"d9f6\"),o=n(\"e4ae\"),i=n(\"c3a1\");t.exports=n(\"8e60\")?Object.defineProperties:function(t,e){o(t);var n,a=i(e),s=a.length,c=0;while(s>c)r.f(t,n=a[c++],e[n]);return t}},\"7f20\":function(t,e,n){var r=n(\"86cc\").f,o=n(\"69a8\"),i=n(\"2b4c\")(\"toStringTag\");t.exports=function(t,e,n){t&&!o(t=n?t:t.prototype,i)&&r(t,i,{configurable:!0,value:e})}},\"7f7f\":function(t,e,n){var r=n(\"86cc\").f,o=Function.prototype,i=/^\\s*function ([^ (]*)/,a=\"name\";a in o||n(\"9e1e\")&&r(o,a,{configurable:!0,get:function(){try{return(\"\"+this).match(i)[1]}catch(t){return\"\"}}})},8079:function(t,e,n){var r=n(\"7726\"),o=n(\"1991\").set,i=r.MutationObserver||r.WebKitMutationObserver,a=r.process,s=r.Promise,c=\"process\"==n(\"2d95\")(a);t.exports=function(){var t,e,n,u=function(){var r,o;c&&(r=a.domain)&&r.exit();while(t){o=t.fn,t=t.next;try{o()}catch(i){throw t?n():e=void 0,i}}e=void 0,r&&r.enter()};if(c)n=function(){a.nextTick(u)};else if(!i||r.navigator&&r.navigator.standalone)if(s&&s.resolve){var f=s.resolve(void 0);n=function(){f.then(u)}}else n=function(){o.call(r,u)};else{var l=!0,p=document.createTextNode(\"\");new i(u).observe(p,{characterData:!0}),n=function(){p.data=l=!l}}return function(r){var o={fn:r,next:void 0};e&&(e.next=o),t||(t=o,n()),e=o}}},8378:function(t,e){var n=t.exports={version:\"2.6.9\"};\"number\"==typeof __e&&(__e=n)},8436:function(t,e){t.exports=function(){}},\"84f2\":function(t,e){t.exports={}},8580:function(t,e,n){n(\"ee6d\"),t.exports=n(\"584a\").Object.getOwnPropertyDescriptors},\"85f2\":function(t,e,n){t.exports=n(\"454f\")},\"86cc\":function(t,e,n){var r=n(\"cb7c\"),o=n(\"c69a\"),i=n(\"6a99\"),a=Object.defineProperty;e.f=n(\"9e1e\")?Object.defineProperty:function(t,e,n){if(r(t),e=i(e,!0),r(n),o)try{return a(t,e,n)}catch(s){}if(\"get\"in n||\"set\"in n)throw TypeError(\"Accessors not supported!\");return\"value\"in n&&(t[e]=n.value),t}},\"8aae\":function(t,e,n){n(\"32a6\"),t.exports=n(\"584a\").Object.keys},\"8c4f\":function(t,e,n){\"use strict\";\n/*!\n  * vue-router v3.0.6\n  * (c) 2019 Evan You\n  * @license MIT\n  */function r(t,e){0}function o(t){return Object.prototype.toString.call(t).indexOf(\"Error\")>-1}function i(t,e){for(var n in e)t[n]=e[n];return t}var a={name:\"RouterView\",functional:!0,props:{name:{type:String,default:\"default\"}},render:function(t,e){var n=e.props,r=e.children,o=e.parent,a=e.data;a.routerView=!0;var c=o.$createElement,u=n.name,f=o.$route,l=o._routerViewCache||(o._routerViewCache={}),p=0,d=!1;while(o&&o._routerRoot!==o){var h=o.$vnode&&o.$vnode.data;h&&(h.routerView&&p++,h.keepAlive&&o._inactive&&(d=!0)),o=o.$parent}if(a.routerViewDepth=p,d)return c(l[u],a,r);var v=f.matched[p];if(!v)return l[u]=null,c();var y=l[u]=v.components[u];a.registerRouteInstance=function(t,e){var n=v.instances[u];(e&&n!==t||!e&&n===t)&&(v.instances[u]=e)},(a.hook||(a.hook={})).prepatch=function(t,e){v.instances[u]=e.componentInstance},a.hook.init=function(t){t.data.keepAlive&&t.componentInstance&&t.componentInstance!==v.instances[u]&&(v.instances[u]=t.componentInstance)};var m=a.props=s(f,v.props&&v.props[u]);if(m){m=a.props=i({},m);var g=a.attrs=a.attrs||{};for(var b in m)y.props&&b in y.props||(g[b]=m[b],delete m[b])}return c(y,a,r)}};function s(t,e){switch(typeof e){case\"undefined\":return;case\"object\":return e;case\"function\":return e(t);case\"boolean\":return e?t.params:void 0;default:0}}var c=/[!'()*]/g,u=function(t){return\"%\"+t.charCodeAt(0).toString(16)},f=/%2C/g,l=function(t){return encodeURIComponent(t).replace(c,u).replace(f,\",\")},p=decodeURIComponent;function d(t,e,n){void 0===e&&(e={});var r,o=n||h;try{r=o(t||\"\")}catch(a){r={}}for(var i in e)r[i]=e[i];return r}function h(t){var e={};return t=t.trim().replace(/^(\\?|#|&)/,\"\"),t?(t.split(\"&\").forEach(function(t){var n=t.replace(/\\+/g,\" \").split(\"=\"),r=p(n.shift()),o=n.length>0?p(n.join(\"=\")):null;void 0===e[r]?e[r]=o:Array.isArray(e[r])?e[r].push(o):e[r]=[e[r],o]}),e):e}function v(t){var e=t?Object.keys(t).map(function(e){var n=t[e];if(void 0===n)return\"\";if(null===n)return l(e);if(Array.isArray(n)){var r=[];return n.forEach(function(t){void 0!==t&&(null===t?r.push(l(e)):r.push(l(e)+\"=\"+l(t)))}),r.join(\"&\")}return l(e)+\"=\"+l(n)}).filter(function(t){return t.length>0}).join(\"&\"):null;return e?\"?\"+e:\"\"}var y=/\\/?$/;function m(t,e,n,r){var o=r&&r.options.stringifyQuery,i=e.query||{};try{i=g(i)}catch(s){}var a={name:e.name||t&&t.name,meta:t&&t.meta||{},path:e.path||\"/\",hash:e.hash||\"\",query:i,params:e.params||{},fullPath:w(e,o),matched:t?_(t):[]};return n&&(a.redirectedFrom=w(n,o)),Object.freeze(a)}function g(t){if(Array.isArray(t))return t.map(g);if(t&&\"object\"===typeof t){var e={};for(var n in t)e[n]=g(t[n]);return e}return t}var b=m(null,{path:\"/\"});function _(t){var e=[];while(t)e.unshift(t),t=t.parent;return e}function w(t,e){var n=t.path,r=t.query;void 0===r&&(r={});var o=t.hash;void 0===o&&(o=\"\");var i=e||v;return(n||\"/\")+i(r)+o}function x(t,e){return e===b?t===e:!!e&&(t.path&&e.path?t.path.replace(y,\"\")===e.path.replace(y,\"\")&&t.hash===e.hash&&O(t.query,e.query):!(!t.name||!e.name)&&(t.name===e.name&&t.hash===e.hash&&O(t.query,e.query)&&O(t.params,e.params)))}function O(t,e){if(void 0===t&&(t={}),void 0===e&&(e={}),!t||!e)return t===e;var n=Object.keys(t),r=Object.keys(e);return n.length===r.length&&n.every(function(n){var r=t[n],o=e[n];return\"object\"===typeof r&&\"object\"===typeof o?O(r,o):String(r)===String(o)})}function E(t,e){return 0===t.path.replace(y,\"/\").indexOf(e.path.replace(y,\"/\"))&&(!e.hash||t.hash===e.hash)&&S(t.query,e.query)}function S(t,e){for(var n in e)if(!(n in t))return!1;return!0}var A,C=[String,Object],k=[String,Array],j={name:\"RouterLink\",props:{to:{type:C,required:!0},tag:{type:String,default:\"a\"},exact:Boolean,append:Boolean,replace:Boolean,activeClass:String,exactActiveClass:String,event:{type:k,default:\"click\"}},render:function(t){var e=this,n=this.$router,r=this.$route,o=n.resolve(this.to,r,this.append),a=o.location,s=o.route,c=o.href,u={},f=n.options.linkActiveClass,l=n.options.linkExactActiveClass,p=null==f?\"router-link-active\":f,d=null==l?\"router-link-exact-active\":l,h=null==this.activeClass?p:this.activeClass,v=null==this.exactActiveClass?d:this.exactActiveClass,y=a.path?m(null,a,null,n):s;u[v]=x(r,y),u[h]=this.exact?u[v]:E(r,y);var g=function(t){T(t)&&(e.replace?n.replace(a):n.push(a))},b={click:T};Array.isArray(this.event)?this.event.forEach(function(t){b[t]=g}):b[this.event]=g;var _={class:u};if(\"a\"===this.tag)_.on=b,_.attrs={href:c};else{var w=$(this.$slots.default);if(w){w.isStatic=!1;var O=w.data=i({},w.data);O.on=b;var S=w.data.attrs=i({},w.data.attrs);S.href=c}else _.on=b}return t(this.tag,_,this.$slots.default)}};function T(t){if(!(t.metaKey||t.altKey||t.ctrlKey||t.shiftKey)&&!t.defaultPrevented&&(void 0===t.button||0===t.button)){if(t.currentTarget&&t.currentTarget.getAttribute){var e=t.currentTarget.getAttribute(\"target\");if(/\\b_blank\\b/i.test(e))return}return t.preventDefault&&t.preventDefault(),!0}}function $(t){if(t)for(var e,n=0;n<t.length;n++){if(e=t[n],\"a\"===e.tag)return e;if(e.children&&(e=$(e.children)))return e}}function M(t){if(!M.installed||A!==t){M.installed=!0,A=t;var e=function(t){return void 0!==t},n=function(t,n){var r=t.$options._parentVnode;e(r)&&e(r=r.data)&&e(r=r.registerRouteInstance)&&r(t,n)};t.mixin({beforeCreate:function(){e(this.$options.router)?(this._routerRoot=this,this._router=this.$options.router,this._router.init(this),t.util.defineReactive(this,\"_route\",this._router.history.current)):this._routerRoot=this.$parent&&this.$parent._routerRoot||this,n(this,this)},destroyed:function(){n(this)}}),Object.defineProperty(t.prototype,\"$router\",{get:function(){return this._routerRoot._router}}),Object.defineProperty(t.prototype,\"$route\",{get:function(){return this._routerRoot._route}}),t.component(\"RouterView\",a),t.component(\"RouterLink\",j);var r=t.config.optionMergeStrategies;r.beforeRouteEnter=r.beforeRouteLeave=r.beforeRouteUpdate=r.created}}var P=\"undefined\"!==typeof window;function L(t,e,n){var r=t.charAt(0);if(\"/\"===r)return t;if(\"?\"===r||\"#\"===r)return e+t;var o=e.split(\"/\");n&&o[o.length-1]||o.pop();for(var i=t.replace(/^\\//,\"\").split(\"/\"),a=0;a<i.length;a++){var s=i[a];\"..\"===s?o.pop():\".\"!==s&&o.push(s)}return\"\"!==o[0]&&o.unshift(\"\"),o.join(\"/\")}function R(t){var e=\"\",n=\"\",r=t.indexOf(\"#\");r>=0&&(e=t.slice(r),t=t.slice(0,r));var o=t.indexOf(\"?\");return o>=0&&(n=t.slice(o+1),t=t.slice(0,o)),{path:t,query:n,hash:e}}function N(t){return t.replace(/\\/\\//g,\"/\")}var F=Array.isArray||function(t){return\"[object Array]\"==Object.prototype.toString.call(t)},I=rt,D=H,q=z,U=K,B=nt,V=new RegExp([\"(\\\\\\\\.)\",\"([\\\\/.])?(?:(?:\\\\:(\\\\w+)(?:\\\\(((?:\\\\\\\\.|[^\\\\\\\\()])+)\\\\))?|\\\\(((?:\\\\\\\\.|[^\\\\\\\\()])+)\\\\))([+*?])?|(\\\\*))\"].join(\"|\"),\"g\");function H(t,e){var n,r=[],o=0,i=0,a=\"\",s=e&&e.delimiter||\"/\";while(null!=(n=V.exec(t))){var c=n[0],u=n[1],f=n.index;if(a+=t.slice(i,f),i=f+c.length,u)a+=u[1];else{var l=t[i],p=n[2],d=n[3],h=n[4],v=n[5],y=n[6],m=n[7];a&&(r.push(a),a=\"\");var g=null!=p&&null!=l&&l!==p,b=\"+\"===y||\"*\"===y,_=\"?\"===y||\"*\"===y,w=n[2]||s,x=h||v;r.push({name:d||o++,prefix:p||\"\",delimiter:w,optional:_,repeat:b,partial:g,asterisk:!!m,pattern:x?J(x):m?\".*\":\"[^\"+X(w)+\"]+?\"})}}return i<t.length&&(a+=t.substr(i)),a&&r.push(a),r}function z(t,e){return K(H(t,e))}function G(t){return encodeURI(t).replace(/[\\/?#]/g,function(t){return\"%\"+t.charCodeAt(0).toString(16).toUpperCase()})}function W(t){return encodeURI(t).replace(/[?#]/g,function(t){return\"%\"+t.charCodeAt(0).toString(16).toUpperCase()})}function K(t){for(var e=new Array(t.length),n=0;n<t.length;n++)\"object\"===typeof t[n]&&(e[n]=new RegExp(\"^(?:\"+t[n].pattern+\")$\"));return function(n,r){for(var o=\"\",i=n||{},a=r||{},s=a.pretty?G:encodeURIComponent,c=0;c<t.length;c++){var u=t[c];if(\"string\"!==typeof u){var f,l=i[u.name];if(null==l){if(u.optional){u.partial&&(o+=u.prefix);continue}throw new TypeError('Expected \"'+u.name+'\" to be defined')}if(F(l)){if(!u.repeat)throw new TypeError('Expected \"'+u.name+'\" to not repeat, but received `'+JSON.stringify(l)+\"`\");if(0===l.length){if(u.optional)continue;throw new TypeError('Expected \"'+u.name+'\" to not be empty')}for(var p=0;p<l.length;p++){if(f=s(l[p]),!e[c].test(f))throw new TypeError('Expected all \"'+u.name+'\" to match \"'+u.pattern+'\", but received `'+JSON.stringify(f)+\"`\");o+=(0===p?u.prefix:u.delimiter)+f}}else{if(f=u.asterisk?W(l):s(l),!e[c].test(f))throw new TypeError('Expected \"'+u.name+'\" to match \"'+u.pattern+'\", but received \"'+f+'\"');o+=u.prefix+f}}else o+=u}return o}}function X(t){return t.replace(/([.+*?=^!:${}()[\\]|\\/\\\\])/g,\"\\\\$1\")}function J(t){return t.replace(/([=!:$\\/()])/g,\"\\\\$1\")}function Y(t,e){return t.keys=e,t}function Z(t){return t.sensitive?\"\":\"i\"}function Q(t,e){var n=t.source.match(/\\((?!\\?)/g);if(n)for(var r=0;r<n.length;r++)e.push({name:r,prefix:null,delimiter:null,optional:!1,repeat:!1,partial:!1,asterisk:!1,pattern:null});return Y(t,e)}function tt(t,e,n){for(var r=[],o=0;o<t.length;o++)r.push(rt(t[o],e,n).source);var i=new RegExp(\"(?:\"+r.join(\"|\")+\")\",Z(n));return Y(i,e)}function et(t,e,n){return nt(H(t,n),e,n)}function nt(t,e,n){F(e)||(n=e||n,e=[]),n=n||{};for(var r=n.strict,o=!1!==n.end,i=\"\",a=0;a<t.length;a++){var s=t[a];if(\"string\"===typeof s)i+=X(s);else{var c=X(s.prefix),u=\"(?:\"+s.pattern+\")\";e.push(s),s.repeat&&(u+=\"(?:\"+c+u+\")*\"),u=s.optional?s.partial?c+\"(\"+u+\")?\":\"(?:\"+c+\"(\"+u+\"))?\":c+\"(\"+u+\")\",i+=u}}var f=X(n.delimiter||\"/\"),l=i.slice(-f.length)===f;return r||(i=(l?i.slice(0,-f.length):i)+\"(?:\"+f+\"(?=$))?\"),i+=o?\"$\":r&&l?\"\":\"(?=\"+f+\"|$)\",Y(new RegExp(\"^\"+i,Z(n)),e)}function rt(t,e,n){return F(e)||(n=e||n,e=[]),n=n||{},t instanceof RegExp?Q(t,e):F(t)?tt(t,e,n):et(t,e,n)}I.parse=D,I.compile=q,I.tokensToFunction=U,I.tokensToRegExp=B;var ot=Object.create(null);function it(t,e,n){e=e||{};try{var r=ot[t]||(ot[t]=I.compile(t));return e.pathMatch&&(e[0]=e.pathMatch),r(e,{pretty:!0})}catch(o){return\"\"}finally{delete e[0]}}function at(t,e,n,r){var o=e||[],i=n||Object.create(null),a=r||Object.create(null);t.forEach(function(t){st(o,i,a,t)});for(var s=0,c=o.length;s<c;s++)\"*\"===o[s]&&(o.push(o.splice(s,1)[0]),c--,s--);return{pathList:o,pathMap:i,nameMap:a}}function st(t,e,n,r,o,i){var a=r.path,s=r.name;var c=r.pathToRegexpOptions||{},u=ut(a,o,c.strict);\"boolean\"===typeof r.caseSensitive&&(c.sensitive=r.caseSensitive);var f={path:u,regex:ct(u,c),components:r.components||{default:r.component},instances:{},name:s,parent:o,matchAs:i,redirect:r.redirect,beforeEnter:r.beforeEnter,meta:r.meta||{},props:null==r.props?{}:r.components?r.props:{default:r.props}};if(r.children&&r.children.forEach(function(r){var o=i?N(i+\"/\"+r.path):void 0;st(t,e,n,r,f,o)}),void 0!==r.alias){var l=Array.isArray(r.alias)?r.alias:[r.alias];l.forEach(function(i){var a={path:i,children:r.children};st(t,e,n,a,o,f.path||\"/\")})}e[f.path]||(t.push(f.path),e[f.path]=f),s&&(n[s]||(n[s]=f))}function ct(t,e){var n=I(t,[],e);return n}function ut(t,e,n){return n||(t=t.replace(/\\/$/,\"\")),\"/\"===t[0]?t:null==e?t:N(e.path+\"/\"+t)}function ft(t,e,n,r){var o=\"string\"===typeof t?{path:t}:t;if(o._normalized)return o;if(o.name)return i({},t);if(!o.path&&o.params&&e){o=i({},o),o._normalized=!0;var a=i(i({},e.params),o.params);if(e.name)o.name=e.name,o.params=a;else if(e.matched.length){var s=e.matched[e.matched.length-1].path;o.path=it(s,a,\"path \"+e.path)}else 0;return o}var c=R(o.path||\"\"),u=e&&e.path||\"/\",f=c.path?L(c.path,u,n||o.append):u,l=d(c.query,o.query,r&&r.options.parseQuery),p=o.hash||c.hash;return p&&\"#\"!==p.charAt(0)&&(p=\"#\"+p),{_normalized:!0,path:f,query:l,hash:p}}function lt(t,e){var n=at(t),r=n.pathList,o=n.pathMap,i=n.nameMap;function a(t){at(t,r,o,i)}function s(t,n,a){var s=ft(t,n,!1,e),c=s.name;if(c){var u=i[c];if(!u)return f(null,s);var l=u.regex.keys.filter(function(t){return!t.optional}).map(function(t){return t.name});if(\"object\"!==typeof s.params&&(s.params={}),n&&\"object\"===typeof n.params)for(var p in n.params)!(p in s.params)&&l.indexOf(p)>-1&&(s.params[p]=n.params[p]);if(u)return s.path=it(u.path,s.params,'named route \"'+c+'\"'),f(u,s,a)}else if(s.path){s.params={};for(var d=0;d<r.length;d++){var h=r[d],v=o[h];if(pt(v.regex,s.path,s.params))return f(v,s,a)}}return f(null,s)}function c(t,n){var r=t.redirect,o=\"function\"===typeof r?r(m(t,n,null,e)):r;if(\"string\"===typeof o&&(o={path:o}),!o||\"object\"!==typeof o)return f(null,n);var a=o,c=a.name,u=a.path,l=n.query,p=n.hash,d=n.params;if(l=a.hasOwnProperty(\"query\")?a.query:l,p=a.hasOwnProperty(\"hash\")?a.hash:p,d=a.hasOwnProperty(\"params\")?a.params:d,c){i[c];return s({_normalized:!0,name:c,query:l,hash:p,params:d},void 0,n)}if(u){var h=dt(u,t),v=it(h,d,'redirect route with path \"'+h+'\"');return s({_normalized:!0,path:v,query:l,hash:p},void 0,n)}return f(null,n)}function u(t,e,n){var r=it(n,e.params,'aliased route with path \"'+n+'\"'),o=s({_normalized:!0,path:r});if(o){var i=o.matched,a=i[i.length-1];return e.params=o.params,f(a,e)}return f(null,e)}function f(t,n,r){return t&&t.redirect?c(t,r||n):t&&t.matchAs?u(t,n,t.matchAs):m(t,n,r,e)}return{match:s,addRoutes:a}}function pt(t,e,n){var r=e.match(t);if(!r)return!1;if(!n)return!0;for(var o=1,i=r.length;o<i;++o){var a=t.keys[o-1],s=\"string\"===typeof r[o]?decodeURIComponent(r[o]):r[o];a&&(n[a.name||\"pathMatch\"]=s)}return!0}function dt(t,e){return L(t,e.parent?e.parent.path:\"/\",!0)}var ht=Object.create(null);function vt(){window.history.replaceState({key:jt()},\"\",window.location.href.replace(window.location.origin,\"\")),window.addEventListener(\"popstate\",function(t){mt(),t.state&&t.state.key&&Tt(t.state.key)})}function yt(t,e,n,r){if(t.app){var o=t.options.scrollBehavior;o&&t.app.$nextTick(function(){var i=gt(),a=o.call(t,e,n,r?i:null);a&&(\"function\"===typeof a.then?a.then(function(t){Et(t,i)}).catch(function(t){0}):Et(a,i))})}}function mt(){var t=jt();t&&(ht[t]={x:window.pageXOffset,y:window.pageYOffset})}function gt(){var t=jt();if(t)return ht[t]}function bt(t,e){var n=document.documentElement,r=n.getBoundingClientRect(),o=t.getBoundingClientRect();return{x:o.left-r.left-e.x,y:o.top-r.top-e.y}}function _t(t){return Ot(t.x)||Ot(t.y)}function wt(t){return{x:Ot(t.x)?t.x:window.pageXOffset,y:Ot(t.y)?t.y:window.pageYOffset}}function xt(t){return{x:Ot(t.x)?t.x:0,y:Ot(t.y)?t.y:0}}function Ot(t){return\"number\"===typeof t}function Et(t,e){var n=\"object\"===typeof t;if(n&&\"string\"===typeof t.selector){var r=document.querySelector(t.selector);if(r){var o=t.offset&&\"object\"===typeof t.offset?t.offset:{};o=xt(o),e=bt(r,o)}else _t(t)&&(e=wt(t))}else n&&_t(t)&&(e=wt(t));e&&window.scrollTo(e.x,e.y)}var St=P&&function(){var t=window.navigator.userAgent;return(-1===t.indexOf(\"Android 2.\")&&-1===t.indexOf(\"Android 4.0\")||-1===t.indexOf(\"Mobile Safari\")||-1!==t.indexOf(\"Chrome\")||-1!==t.indexOf(\"Windows Phone\"))&&(window.history&&\"pushState\"in window.history)}(),At=P&&window.performance&&window.performance.now?window.performance:Date,Ct=kt();function kt(){return At.now().toFixed(3)}function jt(){return Ct}function Tt(t){Ct=t}function $t(t,e){mt();var n=window.history;try{e?n.replaceState({key:Ct},\"\",t):(Ct=kt(),n.pushState({key:Ct},\"\",t))}catch(r){window.location[e?\"replace\":\"assign\"](t)}}function Mt(t){$t(t,!0)}function Pt(t,e,n){var r=function(o){o>=t.length?n():t[o]?e(t[o],function(){r(o+1)}):r(o+1)};r(0)}function Lt(t){return function(e,n,r){var i=!1,a=0,s=null;Rt(t,function(t,e,n,c){if(\"function\"===typeof t&&void 0===t.cid){i=!0,a++;var u,f=Dt(function(e){It(e)&&(e=e.default),t.resolved=\"function\"===typeof e?e:A.extend(e),n.components[c]=e,a--,a<=0&&r()}),l=Dt(function(t){var e=\"Failed to resolve async component \"+c+\": \"+t;s||(s=o(t)?t:new Error(e),r(s))});try{u=t(f,l)}catch(d){l(d)}if(u)if(\"function\"===typeof u.then)u.then(f,l);else{var p=u.component;p&&\"function\"===typeof p.then&&p.then(f,l)}}}),i||r()}}function Rt(t,e){return Nt(t.map(function(t){return Object.keys(t.components).map(function(n){return e(t.components[n],t.instances[n],t,n)})}))}function Nt(t){return Array.prototype.concat.apply([],t)}var Ft=\"function\"===typeof Symbol&&\"symbol\"===typeof Symbol.toStringTag;function It(t){return t.__esModule||Ft&&\"Module\"===t[Symbol.toStringTag]}function Dt(t){var e=!1;return function(){var n=[],r=arguments.length;while(r--)n[r]=arguments[r];if(!e)return e=!0,t.apply(this,n)}}var qt=function(t,e){this.router=t,this.base=Ut(e),this.current=b,this.pending=null,this.ready=!1,this.readyCbs=[],this.readyErrorCbs=[],this.errorCbs=[]};function Ut(t){if(!t)if(P){var e=document.querySelector(\"base\");t=e&&e.getAttribute(\"href\")||\"/\",t=t.replace(/^https?:\\/\\/[^\\/]+/,\"\")}else t=\"/\";return\"/\"!==t.charAt(0)&&(t=\"/\"+t),t.replace(/\\/$/,\"\")}function Bt(t,e){var n,r=Math.max(t.length,e.length);for(n=0;n<r;n++)if(t[n]!==e[n])break;return{updated:e.slice(0,n),activated:e.slice(n),deactivated:t.slice(n)}}function Vt(t,e,n,r){var o=Rt(t,function(t,r,o,i){var a=Ht(t,e);if(a)return Array.isArray(a)?a.map(function(t){return n(t,r,o,i)}):n(a,r,o,i)});return Nt(r?o.reverse():o)}function Ht(t,e){return\"function\"!==typeof t&&(t=A.extend(t)),t.options[e]}function zt(t){return Vt(t,\"beforeRouteLeave\",Wt,!0)}function Gt(t){return Vt(t,\"beforeRouteUpdate\",Wt)}function Wt(t,e){if(e)return function(){return t.apply(e,arguments)}}function Kt(t,e,n){return Vt(t,\"beforeRouteEnter\",function(t,r,o,i){return Xt(t,o,i,e,n)})}function Xt(t,e,n,r,o){return function(i,a,s){return t(i,a,function(t){s(t),\"function\"===typeof t&&r.push(function(){Jt(t,e.instances,n,o)})})}}function Jt(t,e,n,r){e[n]&&!e[n]._isBeingDestroyed?t(e[n]):r()&&setTimeout(function(){Jt(t,e,n,r)},16)}qt.prototype.listen=function(t){this.cb=t},qt.prototype.onReady=function(t,e){this.ready?t():(this.readyCbs.push(t),e&&this.readyErrorCbs.push(e))},qt.prototype.onError=function(t){this.errorCbs.push(t)},qt.prototype.transitionTo=function(t,e,n){var r=this,o=this.router.match(t,this.current);this.confirmTransition(o,function(){r.updateRoute(o),e&&e(o),r.ensureURL(),r.ready||(r.ready=!0,r.readyCbs.forEach(function(t){t(o)}))},function(t){n&&n(t),t&&!r.ready&&(r.ready=!0,r.readyErrorCbs.forEach(function(e){e(t)}))})},qt.prototype.confirmTransition=function(t,e,n){var i=this,a=this.current,s=function(t){o(t)&&(i.errorCbs.length?i.errorCbs.forEach(function(e){e(t)}):(r(!1,\"uncaught error during route navigation:\"),console.error(t))),n&&n(t)};if(x(t,a)&&t.matched.length===a.matched.length)return this.ensureURL(),s();var c=Bt(this.current.matched,t.matched),u=c.updated,f=c.deactivated,l=c.activated,p=[].concat(zt(f),this.router.beforeHooks,Gt(u),l.map(function(t){return t.beforeEnter}),Lt(l));this.pending=t;var d=function(e,n){if(i.pending!==t)return s();try{e(t,a,function(t){!1===t||o(t)?(i.ensureURL(!0),s(t)):\"string\"===typeof t||\"object\"===typeof t&&(\"string\"===typeof t.path||\"string\"===typeof t.name)?(s(),\"object\"===typeof t&&t.replace?i.replace(t):i.push(t)):n(t)})}catch(r){s(r)}};Pt(p,d,function(){var n=[],r=function(){return i.current===t},o=Kt(l,n,r),a=o.concat(i.router.resolveHooks);Pt(a,d,function(){if(i.pending!==t)return s();i.pending=null,e(t),i.router.app&&i.router.app.$nextTick(function(){n.forEach(function(t){t()})})})})},qt.prototype.updateRoute=function(t){var e=this.current;this.current=t,this.cb&&this.cb(t),this.router.afterHooks.forEach(function(n){n&&n(t,e)})};var Yt=function(t){function e(e,n){var r=this;t.call(this,e,n);var o=e.options.scrollBehavior,i=St&&o;i&&vt();var a=Zt(this.base);window.addEventListener(\"popstate\",function(t){var n=r.current,o=Zt(r.base);r.current===b&&o===a||r.transitionTo(o,function(t){i&&yt(e,t,n,!0)})})}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.go=function(t){window.history.go(t)},e.prototype.push=function(t,e,n){var r=this,o=this,i=o.current;this.transitionTo(t,function(t){$t(N(r.base+t.fullPath)),yt(r.router,t,i,!1),e&&e(t)},n)},e.prototype.replace=function(t,e,n){var r=this,o=this,i=o.current;this.transitionTo(t,function(t){Mt(N(r.base+t.fullPath)),yt(r.router,t,i,!1),e&&e(t)},n)},e.prototype.ensureURL=function(t){if(Zt(this.base)!==this.current.fullPath){var e=N(this.base+this.current.fullPath);t?$t(e):Mt(e)}},e.prototype.getCurrentLocation=function(){return Zt(this.base)},e}(qt);function Zt(t){var e=decodeURI(window.location.pathname);return t&&0===e.indexOf(t)&&(e=e.slice(t.length)),(e||\"/\")+window.location.search+window.location.hash}var Qt=function(t){function e(e,n,r){t.call(this,e,n),r&&te(this.base)||ee()}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.setupListeners=function(){var t=this,e=this.router,n=e.options.scrollBehavior,r=St&&n;r&&vt(),window.addEventListener(St?\"popstate\":\"hashchange\",function(){var e=t.current;ee()&&t.transitionTo(ne(),function(n){r&&yt(t.router,n,e,!0),St||ie(n.fullPath)})})},e.prototype.push=function(t,e,n){var r=this,o=this,i=o.current;this.transitionTo(t,function(t){oe(t.fullPath),yt(r.router,t,i,!1),e&&e(t)},n)},e.prototype.replace=function(t,e,n){var r=this,o=this,i=o.current;this.transitionTo(t,function(t){ie(t.fullPath),yt(r.router,t,i,!1),e&&e(t)},n)},e.prototype.go=function(t){window.history.go(t)},e.prototype.ensureURL=function(t){var e=this.current.fullPath;ne()!==e&&(t?oe(e):ie(e))},e.prototype.getCurrentLocation=function(){return ne()},e}(qt);function te(t){var e=Zt(t);if(!/^\\/#/.test(e))return window.location.replace(N(t+\"/#\"+e)),!0}function ee(){var t=ne();return\"/\"===t.charAt(0)||(ie(\"/\"+t),!1)}function ne(){var t=window.location.href,e=t.indexOf(\"#\");if(e<0)return\"\";t=t.slice(e+1);var n=t.indexOf(\"?\");if(n<0){var r=t.indexOf(\"#\");t=r>-1?decodeURI(t.slice(0,r))+t.slice(r):decodeURI(t)}else n>-1&&(t=decodeURI(t.slice(0,n))+t.slice(n));return t}function re(t){var e=window.location.href,n=e.indexOf(\"#\"),r=n>=0?e.slice(0,n):e;return r+\"#\"+t}function oe(t){St?$t(re(t)):window.location.hash=t}function ie(t){St?Mt(re(t)):window.location.replace(re(t))}var ae=function(t){function e(e,n){t.call(this,e,n),this.stack=[],this.index=-1}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.push=function(t,e,n){var r=this;this.transitionTo(t,function(t){r.stack=r.stack.slice(0,r.index+1).concat(t),r.index++,e&&e(t)},n)},e.prototype.replace=function(t,e,n){var r=this;this.transitionTo(t,function(t){r.stack=r.stack.slice(0,r.index).concat(t),e&&e(t)},n)},e.prototype.go=function(t){var e=this,n=this.index+t;if(!(n<0||n>=this.stack.length)){var r=this.stack[n];this.confirmTransition(r,function(){e.index=n,e.updateRoute(r)})}},e.prototype.getCurrentLocation=function(){var t=this.stack[this.stack.length-1];return t?t.fullPath:\"/\"},e.prototype.ensureURL=function(){},e}(qt),se=function(t){void 0===t&&(t={}),this.app=null,this.apps=[],this.options=t,this.beforeHooks=[],this.resolveHooks=[],this.afterHooks=[],this.matcher=lt(t.routes||[],this);var e=t.mode||\"hash\";switch(this.fallback=\"history\"===e&&!St&&!1!==t.fallback,this.fallback&&(e=\"hash\"),P||(e=\"abstract\"),this.mode=e,e){case\"history\":this.history=new Yt(this,t.base);break;case\"hash\":this.history=new Qt(this,t.base,this.fallback);break;case\"abstract\":this.history=new ae(this,t.base);break;default:0}},ce={currentRoute:{configurable:!0}};function ue(t,e){return t.push(e),function(){var n=t.indexOf(e);n>-1&&t.splice(n,1)}}function fe(t,e,n){var r=\"hash\"===n?\"#\"+e:e;return t?N(t+\"/\"+r):r}se.prototype.match=function(t,e,n){return this.matcher.match(t,e,n)},ce.currentRoute.get=function(){return this.history&&this.history.current},se.prototype.init=function(t){var e=this;if(this.apps.push(t),t.$once(\"hook:destroyed\",function(){var n=e.apps.indexOf(t);n>-1&&e.apps.splice(n,1),e.app===t&&(e.app=e.apps[0]||null)}),!this.app){this.app=t;var n=this.history;if(n instanceof Yt)n.transitionTo(n.getCurrentLocation());else if(n instanceof Qt){var r=function(){n.setupListeners()};n.transitionTo(n.getCurrentLocation(),r,r)}n.listen(function(t){e.apps.forEach(function(e){e._route=t})})}},se.prototype.beforeEach=function(t){return ue(this.beforeHooks,t)},se.prototype.beforeResolve=function(t){return ue(this.resolveHooks,t)},se.prototype.afterEach=function(t){return ue(this.afterHooks,t)},se.prototype.onReady=function(t,e){this.history.onReady(t,e)},se.prototype.onError=function(t){this.history.onError(t)},se.prototype.push=function(t,e,n){this.history.push(t,e,n)},se.prototype.replace=function(t,e,n){this.history.replace(t,e,n)},se.prototype.go=function(t){this.history.go(t)},se.prototype.back=function(){this.go(-1)},se.prototype.forward=function(){this.go(1)},se.prototype.getMatchedComponents=function(t){var e=t?t.matched?t:this.resolve(t).route:this.currentRoute;return e?[].concat.apply([],e.matched.map(function(t){return Object.keys(t.components).map(function(e){return t.components[e]})})):[]},se.prototype.resolve=function(t,e,n){e=e||this.history.current;var r=ft(t,e,n,this),o=this.match(r,e),i=o.redirectedFrom||o.fullPath,a=this.history.base,s=fe(a,i,this.mode);return{location:r,route:o,href:s,normalizedTo:r,resolved:o}},se.prototype.addRoutes=function(t){this.matcher.addRoutes(t),this.history.current!==b&&this.history.transitionTo(this.history.getCurrentLocation())},Object.defineProperties(se.prototype,ce),se.install=M,se.version=\"3.0.6\",P&&window.Vue&&window.Vue.use(se),e[\"a\"]=se},\"8df4\":function(t,e,n){\"use strict\";var r=n(\"7a77\");function o(t){if(\"function\"!==typeof t)throw new TypeError(\"executor must be a function.\");var e;this.promise=new Promise(function(t){e=t});var n=this;t(function(t){n.reason||(n.reason=new r(t),e(n.reason))})}o.prototype.throwIfRequested=function(){if(this.reason)throw this.reason},o.source=function(){var t,e=new o(function(e){t=e});return{token:e,cancel:t}},t.exports=o},\"8e60\":function(t,e,n){t.exports=!n(\"294c\")(function(){return 7!=Object.defineProperty({},\"a\",{get:function(){return 7}}).a})},\"8eb7\":function(t,e){var n,r,o,i,a,s,c,u,f,l,p,d,h,v,y,m=!1;function g(){if(!m){m=!0;var t=navigator.userAgent,e=/(?:MSIE.(\\d+\\.\\d+))|(?:(?:Firefox|GranParadiso|Iceweasel).(\\d+\\.\\d+))|(?:Opera(?:.+Version.|.)(\\d+\\.\\d+))|(?:AppleWebKit.(\\d+(?:\\.\\d+)?))|(?:Trident\\/\\d+\\.\\d+.*rv:(\\d+\\.\\d+))/.exec(t),g=/(Mac OS X)|(Windows)|(Linux)/.exec(t);if(d=/\\b(iPhone|iP[ao]d)/.exec(t),h=/\\b(iP[ao]d)/.exec(t),l=/Android/i.exec(t),v=/FBAN\\/\\w+;/i.exec(t),y=/Mobile/i.exec(t),p=!!/Win64/.exec(t),e){n=e[1]?parseFloat(e[1]):e[5]?parseFloat(e[5]):NaN,n&&document&&document.documentMode&&(n=document.documentMode);var b=/(?:Trident\\/(\\d+.\\d+))/.exec(t);s=b?parseFloat(b[1])+4:n,r=e[2]?parseFloat(e[2]):NaN,o=e[3]?parseFloat(e[3]):NaN,i=e[4]?parseFloat(e[4]):NaN,i?(e=/(?:Chrome\\/(\\d+\\.\\d+))/.exec(t),a=e&&e[1]?parseFloat(e[1]):NaN):a=NaN}else n=r=o=a=i=NaN;if(g){if(g[1]){var _=/(?:Mac OS X (\\d+(?:[._]\\d+)?))/.exec(t);c=!_||parseFloat(_[1].replace(\"_\",\".\"))}else c=!1;u=!!g[2],f=!!g[3]}else c=u=f=!1}}var b={ie:function(){return g()||n},ieCompatibilityMode:function(){return g()||s>n},ie64:function(){return b.ie()&&p},firefox:function(){return g()||r},opera:function(){return g()||o},webkit:function(){return g()||i},safari:function(){return b.webkit()},chrome:function(){return g()||a},windows:function(){return g()||u},osx:function(){return g()||c},linux:function(){return g()||f},iphone:function(){return g()||d},mobile:function(){return g()||d||h||l||y},nativeApp:function(){return g()||v},android:function(){return g()||l},ipad:function(){return g()||h}};t.exports=b},\"8f60\":function(t,e,n){\"use strict\";var r=n(\"a159\"),o=n(\"aebd\"),i=n(\"45f2\"),a={};n(\"35e8\")(a,n(\"5168\")(\"iterator\"),function(){return this}),t.exports=function(t,e,n){t.prototype=r(a,{next:o(1,n)}),i(t,e+\" Iterator\")}},9003:function(t,e,n){var r=n(\"6b4c\");t.exports=Array.isArray||function(t){return\"Array\"==r(t)}},9138:function(t,e,n){t.exports=n(\"35e8\")},\"92fa\":function(t,e){var n=/^(attrs|props|on|nativeOn|class|style|hook)$/;function r(t,e){return function(){t&&t.apply(this,arguments),e&&e.apply(this,arguments)}}t.exports=function(t){return t.reduce(function(t,e){var o,i,a,s,c;for(a in e)if(o=t[a],i=e[a],o&&n.test(a))if(\"class\"===a&&(\"string\"===typeof o&&(c=o,t[a]=o={},o[c]=!0),\"string\"===typeof i&&(c=i,e[a]=i={},i[c]=!0)),\"on\"===a||\"nativeOn\"===a||\"hook\"===a)for(s in i)o[s]=r(o[s],i[s]);else if(Array.isArray(o))t[a]=o.concat(i);else if(Array.isArray(i))t[a]=[o].concat(i);else for(s in i)o[s]=i[s];else t[a]=e[a];return t},{})}},9306:function(t,e,n){\"use strict\";var r=n(\"8e60\"),o=n(\"c3a1\"),i=n(\"9aa9\"),a=n(\"355d\"),s=n(\"241e\"),c=n(\"335c\"),u=Object.assign;t.exports=!u||n(\"294c\")(function(){var t={},e={},n=Symbol(),r=\"abcdefghijklmnopqrst\";return t[n]=7,r.split(\"\").forEach(function(t){e[t]=t}),7!=u({},t)[n]||Object.keys(u({},e)).join(\"\")!=r})?function(t,e){var n=s(t),u=arguments.length,f=1,l=i.f,p=a.f;while(u>f){var d,h=c(arguments[f++]),v=l?o(h).concat(l(h)):o(h),y=v.length,m=0;while(y>m)d=v[m++],r&&!p.call(h,d)||(n[d]=h[d])}return n}:u},\"96cf\":function(t,e){!function(e){\"use strict\";var n,r=Object.prototype,o=r.hasOwnProperty,i=\"function\"===typeof Symbol?Symbol:{},a=i.iterator||\"@@iterator\",s=i.asyncIterator||\"@@asyncIterator\",c=i.toStringTag||\"@@toStringTag\",u=\"object\"===typeof t,f=e.regeneratorRuntime;if(f)u&&(t.exports=f);else{f=e.regeneratorRuntime=u?t.exports:{},f.wrap=_;var l=\"suspendedStart\",p=\"suspendedYield\",d=\"executing\",h=\"completed\",v={},y={};y[a]=function(){return this};var m=Object.getPrototypeOf,g=m&&m(m(M([])));g&&g!==r&&o.call(g,a)&&(y=g);var b=E.prototype=x.prototype=Object.create(y);O.prototype=b.constructor=E,E.constructor=O,E[c]=O.displayName=\"GeneratorFunction\",f.isGeneratorFunction=function(t){var e=\"function\"===typeof t&&t.constructor;return!!e&&(e===O||\"GeneratorFunction\"===(e.displayName||e.name))},f.mark=function(t){return Object.setPrototypeOf?Object.setPrototypeOf(t,E):(t.__proto__=E,c in t||(t[c]=\"GeneratorFunction\")),t.prototype=Object.create(b),t},f.awrap=function(t){return{__await:t}},S(A.prototype),A.prototype[s]=function(){return this},f.AsyncIterator=A,f.async=function(t,e,n,r){var o=new A(_(t,e,n,r));return f.isGeneratorFunction(e)?o:o.next().then(function(t){return t.done?t.value:o.next()})},S(b),b[c]=\"Generator\",b[a]=function(){return this},b.toString=function(){return\"[object Generator]\"},f.keys=function(t){var e=[];for(var n in t)e.push(n);return e.reverse(),function n(){while(e.length){var r=e.pop();if(r in t)return n.value=r,n.done=!1,n}return n.done=!0,n}},f.values=M,$.prototype={constructor:$,reset:function(t){if(this.prev=0,this.next=0,this.sent=this._sent=n,this.done=!1,this.delegate=null,this.method=\"next\",this.arg=n,this.tryEntries.forEach(T),!t)for(var e in this)\"t\"===e.charAt(0)&&o.call(this,e)&&!isNaN(+e.slice(1))&&(this[e]=n)},stop:function(){this.done=!0;var t=this.tryEntries[0],e=t.completion;if(\"throw\"===e.type)throw e.arg;return this.rval},dispatchException:function(t){if(this.done)throw t;var e=this;function r(r,o){return s.type=\"throw\",s.arg=t,e.next=r,o&&(e.method=\"next\",e.arg=n),!!o}for(var i=this.tryEntries.length-1;i>=0;--i){var a=this.tryEntries[i],s=a.completion;if(\"root\"===a.tryLoc)return r(\"end\");if(a.tryLoc<=this.prev){var c=o.call(a,\"catchLoc\"),u=o.call(a,\"finallyLoc\");if(c&&u){if(this.prev<a.catchLoc)return r(a.catchLoc,!0);if(this.prev<a.finallyLoc)return r(a.finallyLoc)}else if(c){if(this.prev<a.catchLoc)return r(a.catchLoc,!0)}else{if(!u)throw new Error(\"try statement without catch or finally\");if(this.prev<a.finallyLoc)return r(a.finallyLoc)}}}},abrupt:function(t,e){for(var n=this.tryEntries.length-1;n>=0;--n){var r=this.tryEntries[n];if(r.tryLoc<=this.prev&&o.call(r,\"finallyLoc\")&&this.prev<r.finallyLoc){var i=r;break}}i&&(\"break\"===t||\"continue\"===t)&&i.tryLoc<=e&&e<=i.finallyLoc&&(i=null);var a=i?i.completion:{};return a.type=t,a.arg=e,i?(this.method=\"next\",this.next=i.finallyLoc,v):this.complete(a)},complete:function(t,e){if(\"throw\"===t.type)throw t.arg;return\"break\"===t.type||\"continue\"===t.type?this.next=t.arg:\"return\"===t.type?(this.rval=this.arg=t.arg,this.method=\"return\",this.next=\"end\"):\"normal\"===t.type&&e&&(this.next=e),v},finish:function(t){for(var e=this.tryEntries.length-1;e>=0;--e){var n=this.tryEntries[e];if(n.finallyLoc===t)return this.complete(n.completion,n.afterLoc),T(n),v}},catch:function(t){for(var e=this.tryEntries.length-1;e>=0;--e){var n=this.tryEntries[e];if(n.tryLoc===t){var r=n.completion;if(\"throw\"===r.type){var o=r.arg;T(n)}return o}}throw new Error(\"illegal catch attempt\")},delegateYield:function(t,e,r){return this.delegate={iterator:M(t),resultName:e,nextLoc:r},\"next\"===this.method&&(this.arg=n),v}}}function _(t,e,n,r){var o=e&&e.prototype instanceof x?e:x,i=Object.create(o.prototype),a=new $(r||[]);return i._invoke=C(t,n,a),i}function w(t,e,n){try{return{type:\"normal\",arg:t.call(e,n)}}catch(r){return{type:\"throw\",arg:r}}}function x(){}function O(){}function E(){}function S(t){[\"next\",\"throw\",\"return\"].forEach(function(e){t[e]=function(t){return this._invoke(e,t)}})}function A(t){function e(n,r,i,a){var s=w(t[n],t,r);if(\"throw\"!==s.type){var c=s.arg,u=c.value;return u&&\"object\"===typeof u&&o.call(u,\"__await\")?Promise.resolve(u.__await).then(function(t){e(\"next\",t,i,a)},function(t){e(\"throw\",t,i,a)}):Promise.resolve(u).then(function(t){c.value=t,i(c)},a)}a(s.arg)}var n;function r(t,r){function o(){return new Promise(function(n,o){e(t,r,n,o)})}return n=n?n.then(o,o):o()}this._invoke=r}function C(t,e,n){var r=l;return function(o,i){if(r===d)throw new Error(\"Generator is already running\");if(r===h){if(\"throw\"===o)throw i;return P()}n.method=o,n.arg=i;while(1){var a=n.delegate;if(a){var s=k(a,n);if(s){if(s===v)continue;return s}}if(\"next\"===n.method)n.sent=n._sent=n.arg;else if(\"throw\"===n.method){if(r===l)throw r=h,n.arg;n.dispatchException(n.arg)}else\"return\"===n.method&&n.abrupt(\"return\",n.arg);r=d;var c=w(t,e,n);if(\"normal\"===c.type){if(r=n.done?h:p,c.arg===v)continue;return{value:c.arg,done:n.done}}\"throw\"===c.type&&(r=h,n.method=\"throw\",n.arg=c.arg)}}}function k(t,e){var r=t.iterator[e.method];if(r===n){if(e.delegate=null,\"throw\"===e.method){if(t.iterator.return&&(e.method=\"return\",e.arg=n,k(t,e),\"throw\"===e.method))return v;e.method=\"throw\",e.arg=new TypeError(\"The iterator does not provide a 'throw' method\")}return v}var o=w(r,t.iterator,e.arg);if(\"throw\"===o.type)return e.method=\"throw\",e.arg=o.arg,e.delegate=null,v;var i=o.arg;return i?i.done?(e[t.resultName]=i.value,e.next=t.nextLoc,\"return\"!==e.method&&(e.method=\"next\",e.arg=n),e.delegate=null,v):i:(e.method=\"throw\",e.arg=new TypeError(\"iterator result is not an object\"),e.delegate=null,v)}function j(t){var e={tryLoc:t[0]};1 in t&&(e.catchLoc=t[1]),2 in t&&(e.finallyLoc=t[2],e.afterLoc=t[3]),this.tryEntries.push(e)}function T(t){var e=t.completion||{};e.type=\"normal\",delete e.arg,t.completion=e}function $(t){this.tryEntries=[{tryLoc:\"root\"}],t.forEach(j,this),this.reset(!0)}function M(t){if(t){var e=t[a];if(e)return e.call(t);if(\"function\"===typeof t.next)return t;if(!isNaN(t.length)){var r=-1,i=function e(){while(++r<t.length)if(o.call(t,r))return e.value=t[r],e.done=!1,e;return e.value=n,e.done=!0,e};return i.next=i}}return{next:P}}function P(){return{value:n,done:!0}}}(function(){return this}()||Function(\"return this\")())},\"9aa9\":function(t,e){e.f=Object.getOwnPropertySymbols},\"9b43\":function(t,e,n){var r=n(\"d8e8\");t.exports=function(t,e,n){if(r(t),void 0===e)return t;switch(n){case 1:return function(n){return t.call(e,n)};case 2:return function(n,r){return t.call(e,n,r)};case 3:return function(n,r,o){return t.call(e,n,r,o)}}return function(){return t.apply(e,arguments)}}},\"9c6c\":function(t,e,n){var r=n(\"2b4c\")(\"unscopables\"),o=Array.prototype;void 0==o[r]&&n(\"32e9\")(o,r,{}),t.exports=function(t){o[r][t]=!0}},\"9c80\":function(t,e){t.exports=function(t){try{return{e:!1,v:t()}}catch(e){return{e:!0,v:e}}}},\"9d98\":function(t,e,n){var r=n(\"63b6\");r(r.S+r.F*!n(\"8e60\"),\"Object\",{defineProperties:n(\"7e90\")})},\"9def\":function(t,e,n){var r=n(\"4588\"),o=Math.min;t.exports=function(t){return t>0?o(r(t),9007199254740991):0}},\"9e1e\":function(t,e,n){t.exports=!n(\"79e5\")(function(){return 7!=Object.defineProperty({},\"a\",{get:function(){return 7}}).a})},a159:function(t,e,n){var r=n(\"e4ae\"),o=n(\"7e90\"),i=n(\"1691\"),a=n(\"5559\")(\"IE_PROTO\"),s=function(){},c=\"prototype\",u=function(){var t,e=n(\"1ec9\")(\"iframe\"),r=i.length,o=\"<\",a=\">\";e.style.display=\"none\",n(\"32fc\").appendChild(e),e.src=\"javascript:\",t=e.contentWindow.document,t.open(),t.write(o+\"script\"+a+\"document.F=Object\"+o+\"/script\"+a),t.close(),u=t.F;while(r--)delete u[c][i[r]];return u()};t.exports=Object.create||function(t,e){var n;return null!==t?(s[c]=r(t),n=new s,s[c]=null,n[a]=t):n=u(),void 0===e?n:o(n,e)}},a15e:function(t,e,n){\"use strict\";n.r(e);var r=n(\"41b2\"),o=n.n(r),i=n(\"1098\"),a=n.n(i),s=/%[sdj%]/g,c=function(){};function u(){for(var t=arguments.length,e=Array(t),n=0;n<t;n++)e[n]=arguments[n];var r=1,o=e[0],i=e.length;if(\"function\"===typeof o)return o.apply(null,e.slice(1));if(\"string\"===typeof o){for(var a=String(o).replace(s,function(t){if(\"%%\"===t)return\"%\";if(r>=i)return t;switch(t){case\"%s\":return String(e[r++]);case\"%d\":return Number(e[r++]);case\"%j\":try{return JSON.stringify(e[r++])}catch(n){return\"[Circular]\"}break;default:return t}}),c=e[r];r<i;c=e[++r])a+=\" \"+c;return a}return o}function f(t){return\"string\"===t||\"url\"===t||\"hex\"===t||\"email\"===t||\"pattern\"===t}function l(t,e){return void 0===t||null===t||(!(\"array\"!==e||!Array.isArray(t)||t.length)||!(!f(e)||\"string\"!==typeof t||t))}function p(t,e,n){var r=[],o=0,i=t.length;function a(t){r.push.apply(r,t),o++,o===i&&n(r)}t.forEach(function(t){e(t,a)})}function d(t,e,n){var r=0,o=t.length;function i(a){if(a&&a.length)n(a);else{var s=r;r+=1,s<o?e(t[s],i):n([])}}i([])}function h(t){var e=[];return Object.keys(t).forEach(function(n){e.push.apply(e,t[n])}),e}function v(t,e,n,r){if(e.first){var o=h(t);return d(o,n,r)}var i=e.firstFields||[];!0===i&&(i=Object.keys(t));var a=Object.keys(t),s=a.length,c=0,u=[],f=function(t){u.push.apply(u,t),c++,c===s&&r(u)};a.forEach(function(e){var r=t[e];-1!==i.indexOf(e)?d(r,n,f):p(r,n,f)})}function y(t){return function(e){return e&&e.message?(e.field=e.field||t.fullField,e):{message:e,field:e.field||t.fullField}}}function m(t,e){if(e)for(var n in e)if(e.hasOwnProperty(n)){var r=e[n];\"object\"===(\"undefined\"===typeof r?\"undefined\":a()(r))&&\"object\"===a()(t[n])?t[n]=o()({},t[n],r):t[n]=r}return t}function g(t,e,n,r,o,i){!t.required||n.hasOwnProperty(t.field)&&!l(e,i||t.type)||r.push(u(o.messages.required,t.fullField))}var b=g;function _(t,e,n,r,o){(/^\\s+$/.test(e)||\"\"===e)&&r.push(u(o.messages.whitespace,t.fullField))}var w=_,x={email:/^(([^<>()\\[\\]\\\\.,;:\\s@\"]+(\\.[^<>()\\[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/,url:new RegExp(\"^(?!mailto:)(?:(?:http|https|ftp)://|//)(?:\\\\S+(?::\\\\S*)?@)?(?:(?:(?:[1-9]\\\\d?|1\\\\d\\\\d|2[01]\\\\d|22[0-3])(?:\\\\.(?:1?\\\\d{1,2}|2[0-4]\\\\d|25[0-5])){2}(?:\\\\.(?:[0-9]\\\\d?|1\\\\d\\\\d|2[0-4]\\\\d|25[0-4]))|(?:(?:[a-z\\\\u00a1-\\\\uffff0-9]+-?)*[a-z\\\\u00a1-\\\\uffff0-9]+)(?:\\\\.(?:[a-z\\\\u00a1-\\\\uffff0-9]+-?)*[a-z\\\\u00a1-\\\\uffff0-9]+)*(?:\\\\.(?:[a-z\\\\u00a1-\\\\uffff]{2,})))|localhost)(?::\\\\d{2,5})?(?:(/|\\\\?|#)[^\\\\s]*)?$\",\"i\"),hex:/^#?([a-f0-9]{6}|[a-f0-9]{3})$/i},O={integer:function(t){return O.number(t)&&parseInt(t,10)===t},float:function(t){return O.number(t)&&!O.integer(t)},array:function(t){return Array.isArray(t)},regexp:function(t){if(t instanceof RegExp)return!0;try{return!!new RegExp(t)}catch(e){return!1}},date:function(t){return\"function\"===typeof t.getTime&&\"function\"===typeof t.getMonth&&\"function\"===typeof t.getYear},number:function(t){return!isNaN(t)&&\"number\"===typeof t},object:function(t){return\"object\"===(\"undefined\"===typeof t?\"undefined\":a()(t))&&!O.array(t)},method:function(t){return\"function\"===typeof t},email:function(t){return\"string\"===typeof t&&!!t.match(x.email)&&t.length<255},url:function(t){return\"string\"===typeof t&&!!t.match(x.url)},hex:function(t){return\"string\"===typeof t&&!!t.match(x.hex)}};function E(t,e,n,r,o){if(t.required&&void 0===e)b(t,e,n,r,o);else{var i=[\"integer\",\"float\",\"array\",\"regexp\",\"object\",\"method\",\"email\",\"number\",\"date\",\"url\",\"hex\"],s=t.type;i.indexOf(s)>-1?O[s](e)||r.push(u(o.messages.types[s],t.fullField,t.type)):s&&(\"undefined\"===typeof e?\"undefined\":a()(e))!==t.type&&r.push(u(o.messages.types[s],t.fullField,t.type))}}var S=E;function A(t,e,n,r,o){var i=\"number\"===typeof t.len,a=\"number\"===typeof t.min,s=\"number\"===typeof t.max,c=/[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]/g,f=e,l=null,p=\"number\"===typeof e,d=\"string\"===typeof e,h=Array.isArray(e);if(p?l=\"number\":d?l=\"string\":h&&(l=\"array\"),!l)return!1;h&&(f=e.length),d&&(f=e.replace(c,\"_\").length),i?f!==t.len&&r.push(u(o.messages[l].len,t.fullField,t.len)):a&&!s&&f<t.min?r.push(u(o.messages[l].min,t.fullField,t.min)):s&&!a&&f>t.max?r.push(u(o.messages[l].max,t.fullField,t.max)):a&&s&&(f<t.min||f>t.max)&&r.push(u(o.messages[l].range,t.fullField,t.min,t.max))}var C=A,k=\"enum\";function j(t,e,n,r,o){t[k]=Array.isArray(t[k])?t[k]:[],-1===t[k].indexOf(e)&&r.push(u(o.messages[k],t.fullField,t[k].join(\", \")))}var T=j;function $(t,e,n,r,o){if(t.pattern)if(t.pattern instanceof RegExp)t.pattern.lastIndex=0,t.pattern.test(e)||r.push(u(o.messages.pattern.mismatch,t.fullField,e,t.pattern));else if(\"string\"===typeof t.pattern){var i=new RegExp(t.pattern);i.test(e)||r.push(u(o.messages.pattern.mismatch,t.fullField,e,t.pattern))}}var M=$,P={required:b,whitespace:w,type:S,range:C,enum:T,pattern:M};function L(t,e,n,r,o){var i=[],a=t.required||!t.required&&r.hasOwnProperty(t.field);if(a){if(l(e,\"string\")&&!t.required)return n();P.required(t,e,r,i,o,\"string\"),l(e,\"string\")||(P.type(t,e,r,i,o),P.range(t,e,r,i,o),P.pattern(t,e,r,i,o),!0===t.whitespace&&P.whitespace(t,e,r,i,o))}n(i)}var R=L;function N(t,e,n,r,o){var i=[],a=t.required||!t.required&&r.hasOwnProperty(t.field);if(a){if(l(e)&&!t.required)return n();P.required(t,e,r,i,o),void 0!==e&&P.type(t,e,r,i,o)}n(i)}var F=N;function I(t,e,n,r,o){var i=[],a=t.required||!t.required&&r.hasOwnProperty(t.field);if(a){if(l(e)&&!t.required)return n();P.required(t,e,r,i,o),void 0!==e&&(P.type(t,e,r,i,o),P.range(t,e,r,i,o))}n(i)}var D=I;function q(t,e,n,r,o){var i=[],a=t.required||!t.required&&r.hasOwnProperty(t.field);if(a){if(l(e)&&!t.required)return n();P.required(t,e,r,i,o),void 0!==e&&P.type(t,e,r,i,o)}n(i)}var U=q;function B(t,e,n,r,o){var i=[],a=t.required||!t.required&&r.hasOwnProperty(t.field);if(a){if(l(e)&&!t.required)return n();P.required(t,e,r,i,o),l(e)||P.type(t,e,r,i,o)}n(i)}var V=B;function H(t,e,n,r,o){var i=[],a=t.required||!t.required&&r.hasOwnProperty(t.field);if(a){if(l(e)&&!t.required)return n();P.required(t,e,r,i,o),void 0!==e&&(P.type(t,e,r,i,o),P.range(t,e,r,i,o))}n(i)}var z=H;function G(t,e,n,r,o){var i=[],a=t.required||!t.required&&r.hasOwnProperty(t.field);if(a){if(l(e)&&!t.required)return n();P.required(t,e,r,i,o),void 0!==e&&(P.type(t,e,r,i,o),P.range(t,e,r,i,o))}n(i)}var W=G;function K(t,e,n,r,o){var i=[],a=t.required||!t.required&&r.hasOwnProperty(t.field);if(a){if(l(e,\"array\")&&!t.required)return n();P.required(t,e,r,i,o,\"array\"),l(e,\"array\")||(P.type(t,e,r,i,o),P.range(t,e,r,i,o))}n(i)}var X=K;function J(t,e,n,r,o){var i=[],a=t.required||!t.required&&r.hasOwnProperty(t.field);if(a){if(l(e)&&!t.required)return n();P.required(t,e,r,i,o),void 0!==e&&P.type(t,e,r,i,o)}n(i)}var Y=J,Z=\"enum\";function Q(t,e,n,r,o){var i=[],a=t.required||!t.required&&r.hasOwnProperty(t.field);if(a){if(l(e)&&!t.required)return n();P.required(t,e,r,i,o),e&&P[Z](t,e,r,i,o)}n(i)}var tt=Q;function et(t,e,n,r,o){var i=[],a=t.required||!t.required&&r.hasOwnProperty(t.field);if(a){if(l(e,\"string\")&&!t.required)return n();P.required(t,e,r,i,o),l(e,\"string\")||P.pattern(t,e,r,i,o)}n(i)}var nt=et;function rt(t,e,n,r,o){var i=[],a=t.required||!t.required&&r.hasOwnProperty(t.field);if(a){if(l(e)&&!t.required)return n();if(P.required(t,e,r,i,o),!l(e)){var s=void 0;s=\"number\"===typeof e?new Date(e):e,P.type(t,s,r,i,o),s&&P.range(t,s.getTime(),r,i,o)}}n(i)}var ot=rt;function it(t,e,n,r,o){var i=[],s=Array.isArray(e)?\"array\":\"undefined\"===typeof e?\"undefined\":a()(e);P.required(t,e,r,i,o,s),n(i)}var at=it;function st(t,e,n,r,o){var i=t.type,a=[],s=t.required||!t.required&&r.hasOwnProperty(t.field);if(s){if(l(e,i)&&!t.required)return n();P.required(t,e,r,a,o,i),l(e,i)||P.type(t,e,r,a,o)}n(a)}var ct=st,ut={string:R,method:F,number:D,boolean:U,regexp:V,integer:z,float:W,array:X,object:Y,enum:tt,pattern:nt,date:ot,url:ct,hex:ct,email:ct,required:at};function ft(){return{default:\"Validation error on field %s\",required:\"%s is required\",enum:\"%s must be one of %s\",whitespace:\"%s cannot be empty\",date:{format:\"%s date %s is invalid for format %s\",parse:\"%s date could not be parsed, %s is invalid \",invalid:\"%s date %s is invalid\"},types:{string:\"%s is not a %s\",method:\"%s is not a %s (function)\",array:\"%s is not an %s\",object:\"%s is not an %s\",number:\"%s is not a %s\",date:\"%s is not a %s\",boolean:\"%s is not a %s\",integer:\"%s is not an %s\",float:\"%s is not a %s\",regexp:\"%s is not a valid %s\",email:\"%s is not a valid %s\",url:\"%s is not a valid %s\",hex:\"%s is not a valid %s\"},string:{len:\"%s must be exactly %s characters\",min:\"%s must be at least %s characters\",max:\"%s cannot be longer than %s characters\",range:\"%s must be between %s and %s characters\"},number:{len:\"%s must equal %s\",min:\"%s cannot be less than %s\",max:\"%s cannot be greater than %s\",range:\"%s must be between %s and %s\"},array:{len:\"%s must be exactly %s in length\",min:\"%s cannot be less than %s in length\",max:\"%s cannot be greater than %s in length\",range:\"%s must be between %s and %s in length\"},pattern:{mismatch:\"%s value %s does not match pattern %s\"},clone:function(){var t=JSON.parse(JSON.stringify(this));return t.clone=this.clone,t}}}var lt=ft();function pt(t){this.rules=null,this._messages=lt,this.define(t)}pt.prototype={messages:function(t){return t&&(this._messages=m(ft(),t)),this._messages},define:function(t){if(!t)throw new Error(\"Cannot configure a schema with no rules\");if(\"object\"!==(\"undefined\"===typeof t?\"undefined\":a()(t))||Array.isArray(t))throw new Error(\"Rules must be an object\");this.rules={};var e=void 0,n=void 0;for(e in t)t.hasOwnProperty(e)&&(n=t[e],this.rules[e]=Array.isArray(n)?n:[n])},validate:function(t){var e=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=arguments[2],i=t,s=n,f=r;if(\"function\"===typeof s&&(f=s,s={}),this.rules&&0!==Object.keys(this.rules).length){if(s.messages){var l=this.messages();l===lt&&(l=ft()),m(l,s.messages),s.messages=l}else s.messages=this.messages();var p=void 0,d=void 0,h={},g=s.keys||Object.keys(this.rules);g.forEach(function(n){p=e.rules[n],d=i[n],p.forEach(function(r){var a=r;\"function\"===typeof a.transform&&(i===t&&(i=o()({},i)),d=i[n]=a.transform(d)),a=\"function\"===typeof a?{validator:a}:o()({},a),a.validator=e.getValidationMethod(a),a.field=n,a.fullField=a.fullField||n,a.type=e.getType(a),a.validator&&(h[n]=h[n]||[],h[n].push({rule:a,value:d,source:i,field:n}))})});var b={};v(h,s,function(t,e){var n=t.rule,r=(\"object\"===n.type||\"array\"===n.type)&&(\"object\"===a()(n.fields)||\"object\"===a()(n.defaultField));function i(t,e){return o()({},e,{fullField:n.fullField+\".\"+t})}function f(){var a=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],f=a;if(Array.isArray(f)||(f=[f]),f.length&&c(\"async-validator:\",f),f.length&&n.message&&(f=[].concat(n.message)),f=f.map(y(n)),s.first&&f.length)return b[n.field]=1,e(f);if(r){if(n.required&&!t.value)return f=n.message?[].concat(n.message).map(y(n)):s.error?[s.error(n,u(s.messages.required,n.field))]:[],e(f);var l={};if(n.defaultField)for(var p in t.value)t.value.hasOwnProperty(p)&&(l[p]=n.defaultField);for(var d in l=o()({},l,t.rule.fields),l)if(l.hasOwnProperty(d)){var h=Array.isArray(l[d])?l[d]:[l[d]];l[d]=h.map(i.bind(null,d))}var v=new pt(l);v.messages(s.messages),t.rule.options&&(t.rule.options.messages=s.messages,t.rule.options.error=s.error),v.validate(t.value,t.rule.options||s,function(t){e(t&&t.length?f.concat(t):t)})}else e(f)}r=r&&(n.required||!n.required&&t.value),n.field=t.field;var l=n.validator(n,t.value,f,t.source,s);l&&l.then&&l.then(function(){return f()},function(t){return f(t)})},function(t){_(t)})}else f&&f();function _(t){var e=void 0,n=void 0,r=[],o={};function i(t){Array.isArray(t)?r=r.concat.apply(r,t):r.push(t)}for(e=0;e<t.length;e++)i(t[e]);if(r.length)for(e=0;e<r.length;e++)n=r[e].field,o[n]=o[n]||[],o[n].push(r[e]);else r=null,o=null;f(r,o)}},getType:function(t){if(void 0===t.type&&t.pattern instanceof RegExp&&(t.type=\"pattern\"),\"function\"!==typeof t.validator&&t.type&&!ut.hasOwnProperty(t.type))throw new Error(u(\"Unknown rule type %s\",t.type));return t.type||\"string\"},getValidationMethod:function(t){if(\"function\"===typeof t.validator)return t.validator;var e=Object.keys(t),n=e.indexOf(\"message\");return-1!==n&&e.splice(n,1),1===e.length&&\"required\"===e[0]?ut.required:ut[this.getType(t)]||!1}},pt.register=function(t,e){if(\"function\"!==typeof e)throw new Error(\"Cannot register a validator by type, validator is not a function\");ut[t]=e},pt.messages=lt;e[\"default\"]=pt},a22a:function(t,e,n){var r=n(\"d864\"),o=n(\"b0dc\"),i=n(\"3702\"),a=n(\"e4ae\"),s=n(\"b447\"),c=n(\"7cd6\"),u={},f={};e=t.exports=function(t,e,n,l,p){var d,h,v,y,m=p?function(){return t}:c(t),g=r(n,l,e?2:1),b=0;if(\"function\"!=typeof m)throw TypeError(t+\" is not iterable!\");if(i(m)){for(d=s(t.length);d>b;b++)if(y=e?g(a(h=t[b])[0],h[1]):g(t[b]),y===u||y===f)return y}else for(v=m.call(t);!(h=v.next()).done;)if(y=o(v,g,h.value,e),y===u||y===f)return y};e.BREAK=u,e.RETURN=f},a25f:function(t,e,n){var r=n(\"7726\"),o=r.navigator;t.exports=o&&o.userAgent||\"\"},a3c3:function(t,e,n){var r=n(\"63b6\");r(r.S+r.F,\"Object\",{assign:n(\"9306\")})},a3de:function(t,e,n){\"use strict\";var r=!(\"undefined\"===typeof window||!window.document||!window.document.createElement),o={canUseDOM:r,canUseWorkers:\"undefined\"!==typeof Worker,canUseEventListeners:r&&!(!window.addEventListener&&!window.attachEvent),canUseViewport:r&&!!window.screen,isInWorker:!r};t.exports=o},a4bb:function(t,e,n){t.exports=n(\"8aae\")},a5b8:function(t,e,n){\"use strict\";var r=n(\"d8e8\");function o(t){var e,n;this.promise=new t(function(t,r){if(void 0!==e||void 0!==n)throw TypeError(\"Bad Promise constructor\");e=t,n=r}),this.resolve=r(e),this.reject=r(n)}t.exports.f=function(t){return new o(t)}},a5d8:function(t,e,n){},a78e:function(t,e,n){var r,o;\n/*!\n * JavaScript Cookie v2.2.0\n * https://github.com/js-cookie/js-cookie\n *\n * Copyright 2006, 2015 Klaus Hartl & Fagner Brack\n * Released under the MIT license\n */(function(i){var a=!1;if(r=i,o=\"function\"===typeof r?r.call(e,n,e,t):r,void 0===o||(t.exports=o),a=!0,t.exports=i(),a=!0,!a){var s=window.Cookies,c=window.Cookies=i();c.noConflict=function(){return window.Cookies=s,c}}})(function(){function t(){for(var t=0,e={};t<arguments.length;t++){var n=arguments[t];for(var r in n)e[r]=n[r]}return e}function e(n){function r(e,o,i){var a;if(\"undefined\"!==typeof document){if(arguments.length>1){if(i=t({path:\"/\"},r.defaults,i),\"number\"===typeof i.expires){var s=new Date;s.setMilliseconds(s.getMilliseconds()+864e5*i.expires),i.expires=s}i.expires=i.expires?i.expires.toUTCString():\"\";try{a=JSON.stringify(o),/^[\\{\\[]/.test(a)&&(o=a)}catch(y){}o=n.write?n.write(o,e):encodeURIComponent(String(o)).replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g,decodeURIComponent),e=encodeURIComponent(String(e)),e=e.replace(/%(23|24|26|2B|5E|60|7C)/g,decodeURIComponent),e=e.replace(/[\\(\\)]/g,escape);var c=\"\";for(var u in i)i[u]&&(c+=\"; \"+u,!0!==i[u]&&(c+=\"=\"+i[u]));return document.cookie=e+\"=\"+o+c}e||(a={});for(var f=document.cookie?document.cookie.split(\"; \"):[],l=/(%[0-9A-Z]{2})+/g,p=0;p<f.length;p++){var d=f[p].split(\"=\"),h=d.slice(1).join(\"=\");this.json||'\"'!==h.charAt(0)||(h=h.slice(1,-1));try{var v=d[0].replace(l,decodeURIComponent);if(h=n.read?n.read(h,v):n(h,v)||h.replace(l,decodeURIComponent),this.json)try{h=JSON.parse(h)}catch(y){}if(e===v){a=h;break}e||(a[v]=h)}catch(y){}}return a}}return r.set=r,r.get=function(t){return r.call(r,t)},r.getJSON=function(){return r.apply({json:!0},[].slice.call(arguments))},r.defaults={},r.remove=function(e,n){r(e,\"\",t(n,{expires:-1}))},r.withConverter=e,r}return e(function(){})})},aba2:function(t,e,n){var r=n(\"e53d\"),o=n(\"4178\").set,i=r.MutationObserver||r.WebKitMutationObserver,a=r.process,s=r.Promise,c=\"process\"==n(\"6b4c\")(a);t.exports=function(){var t,e,n,u=function(){var r,o;c&&(r=a.domain)&&r.exit();while(t){o=t.fn,t=t.next;try{o()}catch(i){throw t?n():e=void 0,i}}e=void 0,r&&r.enter()};if(c)n=function(){a.nextTick(u)};else if(!i||r.navigator&&r.navigator.standalone)if(s&&s.resolve){var f=s.resolve(void 0);n=function(){f.then(u)}}else n=function(){o.call(r,u)};else{var l=!0,p=document.createTextNode(\"\");new i(u).observe(p,{characterData:!0}),n=function(){p.data=l=!l}}return function(r){var o={fn:r,next:void 0};e&&(e.next=o),t||(t=o,n()),e=o}}},ac6a:function(t,e,n){for(var r=n(\"cadf\"),o=n(\"0d58\"),i=n(\"2aba\"),a=n(\"7726\"),s=n(\"32e9\"),c=n(\"84f2\"),u=n(\"2b4c\"),f=u(\"iterator\"),l=u(\"toStringTag\"),p=c.Array,d={CSSRuleList:!0,CSSStyleDeclaration:!1,CSSValueList:!1,ClientRectList:!1,DOMRectList:!1,DOMStringList:!1,DOMTokenList:!0,DataTransferItemList:!1,FileList:!1,HTMLAllCollection:!1,HTMLCollection:!1,HTMLFormElement:!1,HTMLSelectElement:!1,MediaList:!0,MimeTypeArray:!1,NamedNodeMap:!1,NodeList:!0,PaintRequestList:!1,Plugin:!1,PluginArray:!1,SVGLengthList:!1,SVGNumberList:!1,SVGPathSegList:!1,SVGPointList:!1,SVGStringList:!1,SVGTransformList:!1,SourceBufferList:!1,StyleSheetList:!0,TextTrackCueList:!1,TextTrackList:!1,TouchList:!1},h=o(d),v=0;v<h.length;v++){var y,m=h[v],g=d[m],b=a[m],_=b&&b.prototype;if(_&&(_[f]||s(_,f,p),_[l]||s(_,l,m),c[m]=p,g))for(y in r)_[y]||i(_,y,r[y],!0)}},aebd:function(t,e){t.exports=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}}},b0dc:function(t,e,n){var r=n(\"e4ae\");t.exports=function(t,e,n,o){try{return o?e(r(n)[0],n[1]):e(n)}catch(a){var i=t[\"return\"];throw void 0!==i&&r(i.call(t)),a}}},b447:function(t,e,n){var r=n(\"3a38\"),o=Math.min;t.exports=function(t){return t>0?o(r(t),9007199254740991):0}},b50d:function(t,e,n){\"use strict\";var r=n(\"c532\"),o=n(\"467f\"),i=n(\"30b5\"),a=n(\"c345\"),s=n(\"3934\"),c=n(\"2d83\");t.exports=function(t){return new Promise(function(e,u){var f=t.data,l=t.headers;r.isFormData(f)&&delete l[\"Content-Type\"];var p=new XMLHttpRequest;if(t.auth){var d=t.auth.username||\"\",h=t.auth.password||\"\";l.Authorization=\"Basic \"+btoa(d+\":\"+h)}if(p.open(t.method.toUpperCase(),i(t.url,t.params,t.paramsSerializer),!0),p.timeout=t.timeout,p.onreadystatechange=function(){if(p&&4===p.readyState&&(0!==p.status||p.responseURL&&0===p.responseURL.indexOf(\"file:\"))){var n=\"getAllResponseHeaders\"in p?a(p.getAllResponseHeaders()):null,r=t.responseType&&\"text\"!==t.responseType?p.response:p.responseText,i={data:r,status:p.status,statusText:p.statusText,headers:n,config:t,request:p};o(e,u,i),p=null}},p.onerror=function(){u(c(\"Network Error\",t,null,p)),p=null},p.ontimeout=function(){u(c(\"timeout of \"+t.timeout+\"ms exceeded\",t,\"ECONNABORTED\",p)),p=null},r.isStandardBrowserEnv()){var v=n(\"7aac\"),y=(t.withCredentials||s(t.url))&&t.xsrfCookieName?v.read(t.xsrfCookieName):void 0;y&&(l[t.xsrfHeaderName]=y)}if(\"setRequestHeader\"in p&&r.forEach(l,function(t,e){\"undefined\"===typeof f&&\"content-type\"===e.toLowerCase()?delete l[e]:p.setRequestHeader(e,t)}),t.withCredentials&&(p.withCredentials=!0),t.responseType)try{p.responseType=t.responseType}catch(m){if(\"json\"!==t.responseType)throw m}\"function\"===typeof t.onDownloadProgress&&p.addEventListener(\"progress\",t.onDownloadProgress),\"function\"===typeof t.onUploadProgress&&p.upload&&p.upload.addEventListener(\"progress\",t.onUploadProgress),t.cancelToken&&t.cancelToken.promise.then(function(t){p&&(p.abort(),u(t),p=null)}),void 0===f&&(f=null),p.send(f)})}},b8e3:function(t,e){t.exports=!0},ba99:function(t,e,n){var r=n(\"6abf\"),o=n(\"9aa9\"),i=n(\"e4ae\"),a=n(\"e53d\").Reflect;t.exports=a&&a.ownKeys||function(t){var e=r.f(i(t)),n=o.f;return n?e.concat(n(t)):e}},bc13:function(t,e,n){var r=n(\"e53d\"),o=r.navigator;t.exports=o&&o.userAgent||\"\"},bc3a:function(t,e,n){t.exports=n(\"cee4\")},bcaa:function(t,e,n){var r=n(\"cb7c\"),o=n(\"d3f4\"),i=n(\"a5b8\");t.exports=function(t,e){if(r(t),o(e)&&e.constructor===t)return e;var n=i.f(t),a=n.resolve;return a(e),n.promise}},bd11:function(t,e){t.exports=v,t.exports.parse=i,t.exports.compile=a,t.exports.tokensToFunction=s,t.exports.tokensToRegExp=h;var n=\"/\",r=\"./\",o=new RegExp([\"(\\\\\\\\.)\",\"(?:\\\\:(\\\\w+)(?:\\\\(((?:\\\\\\\\.|[^\\\\\\\\()])+)\\\\))?|\\\\(((?:\\\\\\\\.|[^\\\\\\\\()])+)\\\\))([+*?])?\"].join(\"|\"),\"g\");function i(t,e){var i,a=[],s=0,f=0,l=\"\",p=e&&e.delimiter||n,d=e&&e.delimiters||r,h=!1;while(null!==(i=o.exec(t))){var v=i[0],y=i[1],m=i.index;if(l+=t.slice(f,m),f=m+v.length,y)l+=y[1],h=!0;else{var g=\"\",b=t[f],_=i[2],w=i[3],x=i[4],O=i[5];if(!h&&l.length){var E=l.length-1;d.indexOf(l[E])>-1&&(g=l[E],l=l.slice(0,E))}l&&(a.push(l),l=\"\",h=!1);var S=\"\"!==g&&void 0!==b&&b!==g,A=\"+\"===O||\"*\"===O,C=\"?\"===O||\"*\"===O,k=g||p,j=w||x;a.push({name:_||s++,prefix:g,delimiter:k,optional:C,repeat:A,partial:S,pattern:j?u(j):\"[^\"+c(k)+\"]+?\"})}}return(l||f<t.length)&&a.push(l+t.substr(f)),a}function a(t,e){return s(i(t,e))}function s(t){for(var e=new Array(t.length),n=0;n<t.length;n++)\"object\"===typeof t[n]&&(e[n]=new RegExp(\"^(?:\"+t[n].pattern+\")$\"));return function(n,r){for(var o=\"\",i=r&&r.encode||encodeURIComponent,a=0;a<t.length;a++){var s=t[a];if(\"string\"!==typeof s){var c,u=n?n[s.name]:void 0;if(Array.isArray(u)){if(!s.repeat)throw new TypeError('Expected \"'+s.name+'\" to not repeat, but got array');if(0===u.length){if(s.optional)continue;throw new TypeError('Expected \"'+s.name+'\" to not be empty')}for(var f=0;f<u.length;f++){if(c=i(u[f],s),!e[a].test(c))throw new TypeError('Expected all \"'+s.name+'\" to match \"'+s.pattern+'\"');o+=(0===f?s.prefix:s.delimiter)+c}}else if(\"string\"!==typeof u&&\"number\"!==typeof u&&\"boolean\"!==typeof u){if(!s.optional)throw new TypeError('Expected \"'+s.name+'\" to be '+(s.repeat?\"an array\":\"a string\"));s.partial&&(o+=s.prefix)}else{if(c=i(String(u),s),!e[a].test(c))throw new TypeError('Expected \"'+s.name+'\" to match \"'+s.pattern+'\", but got \"'+c+'\"');o+=s.prefix+c}}else o+=s}return o}}function c(t){return t.replace(/([.+*?=^!:${}()[\\]|\\/\\\\])/g,\"\\\\$1\")}function u(t){return t.replace(/([=!:$\\/()])/g,\"\\\\$1\")}function f(t){return t&&t.sensitive?\"\":\"i\"}function l(t,e){if(!e)return t;var n=t.source.match(/\\((?!\\?)/g);if(n)for(var r=0;r<n.length;r++)e.push({name:r,prefix:null,delimiter:null,optional:!1,repeat:!1,partial:!1,pattern:null});return t}function p(t,e,n){for(var r=[],o=0;o<t.length;o++)r.push(v(t[o],e,n).source);return new RegExp(\"(?:\"+r.join(\"|\")+\")\",f(n))}function d(t,e,n){return h(i(t,n),e,n)}function h(t,e,o){o=o||{};for(var i=o.strict,a=!1!==o.start,s=!1!==o.end,u=c(o.delimiter||n),l=o.delimiters||r,p=[].concat(o.endsWith||[]).map(c).concat(\"$\").join(\"|\"),d=a?\"^\":\"\",h=0===t.length,v=0;v<t.length;v++){var y=t[v];if(\"string\"===typeof y)d+=c(y),h=v===t.length-1&&l.indexOf(y[y.length-1])>-1;else{var m=y.repeat?\"(?:\"+y.pattern+\")(?:\"+c(y.delimiter)+\"(?:\"+y.pattern+\"))*\":y.pattern;e&&e.push(y),y.optional?y.partial?d+=c(y.prefix)+\"(\"+m+\")?\":d+=\"(?:\"+c(y.prefix)+\"(\"+m+\"))?\":d+=c(y.prefix)+\"(\"+m+\")\"}}return s?(i||(d+=\"(?:\"+u+\")?\"),d+=\"$\"===p?\"$\":\"(?=\"+p+\")\"):(i||(d+=\"(?:\"+u+\"(?=\"+p+\"))?\"),h||(d+=\"(?=\"+u+\"|\"+p+\")\")),new RegExp(d,f(o))}function v(t,e,n){return t instanceof RegExp?l(t,e):Array.isArray(t)?p(t,e,n):d(t,e,n)}},be13:function(t,e){t.exports=function(t){if(void 0==t)throw TypeError(\"Can't call method on  \"+t);return t}},bf0b:function(t,e,n){var r=n(\"355d\"),o=n(\"aebd\"),i=n(\"36c3\"),a=n(\"1bc3\"),s=n(\"07e3\"),c=n(\"794b\"),u=Object.getOwnPropertyDescriptor;e.f=n(\"8e60\")?u:function(t,e){if(t=i(t),e=a(e,!0),c)try{return u(t,e)}catch(n){}if(s(t,e))return o(!r.f.call(t,e),t[e])}},bf90:function(t,e,n){var r=n(\"36c3\"),o=n(\"bf0b\").f;n(\"ce7e\")(\"getOwnPropertyDescriptor\",function(){return function(t,e){return o(r(t),e)}})},c098:function(t,e,n){t.exports=n(\"d4af\")},c207:function(t,e){},c345:function(t,e,n){\"use strict\";var r=n(\"c532\"),o=[\"age\",\"authorization\",\"content-length\",\"content-type\",\"etag\",\"expires\",\"from\",\"host\",\"if-modified-since\",\"if-unmodified-since\",\"last-modified\",\"location\",\"max-forwards\",\"proxy-authorization\",\"referer\",\"retry-after\",\"user-agent\"];t.exports=function(t){var e,n,i,a={};return t?(r.forEach(t.split(\"\\n\"),function(t){if(i=t.indexOf(\":\"),e=r.trim(t.substr(0,i)).toLowerCase(),n=r.trim(t.substr(i+1)),e){if(a[e]&&o.indexOf(e)>=0)return;a[e]=\"set-cookie\"===e?(a[e]?a[e]:[]).concat([n]):a[e]?a[e]+\", \"+n:n}}),a):a}},c366:function(t,e,n){var r=n(\"6821\"),o=n(\"9def\"),i=n(\"77f1\");t.exports=function(t){return function(e,n,a){var s,c=r(e),u=o(c.length),f=i(a,u);if(t&&n!=n){while(u>f)if(s=c[f++],s!=s)return!0}else for(;u>f;f++)if((t||f in c)&&c[f]===n)return t||f||0;return!t&&-1}}},c367:function(t,e,n){\"use strict\";var r=n(\"8436\"),o=n(\"50ed\"),i=n(\"481b\"),a=n(\"36c3\");t.exports=n(\"30f1\")(Array,\"Array\",function(t,e){this._t=a(t),this._i=0,this._k=e},function(){var t=this._t,e=this._k,n=this._i++;return!t||n>=t.length?(this._t=void 0,o(1)):o(0,\"keys\"==e?n:\"values\"==e?t[n]:[n,t[n]])},\"values\"),i.Arguments=i.Array,r(\"keys\"),r(\"values\"),r(\"entries\")},c3a1:function(t,e,n){var r=n(\"e6f3\"),o=n(\"1691\");t.exports=Object.keys||function(t){return r(t,o)}},c401:function(t,e,n){\"use strict\";var r=n(\"c532\");t.exports=function(t,e,n){return r.forEach(n,function(n){t=n(t,e)}),t}},c532:function(t,e,n){\"use strict\";var r=n(\"1d2b\"),o=n(\"044b\"),i=Object.prototype.toString;function a(t){return\"[object Array]\"===i.call(t)}function s(t){return\"[object ArrayBuffer]\"===i.call(t)}function c(t){return\"undefined\"!==typeof FormData&&t instanceof FormData}function u(t){var e;return e=\"undefined\"!==typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(t):t&&t.buffer&&t.buffer instanceof ArrayBuffer,e}function f(t){return\"string\"===typeof t}function l(t){return\"number\"===typeof t}function p(t){return\"undefined\"===typeof t}function d(t){return null!==t&&\"object\"===typeof t}function h(t){return\"[object Date]\"===i.call(t)}function v(t){return\"[object File]\"===i.call(t)}function y(t){return\"[object Blob]\"===i.call(t)}function m(t){return\"[object Function]\"===i.call(t)}function g(t){return d(t)&&m(t.pipe)}function b(t){return\"undefined\"!==typeof URLSearchParams&&t instanceof URLSearchParams}function _(t){return t.replace(/^\\s*/,\"\").replace(/\\s*$/,\"\")}function w(){return(\"undefined\"===typeof navigator||\"ReactNative\"!==navigator.product)&&(\"undefined\"!==typeof window&&\"undefined\"!==typeof document)}function x(t,e){if(null!==t&&\"undefined\"!==typeof t)if(\"object\"!==typeof t&&(t=[t]),a(t))for(var n=0,r=t.length;n<r;n++)e.call(null,t[n],n,t);else for(var o in t)Object.prototype.hasOwnProperty.call(t,o)&&e.call(null,t[o],o,t)}function O(){var t={};function e(e,n){\"object\"===typeof t[n]&&\"object\"===typeof e?t[n]=O(t[n],e):t[n]=e}for(var n=0,r=arguments.length;n<r;n++)x(arguments[n],e);return t}function E(t,e,n){return x(e,function(e,o){t[o]=n&&\"function\"===typeof e?r(e,n):e}),t}t.exports={isArray:a,isArrayBuffer:s,isBuffer:o,isFormData:c,isArrayBufferView:u,isString:f,isNumber:l,isObject:d,isUndefined:p,isDate:h,isFile:v,isBlob:y,isFunction:m,isStream:g,isURLSearchParams:b,isStandardBrowserEnv:w,forEach:x,merge:O,extend:E,trim:_}},c69a:function(t,e,n){t.exports=!n(\"9e1e\")&&!n(\"79e5\")(function(){return 7!=Object.defineProperty(n(\"230e\")(\"div\"),\"a\",{get:function(){return 7}}).a})},c8af:function(t,e,n){\"use strict\";var r=n(\"c532\");t.exports=function(t,e){r.forEach(t,function(n,r){r!==e&&r.toUpperCase()===e.toUpperCase()&&(t[e]=n,delete t[r])})}},c8ba:function(t,e){var n;n=function(){return this}();try{n=n||new Function(\"return this\")()}catch(r){\"object\"===typeof window&&(n=window)}t.exports=n},ca5a:function(t,e){var n=0,r=Math.random();t.exports=function(t){return\"Symbol(\".concat(void 0===t?\"\":t,\")_\",(++n+r).toString(36))}},cadf:function(t,e,n){\"use strict\";var r=n(\"9c6c\"),o=n(\"d53b\"),i=n(\"84f2\"),a=n(\"6821\");t.exports=n(\"01f9\")(Array,\"Array\",function(t,e){this._t=a(t),this._i=0,this._k=e},function(){var t=this._t,e=this._k,n=this._i++;return!t||n>=t.length?(this._t=void 0,o(1)):o(0,\"keys\"==e?n:\"values\"==e?t[n]:[n,t[n]])},\"values\"),i.Arguments=i.Array,r(\"keys\"),r(\"values\"),r(\"entries\")},cb7c:function(t,e,n){var r=n(\"d3f4\");t.exports=function(t){if(!r(t))throw TypeError(t+\" is not an object!\");return t}},ccb9:function(t,e,n){e.f=n(\"5168\")},cd78:function(t,e,n){var r=n(\"e4ae\"),o=n(\"f772\"),i=n(\"656e\");t.exports=function(t,e){if(r(t),o(e)&&e.constructor===t)return e;var n=i.f(t),a=n.resolve;return a(e),n.promise}},ce10:function(t,e,n){var r=n(\"69a8\"),o=n(\"6821\"),i=n(\"c366\")(!1),a=n(\"613b\")(\"IE_PROTO\");t.exports=function(t,e){var n,s=o(t),c=0,u=[];for(n in s)n!=a&&r(s,n)&&u.push(n);while(e.length>c)r(s,n=e[c++])&&(~i(u,n)||u.push(n));return u}},ce7e:function(t,e,n){var r=n(\"63b6\"),o=n(\"584a\"),i=n(\"294c\");t.exports=function(t,e){var n=(o.Object||{})[t]||Object[t],a={};a[t]=e(n),r(r.S+r.F*i(function(){n(1)}),\"Object\",a)}},cee4:function(t,e,n){\"use strict\";var r=n(\"c532\"),o=n(\"1d2b\"),i=n(\"0a06\"),a=n(\"2444\");function s(t){var e=new i(t),n=o(i.prototype.request,e);return r.extend(n,i.prototype,e),r.extend(n,e),n}var c=s(a);c.Axios=i,c.create=function(t){return s(r.merge(a,t))},c.Cancel=n(\"7a77\"),c.CancelToken=n(\"8df4\"),c.isCancel=n(\"2e67\"),c.all=function(t){return Promise.all(t)},c.spread=n(\"0df6\"),t.exports=c,t.exports.default=c},d3f4:function(t,e){t.exports=function(t){return\"object\"===typeof t?null!==t:\"function\"===typeof t}},d4af:function(t,e,n){\"use strict\";var r=n(\"8eb7\"),o=n(\"7b3e\"),i=10,a=40,s=800;function c(t){var e=0,n=0,r=0,o=0;return\"detail\"in t&&(n=t.detail),\"wheelDelta\"in t&&(n=-t.wheelDelta/120),\"wheelDeltaY\"in t&&(n=-t.wheelDeltaY/120),\"wheelDeltaX\"in t&&(e=-t.wheelDeltaX/120),\"axis\"in t&&t.axis===t.HORIZONTAL_AXIS&&(e=n,n=0),r=e*i,o=n*i,\"deltaY\"in t&&(o=t.deltaY),\"deltaX\"in t&&(r=t.deltaX),(r||o)&&t.deltaMode&&(1==t.deltaMode?(r*=a,o*=a):(r*=s,o*=s)),r&&!e&&(e=r<1?-1:1),o&&!n&&(n=o<1?-1:1),{spinX:e,spinY:n,pixelX:r,pixelY:o}}c.getEventType=function(){return r.firefox()?\"DOMMouseScroll\":o(\"wheel\")?\"wheel\":\"mousewheel\"},t.exports=c},d53b:function(t,e){t.exports=function(t,e){return{value:e,done:!!t}}},d847:function(t,e,n){t.exports=n(\"5bba\")},d864:function(t,e,n){var r=n(\"79aa\");t.exports=function(t,e,n){if(r(t),void 0===e)return t;switch(n){case 1:return function(n){return t.call(e,n)};case 2:return function(n,r){return t.call(e,n,r)};case 3:return function(n,r,o){return t.call(e,n,r,o)}}return function(){return t.apply(e,arguments)}}},d8d6:function(t,e,n){n(\"1654\"),n(\"6c1c\"),t.exports=n(\"ccb9\").f(\"iterator\")},d8e8:function(t,e){t.exports=function(t){if(\"function\"!=typeof t)throw TypeError(t+\" is not a function!\");return t}},d925:function(t,e,n){\"use strict\";t.exports=function(t){return/^([a-z][a-z\\d\\+\\-\\.]*:)?\\/\\//i.test(t)}},d9f6:function(t,e,n){var r=n(\"e4ae\"),o=n(\"794b\"),i=n(\"1bc3\"),a=Object.defineProperty;e.f=n(\"8e60\")?Object.defineProperty:function(t,e,n){if(r(t),e=i(e,!0),r(n),o)try{return a(t,e,n)}catch(s){}if(\"get\"in n||\"set\"in n)throw TypeError(\"Accessors not supported!\");return\"value\"in n&&(t[e]=n.value),t}},db72:function(t,e,n){\"use strict\";var r=n(\"85f2\"),o=n.n(r),i=n(\"d847\"),a=n.n(i),s=n(\"5e83\"),c=n.n(s),u=n(\"268f\"),f=n.n(u),l=n(\"e265\"),p=n.n(l),d=n(\"a4bb\"),h=n.n(d);function v(t,e,n){return e in t?o()(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function y(t,e){var n=h()(t);return p.a&&n.push.apply(n,p()(t)),e&&(n=n.filter(function(e){return f()(t,e).enumerable})),n}function m(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{};e%2?y(n,!0).forEach(function(e){v(t,e,n[e])}):c.a?a()(t,c()(n)):y(n).forEach(function(e){o()(t,e,f()(n,e))})}return t}n.d(e,\"a\",function(){return m})},dbdb:function(t,e,n){var r=n(\"584a\"),o=n(\"e53d\"),i=\"__core-js_shared__\",a=o[i]||(o[i]={});(t.exports=function(t,e){return a[t]||(a[t]=void 0!==e?e:{})})(\"versions\",[]).push({version:r.version,mode:n(\"b8e3\")?\"pure\":\"global\",copyright:\"© 2019 Denis Pushkarev (zloirock.ru)\"})},dcbc:function(t,e,n){var r=n(\"2aba\");t.exports=function(t,e,n){for(var o in e)r(t,o,e[o],n);return t}},df7c:function(t,e,n){(function(t){function n(t,e){for(var n=0,r=t.length-1;r>=0;r--){var o=t[r];\".\"===o?t.splice(r,1):\"..\"===o?(t.splice(r,1),n++):n&&(t.splice(r,1),n--)}if(e)for(;n--;n)t.unshift(\"..\");return t}function r(t){\"string\"!==typeof t&&(t+=\"\");var e,n=0,r=-1,o=!0;for(e=t.length-1;e>=0;--e)if(47===t.charCodeAt(e)){if(!o){n=e+1;break}}else-1===r&&(o=!1,r=e+1);return-1===r?\"\":t.slice(n,r)}function o(t,e){if(t.filter)return t.filter(e);for(var n=[],r=0;r<t.length;r++)e(t[r],r,t)&&n.push(t[r]);return n}e.resolve=function(){for(var e=\"\",r=!1,i=arguments.length-1;i>=-1&&!r;i--){var a=i>=0?arguments[i]:t.cwd();if(\"string\"!==typeof a)throw new TypeError(\"Arguments to path.resolve must be strings\");a&&(e=a+\"/\"+e,r=\"/\"===a.charAt(0))}return e=n(o(e.split(\"/\"),function(t){return!!t}),!r).join(\"/\"),(r?\"/\":\"\")+e||\".\"},e.normalize=function(t){var r=e.isAbsolute(t),a=\"/\"===i(t,-1);return t=n(o(t.split(\"/\"),function(t){return!!t}),!r).join(\"/\"),t||r||(t=\".\"),t&&a&&(t+=\"/\"),(r?\"/\":\"\")+t},e.isAbsolute=function(t){return\"/\"===t.charAt(0)},e.join=function(){var t=Array.prototype.slice.call(arguments,0);return e.normalize(o(t,function(t,e){if(\"string\"!==typeof t)throw new TypeError(\"Arguments to path.join must be strings\");return t}).join(\"/\"))},e.relative=function(t,n){function r(t){for(var e=0;e<t.length;e++)if(\"\"!==t[e])break;for(var n=t.length-1;n>=0;n--)if(\"\"!==t[n])break;return e>n?[]:t.slice(e,n-e+1)}t=e.resolve(t).substr(1),n=e.resolve(n).substr(1);for(var o=r(t.split(\"/\")),i=r(n.split(\"/\")),a=Math.min(o.length,i.length),s=a,c=0;c<a;c++)if(o[c]!==i[c]){s=c;break}var u=[];for(c=s;c<o.length;c++)u.push(\"..\");return u=u.concat(i.slice(s)),u.join(\"/\")},e.sep=\"/\",e.delimiter=\":\",e.dirname=function(t){if(\"string\"!==typeof t&&(t+=\"\"),0===t.length)return\".\";for(var e=t.charCodeAt(0),n=47===e,r=-1,o=!0,i=t.length-1;i>=1;--i)if(e=t.charCodeAt(i),47===e){if(!o){r=i;break}}else o=!1;return-1===r?n?\"/\":\".\":n&&1===r?\"/\":t.slice(0,r)},e.basename=function(t,e){var n=r(t);return e&&n.substr(-1*e.length)===e&&(n=n.substr(0,n.length-e.length)),n},e.extname=function(t){\"string\"!==typeof t&&(t+=\"\");for(var e=-1,n=0,r=-1,o=!0,i=0,a=t.length-1;a>=0;--a){var s=t.charCodeAt(a);if(47!==s)-1===r&&(o=!1,r=a+1),46===s?-1===e?e=a:1!==i&&(i=1):-1!==e&&(i=-1);else if(!o){n=a+1;break}}return-1===e||-1===r||0===i||1===i&&e===r-1&&e===n+1?\"\":t.slice(e,r)};var i=\"b\"===\"ab\".substr(-1)?function(t,e,n){return t.substr(e,n)}:function(t,e,n){return e<0&&(e=t.length+e),t.substr(e,n)}}).call(this,n(\"4362\"))},e017:function(t,e,n){(function(e){(function(e,n){t.exports=n()})(0,function(){\"use strict\";var t=function(t){var e=t.id,n=t.viewBox,r=t.content;this.id=e,this.viewBox=n,this.content=r};t.prototype.stringify=function(){return this.content},t.prototype.toString=function(){return this.stringify()},t.prototype.destroy=function(){var t=this;[\"id\",\"viewBox\",\"content\"].forEach(function(e){return delete t[e]})};var n=function(t){var e=!!document.importNode,n=(new DOMParser).parseFromString(t,\"image/svg+xml\").documentElement;return e?document.importNode(n,!0):n};\"undefined\"!==typeof window?window:\"undefined\"!==typeof e||\"undefined\"!==typeof self&&self;function r(t,e){return e={exports:{}},t(e,e.exports),e.exports}var o=r(function(t,e){(function(e,n){t.exports=n()})(0,function(){function t(t){var e=t&&\"object\"===typeof t;return e&&\"[object RegExp]\"!==Object.prototype.toString.call(t)&&\"[object Date]\"!==Object.prototype.toString.call(t)}function e(t){return Array.isArray(t)?[]:{}}function n(n,r){var o=r&&!0===r.clone;return o&&t(n)?i(e(n),n,r):n}function r(e,r,o){var a=e.slice();return r.forEach(function(r,s){\"undefined\"===typeof a[s]?a[s]=n(r,o):t(r)?a[s]=i(e[s],r,o):-1===e.indexOf(r)&&a.push(n(r,o))}),a}function o(e,r,o){var a={};return t(e)&&Object.keys(e).forEach(function(t){a[t]=n(e[t],o)}),Object.keys(r).forEach(function(s){t(r[s])&&e[s]?a[s]=i(e[s],r[s],o):a[s]=n(r[s],o)}),a}function i(t,e,i){var a=Array.isArray(e),s=i||{arrayMerge:r},c=s.arrayMerge||r;return a?Array.isArray(t)?c(t,e,i):n(e,i):o(t,e,i)}return i.all=function(t,e){if(!Array.isArray(t)||t.length<2)throw new Error(\"first argument should be an array with at least two elements\");return t.reduce(function(t,n){return i(t,n,e)})},i})}),i=r(function(t,e){var n={svg:{name:\"xmlns\",uri:\"http://www.w3.org/2000/svg\"},xlink:{name:\"xmlns:xlink\",uri:\"http://www.w3.org/1999/xlink\"}};e.default=n,t.exports=e.default}),a=function(t){return Object.keys(t).map(function(e){var n=t[e].toString().replace(/\"/g,\"&quot;\");return e+'=\"'+n+'\"'}).join(\" \")},s=i.svg,c=i.xlink,u={};u[s.name]=s.uri,u[c.name]=c.uri;var f=function(t,e){void 0===t&&(t=\"\");var n=o(u,e||{}),r=a(n);return\"<svg \"+r+\">\"+t+\"</svg>\"},l=function(t){function e(){t.apply(this,arguments)}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var r={isMounted:{}};return r.isMounted.get=function(){return!!this.node},e.createFromExistingNode=function(t){return new e({id:t.getAttribute(\"id\"),viewBox:t.getAttribute(\"viewBox\"),content:t.outerHTML})},e.prototype.destroy=function(){this.isMounted&&this.unmount(),t.prototype.destroy.call(this)},e.prototype.mount=function(t){if(this.isMounted)return this.node;var e=\"string\"===typeof t?document.querySelector(t):t,n=this.render();return this.node=n,e.appendChild(n),n},e.prototype.render=function(){var t=this.stringify();return n(f(t)).childNodes[0]},e.prototype.unmount=function(){this.node.parentNode.removeChild(this.node)},Object.defineProperties(e.prototype,r),e}(t);return l})}).call(this,n(\"c8ba\"))},e11e:function(t,e){t.exports=\"constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf\".split(\",\")},e265:function(t,e,n){t.exports=n(\"ed33\")},e4ae:function(t,e,n){var r=n(\"f772\");t.exports=function(t){if(!r(t))throw TypeError(t+\" is not an object!\");return t}},e53d:function(t,e){var n=t.exports=\"undefined\"!=typeof window&&window.Math==Math?window:\"undefined\"!=typeof self&&self.Math==Math?self:Function(\"return this\")();\"number\"==typeof __g&&(__g=n)},e683:function(t,e,n){\"use strict\";t.exports=function(t,e){return e?t.replace(/\\/+$/,\"\")+\"/\"+e.replace(/^\\/+/,\"\"):t}},e6f3:function(t,e,n){var r=n(\"07e3\"),o=n(\"36c3\"),i=n(\"5b4e\")(!1),a=n(\"5559\")(\"IE_PROTO\");t.exports=function(t,e){var n,s=o(t),c=0,u=[];for(n in s)n!=a&&r(s,n)&&u.push(n);while(e.length>c)r(s,n=e[c++])&&(~i(u,n)||u.push(n));return u}},ebd6:function(t,e,n){var r=n(\"cb7c\"),o=n(\"d8e8\"),i=n(\"2b4c\")(\"species\");t.exports=function(t,e){var n,a=r(t).constructor;return void 0===a||void 0==(n=r(a)[i])?e:o(n)}},ebfd:function(t,e,n){var r=n(\"62a0\")(\"meta\"),o=n(\"f772\"),i=n(\"07e3\"),a=n(\"d9f6\").f,s=0,c=Object.isExtensible||function(){return!0},u=!n(\"294c\")(function(){return c(Object.preventExtensions({}))}),f=function(t){a(t,r,{value:{i:\"O\"+ ++s,w:{}}})},l=function(t,e){if(!o(t))return\"symbol\"==typeof t?t:(\"string\"==typeof t?\"S\":\"P\")+t;if(!i(t,r)){if(!c(t))return\"F\";if(!e)return\"E\";f(t)}return t[r].i},p=function(t,e){if(!i(t,r)){if(!c(t))return!0;if(!e)return!1;f(t)}return t[r].w},d=function(t){return u&&h.NEED&&c(t)&&!i(t,r)&&f(t),t},h=t.exports={KEY:r,NEED:!1,fastKey:l,getWeak:p,onFreeze:d}},ed33:function(t,e,n){n(\"014b\"),t.exports=n(\"584a\").Object.getOwnPropertySymbols},ee6d:function(t,e,n){var r=n(\"63b6\"),o=n(\"ba99\"),i=n(\"36c3\"),a=n(\"bf0b\"),s=n(\"20fd\");r(r.S,\"Object\",{getOwnPropertyDescriptors:function(t){var e,n,r=i(t),c=a.f,u=o(r),f={},l=0;while(u.length>l)n=c(r,e=u[l++]),void 0!==n&&s(f,e,n);return f}})},f201:function(t,e,n){var r=n(\"e4ae\"),o=n(\"79aa\"),i=n(\"5168\")(\"species\");t.exports=function(t,e){var n,a=r(t).constructor;return void 0===a||void 0==(n=r(a)[i])?e:o(n)}},f5df:function(t,e,n){},f605:function(t,e){t.exports=function(t,e,n,r){if(!(t instanceof e)||void 0!==r&&r in t)throw TypeError(n+\": incorrect invocation!\");return t}},f6b4:function(t,e,n){\"use strict\";var r=n(\"c532\");function o(){this.handlers=[]}o.prototype.use=function(t,e){return this.handlers.push({fulfilled:t,rejected:e}),this.handlers.length-1},o.prototype.eject=function(t){this.handlers[t]&&(this.handlers[t]=null)},o.prototype.forEach=function(t){r.forEach(this.handlers,function(e){null!==e&&t(e)})},t.exports=o},f751:function(t,e,n){var r=n(\"5ca1\");r(r.S+r.F,\"Object\",{assign:n(\"7333\")})},f772:function(t,e){t.exports=function(t){return\"object\"===typeof t?null!==t:\"function\"===typeof t}},f893:function(t,e,n){t.exports={default:n(\"f921\"),__esModule:!0}},f921:function(t,e,n){n(\"014b\"),n(\"c207\"),n(\"69d3\"),n(\"765d\"),t.exports=n(\"584a\").Symbol},fa5b:function(t,e,n){t.exports=n(\"5537\")(\"native-function-to-string\",Function.toString)},fab2:function(t,e,n){var r=n(\"7726\").document;t.exports=r&&r.documentElement},fde4:function(t,e,n){n(\"bf90\");var r=n(\"584a\").Object;t.exports=function(t,e){return r.getOwnPropertyDescriptor(t,e)}}}]);"
  },
  {
    "path": "admin/admin-web/src/test/java/com/alibaba/otter/canal/admin/SimpleAdminConnectorTest.java",
    "content": "package com.alibaba.otter.canal.admin;\n\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.admin.connector.SimpleAdminConnector;\n\n@Ignore\npublic class SimpleAdminConnectorTest {\n\n    @Test\n    public void testSimple() {\n        SimpleAdminConnector connector = new SimpleAdminConnector(\"127.0.0.1\", 11110, \"admin\", \"admin\");\n        connector.connect();\n        System.out.println(\"check 1 : \" + connector.check());\n        System.out.println(\"getRunning Before stop 1 : \" + connector.getRunningInstances());\n        System.out.println(\"stop 1: \" + connector.stop());\n        System.out.println(\"getRunning After stop 1 : \" + connector.getRunningInstances());\n        System.out.println(\"check 1 : \" + connector.check());\n        System.out.println(\"listFile 1 : \" + connector.listCanalLog());\n        System.out.println(\"getFile 1 : \" + connector.canalLog(10));\n        connector.disconnect();\n\n        connector.connect();\n        System.out.println(\"check 2 : \" + connector.check());\n        System.out.println(\"get Running Before start : \" + connector.getRunningInstances());\n        System.out.println(\"start 2 : \" + connector.start());\n        System.out.println(\"get Running After start : \" + connector.getRunningInstances());\n        System.out.println(\"check 2 : \" + connector.check());\n        System.out.println(\"check after before example 2 : \" + connector.checkInstance(\"example\"));\n        System.out.println(\"stop example 2 : \" + connector.stopInstance(\"example\"));\n        System.out.println(\"check example 2 : \" + connector.checkInstance(\"example\"));\n        System.out.println(\"start example 2 : \" + connector.startInstance(\"example\"));\n        System.out.println(\"check after start example 2 : \" + connector.checkInstance(\"example\"));\n        System.out.println(\"listFile 2 : \" + connector.listCanalLog());\n        System.out.println(\"getFile 2 : \" + connector.canalLog(10));\n\n        System.out.println(\"listFile 3 : \" + connector.listInstanceLog(\"example\"));\n        System.out.println(\"getFile 3 : \" + connector.instanceLog(\"example\", \"example.log\", 10));\n        connector.disconnect();\n    }\n}\n"
  },
  {
    "path": "admin/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <groupId>com.alibaba.otter</groupId>\n        <artifactId>canal</artifactId>\n        <version>1.1.9-SNAPSHOT</version>\n        <relativePath>../pom.xml</relativePath>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>com.alibaba.otter</groupId>\n    <artifactId>canal.admin</artifactId>\n    <version>1.1.9-SNAPSHOT</version>\n    <packaging>pom</packaging>\n    <name>canal admin module for otter ${project.version}</name>\n    <modules>\n        <module>admin-ui</module>\n        <module>admin-web</module>\n    </modules>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <maven.test.skip>true</maven.test.skip>\n        <downloadSources>true</downloadSources>\n        <java_source_version>1.8</java_source_version>\n        <java_target_version>1.8</java_target_version>\n        <file_encoding>UTF-8</file_encoding>\n    </properties>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-context</artifactId>\n                <version>3.0.6</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <version>2.5.15</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>com.github.ben-manes.caffeine</groupId>\n                <artifactId>caffeine</artifactId>\n                <version>2.6.2</version>\n            </dependency>\n            <dependency>\n                <groupId>io.ebean</groupId>\n                <artifactId>ebean</artifactId>\n                <version>11.45.1</version>\n            </dependency>\n            <dependency>\n                <groupId>org.yaml</groupId>\n                <artifactId>snakeyaml</artifactId>\n                <version>2.0</version>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.7.0</version>\n                <configuration>\n                    <source>${java_source_version}</source>\n                    <target>${java_target_version}</target>\n                    <encoding>${file_encoding}</encoding>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "charts/README.md",
    "content": "# helm charts 使用说明\n\n包含`canal-admin`和`canal-server`两个chart，基本配置保存在k8s的`secret`里，`canal.properties`和`instance.properties`保存在mysql数据库中，使用zookeeper注册中心实现高可用。\n\n- [helm charts 使用说明](#helm-charts-使用说明)\n  - [创建zk集群](#创建zk集群)\n  - [初始化数据库](#初始化数据库)\n  - [部署canal-admin chart](#部署canal-admin-chart)\n    - [配置values.yaml](#配置valuesyaml)\n    - [配置集群信息](#配置集群信息)\n  - [部署canal-server chart](#部署canal-server-chart)\n    - [配置values.yaml](#配置valuesyaml-1)\n  - [instance 实例创建](#instance-实例创建)\n\n## 创建zk集群\n\n```sh\nhelm install canal-zookeeper oci://registry-1.docker.io/bitnamicharts/zookeeper\n```\n\n如需挂载磁盘参考 [bitnami/zookeeper](`https://github.com/bitnami/charts/tree/main/bitnami/zookeeper`)\n\n\n## 初始化数据库\n\n[/admin/admin-web/src/main/resources/canal_manager.sql](/admin/admin-web/src/main/resources/canal_manager.sql)\n\n[/deployer/src/main/resources/spring/tsdb/sql/create_table.sql](/deployer/src/main/resources/spring/tsdb/sql/create_table.sql)\n\n## 部署canal-admin chart\n\n### 配置values.yaml\n\n```yaml\n# 主要配置\nadmin:\n  config: |\n    server:\n      port: 8089\n    spring:\n      jackson:\n        date-format: yyyy-MM-dd HH:mm:ss\n        time-zone: GMT+8\n    spring.datasource:\n      address: your_db_host:3306\n      database: canal_manager\n      username: ****\n      password: ****\n      driver-class-name: com.mysql.jdbc.Driver\n      url: jdbc:mysql://${spring.datasource.address}/${spring.datasource.database}?useUnicode=true&characterEncoding=UTF-8&useSSL=false&allowPublicKeyRetrieval=true\n      hikari:\n        maximum-pool-size: 30\n        minimum-idle: 1\n    canal:\n      adminUser: admin\n      adminPasswd: admin\n    # debug: true\n```\n\n全量参数见：[canal-admin/values.yaml](./canal-admin/values.yaml)，测试用例见：[tests/admin-values.yaml](./tests/admin-values.yaml)\n\n```sh\nhelm install canal-admin -f ./admin-values.yaml ./canal-admin\n```\n\n### 配置集群信息\n\n![cluster](./images/cluster.png)\n\n等待pod启动后，使用默认账户`admin`密码`123456`登录\n\n创建集群`default`并配置`zk地址`为`canal-zookeeper.default.svc.cluster.local:2181`\n\n配置完成后，点击`配置`-`主配置`，修改以下配置项，不是覆盖整个文件\n\n```yaml\ncanal.user = admin\ncanal.passwd = 4ACFE3202A5FF5CF467898FC58AAB1D615029441\n\ncanal.zkServers = canal-zookeeper.default.svc.cluster.local:2181\n# tcp, kafka, rocketMQ, rabbitMQ, pulsarMQ 看实际需求，此处改为了rabbitMQ\ncanal.serverMode = rabbitMQ\n\n#canal.instance.tsdb.dir = ${canal.file.data.dir:../conf}/${canal.instance.destination:}\ncanal.instance.tsdb.url = jdbc:mysql://you_db_host:3306/canal_tsdb?useUnicode=true&characterEncoding=UTF-8&useSSL=false\ncanal.instance.tsdb.dbUsername = ****\ncanal.instance.tsdb.dbPassword = ****\n\n#canal.instance.tsdb.spring.xml = classpath:spring/tsdb/h2-tsdb.xml\ncanal.instance.tsdb.spring.xml = classpath:spring/tsdb/mysql-tsdb.xml\n\n#canal.instance.global.spring.xml = classpath:spring/file-instance.xml\ncanal.instance.global.spring.xml = classpath:spring/default-instance.xml\n\n# 如果用的是阿里云polardb需要配置\ncanal.aliyun.accessKey = ****\ncanal.aliyun.secretKey = ****\ncanal.aliyun.uid = 主账号id\n\n# 我们是推送到rabbitmq所以需要配置\nrabbitmq.host = ****:5672\nrabbitmq.virtual.host = ****\nrabbitmq.exchange = ****\n# canal.aliyun.accessKey\nrabbitmq.username = ****\n# canal.aliyun.secretKey\nrabbitmq.password = ****\nrabbitmq.deliveryMode = direct\n```\n\n## 部署canal-server chart\n\n### 配置values.yaml\n\n```yaml\n# 主要配置\nserver:\n  config: |\n    canal.port = 11111\n    canal.metrics.pull.port = 11112\n\n    # register ip\n    canal.register.ip =\n\n    # canal admin config\n    canal.admin.manager = canal-admin.default:8089\n    canal.admin.port = 11110\n    canal.admin.user = admin\n    canal.admin.passwd = 4ACFE3202A5FF5CF467898FC58AAB1D615029441\n    # admin auto register\n    canal.admin.register.auto = true\n    canal.admin.register.cluster = default\n```\n\n```sh\nhelm install canal-server -f ./server-values.yaml ./canal-server\n```\n\n全量参数见：[canal-server/values.yaml](./canal-server/values.yaml)，测试用例见：[tests/server-values.yaml](./tests/server-values.yaml)\n\n![server](./images/server.png)\n\n至此，canal-server已自动创建，并自动注册。\n\n## instance 实例创建\n\n主要配置如下\n\n```yaml\n# 配置你要监听的数据库\ncanal.instance.master.address=127.0.0.1:3306\ncanal.instance.dbUsername=****\ncanal.instance.dbPassword=****\n\n# 过滤监听哪些表\ncanal.instance.filter.regex=.*\\\\..*\n\n# 如果是推送到rabbitmq，需要配置 Routing Key\ncanal.mq.topic=你的Routing Key\n```\n"
  },
  {
    "path": "charts/canal-admin/.helmignore",
    "content": "# Patterns to ignore when building packages.\n# This supports shell glob matching, relative path matching, and\n# negation (prefixed with !). Only one pattern per line.\n.DS_Store\n# Common VCS dirs\n.git/\n.gitignore\n.bzr/\n.bzrignore\n.hg/\n.hgignore\n.svn/\n# Common backup files\n*.swp\n*.bak\n*.tmp\n*.orig\n*~\n# Various IDEs\n.project\n.idea/\n*.tmproj\n.vscode/\n"
  },
  {
    "path": "charts/canal-admin/Chart.yaml",
    "content": "apiVersion: v2\nname: canal-admin\ndescription: A Helm chart for Kubernetes\n\n# A chart can be either an 'application' or a 'library' chart.\n#\n# Application charts are a collection of templates that can be packaged into versioned archives\n# to be deployed.\n#\n# Library charts provide useful utilities or functions for the chart developer. They're included as\n# a dependency of application charts to inject those utilities and functions into the rendering\n# pipeline. Library charts do not define any templates and therefore cannot be deployed.\ntype: application\n\n# This is the chart version. This version number should be incremented each time you make changes\n# to the chart and its templates, including the app version.\n# Versions are expected to follow Semantic Versioning (https://semver.org/)\nversion: 1.1.8-alpha-3\n\n# This is the version number of the application being deployed. This version number should be\n# incremented each time you make changes to the application. Versions are not expected to\n# follow Semantic Versioning. They should reflect the version the application is using.\n# It is recommended to use it with quotes.\nappVersion: \"1.16.0\"\n"
  },
  {
    "path": "charts/canal-admin/templates/NOTES.txt",
    "content": "1. Get the application URL by running these commands:\n{{- if .Values.ingress.enabled }}\n{{- range $host := .Values.ingress.hosts }}\n  {{- range .paths }}\n  http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}\n  {{- end }}\n{{- end }}\n{{- else if contains \"NodePort\" .Values.service.type }}\n  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath=\"{.spec.ports[0].nodePort}\" services {{ include \"canal-admin.fullname\" . }})\n  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath=\"{.items[0].status.addresses[0].address}\")\n  echo http://$NODE_IP:$NODE_PORT\n{{- else if contains \"LoadBalancer\" .Values.service.type }}\n     NOTE: It may take a few minutes for the LoadBalancer IP to be available.\n           You can watch its status by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include \"canal-admin.fullname\" . }}'\n  export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include \"canal-admin.fullname\" . }} --template \"{{\"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}\"}}\")\n  echo http://$SERVICE_IP:{{ .Values.service.port }}\n{{- else if contains \"ClusterIP\" .Values.service.type }}\n  export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l \"app.kubernetes.io/name={{ include \"canal-admin.name\" . }},app.kubernetes.io/instance={{ .Release.Name }}\" -o jsonpath=\"{.items[0].metadata.name}\")\n  export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath=\"{.spec.containers[0].ports[0].containerPort}\")\n  echo \"Visit http://127.0.0.1:8080 to use your application\"\n  kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT\n{{- end }}\n"
  },
  {
    "path": "charts/canal-admin/templates/_helpers.tpl",
    "content": "{{/*\nExpand the name of the chart.\n*/}}\n{{- define \"canal-admin.name\" -}}\n{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix \"-\" }}\n{{- end }}\n\n{{/*\nCreate a default fully qualified app name.\nWe truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).\nIf release name contains chart name it will be used as a full name.\n*/}}\n{{- define \"canal-admin.fullname\" -}}\n{{- if .Values.fullnameOverride }}\n{{- .Values.fullnameOverride | trunc 63 | trimSuffix \"-\" }}\n{{- else }}\n{{- $name := default .Chart.Name .Values.nameOverride }}\n{{- if contains $name .Release.Name }}\n{{- .Release.Name | trunc 63 | trimSuffix \"-\" }}\n{{- else }}\n{{- printf \"%s-%s\" .Release.Name $name | trunc 63 | trimSuffix \"-\" }}\n{{- end }}\n{{- end }}\n{{- end }}\n\n{{/*\nCreate chart name and version as used by the chart label.\n*/}}\n{{- define \"canal-admin.chart\" -}}\n{{- printf \"%s-%s\" .Chart.Name .Chart.Version | replace \"+\" \"_\" | trunc 63 | trimSuffix \"-\" }}\n{{- end }}\n\n{{/*\nCommon labels\n*/}}\n{{- define \"canal-admin.labels\" -}}\nhelm.sh/chart: {{ include \"canal-admin.chart\" . }}\n{{ include \"canal-admin.selectorLabels\" . }}\n{{- if .Chart.AppVersion }}\napp.kubernetes.io/version: {{ .Chart.AppVersion | quote }}\n{{- end }}\napp.kubernetes.io/managed-by: {{ .Release.Service }}\n{{- end }}\n\n{{/*\nSelector labels\n*/}}\n{{- define \"canal-admin.selectorLabels\" -}}\napp.kubernetes.io/name: {{ include \"canal-admin.name\" . }}\napp.kubernetes.io/instance: {{ .Release.Name }}\n{{- end }}\n\n{{/*\nCreate the name of the service account to use\n*/}}\n{{- define \"canal-admin.serviceAccountName\" -}}\n{{- if .Values.serviceAccount.create }}\n{{- default (include \"canal-admin.fullname\" .) .Values.serviceAccount.name }}\n{{- else }}\n{{- default \"default\" .Values.serviceAccount.name }}\n{{- end }}\n{{- end }}\n"
  },
  {
    "path": "charts/canal-admin/templates/deployment.yaml",
    "content": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: {{ include \"canal-admin.fullname\" . }}\n  labels:\n    {{- include \"canal-admin.labels\" . | nindent 4 }}\nspec:\n  {{- if not .Values.autoscaling.enabled }}\n  replicas: {{ .Values.replicaCount }}\n  {{- end }}\n  selector:\n    matchLabels:\n      {{- include \"canal-admin.selectorLabels\" . | nindent 6 }}\n  template:\n    metadata:\n      {{- with .Values.podAnnotations }}\n      annotations:\n        {{- toYaml . | nindent 8 }}\n      {{- end }}\n      labels:\n        {{- include \"canal-admin.labels\" . | nindent 8 }}\n        {{- with .Values.podLabels }}\n        {{- toYaml . | nindent 8 }}\n        {{- end }}\n    spec:\n      {{- with .Values.imagePullSecrets }}\n      imagePullSecrets:\n        {{- toYaml . | nindent 8 }}\n      {{- end }}\n      serviceAccountName: {{ include \"canal-admin.serviceAccountName\" . }}\n      securityContext:\n        {{- toYaml .Values.podSecurityContext | nindent 8 }}\n      containers:\n        - name: {{ .Chart.Name }}\n          securityContext:\n            {{- toYaml .Values.securityContext | nindent 12 }}\n          image: \"{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}\"\n          imagePullPolicy: {{ .Values.image.pullPolicy }}\n          ports:\n            - name: http\n              containerPort: {{ .Values.service.port }}\n              protocol: TCP\n          livenessProbe:\n            {{- toYaml .Values.livenessProbe | nindent 12 }}\n          readinessProbe:\n            {{- toYaml .Values.readinessProbe | nindent 12 }}\n          resources:\n            {{- toYaml .Values.resources | nindent 12 }}\n          volumeMounts:\n            - mountPath: /home/admin/canal-admin/conf/application.yml\n              name: secret\n              subPath: application.yml\n            {{- with .Values.volumeMounts }}\n            {{- toYaml . | nindent 12 }}\n            {{- end }}\n      volumes:\n        - name: secret\n          secret:\n            defaultMode: 420\n            secretName: {{ include \"canal-admin.fullname\" . }}\n        {{- with .Values.volumes }}\n        {{- toYaml . | nindent 8 }}\n        {{- end }}\n      {{- with .Values.nodeSelector }}\n      nodeSelector:\n        {{- toYaml . | nindent 8 }}\n      {{- end }}\n      {{- with .Values.affinity }}\n      affinity:\n        {{- toYaml . | nindent 8 }}\n      {{- end }}\n      {{- with .Values.tolerations }}\n      tolerations:\n        {{- toYaml . | nindent 8 }}\n      {{- end }}\n"
  },
  {
    "path": "charts/canal-admin/templates/hpa.yaml",
    "content": "{{- if .Values.autoscaling.enabled }}\napiVersion: autoscaling/v2\nkind: HorizontalPodAutoscaler\nmetadata:\n  name: {{ include \"canal-admin.fullname\" . }}\n  labels:\n    {{- include \"canal-admin.labels\" . | nindent 4 }}\nspec:\n  scaleTargetRef:\n    apiVersion: apps/v1\n    kind: Deployment\n    name: {{ include \"canal-admin.fullname\" . }}\n  minReplicas: {{ .Values.autoscaling.minReplicas }}\n  maxReplicas: {{ .Values.autoscaling.maxReplicas }}\n  metrics:\n    {{- if .Values.autoscaling.targetCPUUtilizationPercentage }}\n    - type: Resource\n      resource:\n        name: cpu\n        target:\n          type: Utilization\n          averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}\n    {{- end }}\n    {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}\n    - type: Resource\n      resource:\n        name: memory\n        target:\n          type: Utilization\n          averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}\n    {{- end }}\n{{- end }}\n"
  },
  {
    "path": "charts/canal-admin/templates/ingress.yaml",
    "content": "{{- if .Values.ingress.enabled -}}\napiVersion: networking.k8s.io/v1\nkind: Ingress\nmetadata:\n  name: {{ include \"canal-admin.fullname\" . }}\n  labels:\n    {{- include \"canal-admin.labels\" . | nindent 4 }}\n  {{- with .Values.ingress.annotations }}\n  annotations:\n    {{- toYaml . | nindent 4 }}\n  {{- end }}\nspec:\n  {{- with .Values.ingress.className }}\n  ingressClassName: {{ . }}\n  {{- end }}\n  {{- if .Values.ingress.tls }}\n  tls:\n    {{- range .Values.ingress.tls }}\n    - hosts:\n        {{- range .hosts }}\n        - {{ . | quote }}\n        {{- end }}\n      secretName: {{ .secretName }}\n    {{- end }}\n  {{- end }}\n  rules:\n    {{- range .Values.ingress.hosts }}\n    - host: {{ .host | quote }}\n      http:\n        paths:\n          {{- range .paths }}\n          - path: {{ .path }}\n            {{- with .pathType }}\n            pathType: {{ . }}\n            {{- end }}\n            backend:\n              service:\n                name: {{ include \"canal-admin.fullname\" $ }}\n                port:\n                  number: {{ $.Values.service.port }}\n          {{- end }}\n    {{- end }}\n{{- end }}\n"
  },
  {
    "path": "charts/canal-admin/templates/secret.yaml",
    "content": "apiVersion: v1\nkind: Secret\nmetadata:\n  name: {{ include \"canal-admin.fullname\" . }}\n  labels:\n    {{- include \"canal-admin.labels\" . | nindent 4 }}\ntype: Opaque\ndata:\n  application.yml: {{tpl .Values.admin.config $ | b64enc | quote }}"
  },
  {
    "path": "charts/canal-admin/templates/service.yaml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  name: {{ include \"canal-admin.fullname\" . }}\n  labels:\n    {{- include \"canal-admin.labels\" . | nindent 4 }}\nspec:\n  type: {{ .Values.service.type }}\n  ports:\n    - port: {{ .Values.service.port }}\n      targetPort: http\n      protocol: TCP\n      name: http\n  selector:\n    {{- include \"canal-admin.selectorLabels\" . | nindent 4 }}\n"
  },
  {
    "path": "charts/canal-admin/templates/serviceaccount.yaml",
    "content": "{{- if .Values.serviceAccount.create -}}\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: {{ include \"canal-admin.serviceAccountName\" . }}\n  labels:\n    {{- include \"canal-admin.labels\" . | nindent 4 }}\n  {{- with .Values.serviceAccount.annotations }}\n  annotations:\n    {{- toYaml . | nindent 4 }}\n  {{- end }}\nautomountServiceAccountToken: {{ .Values.serviceAccount.automount }}\n{{- end }}\n"
  },
  {
    "path": "charts/canal-admin/templates/tests/test-connection.yaml",
    "content": "apiVersion: v1\nkind: Pod\nmetadata:\n  name: \"{{ include \"canal-admin.fullname\" . }}-test-connection\"\n  labels:\n    {{- include \"canal-admin.labels\" . | nindent 4 }}\n  annotations:\n    \"helm.sh/hook\": test\nspec:\n  containers:\n    - name: wget\n      image: busybox\n      command: ['wget']\n      args: ['{{ include \"canal-admin.fullname\" . }}:{{ .Values.service.port }}']\n  restartPolicy: Never\n"
  },
  {
    "path": "charts/canal-admin/values.yaml",
    "content": "# Default values for canal-admin.\n# This is a YAML-formatted file.\n# Declare variables to be passed into your templates.\n\n# This will set the replicaset count more information can be found here: https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/\nreplicaCount: 1\n\n# This sets the container image more information can be found here: https://kubernetes.io/docs/concepts/containers/images/\nimage:\n  repository: canal/canal-admin\n  # This sets the pull policy for images.\n  pullPolicy: IfNotPresent\n  # Overrides the image tag whose default is the chart appVersion.\n  tag: \"latest\"\n\n# This is for the secretes for pulling an image from a private repository more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/\nimagePullSecrets: []\n# This is to override the chart name.\nnameOverride: \"\"\nfullnameOverride: \"\"\n\n# This section builds out the service account more information can be found here: https://kubernetes.io/docs/concepts/security/service-accounts/\nserviceAccount:\n  # Specifies whether a service account should be created\n  create: false\n  # Automatically mount a ServiceAccount's API credentials?\n  automount: false\n  # Annotations to add to the service account\n  annotations: {}\n  # The name of the service account to use.\n  # If not set and create is true, a name is generated using the fullname template\n  name: \"\"\n\n# This is for setting Kubernetes Annotations to a Pod.\n# For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/\npodAnnotations: {}\n# This is for setting Kubernetes Labels to a Pod.\n# For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/\npodLabels: {}\n\npodSecurityContext: {}\n  # fsGroup: 2000\n\nsecurityContext: {}\n  # capabilities:\n  #   drop:\n  #   - ALL\n  # readOnlyRootFilesystem: true\n  # runAsNonRoot: true\n  # runAsUser: 1000\n\n# This is for setting up a service more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/\nservice:\n  # This sets the service type more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types\n  type: ClusterIP\n  # This sets the ports more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/#field-spec-ports\n  port: 8089\n\n# This block is for setting up the ingress for more information can be found here: https://kubernetes.io/docs/concepts/services-networking/ingress/\ningress:\n  enabled: false\n  className: \"\"\n  annotations: {}\n    # kubernetes.io/ingress.class: nginx\n    # kubernetes.io/tls-acme: \"true\"\n  hosts:\n    - host: chart-example.local\n      paths:\n        - path: /\n          pathType: ImplementationSpecific\n  tls: []\n  #  - secretName: chart-example-tls\n  #    hosts:\n  #      - chart-example.local\n\nresources: {}\n  # We usually recommend not to specify default resources and to leave this as a conscious\n  # choice for the user. This also increases chances charts run on environments with little\n  # resources, such as Minikube. If you do want to specify resources, uncomment the following\n  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.\n  # limits:\n  #   cpu: 100m\n  #   memory: 128Mi\n  # requests:\n  #   cpu: 100m\n  #   memory: 128Mi\n\n# This is to setup the liveness and readiness probes more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/\nlivenessProbe:\n  httpGet:\n    path: /\n    port: http\nreadinessProbe:\n  httpGet:\n    path: /\n    port: http\n\n# This section is for setting up autoscaling more information can be found here: https://kubernetes.io/docs/concepts/workloads/autoscaling/\nautoscaling:\n  enabled: false\n  minReplicas: 1\n  maxReplicas: 100\n  targetCPUUtilizationPercentage: 80\n  # targetMemoryUtilizationPercentage: 80\n\n# Additional volumes on the output Deployment definition.\nvolumes: []\n# - name: foo\n#   secret:\n#     secretName: mysecret\n#     optional: false\n\n# Additional volumeMounts on the output Deployment definition.\nvolumeMounts: []\n# - name: foo\n#   mountPath: \"/etc/foo\"\n#   readOnly: true\n\nnodeSelector: {}\n\ntolerations: []\n\naffinity: {}\n\nadmin:\n  config: |\n    server:\n      port: 8089\n    spring:\n      jackson:\n        date-format: yyyy-MM-dd HH:mm:ss\n        time-zone: GMT+8\n    spring.datasource:\n      address: you_db_host:3306\n      database: canal_manager\n      username: ****\n      password: ****\n      driver-class-name: com.mysql.jdbc.Driver\n      url: jdbc:mysql://${spring.datasource.address}/${spring.datasource.database}?useUnicode=true&characterEncoding=UTF-8&useSSL=false&allowPublicKeyRetrieval=true\n      hikari:\n        maximum-pool-size: 30\n        minimum-idle: 1\n    canal:\n      adminUser: admin\n      adminPasswd: admin\n    # debug: true"
  },
  {
    "path": "charts/canal-server/.helmignore",
    "content": "# Patterns to ignore when building packages.\n# This supports shell glob matching, relative path matching, and\n# negation (prefixed with !). Only one pattern per line.\n.DS_Store\n# Common VCS dirs\n.git/\n.gitignore\n.bzr/\n.bzrignore\n.hg/\n.hgignore\n.svn/\n# Common backup files\n*.swp\n*.bak\n*.tmp\n*.orig\n*~\n# Various IDEs\n.project\n.idea/\n*.tmproj\n.vscode/\n"
  },
  {
    "path": "charts/canal-server/Chart.yaml",
    "content": "apiVersion: v2\nname: canal-server\ndescription: A Helm chart for Kubernetes\n\n# A chart can be either an 'application' or a 'library' chart.\n#\n# Application charts are a collection of templates that can be packaged into versioned archives\n# to be deployed.\n#\n# Library charts provide useful utilities or functions for the chart developer. They're included as\n# a dependency of application charts to inject those utilities and functions into the rendering\n# pipeline. Library charts do not define any templates and therefore cannot be deployed.\ntype: application\n\n# This is the chart version. This version number should be incremented each time you make changes\n# to the chart and its templates, including the app version.\n# Versions are expected to follow Semantic Versioning (https://semver.org/)\nversion: 1.1.8-alpha-3\n\n# This is the version number of the application being deployed. This version number should be\n# incremented each time you make changes to the application. Versions are not expected to\n# follow Semantic Versioning. They should reflect the version the application is using.\n# It is recommended to use it with quotes.\nappVersion: \"1.16.0\"\n"
  },
  {
    "path": "charts/canal-server/templates/NOTES.txt",
    "content": "1. Get the application URL by running these commands:\n{{- if .Values.ingress.enabled }}\n{{- range $host := .Values.ingress.hosts }}\n  {{- range .paths }}\n  http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}\n  {{- end }}\n{{- end }}\n{{- else if contains \"NodePort\" .Values.service.type }}\n  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath=\"{.spec.ports[0].nodePort}\" services {{ include \"canal-server.fullname\" . }})\n  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath=\"{.items[0].status.addresses[0].address}\")\n  echo http://$NODE_IP:$NODE_PORT\n{{- else if contains \"LoadBalancer\" .Values.service.type }}\n     NOTE: It may take a few minutes for the LoadBalancer IP to be available.\n           You can watch its status by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include \"canal-server.fullname\" . }}'\n  export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include \"canal-server.fullname\" . }} --template \"{{\"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}\"}}\")\n  echo http://$SERVICE_IP:{{ .Values.service.port }}\n{{- else if contains \"ClusterIP\" .Values.service.type }}\n  export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l \"app.kubernetes.io/name={{ include \"canal-server.name\" . }},app.kubernetes.io/instance={{ .Release.Name }}\" -o jsonpath=\"{.items[0].metadata.name}\")\n  export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath=\"{.spec.containers[0].ports[0].containerPort}\")\n  echo \"Visit http://127.0.0.1:8080 to use your application\"\n  kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT\n{{- end }}\n"
  },
  {
    "path": "charts/canal-server/templates/_helpers.tpl",
    "content": "{{/*\nExpand the name of the chart.\n*/}}\n{{- define \"canal-server.name\" -}}\n{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix \"-\" }}\n{{- end }}\n\n{{/*\nCreate a default fully qualified app name.\nWe truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).\nIf release name contains chart name it will be used as a full name.\n*/}}\n{{- define \"canal-server.fullname\" -}}\n{{- if .Values.fullnameOverride }}\n{{- .Values.fullnameOverride | trunc 63 | trimSuffix \"-\" }}\n{{- else }}\n{{- $name := default .Chart.Name .Values.nameOverride }}\n{{- if contains $name .Release.Name }}\n{{- .Release.Name | trunc 63 | trimSuffix \"-\" }}\n{{- else }}\n{{- printf \"%s-%s\" .Release.Name $name | trunc 63 | trimSuffix \"-\" }}\n{{- end }}\n{{- end }}\n{{- end }}\n\n{{/*\nCreate chart name and version as used by the chart label.\n*/}}\n{{- define \"canal-server.chart\" -}}\n{{- printf \"%s-%s\" .Chart.Name .Chart.Version | replace \"+\" \"_\" | trunc 63 | trimSuffix \"-\" }}\n{{- end }}\n\n{{/*\nCommon labels\n*/}}\n{{- define \"canal-server.labels\" -}}\nhelm.sh/chart: {{ include \"canal-server.chart\" . }}\n{{ include \"canal-server.selectorLabels\" . }}\n{{- if .Chart.AppVersion }}\napp.kubernetes.io/version: {{ .Chart.AppVersion | quote }}\n{{- end }}\napp.kubernetes.io/managed-by: {{ .Release.Service }}\n{{- end }}\n\n{{/*\nSelector labels\n*/}}\n{{- define \"canal-server.selectorLabels\" -}}\napp.kubernetes.io/name: {{ include \"canal-server.name\" . }}\napp.kubernetes.io/instance: {{ .Release.Name }}\n{{- end }}\n\n{{/*\nCreate the name of the service account to use\n*/}}\n{{- define \"canal-server.serviceAccountName\" -}}\n{{- if .Values.serviceAccount.create }}\n{{- default (include \"canal-server.fullname\" .) .Values.serviceAccount.name }}\n{{- else }}\n{{- default \"default\" .Values.serviceAccount.name }}\n{{- end }}\n{{- end }}\n"
  },
  {
    "path": "charts/canal-server/templates/hpa.yaml",
    "content": "{{- if .Values.autoscaling.enabled }}\napiVersion: autoscaling/v2\nkind: HorizontalPodAutoscaler\nmetadata:\n  name: {{ include \"canal-server.fullname\" . }}\n  labels:\n    {{- include \"canal-server.labels\" . | nindent 4 }}\nspec:\n  scaleTargetRef:\n    apiVersion: apps/v1\n    kind: Deployment\n    name: {{ include \"canal-server.fullname\" . }}\n  minReplicas: {{ .Values.autoscaling.minReplicas }}\n  maxReplicas: {{ .Values.autoscaling.maxReplicas }}\n  metrics:\n    {{- if .Values.autoscaling.targetCPUUtilizationPercentage }}\n    - type: Resource\n      resource:\n        name: cpu\n        target:\n          type: Utilization\n          averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}\n    {{- end }}\n    {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}\n    - type: Resource\n      resource:\n        name: memory\n        target:\n          type: Utilization\n          averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}\n    {{- end }}\n{{- end }}\n"
  },
  {
    "path": "charts/canal-server/templates/secret.yaml",
    "content": "apiVersion: v1\nkind: Secret\nmetadata:\n  name: {{ include \"canal-server.fullname\" . }}\n  labels:\n    {{- include \"canal-server.labels\" . | nindent 4 }}\ntype: Opaque\ndata:\n  canal.properties: {{tpl .Values.server.config $ | b64enc | quote }}"
  },
  {
    "path": "charts/canal-server/templates/service.yaml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  name: {{ printf \"%s-headless\" (include \"canal-server.fullname\" .) | trunc 63 | trimSuffix \"-\" }}\n  labels:\n    {{- include \"canal-server.labels\" . | nindent 4 }}\nspec:\n  type: {{ .Values.service.type }}\n  ports:\n    - port: {{ .Values.service.ports.admin }}\n      targetPort: admin\n      protocol: TCP\n      name: tcp-admin\n    - port: {{ .Values.service.ports.tcp }}\n      targetPort: tcp\n      protocol: TCP\n      name: tcp-tcp\n    - port: {{ .Values.service.ports.metric }}\n      targetPort: metric\n      protocol: TCP\n      name: tcp-metric\n  selector:\n    {{- include \"canal-server.selectorLabels\" . | nindent 4 }}\n"
  },
  {
    "path": "charts/canal-server/templates/serviceaccount.yaml",
    "content": "{{- if .Values.serviceAccount.create -}}\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: {{ include \"canal-server.serviceAccountName\" . }}\n  labels:\n    {{- include \"canal-server.labels\" . | nindent 4 }}\n  {{- with .Values.serviceAccount.annotations }}\n  annotations:\n    {{- toYaml . | nindent 4 }}\n  {{- end }}\nautomountServiceAccountToken: {{ .Values.serviceAccount.automount }}\n{{- end }}\n"
  },
  {
    "path": "charts/canal-server/templates/statefulsets.yaml",
    "content": "apiVersion: apps/v1\nkind: StatefulSet\nmetadata:\n  name: {{ include \"canal-server.fullname\" . }}\n  labels:\n    {{- include \"canal-server.labels\" . | nindent 4 }}\nspec:\n  serviceName: {{ printf \"%s-headless\" (include \"canal-server.fullname\" .) | trunc 63 | trimSuffix \"-\" }}\n  replicas: {{ .Values.replicaCount }}\n  selector:\n    matchLabels:\n      {{- include \"canal-server.selectorLabels\" . | nindent 6 }}\n  template:\n    metadata:\n      {{- with .Values.podAnnotations }}\n      annotations:\n        {{- toYaml . | nindent 8 }}\n      {{- end }}\n      labels:\n        {{- include \"canal-server.labels\" . | nindent 8 }}\n        {{- with .Values.podLabels }}\n        {{- toYaml . | nindent 8 }}\n        {{- end }}\n    spec:\n      {{- with .Values.imagePullSecrets }}\n      imagePullSecrets:\n        {{- toYaml . | nindent 8 }}\n      {{- end }}\n      serviceAccountName: {{ include \"canal-server.serviceAccountName\" . }}\n      securityContext:\n        {{- toYaml .Values.podSecurityContext | nindent 8 }}\n      containers:\n        - name: {{ .Chart.Name }}\n          securityContext:\n            {{- toYaml .Values.securityContext | nindent 12 }}\n          image: \"{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}\"\n          imagePullPolicy: {{ .Values.image.pullPolicy }}\n          ports:\n            - name: admin\n              containerPort: {{ .Values.service.ports.admin }}\n              protocol: TCP\n            - name: tcp\n              containerPort: {{ .Values.service.ports.tcp }}\n              protocol: TCP\n            - name: metric\n              containerPort: {{ .Values.service.ports.metric }}\n              protocol: TCP\n          livenessProbe:\n            {{- toYaml .Values.livenessProbe | nindent 12 }}\n          readinessProbe:\n            {{- toYaml .Values.readinessProbe | nindent 12 }}\n          resources:\n            {{- toYaml .Values.resources | nindent 12 }}\n          volumeMounts:\n            - mountPath: /home/admin/canal-server/conf/canal.properties\n              name: secret\n              subPath: canal.properties\n            {{- with .Values.volumeMounts }}\n            {{- toYaml . | nindent 12 }}\n            {{- end }}\n      volumes:\n        - name: secret\n          secret:\n            defaultMode: 420\n            secretName: {{ include \"canal-server.fullname\" . }}\n        {{- with .Values.volumes }}\n        {{- toYaml . | nindent 8 }}\n        {{- end }}\n      {{- with .Values.nodeSelector }}\n      nodeSelector:\n        {{- toYaml . | nindent 8 }}\n      {{- end }}\n      {{- with .Values.affinity }}\n      affinity:\n        {{- toYaml . | nindent 8 }}\n      {{- end }}\n      {{- with .Values.tolerations }}\n      tolerations:\n        {{- toYaml . | nindent 8 }}\n      {{- end }}\n"
  },
  {
    "path": "charts/canal-server/templates/tests/test-connection.yaml",
    "content": "apiVersion: v1\nkind: Pod\nmetadata:\n  name: \"{{ include \"canal-server.fullname\" . }}-test-connection\"\n  labels:\n    {{- include \"canal-server.labels\" . | nindent 4 }}\n  annotations:\n    \"helm.sh/hook\": test\nspec:\n  containers:\n    - name: wget\n      image: busybox\n      command: ['wget']\n      args: ['{{ include \"canal-server.fullname\" . }}:{{ .Values.service.port }}']\n  restartPolicy: Never\n"
  },
  {
    "path": "charts/canal-server/values.yaml",
    "content": "# Default values for canal-server.\n# This is a YAML-formatted file.\n# Declare variables to be passed into your templates.\n\n# This will set the replicaset count more information can be found here: https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/\nreplicaCount: 1\n\n# This sets the container image more information can be found here: https://kubernetes.io/docs/concepts/containers/images/\nimage:\n  repository: canal/canal-server\n  # This sets the pull policy for images.\n  pullPolicy: IfNotPresent\n  # Overrides the image tag whose default is the chart appVersion.\n  tag: \"1.1.8-alpha-3\"\n\n# This is for the secretes for pulling an image from a private repository more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/\nimagePullSecrets: []\n# This is to override the chart name.\nnameOverride: \"\"\nfullnameOverride: \"\"\n\n# This section builds out the service account more information can be found here: https://kubernetes.io/docs/concepts/security/service-accounts/\nserviceAccount:\n  # Specifies whether a service account should be created\n  create: false\n  # Automatically mount a ServiceAccount's API credentials?\n  automount: false\n  # Annotations to add to the service account\n  annotations: {}\n  # The name of the service account to use.\n  # If not set and create is true, a name is generated using the fullname template\n  name: \"\"\n\n# This is for setting Kubernetes Annotations to a Pod.\n# For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/\npodAnnotations: {}\n# This is for setting Kubernetes Labels to a Pod.\n# For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/\npodLabels: {}\n\npodSecurityContext: {}\n  # fsGroup: 2000\n\nsecurityContext: {}\n  # capabilities:\n  #   drop:\n  #   - ALL\n  # readOnlyRootFilesystem: true\n  # runAsNonRoot: true\n  # runAsUser: 1000\n\n# This is for setting up a service more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/\nservice:\n  # This sets the service type more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types\n  type: ClusterIP\n  # This sets the ports more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/#field-spec-ports\n  # port: 80\n  ports:\n    admin: 11110\n    tcp: 11111\n    metric: 11112\n\n# This block is for setting up the ingress for more information can be found here: https://kubernetes.io/docs/concepts/services-networking/ingress/\ningress:\n  enabled: false\n  className: \"\"\n  annotations: {}\n    # kubernetes.io/ingress.class: nginx\n    # kubernetes.io/tls-acme: \"true\"\n  hosts:\n    - host: chart-example.local\n      paths:\n        - path: /\n          pathType: ImplementationSpecific\n  tls: []\n  #  - secretName: chart-example-tls\n  #    hosts:\n  #      - chart-example.local\n\nresources: {}\n  # We usually recommend not to specify default resources and to leave this as a conscious\n  # choice for the user. This also increases chances charts run on environments with little\n  # resources, such as Minikube. If you do want to specify resources, uncomment the following\n  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.\n  # limits:\n  #   cpu: 100m\n  #   memory: 128Mi\n  # requests:\n  #   cpu: 100m\n  #   memory: 128Mi\n\n# This is to setup the liveness and readiness probes more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/\nlivenessProbe:\n  httpGet:\n    path: /\n    port: metric\nreadinessProbe:\n  httpGet:\n    path: /\n    port: metric\n\n# This section is for setting up autoscaling more information can be found here: https://kubernetes.io/docs/concepts/workloads/autoscaling/\nautoscaling:\n  enabled: false\n  minReplicas: 1\n  maxReplicas: 100\n  targetCPUUtilizationPercentage: 80\n  # targetMemoryUtilizationPercentage: 80\n\n# Additional volumes on the output Deployment definition.\nvolumes: []\n# - name: foo\n#   secret:\n#     secretName: mysecret\n#     optional: false\n\n# Additional volumeMounts on the output Deployment definition.\nvolumeMounts: []\n# - name: foo\n#   mountPath: \"/etc/foo\"\n#   readOnly: true\n\nnodeSelector: {}\n\ntolerations: []\n\naffinity: {}\n\nserver:\n  config: |\n    canal.port = 11111\n    canal.metrics.pull.port = 11112\n\n    # register ip\n    canal.register.ip =\n\n    # canal admin config\n    canal.admin.manager = canal-admin.default:8089\n    canal.admin.port = 11110\n    canal.admin.user = admin\n    canal.admin.passwd = 4ACFE3202A5FF5CF467898FC58AAB1D615029441\n    # admin auto register\n    canal.admin.register.auto = true\n    canal.admin.register.cluster = default"
  },
  {
    "path": "charts/tests/admin-values.yaml",
    "content": "ingress:\n  enabled: true\n  hosts:\n    - host: admin.canal.com\n      paths:\n        - path: /\n          pathType: ImplementationSpecific\n\nadmin:\n  config: |\n    server:\n      port: 8089\n    spring:\n      jackson:\n        date-format: yyyy-MM-dd HH:mm:ss\n        time-zone: GMT+8\n    spring.datasource:\n      address: you_db_host:3306\n      database: canal_manager\n      username: ****\n      password: ****\n      driver-class-name: com.mysql.jdbc.Driver\n      url: jdbc:mysql://${spring.datasource.address}/${spring.datasource.database}?useUnicode=true&characterEncoding=UTF-8&useSSL=false&allowPublicKeyRetrieval=true\n      hikari:\n        maximum-pool-size: 30\n        minimum-idle: 1\n    canal:\n      adminUser: admin\n      adminPasswd: admin\n    debug: true\n    \nimage:\n  repository: registry.us-east-1.aliyuncs.com/sll0/canal-admin\n  tag: \"latest\""
  },
  {
    "path": "charts/tests/server-values.yaml",
    "content": "server:\n  config: |\n    canal.port = 11111\n    canal.metrics.pull.port = 11112\n\n    # register ip\n    canal.register.ip =\n\n    # canal admin config\n    canal.admin.manager = canal-admin.default:8089\n    canal.admin.port = 11110\n    canal.admin.user = admin\n    canal.admin.passwd = 4ACFE3202A5FF5CF467898FC58AAB1D615029441\n    # admin auto register\n    canal.admin.register.auto = true\n    canal.admin.register.cluster = default\n    \nimage:\n  repository: registry.us-east-1.aliyuncs.com/sll0/canal-server\n  tag: \"v1.1.8-alpha-3\""
  },
  {
    "path": "charts/tests/test.sh",
    "content": "#! /bin/bash\n\nhelm install canal-admin -f ./admin-values.yaml ../canal-admin --dry-run\n\nhelm install canal-server -f ./server-values.yaml ../canal-server --dry-run"
  },
  {
    "path": "client/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\" \">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>com.alibaba.otter</groupId>\n\t\t<artifactId>canal</artifactId>\n\t\t<version>1.1.9-SNAPSHOT</version>\n\t\t<relativePath>../pom.xml</relativePath>\n\t</parent>\n\t<groupId>com.alibaba.otter</groupId>\n\t<artifactId>canal.client</artifactId>\n\t<packaging>jar</packaging>\n\t<name>canal client module for otter ${project.version}</name>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.protocol</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>com.google.protobuf</groupId>\n\t\t\t<artifactId>protobuf-java</artifactId>\n\t\t</dependency>\n\n\t\t<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->\n\t\t<dependency>\n\t\t\t<groupId>io.netty</groupId>\n\t\t\t<artifactId>netty-all</artifactId>\n\t\t</dependency>\n\t\t<!-- zk -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.zookeeper</groupId>\n\t\t\t<artifactId>zookeeper</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.101tec</groupId>\n\t\t\t<artifactId>zkclient</artifactId>\n\t\t</dependency>\n\t\t<!-- external -->\n\t\t<dependency>\n\t\t\t<groupId>commons-io</groupId>\n\t\t\t<artifactId>commons-io</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>commons-lang</groupId>\n\t\t\t<artifactId>commons-lang</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>commons-codec</groupId>\n\t\t\t<artifactId>commons-codec</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.google.guava</groupId>\n\t\t\t<artifactId>guava</artifactId>\n\t\t</dependency>\n\t\t<!-- log -->\n\t\t<dependency>\n\t\t\t<groupId>ch.qos.logback</groupId>\n\t\t\t<artifactId>logback-core</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>ch.qos.logback</groupId>\n\t\t\t<artifactId>logback-classic</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>jcl-over-slf4j</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-core</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-aop</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-jdbc</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-orm</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-test</artifactId>\n\t\t\t<version>${spring_version}</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<!-- 客户端要使用请单独引入mq-clients依赖 -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.rocketmq</groupId>\n\t\t\t<artifactId>rocketmq-client</artifactId>\n\t\t\t<version>${rocketmq_version}</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.rocketmq</groupId>\n\t\t\t<artifactId>rocketmq-acl</artifactId>\n\t\t\t<version>${rocketmq_version}</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.rabbitmq</groupId>\n\t\t\t<artifactId>amqp-client</artifactId>\n\t\t\t<version>${rabbitmq_version}</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.mq-amqp</groupId>\n\t\t\t<artifactId>mq-amqp-client</artifactId>\n\t\t\t<version>${mq_amqp_client}</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.kafka</groupId>\n\t\t\t<artifactId>kafka-clients</artifactId>\n\t\t\t<version>${kafka_version}</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<!-- Pulsar -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.pulsar</groupId>\n\t\t\t<artifactId>pulsar-client</artifactId>\n\t\t\t<version>${pulsar_version}</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.pulsar</groupId>\n\t\t\t<artifactId>pulsar-client-admin</artifactId>\n\t\t\t<version>${pulsar_version}</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\n\t\t<!-- junit -->\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-shade-plugin</artifactId>\n\t\t\t\t<version>3.2.1</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<createDependencyReducedPom>false</createDependencyReducedPom>\n\t\t\t\t\t<artifactSet>\n\t\t\t\t\t\t<includes>\n\t\t\t\t\t\t\t<include>com.alibaba.otter:canal.client</include>\n\t\t\t\t\t\t\t<include>com.google.guava:*</include>\n\t\t\t\t\t\t\t<include>org.joda:*</include>\n\t\t\t\t\t\t\t<include>com.google.common:*</include>\n\t\t\t\t\t\t\t<include>com.google.thirdparty:*</include>\n\t\t\t\t\t\t</includes>\n\t\t\t\t\t</artifactSet>\n\t\t\t\t</configuration>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>shade</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<relocations>\n\t\t\t\t\t\t\t\t<relocation>\n\t\t\t\t\t\t\t\t\t<pattern>com.google.guava</pattern>\n\t\t\t\t\t\t\t\t\t<shadedPattern>com.alibaba.google.guava</shadedPattern>\n\t\t\t\t\t\t\t\t</relocation>\n\t\t\t\t\t\t\t\t<relocation>\n\t\t\t\t\t\t\t\t\t<pattern>org.joda</pattern>\n\t\t\t\t\t\t\t\t\t<shadedPattern>com.alibaba.google.joda</shadedPattern>\n\t\t\t\t\t\t\t\t</relocation>\n\t\t\t\t\t\t\t\t<relocation>\n\t\t\t\t\t\t\t\t\t<pattern>com.google.common</pattern>\n\t\t\t\t\t\t\t\t\t<shadedPattern>com.alibaba.google.common</shadedPattern>\n\t\t\t\t\t\t\t\t</relocation>\n\t\t\t\t\t\t\t\t<relocation>\n\t\t\t\t\t\t\t\t\t<pattern>com.google.thirdparty</pattern>\n\t\t\t\t\t\t\t\t\t<shadedPattern>com.alibaba.google.thirdparty</shadedPattern>\n\t\t\t\t\t\t\t\t</relocation>\n\t\t\t\t\t\t\t</relocations>\n\t\t\t\t\t\t\t<transformers>\n\t\t\t\t\t\t\t\t<transformer implementation=\"org.apache.maven.plugins.shade.resource.ManifestResourceTransformer\" />\n\t\t\t\t\t\t\t</transformers>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n\t<profiles>\n\t\t<profile>\n\t\t\t<id>dev</id>\n\t\t\t<activation>\n\t\t\t\t<activeByDefault>true</activeByDefault>\n\t\t\t\t<property>\n\t\t\t\t\t<name>env</name>\n\t\t\t\t\t<value>!javadoc</value>\n\t\t\t\t</property>\n\t\t\t</activation>\n\t\t</profile>\n\n\t\t<profile>\n\t\t\t<id>javadoc</id>\n\t\t\t<activation>\n\t\t\t\t<property>\n\t\t\t\t\t<name>env</name>\n\t\t\t\t\t<value>javadoc</value>\n\t\t\t\t</property>\n\t\t\t</activation>\n\t\t\t<build>\n\t\t\t\t<plugins>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t\t\t<artifactId>maven-javadoc-plugin</artifactId>\n\t\t\t\t\t\t<version>2.9.1</version>\n\t\t\t\t\t\t<executions>\n\t\t\t\t\t\t\t<execution>\n\t\t\t\t\t\t\t\t<id>attach-javadocs</id>\n\t\t\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t\t</execution>\n\t\t\t\t\t\t</executions>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<aggregate>true</aggregate>\n\t\t\t\t\t\t\t<show>public</show>\n\t\t\t\t\t\t\t<nohelp>true</nohelp>\n\t\t\t\t\t\t\t<header>${project.artifactId}-${project.version}</header>\n\t\t\t\t\t\t\t<footer>${project.artifactId}-${project.version}</footer>\n\t\t\t\t\t\t\t<doctitle>${project.artifactId}-${project.version}</doctitle>\n\t\t\t\t\t\t\t<links>\n\t\t\t\t\t\t\t\t<link>https://github.com/alibaba/canal</link>\n\t\t\t\t\t\t\t</links>\n\t\t\t\t\t\t\t<outputDirectory>${project.build.directory}/apidocs/apidocs/${project.version}</outputDirectory>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</plugin>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t\t\t<artifactId>maven-scm-publish-plugin</artifactId>\n\t\t\t\t\t\t<version>1.0-beta-2</version>\n\t\t\t\t\t\t<executions>\n\t\t\t\t\t\t\t<execution>\n\t\t\t\t\t\t\t\t<id>attach-javadocs</id>\n\t\t\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t<goal>publish-scm</goal>\n\t\t\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t\t</execution>\n\t\t\t\t\t\t</executions>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<checkoutDirectory>${project.build.directory}/scmpublish</checkoutDirectory>\n\t\t\t\t\t\t\t<checkinComment>Publishing javadoc for ${project.artifactId}:${project.version}</checkinComment>\n\t\t\t\t\t\t\t<content>${project.build.directory}/apidocs</content>\n\t\t\t\t\t\t\t<skipDeletedFiles>true</skipDeletedFiles>\n\t\t\t\t\t\t\t<pubScmUrl>scm:git:git@github.com:alibaba/canal.git</pubScmUrl>\n\t\t\t\t\t\t\t<scmBranch>gh-pages</scmBranch>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</plugin>\n\t\t\t\t</plugins>\n\t\t\t</build>\n\t\t</profile>\n\t</profiles>\n</project>\n"
  },
  {
    "path": "client/src/main/java/com/alibaba/otter/canal/client/CanalConnector.java",
    "content": "package com.alibaba.otter.canal.client;\n\nimport java.util.concurrent.TimeUnit;\n\nimport com.alibaba.otter.canal.protocol.Message;\nimport com.alibaba.otter.canal.protocol.exception.CanalClientException;\n\n/**\n * canal数据操作客户端\n * \n * @author zebin.xuzb @ 2012-6-19\n * @author jianghang\n * @version 1.0.0\n */\npublic interface CanalConnector {\n\n    /**\n     * 链接对应的canal server\n     * \n     * @throws CanalClientException\n     */\n    void connect() throws CanalClientException;\n\n    /**\n     * 释放链接\n     * \n     * @throws CanalClientException\n     */\n    void disconnect() throws CanalClientException;\n\n    /**\n     * 检查下链接是否合法\n     * \n     * <pre>\n     * 几种case下链接不合法:\n     * 1. 链接canal server失败，一直没有一个可用的链接，返回false\n     * 2. 当前客户端在进行running抢占的时候，做为备份节点存在，非处于工作节点，返回false\n     * \n     * 说明：\n     * a. 当前客户端一旦做为备份节点存在，当前所有的对{@linkplain CanalConnector}的操作都会处于阻塞状态，直到转为工作节点\n     * b. 所以业务方最好定时调用checkValid()方法用，比如调用CanalConnector所在线程的interrupt，直接退出CanalConnector，并根据自己的需要退出自己的资源\n     * </pre>\n     * \n     * @throws CanalClientException\n     */\n    boolean checkValid() throws CanalClientException;\n\n    /**\n     * 客户端订阅，重复订阅时会更新对应的filter信息\n     * \n     * <pre>\n     * 说明：\n     * a. 如果本次订阅中filter信息为空，则直接使用canal server服务端配置的filter信息\n     * b. 如果本次订阅中filter信息不为空，目前会直接替换canal server服务端配置的filter信息，以本次提交的为准\n     * \n     * TODO: 后续可以考虑，如果本次提交的filter不为空，在执行过滤时，是对canal server filter + 本次filter的交集处理，达到只取1份binlog数据，多个客户端消费不同的表\n     * </pre>\n     * \n     * @throws CanalClientException\n     */\n    void subscribe(String filter) throws CanalClientException;\n\n    /**\n     * 客户端订阅，不提交客户端filter，以服务端的filter为准\n     * \n     * @throws CanalClientException\n     */\n    void subscribe() throws CanalClientException;\n\n    /**\n     * 取消订阅\n     * \n     * @throws CanalClientException\n     */\n    void unsubscribe() throws CanalClientException;\n\n    /**\n     * 获取数据，自动进行确认，该方法返回的条件：尝试拿batchSize条记录，有多少取多少，不会阻塞等待\n     * \n     * @param batchSize\n     * @return\n     * @throws CanalClientException\n     */\n    Message get(int batchSize) throws CanalClientException;\n\n    /**\n     * 获取数据，自动进行确认\n     * \n     * <pre>\n     * 该方法返回的条件：\n     *  a. 拿够batchSize条记录或者超过timeout时间\n     *  b. 如果timeout=0，则阻塞至拿到batchSize记录才返回\n     * </pre>\n     * \n     * @param batchSize\n     * @return\n     * @throws CanalClientException\n     */\n    Message get(int batchSize, Long timeout, TimeUnit unit) throws CanalClientException;\n\n    /**\n     * 不指定 position 获取事件，该方法返回的条件: 尝试拿batchSize条记录，有多少取多少，不会阻塞等待<br/>\n     * canal 会记住此 client 最新的position。 <br/>\n     * 如果是第一次 fetch，则会从 canal 中保存的最老一条数据开始输出。\n     * \n     * @param batchSize\n     * @throws CanalClientException\n     */\n    Message getWithoutAck(int batchSize) throws CanalClientException;\n\n    /**\n     * 不指定 position 获取事件.\n     * \n     * <pre>\n     * 该方法返回的条件：\n     *  a. 拿够batchSize条记录或者超过timeout时间\n     *  b. 如果timeout=0，则阻塞至拿到batchSize记录才返回\n     * </pre>\n     * \n     * canal 会记住此 client 最新的position。 <br/>\n     * 如果是第一次 fetch，则会从 canal 中保存的最老一条数据开始输出。\n     * \n     * @param batchSize\n     * @param timeout\n     * @param unit\n     * @return\n     * @throws CanalClientException\n     */\n    Message getWithoutAck(int batchSize, Long timeout, TimeUnit unit) throws CanalClientException;\n\n    /**\n     * 进行 batch id 的确认。确认之后，小于等于此 batchId 的 Message 都会被确认。\n     * \n     * @param batchId\n     * @throws CanalClientException\n     */\n    void ack(long batchId) throws CanalClientException;\n\n    /**\n     * 回滚到未进行 {@link #ack} 的地方，指定回滚具体的batchId\n     * \n     * @throws CanalClientException\n     */\n    void rollback(long batchId) throws CanalClientException;\n\n    /**\n     * 回滚到未进行 {@link #ack} 的地方，下次fetch的时候，可以从最后一个没有 {@link #ack} 的地方开始拿\n     * \n     * @throws CanalClientException\n     */\n    void rollback() throws CanalClientException;\n}\n"
  },
  {
    "path": "client/src/main/java/com/alibaba/otter/canal/client/CanalConnectors.java",
    "content": "package com.alibaba.otter.canal.client;\n\nimport java.net.SocketAddress;\nimport java.util.List;\n\nimport com.alibaba.otter.canal.client.impl.ClusterCanalConnector;\nimport com.alibaba.otter.canal.client.impl.ClusterNodeAccessStrategy;\nimport com.alibaba.otter.canal.client.impl.SimpleCanalConnector;\nimport com.alibaba.otter.canal.client.impl.SimpleNodeAccessStrategy;\nimport com.alibaba.otter.canal.common.zookeeper.ZkClientx;\n\n/**\n * canal connectors创建工具类\n * \n * @author jianghang 2012-10-29 下午11:18:50\n * @version 1.0.0\n */\npublic class CanalConnectors {\n\n    /**\n     * 创建单链接的客户端链接\n     *\n     * @param address\n     * @param destination\n     * @param username\n     * @param password\n     * @return\n     */\n    public static CanalConnector newSingleConnector(SocketAddress address, String destination, String username,\n                                                    String password) {\n        SimpleCanalConnector canalConnector = new SimpleCanalConnector(address, username, password, destination);\n        canalConnector.setSoTimeout(60 * 1000);\n        canalConnector.setIdleTimeout(60 * 60 * 1000);\n        return canalConnector;\n    }\n\n    /**\n     * 创建带cluster模式的客户端链接，自动完成failover切换\n     *\n     * @param addresses\n     * @param destination\n     * @param username\n     * @param password\n     * @return\n     */\n    public static CanalConnector newClusterConnector(List<? extends SocketAddress> addresses, String destination,\n                                                     String username, String password) {\n        ClusterCanalConnector canalConnector = new ClusterCanalConnector(username,\n            password,\n            destination,\n            new SimpleNodeAccessStrategy(addresses));\n        canalConnector.setSoTimeout(60 * 1000);\n        canalConnector.setIdleTimeout(60 * 60 * 1000);\n        return canalConnector;\n    }\n\n    /**\n     * 创建带cluster模式的客户端链接，自动完成failover切换，服务器列表自动扫描\n     *\n     * @param zkServers\n     * @param destination\n     * @param username\n     * @param password\n     * @return\n     */\n    public static CanalConnector newClusterConnector(String zkServers, String destination, String username,\n                                                     String password) {\n        ClusterCanalConnector canalConnector = new ClusterCanalConnector(username,\n            password,\n            destination,\n            new ClusterNodeAccessStrategy(destination, ZkClientx.getZkClient(zkServers)));\n        canalConnector.setSoTimeout(60 * 1000);\n        canalConnector.setIdleTimeout(60 * 60 * 1000);\n        return canalConnector;\n    }\n}\n"
  },
  {
    "path": "client/src/main/java/com/alibaba/otter/canal/client/CanalMQConnector.java",
    "content": "package com.alibaba.otter.canal.client;\n\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport com.alibaba.otter.canal.protocol.FlatMessage;\nimport com.alibaba.otter.canal.protocol.Message;\nimport com.alibaba.otter.canal.protocol.exception.CanalClientException;\n\n/**\n * canal MQ数据操作客户端\n * \n * <pre>\n * 1. canal server写入MQ消息，考虑性能会合并多条数据写入为一个MQ消息，一个Message对应一个MQ消息\n * 2. canal client消费MQ消息，因为client性能会弱于server的写入，MQ数据获取时会拿到堆积的多条MQ消息，会拿到List<Message>\n * 3. client的ack/rollback，都是和MQ直接交互，不存在对应的batchId概念\n * </pre>\n * \n * @author agapple 2018年10月28日 下午6:42:27\n * @since 1.1.1\n */\npublic interface CanalMQConnector extends CanalConnector {\n\n    /**\n     * 获取数据，自动进行确认，设置timeout时间直到拿到数据为止\n     * \n     * <pre>\n     * 该方法返回的条件：\n     *  a. 如果timeout=0，有多少取多少，不会阻塞等待\n     *  b. 如果timeout不为0，尝试阻塞对应的超时时间，直到拿到数据就返回\n     * </pre>\n     * \n     * @return\n     * @throws CanalClientException\n     */\n    List<Message> getList(Long timeout, TimeUnit unit) throws CanalClientException;\n\n    /**\n     * 获取数据，设置timeout时间直到拿到数据为止\n     * \n     * <pre>\n     * 该方法返回的条件：\n     *  a. 如果timeout=0，有多少取多少，不会阻塞等待\n     *  b. 如果timeout不为0，尝试阻塞对应的超时时间，直到拿到数据就返回\n     * </pre>\n     * \n     * @throws CanalClientException\n     */\n    List<Message> getListWithoutAck(Long timeout, TimeUnit unit) throws CanalClientException;\n\n    /**\n     * 获取数据，自动进行确认，设置timeout时间直到拿到数据为止\n     * \n     * <pre>\n     * 该方法返回的条件：\n     *  a. 如果timeout=0，有多少取多少，不会阻塞等待\n     *  b. 如果timeout不为0，尝试阻塞对应的超时时间，直到拿到数据就返回\n     * </pre>\n     * \n     * @return\n     * @throws CanalClientException\n     */\n    List<FlatMessage> getFlatList(Long timeout, TimeUnit unit) throws CanalClientException;\n\n    /**\n     * 获取数据，设置timeout时间直到拿到数据为止\n     * \n     * <pre>\n     * 该方法返回的条件：\n     *  a. 如果timeout=0，有多少取多少，不会阻塞等待\n     *  b. 如果timeout不为0，尝试阻塞对应的超时时间，直到拿到数据就返回\n     * </pre>\n     * \n     * @throws CanalClientException\n     */\n    List<FlatMessage> getFlatListWithoutAck(Long timeout, TimeUnit unit) throws CanalClientException;\n\n    /**\n     * 消费确认。\n     * \n     * @throws CanalClientException\n     */\n    void ack() throws CanalClientException;\n\n    /**\n     * 回滚到未进行 {@link #ack} 的地方，下次fetch的时候，可以从最后一个没有 {@link #ack} 的地方开始拿\n     * \n     * @throws CanalClientException\n     */\n    void rollback() throws CanalClientException;\n}\n"
  },
  {
    "path": "client/src/main/java/com/alibaba/otter/canal/client/CanalMessageDeserializer.java",
    "content": "package com.alibaba.otter.canal.client;\n\nimport com.alibaba.otter.canal.protocol.CanalEntry;\nimport com.alibaba.otter.canal.protocol.CanalPacket;\nimport com.alibaba.otter.canal.protocol.CanalPacket.Ack;\nimport com.alibaba.otter.canal.protocol.CanalPacket.Compression;\nimport com.alibaba.otter.canal.protocol.Message;\nimport com.alibaba.otter.canal.protocol.exception.CanalClientException;\nimport com.google.protobuf.ByteString;\n\npublic class CanalMessageDeserializer {\n\n    public static Message deserializer(byte[] data) {\n        return deserializer(data, false);\n    }\n\n    public static Message deserializer(byte[] data, boolean lazyParseEntry) {\n        try {\n            if (data == null) {\n                return null;\n            } else {\n                CanalPacket.Packet p = CanalPacket.Packet.parseFrom(data);\n                switch (p.getType()) {\n                    case MESSAGES: {\n                        if (!p.getCompression().equals(Compression.NONE)\n                            && !p.getCompression().equals(Compression.COMPRESSIONCOMPATIBLEPROTO2)) {\n                            throw new CanalClientException(\"compression is not supported in this connector\");\n                        }\n\n                        CanalPacket.Messages messages = CanalPacket.Messages.parseFrom(p.getBody());\n                        Message result = new Message(messages.getBatchId());\n                        if (lazyParseEntry) {\n                            // byteString\n                            result.setRawEntries(messages.getMessagesList());\n                            result.setRaw(true);\n                        } else {\n                            for (ByteString byteString : messages.getMessagesList()) {\n                                result.addEntry(CanalEntry.Entry.parseFrom(byteString));\n                            }\n                            result.setRaw(false);\n                        }\n                        return result;\n                    }\n                    case ACK: {\n                        Ack ack = Ack.parseFrom(p.getBody());\n                        throw new CanalClientException(\"something goes wrong with reason: \" + ack.getErrorMessage());\n                    }\n                    default: {\n                        throw new CanalClientException(\"unexpected packet type: \" + p.getType());\n                    }\n                }\n            }\n        } catch (Exception e) {\n            throw new CanalClientException(\"deserializer failed by \" + e.getMessage(), e);\n        }\n    }\n}\n"
  },
  {
    "path": "client/src/main/java/com/alibaba/otter/canal/client/CanalNodeAccessStrategy.java",
    "content": "package com.alibaba.otter.canal.client;\n\nimport java.net.SocketAddress;\n\n/**\n * 集群节点访问控制接口\n * \n * @author jianghang 2012-10-29 下午07:55:41\n * @version 1.0.0\n */\npublic interface CanalNodeAccessStrategy {\n\n    SocketAddress currentNode();\n\n    SocketAddress nextNode();\n}\n"
  },
  {
    "path": "client/src/main/java/com/alibaba/otter/canal/client/ConsumerBatchMessage.java",
    "content": "package com.alibaba.otter.canal.client;\n\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\npublic class ConsumerBatchMessage<T> {\n\n    private final List<T>  data;\n    private CountDownLatch         latch;\n    private boolean                hasFailure = false;\n\n    public ConsumerBatchMessage(List<T> data){\n        this.data = data;\n        latch = new CountDownLatch(1);\n    }\n\n    public boolean waitFinish(long timeout) throws InterruptedException {\n        return latch.await(timeout, TimeUnit.MILLISECONDS);\n    }\n\n    public boolean isSuccess() {\n        return !hasFailure;\n    }\n\n    public List<T> getData() {\n        return data;\n    }\n\n    /**\n     * Countdown if the sub message is successful.\n     */\n    public void ack() {\n        latch.countDown();\n    }\n\n    /**\n     * Countdown and fail-fast if the sub message is failed.\n     */\n    public void fail() {\n        hasFailure = true;\n        // fail fast\n        long count = latch.getCount();\n        for (int i = 0; i < count; i++) {\n            latch.countDown();\n        }\n    }\n}\n"
  },
  {
    "path": "client/src/main/java/com/alibaba/otter/canal/client/impl/ClusterCanalConnector.java",
    "content": "package com.alibaba.otter.canal.client.impl;\n\nimport com.alibaba.otter.canal.client.CanalConnector;\nimport com.alibaba.otter.canal.client.CanalNodeAccessStrategy;\nimport com.alibaba.otter.canal.protocol.Message;\nimport com.alibaba.otter.canal.protocol.exception.CanalClientException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.net.SocketAddress;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * 集群版本connector实现，自带了failover功能<br/>\n *\n * @author jianghang 2012-10-29 下午08:04:06\n * @version 1.0.0\n */\npublic class ClusterCanalConnector implements CanalConnector {\n\n    private final Logger            logger        = LoggerFactory.getLogger(this.getClass());\n    private String                  username;\n    private String                  password;\n    private int                     soTimeout     = 60000;\n    private int                     idleTimeout   = 60 * 60 * 1000;\n    private int                     retryTimes    = 3;                                       // 设置-1时可以subscribe阻塞等待时优雅停机\n    private int                     retryInterval = 5000;                                    // 重试的时间间隔，默认5秒\n    private CanalNodeAccessStrategy accessStrategy;\n    private SimpleCanalConnector    currentConnector;\n    private String                  destination;\n    private String                  filter;                                                  // 记录上一次的filter提交值,便于自动重试时提交\n\n    public ClusterCanalConnector(String username, String password, String destination,\n                                 CanalNodeAccessStrategy accessStrategy){\n        this.username = username;\n        this.password = password;\n        this.destination = destination;\n        this.accessStrategy = accessStrategy;\n    }\n\n    @Override\n    public void connect() throws CanalClientException {\n        while (currentConnector == null) {\n            int times = 0;\n            while (true) {\n                try {\n                    currentConnector = new SimpleCanalConnector(null, username, password, destination) {\n\n                        @Override\n                        public SocketAddress getNextAddress() {\n                            return accessStrategy.nextNode();\n                        }\n\n                    };\n                    currentConnector.setSoTimeout(soTimeout);\n                    currentConnector.setIdleTimeout(idleTimeout);\n                    if (filter != null) {\n                        currentConnector.setFilter(filter);\n                    }\n                    if (accessStrategy instanceof ClusterNodeAccessStrategy) {\n                        currentConnector.setZkClientx(((ClusterNodeAccessStrategy) accessStrategy).getZkClient());\n                    }\n\n                    currentConnector.connect();\n                    break;\n                } catch (Exception e) {\n                    logger.warn(\"failed to connect to canal server after retry {} times\", times);\n                    currentConnector.disconnect();\n                    currentConnector = null;\n                    // retry for #retryTimes for each node when trying to\n                    // connect to it.\n                    times = times + 1;\n                    if (times >= retryTimes) {\n                        throw new CanalClientException(e);\n                    } else {\n                        // fixed issue #55，增加sleep控制，避免重试connect时cpu使用过高\n                        try {\n                            Thread.sleep(retryInterval);\n                        } catch (InterruptedException e1) {\n                            throw new CanalClientException(e1);\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    @Override\n    public boolean checkValid() {\n        return currentConnector != null && currentConnector.checkValid();\n    }\n\n    @Override\n    public void disconnect() throws CanalClientException {\n        if (currentConnector != null) {\n            currentConnector.disconnect();\n            currentConnector = null;\n        }\n    }\n\n    @Override\n    public void subscribe() throws CanalClientException {\n        subscribe(\"\"); // 传递空字符即可\n    }\n\n    @Override\n    public void subscribe(String filter) throws CanalClientException {\n        int times = 0;\n        while (times < retryTimes) {\n            try {\n                currentConnector.subscribe(filter);\n                this.filter = filter;\n                return;\n            } catch (Throwable t) {\n                if (retryTimes == -1 && t.getCause() instanceof InterruptedException) {\n                    logger.info(\"block waiting interrupted by other thread.\");\n                    return;\n                } else {\n                    logger.warn(String.format(\"something goes wrong when subscribing from server: %s\",\n                        currentConnector != null ? currentConnector.getAddress() : \"null\"), t);\n                    times++;\n                    restart();\n                    logger.info(\"restart the connector for next round retry.\");\n                }\n\n            }\n        }\n\n        throw new CanalClientException(\"failed to subscribe after \" + times + \" times retry.\");\n    }\n\n    @Override\n    public void unsubscribe() throws CanalClientException {\n        int times = 0;\n        while (times < retryTimes) {\n            try {\n                currentConnector.unsubscribe();\n                return;\n            } catch (Throwable t) {\n                logger.warn(String.format(\"something goes wrong when unsubscribing from server:%s\",\n                    currentConnector != null ? currentConnector.getAddress() : \"null\"), t);\n                times++;\n                restart();\n                logger.info(\"restart the connector for next round retry.\");\n            }\n        }\n        throw new CanalClientException(\"failed to unsubscribe after \" + times + \" times retry.\");\n    }\n\n    @Override\n    public Message get(int batchSize) throws CanalClientException {\n        int times = 0;\n        while (times < retryTimes) {\n            try {\n                Message msg = currentConnector.get(batchSize);\n                return msg;\n            } catch (Throwable t) {\n                logger.warn(String.format(\"something goes wrong when getting data from server:%s\",\n                    currentConnector != null ? currentConnector.getAddress() : \"null\"), t);\n                times++;\n                restart();\n                logger.info(\"restart the connector for next round retry.\");\n            }\n        }\n        throw new CanalClientException(\"failed to fetch the data after \" + times + \" times retry\");\n    }\n\n    @Override\n    public Message get(int batchSize, Long timeout, TimeUnit unit) throws CanalClientException {\n        int times = 0;\n        while (times < retryTimes) {\n            try {\n                Message msg = currentConnector.get(batchSize, timeout, unit);\n                return msg;\n            } catch (Throwable t) {\n                logger.warn(String.format(\"something goes wrong when getting data from server:%s\",\n                    currentConnector != null ? currentConnector.getAddress() : \"null\"), t);\n                times++;\n                restart();\n                logger.info(\"restart the connector for next round retry.\");\n            }\n        }\n        throw new CanalClientException(\"failed to fetch the data after \" + times + \" times retry\");\n    }\n\n    @Override\n    public Message getWithoutAck(int batchSize) throws CanalClientException {\n        int times = 0;\n        while (times < retryTimes) {\n            try {\n                Message msg = currentConnector.getWithoutAck(batchSize);\n                return msg;\n            } catch (Throwable t) {\n                logger.warn(String.format(\"something goes wrong when getWithoutAck data from server:%s\",\n                    currentConnector != null ? currentConnector.getAddress() : \"null\"), t);\n                times++;\n                restart();\n                logger.info(\"restart the connector for next round retry.\");\n            }\n        }\n        throw new CanalClientException(\"failed to fetch the data after \" + times + \" times retry\");\n    }\n\n    @Override\n    public Message getWithoutAck(int batchSize, Long timeout, TimeUnit unit) throws CanalClientException {\n        int times = 0;\n        while (times < retryTimes) {\n            try {\n                Message msg = currentConnector.getWithoutAck(batchSize, timeout, unit);\n                return msg;\n            } catch (Throwable t) {\n                logger.warn(String.format(\"something goes wrong when getWithoutAck data from server:%s\",\n                    currentConnector != null ? currentConnector.getAddress() : \"null\"), t);\n                times++;\n                restart();\n                logger.info(\"restart the connector for next round retry.\");\n            }\n        }\n        throw new CanalClientException(\"failed to fetch the data after \" + times + \" times retry\");\n    }\n\n    @Override\n    public void rollback(long batchId) throws CanalClientException {\n        int times = 0;\n        while (times < retryTimes) {\n            try {\n                currentConnector.rollback(batchId);\n                return;\n            } catch (Throwable t) {\n                logger.warn(String.format(\"something goes wrong when rollbacking data from server:%s\",\n                    currentConnector != null ? currentConnector.getAddress() : \"null\"), t);\n                times++;\n                restart();\n                logger.info(\"restart the connector for next round retry.\");\n            }\n        }\n        throw new CanalClientException(\"failed to rollback after \" + times + \" times retry\");\n    }\n\n    @Override\n    public void rollback() throws CanalClientException {\n        int times = 0;\n        while (times < retryTimes) {\n            try {\n                currentConnector.rollback();\n                return;\n            } catch (Throwable t) {\n                logger.warn(String.format(\"something goes wrong when rollbacking data from server:%s\",\n                    currentConnector != null ? currentConnector.getAddress() : \"null\"), t);\n                times++;\n                restart();\n                logger.info(\"restart the connector for next round retry.\");\n            }\n        }\n\n        throw new CanalClientException(\"failed to rollback after \" + times + \" times retry\");\n    }\n\n    @Override\n    public void ack(long batchId) throws CanalClientException {\n        int times = 0;\n        while (times < retryTimes) {\n            try {\n                currentConnector.ack(batchId);\n                return;\n            } catch (Throwable t) {\n                logger.warn(String.format(\"something goes wrong when acking data from server:%s\",\n                    currentConnector != null ? currentConnector.getAddress() : \"null\"), t);\n                times++;\n                restart();\n                logger.info(\"restart the connector for next round retry.\");\n            }\n        }\n\n        throw new CanalClientException(\"failed to ack after \" + times + \" times retry\");\n    }\n\n    private void restart() throws CanalClientException {\n        disconnect();\n        try {\n            Thread.sleep(retryInterval);\n        } catch (InterruptedException e) {\n            throw new CanalClientException(e);\n        }\n        connect();\n    }\n\n    // ============================= setter / getter\n    // ============================\n\n    public String getUsername() {\n        return username;\n    }\n\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    public int getSoTimeout() {\n        return soTimeout;\n    }\n\n    public void setSoTimeout(int soTimeout) {\n        this.soTimeout = soTimeout;\n    }\n\n    public int getIdleTimeout() {\n        return idleTimeout;\n    }\n\n    public void setIdleTimeout(int idleTimeout) {\n        this.idleTimeout = idleTimeout;\n    }\n\n    public int getRetryTimes() {\n        return retryTimes;\n    }\n\n    public void setRetryTimes(int retryTimes) {\n        this.retryTimes = retryTimes;\n    }\n\n    public int getRetryInterval() {\n        return retryInterval;\n    }\n\n    public void setRetryInterval(int retryInterval) {\n        this.retryInterval = retryInterval;\n    }\n\n    public CanalNodeAccessStrategy getAccessStrategy() {\n        return accessStrategy;\n    }\n\n    public void setAccessStrategy(CanalNodeAccessStrategy accessStrategy) {\n        this.accessStrategy = accessStrategy;\n    }\n\n    public SimpleCanalConnector getCurrentConnector() {\n        return currentConnector;\n    }\n\n    public void stopRunning() {\n        currentConnector.stopRunning();\n    }\n\n}\n"
  },
  {
    "path": "client/src/main/java/com/alibaba/otter/canal/client/impl/ClusterNodeAccessStrategy.java",
    "content": "package com.alibaba.otter.canal.client.impl;\n\nimport java.net.InetSocketAddress;\nimport java.net.SocketAddress;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.I0Itec.zkclient.IZkChildListener;\nimport org.I0Itec.zkclient.IZkDataListener;\nimport org.apache.commons.lang.StringUtils;\n\nimport com.alibaba.otter.canal.client.CanalNodeAccessStrategy;\nimport com.alibaba.otter.canal.common.utils.JsonUtils;\nimport com.alibaba.otter.canal.common.zookeeper.ZkClientx;\nimport com.alibaba.otter.canal.common.zookeeper.ZookeeperPathUtils;\nimport com.alibaba.otter.canal.common.zookeeper.running.ServerRunningData;\n\n/**\n * 集群模式的调度策略\n * \n * @author jianghang 2012-12-3 下午10:01:04\n * @version 1.0.0\n */\npublic class ClusterNodeAccessStrategy implements CanalNodeAccessStrategy {\n\n    private String                           destination;\n    private IZkChildListener                 childListener;                                      // 监听所有的服务器列表\n    private IZkDataListener                  dataListener;                                       // 监听当前的工作节点\n    private ZkClientx                        zkClient;\n    private volatile List<InetSocketAddress> currentAddress = new ArrayList<>();\n    private volatile InetSocketAddress       runningAddress = null;\n\n    public ClusterNodeAccessStrategy(String destination, ZkClientx zkClient){\n        this.destination = destination;\n        this.zkClient = zkClient;\n        // handleChildChange\n        childListener = (parentPath, currentChilds) -> initClusters(currentChilds);\n\n        dataListener = new IZkDataListener() {\n\n            public void handleDataDeleted(String dataPath) throws Exception {\n                runningAddress = null;\n            }\n\n            public void handleDataChange(String dataPath, Object data) throws Exception {\n                initRunning(data);\n            }\n\n        };\n\n        String clusterPath = ZookeeperPathUtils.getDestinationClusterRoot(destination);\n        this.zkClient.subscribeChildChanges(clusterPath, childListener);\n        initClusters(this.zkClient.getChildren(clusterPath));\n\n        String runningPath = ZookeeperPathUtils.getDestinationServerRunning(destination);\n        this.zkClient.subscribeDataChanges(runningPath, dataListener);\n        initRunning(this.zkClient.readData(runningPath, true));\n    }\n\n    @Override\n    public SocketAddress currentNode() {\n        return nextNode();\n    }\n\n    @Override\n    public SocketAddress nextNode() {\n        if (runningAddress != null) {// 如果服务已经启动，直接选择当前正在工作的节点\n            return runningAddress;\n        } else if (!currentAddress.isEmpty()) { // 如果不存在已经启动的服务，可能服务是一种lazy启动，随机选择一台触发服务器进行启动\n            return currentAddress.get(0);// 默认返回第一个节点，之前已经做过shuffle\n        } else {\n            throw new ServerNotFoundException(\"no alive canal server for \" + destination);\n        }\n    }\n\n    private void initClusters(List<String> currentChilds) {\n        if (currentChilds == null || currentChilds.isEmpty()) {\n            currentAddress = new ArrayList<>();\n        } else {\n            List<InetSocketAddress> addresses = new ArrayList<>();\n            for (String address : currentChilds) {\n                String[] strs = StringUtils.split(address, \":\");\n                if (strs != null && strs.length == 2) {\n                    addresses.add(new InetSocketAddress(strs[0], Integer.parseInt(strs[1])));\n                }\n            }\n\n            Collections.shuffle(addresses);\n            currentAddress = addresses;// 直接切换引用\n        }\n    }\n\n    private void initRunning(Object data) {\n        if (data == null) {\n            return;\n        }\n\n        ServerRunningData runningData = JsonUtils.unmarshalFromByte((byte[]) data, ServerRunningData.class);\n        String[] strs = StringUtils.split(runningData.getAddress(), ':');\n        if (strs.length == 2) {\n            runningAddress = new InetSocketAddress(strs[0], Integer.parseInt(strs[1]));\n        }\n    }\n\n    public void setZkClient(ZkClientx zkClient) {\n        this.zkClient = zkClient;\n    }\n\n    public ZkClientx getZkClient() {\n        return zkClient;\n    }\n\n}\n"
  },
  {
    "path": "client/src/main/java/com/alibaba/otter/canal/client/impl/ServerNotFoundException.java",
    "content": "package com.alibaba.otter.canal.client.impl;\n\nimport com.alibaba.otter.canal.protocol.exception.CanalClientException;\n\npublic class ServerNotFoundException extends CanalClientException {\n\n    private static final long serialVersionUID = -3471518241911601774L;\n\n    public ServerNotFoundException(String errorCode, String errorDesc, Throwable cause){\n        super(errorCode, errorDesc, cause);\n    }\n\n    public ServerNotFoundException(String errorCode, String errorDesc){\n        super(errorCode, errorDesc);\n    }\n\n    public ServerNotFoundException(String errorCode, Throwable cause){\n        super(errorCode, cause);\n    }\n\n    public ServerNotFoundException(String errorCode){\n        super(errorCode);\n    }\n\n    public ServerNotFoundException(Throwable cause){\n        super(cause);\n    }\n\n}\n"
  },
  {
    "path": "client/src/main/java/com/alibaba/otter/canal/client/impl/SimpleCanalConnector.java",
    "content": "package com.alibaba.otter.canal.client.impl;\n\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.net.SocketAddress;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.channels.Channel;\nimport java.nio.channels.Channels;\nimport java.nio.channels.ReadableByteChannel;\nimport java.nio.channels.SocketChannel;\nimport java.nio.channels.WritableByteChannel;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.client.CanalConnector;\nimport com.alibaba.otter.canal.client.CanalMessageDeserializer;\nimport com.alibaba.otter.canal.client.impl.running.ClientRunningData;\nimport com.alibaba.otter.canal.client.impl.running.ClientRunningListener;\nimport com.alibaba.otter.canal.client.impl.running.ClientRunningMonitor;\nimport com.alibaba.otter.canal.common.utils.AddressUtils;\nimport com.alibaba.otter.canal.common.utils.BooleanMutex;\nimport com.alibaba.otter.canal.common.zookeeper.ZkClientx;\nimport com.alibaba.otter.canal.protocol.CanalPacket.Ack;\nimport com.alibaba.otter.canal.protocol.CanalPacket.ClientAck;\nimport com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth;\nimport com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback;\nimport com.alibaba.otter.canal.protocol.CanalPacket.Compression;\nimport com.alibaba.otter.canal.protocol.CanalPacket.Get;\nimport com.alibaba.otter.canal.protocol.CanalPacket.Handshake;\nimport com.alibaba.otter.canal.protocol.CanalPacket.Packet;\nimport com.alibaba.otter.canal.protocol.CanalPacket.PacketType;\nimport com.alibaba.otter.canal.protocol.CanalPacket.Sub;\nimport com.alibaba.otter.canal.protocol.CanalPacket.Unsub;\nimport com.alibaba.otter.canal.protocol.ClientIdentity;\nimport com.alibaba.otter.canal.protocol.Message;\nimport com.alibaba.otter.canal.protocol.SecurityUtil;\nimport com.alibaba.otter.canal.protocol.exception.CanalClientException;\nimport com.google.protobuf.ByteString;\n\n/**\n * 基于{@linkplain CanalServerWithNetty}定义的网络协议接口，对于canal数据进行get/rollback/ack等操作\n *\n * @author jianghang 2012-10-24 下午05:37:20\n * @version 1.0.0\n */\npublic class SimpleCanalConnector implements CanalConnector {\n\n    private static final Logger  logger                = LoggerFactory.getLogger(SimpleCanalConnector.class);\n    private SocketAddress        address;\n    private String               username;\n    private String               password;\n    private int                  soTimeout             = 60000;                                              // milliseconds\n    private int                  idleTimeout           = 60 * 60 * 1000;                                     // client和server之间的空闲链接超时的时间,默认为1小时\n    private String               filter;                                                                     // 记录上一次的filter提交值,便于自动重试时提交\n\n    private final ByteBuffer     readHeader            = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN);\n    private final ByteBuffer     writeHeader           = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN);\n    private SocketChannel        channel;\n    private ReadableByteChannel  readableChannel;\n    private WritableByteChannel  writableChannel;\n    private List<Compression>    supportedCompressions = new ArrayList<>();\n    private ClientIdentity       clientIdentity;\n    private ClientRunningMonitor runningMonitor;                                                             // 运行控制\n    private ZkClientx            zkClientx;\n    private BooleanMutex         mutex                 = new BooleanMutex(false);\n    private volatile boolean     connected             = false;                                              // 代表connected是否已正常执行，因为有HA，不代表在工作中\n    private boolean              rollbackOnConnect     = true;                                               // 是否在connect链接成功后，自动执行rollback操作\n    private boolean              rollbackOnDisConnect  = false;                                              // 是否在connect链接成功后，自动执行rollback操作\n    private boolean              lazyParseEntry        = false;                                              // 是否自动化解析Entry对象,如果考虑最大化性能可以延后解析\n    // 读写数据分别使用不同的锁进行控制，减小锁粒度,读也需要排他锁，并发度容易造成数据包混乱，反序列化失败\n    private Object               readDataLock          = new Object();\n    private Object               writeDataLock         = new Object();\n\n    private volatile boolean     running               = false;\n\n    public SimpleCanalConnector(SocketAddress address, String username, String password, String destination){\n        this(address, username, password, destination, 60000, 60 * 60 * 1000);\n    }\n\n    public SimpleCanalConnector(SocketAddress address, String username, String password, String destination,\n                                int soTimeout){\n        this(address, username, password, destination, soTimeout, 60 * 60 * 1000);\n    }\n\n    public SimpleCanalConnector(SocketAddress address, String username, String password, String destination,\n                                int soTimeout, int idleTimeout){\n        this.address = address;\n        this.username = username;\n        this.password = password;\n        this.soTimeout = soTimeout;\n        this.idleTimeout = idleTimeout;\n        this.clientIdentity = new ClientIdentity(destination, (short) 1001);\n    }\n\n    @Override\n    public void connect() throws CanalClientException {\n        if (connected) {\n            return;\n        }\n\n        if (runningMonitor != null) {\n            if (!runningMonitor.isStart()) {\n                runningMonitor.start();\n            }\n        } else {\n            waitClientRunning();\n            if (!running) {\n                return;\n            }\n            doConnect();\n            if (filter != null) { // 如果存在条件，说明是自动切换，基于上一次的条件订阅一次\n                subscribe(filter);\n            }\n            if (rollbackOnConnect) {\n                rollback();\n            }\n        }\n\n        connected = true;\n    }\n\n    @Override\n    public void disconnect() throws CanalClientException {\n        if (rollbackOnDisConnect && channel.isConnected()) {\n            rollback();\n        }\n\n        connected = false;\n        if (runningMonitor != null) {\n            if (runningMonitor.isStart()) {\n                runningMonitor.stop();\n            }\n        } else {\n            doDisconnect();\n        }\n    }\n\n    private InetSocketAddress doConnect() throws CanalClientException {\n        try {\n            channel = SocketChannel.open();\n            channel.socket().setSoTimeout(soTimeout);\n            SocketAddress address = getAddress();\n            if (address == null) {\n                address = getNextAddress();\n            }\n            channel.connect(address);\n            readableChannel = Channels.newChannel(channel.socket().getInputStream());\n            writableChannel = Channels.newChannel(channel.socket().getOutputStream());\n            Packet p = Packet.parseFrom(readNextPacket());\n            if (p.getVersion() != 1) {\n                throw new CanalClientException(\"unsupported version at this client.\");\n            }\n\n            if (p.getType() != PacketType.HANDSHAKE) {\n                throw new CanalClientException(\"expect handshake but found other type.\");\n            }\n            //\n            Handshake handshake = Handshake.parseFrom(p.getBody());\n            supportedCompressions.add(handshake.getSupportedCompressions());\n            //\n            ByteString seed = handshake.getSeeds(); // seed for auth\n            String newPasswd = password;\n            if (password != null) {\n                // encode passwd\n                newPasswd = SecurityUtil.byte2HexStr(SecurityUtil.scramble411(password.getBytes(), seed.toByteArray()));\n            }\n\n            ClientAuth ca = ClientAuth.newBuilder()\n                .setUsername(username != null ? username : \"\")\n                .setPassword(ByteString.copyFromUtf8(newPasswd != null ? newPasswd : \"\"))\n                .setNetReadTimeout(idleTimeout)\n                .setNetWriteTimeout(idleTimeout)\n                .build();\n            writeWithHeader(Packet.newBuilder()\n                .setType(PacketType.CLIENTAUTHENTICATION)\n                .setBody(ca.toByteString())\n                .build()\n                .toByteArray());\n            //\n            Packet ack = Packet.parseFrom(readNextPacket());\n            if (ack.getType() != PacketType.ACK) {\n                throw new CanalClientException(\"unexpected packet type when ack is expected\");\n            }\n\n            Ack ackBody = Ack.parseFrom(ack.getBody());\n            if (ackBody.getErrorCode() > 0) {\n                throw new CanalClientException(\"something goes wrong when doing authentication: \"\n                                               + ackBody.getErrorMessage());\n            }\n\n            connected = true;\n            return new InetSocketAddress(channel.socket().getLocalAddress(), channel.socket().getLocalPort());\n        } catch (IOException | NoSuchAlgorithmException e) {\n            throw new CanalClientException(e);\n        }\n    }\n\n    private void doDisconnect() throws CanalClientException {\n        if (readableChannel != null) {\n            quietlyClose(readableChannel);\n            readableChannel = null;\n        }\n        if (writableChannel != null) {\n            quietlyClose(writableChannel);\n            writableChannel = null;\n        }\n        if (channel != null) {\n            quietlyClose(channel);\n            channel = null;\n        }\n    }\n\n    private void quietlyClose(Channel channel) {\n        try {\n            channel.close();\n        } catch (IOException e) {\n            logger.warn(\"exception on closing channel:{} \\n {}\", channel, e);\n        }\n    }\n\n    @Override\n    public void subscribe() throws CanalClientException {\n        subscribe(\"\"); // 传递空字符即可\n    }\n\n    @Override\n    public void subscribe(String filter) throws CanalClientException {\n        waitClientRunning();\n        if (!running) {\n            return;\n        }\n        try {\n            writeWithHeader(Packet.newBuilder()\n                .setType(PacketType.SUBSCRIPTION)\n                .setBody(Sub.newBuilder()\n                    .setDestination(clientIdentity.getDestination())\n                    .setClientId(String.valueOf(clientIdentity.getClientId()))\n                    .setFilter(filter != null ? filter : \"\")\n                    .build()\n                    .toByteString())\n                .build()\n                .toByteArray());\n            //\n            Packet p = Packet.parseFrom(readNextPacket());\n            Ack ack = Ack.parseFrom(p.getBody());\n            if (ack.getErrorCode() > 0) {\n                throw new CanalClientException(\"failed to subscribe with reason: \" + ack.getErrorMessage());\n            }\n\n            clientIdentity.setFilter(filter);\n        } catch (IOException e) {\n            throw new CanalClientException(e);\n        }\n    }\n\n    @Override\n    public void unsubscribe() throws CanalClientException {\n        waitClientRunning();\n        if (!running) {\n            return;\n        }\n        try {\n            writeWithHeader(Packet.newBuilder()\n                .setType(PacketType.UNSUBSCRIPTION)\n                .setBody(Unsub.newBuilder()\n                    .setDestination(clientIdentity.getDestination())\n                    .setClientId(String.valueOf(clientIdentity.getClientId()))\n                    .build()\n                    .toByteString())\n                .build()\n                .toByteArray());\n            //\n            Packet p = Packet.parseFrom(readNextPacket());\n            Ack ack = Ack.parseFrom(p.getBody());\n            if (ack.getErrorCode() > 0) {\n                throw new CanalClientException(\"failed to unSubscribe with reason: \" + ack.getErrorMessage());\n            }\n        } catch (IOException e) {\n            throw new CanalClientException(e);\n        }\n    }\n\n    @Override\n    public Message get(int batchSize) throws CanalClientException {\n        return get(batchSize, null, null);\n    }\n\n    @Override\n    public Message get(int batchSize, Long timeout, TimeUnit unit) throws CanalClientException {\n        Message message = getWithoutAck(batchSize, timeout, unit);\n        ack(message.getId());\n        return message;\n    }\n\n    @Override\n    public Message getWithoutAck(int batchSize) throws CanalClientException {\n        return getWithoutAck(batchSize, null, null);\n    }\n\n    @Override\n    public Message getWithoutAck(int batchSize, Long timeout, TimeUnit unit) throws CanalClientException {\n        waitClientRunning();\n        if (!running) {\n            return null;\n        }\n        try {\n            int size = (batchSize <= 0) ? 1000 : batchSize;\n            long time = (timeout == null || timeout < 0) ? -1 : timeout; // -1代表不做timeout控制\n            if (unit == null) {\n                unit = TimeUnit.MILLISECONDS;\n            }\n\n            writeWithHeader(Packet.newBuilder()\n                .setType(PacketType.GET)\n                .setBody(Get.newBuilder()\n                    .setAutoAck(false)\n                    .setDestination(clientIdentity.getDestination())\n                    .setClientId(String.valueOf(clientIdentity.getClientId()))\n                    .setFetchSize(size)\n                    .setTimeout(time)\n                    .setUnit(unit.ordinal())\n                    .build()\n                    .toByteString())\n                .build()\n                .toByteArray());\n            return receiveMessages();\n        } catch (IOException e) {\n            throw new CanalClientException(e);\n        }\n    }\n\n    private Message receiveMessages() throws IOException {\n        byte[] data = readNextPacket();\n        return CanalMessageDeserializer.deserializer(data, lazyParseEntry);\n    }\n\n    @Override\n    public void ack(long batchId) throws CanalClientException {\n        waitClientRunning();\n        if (!running) {\n            return;\n        }\n        ClientAck ca = ClientAck.newBuilder()\n            .setDestination(clientIdentity.getDestination())\n            .setClientId(String.valueOf(clientIdentity.getClientId()))\n            .setBatchId(batchId)\n            .build();\n        try {\n            writeWithHeader(Packet.newBuilder()\n                .setType(PacketType.CLIENTACK)\n                .setBody(ca.toByteString())\n                .build()\n                .toByteArray());\n        } catch (IOException e) {\n            throw new CanalClientException(e);\n        }\n    }\n\n    @Override\n    public void rollback(long batchId) throws CanalClientException {\n        waitClientRunning();\n        ClientRollback ca = ClientRollback.newBuilder()\n            .setDestination(clientIdentity.getDestination())\n            .setClientId(String.valueOf(clientIdentity.getClientId()))\n            .setBatchId(batchId)\n            .build();\n        try {\n            writeWithHeader(Packet.newBuilder()\n                .setType(PacketType.CLIENTROLLBACK)\n                .setBody(ca.toByteString())\n                .build()\n                .toByteArray());\n        } catch (IOException e) {\n            throw new CanalClientException(e);\n        }\n    }\n\n    @Override\n    public void rollback() throws CanalClientException {\n        waitClientRunning();\n        rollback(0); // 0 代表未设置\n    }\n\n    // ==================== helper method ====================\n\n    private void writeWithHeader(byte[] body) throws IOException {\n        writeWithHeader(writableChannel, body);\n    }\n\n    private byte[] readNextPacket() throws IOException {\n        return readNextPacket(readableChannel);\n    }\n\n    private void writeWithHeader(WritableByteChannel channel, byte[] body) throws IOException {\n        synchronized (writeDataLock) {\n            writeHeader.clear();\n            writeHeader.putInt(body.length);\n            writeHeader.flip();\n            channel.write(writeHeader);\n            channel.write(ByteBuffer.wrap(body));\n        }\n    }\n\n    private byte[] readNextPacket(ReadableByteChannel channel) throws IOException {\n        synchronized (readDataLock) {\n            readHeader.clear();\n            read(channel, readHeader);\n            int bodyLen = readHeader.getInt(0);\n            ByteBuffer bodyBuf = ByteBuffer.allocate(bodyLen).order(ByteOrder.BIG_ENDIAN);\n            read(channel, bodyBuf);\n            return bodyBuf.array();\n        }\n    }\n\n    private void read(ReadableByteChannel channel, ByteBuffer buffer) throws IOException {\n        while (buffer.hasRemaining()) {\n            int r = channel.read(buffer);\n            if (r == -1) {\n                throw new IOException(\"end of stream when reading header\");\n            }\n        }\n    }\n\n    private synchronized void initClientRunningMonitor(ClientIdentity clientIdentity) {\n        if (zkClientx != null && clientIdentity != null && runningMonitor == null) {\n            ClientRunningData clientData = new ClientRunningData();\n            clientData.setClientId(clientIdentity.getClientId());\n            clientData.setAddress(AddressUtils.getHostIp());\n\n            runningMonitor = new ClientRunningMonitor();\n            runningMonitor.setDestination(clientIdentity.getDestination());\n            runningMonitor.setZkClient(zkClientx);\n            runningMonitor.setClientData(clientData);\n            runningMonitor.setListener(new ClientRunningListener() {\n\n                public InetSocketAddress processActiveEnter() {\n                    InetSocketAddress address = doConnect();\n                    mutex.set(true);\n                    if (filter != null) { // 如果存在条件，说明是自动切换，基于上一次的条件订阅一次\n                        subscribe(filter);\n                    }\n\n                    if (rollbackOnConnect) {\n                        rollback();\n                    }\n\n                    return address;\n                }\n\n                public void processActiveExit() {\n                    mutex.set(false);\n                    doDisconnect();\n                }\n\n            });\n        }\n    }\n\n    private void waitClientRunning() {\n        try {\n            if (zkClientx != null) {\n                if (!connected) {// 未调用connect\n                    throw new CanalClientException(\"should connect first\");\n                }\n\n                running = true;\n                mutex.get();// 阻塞等待\n            } else {\n                // 单机模式直接设置为running\n                running = true;\n            }\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            throw new CanalClientException(e);\n        }\n    }\n\n    public boolean checkValid() {\n        if (zkClientx != null) {\n            return mutex.state();\n        } else {\n            return true;// 默认都放过\n        }\n    }\n\n    public SocketAddress getNextAddress() {\n        return null;\n    }\n\n    public SocketAddress getAddress() {\n        return address;\n    }\n\n    public String getUsername() {\n        return username;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public int getSoTimeout() {\n        return soTimeout;\n    }\n\n    public void setSoTimeout(int soTimeout) {\n        this.soTimeout = soTimeout;\n    }\n\n    public int getIdleTimeout() {\n        return idleTimeout;\n    }\n\n    public void setIdleTimeout(int idleTimeout) {\n        this.idleTimeout = idleTimeout;\n    }\n\n    public void setZkClientx(ZkClientx zkClientx) {\n        this.zkClientx = zkClientx;\n        initClientRunningMonitor(this.clientIdentity);\n    }\n\n    public void setRollbackOnConnect(boolean rollbackOnConnect) {\n        this.rollbackOnConnect = rollbackOnConnect;\n    }\n\n    public void setRollbackOnDisConnect(boolean rollbackOnDisConnect) {\n        this.rollbackOnDisConnect = rollbackOnDisConnect;\n    }\n\n    public void setFilter(String filter) {\n        this.filter = filter;\n    }\n\n    public boolean isLazyParseEntry() {\n        return lazyParseEntry;\n    }\n\n    public void setLazyParseEntry(boolean lazyParseEntry) {\n        this.lazyParseEntry = lazyParseEntry;\n    }\n\n    public void stopRunning() {\n        if (running) {\n            running = false; // 设置为非running状态\n            if (!mutex.state()) {\n                mutex.set(true); // 中断阻塞\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "client/src/main/java/com/alibaba/otter/canal/client/impl/SimpleNodeAccessStrategy.java",
    "content": "package com.alibaba.otter.canal.client.impl;\n\nimport java.net.SocketAddress;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport com.alibaba.otter.canal.client.CanalNodeAccessStrategy;\n\n/**\n * 简单版本的node访问实现\n * \n * @author jianghang 2012-10-29 下午08:00:23\n * @version 1.0.0\n */\npublic class SimpleNodeAccessStrategy implements CanalNodeAccessStrategy {\n\n    private List<SocketAddress> nodes = new ArrayList<>();\n    private int                 index = 0;\n\n    public SimpleNodeAccessStrategy(List<? extends SocketAddress> nodes){\n        if (nodes == null || nodes.size() < 1) {\n            throw new IllegalArgumentException(\"at least 1 node required.\");\n        }\n        this.nodes.addAll(nodes);\n    }\n\n    @Override\n    public SocketAddress nextNode() {\n        try {\n            return nodes.get(index);\n        } finally {\n            index = (index + 1) % nodes.size();\n        }\n    }\n\n    @Override\n    public SocketAddress currentNode() {\n        return nodes.get(index);\n    }\n\n}\n"
  },
  {
    "path": "client/src/main/java/com/alibaba/otter/canal/client/impl/running/ClientRunningData.java",
    "content": "package com.alibaba.otter.canal.client.impl.running;\n\n/**\n * client running状态信息\n * \n * @author jianghang 2012-11-22 下午03:41:50\n * @version 1.0.0\n */\npublic class ClientRunningData {\n\n    private short   clientId;\n    private String  address;\n    private boolean active = true;\n\n    public short getClientId() {\n        return clientId;\n    }\n\n    public void setClientId(short clientId) {\n        this.clientId = clientId;\n    }\n\n    public String getAddress() {\n        return address;\n    }\n\n    public void setAddress(String address) {\n        this.address = address;\n    }\n\n    public boolean isActive() {\n        return active;\n    }\n\n    public void setActive(boolean active) {\n        this.active = active;\n    }\n\n}\n"
  },
  {
    "path": "client/src/main/java/com/alibaba/otter/canal/client/impl/running/ClientRunningListener.java",
    "content": "package com.alibaba.otter.canal.client.impl.running;\n\nimport java.net.InetSocketAddress;\n\n/**\n * 触发一下mainstem发生切换\n * \n * @author jianghang 2012-9-11 下午02:26:03\n * @version 1.0.0\n */\npublic interface ClientRunningListener {\n\n    /**\n     * 触发现在轮到自己做为active，需要载入上一个active的上下文数据\n     */\n    public InetSocketAddress processActiveEnter();\n\n    /**\n     * 触发一下当前active模式失败\n     */\n    public void processActiveExit();\n\n}\n"
  },
  {
    "path": "client/src/main/java/com/alibaba/otter/canal/client/impl/running/ClientRunningMonitor.java",
    "content": "package com.alibaba.otter.canal.client.impl.running;\n\nimport java.net.InetSocketAddress;\nimport java.text.MessageFormat;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\n\nimport org.I0Itec.zkclient.IZkDataListener;\nimport org.I0Itec.zkclient.exception.ZkException;\nimport org.I0Itec.zkclient.exception.ZkInterruptedException;\nimport org.I0Itec.zkclient.exception.ZkNoNodeException;\nimport org.I0Itec.zkclient.exception.ZkNodeExistsException;\nimport org.apache.zookeeper.CreateMode;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.slf4j.MDC;\n\nimport com.alibaba.otter.canal.client.impl.ServerNotFoundException;\nimport com.alibaba.otter.canal.common.AbstractCanalLifeCycle;\nimport com.alibaba.otter.canal.common.utils.BooleanMutex;\nimport com.alibaba.otter.canal.common.utils.JsonUtils;\nimport com.alibaba.otter.canal.common.zookeeper.ZkClientx;\nimport com.alibaba.otter.canal.common.zookeeper.ZookeeperPathUtils;\nimport com.alibaba.otter.canal.protocol.exception.CanalClientException;\n\n/**\n * clinet running控制\n * \n * @author jianghang 2012-11-22 下午03:43:01\n * @version 1.0.0\n */\npublic class ClientRunningMonitor extends AbstractCanalLifeCycle {\n\n    private static final Logger        logger       = LoggerFactory.getLogger(ClientRunningMonitor.class);\n    private ZkClientx                  zkClient;\n    private String                     destination;\n    private ClientRunningData          clientData;\n    private IZkDataListener            dataListener;\n    private BooleanMutex               mutex        = new BooleanMutex(false);\n    private volatile boolean           release      = false;\n    private volatile ClientRunningData activeData;\n    private ScheduledExecutorService   delayExector = Executors.newScheduledThreadPool(1);\n    private ClientRunningListener      listener;\n    private int                        delayTime    = 5;\n\n    public ClientRunningMonitor(){\n        dataListener = new IZkDataListener() {\n\n            public void handleDataChange(String dataPath, Object data) throws Exception {\n                MDC.put(\"destination\", destination);\n                ClientRunningData runningData = JsonUtils.unmarshalFromByte((byte[]) data, ClientRunningData.class);\n                if (!isMine(runningData.getAddress())) {\n                    mutex.set(false);\n                }\n\n                if (!runningData.isActive() && isMine(runningData.getAddress())) { // 说明出现了主动释放的操作，并且本机之前是active\n                    release = true;\n                    releaseRunning();// 彻底释放mainstem\n                }\n\n                activeData = (ClientRunningData) runningData;\n            }\n\n            public void handleDataDeleted(String dataPath) throws Exception {\n                MDC.put(\"destination\", destination);\n                mutex.set(false);\n                // 触发一下退出,可能是人为干预的释放操作或者网络闪断引起的session expired timeout\n                processActiveExit();\n                if (!release && activeData != null && isMine(activeData.getAddress())) {\n                    // 如果上一次active的状态就是本机，则即时触发一下active抢占\n                    initRunning();\n                } else {\n                    // 否则就是等待delayTime，避免因网络瞬端或者zk异常，导致出现频繁的切换操作\n                    delayExector.schedule(() -> initRunning(), delayTime, TimeUnit.SECONDS);\n                }\n            }\n\n        };\n\n    }\n\n    public void start() {\n        super.start();\n\n        String path = ZookeeperPathUtils.getDestinationClientRunning(this.destination, clientData.getClientId());\n        zkClient.subscribeDataChanges(path, dataListener);\n        initRunning();\n    }\n\n    public void stop() {\n        super.stop();\n\n        String path = ZookeeperPathUtils.getDestinationClientRunning(this.destination, clientData.getClientId());\n        zkClient.unsubscribeDataChanges(path, dataListener);\n        releaseRunning(); // 尝试一下release\n        // Fix issue #697\n        if (delayExector != null) {\n            delayExector.shutdown();\n        }\n    }\n\n    // 改动记录：\n    // 1,在方法上加synchronized关键字,保证同步顺序执行;\n    // 2,判断Zk上已经存在的activeData是否是本机，是的话把mutex重置为true，否则会导致死锁\n    // 3,增加异常处理，保证出现异常时，running节点能被删除,否则会导致死锁\n    public synchronized void initRunning() {\n        if (!isStart()) {\n            return;\n        }\n\n        String path = ZookeeperPathUtils.getDestinationClientRunning(this.destination, clientData.getClientId());\n        // 序列化\n        byte[] bytes = JsonUtils.marshalToByte(clientData);\n        try {\n            mutex.set(false);\n            zkClient.create(path, bytes, CreateMode.EPHEMERAL);\n            processActiveEnter();// 触发一下事件\n            activeData = clientData;\n            mutex.set(true);\n        } catch (ZkNodeExistsException e) {\n            bytes = zkClient.readData(path, true);\n            if (bytes == null) {// 如果不存在节点，立即尝试一次\n                initRunning();\n            } else {\n                activeData = JsonUtils.unmarshalFromByte(bytes, ClientRunningData.class);\n                // 如果发现已经存在,判断一下是否自己,避免活锁\n                if (activeData.getAddress().contains(\":\") && isMine(activeData.getAddress())) {\n                    mutex.set(true);\n                }\n            }\n        } catch (ZkNoNodeException e) {\n            zkClient.createPersistent(ZookeeperPathUtils.getClientIdNodePath(this.destination, clientData.getClientId()),\n                true); // 尝试创建父节点\n            initRunning();\n        } catch (Throwable t) {\n            logger.error(MessageFormat.format(\"There is an error when execute initRunning method, with destination [{0}].\",\n                destination),\n                t);\n\n            // fixed issue 1220, 针对server节点不工作避免死循环\n            if (t instanceof ServerNotFoundException) {\n                try {\n                    Thread.sleep(1000);\n                } catch (InterruptedException e) {\n                }\n            }\n\n            // 出现任何异常尝试release\n            releaseRunning();\n            throw new CanalClientException(\"something goes wrong in initRunning method. \", t);\n        }\n    }\n\n    /**\n     * 阻塞等待自己成为active，如果自己成为active，立马返回\n     * \n     * @throws InterruptedException\n     */\n    public void waitForActive() throws InterruptedException {\n        initRunning();\n        mutex.get();\n    }\n\n    /**\n     * 检查当前的状态\n     */\n    public boolean check() {\n        String path = ZookeeperPathUtils.getDestinationClientRunning(this.destination, clientData.getClientId());\n        try {\n            byte[] bytes = zkClient.readData(path);\n            ClientRunningData eventData = JsonUtils.unmarshalFromByte(bytes, ClientRunningData.class);\n            activeData = eventData;// 更新下为最新值\n            // 检查下nid是否为自己\n            boolean result = isMine(activeData.getAddress());\n            if (!result) {\n                logger.warn(\"canal is running in [{}] , but not in [{}]\",\n                    activeData.getAddress(),\n                    clientData.getAddress());\n            }\n            return result;\n        } catch (ZkNoNodeException e) {\n            logger.warn(\"canal is not run any in node\");\n            return false;\n        } catch (ZkInterruptedException e) {\n            logger.warn(\"canal check is interrupt\");\n            Thread.interrupted();// 清除interrupt标记\n            return check();\n        } catch (ZkException e) {\n            logger.warn(\"canal check is failed\");\n            return false;\n        }\n    }\n\n    public boolean releaseRunning() {\n        if (check()) {\n            String path = ZookeeperPathUtils.getDestinationClientRunning(this.destination, clientData.getClientId());\n            zkClient.delete(path);\n            mutex.set(false);\n            processActiveExit();\n            return true;\n        }\n\n        return false;\n    }\n\n    // ====================== helper method ======================\n\n    private boolean isMine(String address) {\n        return address.equals(clientData.getAddress());\n    }\n\n    private void processActiveEnter() {\n        if (listener != null) {\n            // 触发回调，建立与server的socket链接\n            InetSocketAddress connectAddress = listener.processActiveEnter();\n            String address = connectAddress.getAddress().getHostAddress() + \":\" + connectAddress.getPort();\n            this.clientData.setAddress(address);\n\n            String path = ZookeeperPathUtils.getDestinationClientRunning(this.destination,\n                this.clientData.getClientId());\n            // 序列化\n            byte[] bytes = JsonUtils.marshalToByte(clientData);\n            zkClient.writeData(path, bytes);\n        }\n    }\n\n    private void processActiveExit() {\n        if (listener != null) {\n            listener.processActiveExit();\n        }\n    }\n\n    public void setListener(ClientRunningListener listener) {\n        this.listener = listener;\n    }\n\n    // ===================== setter / getter =======================\n\n    public void setDestination(String destination) {\n        this.destination = destination;\n    }\n\n    public void setClientData(ClientRunningData clientData) {\n        this.clientData = clientData;\n    }\n\n    public void setDelayTime(int delayTime) {\n        this.delayTime = delayTime;\n    }\n\n    public void setZkClient(ZkClientx zkClient) {\n        this.zkClient = zkClient;\n    }\n\n}\n"
  },
  {
    "path": "client/src/main/java/com/alibaba/otter/canal/client/kafka/KafkaCanalConnector.java",
    "content": "package com.alibaba.otter.canal.client.kafka;\n\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.kafka.clients.consumer.ConsumerRecord;\nimport org.apache.kafka.clients.consumer.ConsumerRecords;\nimport org.apache.kafka.clients.consumer.KafkaConsumer;\nimport org.apache.kafka.common.TopicPartition;\nimport org.apache.kafka.common.serialization.StringDeserializer;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.otter.canal.client.CanalMQConnector;\nimport com.alibaba.otter.canal.client.impl.SimpleCanalConnector;\nimport com.alibaba.otter.canal.protocol.FlatMessage;\nimport com.alibaba.otter.canal.protocol.Message;\nimport com.alibaba.otter.canal.protocol.exception.CanalClientException;\nimport com.google.common.collect.Lists;\n\n/**\n * canal kafka 数据操作客户端\n *\n * <pre>\n * 注意点：\n * 1. 相比于canal {@linkplain SimpleCanalConnector}, 这里get和ack操作不能有并发, 必须是一个线程执行get后，内存里执行完毕ack后再取下一个get\n * </pre>\n *\n * @author machengyuan @ 2018-6-12\n * @version 1.1.1\n */\npublic class KafkaCanalConnector implements CanalMQConnector {\n\n    protected KafkaConsumer<String, Message> kafkaConsumer;\n    protected KafkaConsumer<String, String>  kafkaConsumer2;                            // 用于扁平message的数据消费\n    protected String                         topic;\n    protected Integer                        partition;\n    protected Properties                     properties;\n    protected volatile boolean               connected      = false;\n    protected volatile boolean               running        = false;\n    protected boolean                        flatMessage;\n\n    private Map<Integer, Long>               currentOffsets = new ConcurrentHashMap<>();\n\n    public KafkaCanalConnector(String servers, String topic, Integer partition, String groupId, Integer batchSize,\n                               boolean flatMessage){\n        this.topic = topic;\n        this.partition = partition;\n        this.flatMessage = flatMessage;\n\n        properties = new Properties();\n        properties.put(\"bootstrap.servers\", servers);\n        properties.put(\"group.id\", groupId);\n        properties.put(\"enable.auto.commit\", false);\n        properties.put(\"auto.commit.interval.ms\", \"1000\");\n        properties.put(\"auto.offset.reset\", \"latest\"); // 如果没有offset则从最后的offset开始读\n        properties.put(\"request.timeout.ms\", \"40000\"); // 必须大于session.timeout.ms的设置\n        properties.put(\"session.timeout.ms\", \"30000\"); // 默认为30秒\n        properties.put(\"isolation.level\", \"read_committed\");\n        if (batchSize == null) {\n            batchSize = 100;\n        }\n        properties.put(\"max.poll.records\", batchSize.toString());\n        properties.put(\"key.deserializer\", StringDeserializer.class);\n        if (!flatMessage) {\n            properties.put(\"value.deserializer\", MessageDeserializer.class);\n        } else {\n            properties.put(\"value.deserializer\", StringDeserializer.class);\n        }\n    }\n\n    /**\n     * 打开连接\n     */\n    @Override\n    public void connect() {\n        if (connected) {\n            return;\n        }\n\n        if (kafkaConsumer == null && !flatMessage) {\n            kafkaConsumer = new KafkaConsumer<>(properties);\n        }\n\n        if (kafkaConsumer2 == null && flatMessage) {\n            kafkaConsumer2 = new KafkaConsumer<>(properties);\n        }\n\n        connected = true;\n    }\n\n    /**\n     * 关闭链接\n     */\n    @Override\n    public void disconnect() {\n        if (kafkaConsumer != null) {\n            kafkaConsumer.close();\n            kafkaConsumer = null;\n        }\n        if (kafkaConsumer2 != null) {\n            kafkaConsumer2.close();\n            kafkaConsumer2 = null;\n        }\n\n        connected = false;\n    }\n\n    protected void waitClientRunning() {\n        running = true;\n    }\n\n    @Override\n    public boolean checkValid() {\n        return true;// 默认都放过\n    }\n\n    /**\n     * 订阅topic\n     */\n    @Override\n    public void subscribe() {\n        waitClientRunning();\n        if (!running) {\n            return;\n        }\n\n        if (partition == null) {\n            if (kafkaConsumer != null) {\n                kafkaConsumer.subscribe(Collections.singletonList(topic));\n            }\n            if (kafkaConsumer2 != null) {\n                kafkaConsumer2.subscribe(Collections.singletonList(topic));\n            }\n        } else {\n            TopicPartition topicPartition = new TopicPartition(topic, partition);\n            if (kafkaConsumer != null) {\n                kafkaConsumer.assign(Collections.singletonList(topicPartition));\n            }\n            if (kafkaConsumer2 != null) {\n                kafkaConsumer2.assign(Collections.singletonList(topicPartition));\n            }\n        }\n    }\n\n    /**\n     * 取消订阅\n     */\n    @Override\n    public void unsubscribe() {\n        waitClientRunning();\n        if (!running) {\n            return;\n        }\n\n        if (kafkaConsumer != null) {\n            kafkaConsumer.unsubscribe();\n        }\n        if (kafkaConsumer2 != null) {\n            kafkaConsumer2.unsubscribe();\n        }\n    }\n\n    @Override\n    public List<Message> getList(Long timeout, TimeUnit unit) throws CanalClientException {\n        waitClientRunning();\n        if (!running) {\n            return Lists.newArrayList();\n        }\n\n        List<Message> messages = getListWithoutAck(timeout, unit);\n        if (messages != null && !messages.isEmpty()) {\n            this.ack();\n        }\n        return messages;\n    }\n\n    @Override\n    public List<Message> getListWithoutAck(Long timeout, TimeUnit unit) throws CanalClientException {\n        waitClientRunning();\n        if (!running) {\n            return Lists.newArrayList();\n        }\n\n        ConsumerRecords<String, Message> records = kafkaConsumer.poll(unit.toMillis(timeout));\n\n        if (!records.isEmpty()) {\n            currentOffsets.clear();\n            List<Message> messages = new ArrayList<>();\n            for (ConsumerRecord<String, Message> record : records) {\n                if (currentOffsets.get(record.partition()) == null) {\n                    currentOffsets.put(record.partition(), record.offset());\n                }\n                messages.add(record.value());\n            }\n            return messages;\n        }\n        return Lists.newArrayList();\n    }\n\n    @Override\n    public List<FlatMessage> getFlatList(Long timeout, TimeUnit unit) throws CanalClientException {\n        waitClientRunning();\n        if (!running) {\n            return Lists.newArrayList();\n        }\n\n        List<FlatMessage> messages = getFlatListWithoutAck(timeout, unit);\n        if (messages != null && !messages.isEmpty()) {\n            this.ack();\n        }\n        return messages;\n    }\n\n    @Override\n    public List<FlatMessage> getFlatListWithoutAck(Long timeout, TimeUnit unit) throws CanalClientException {\n        waitClientRunning();\n        if (!running) {\n            return Lists.newArrayList();\n        }\n\n        ConsumerRecords<String, String> records = kafkaConsumer2.poll(unit.toMillis(timeout));\n\n        if (!records.isEmpty()) {\n            currentOffsets.clear();\n            List<FlatMessage> flatMessages = new ArrayList<>();\n            for (ConsumerRecord<String, String> record : records) {\n                if (currentOffsets.get(record.partition()) == null) {\n                    currentOffsets.put(record.partition(), record.offset());\n                }\n                String flatMessageJson = record.value();\n                FlatMessage flatMessage = JSON.parseObject(flatMessageJson, FlatMessage.class);\n                flatMessages.add(flatMessage);\n            }\n\n            return flatMessages;\n        }\n        return Lists.newArrayList();\n    }\n\n    @Override\n    public void rollback() {\n        waitClientRunning();\n        if (!running) {\n            return;\n        }\n        // 回滚所有分区\n        if (kafkaConsumer != null) {\n            for (Map.Entry<Integer, Long> entry : currentOffsets.entrySet()) {\n                kafkaConsumer.seek(new TopicPartition(topic, entry.getKey()), currentOffsets.get(entry.getKey()));\n                kafkaConsumer.commitSync();\n            }\n        }\n        if (kafkaConsumer2 != null) {\n            for (Map.Entry<Integer, Long> entry : currentOffsets.entrySet()) {\n                kafkaConsumer2.seek(new TopicPartition(topic, entry.getKey()), currentOffsets.get(entry.getKey()));\n                kafkaConsumer.commitSync();\n            }\n        }\n    }\n\n    /**\n     * 提交offset，如果超过 session.timeout.ms 设置的时间没有ack则会抛出异常，ack失败\n     */\n    @Override\n    public void ack() {\n        waitClientRunning();\n        if (!running) {\n            return;\n        }\n\n        if (kafkaConsumer != null) {\n            kafkaConsumer.commitSync();\n        }\n        if (kafkaConsumer2 != null) {\n            kafkaConsumer2.commitSync();\n        }\n    }\n\n    @Override\n    public void subscribe(String filter) throws CanalClientException {\n        throw new CanalClientException(\"mq not support this method\");\n    }\n\n    @Override\n    public Message get(int batchSize) throws CanalClientException {\n        throw new CanalClientException(\"mq not support this method\");\n    }\n\n    @Override\n    public Message get(int batchSize, Long timeout, TimeUnit unit) throws CanalClientException {\n        throw new CanalClientException(\"mq not support this method\");\n    }\n\n    @Override\n    public Message getWithoutAck(int batchSize) throws CanalClientException {\n        throw new CanalClientException(\"mq not support this method\");\n    }\n\n    @Override\n    public Message getWithoutAck(int batchSize, Long timeout, TimeUnit unit) throws CanalClientException {\n        throw new CanalClientException(\"mq not support this method\");\n    }\n\n    @Override\n    public void ack(long batchId) throws CanalClientException {\n        throw new CanalClientException(\"mq not support this method\");\n    }\n\n    @Override\n    public void rollback(long batchId) throws CanalClientException {\n        throw new CanalClientException(\"mq not support this method\");\n    }\n\n    /**\n     * 重新设置sessionTime\n     *\n     * @param timeout\n     * @param unit\n     */\n    public void setSessionTimeout(Long timeout, TimeUnit unit) {\n        long t = unit.toMillis(timeout);\n        properties.put(\"request.timeout.ms\", String.valueOf(t + 60000));\n        properties.put(\"session.timeout.ms\", String.valueOf(t));\n    }\n\n}\n"
  },
  {
    "path": "client/src/main/java/com/alibaba/otter/canal/client/kafka/KafkaOffsetCanalConnector.java",
    "content": "package com.alibaba.otter.canal.client.kafka;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.otter.canal.client.kafka.protocol.KafkaFlatMessage;\nimport com.alibaba.otter.canal.client.kafka.protocol.KafkaMessage;\nimport com.alibaba.otter.canal.protocol.FlatMessage;\nimport com.alibaba.otter.canal.protocol.Message;\nimport com.alibaba.otter.canal.protocol.exception.CanalClientException;\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.kafka.clients.consumer.ConsumerRecord;\nimport org.apache.kafka.clients.consumer.ConsumerRecords;\nimport org.apache.kafka.common.TopicPartition;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * kafka带消息offset的连接器\n *\n * @Author panjianping\n * @Email ipanjianping@qq.com\n * @Date 2018/12/17\n */\npublic class KafkaOffsetCanalConnector extends KafkaCanalConnector {\n\n    public KafkaOffsetCanalConnector(String servers, String topic, Integer partition, String groupId, boolean flatMessage) {\n        super(servers, topic, partition, groupId, 100, flatMessage);\n        // 启动时从未消费的消息位置开始\n        properties.put(\"auto.offset.reset\", \"earliest\");\n    }\n\n    /**\n     * 获取Kafka消息，不确认\n     *\n     * @param timeout\n     * @param unit\n     * @param offset  消息偏移地址（-1为不偏移）\n     * @return\n     * @throws CanalClientException\n     */\n    public List<KafkaMessage> getListWithoutAck(Long timeout, TimeUnit unit, long offset) throws CanalClientException {\n        waitClientRunning();\n        if (!running) {\n            return new ArrayList<>();\n        }\n\n        if (offset > -1) {\n            TopicPartition tp = new TopicPartition(topic, partition == null ? 0 : partition);\n            kafkaConsumer.seek(tp, offset);\n        }\n\n        ConsumerRecords<String, Message> records = kafkaConsumer.poll(unit.toMillis(timeout));\n\n        if (!records.isEmpty()) {\n            List<KafkaMessage> messages = new ArrayList<>();\n            for (ConsumerRecord<String, Message> record : records) {\n                KafkaMessage message = new KafkaMessage(record.value(), record.offset());\n                messages.add(message);\n            }\n            return messages;\n        }\n        return new ArrayList<>();\n    }\n\n    /**\n     * 获取Kafka消息，不确认\n     *\n     * @param timeout\n     * @param unit\n     * @param offset  消息偏移地址（-1为不偏移）\n     * @return\n     * @throws CanalClientException\n     */\n    public List<KafkaFlatMessage> getFlatListWithoutAck(Long timeout, TimeUnit unit, long offset) throws CanalClientException {\n        waitClientRunning();\n        if (!running) {\n            return new ArrayList<>();\n        }\n\n        if (offset > -1) {\n            TopicPartition tp = new TopicPartition(topic, partition == null ? 0 : partition);\n            kafkaConsumer2.seek(tp, offset);\n        }\n\n        ConsumerRecords<String, String> records = kafkaConsumer2.poll(unit.toMillis(timeout));\n        if (!records.isEmpty()) {\n            List<KafkaFlatMessage> flatMessages = new ArrayList<>();\n            for (ConsumerRecord<String, String> record : records) {\n                String flatMessageJson = record.value();\n                FlatMessage flatMessage = JSON.parseObject(flatMessageJson, FlatMessage.class);\n                KafkaFlatMessage message = new KafkaFlatMessage(flatMessage, record.offset());\n                flatMessages.add(message);\n            }\n\n            return flatMessages;\n        }\n        return new ArrayList<>();\n    }\n\n    /**\n     * 重新设置AutoOffsetReset（默认 earliest ）\n     *\n     * @param value\n     */\n    public void setAutoOffsetReset(String value) {\n        if (StringUtils.isNotBlank(value)) {\n            properties.put(\"auto.offset.reset\", value);\n        }\n    }\n}\n"
  },
  {
    "path": "client/src/main/java/com/alibaba/otter/canal/client/kafka/MessageDeserializer.java",
    "content": "package com.alibaba.otter.canal.client.kafka;\n\nimport java.util.Map;\n\nimport org.apache.kafka.common.serialization.Deserializer;\n\nimport com.alibaba.otter.canal.client.CanalMessageDeserializer;\nimport com.alibaba.otter.canal.protocol.Message;\n\n/**\n * Kafka Message类的反序列化\n *\n * @author machengyuan @ 2018-6-12\n * @version 1.0.0\n */\npublic class MessageDeserializer implements Deserializer<Message> {\n\n    @Override\n    public void configure(Map<String, ?> configs, boolean isKey) {\n    }\n\n    @Override\n    public Message deserialize(String topic1, byte[] data) {\n        return CanalMessageDeserializer.deserializer(data);\n    }\n\n    @Override\n    public void close() {\n        // nothing to do\n    }\n}\n"
  },
  {
    "path": "client/src/main/java/com/alibaba/otter/canal/client/kafka/protocol/KafkaFlatMessage.java",
    "content": "package com.alibaba.otter.canal.client.kafka.protocol;\r\n\r\nimport com.alibaba.otter.canal.protocol.FlatMessage;\r\nimport org.springframework.beans.BeanUtils;\r\n\r\n/**\r\n * 消息对象（Kafka）\r\n *\r\n * @Author panjianping\r\n * @Email ipanjianping@qq.com\r\n * @Date 2018/12/17\r\n */\r\npublic class KafkaFlatMessage extends FlatMessage {\r\n\r\n    private static final long serialVersionUID = 5748024400508080710L;\r\n\r\n    /**\r\n     * Kafka 消息 offset\r\n     */\r\n    private long              offset;\r\n\r\n    public KafkaFlatMessage(FlatMessage message, long offset){\r\n        super(message.getId());\r\n        BeanUtils.copyProperties(message, this);\r\n        this.offset = offset;\r\n    }\r\n\r\n    public long getOffset() {\r\n        return offset;\r\n    }\r\n\r\n    public void setOffset(long offset) {\r\n        this.offset = offset;\r\n    }\r\n}\r\n"
  },
  {
    "path": "client/src/main/java/com/alibaba/otter/canal/client/kafka/protocol/KafkaMessage.java",
    "content": "package com.alibaba.otter.canal.client.kafka.protocol;\r\n\r\nimport com.alibaba.otter.canal.protocol.Message;\r\nimport org.springframework.beans.BeanUtils;\r\n\r\n/**\r\n * 消息对象（Kafka）\r\n *\r\n * @Author panjianping\r\n * @Email ipanjianping@qq.com\r\n * @Date 2018/12/17\r\n */\r\npublic class KafkaMessage extends Message {\r\n\r\n    private static final long serialVersionUID = -293120358490119447L;\r\n\r\n    /**\r\n     * Kafka 消息 offset\r\n     */\r\n    private long              offset;\r\n\r\n    public KafkaMessage(Message message, long offset){\r\n        super(message.getId());\r\n        BeanUtils.copyProperties(message, this);\r\n        this.offset = offset;\r\n    }\r\n\r\n    public long getOffset() {\r\n        return offset;\r\n    }\r\n\r\n    public void setOffset(long offset) {\r\n        this.offset = offset;\r\n    }\r\n}\r\n"
  },
  {
    "path": "client/src/main/java/com/alibaba/otter/canal/client/pulsarmq/PulsarMQCanalConnector.java",
    "content": "package com.alibaba.otter.canal.client.pulsarmq;\n\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.pulsar.client.api.*;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.otter.canal.client.CanalMQConnector;\nimport com.alibaba.otter.canal.client.CanalMessageDeserializer;\nimport com.alibaba.otter.canal.client.impl.SimpleCanalConnector;\nimport com.alibaba.otter.canal.common.utils.MQUtil;\nimport com.alibaba.otter.canal.protocol.FlatMessage;\nimport com.alibaba.otter.canal.protocol.Message;\nimport com.alibaba.otter.canal.protocol.exception.CanalClientException;\nimport com.google.common.collect.Lists;\n\n/**\n * PulsarMQ的连接\n *\n * <pre>\n * 注意点:\n * 1. 相比于canal {@linkplain SimpleCanalConnector}, 这里get和ack操作不能有并发, 必须是一个线程执行get后，内存里执行完毕ack后再取下一个get\n * </pre>\n * \n * todo 重复消费的概率相当高。一次批处理中，只要有一个消息处理失败，则该批次全部重试\n *\n * @since 1.1.1\n */\npublic class PulsarMQCanalConnector implements CanalMQConnector {\n\n    private static final Logger       logger                     = LoggerFactory\n        .getLogger(PulsarMQCanalConnector.class);\n\n    private volatile Messages<byte[]> lastGetBatchMessage;\n\n    /**\n     * 连接pulsar客户端\n     */\n    private PulsarClient              pulsarClient;\n    /**\n     * 消费者\n     */\n    private Consumer<byte[]>          consumer;\n    /**\n     * 是否扁平化Canal消息内容\n     */\n    private boolean                   isFlatMessage              = false;\n    /**\n     * 主题名称\n     */\n    private String                    topic;\n    /**\n     * 环境连接URL\n     */\n    private String                    serviceUrl;\n    /**\n     * 角色认证token\n     */\n    private String                    roleToken;\n\n    /**\n     * listener name\n     */\n    private String                    listenerName;\n\n    /**\n     * 订阅客户端名称\n     */\n    private String                    subscriptName;\n    /**\n     * 每次批量获取数据的最大条目数，默认30\n     */\n    private int                       batchSize                  = 30;\n    /**\n     * 与{@code batchSize}一起决定批量获取的数据大小 当：\n     * <p>\n     * 1. {@code batchSize} 条消息未消费时<br/>\n     * 2. 距上一次批量消费时间达到{@code batchTimeoutSeconds}秒时\n     * </p>\n     * 任一条件满足，即执行批量消费\n     */\n    private int                       getBatchTimeoutSeconds     = 30;\n    /**\n     * 批量处理消息时，一次批量处理的超时时间秒数\n     * <p>\n     * 该时间应该根据{@code batchSize}和{@code batchTimeoutSeconds}合理设置\n     * </p>\n     */\n    private int                       batchProcessTimeoutSeconds = 60;\n    /**\n     * 消费失败后的重试秒数，默认60秒\n     */\n    private int                       redeliveryDelaySeconds     = 60;\n    /**\n     * 当客户端接收到消息，30秒还没有返回ack给服务端时，ack超时，会重新消费该消息\n     */\n    private int                       ackTimeoutSeconds          = 30;\n    /**\n     * 是否开启消息失败重试功能，默认开启\n     */\n    private boolean                   isRetry                    = true;\n    /**\n     * <p>\n     * true重试(-RETRY)和死信队列(-DLQ)后缀为大写，有些地方创建的为小写，需确保正确\n     * </p>\n     */\n    private boolean                   isRetryDLQUpperCase        = false;\n    /**\n     * 最大重试次数\n     */\n    private int                       maxRedeliveryCount         = 128;\n    /**\n     * 连接标识位，在连接或关闭连接后改变值\n     */\n    private boolean                   connected                  = false;\n\n    /**\n     * 除必要参数外，其他参数使用默认值\n     * <p>\n     * 由于pulsar会根据subscriptName来区分消费实例，并且已经分配的指定实例的消息会固定到该实例的retry（重试）和dlq（死信）队列中，\n     * 所以subscriptName必传，且必须跟之前的一致，否则会导致之前消费失败的消息不会重消费。\n     * </p>\n     *\n     * @param isFlatMessage true使用扁平消息\n     * @param serviceUrl pulsar服务连接地址，通常为：pulsar:host:ip或http://host:ip\n     * @param roleToken 有对应topic的消费者权限的角色token\n     * @param topic 订阅主题\n     * @param subscriptName 订阅和客户端名称，同一个订阅名视为同一个消费实例\n     * @date 2021/9/18 08:54\n     * @author chad\n     * @since 1 by chad at 2021/9/18 完善\n     */\n    public PulsarMQCanalConnector(boolean isFlatMessage, String serviceUrl, String roleToken, String topic,\n                                  String subscriptName){\n        this(isFlatMessage, serviceUrl, roleToken, topic, subscriptName, null);\n    }\n\n    public PulsarMQCanalConnector(boolean isFlatMessage, String serviceUrl, String roleToken, String topic,\n                                  String subscriptName, String listenerName){\n        this.isFlatMessage = isFlatMessage;\n        this.serviceUrl = serviceUrl;\n        this.roleToken = roleToken;\n        this.topic = topic;\n        this.subscriptName = subscriptName;\n        if (StringUtils.isEmpty(this.subscriptName)) {\n            throw new RuntimeException(\"Pulsar Consumer subscriptName required\");\n        }\n        this.listenerName = listenerName;\n    }\n\n    /**\n     * 完全自定义的消费实例参数\n     *\n     * @date 2021/9/18 10:20\n     * @author chad\n     * @since 1 by chad at 2021/9/18 完善\n     */\n    public PulsarMQCanalConnector(boolean isFlatMessage, String serviceUrl, String roleToken, String topic,\n                                  String subscriptName, int batchSize, int getBatchTimeoutSeconds,\n                                  int batchProcessTimeoutSeconds, int redeliveryDelaySeconds, int ackTimeoutSeconds,\n                                  boolean isRetry, boolean isRetryDLQUpperCase, int maxRedeliveryCount){\n        this(isFlatMessage,\n            serviceUrl,\n            roleToken,\n            topic,\n            subscriptName,\n            batchSize,\n            getBatchTimeoutSeconds,\n            batchProcessTimeoutSeconds,\n            redeliveryDelaySeconds,\n            ackTimeoutSeconds,\n            isRetry,\n            isRetryDLQUpperCase,\n            maxRedeliveryCount,\n            null);\n    }\n\n    public PulsarMQCanalConnector(boolean isFlatMessage, String serviceUrl, String roleToken, String topic,\n                                  String subscriptName, int batchSize, int getBatchTimeoutSeconds,\n                                  int batchProcessTimeoutSeconds, int redeliveryDelaySeconds, int ackTimeoutSeconds,\n                                  boolean isRetry, boolean isRetryDLQUpperCase, int maxRedeliveryCount,\n                                  String listenerName){\n        this.isFlatMessage = isFlatMessage;\n        this.serviceUrl = serviceUrl;\n        this.roleToken = roleToken;\n        this.topic = topic;\n        this.subscriptName = subscriptName;\n        if (StringUtils.isEmpty(this.subscriptName)) {\n            throw new RuntimeException(\"Pulsar Consumer subscriptName required\");\n        }\n        this.batchSize = batchSize;\n        this.getBatchTimeoutSeconds = getBatchTimeoutSeconds;\n        this.batchProcessTimeoutSeconds = batchProcessTimeoutSeconds;\n        this.redeliveryDelaySeconds = redeliveryDelaySeconds;\n        this.ackTimeoutSeconds = ackTimeoutSeconds;\n        this.isRetry = isRetry;\n        this.isRetryDLQUpperCase = isRetryDLQUpperCase;\n        this.maxRedeliveryCount = maxRedeliveryCount;\n        this.listenerName = listenerName;\n    }\n\n    @Override\n    public void connect() throws CanalClientException {\n        // 连接创建客户端\n        try {\n            ClientBuilder builder = PulsarClient.builder()\n                .serviceUrl(serviceUrl)\n                .authentication(AuthenticationFactory.token(roleToken));\n            if (StringUtils.isNotEmpty(listenerName)) {\n                builder.listenerName(listenerName);\n            }\n            pulsarClient = builder.build();\n        } catch (PulsarClientException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    @Override\n    public void disconnect() throws CanalClientException {\n        try {\n            if (null != this.consumer && this.consumer.isConnected()) {\n                this.consumer.close();\n            }\n        } catch (PulsarClientException e) {\n            logger.error(\"close pulsar consumer error\", e);\n        }\n        try {\n            if (null != this.pulsarClient) {\n                this.pulsarClient.close();\n            }\n        } catch (PulsarClientException e) {\n            logger.error(\"close pulsar client error\", e);\n        }\n\n        this.connected = false;\n    }\n\n    @Override\n    public boolean checkValid() throws CanalClientException {\n        return connected;\n    }\n\n    @Override\n    public synchronized void subscribe(String filter) throws CanalClientException {\n        if (connected) {\n            return;\n        }\n        ConsumerBuilder<byte[]> builder = pulsarClient.newConsumer();\n\n        if (MQUtil.isPatternTopic(this.topic)) {\n            // 正则\n            builder.topicsPattern(this.topic);\n        } else {// 多个topic\n            builder.topic(this.topic);\n        }\n        // 为保证消息的有序性，仅支持单消费实例模式\n        // 灾备模式，一个分区只能有一个消费者，如果当前消费者不可用，自动切换到其他消费者\n        builder.subscriptionType(SubscriptionType.Failover);\n\n        builder\n            // 调用consumer.negativeAcknowledge(message) （即nack）来表示消费失败的消息\n            // 在指定的时间进行重新消费，默认是1分钟。\n            .negativeAckRedeliveryDelay(this.redeliveryDelaySeconds, TimeUnit.SECONDS)\n            .subscriptionName(this.subscriptName);\n        if (this.isRetry) {\n            DeadLetterPolicy.DeadLetterPolicyBuilder dlqBuilder = DeadLetterPolicy.builder()\n                // 最大重试次数\n                .maxRedeliverCount(this.maxRedeliveryCount);\n            // 指定重试队列，不是多个或通配符topic才能判断重试队列\n            if (!MQUtil.isPatternTag(this.topic)) {\n                String retryTopic = this.topic + (this.isRetryDLQUpperCase ? \"-RETRY\" : \"-retry\");\n                dlqBuilder.retryLetterTopic(retryTopic);\n                String dlqTopic = this.topic + (this.isRetryDLQUpperCase ? \"-DLQ\" : \"-dlq\");\n                dlqBuilder.deadLetterTopic(dlqTopic);\n            }\n\n            // 默认关闭，如果需要重试则开启\n            builder.enableRetry(true).deadLetterPolicy(dlqBuilder.build());\n        }\n\n        // ack超时\n        builder.ackTimeout(this.ackTimeoutSeconds, TimeUnit.SECONDS);\n\n        // pulsar批量获取消息设置\n        builder.batchReceivePolicy(new BatchReceivePolicy.Builder().maxNumMessages(this.batchSize)\n            .timeout(this.getBatchTimeoutSeconds, TimeUnit.SECONDS)\n            .build());\n\n        try {\n            this.consumer = builder.subscribe();\n            connected = true;\n        } catch (PulsarClientException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    @Override\n    public void subscribe() throws CanalClientException {\n        this.subscribe(null);\n    }\n\n    @Override\n    public void unsubscribe() throws CanalClientException {\n        try {\n            if (null != this.consumer) {\n                this.consumer.unsubscribe();\n            }\n        } catch (PulsarClientException e) {\n            throw new CanalClientException(e.getMessage(), e);\n        }\n    }\n\n    /**\n     * 不关注业务执行结果，只要收到消息即认识消费成功，自动ack\n     *\n     * @param timeout 阻塞获取消息的超时时间\n     * @param unit 时间单位\n     * @return java.util.List<com.alibaba.otter.canal.protocol.Message>\n     * @date 2021/9/13 22:24\n     * @author chad\n     * @since 1 by chad at 2021/9/13 添加注释\n     */\n    @Override\n    public List<Message> getList(Long timeout, TimeUnit unit) throws CanalClientException {\n        List<Message> messages = getListWithoutAck(timeout, unit);\n        if (messages != null && !messages.isEmpty()) {\n            ack();\n        }\n        return messages;\n    }\n\n    /**\n     * 关心业务执行结果，业务侧根据执行结果调用\n     * {@link PulsarMQCanalConnector#ack()}或{@link PulsarMQCanalConnector#rollback()}\n     * <p>\n     * 本方法示支持多线程，在MQ保障顺序的前提下，也无法提供单Topic多线程\n     * </p>\n     *\n     * @param timeout 阻塞获取消息的超时时间\n     * @param unit 时间单位\n     * @return java.util.List<com.alibaba.otter.canal.protocol.Message>\n     * @date 2021/9/13 22:26\n     * @author chad\n     * @since 1 by chad at 2021/9/13 添加注释\n     */\n    @Override\n    public List<Message> getListWithoutAck(Long timeout, TimeUnit unit) throws CanalClientException {\n        return getListWithoutAck();\n    }\n\n    @Override\n    public List<FlatMessage> getFlatList(Long timeout, TimeUnit unit) throws CanalClientException {\n        List<FlatMessage> messages = getFlatListWithoutAck(timeout, unit);\n        if (messages != null && !messages.isEmpty()) {\n            ack();\n        }\n        return messages;\n    }\n\n    @Override\n    public List<FlatMessage> getFlatListWithoutAck(Long timeout, TimeUnit unit) throws CanalClientException {\n        return getListWithoutAck();\n    }\n\n    /**\n     * 获取泛型数据，供其他方法调用\n     * <p>\n     * 不支持多线程调用\n     * </p>\n     *\n     * @return java.util.List<T>\n     * @date 2021/9/14 15:20\n     * @author chad\n     * @since 1 by chad at 2021/9/14\n     * 供{@link PulsarMQCanalConnector#getListWithoutAck(Long, TimeUnit)}\n     * 和{@link PulsarMQCanalConnector#getFlatListWithoutAck(Long, TimeUnit)}调用\n     */\n    private <T> List<T> getListWithoutAck() {\n        if (null != this.lastGetBatchMessage) {\n            throw new CanalClientException(\"mq get/ack not support concurrent & async ack\");\n        }\n        List messageList = Lists.newArrayList();\n\n        try {\n            this.lastGetBatchMessage = consumer.batchReceive();\n            if (null == this.lastGetBatchMessage || this.lastGetBatchMessage.size() < 1) {\n                this.lastGetBatchMessage = null;\n                return messageList;\n            }\n        } catch (PulsarClientException e) {\n            logger.error(\"Receiver Pulsar MQ message error\", e);\n            throw new CanalClientException(e);\n        }\n\n        for (org.apache.pulsar.client.api.Message<byte[]> msgExt : this.lastGetBatchMessage) {\n            byte[] data = msgExt.getData();\n            if (data == null) {\n                logger.warn(\"Received message data is null\");\n                continue;\n            }\n            try {\n                if (isFlatMessage) {\n                    FlatMessage flatMessage = JSON.parseObject(data, FlatMessage.class);\n                    messageList.add(flatMessage);\n                } else {\n                    Message message = CanalMessageDeserializer.deserializer(data);\n                    messageList.add(message);\n                }\n            } catch (Exception ex) {\n                logger.error(\"Add message error\", ex);\n                throw new CanalClientException(ex);\n            }\n        }\n\n        return messageList;\n    }\n\n    /**\n     * 当业务侧执行成功时，需要手动执行消息的ack操作\n     *\n     * @return void\n     * @date 2021/9/13 22:27\n     * @author chad\n     * @since 1 by chad at 2021/9/13 添加注释\n     */\n    @Override\n    public void ack() throws CanalClientException {\n        // 为什么要一个批次要么全部成功要么全部失败\n        try {\n            if (this.lastGetBatchMessage != null) {\n                this.consumer.acknowledge(this.lastGetBatchMessage);\n            }\n        } catch (Throwable e) {\n            if (this.lastGetBatchMessage != null) {\n                this.consumer.negativeAcknowledge(this.lastGetBatchMessage);\n            }\n        } finally {\n            this.lastGetBatchMessage = null;\n        }\n    }\n\n    /**\n     * 当业务侧执行失败时，需要手动执行消息的rollback操作，从而让消息重新消费\n     *\n     * @return void\n     * @date 2021/9/13 22:28\n     * @author chad\n     * @since 1 by chad at 2021/9/13 添加注释\n     */\n    @Override\n    public void rollback() throws CanalClientException {\n        try {\n            if (this.lastGetBatchMessage != null) {\n                this.consumer.negativeAcknowledge(this.lastGetBatchMessage);\n            }\n        } finally {\n            this.lastGetBatchMessage = null;\n        }\n    }\n\n    @Override\n    public Message get(int batchSize) throws CanalClientException {\n        throw new CanalClientException(\"mq not support this method\");\n    }\n\n    @Override\n    public Message get(int batchSize, Long timeout, TimeUnit unit) throws CanalClientException {\n        throw new CanalClientException(\"mq not support this method\");\n    }\n\n    @Override\n    public Message getWithoutAck(int batchSize) throws CanalClientException {\n        throw new CanalClientException(\"mq not support this method\");\n    }\n\n    @Override\n    public Message getWithoutAck(int batchSize, Long timeout, TimeUnit unit) throws CanalClientException {\n        throw new CanalClientException(\"mq not support this method\");\n    }\n\n    @Override\n    public void ack(long batchId) throws CanalClientException {\n        throw new CanalClientException(\"mq not support this method\");\n    }\n\n    @Override\n    public void rollback(long batchId) throws CanalClientException {\n        throw new CanalClientException(\"mq not support this method\");\n    }\n\n}\n"
  },
  {
    "path": "client/src/main/java/com/alibaba/otter/canal/client/rabbitmq/AliyunCredentialsProvider.java",
    "content": "/**\n * aliyun amqp协议 账号类\n * 暂不支持STS授权情况\n */\npackage com.alibaba.otter.canal.client.rabbitmq;\n\nimport com.alibaba.mq.amqp.utils.UserUtils;\nimport com.rabbitmq.client.impl.CredentialsProvider;\nimport java.security.InvalidKeyException;\nimport java.security.NoSuchAlgorithmException;\n\n\npublic class AliyunCredentialsProvider implements CredentialsProvider {\n\n\n    /**\n     * Access Key ID\n     */\n    private final String AliyunAccessKey;\n\n    /**\n     * Access Key Secret\n     */\n    private final String AliyunAccessSecret;\n\n    /**\n     * 资源主账号ID\n     */\n    private final long resourceOwnerId;\n\n\n    public AliyunCredentialsProvider(final String accessKey, final String accessSecret, final long resourceOwnerId) {\n        this.AliyunAccessKey = accessKey;\n        this.AliyunAccessSecret = accessSecret;\n        this.resourceOwnerId = resourceOwnerId;\n    }\n\n\n    @Override\n    public String getUsername() {\n        return UserUtils.getUserName(AliyunAccessKey, resourceOwnerId);\n    }\n\n    @Override\n    public String getPassword() {\n        try {\n            return UserUtils.getPassord(AliyunAccessSecret);\n        } catch (InvalidKeyException | NoSuchAlgorithmException ignored) {\n        }\n        return null;\n    }\n\n\n}\n"
  },
  {
    "path": "client/src/main/java/com/alibaba/otter/canal/client/rabbitmq/RabbitMQCanalConnector.java",
    "content": "package com.alibaba.otter.canal.client.rabbitmq;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.otter.canal.client.CanalMQConnector;\nimport com.alibaba.otter.canal.client.CanalMessageDeserializer;\nimport com.alibaba.otter.canal.client.ConsumerBatchMessage;\nimport com.alibaba.otter.canal.protocol.FlatMessage;\nimport com.alibaba.otter.canal.protocol.Message;\nimport com.alibaba.otter.canal.protocol.exception.CanalClientException;\nimport com.google.common.collect.Lists;\nimport com.rabbitmq.client.*;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\n\npublic class RabbitMQCanalConnector implements CanalMQConnector {\n\n    private static final Logger                 logger              = LoggerFactory\n        .getLogger(RabbitMQCanalConnector.class);\n\n    // 链接地址\n    private String                              nameServer;\n\n    // 主机名\n    private String                              vhost;\n\n    private String                              queueName;\n\n    // 一些鉴权信息\n    private String                              accessKey;\n    private String                              secretKey;\n    private Long                                resourceOwnerId;\n    private String                              username;\n    private String                              password;\n\n    private boolean                             flatMessage;\n\n    private Connection                          connect;\n    private Channel                             channel;\n\n\n    private long                                batchProcessTimeout = 60 * 1000;\n    private BlockingQueue<ConsumerBatchMessage> messageBlockingQueue;\n    private volatile ConsumerBatchMessage       lastGetBatchMessage = null;\n\n    public RabbitMQCanalConnector(String nameServer, String vhost, String queueName, String accessKey, String secretKey,\n                                  String username, String password, Long resourceOwnerId, boolean flatMessage){\n        this.nameServer = nameServer;\n        this.vhost = vhost;\n        this.queueName = queueName;\n        this.accessKey = accessKey;\n        this.secretKey = secretKey;\n        this.username = username;\n        this.password = password;\n        this.resourceOwnerId = resourceOwnerId;\n        this.flatMessage = flatMessage;\n        this.messageBlockingQueue = new LinkedBlockingQueue<>(1024);\n    }\n\n    public void connect() throws CanalClientException {\n        ConnectionFactory factory = new ConnectionFactory();\n        if (accessKey.length() > 0 && secretKey.length() > 0) {\n            factory.setCredentialsProvider(new AliyunCredentialsProvider(accessKey, secretKey, resourceOwnerId));\n        } else {\n            factory.setUsername(username);\n            factory.setPassword(password);\n        }\n        factory.setHost(nameServer);\n        factory.setAutomaticRecoveryEnabled(true);\n        factory.setNetworkRecoveryInterval(5000);\n        factory.setVirtualHost(vhost);\n        try {\n            connect = factory.newConnection();\n            channel = connect.createChannel();\n        } catch (IOException | TimeoutException e) {\n            throw new CanalClientException(\"Start RabbitMQ producer error\", e);\n        }\n    }\n\n    @Override\n    public void disconnect() throws CanalClientException {\n        if (connect != null) {\n            try {\n                connect.close();\n            } catch (IOException e) {\n                throw new CanalClientException(\"stop connect error\", e);\n            }\n        }\n        if (channel != null) {\n            try {\n                channel.close();\n            } catch (IOException | TimeoutException e) {\n                throw new CanalClientException(\"stop channel error\", e);\n            }\n        }\n    }\n\n    @Override\n    public boolean checkValid() throws CanalClientException {\n        return true; // 永远true\n    }\n\n    /**\n     * RabbitMQ支持拉取 不需要订阅\n     *\n     * @param filter\n     * @throws CanalClientException\n     */\n    @Override\n    public void subscribe(String filter) throws CanalClientException {\n        // 不存在连接 则重新连接\n        if (connect == null) {\n            this.connect();\n        }\n\n        Consumer consumer = new DefaultConsumer(channel) {\n\n            @Override\n            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,\n                                       byte[] body) throws IOException {\n\n                if (body != null) {\n                    channel.basicAck(envelope.getDeliveryTag(), process(body));\n                }\n            }\n        };\n        try {\n            channel.basicConsume(queueName, false, consumer);\n        } catch (IOException e) {\n            throw new CanalClientException(\"error\", e);\n        }\n    }\n\n    @Override\n    public void subscribe() throws CanalClientException {\n        this.subscribe(null);\n    }\n\n    @Override\n    public void unsubscribe() throws CanalClientException {\n        // 取消订阅 直接强行断开吧\n        this.disconnect();\n    }\n\n    @Override\n    public Message get(int batchSize) throws CanalClientException {\n        return null;\n    }\n\n    @Override\n    public Message get(int batchSize, Long timeout, TimeUnit unit) throws CanalClientException {\n        return null;\n    }\n\n    @Override\n    public Message getWithoutAck(int batchSize) throws CanalClientException {\n        throw new CanalClientException(\"mq not support this method\");\n    }\n\n    @Override\n    public Message getWithoutAck(int batchSize, Long timeout, TimeUnit unit) throws CanalClientException {\n        throw new CanalClientException(\"mq not support this method\");\n    }\n\n    @Override\n    public void ack(long batchId) throws CanalClientException {\n        throw new CanalClientException(\"mq not support this method\");\n    }\n\n    @Override\n    public void rollback(long batchId) throws CanalClientException {\n        throw new CanalClientException(\"mq not support this method\");\n\n    }\n\n    @Override\n    public List<Message> getList(Long timeout, TimeUnit unit) throws CanalClientException {\n        List<Message> messages = getListWithoutAck(timeout, unit);\n        if (messages != null && !messages.isEmpty()) {\n            ack();\n        }\n        return messages;\n    }\n\n    @Override\n    public List<Message> getListWithoutAck(Long timeout, TimeUnit unit) throws CanalClientException {\n        try {\n            if (this.lastGetBatchMessage != null) {\n                throw new CanalClientException(\"mq get/ack not support concurrent & async ack\");\n            }\n\n            ConsumerBatchMessage batchMessage = messageBlockingQueue.poll(timeout, unit);\n            if (batchMessage != null) {\n                this.lastGetBatchMessage = batchMessage;\n                return batchMessage.getData();\n            }\n        } catch (InterruptedException ex) {\n            logger.warn(\"Get message timeout\", ex);\n            throw new CanalClientException(\"Failed to fetch the data after: \" + timeout);\n        }\n        return Lists.newArrayList();\n    }\n\n    @Override\n    public List<FlatMessage> getFlatList(Long timeout, TimeUnit unit) throws CanalClientException {\n        List<FlatMessage> messages = getFlatListWithoutAck(timeout, unit);\n        if (messages != null && !messages.isEmpty()) {\n            ack();\n        }\n        return messages;\n    }\n\n    @Override\n    public List<FlatMessage> getFlatListWithoutAck(Long timeout, TimeUnit unit) throws CanalClientException {\n        try {\n            if (this.lastGetBatchMessage != null) {\n                throw new CanalClientException(\"mq get/ack not support concurrent & async ack\");\n            }\n\n            ConsumerBatchMessage batchMessage = messageBlockingQueue.poll(timeout, unit);\n            if (batchMessage != null) {\n                this.lastGetBatchMessage = batchMessage;\n                return batchMessage.getData();\n            }\n        } catch (InterruptedException ex) {\n            logger.warn(\"Get message timeout\", ex);\n            throw new CanalClientException(\"Failed to fetch the data after: \" + timeout);\n        }\n        return Lists.newArrayList();\n    }\n\n    private boolean process(byte[] messageData) {\n        if (logger.isDebugEnabled()) {\n            logger.debug(\"Get Message: {}\", new String(messageData));\n        }\n        List messageList = new ArrayList<>();\n        if (!flatMessage) {\n            Message message = CanalMessageDeserializer.deserializer(messageData);\n            messageList.add(message);\n        } else {\n            FlatMessage flatMessage = JSON.parseObject(messageData, FlatMessage.class);\n            messageList.add(flatMessage);\n        }\n        ConsumerBatchMessage batchMessage;\n        if (!flatMessage) {\n            batchMessage = new ConsumerBatchMessage<Message>(messageList);\n        } else {\n            batchMessage = new ConsumerBatchMessage<FlatMessage>(messageList);\n        }\n        try {\n            messageBlockingQueue.put(batchMessage);\n        } catch (InterruptedException e) {\n            logger.error(\"Put message to queue error\", e);\n            throw new RuntimeException(e);\n        }\n        boolean isCompleted;\n        try {\n            isCompleted = batchMessage.waitFinish(batchProcessTimeout);\n        } catch (InterruptedException e) {\n            logger.error(\"Interrupted when waiting messages to be finished.\", e);\n            throw new RuntimeException(e);\n        }\n        boolean isSuccess = batchMessage.isSuccess();\n        return isCompleted && isSuccess;\n    }\n\n    @Override\n    public void ack() throws CanalClientException {\n        try {\n            if (this.lastGetBatchMessage != null) {\n                this.lastGetBatchMessage.ack();\n            }\n        } catch (Throwable e) {\n            if (this.lastGetBatchMessage != null) {\n                this.lastGetBatchMessage.fail();\n            }\n        } finally {\n            this.lastGetBatchMessage = null;\n        }\n    }\n\n    @Override\n    public void rollback() throws CanalClientException {\n        try {\n            if (this.lastGetBatchMessage != null) {\n                this.lastGetBatchMessage.fail();\n            }\n        } finally {\n            this.lastGetBatchMessage = null;\n        }\n    }\n\n}\n"
  },
  {
    "path": "client/src/main/java/com/alibaba/otter/canal/client/rocketmq/RocketMQCanalConnector.java",
    "content": "package com.alibaba.otter.canal.client.rocketmq;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.rocketmq.acl.common.AclClientRPCHook;\nimport org.apache.rocketmq.acl.common.SessionCredentials;\nimport org.apache.rocketmq.client.AccessChannel;\nimport org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;\nimport org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyContext;\nimport org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyStatus;\nimport org.apache.rocketmq.client.consumer.listener.MessageListenerOrderly;\nimport org.apache.rocketmq.client.consumer.rebalance.AllocateMessageQueueAveragely;\nimport org.apache.rocketmq.client.exception.MQClientException;\nimport org.apache.rocketmq.common.message.MessageExt;\nimport org.apache.rocketmq.remoting.RPCHook;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.otter.canal.client.CanalMQConnector;\nimport com.alibaba.otter.canal.client.CanalMessageDeserializer;\nimport com.alibaba.otter.canal.client.ConsumerBatchMessage;\nimport com.alibaba.otter.canal.client.impl.SimpleCanalConnector;\nimport com.alibaba.otter.canal.protocol.FlatMessage;\nimport com.alibaba.otter.canal.protocol.Message;\nimport com.alibaba.otter.canal.protocol.exception.CanalClientException;\nimport com.google.common.collect.Lists;\n\n/**\n * RocketMQ的连接\n * \n * <pre>\n * 注意点:\n * 1. 相比于canal {@linkplain SimpleCanalConnector}, 这里get和ack操作不能有并发, 必须是一个线程执行get后，内存里执行完毕ack后再取下一个get\n * </pre>\n * \n * @since 1.1.1\n */\npublic class RocketMQCanalConnector implements CanalMQConnector {\n\n    private static final Logger                 logger               = LoggerFactory.getLogger(RocketMQCanalConnector.class);\n    private static final String                 CLOUD_ACCESS_CHANNEL = \"cloud\";\n\n    private String                              nameServer;\n    private String                              topic;\n    private String                              groupName;\n    private volatile boolean                    connected           = false;\n    private DefaultMQPushConsumer               rocketMQConsumer;\n    private BlockingQueue<ConsumerBatchMessage> messageBlockingQueue;\n    private int                                 batchSize           = -1;\n    private long                                batchProcessTimeout = 60 * 1000;\n    private boolean                             flatMessage;\n    private volatile ConsumerBatchMessage       lastGetBatchMessage = null;\n    private String                              accessKey;\n    private String                              secretKey;\n    private String                              customizedTraceTopic;\n    private boolean                             enableMessageTrace = false;\n    private String                              accessChannel;\n    private String                              namespace;\n\n    public RocketMQCanalConnector(String nameServer, String topic, String groupName, String accessKey,\n        String secretKey, Integer batchSize, boolean flatMessage, boolean enableMessageTrace,\n        String customizedTraceTopic, String accessChannel, String namespace) {\n        this(nameServer, topic, groupName, accessKey, secretKey, batchSize, flatMessage, enableMessageTrace, customizedTraceTopic, accessChannel);\n        this.namespace = namespace;\n    }\n\n    public RocketMQCanalConnector(String nameServer, String topic, String groupName, String accessKey,\n        String secretKey, Integer batchSize, boolean flatMessage, boolean enableMessageTrace,\n        String customizedTraceTopic, String accessChannel) {\n        this(nameServer, topic, groupName, accessKey, secretKey, batchSize, flatMessage);\n        this.enableMessageTrace = enableMessageTrace;\n        this.customizedTraceTopic = customizedTraceTopic;\n        this.accessChannel = accessChannel;\n    }\n\n    public RocketMQCanalConnector(String nameServer, String topic, String groupName, Integer batchSize,\n                                  boolean flatMessage){\n        this.nameServer = nameServer;\n        this.topic = topic;\n        this.groupName = groupName;\n        this.flatMessage = flatMessage;\n        this.messageBlockingQueue = new LinkedBlockingQueue<>(1024);\n        this.batchSize = batchSize;\n    }\n\n    public RocketMQCanalConnector(String nameServer, String topic, String groupName, String accessKey,\n                                  String secretKey, Integer batchSize, boolean flatMessage){\n        this(nameServer, topic, groupName, batchSize, flatMessage);\n        this.accessKey = accessKey;\n        this.secretKey = secretKey;\n    }\n\n    public void connect() throws CanalClientException {\n        RPCHook rpcHook = null;\n        if (null != accessKey && accessKey.length() > 0 && null != secretKey && secretKey.length() > 0) {\n            SessionCredentials sessionCredentials = new SessionCredentials();\n            sessionCredentials.setAccessKey(accessKey);\n            sessionCredentials.setSecretKey(secretKey);\n            rpcHook = new AclClientRPCHook(sessionCredentials);\n        }\n\n        rocketMQConsumer = new DefaultMQPushConsumer(groupName, rpcHook, new AllocateMessageQueueAveragely(), enableMessageTrace, customizedTraceTopic);\n        rocketMQConsumer.setVipChannelEnabled(false);\n        if (CLOUD_ACCESS_CHANNEL.equals(this.accessChannel)) {\n            rocketMQConsumer.setAccessChannel(AccessChannel.CLOUD);\n        }\n\n        if (!StringUtils.isEmpty(this.namespace)) {\n            rocketMQConsumer.setNamespace(this.namespace);\n        }\n\n        if (!StringUtils.isBlank(nameServer)) {\n            rocketMQConsumer.setNamesrvAddr(nameServer);\n        }\n        if (batchSize != -1) {\n            rocketMQConsumer.setConsumeMessageBatchMaxSize(batchSize);\n        }\n    }\n\n    public void disconnect() throws CanalClientException {\n        rocketMQConsumer.shutdown();\n        connected = false;\n    }\n\n    public boolean checkValid() throws CanalClientException {\n        return connected;\n    }\n\n    public synchronized void subscribe(String filter) throws CanalClientException {\n        if (connected) {\n            return;\n        }\n        try {\n            if (rocketMQConsumer == null) {\n                this.connect();\n            }\n            rocketMQConsumer.subscribe(this.topic, \"*\");\n            rocketMQConsumer.registerMessageListener(new MessageListenerOrderly() {\n\n                @Override\n                public ConsumeOrderlyStatus consumeMessage(List<MessageExt> messageExts, ConsumeOrderlyContext context) {\n                    context.setAutoCommit(true);\n                    boolean isSuccess = process(messageExts);\n                    if (isSuccess) {\n                        return ConsumeOrderlyStatus.SUCCESS;\n                    } else {\n                        return ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT;\n                    }\n                }\n            });\n            rocketMQConsumer.start();\n            connected = true;\n        } catch (MQClientException ex) {\n            throw new RuntimeException(\"Start RocketMQ consumer error\", ex);\n        }\n    }\n\n    private boolean process(List<MessageExt> messageExts) {\n        if (logger.isDebugEnabled()) {\n            logger.debug(\"Get Message: {}\", messageExts);\n        }\n        List messageList = new ArrayList<>();\n        for (MessageExt messageExt : messageExts) {\n            byte[] data = messageExt.getBody();\n            if (data != null) {\n                try {\n                    if (!flatMessage) {\n                        Message message = CanalMessageDeserializer.deserializer(data);\n                        messageList.add(message);\n                    } else {\n                        FlatMessage flatMessage = JSON.parseObject(data, FlatMessage.class);\n                        messageList.add(flatMessage);\n                    }\n                } catch (Exception ex) {\n                    logger.error(\"Add message error\", ex);\n                    throw new CanalClientException(ex);\n                }\n            } else {\n                logger.warn(\"Received message data is null\");\n            }\n        }\n        ConsumerBatchMessage batchMessage;\n        if (!flatMessage) {\n            batchMessage = new ConsumerBatchMessage<Message>(messageList);\n        } else {\n            batchMessage = new ConsumerBatchMessage<FlatMessage>(messageList);\n        }\n        try {\n            messageBlockingQueue.put(batchMessage);\n        } catch (InterruptedException e) {\n            logger.error(\"Put message to queue error\", e);\n            throw new RuntimeException(e);\n        }\n        boolean isCompleted;\n        try {\n            isCompleted = batchMessage.waitFinish(batchProcessTimeout);\n        } catch (InterruptedException e) {\n            logger.error(\"Interrupted when waiting messages to be finished.\", e);\n            throw new RuntimeException(e);\n        }\n        boolean isSuccess = batchMessage.isSuccess();\n        return isCompleted && isSuccess;\n    }\n\n    public void subscribe() throws CanalClientException {\n        this.subscribe(null);\n    }\n\n    public void unsubscribe() throws CanalClientException {\n        this.rocketMQConsumer.unsubscribe(this.topic);\n    }\n\n    @Override\n    public List<Message> getList(Long timeout, TimeUnit unit) throws CanalClientException {\n        List<Message> messages = getListWithoutAck(timeout, unit);\n        if (messages != null && !messages.isEmpty()) {\n            ack();\n        }\n        return messages;\n    }\n\n    @Override\n    public List<Message> getListWithoutAck(Long timeout, TimeUnit unit) throws CanalClientException {\n        try {\n            if (this.lastGetBatchMessage != null) {\n                throw new CanalClientException(\"mq get/ack not support concurrent & async ack\");\n            }\n\n            ConsumerBatchMessage batchMessage = messageBlockingQueue.poll(timeout, unit);\n            if (batchMessage != null) {\n                this.lastGetBatchMessage = batchMessage;\n                return batchMessage.getData();\n            }\n        } catch (InterruptedException ex) {\n            logger.warn(\"Get message timeout\", ex);\n            throw new CanalClientException(\"Failed to fetch the data after: \" + timeout);\n        }\n        return Lists.newArrayList();\n    }\n\n    @Override\n    public List<FlatMessage> getFlatList(Long timeout, TimeUnit unit) throws CanalClientException {\n        List<FlatMessage> messages = getFlatListWithoutAck(timeout, unit);\n        if (messages != null && !messages.isEmpty()) {\n            ack();\n        }\n        return messages;\n    }\n\n    @Override\n    public List<FlatMessage> getFlatListWithoutAck(Long timeout, TimeUnit unit) throws CanalClientException {\n        try {\n            if (this.lastGetBatchMessage != null) {\n                throw new CanalClientException(\"mq get/ack not support concurrent & async ack\");\n            }\n\n            ConsumerBatchMessage batchMessage = messageBlockingQueue.poll(timeout, unit);\n            if (batchMessage != null) {\n                this.lastGetBatchMessage = batchMessage;\n                return batchMessage.getData();\n            }\n        } catch (InterruptedException ex) {\n            logger.warn(\"Get message timeout\", ex);\n            throw new CanalClientException(\"Failed to fetch the data after: \" + timeout);\n        }\n        return Lists.newArrayList();\n    }\n\n    @Override\n    public void ack() throws CanalClientException {\n        try {\n            if (this.lastGetBatchMessage != null) {\n                this.lastGetBatchMessage.ack();\n            }\n        } catch (Throwable e) {\n            if (this.lastGetBatchMessage != null) {\n                this.lastGetBatchMessage.fail();\n            }\n        } finally {\n            this.lastGetBatchMessage = null;\n        }\n    }\n\n    @Override\n    public void rollback() throws CanalClientException {\n        try {\n            if (this.lastGetBatchMessage != null) {\n                this.lastGetBatchMessage.fail();\n            }\n        } finally {\n            this.lastGetBatchMessage = null;\n        }\n    }\n\n    public Message get(int batchSize) throws CanalClientException {\n        throw new CanalClientException(\"mq not support this method\");\n    }\n\n    @Override\n    public Message get(int batchSize, Long timeout, TimeUnit unit) throws CanalClientException {\n        throw new CanalClientException(\"mq not support this method\");\n    }\n\n    @Override\n    public Message getWithoutAck(int batchSize) throws CanalClientException {\n        throw new CanalClientException(\"mq not support this method\");\n    }\n\n    @Override\n    public Message getWithoutAck(int batchSize, Long timeout, TimeUnit unit) throws CanalClientException {\n        throw new CanalClientException(\"mq not support this method\");\n    }\n\n    @Override\n    public void ack(long batchId) throws CanalClientException {\n        throw new CanalClientException(\"mq not support this method\");\n    }\n\n    @Override\n    public void rollback(long batchId) throws CanalClientException {\n        throw new CanalClientException(\"mq not support this method\");\n    }\n\n}\n"
  },
  {
    "path": "client/src/test/java/com/alibaba/otter/canal/client/running/AbstractZkTest.java",
    "content": "package com.alibaba.otter.canal.client.running;\n\nimport org.junit.Assert;\n\npublic class AbstractZkTest {\n\n    protected String destination = \"ljhtest1\";\n    protected String cluster1    = \"127.0.0.1:2188\";\n    protected String cluster2    = \"127.0.0.1:2188,127.0.0.1:2188\";\n\n    public void sleep(long time) {\n        try {\n            Thread.sleep(time);\n        } catch (InterruptedException e) {\n            Assert.fail(e.getMessage());\n        }\n    }\n}\n"
  },
  {
    "path": "client/src/test/java/com/alibaba/otter/canal/client/running/ClientRunningTest.java",
    "content": "package com.alibaba.otter.canal.client.running;\n\nimport java.net.InetSocketAddress;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport org.apache.commons.lang.math.RandomUtils;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.client.impl.running.ClientRunningData;\nimport com.alibaba.otter.canal.client.impl.running.ClientRunningListener;\nimport com.alibaba.otter.canal.client.impl.running.ClientRunningMonitor;\nimport com.alibaba.otter.canal.common.utils.AddressUtils;\nimport com.alibaba.otter.canal.common.zookeeper.ZkClientx;\nimport com.alibaba.otter.canal.common.zookeeper.ZookeeperPathUtils;\n@Ignore\npublic class ClientRunningTest extends AbstractZkTest {\n\n    private ZkClientx zkclientx = new ZkClientx(cluster1 + \";\" + cluster2);\n    private short     clientId  = 1001;\n\n    @Before\n    public void setUp() {\n        String path = ZookeeperPathUtils.getDestinationPath(destination);\n        zkclientx.deleteRecursive(path);\n\n        zkclientx.createPersistent(ZookeeperPathUtils.getClientIdNodePath(this.destination, clientId), true);\n    }\n\n    @After\n    public void tearDown() {\n        String path = ZookeeperPathUtils.getDestinationPath(destination);\n        zkclientx.deleteRecursive(path);\n    }\n\n    @Test\n    public void testOneServer() {\n        final CountDownLatch countLatch = new CountDownLatch(2);\n        ClientRunningMonitor runningMonitor = buildClientRunning(countLatch, clientId, 2088);\n        runningMonitor.start();\n        sleep(2000L);\n        runningMonitor.stop();\n        sleep(2000L);\n\n        if (countLatch.getCount() != 0) {\n            Assert.fail();\n        }\n    }\n\n    @Test\n    public void testMultiServer() {\n        final CountDownLatch countLatch = new CountDownLatch(30);\n        final ClientRunningMonitor runningMonitor1 = buildClientRunning(countLatch, clientId, 2088);\n        final ClientRunningMonitor runningMonitor2 = buildClientRunning(countLatch, clientId, 2089);\n        final ClientRunningMonitor runningMonitor3 = buildClientRunning(countLatch, clientId, 2090);\n        final ExecutorService executor = Executors.newFixedThreadPool(3);\n        executor.submit(() -> {\n            for (int i = 0; i < 10; i++) {\n                if (!runningMonitor1.isStart()) {\n                    runningMonitor1.start();\n                }\n                sleep(2000L + RandomUtils.nextInt(500));\n                runningMonitor1.stop();\n                sleep(2000L + RandomUtils.nextInt(500));\n            }\n        });\n\n        executor.submit(() -> {\n            for (int i = 0; i < 10; i++) {\n                if (!runningMonitor2.isStart()) {\n                    runningMonitor2.start();\n                }\n                sleep(2000L + RandomUtils.nextInt(500));\n                runningMonitor2.stop();\n                sleep(2000L + RandomUtils.nextInt(500));\n            }\n        });\n\n        executor.submit(() -> {\n            for (int i = 0; i < 10; i++) {\n                if (!runningMonitor3.isStart()) {\n                    runningMonitor3.start();\n                }\n                sleep(2000L + RandomUtils.nextInt(500));\n                runningMonitor3.stop();\n                sleep(2000L + RandomUtils.nextInt(500));\n            }\n        });\n\n        sleep(30000L);\n    }\n\n    private ClientRunningMonitor buildClientRunning(final CountDownLatch countLatch, final short clientId,\n                                                    final int port) {\n        ClientRunningData clientData = new ClientRunningData();\n        clientData.setClientId(clientId);\n        clientData.setAddress(AddressUtils.getHostIp());\n\n        ClientRunningMonitor runningMonitor = new ClientRunningMonitor();\n        runningMonitor.setDestination(destination);\n        runningMonitor.setZkClient(zkclientx);\n        runningMonitor.setClientData(clientData);\n        runningMonitor.setListener(new ClientRunningListener() {\n\n            public InetSocketAddress processActiveEnter() {\n                System.out.println(String.format(\"clientId:%s port:%s has start\", clientId, port));\n                countLatch.countDown();\n                return new InetSocketAddress(AddressUtils.getHostIp(), port);\n            }\n\n            public void processActiveExit() {\n                countLatch.countDown();\n                System.out.println(String.format(\"clientId:%s port:%s has stop\", clientId, port));\n            }\n\n        });\n        runningMonitor.setDelayTime(1);\n        return runningMonitor;\n    }\n}\n"
  },
  {
    "path": "client/src/test/java/logback.xml",
    "content": "<configuration scan=\"true\" scanPeriod=\" 5 seconds\">\n\n\t<jmxConfigurator />\n\t<appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n\t\t<encoder>\n\t\t\t<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{56} - %msg%n\n\t\t\t</pattern>\n\t\t</encoder>\n\t</appender>\n\t\n\t<root level=\"INFO\">\n\t\t<appender-ref ref=\"STDOUT\"/>\n\t</root>\n</configuration>"
  },
  {
    "path": "client-adapter/README.md",
    "content": "## 基本说明\ncanal 1.1.1版本之后, 增加客户端数据落地的适配及启动功能, 目前支持功能:\n* 客户端启动器\n* 同步管理REST接口\n* 日志适配器, 作为DEMO\n* HBase的数据同步(表对表同步), ETL功能\n* (后续支持) ElasticSearch多表数据同步,ETL功能\n\n## 环境版本\n* 操作系统：无要求\n* java版本: jdk1.8 以上 \n* canal 版本: 请下载最新的安装包，本文以当前v1.1.1 的canal.deployer-1.1.1.tar.gz为例\n* MySQL版本 ：5.7.18\n* HBase版本: Apache HBase 1.1.2, 若和服务端版本不一致可自行替换客户端HBase依赖\n\n## 一、适配器启动器\nclient-adapter分为适配器和启动器两部分, 适配器为多个fat jar, 每个适配器会将自己所需的依赖打成一个包, 以SPI的方式让启动器动态加载\n\n\n启动器为 SpringBoot 项目, 支持canal-client启动的同时提供相关REST管理接口, 运行目录结构为:\n```\n- bin\n    restart.sh\n    startup.bat\n    startup.sh\n    stop.sh\n- lib\n    client-adapter.logger-1.1.1-jar-with-dependencies.jar\n    client-adapter.hbase-1.1.1-jar-with-dependencies.jar\n    ...\n- conf\n    application.yml\n    - hbase\n        mytest_person2.yml\n- logs\n```\n以上目录结构最终会打包成 canal-adapter-launcher.tar.gz 压缩包\n\n## 二、启动器\n### 2.1 启动器配置 application.yml\n#### canal相关配置部分说明\n```\ncanal.conf:\n  canalServerHost: 127.0.0.1:11111  # 对应单机模式下的canal server的ip:port\n  zookeeperHosts: slave1:2181       # 对应集群模式下的zk地址, 如果配置了canalServerHost, 则以canalServerHost为准\n  bootstrapServers: slave1:6667     # kafka或rocketMQ地址, 与canalServerHost不能并存\n  flatMessage: true                 # 扁平message开关, 是否以json字符串形式投递数据, 仅在kafka/rocketMQ模式下有效\n  canalInstances:                   # canal实例组, 如果是tcp模式可配置此项\n  - instance: example               # 对应canal destination\n    groups:                  # 对应适配器分组, 分组间的适配器并行运行\n    - outAdapters:                  # 适配器列表, 分组内的适配串行运行\n      - name: logger                # 适配器SPI名\n      - name: hbase\n        properties:                 # HBase相关连接参数\n          hbase.zookeeper.quorum: slave1\n          hbase.zookeeper.property.clientPort: 2181\n          zookeeper.znode.parent: /hbase\n  mqTopics:                         # MQ topic组, 如果是kafka或者rockeMQ模式可配置此项, 与canalInstances不能并存\n  - mqMode: kafka                   # MQ的模式: kafak/rocketMQ\n    topic: example                  # MQ topic\n    groups:                         # group组\n    - groupId: g2                   # group id\n      outAdapters:                  # 适配器列表, 以下配置和canalInstances中一样\n      - name: logger                \n```\n#### 适配器相关配置部分说明\n```\nadapter.conf:\n  datasourceConfigs:                # 数据源配置列表, 数据源将在适配器中用于ETL、数据同步回查等使用\n    defaultDS:                      # 数据源 dataSourceKey, 适配器中通过该值获取指定数据源\n      url: jdbc:mysql://127.0.0.1:3306/mytest?useUnicode=true\n      username: root\n      password: 121212\n  adapterConfigs:                   # 适配器内部配置列表\n  - hbase/mytest_person2.yml        # 类型/配置文件名, 这里示例就是对应HBase适配器hbase目录下的mytest_person2.yml文件\n```\n## 2.2 同步管理REST接口\n#### 2.2.1 查询所有订阅同步的canal destination或MQ topic\n```\ncurl http://127.0.0.1:8081/destinations\n```\n#### 2.2.2 数据同步开关\n```\ncurl http://127.0.0.1:8081/syncSwitch/example/off -X PUT\n```\n针对 example 这个canal destination/MQ topic 进行开关操作. off代表关闭, 该destination/topic下的同步将阻塞或者断开连接不再接收数据, on代表开启\n\n注: 如果在配置文件中配置了 zookeeperHosts 项, 则会使用分布式锁来控制HA中的数据同步开关, 如果是单机模式则使用本地锁来控制开关\n#### 2.2.3 数据同步开关状态\n```\ncurl http://127.0.0.1:8081/syncSwitch/example\n```\n查看指定 canal destination/MQ topic 的数据同步开关状态\n#### 2.2.4 手动ETL\n```\ncurl http://127.0.0.1:8081/etl/hbase/mytest_person2.yml -X POST -d \"params=2018-10-21 00:00:00\"\n```\n导入数据到指定类型的库\n#### 2.2.5 查看相关库总数据\n```\ncurl http://127.0.0.1:8081/count/hbase/mytest_person2.yml\n```\n### 2.3 启动canal-adapter示例\n#### 2.3.1 启动canal server (单机模式), 参考: [Canal QuickStart](https://github.com/alibaba/canal/wiki/QuickStart)\n#### 2.3.2 修改conf/application.yml为:\n```\nserver:\n  port: 8081\nlogging:\n  level:\n    com.alibaba.otter.canal.client.adapter.hbase: DEBUG\nspring:\n  jackson:\n    date-format: yyyy-MM-dd HH:mm:ss\n    time-zone: GMT+8\n    default-property-inclusion: non_null\n\ncanal.conf:\n  canalServerHost: 127.0.0.1:11111\n  flatMessage: true\n  canalInstances:\n  - instance: example\n    adapterGroups:\n    - outAdapters:\n      - name: logger\n```\n启动\n```\nbin/startup.sh\n```\n\n## 三、HBase适配器\n### 3.1 修改启动器配置: application.yml\n```\nserver:\n  port: 8081\nlogging:\n  level:\n    com.alibaba.otter.canal.client.adapter.hbase: DEBUG\nspring:\n  jackson:\n    date-format: yyyy-MM-dd HH:mm:ss\n    time-zone: GMT+8\n    default-property-inclusion: non_null\n\ncanal.conf:\n  canalServerHost: 127.0.0.1:11111\n  flatMessage: true\n  srcDataSources:\n    defaultDS:\n      url: jdbc:mysql://127.0.0.1:3306/mytest?useUnicode=true\n      username: root\n      password: 121212\n  canalInstances:\n  - instance: example\n    adapterGroups:\n    - outAdapters:\n      - name: hbase\n        properties:\n          hbase.zookeeper.quorum: slave1\n          hbase.zookeeper.property.clientPort: 2181\n          zookeeper.znode.parent: /hbase\n```\nadapter将会自动加载 conf/hbase 下的所有.yml结尾的配置文件\n### 3.2 适配器表映射文件\n修改 conf/hbase/mytest_person.yml文件:\n```\ndataSourceKey: defaultDS            # 对应application.yml中的datasourceConfigs下的配置\nhbaseMapping:                       # mysql--HBase的单表映射配置\n  mode: STRING                      # HBase中的存储类型, 默认统一存为String, 可选: #PHOENIX  #NATIVE   #STRING \n                                    # NATIVE: 以java类型为主, PHOENIX: 将类型转换为Phoenix对应的类型\n  destination: example              # 对应 canal destination/MQ topic 名称\n  database: mytest                  # 数据库名/schema名\n  table: person                     # 表名\n  hbaseTable: MYTEST.PERSON         # HBase表名\n  family: CF                        # 默认统一Column Family名称\n  uppercaseQualifier: true          # 字段名转大写, 默认为true\n  commitBatch: 3000                 # 批量提交的大小, ETL中用到\n  #rowKey: id,type                  # 复合字段rowKey不能和columns中的rowKey并存\n                                    # 复合rowKey会以 '|' 分隔\n  columns:                          # 字段映射, 如果不配置将自动映射所有字段, \n                                    # 并取第一个字段为rowKey, HBase字段名以mysql字段名为主\n    id: ROWKE                       \n    name: CF:NAME\n    email: EMAIL                    # 如果column family为默认CF, 则可以省略\n    type:                           # 如果HBase字段和mysql字段名一致, 则可以省略\n    c_time: \n    birthday: \n```\n如果涉及到类型转换,可以如下形式:\n```\n...\n  columns:                         \n    id: ROWKE$STRING                      \n    ...                   \n    type: TYPE$BYTE                          \n    ...\n```\n类型转换涉及到Java类型和Phoenix类型两种, 分别定义如下:\n```\n#Java 类型转换, 对应配置 mode: NATIVE\n$DEFAULT\n$STRING\n$INTEGER\n$LONG\n$SHORT\n$BOOLEAN\n$FLOAT\n$DOUBLE\n$BIGDECIMAL\n$DATE\n$BYTE\n$BYTES\n```\n```\n#Phoenix 类型转换, 对应配置 mode: PHOENIX\n$DEFAULT                  对应PHOENIX里的VARCHAR\n$UNSIGNED_INT             对应PHOENIX里的UNSIGNED_INT           4字节\n$UNSIGNED_LONG            对应PHOENIX里的UNSIGNED_LONG          8字节\n$UNSIGNED_TINYINT         对应PHOENIX里的UNSIGNED_TINYINT       1字节\n$UNSIGNED_SMALLINT        对应PHOENIX里的UNSIGNED_SMALLINT      2字节\n$UNSIGNED_FLOAT           对应PHOENIX里的UNSIGNED_FLOAT         4字节\n$UNSIGNED_DOUBLE          对应PHOENIX里的UNSIGNED_DOUBLE        8字节\n$INTEGER                  对应PHOENIX里的INTEGER                4字节\n$BIGINT                   对应PHOENIX里的BIGINT                 8字节\n$TINYINT                  对应PHOENIX里的TINYINT                1字节\n$SMALLINT                 对应PHOENIX里的SMALLINT               2字节\n$FLOAT                    对应PHOENIX里的FLOAT                  4字节\n$DOUBLE                   对应PHOENIX里的DOUBLE                 8字节\n$BOOLEAN                  对应PHOENIX里的BOOLEAN                1字节\n$TIME                     对应PHOENIX里的TIME                   8字节\n$DATE                     对应PHOENIX里的DATE                   8字节\n$TIMESTAMP                对应PHOENIX里的TIMESTAMP              12字节\n$UNSIGNED_TIME            对应PHOENIX里的UNSIGNED_TIME          8字节\n$UNSIGNED_DATE            对应PHOENIX里的UNSIGNED_DATE          8字节\n$UNSIGNED_TIMESTAMP       对应PHOENIX里的UNSIGNED_TIMESTAMP     12字节\n$VARCHAR                  对应PHOENIX里的VARCHAR                动态长度\n$VARBINARY                对应PHOENIX里的VARBINARY              动态长度\n$DECIMAL                  对应PHOENIX里的DECIMAL                动态长度\n```\n如果不配置将以java对象原生类型默认映射转换\n### 3.3 启动HBase数据同步\n#### 创建HBase表\n在HBase shell中运行:\n```\ncreate 'MYTEST.PERSON', {NAME=>'CF'}\n```\n#### 启动canal-adapter启动器\n```\nbin/startup.sh\n```\n#### 验证\n修改mysql mytest.person表的数据, 将会自动同步到HBase的MYTEST.PERSON表下面, 并会打出DML的log\n\n\n## 四、关系型数据库适配器\n\nRDB adapter 用于适配mysql到任意关系型数据库(需支持jdbc)的数据同步及导入\n\n### 4.1 修改启动器配置: application.yml, 这里以oracle目标库为例\n```\nserver:\n  port: 8081\nlogging:\n  level:\n    com.alibaba.otter.canal.client.adapter.rdb: DEBUG\n......\n\ncanal.conf:\n  canalServerHost: 127.0.0.1:11111\n  srcDataSources:\n    defaultDS:\n      url: jdbc:mysql://127.0.0.1:3306/mytest?useUnicode=true\n      username: root\n      password: 121212\n  canalInstances:\n  - instance: example\n    groups:\n    - outAdapters:\n      - name: rdb                                               # 指定为rdb类型同步\n        key: oracle1                                            # 指定adapter的唯一key, 与表映射配置中outerAdapterKey对应\n        properties:\n          jdbc.driverClassName: oracle.jdbc.OracleDriver        # jdbc驱动名, jdbc的jar包需要自行放致lib目录下\n          jdbc.url: jdbc:oracle:thin:@localhost:49161:XE        # jdbc url\n          jdbc.username: mytest                                 # jdbc username\n          jdbc.password: m121212                                # jdbc password\n          threads: 5                                            # 并行执行的线程数, 默认为1\n          commitSize: 3000                                      # 批次提交的最大行数\n```\n其中 outAdapter 的配置: name统一为rdb, key为对应的数据源的唯一标识需和下面的表映射文件中的outerAdapterKey对应, properties为目标库jdb的相关参数\nadapter将会自动加载 conf/rdb 下的所有.yml结尾的表映射配置文件\n\n### 4.2 适配器表映射文件\n修改 conf/rdb/mytest_user.yml文件:\n```\ndataSourceKey: defaultDS        # 源数据源的key, 对应上面配置的srcDataSources中的值\ndestination: example            # cannal的instance或者MQ的topic\nouterAdapterKey: oracle1        # adapter key, 对应上面配置outAdapters中的key\nconcurrent: true                # 是否按主键hase并行同步, 并行同步的表必须保证主键不会更改及主键不能为其他同步表的外键!!\ndbMapping:\n  database: mytest              # 源数据源的database/shcema\n  table: user                   # 源数据源表名\n  targetTable: mytest.tb_user   # 目标数据源的库名.表名\n  targetPk:                     # 主键映射\n    id: id                      # 如果是复合主键可以换行映射多个\n#  mapAll: true                 # 是否整表映射, 要求源表和目标表字段名一模一样 (如果targetColumns也配置了映射,则以targetColumns配置为准)\n  targetColumns:                # 字段映射, 格式: 目标表字段: 源表字段, 如果字段名一样源表字段名可不填\n    id:\n    name:\n    role_id:\n    c_time:\n    test1: \n```\n导入的类型以目标表的元类型为准, 将自动转换\n\n### 4.3 启动RDB数据同步\n#### 将目标库的jdbc jar包放入lib文件夹, 这里放入ojdbc6.jar\n\n#### 启动canal-adapter启动器\n```\nbin/startup.sh\n```\n#### 验证\n修改mysql mytest.user表的数据, 将会自动同步到Oracle的MYTEST.TB_USER表下面, 并会打出DML的log\n\n\n## 五、ElasticSearch适配器\n### 5.1 修改启动器配置: application.yml\n```\nserver:\n  port: 8081\nlogging:\n  level:\n    com.alibaba.otter.canal.client.adapter.es: DEBUG\nspring:\n  jackson:\n    date-format: yyyy-MM-dd HH:mm:ss\n    time-zone: GMT+8\n    default-property-inclusion: non_null\n\ncanal.conf:\n  canalServerHost: 127.0.0.1:11111\n  flatMessage: true\n  srcDataSources:\n    defaultDS:\n      url: jdbc:mysql://127.0.0.1:3306/mytest?useUnicode=true\n      username: root\n      password: 121212\n  canalInstances:\n  - instance: example\n    adapterGroups:\n    - outAdapters:\n      - name: es\n        hosts: 127.0.0.1:9300               # es 集群地址, 逗号分隔\n        properties:\n          cluster.name: elasticsearch       # es cluster name\n```\nadapter将会自动加载 conf/es 下的所有.yml结尾的配置文件\n### 5.2 适配器表映射文件\n修改 conf/es/mytest_user.yml文件:\n```\ndataSourceKey: defaultDS        # 源数据源的key, 对应上面配置的srcDataSources中的值\ndestination: example            # cannal的instance或者MQ的topic\nesMapping:\n  _index: mytest_user           # es 的索引名称\n  _type: _doc                   # es 的doc名称\n  _id: _id                      # es 的_id, 如果不配置该项必须配置下面的pk项_id则会由es自动分配\n#  pk: id                       # 如果不需要_id, 则需要指定一个属性为主键属性\n  # sql映射\n  sql: \"select a.id as _id, a.name as _name, a.role_id as _role_id, b.role_name as _role_name,\n        a.c_time as _c_time, c.labels as _labels from user a\n        left join role b on b.id=a.role_id\n        left join (select user_id, group_concat(label order by id desc separator ';') as labels from label\n        group by user_id) c on c.user_id=a.id\"\n#  objFields:\n#    _labels: array:;           # 数组或者对象属性, array:; 代表以;字段里面是以;分隔的\n#    _obj: obj:{\"test\":\"123\"}\n  etlCondition: \"where a.c_time>='{0}'\"     # etl 的条件参数\n  commitBatch: 3000                         # 提交批大小\n```\nsql映射说明: \n\nsql支持多表关联自由组合, 但是有一定的限制: \n1. 主表不能为子查询语句\n2. 只能使用left outer join即最左表一定要是主表\n3. 关联从表如果是子查询不能有多张表\n4. 主sql中不能有where查询条件(从表子查询中可以有where条件但是不推荐, 可能会造成数据同步的不一致, 比如修改了where条件中的字段内容)\n5. 关联条件只允许主外键的'='操作不能出现其他常量判断比如: on a.role_id=b.id and b.statues=1\n6. 关联条件必须要有一个字段出现在主查询语句中比如: on a.role_id=b.id  其中的 a.role_id 或者 b.id 必须出现在主select语句中\n\n\nElastic Search的mapping 属性与sql的查询值将一一对应(不支持 select *), 比如: select a.id as _id, a.name, a.email as _email from user, 其中name将映射到es mapping的name field, _email将\n映射到mapping的_email field, 这里以别名(如果有别名)作为最终的映射字段. 这里的_id可以填写到配置文件的 _id: _id映射. \n\n#### 5.2.1.单表映射索引示例sql:\n```\nselect a.id as _id, a.name, a.role_id, a.c_time from user a\n```\n该sql对应的es mapping示例:\n```\n{\n    \"mytest_user\": {\n        \"mappings\": {\n            \"_doc\": {\n                \"properties\": {\n                    \"name\": {\n                        \"type\": \"text\"\n                    },\n                    \"role_id\": {\n                        \"type\": \"long\"\n                    },\n                    \"c_time\": {\n                        \"type\": \"date\"\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\n#### 5.2.2.单表映射索引示例sql带函数或运算操作:\n```\nselect a.id as _id, concat(a.name,'_test') as name, a.role_id+10000 as role_id, a.c_time from user a\n```\n函数字段后必须跟上别名, 该sql对应的es mapping示例:\n```\n{\n    \"mytest_user\": {\n        \"mappings\": {\n            \"_doc\": {\n                \"properties\": {\n                    \"name\": {\n                        \"type\": \"text\"\n                    },\n                    \"role_id\": {\n                        \"type\": \"long\"\n                    },\n                    \"c_time\": {\n                        \"type\": \"date\"\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\n#### 5.2.3.多表映射(一对一, 多对一)索引示例sql:\n```\nselect a.id as _id, a.name, a.role_id, b.role_name, a.c_time from user a \nleft join role b on b.id = a.role_id\n```\n注:这里join操作只能是left outer join, 第一张表必须为主表!!\n\n该sql对应的es mapping示例:\n```\n{\n    \"mytest_user\": {\n        \"mappings\": {\n            \"_doc\": {\n                \"properties\": {\n                    \"name\": {\n                        \"type\": \"text\"\n                    },\n                    \"role_id\": {\n                        \"type\": \"long\"\n                    },\n                    \"role_name\": {\n                        \"type\": \"text\"\n                    },\n                    \"c_time\": {\n                        \"type\": \"date\"\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\n#### 5.2.4.多表映射(一对多)索引示例sql:\n```\nselect a.id as _id, a.name, a.role_id, c.labels, a.c_time from user a \nleft join (select user_id, group_concat(label order by id desc separator ';') as labels from label\n        group by user_id) c on c.user_id=a.id\n```\n注:left join 后的子查询只允许一张表, 即子查询中不能再包含子查询或者关联!!\n\n该sql对应的es mapping示例:\n```\n{\n    \"mytest_user\": {\n        \"mappings\": {\n            \"_doc\": {\n                \"properties\": {\n                    \"name\": {\n                        \"type\": \"text\"\n                    },\n                    \"role_id\": {\n                        \"type\": \"long\"\n                    },\n                    \"c_time\": {\n                        \"type\": \"date\"\n                    },\n                    \"labels\": {\n                        \"type\": \"text\"\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\n#### 5.2.5.其它类型的sql示例:\n- geo type\n```\nselect ... concat(IFNULL(a.latitude, 0), ',', IFNULL(a.longitude, 0)) AS location, ...\n```\n- 复合主键\n```\nselect concat(a.id,'_',b.type) as _id, ... from user a left join role b on b.id=a.role_id\n```\n- 数组字段\n```\nselect a.id as _id, a.name, a.role_id, c.labels, a.c_time from user a \nleft join (select user_id, group_concat(label order by id desc separator ';') as labels from label\n        group by user_id) c on c.user_id=a.id\n```\n配置中使用:\n```\nobjFields:\n  labels: array:;\n```\n\n### 5.3 启动ES数据同步\n#### 启动canal-adapter启动器\n```\nbin/startup.sh\n```\n#### 验证\n1. 新增mysql mytest.user表的数据, 将会自动同步到es的mytest_user索引下面, 并会打出DML的log\n2. 修改mysql mytest.role表的role_name, 将会自动同步es的mytest_user索引中的role_name数据\n3. 新增或者修改mysql mytest.label表的label, 将会自动同步es的mytest_user索引中的labels数据\n"
  },
  {
    "path": "client-adapter/clickhouse/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>canal.client-adapter</artifactId>\n        <groupId>com.alibaba.otter</groupId>\n        <version>1.1.9-SNAPSHOT</version>\n        <relativePath>../pom.xml</relativePath>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>com.alibaba.otter</groupId>\n    <artifactId>client-adapter.clickhouse</artifactId>\n    <packaging>jar</packaging>\n    <name>canal client adapter clickhouse module for otter ${project.version}</name>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>client-adapter.common</artifactId>\n            <version>${project.version}</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>ru.yandex.clickhouse</groupId>\n            <artifactId>clickhouse-jdbc</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.yaml</groupId>\n            <artifactId>snakeyaml</artifactId>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-assembly-plugin</artifactId>\n                <version>2.4</version>\n                <configuration>\n                    <descriptorRefs>\n                        <descriptorRef>jar-with-dependencies</descriptorRef>\n                    </descriptorRefs>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>make-assembly</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>single</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-antrun-plugin</artifactId>\n                <version>1.8</version>\n                <executions>\n                    <execution>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>run</goal>\n                        </goals>\n                        <configuration>\n                            <tasks>\n                                <copy todir=\"${project.basedir}/../launcher/target/classes/clickhouse\" overwrite=\"true\">\n                                    <fileset dir=\"${project.basedir}/target/classes/clickhouse\" erroronmissingdir=\"true\">\n                                        <include name=\"*.yml\" />\n                                    </fileset>\n                                </copy>\n                            </tasks>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "client-adapter/clickhouse/src/main/java/com/alibaba/otter/canal/client/adapter/clickhouse/ClickHouseAdapter.java",
    "content": "package com.alibaba.otter.canal.client.adapter.clickhouse;\n\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.apache.commons.lang.BooleanUtils;\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.druid.filter.stat.StatFilter;\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.alibaba.druid.util.JdbcUtils;\nimport com.alibaba.otter.canal.client.adapter.OuterAdapter;\nimport com.alibaba.otter.canal.client.adapter.clickhouse.config.ConfigLoader;\nimport com.alibaba.otter.canal.client.adapter.clickhouse.config.MappingConfig;\nimport com.alibaba.otter.canal.client.adapter.clickhouse.config.MirrorDbConfig;\nimport com.alibaba.otter.canal.client.adapter.clickhouse.monitor.ClickHouseConfigMonitor;\nimport com.alibaba.otter.canal.client.adapter.clickhouse.service.ClickHouseBatchSyncService;\nimport com.alibaba.otter.canal.client.adapter.clickhouse.service.ClickHouseEtlService;\nimport com.alibaba.otter.canal.client.adapter.clickhouse.service.ClickHouseMirrorDbBatchSyncService;\nimport com.alibaba.otter.canal.client.adapter.clickhouse.support.SyncUtil;\nimport com.alibaba.otter.canal.client.adapter.support.*;\n\n/**\n * ClickHouse Adapter implementation\n *\n * @author: Xander\n * @date: Created in 2023/11/10 1:13\n * @email: zhrunxin33@gmail.com\n */\n@SPI\npublic class ClickHouseAdapter implements OuterAdapter {\n\n    private static final Logger                         logger = LoggerFactory.getLogger(ClickHouseAdapter.class);\n\n    // Store the mapping of filename and configuration, load yml files below\n    // resource path\n    private Map<String, MappingConfig>              clickHouseMapping   = new ConcurrentHashMap<>();\n\n    // Schema -> Table -> MappingConfig\n    private Map<String, Map<String, MappingConfig>> mappingConfigCache  = new ConcurrentHashMap<>();\n\n    // Mirror DB Configuration, don't need to load column mapping\n    private Map<String, MirrorDbConfig>             mirrorDbConfigCache = new ConcurrentHashMap<>();\n\n    private DruidDataSource                             dataSource;\n\n    private ClickHouseBatchSyncService clickHouseBatchSyncService;\n\n    private ClickHouseMirrorDbBatchSyncService clickHouseMirrorDbBatchSyncService;\n\n    private Properties                                  envProperties;\n\n    // Launch configuration\n    private OuterAdapterConfig                      configuration;\n\n    private ClickHouseConfigMonitor clickHouseConfigMonitor;\n\n    public Map<String, MappingConfig> getClickHouseMapping() {\n        return clickHouseMapping;\n    }\n\n    @Override\n    public void init(OuterAdapterConfig configuration, Properties envProperties) {\n        this.envProperties = envProperties;\n        this.configuration = configuration;\n        // Load DB type from adapter.launch/bootstrap.yml\n        Map<String, String> properties = configuration.getProperties();\n        String dbType = JdbcUtils.getDbType(properties.get(\"jdbc.url\"), null);\n        // 当.yml文件编码格式存在问题，此处clickhouse yml文件构建 可能会抛出异常\n        Map<String, MappingConfig> clickHouseMappingTmp = ConfigLoader.load(envProperties);\n        // 过滤不匹配的key的配置\n        clickHouseMappingTmp.forEach((key, config) -> {\n            addConfig(key, config);\n        });\n\n        if (clickHouseMapping.isEmpty()) {\n            throw new RuntimeException(\"No clickhouse adapter found for config key: \" + configuration.getKey());\n        }\n\n        // 初始化连接池\n        dataSource = new DruidDataSource();\n        dataSource.setDriverClassName(properties.get(\"jdbc.driverClassName\"));\n        dataSource.setUrl(properties.get(\"jdbc.url\"));\n        dataSource.setUsername(properties.get(\"jdbc.username\"));\n        dataSource.setPassword(properties.get(\"jdbc.password\"));\n        dataSource.setInitialSize(1);\n        dataSource.setMinIdle(1);\n        dataSource.setMaxActive(30);\n        dataSource.setMaxWait(60000);\n        dataSource.setTimeBetweenEvictionRunsMillis(60000);\n        dataSource.setMinEvictableIdleTimeMillis(300000);\n        dataSource.setUseUnfairLock(true);\n        dataSource.setDefaultAutoCommit(false); // disable auto commit or disable Transactional\n        dataSource.setDbType(dbType);\n\n        if (\"true\".equals(properties.getOrDefault(\"druid.stat.enable\", \"true\"))) {\n            StatFilter statFilter = new StatFilter();\n            statFilter.setSlowSqlMillis(Long.parseLong(properties.getOrDefault(\"druid.stat.slowSqlMillis\", \"1000\")));\n            statFilter.setMergeSql(true);\n            statFilter.setLogSlowSql(true);\n            dataSource.setProxyFilters(Collections.singletonList(statFilter));\n        }\n\n        try {\n            dataSource.init();\n        } catch (SQLException e) {\n            logger.error(\"ERROR ## failed to initial datasource: \" + properties.get(\"jdbc.url\"), e);\n        }\n\n        String threads = properties.get(\"threads\");\n        String scheduleTime = properties.get(\"scheduleTime\");\n        String batchSize = properties.get(\"batchSize\");\n\n        boolean skipDupException = BooleanUtils.toBoolean(configuration.getProperties()\n                .getOrDefault(\"skipDupException\", \"true\"));\n        clickHouseBatchSyncService = new ClickHouseBatchSyncService(dataSource,\n                threads != null ? Integer.valueOf(threads) : null,\n                batchSize != null ? Integer.valueOf(batchSize) : null,\n                scheduleTime != null ? Long.valueOf(scheduleTime) : null,\n                skipDupException);\n\n        clickHouseMirrorDbBatchSyncService = new ClickHouseMirrorDbBatchSyncService(mirrorDbConfigCache,\n                dataSource,\n                threads != null ? Integer.valueOf(threads) : null,\n                batchSize != null ? Integer.valueOf(batchSize) : null,\n                scheduleTime != null ? Long.valueOf(scheduleTime) : null,\n                clickHouseBatchSyncService.getColumnsTypeCache(),\n                skipDupException);\n\n        clickHouseConfigMonitor = new ClickHouseConfigMonitor();\n        clickHouseConfigMonitor.init(configuration.getKey(), this, envProperties);\n    }\n\n    /**\n     * Sync main entrance\n     *\n     * @param dmls 数据包\n     */\n    @Override\n    public void sync(List<Dml> dmls) {\n        if (dmls == null || dmls.isEmpty()) {\n            return;\n        }\n        try {\n            // If mappingConfigCache(column mapping) is empty, that must be mirroring synchronize\n            if (!mappingConfigCache.isEmpty()) {\n                clickHouseBatchSyncService.sync(mappingConfigCache, dmls, envProperties);\n            }\n            clickHouseMirrorDbBatchSyncService.sync(dmls);\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * Destroy\n     */\n    @Override\n    public void destroy() {\n        if (clickHouseConfigMonitor != null) {\n            clickHouseConfigMonitor.destroy();\n        }\n\n        if (clickHouseBatchSyncService != null) {\n            clickHouseBatchSyncService.close();\n        }\n\n        if (dataSource != null) {\n            dataSource.close();\n        }\n    }\n\n\n    /**\n     * ETL方法\n     *\n     * @param task 任务名, 对应配置名\n     * @param params etl筛选条件\n     * @return ETL结果\n     */\n    @Override\n    public EtlResult etl(String task, List<String> params) {\n        EtlResult etlResult = new EtlResult();\n        MappingConfig config = clickHouseMapping.get(task);\n        ClickHouseEtlService clickhouseEtlService = new ClickHouseEtlService(dataSource, config);\n        if (config != null) {\n            return clickhouseEtlService.importData(params);\n        } else {\n            StringBuilder resultMsg = new StringBuilder();\n            boolean resSucc = true;\n            for (MappingConfig configTmp : clickHouseMapping.values()) {\n                // 取所有的destination为task的配置\n                if (configTmp.getDestination().equals(task)) {\n                    EtlResult etlRes = clickhouseEtlService.importData(params);\n                    if (!etlRes.getSucceeded()) {\n                        resSucc = false;\n                        resultMsg.append(etlRes.getErrorMessage()).append(\"\\n\");\n                    } else {\n                        resultMsg.append(etlRes.getResultMessage()).append(\"\\n\");\n                    }\n                }\n            }\n            if (resultMsg.length() > 0) {\n                etlResult.setSucceeded(resSucc);\n                if (resSucc) {\n                    etlResult.setResultMessage(resultMsg.toString());\n                } else {\n                    etlResult.setErrorMessage(resultMsg.toString());\n                }\n                return etlResult;\n            }\n        }\n        etlResult.setSucceeded(false);\n        etlResult.setErrorMessage(\"Task not found\");\n        return etlResult;\n    }\n\n    /**\n     * 获取总数方法\n     *\n     * @param task 任务名, 对应配置名\n     * @return 总数\n     */\n    @Override\n    public Map<String, Object> count(String task) {\n        MappingConfig config = clickHouseMapping.get(task);\n        MappingConfig.DbMapping dbMapping = config.getDbMapping();\n        String sql = \"SELECT COUNT(1) AS cnt FROM \" + SyncUtil.getDbTableName(dbMapping, dataSource.getDbType());\n        Connection conn = null;\n        Map<String, Object> res = new LinkedHashMap<>();\n        try {\n            conn = dataSource.getConnection();\n            Util.sqlRS(conn, sql, rs -> {\n                try {\n                    if (rs.next()) {\n                        Long rowCount = rs.getLong(\"cnt\");\n                        res.put(\"count\", rowCount);\n                    }\n                } catch (SQLException e) {\n                    logger.error(e.getMessage(), e);\n                }\n            });\n        } catch (SQLException e) {\n            logger.error(e.getMessage(), e);\n        } finally {\n            if (conn != null) {\n                try {\n                    conn.close();\n                } catch (SQLException e) {\n                    logger.error(e.getMessage(), e);\n                }\n            }\n        }\n        res.put(\"targetTable\", SyncUtil.getDbTableName(dbMapping, dataSource.getDbType()));\n\n        return res;\n    }\n\n    /**\n     * 获取对应canal instance name 或 mq topic\n     *\n     * @param task 任务名, 对应配置名\n     * @return destination\n     */\n    @Override\n    public String getDestination(String task) {\n        MappingConfig config = clickHouseMapping.get(task);\n        if (config != null) {\n            return config.getDestination();\n        }\n        return null;\n    }\n\n    private void addSyncConfigToCache(String configName, MappingConfig mappingConfig) {\n        if (!mappingConfig.getDbMapping().getMirrorDb()) {\n            String key;\n            if (envProperties != null && !\"tcp\".equalsIgnoreCase(envProperties.getProperty(\"canal.conf.mode\"))) {\n                key = StringUtils.trimToEmpty(mappingConfig.getDestination()) + \"-\"\n                        + StringUtils.trimToEmpty(mappingConfig.getGroupId()) + \"_\"\n                        + mappingConfig.getDbMapping().getDatabase() + \"-\" + mappingConfig.getDbMapping().getTable();\n            } else {\n                key = StringUtils.trimToEmpty(mappingConfig.getDestination()) + \"_\"\n                        + mappingConfig.getDbMapping().getDatabase() + \"-\" + mappingConfig.getDbMapping().getTable();\n            }\n            Map<String, MappingConfig> configMap = mappingConfigCache.computeIfAbsent(key,\n                    k1 -> new ConcurrentHashMap<>());\n            configMap.put(configName, mappingConfig);\n        } else {\n            // mirrorDB\n            String key = StringUtils.trimToEmpty(mappingConfig.getDestination()) + \".\"\n                    + mappingConfig.getDbMapping().getDatabase();\n            mirrorDbConfigCache.put(key, MirrorDbConfig.create(configName, mappingConfig));\n        }\n    }\n\n    public boolean addConfig(String fileName, MappingConfig config) {\n        if (match(config)) {\n            clickHouseMapping.put(fileName, config);\n            addSyncConfigToCache(fileName, config);\n            FileName2KeyMapping.register(getClass().getAnnotation(SPI.class).value(), fileName,\n                    configuration.getKey());\n            return true;\n        }\n        return false;\n    }\n\n    public void updateConfig(String fileName, MappingConfig config) {\n        if (config.getOuterAdapterKey() != null && !config.getOuterAdapterKey()\n                .equals(configuration.getKey())) {\n            // 理论上不允许改这个 因为本身就是通过这个关联起Adapter和Config的\n            throw new RuntimeException(\"not allow to change outAdapterKey\");\n        }\n        clickHouseMapping.put(fileName, config);\n        addSyncConfigToCache(fileName, config);\n    }\n\n    public void deleteConfig(String fileName) {\n        clickHouseMapping.remove(fileName);\n        for (Map<String, MappingConfig> configMap : mappingConfigCache.values()) {\n            if (configMap != null) {\n                configMap.remove(fileName);\n            }\n        }\n        FileName2KeyMapping.unregister(getClass().getAnnotation(SPI.class).value(), fileName);\n    }\n\n    private boolean match(MappingConfig config) {\n        boolean sameMatch = config.getOuterAdapterKey() != null && config.getOuterAdapterKey()\n                .equalsIgnoreCase(configuration.getKey());\n        boolean prefixMatch = config.getOuterAdapterKey() == null && configuration.getKey()\n                .startsWith(StringUtils\n                        .join(new String[]{Util.AUTO_GENERATED_PREFIX, config.getDestination(),\n                                config.getGroupId()}, '-'));\n        return sameMatch || prefixMatch;\n    }\n}\n"
  },
  {
    "path": "client-adapter/clickhouse/src/main/java/com/alibaba/otter/canal/client/adapter/clickhouse/config/ConfigLoader.java",
    "content": "package com.alibaba.otter.canal.client.adapter.clickhouse.config;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.client.adapter.support.MappingConfigsLoader;\nimport com.alibaba.otter.canal.client.adapter.support.YamlUtils;\n\n/**\n * CLICKHOUSE表映射配置加载器\n *\n * @author: Xander\n * @date: Created in 2023/11/10 22:23\n * @email: zhrunxin33@gmail.com\n * @version 1.1.8\n */\npublic class ConfigLoader {\n\n    private static Logger logger = LoggerFactory.getLogger(ConfigLoader.class);\n\n    /**\n     * 加载CLICKHOUSE表映射配置\n     *\n     * @return 配置名/配置文件名--对象\n     */\n    public static Map<String, MappingConfig> load(Properties envProperties) {\n        logger.info(\"## Start loading clickhouse mapping config ... \");\n\n        Map<String, MappingConfig> result = new LinkedHashMap<>();\n\n        Map<String, String> configContentMap = MappingConfigsLoader.loadConfigs(\"clickhouse\");\n        configContentMap.forEach((fileName, content) -> {\n            MappingConfig config = YamlUtils.ymlToObj(null, content, MappingConfig.class, null, envProperties);\n            if (config == null) {\n                return;\n            }\n            try {\n                config.validate();\n            } catch (Exception e) {\n                throw new RuntimeException(\"ERROR Config: \" + fileName + \" \" + e.getMessage(), e);\n            }\n            result.put(fileName, config);\n        });\n\n        logger.info(\"## ClickHouse mapping config loaded\");\n        return result;\n    }\n}\n"
  },
  {
    "path": "client-adapter/clickhouse/src/main/java/com/alibaba/otter/canal/client/adapter/clickhouse/config/MappingConfig.java",
    "content": "package com.alibaba.otter.canal.client.adapter.clickhouse.config;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.apache.commons.lang.StringUtils;\n\nimport com.alibaba.otter.canal.client.adapter.support.AdapterConfig;\n\n/**\n * CLICKHOUSE表映射配置\n *\n * @author: Xander\n * @date: Created in 2023/11/10 22:23\n * @email: zhrunxin33@gmail.com\n * @version 1.1.8\n */\npublic class MappingConfig implements AdapterConfig {\n\n    private String    dataSourceKey;      // 数据源key\n\n    private String    destination;        // canal实例或MQ的topic\n\n    private String    groupId;            // groupId\n\n    private String    outerAdapterKey;    // 对应适配器的key\n\n    private boolean   concurrent = false; // 是否并行同步\n\n    private DbMapping dbMapping;          // db映射配置\n\n    public String getDataSourceKey() {\n        return dataSourceKey;\n    }\n\n    public void setDataSourceKey(String dataSourceKey) {\n        this.dataSourceKey = dataSourceKey;\n    }\n\n    public String getGroupId() {\n        return groupId;\n    }\n\n    public void setGroupId(String groupId) {\n        this.groupId = groupId;\n    }\n\n    public String getOuterAdapterKey() {\n        return outerAdapterKey;\n    }\n\n    public void setOuterAdapterKey(String outerAdapterKey) {\n        this.outerAdapterKey = outerAdapterKey;\n    }\n\n    public boolean getConcurrent() {\n        return concurrent;\n    }\n\n    public void setConcurrent(boolean concurrent) {\n        this.concurrent = concurrent;\n    }\n\n    public DbMapping getDbMapping() {\n        return dbMapping;\n    }\n\n    public void setDbMapping(DbMapping dbMapping) {\n        this.dbMapping = dbMapping;\n    }\n\n    public String getDestination() {\n        return destination;\n    }\n\n    public void setDestination(String destination) {\n        this.destination = destination;\n    }\n\n    public AdapterMapping getMapping() {\n        return dbMapping;\n    }\n\n    public void validate() {\n        if (dbMapping.database == null || dbMapping.database.isEmpty()) {\n            throw new NullPointerException(\"dbMapping.database\");\n        }\n        if (!dbMapping.getMirrorDb() && (dbMapping.table == null || dbMapping.table.isEmpty())) {\n            throw new NullPointerException(\"dbMapping.table\");\n        }\n        if (!dbMapping.getMirrorDb() && (dbMapping.targetTable == null || dbMapping.targetTable.isEmpty())) {\n            throw new NullPointerException(\"dbMapping.targetTable\");\n        }\n    }\n\n    public static class DbMapping implements AdapterMapping {\n\n        private boolean             mirrorDb        = false;                 // 是否镜像库\n        private String              database;                                // 数据库名或schema名\n        private String              table;                                   // 表名\n        private Map<String, String> targetPk        = new LinkedHashMap<>(); // 目标表主键字段\n        private boolean             mapAll          = false;                 // 映射所有字段\n        private String              targetDb;                                // 目标库名\n        private String              targetTable;                             // 目标表名\n        private Map<String, String> targetColumns;                           // 目标表字段映射\n\n        private boolean             caseInsensitive = false;                 // 目标表不区分大小写，默认是否\n\n        private String              etlCondition;                            // etl条件sql\n\n        private int                 readBatch       = 5000;\n        private int                 commitBatch     = 5000;                  // etl等批量提交大小\n\n        private Map<String, String> allMapColumns;\n\n        public boolean getMirrorDb() {\n            return mirrorDb;\n        }\n\n        public void setMirrorDb(boolean mirrorDb) {\n            this.mirrorDb = mirrorDb;\n        }\n\n        public String getDatabase() {\n            return database;\n        }\n\n        public void setDatabase(String database) {\n            this.database = database;\n        }\n\n        public String getTable() {\n            return table;\n        }\n\n        public void setTable(String table) {\n            this.table = table;\n        }\n\n        public Map<String, String> getTargetPk() {\n            return targetPk;\n        }\n\n        public void setTargetPk(Map<String, String> targetPk) {\n            this.targetPk = targetPk;\n        }\n\n        public Boolean getMapAll() {\n            return mapAll;\n        }\n\n        public void setMapAll(Boolean mapAll) {\n            this.mapAll = mapAll;\n        }\n\n        public String getTargetDb() {\n            return targetDb;\n        }\n\n        public void setTargetDb(String targetDb) {\n            this.targetDb = targetDb;\n        }\n\n        public String getTargetTable() {\n            return targetTable;\n        }\n\n        public void setTargetTable(String targetTable) {\n            this.targetTable = targetTable;\n        }\n\n        public Map<String, String> getTargetColumns() {\n            if (targetColumns != null) {\n                targetColumns.forEach((key, value) -> {\n                    if (StringUtils.isEmpty(value)) {\n                        targetColumns.put(key, key);\n                    }\n                });\n            }\n            return targetColumns;\n        }\n\n        public void setTargetColumns(Map<String, String> targetColumns) {\n            this.targetColumns = targetColumns;\n        }\n\n        public boolean isCaseInsensitive() {\n            return caseInsensitive;\n        }\n\n        public void setCaseInsensitive(boolean caseInsensitive) {\n            this.caseInsensitive = caseInsensitive;\n        }\n\n        public String getEtlCondition() {\n            return etlCondition;\n        }\n\n        public void setEtlCondition(String etlCondition) {\n            this.etlCondition = etlCondition;\n        }\n\n        public int getReadBatch() {\n            return readBatch;\n        }\n\n        public void setReadBatch(int readBatch) {\n            this.readBatch = readBatch;\n        }\n\n        public int getCommitBatch() {\n            return commitBatch;\n        }\n\n        public void setCommitBatch(int commitBatch) {\n            this.commitBatch = commitBatch;\n        }\n\n        public Map<String, String> getAllMapColumns() {\n            return allMapColumns;\n        }\n\n        public void setAllMapColumns(Map<String, String> allMapColumns) {\n            this.allMapColumns = allMapColumns;\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/clickhouse/src/main/java/com/alibaba/otter/canal/client/adapter/clickhouse/config/MirrorDbConfig.java",
    "content": "package com.alibaba.otter.canal.client.adapter.clickhouse.config;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * @author: Xander\n * @date: Created in 2023/11/10 22:23\n * @email: zhrunxin33@gmail.com\n * @version 1.1.8\n */\n\npublic class MirrorDbConfig {\n\n    private String                     fileName;\n    private MappingConfig              mappingConfig;\n    private Map<String, MappingConfig> tableConfig = new ConcurrentHashMap<>();\n\n    public static MirrorDbConfig create(String fileName, MappingConfig mappingConfig) {\n        return new MirrorDbConfig(fileName, mappingConfig);\n    }\n\n    public MirrorDbConfig(String fileName, MappingConfig mappingConfig){\n        this.fileName = fileName;\n        this.mappingConfig = mappingConfig;\n    }\n\n    public String getFileName() {\n        return fileName;\n    }\n\n    public void setFileName(String fileName) {\n        this.fileName = fileName;\n    }\n\n    public MappingConfig getMappingConfig() {\n        return mappingConfig;\n    }\n\n    public void setMappingConfig(MappingConfig mappingConfig) {\n        this.mappingConfig = mappingConfig;\n    }\n\n    public Map<String, MappingConfig> getTableConfig() {\n        return tableConfig;\n    }\n\n    public void setTableConfig(Map<String, MappingConfig> tableConfig) {\n        this.tableConfig = tableConfig;\n    }\n}\n"
  },
  {
    "path": "client-adapter/clickhouse/src/main/java/com/alibaba/otter/canal/client/adapter/clickhouse/monitor/ClickHouseConfigMonitor.java",
    "content": "package com.alibaba.otter.canal.client.adapter.clickhouse.monitor;\n\nimport java.io.File;\nimport java.util.Properties;\n\nimport org.apache.commons.io.filefilter.FileFilterUtils;\nimport org.apache.commons.io.monitor.FileAlterationListenerAdaptor;\nimport org.apache.commons.io.monitor.FileAlterationMonitor;\nimport org.apache.commons.io.monitor.FileAlterationObserver;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.client.adapter.clickhouse.ClickHouseAdapter;\nimport com.alibaba.otter.canal.client.adapter.clickhouse.config.MappingConfig;\nimport com.alibaba.otter.canal.client.adapter.support.MappingConfigsLoader;\nimport com.alibaba.otter.canal.client.adapter.support.Util;\nimport com.alibaba.otter.canal.client.adapter.support.YamlUtils;\n\n/**\n * @author: Xander\n * @date: Created in 2023/11/10 22:23\n * @email: zhrunxin33@gmail.com\n * @version 1.1.8\n */\n\npublic class ClickHouseConfigMonitor {\n\n    private static final Logger   logger      = LoggerFactory.getLogger(ClickHouseConfigMonitor.class);\n\n    private static final String   adapterName = \"clickhouse\";\n\n    private String                key;\n\n    private ClickHouseAdapter     clickHouseAdapter;\n\n    private Properties            envProperties;\n\n    private FileAlterationMonitor fileMonitor;\n\n    public void init(String key, ClickHouseAdapter clickHouseAdapter, Properties envProperties) {\n        this.key = key;\n        this.clickHouseAdapter = clickHouseAdapter;\n        this.envProperties = envProperties;\n        File confDir = Util.getConfDirPath(adapterName);\n        try {\n            FileAlterationObserver observer = new FileAlterationObserver(confDir,\n                FileFilterUtils.and(FileFilterUtils.fileFileFilter(), FileFilterUtils.suffixFileFilter(\"yml\")));\n            FileListener listener = new FileListener();\n            observer.addListener(listener);\n            fileMonitor = new FileAlterationMonitor(3000, observer);\n            fileMonitor.start();\n\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n        }\n    }\n\n    public void destroy() {\n        try {\n            fileMonitor.stop();\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n        }\n    }\n\n    private class FileListener extends FileAlterationListenerAdaptor {\n\n        @Override\n        public void onFileCreate(File file) {\n            super.onFileCreate(file);\n            try {\n                // 加载新增的配置文件\n                String configContent = MappingConfigsLoader.loadConfig(adapterName + File.separator + file.getName());\n                MappingConfig config = YamlUtils\n                    .ymlToObj(null, configContent, MappingConfig.class, null, envProperties);\n                if (config == null) {\n                    return;\n                }\n                config.validate();\n                boolean result = clickHouseAdapter.addConfig(file.getName(), config);\n                if (result) {\n                    logger.info(\"Add a new clickhouse mapping config: {} to canal adapter\", file.getName());\n                }\n            } catch (Exception e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n\n        @Override\n        public void onFileChange(File file) {\n            super.onFileChange(file);\n\n            try {\n                if (clickHouseAdapter.getClickHouseMapping().containsKey(file.getName())) {\n                    // 加载配置文件\n                    String configContent = MappingConfigsLoader\n                        .loadConfig(adapterName + File.separator + file.getName());\n                    if (configContent == null) {\n                        onFileDelete(file);\n                        return;\n                    }\n                    MappingConfig config = YamlUtils\n                        .ymlToObj(null, configContent, MappingConfig.class, null, envProperties);\n                    if (config == null) {\n                        return;\n                    }\n                    config.validate();\n                    clickHouseAdapter.updateConfig(file.getName(), config);\n                    logger.info(\"Change a clickhouse mapping config: {} of canal adapter\", file.getName());\n                }\n            } catch (Exception e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n\n        @Override\n        public void onFileDelete(File file) {\n            super.onFileDelete(file);\n\n            try {\n                if (clickHouseAdapter.getClickHouseMapping().containsKey(file.getName())) {\n                    clickHouseAdapter.deleteConfig(file.getName());\n\n                    logger.info(\"Delete a clickhouse mapping config: {} of canal adapter\", file.getName());\n                }\n            } catch (Exception e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/clickhouse/src/main/java/com/alibaba/otter/canal/client/adapter/clickhouse/service/ClickHouseBatchSyncService.java",
    "content": "package com.alibaba.otter.canal.client.adapter.clickhouse.service;\n\nimport java.sql.Connection;\nimport java.sql.ResultSetMetaData;\nimport java.sql.SQLException;\nimport java.sql.Types;\nimport java.util.*;\nimport java.util.concurrent.*;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.JSONWriter.Feature;\nimport com.alibaba.otter.canal.client.adapter.clickhouse.config.MappingConfig;\nimport com.alibaba.otter.canal.client.adapter.clickhouse.config.MappingConfig.DbMapping;\nimport com.alibaba.otter.canal.client.adapter.clickhouse.support.BatchExecutor;\nimport com.alibaba.otter.canal.client.adapter.clickhouse.support.SingleDml;\nimport com.alibaba.otter.canal.client.adapter.clickhouse.support.SyncUtil;\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\nimport com.alibaba.otter.canal.client.adapter.support.Util;\n\n/**\n * ClickHouse batch synchronize\n *\n * @author: Xander\n * @date: Created in 2023/11/10 22:23\n * @email: zhrunxin33@gmail.com\n * @version 1.1.8\n */\npublic class ClickHouseBatchSyncService {\n\n    private static final Logger                         logger  = LoggerFactory.getLogger(ClickHouseBatchSyncService.class);\n\n    private DruidDataSource                             dataSource;\n\n    private Map<String, Map<String, Integer>>           columnsTypeCache;     // Cache of instance.schema.table -> <columnName, jdbcType>\n\n    private Map<MappingConfig, List<SingleDml>>[]       bufferPools;          // Data buffer pool store sync data, List<Dml> dispersed as arrays according to hash value\n\n    private BatchExecutor[]                             batchExecutors;       // Batch Executor\n\n    private BatchExecutor                               alterExecutors;       // Alter Single Executor(update/delete/truncate)\n\n    private ExecutorService[]                           executorThreads;      // Be initialized once\n\n    private ScheduledExecutorService[]                  scheduledExecutors;\n\n    private int                                         threads = 3;          // Default parallel thread count\n    private int                                         batchSize = 1000;\n    private long                                        scheduleTime = 10;\n    private boolean                                     skipDupException;\n\n    public Map<String, Map<String, Integer>> getColumnsTypeCache() {\n        return columnsTypeCache;\n    }\n\n    public ClickHouseBatchSyncService(DruidDataSource dataSource, Integer threads, Integer batchSize, Long scheduleTime, boolean skipDupException){\n        this(dataSource, threads, batchSize, scheduleTime, new ConcurrentHashMap<>(), skipDupException);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public ClickHouseBatchSyncService(DruidDataSource dataSource, Integer threads, Integer batchSize, Long scheduleTime, Map<String, Map<String, Integer>> columnsTypeCache,\n                                      boolean skipDupException){\n        this.dataSource = dataSource;\n        this.columnsTypeCache = columnsTypeCache;\n        this.skipDupException = skipDupException;\n        try {\n            if (threads != null) {\n                this.threads = threads;\n            }\n            if (batchSize != null) {\n                this.batchSize = batchSize;\n            }\n            if (scheduleTime != null) {\n                this.scheduleTime = scheduleTime;\n            }\n            this.alterExecutors = new BatchExecutor(dataSource);\n            this.bufferPools = new ConcurrentHashMap[this.threads];\n            this.batchExecutors = new BatchExecutor[this.threads];\n            this.executorThreads = new ExecutorService[this.threads];\n            this.scheduledExecutors = new ScheduledExecutorService[this.threads];\n            for (int i = 0; i < this.threads; i++) {\n                bufferPools[i] = new ConcurrentHashMap<>();\n                batchExecutors[i] = new BatchExecutor(dataSource);\n                executorThreads[i] = Executors.newSingleThreadExecutor();\n                scheduledExecutors[i] = Executors.newSingleThreadScheduledExecutor();\n            }\n            scheduleBatchSync();\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * Timing-driven event\n     * start schedule batch sync threadPool\n     */\n    private void scheduleBatchSync() {\n        for (int i = 0; i < scheduledExecutors.length; i++) {\n            int index = i;\n            scheduledExecutors[i].scheduleAtFixedRate(()->{\n                List<Future<Boolean>> futures = new ArrayList<>();\n                for (MappingConfig mappingConfig : bufferPools[index].keySet()) {\n                    List<SingleDml> dmls = bufferPools[index].get(mappingConfig);\n                    if (dmls == null || dmls.isEmpty()) {\n                        return;\n                    }\n                    List<SingleDml> tempDmls;\n                    synchronized (dmls) {\n                        tempDmls = new ArrayList<>(dmls);\n                        dmls.clear();\n                    }\n                    futures.add(executorThreads[index].submit(()->{\n                        try {\n                            insert(batchExecutors[index], mappingConfig, tempDmls);\n                            batchExecutors[index].commit();\n                            return true;\n                        } catch (Exception e){\n                            batchExecutors[index].rollback();\n                            throw new RuntimeException(e);\n                        }\n                    }));\n                }\n            }, 0, scheduleTime, TimeUnit.SECONDS);\n        }\n        logger.info(\"Schedule batch executors has started successfully!\");\n    }\n\n    /**\n     * 批量同步回调\n     *\n     * @param dmls 批量 DML\n     * @param function 回调方法\n     */\n    public void sync(List<Dml> dmls, Function<Dml, Boolean> function) {\n        boolean toExecute = false;\n        for (Dml dml : dmls) {\n            if (!toExecute) {\n                toExecute = function.apply(dml);\n            } else {\n                function.apply(dml);\n            }\n        }\n    }\n\n    /**\n     * Distribute dmls into different partition\n     *\n     * @param mappingConfig {@link com.alibaba.otter.canal.client.adapter.clickhouse.ClickHouseAdapter#mappingConfigCache }\n     * @param dmls received DML\n     */\n    public void sync(Map<String, Map<String, MappingConfig>> mappingConfig, List<Dml> dmls, Properties envProperties) {\n        sync(dmls, dml -> {\n            if (dml.getIsDdl() != null && dml.getIsDdl() && StringUtils.isNotEmpty(dml.getSql())) {\n                // DDL(Cache need to update when DDL was executed)\n            columnsTypeCache.remove(dml.getDestination() + \".\" + dml.getDatabase() + \".\" + dml.getTable());\n            return false;\n        } else {\n            // DML\n            String destination = StringUtils.trimToEmpty(dml.getDestination());\n            String groupId = StringUtils.trimToEmpty(dml.getGroupId());\n            String database = dml.getDatabase();\n            String table = dml.getTable();\n            Map<String, MappingConfig> configMap;\n            if (envProperties != null && !\"tcp\".equalsIgnoreCase(envProperties.getProperty(\"canal.conf.mode\"))) {\n                configMap = mappingConfig.get(destination + \"-\" + groupId + \"_\" + database + \"-\" + table);\n            } else {\n                configMap = mappingConfig.get(destination + \"_\" + database + \"-\" + table);\n            }\n\n            if (configMap == null) {\n                return false;\n            }\n\n            if (configMap.values().isEmpty()) {\n                return false;\n            }\n\n            for (MappingConfig config : configMap.values()) {\n                distributeDml(config, dml);\n            }\n            return true;\n        }\n    }   );\n    }\n\n    /**\n     * Dml distributor\n     */\n    private void distributeDml(MappingConfig config, Dml dml) {\n        if (config != null) {\n            try {\n                String type = dml.getType();\n                if (type == null) return;\n\n                if (type.equalsIgnoreCase(\"INSERT\")) {\n                    appendDmlBufferPartition(config, dml);\n                } else {\n                    boolean caseInsensitive = config.getDbMapping().isCaseInsensitive();\n                    List<SingleDml> singleDmls = SingleDml.dml2SingleDmls(dml, caseInsensitive);\n\n                    if (type.equalsIgnoreCase(\"UPDATE\")) {\n                        for (SingleDml singleDml : singleDmls) {\n                            update(alterExecutors, config, singleDml);\n                        }\n                    } else if (type.equalsIgnoreCase(\"DELETE\")) {\n                        for (SingleDml singleDml : singleDmls) {\n                            delete(alterExecutors, config, singleDml);\n                        }\n                    } else if (type.equalsIgnoreCase(\"TRUNCATE\")) {\n                        truncate(alterExecutors, config);\n                    }\n                }\n                if (logger.isDebugEnabled()) {\n                    logger.debug(\"DML: {}\", JSON.toJSONString(dml, Feature.WriteNulls));\n                }\n            } catch (SQLException e) {\n                throw new RuntimeException(e);\n            }\n        }\n    }\n\n    public void appendDmlBufferPartition(MappingConfig config, Dml dml) {\n        boolean caseInsensitive = config.getDbMapping().isCaseInsensitive();\n        List<SingleDml> singleDmls = SingleDml.dml2SingleDmls(dml, caseInsensitive);\n\n        singleDmls.forEach(singleDml -> {\n            int hash = mappingHash(config.getDbMapping());\n            if (!config.getConcurrent()) {\n                hash = 0;\n            }\n            List<SingleDml> dmls = bufferPools[hash].computeIfAbsent(config, k -> new ArrayList<>());\n            synchronized (dmls) {\n                dmls.add(singleDml);\n                logger.info(\"Append one data into pool, id {}\", singleDml.getData().get(\"id\"));\n            }\n            // Check the size of the List, achieve when it reaches the maximum value\n            if (dmls.size() >= batchSize) syncToClickHouse(config, hash);\n        });\n    }\n\n    /**\n     * sync when size of list{@link #bufferPools } reaches the maximum value\n     *\n     * @param config key\n     * @param index parallel thread index\n     */\n    private void syncToClickHouse(MappingConfig config, int index) {\n        List<SingleDml> dmls = bufferPools[index].get(config);\n        logger.info(\"schema:{} table:{} reaches the maximum value, ready to synchronize, size {}\", config.getDbMapping().getDatabase(), config.getDbMapping().getTable(), dmls.size());\n        if (dmls ==null || dmls.isEmpty()) {\n            return;\n        }\n        List<SingleDml> tempDmls;\n        synchronized (dmls) {\n            tempDmls = new ArrayList<>(dmls);\n            dmls.clear();\n        }\n        executorThreads[index].submit(() -> {\n            try {\n                insert(batchExecutors[index], config, tempDmls);\n                batchExecutors[index].commit();\n                return true;\n            } catch (Exception e) {\n                batchExecutors[index].rollback();\n                throw new RuntimeException(e);\n            }\n        });\n    }\n\n    /**\n     * Insert\n     *\n     * @param batchExecutor batch translational executor\n     * @param config corresponding configuration object\n     * @param dmls DMLs\n     */\n    private void insert(BatchExecutor batchExecutor, MappingConfig config, List<SingleDml> dmls) throws SQLException {\n        if (dmls == null || dmls.isEmpty()) {\n            return;\n        }\n        List<SingleDml> clearDmls = dmls.stream().filter(e -> e.getData() != null && !e.getData().isEmpty()).collect(Collectors.toList());\n        if (clearDmls == null || clearDmls.isEmpty()) {\n            return;\n        }\n\n        DbMapping dbMapping = config.getDbMapping();\n        String backtick = SyncUtil.getBacktickByDbType(dataSource.getDbType());\n        Map<String, String> columnsMap = SyncUtil.getColumnsMap(dbMapping, clearDmls.get(0).getData());\n\n        StringBuilder insertSql = new StringBuilder();\n        insertSql.append(\"INSERT INTO \").append(SyncUtil.getDbTableName(dbMapping, dataSource.getDbType())).append(\" (\");\n\n        columnsMap.forEach((targetColumnName, srcColumnName) -> insertSql.append(backtick)\n            .append(targetColumnName)\n            .append(backtick)\n            .append(\",\"));\n        int len = insertSql.length();\n        insertSql.delete(len - 1, len).append(\") VALUES (\");\n        int mapLen = columnsMap.size();\n        for (int i = 0; i < mapLen; i++) {\n            insertSql.append(\"?,\");\n        }\n        len = insertSql.length();\n        insertSql.delete(len - 1, len).append(\")\");\n\n        Map<String, Integer> ctype = getTargetColumnType(batchExecutor.getConn(), config);\n\n        List<List<Map<String, ?>>> values = new ArrayList<>();\n        boolean flag = false;\n        for (Map.Entry<String, String> entry : columnsMap.entrySet()) {\n            String targetColumnName = entry.getKey();\n            String srcColumnName = entry.getValue();\n            if (srcColumnName == null) {\n                srcColumnName = Util.cleanColumn(targetColumnName);\n            }\n\n            Integer type = ctype.get(Util.cleanColumn(targetColumnName).toLowerCase());\n            if (type == null) {\n                throw new RuntimeException(\"Target column: \" + targetColumnName + \" not matched\");\n            }\n            for (int i = 0; i < clearDmls.size(); i++) {\n                Map<String, Object> dmlData = clearDmls.get(i).getData();\n                List<Map<String, ?>> item;\n                if (flag == false) {\n                    item = new ArrayList<>();\n                    values.add(item);\n                } else {\n                    item = values.get(i);\n                }\n                Object value = dmlData.get(srcColumnName);\n                BatchExecutor.setValue(item, type, value);\n            }\n            flag = true;\n        }\n\n        try {\n            batchExecutor.batchExecute(insertSql.toString(), values);\n        } catch (SQLException e) {\n            if (skipDupException\n                && (e.getMessage().contains(\"Duplicate entry\") || e.getMessage().startsWith(\"ORA-00001:\"))) {\n                // ignore\n                // TODO 增加更多关系数据库的主键冲突的错误码\n            } else {\n                throw e;\n            }\n        }\n        if (logger.isTraceEnabled()) {\n            logger.trace(\"Insert into target table, sql: {}\", insertSql);\n        }\n\n    }\n\n    /**\n     * 更新操作\n     *\n     * @param config 配置项\n     * @param dml DML数据\n     */\n    private void update(BatchExecutor batchExecutor, MappingConfig config, SingleDml dml) throws SQLException {\n        Map<String, Object> data = dml.getData();\n        if (data == null || data.isEmpty()) {\n            return;\n        }\n\n        Map<String, Object> old = dml.getOld();\n        if (old == null || old.isEmpty()) {\n            return;\n        }\n\n        DbMapping dbMapping = config.getDbMapping();\n        String backtick = SyncUtil.getBacktickByDbType(dataSource.getDbType());\n        Map<String, String> columnsMap = SyncUtil.getColumnsMap(dbMapping, data);\n\n        Map<String, Integer> ctype = getTargetColumnType(batchExecutor.getConn(), config);\n\n        StringBuilder updateSql = new StringBuilder();\n        updateSql.append(\"ALTER TABLE \").append(SyncUtil.getDbTableName(dbMapping, dataSource.getDbType())).append(\" UPDATE \");\n        List<Map<String, ?>> values = new ArrayList<>();\n        boolean hasMatched = false;\n        for (String srcColumnName : old.keySet()) {\n            List<String> targetColumnNames = new ArrayList<>();\n            columnsMap.forEach((targetColumn, srcColumn) -> {\n                if (srcColumnName.equalsIgnoreCase(srcColumn)) {\n                    targetColumnNames.add(targetColumn);\n                }\n            });\n            if (!targetColumnNames.isEmpty()) {\n                hasMatched = true;\n                for (String targetColumnName : targetColumnNames) {\n                    updateSql.append(backtick).append(targetColumnName).append(backtick).append(\"=?, \");\n                    Integer type = ctype.get(Util.cleanColumn(targetColumnName).toLowerCase());\n                    if (type == null) {\n                        throw new RuntimeException(\"Target column: \" + targetColumnName + \" not matched\");\n                    }\n                    BatchExecutor.setValue(values, type, data.get(srcColumnName));\n                }\n            }\n        }\n        if (!hasMatched) {\n            logger.warn(\"Did not matched any columns to update \");\n            return;\n        }\n        int len = updateSql.length();\n        updateSql.delete(len - 2, len).append(\" WHERE \");\n\n        // 拼接主键\n        appendCondition(dbMapping, updateSql, ctype, values, data, old);\n        batchExecutor.execute(updateSql.toString(), values);\n        if (logger.isTraceEnabled()) {\n            logger.trace(\"Alter update target table, sql: {}\", updateSql);\n        }\n    }\n\n    /**\n     * 删除操作\n     *\n     * @param config\n     * @param dml\n     */\n    private void delete(BatchExecutor batchExecutor, MappingConfig config, SingleDml dml) throws SQLException {\n        Map<String, Object> data = dml.getData();\n        if (data == null || data.isEmpty()) {\n            return;\n        }\n\n        DbMapping dbMapping = config.getDbMapping();\n        Map<String, Integer> ctype = getTargetColumnType(batchExecutor.getConn(), config);\n\n        StringBuilder sql = new StringBuilder();\n        sql.append(\"ALTER TABLE \").append(SyncUtil.getDbTableName(dbMapping, dataSource.getDbType())).append(\" DELETE WHERE \");\n\n        List<Map<String, ?>> values = new ArrayList<>();\n        // 拼接主键\n        appendCondition(dbMapping, sql, ctype, values, data);\n        batchExecutor.execute(sql.toString(), values);\n        if (logger.isTraceEnabled()) {\n            logger.trace(\"Alter delete from target table, sql: {}\", sql);\n        }\n    }\n\n    /**\n     * truncate操作\n     *\n     * @param config\n     */\n    private void truncate(BatchExecutor batchExecutor, MappingConfig config) throws SQLException {\n        DbMapping dbMapping = config.getDbMapping();\n        StringBuilder sql = new StringBuilder();\n        sql.append(\"TRUNCATE TABLE \").append(SyncUtil.getDbTableName(dbMapping, dataSource.getDbType()));\n        batchExecutor.execute(sql.toString(), new ArrayList<>());\n        if (logger.isTraceEnabled()) {\n            logger.trace(\"Truncate target table, sql: {}\", sql);\n        }\n    }\n\n    /**\n     * 获取目标字段类型\n     *\n     * @param conn sql connection\n     * @param config 映射配置\n     * @return 字段sqlType\n     */\n    private Map<String, Integer> getTargetColumnType(Connection conn, MappingConfig config) {\n        DbMapping dbMapping = config.getDbMapping();\n        String cacheKey = config.getDestination() + \".\" + dbMapping.getDatabase() + \".\" + dbMapping.getTable();\n        Map<String, Integer> columnType = columnsTypeCache.get(cacheKey);\n        if (columnType == null) {\n            synchronized (ClickHouseBatchSyncService.class) {\n                columnType = columnsTypeCache.get(cacheKey);\n                if (columnType == null) {\n                    columnType = new LinkedHashMap<>();\n                    final Map<String, Integer> columnTypeTmp = columnType;\n                    String sql = \"SELECT * FROM \" + SyncUtil.getDbTableName(dbMapping, dataSource.getDbType()) + \" WHERE 1=2\";\n                    Util.sqlRS(conn, sql, rs -> {\n                        try {\n                            ResultSetMetaData rsd = rs.getMetaData();\n                            int columnCount = rsd.getColumnCount();\n                            for (int i = 1; i <= columnCount; i++) {\n                                int colType = rsd.getColumnType(i);\n                                // 修复year类型作为date处理时的data truncated问题\n                                if (\"YEAR\".equals(rsd.getColumnTypeName(i))) {\n                                    colType = Types.VARCHAR;\n                                }\n                                columnTypeTmp.put(rsd.getColumnName(i).toLowerCase(), colType);\n                            }\n                            columnsTypeCache.put(cacheKey, columnTypeTmp);\n                        } catch (SQLException e) {\n                            logger.error(e.getMessage(), e);\n                        }\n                    });\n                }\n            }\n        }\n        return columnType;\n    }\n\n    /**\n     * 拼接主键 where条件\n     */\n    private void appendCondition(MappingConfig.DbMapping dbMapping, StringBuilder sql, Map<String, Integer> ctype,\n                                 List<Map<String, ?>> values, Map<String, Object> d) {\n        appendCondition(dbMapping, sql, ctype, values, d, null);\n    }\n\n    private void appendCondition(MappingConfig.DbMapping dbMapping, StringBuilder sql, Map<String, Integer> ctype,\n                                 List<Map<String, ?>> values, Map<String, Object> d, Map<String, Object> o) {\n        String backtick = SyncUtil.getBacktickByDbType(dataSource.getDbType());\n\n        // 拼接主键\n        for (Map.Entry<String, String> entry : dbMapping.getTargetPk().entrySet()) {\n            String targetColumnName = entry.getKey();\n            String srcColumnName = entry.getValue();\n            if (srcColumnName == null) {\n                srcColumnName = Util.cleanColumn(targetColumnName);\n            }\n            sql.append(backtick).append(targetColumnName).append(backtick).append(\"=? AND \");\n            Integer type = ctype.get(Util.cleanColumn(targetColumnName).toLowerCase());\n            if (type == null) {\n                throw new RuntimeException(\"Target column: \" + targetColumnName + \" not matched\");\n            }\n            // 如果有修改主键的情况\n            if (o != null && o.containsKey(srcColumnName)) {\n                BatchExecutor.setValue(values, type, o.get(srcColumnName));\n            } else {\n                BatchExecutor.setValue(values, type, d.get(srcColumnName));\n            }\n        }\n        int len = sql.length();\n        sql.delete(len - 4, len);\n    }\n\n    /**\n     * make sure the same table in one index\n     *\n     * @param dbMapping\n     * @return\n     */\n    private int mappingHash(MappingConfig.DbMapping dbMapping) {\n        int hash = dbMapping.getDatabase().toLowerCase().hashCode() + dbMapping.getTable().toLowerCase().hashCode();\n        hash = Math.abs(hash) % threads;\n        return Math.abs(hash);\n    }\n\n    public void close() {\n        for (int i = 0; i < threads; i++) {\n            executorThreads[i].shutdown();\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/clickhouse/src/main/java/com/alibaba/otter/canal/client/adapter/clickhouse/service/ClickHouseEtlService.java",
    "content": "package com.alibaba.otter.canal.client.adapter.clickhouse.service;\n\nimport java.sql.*;\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport javax.sql.DataSource;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.alibaba.otter.canal.client.adapter.clickhouse.config.MappingConfig;\nimport com.alibaba.otter.canal.client.adapter.clickhouse.config.MappingConfig.DbMapping;\nimport com.alibaba.otter.canal.client.adapter.clickhouse.support.SyncUtil;\nimport com.alibaba.otter.canal.client.adapter.support.*;\n\n/**\n * ClickHouse ETL 操作业务类\n *\n * @author: Xander\n * @date: Created in 2023/11/10 22:23\n * @email: zhrunxin33@gmail.com\n * @version 1.1.8\n */\npublic class ClickHouseEtlService extends AbstractEtlService {\n\n    private DataSource    targetDS;\n    private MappingConfig config;\n\n    public ClickHouseEtlService(DataSource targetDS, MappingConfig config){\n        super(\"CLICKHOUSE\", config);\n        this.targetDS = targetDS;\n        this.config = config;\n    }\n\n    /**\n     * 导入数据\n     */\n    public EtlResult importData(List<String> params) {\n        DbMapping dbMapping = config.getDbMapping();\n        DruidDataSource dataSource = DatasourceConfig.DATA_SOURCES.get(config.getDataSourceKey());\n        String sql = \"SELECT * FROM \" + SyncUtil.getSourceDbTableName(dbMapping, dataSource.getDbType());\n        return importData(sql, params);\n    }\n\n    /**\n     * 执行导入\n     */\n    protected boolean executeSqlImport(DataSource srcDS, String sql, List<Object> values,\n                                       AdapterConfig.AdapterMapping mapping, AtomicLong impCount, List<String> errMsg) {\n        try {\n            DbMapping dbMapping = (DbMapping) mapping;\n            Map<String, String> columnsMap = new LinkedHashMap<>();\n            Map<String, Integer> columnType = new LinkedHashMap<>();\n            DruidDataSource dataSource = (DruidDataSource) srcDS;\n            String backtick = SyncUtil.getBacktickByDbType(dataSource.getDbType());\n\n            Util.sqlRS(targetDS,\n                \"SELECT * FROM \" + SyncUtil.getDbTableName(dbMapping, dataSource.getDbType()) + \" LIMIT 1 \",\n                rs -> {\n                    try {\n\n                        ResultSetMetaData rsd = rs.getMetaData();\n                        int columnCount = rsd.getColumnCount();\n                        List<String> columns = new ArrayList<>();\n                        for (int i = 1; i <= columnCount; i++) {\n                            columnType.put(rsd.getColumnName(i).toLowerCase(), rsd.getColumnType(i));\n                            columns.add(rsd.getColumnName(i));\n                        }\n\n                        columnsMap.putAll(SyncUtil.getColumnsMap(dbMapping, columns));\n                        return true;\n                    } catch (Exception e) {\n                        logger.error(e.getMessage(), e);\n                        return false;\n                    }\n                });\n\n            Util.sqlRS(srcDS, sql, values, rs -> {\n                int idx = 1;\n\n                try {\n                    boolean completed = false;\n\n                    StringBuilder insertSql = new StringBuilder();\n                    insertSql.append(\"INSERT INTO \")\n                        .append(SyncUtil.getDbTableName(dbMapping, dataSource.getDbType()))\n                        .append(\" (\");\n                    columnsMap.forEach((targetColumnName, srcColumnName) -> insertSql.append(backtick)\n                        .append(targetColumnName)\n                        .append(backtick)\n                        .append(\",\"));\n\n                    int len = insertSql.length();\n                    insertSql.delete(len - 1, len).append(\") VALUES (\");\n                    int mapLen = columnsMap.size();\n                    for (int i = 0; i < mapLen; i++) {\n                        insertSql.append(\"?,\");\n                    }\n                    len = insertSql.length();\n                    insertSql.delete(len - 1, len).append(\")\");\n                    logger.info(\"executeSqlImport sql:{}\", insertSql.toString());\n                    try (Connection connTarget = targetDS.getConnection();\n                            PreparedStatement pstmt = connTarget.prepareStatement(insertSql.toString())) {\n                        connTarget.setAutoCommit(false);\n\n                        while (rs.next()) {\n                            completed = false;\n\n                            pstmt.clearParameters();\n\n                            // 删除数据\n                            Map<String, Object> pkVal = new LinkedHashMap<>();\n                            StringBuilder deleteSql = new StringBuilder(\n                                \"ALTER TABLE \" + SyncUtil.getDbTableName(dbMapping, dataSource.getDbType())\n                                                                        + \" DELETE WHERE \");\n                            appendCondition(dbMapping, deleteSql, pkVal, rs, backtick);\n                            try (PreparedStatement pstmt2 = connTarget.prepareStatement(deleteSql.toString())) {\n                                int k = 1;\n                                for (Object val : pkVal.values()) {\n                                    pstmt2.setObject(k++, val);\n                                }\n                                pstmt2.execute();\n                            }\n\n                            int i = 1;\n                            for (Map.Entry<String, String> entry : columnsMap.entrySet()) {\n                                String targetColumnName = entry.getKey();\n                                String srcColumnName = entry.getValue();\n                                if (srcColumnName == null) {\n                                    srcColumnName = targetColumnName;\n                                }\n\n                                Integer type = columnType.get(targetColumnName.toLowerCase());\n                                Object value = rs.getObject(srcColumnName);\n                                if (value != null) {\n                                    SyncUtil.setPStmt(type, pstmt, value, i);\n                                } else {\n                                    pstmt.setNull(i, type);\n                                }\n\n                                i++;\n                            }\n\n                            pstmt.execute();\n                            if (logger.isTraceEnabled()) {\n                                logger.trace(\"Insert into target table, sql: {}\", insertSql);\n                            }\n\n                            if (idx % dbMapping.getCommitBatch() == 0) {\n                                connTarget.commit();\n                                completed = true;\n                            }\n                            idx++;\n                            impCount.incrementAndGet();\n                            if (logger.isDebugEnabled()) {\n                                logger.debug(\"successful import count:\" + impCount.get());\n                            }\n                        }\n                        if (!completed) {\n                            connTarget.commit();\n                        }\n                    }\n\n                } catch (Exception e) {\n                    logger.error(dbMapping.getTable() + \" etl failed! ==>\" + e.getMessage(), e);\n                    errMsg.add(dbMapping.getTable() + \" etl failed! ==>\" + e.getMessage());\n                }\n                return idx;\n            });\n            return true;\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n            return false;\n        }\n    }\n\n    /**\n     * 拼接目标表主键where条件\n     */\n    private static void appendCondition(DbMapping dbMapping, StringBuilder sql, Map<String, Object> values,\n                                        ResultSet rs, String backtick) throws SQLException {\n        // 拼接主键\n        for (Map.Entry<String, String> entry : dbMapping.getTargetPk().entrySet()) {\n            String targetColumnName = entry.getKey();\n            String srcColumnName = entry.getValue();\n            if (srcColumnName == null) {\n                srcColumnName = targetColumnName;\n            }\n            sql.append(backtick).append(targetColumnName).append(backtick).append(\"=? AND \");\n            values.put(targetColumnName, rs.getObject(srcColumnName));\n        }\n        int len = sql.length();\n        sql.delete(len - 4, len);\n    }\n}\n"
  },
  {
    "path": "client-adapter/clickhouse/src/main/java/com/alibaba/otter/canal/client/adapter/clickhouse/service/ClickHouseMirrorDbBatchSyncService.java",
    "content": "package com.alibaba.otter.canal.client.adapter.clickhouse.service;\n\nimport java.sql.Connection;\nimport java.sql.Statement;\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.JSONWriter.Feature;\nimport com.alibaba.otter.canal.client.adapter.clickhouse.config.MappingConfig;\nimport com.alibaba.otter.canal.client.adapter.clickhouse.config.MirrorDbConfig;\nimport com.alibaba.otter.canal.client.adapter.clickhouse.support.SyncUtil;\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\n\n/**\n * CLICKHOUSE镜像库同步操作业务\n *\n * @author: Xander\n * @date: Created in 2023/11/10 22:23\n * @email: zhrunxin33@gmail.com\n * @version 1.1.8\n */\npublic class ClickHouseMirrorDbBatchSyncService {\n\n    private static final Logger         logger = LoggerFactory.getLogger(ClickHouseMirrorDbBatchSyncService.class);\n\n    // 镜像库配置\n    private Map<String, MirrorDbConfig> mirrorDbConfigCache;\n    private DruidDataSource             dataSource;\n    // clickhouseSyncService代理\n    private ClickHouseBatchSyncService  clickHouseBatchSyncService;\n\n    public ClickHouseMirrorDbBatchSyncService(Map<String, MirrorDbConfig> mirrorDbConfigCache,\n                                              DruidDataSource dataSource, Integer threads, Integer batchSize,\n                                              Long scheduleTime, Map<String, Map<String, Integer>> columnsTypeCache,\n                                              boolean skipDupException){\n        this.mirrorDbConfigCache = mirrorDbConfigCache;\n        this.dataSource = dataSource;\n        this.clickHouseBatchSyncService = new ClickHouseBatchSyncService(dataSource,\n            threads,\n            batchSize,\n            scheduleTime,\n            columnsTypeCache,\n            skipDupException);\n    }\n\n    /**\n     * 批量同步方法\n     *\n     * @param dmls 批量 DML，包含DDL\n     */\n    public void sync(List<Dml> dmls) {\n        List<Dml> dmlList = new ArrayList<>();\n        for (Dml dml : dmls) {\n            String destination = StringUtils.trimToEmpty(dml.getDestination());\n            String database = dml.getDatabase();\n            MirrorDbConfig mirrorDbConfig = mirrorDbConfigCache.get(destination + \".\" + database);\n            if (mirrorDbConfig == null) {\n                continue;\n            }\n            if (mirrorDbConfig.getMappingConfig() == null) {\n                continue;\n            }\n            if (dml.getGroupId() != null && StringUtils.isNotEmpty(mirrorDbConfig.getMappingConfig().getGroupId())) {\n                if (!mirrorDbConfig.getMappingConfig().getGroupId().equals(dml.getGroupId())) {\n                    continue; // 如果groupId不匹配则过滤\n                }\n            }\n\n            if (dml.getIsDdl() != null && dml.getIsDdl() && StringUtils.isNotEmpty(dml.getSql())) {\n                // 确保执行DDL前DML已执行完\n                syncDml(dmlList);\n                dmlList.clear();\n\n                // DDL\n                if (logger.isDebugEnabled()) {\n                    logger.debug(\"DDL: {}\", JSON.toJSONString(dml, Feature.WriteNulls));\n                }\n                executeDdl(mirrorDbConfig, dml);\n                clickHouseBatchSyncService.getColumnsTypeCache()\n                    .remove(destination + \".\" + database + \".\" + dml.getTable());\n                mirrorDbConfig.getTableConfig().remove(dml.getTable()); // 删除对应库表配置\n            } else {\n                // DML\n                initMappingConfig(dml.getTable(), mirrorDbConfig.getMappingConfig(), mirrorDbConfig, dml);\n                dmlList.add(dml);\n            }\n        }\n        syncDml(dmlList);\n    }\n\n    /**\n     * 批量同步Dml\n     *\n     * @param dmlList Dml列表，不包含DDL\n     */\n    private void syncDml(List<Dml> dmlList) {\n        if (dmlList == null || dmlList.isEmpty()) {\n            return;\n        }\n        clickHouseBatchSyncService.sync(dmlList, dml -> {\n            MirrorDbConfig mirrorDbConfig = mirrorDbConfigCache.get(dml.getDestination() + \".\" + dml.getDatabase());\n            if (mirrorDbConfig == null) {\n                return false;\n            }\n            String table = dml.getTable();\n            MappingConfig config = mirrorDbConfig.getTableConfig().get(table);\n\n            if (config == null) {\n                return false;\n            }\n            clickHouseBatchSyncService.appendDmlBufferPartition(config, dml);\n            return true;\n        });\n    }\n\n    /**\n     * 初始化表配置\n     *\n     * @param key 配置key: destination.database.table\n     * @param baseConfigMap db sync config\n     * @param dml DML\n     */\n    private void initMappingConfig(String key, MappingConfig baseConfigMap, MirrorDbConfig mirrorDbConfig, Dml dml) {\n        MappingConfig mappingConfig = mirrorDbConfig.getTableConfig().get(key);\n        if (mappingConfig == null) {\n            // 构造表配置\n            mappingConfig = new MappingConfig();\n            mappingConfig.setDataSourceKey(baseConfigMap.getDataSourceKey());\n            mappingConfig.setDestination(baseConfigMap.getDestination());\n            mappingConfig.setGroupId(baseConfigMap.getGroupId());\n            mappingConfig.setOuterAdapterKey(baseConfigMap.getOuterAdapterKey());\n            mappingConfig.setConcurrent(baseConfigMap.getConcurrent());\n            MappingConfig.DbMapping dbMapping = new MappingConfig.DbMapping();\n            mappingConfig.setDbMapping(dbMapping);\n            dbMapping.setDatabase(dml.getDatabase());\n            dbMapping.setTable(dml.getTable());\n            dbMapping.setTargetDb(dml.getDatabase());\n            dbMapping.setTargetTable(dml.getTable());\n            dbMapping.setMapAll(true);\n            List<String> pkNames = dml.getPkNames();\n            Map<String, String> pkMapping = new LinkedHashMap<>();\n            pkNames.forEach(pkName -> pkMapping.put(pkName, pkName));\n            dbMapping.setTargetPk(pkMapping);\n\n            mirrorDbConfig.getTableConfig().put(key, mappingConfig);\n        }\n    }\n\n    /**\n     * DDL 操作\n     *\n     * @param ddl DDL\n     */\n    private void executeDdl(MirrorDbConfig mirrorDbConfig, Dml ddl) {\n        try (Connection conn = dataSource.getConnection(); Statement statement = conn.createStatement()) {\n            // 替换反引号\n            String sql = ddl.getSql();\n            String backtick = SyncUtil.getBacktickByDbType(dataSource.getDbType());\n            if (!\"`\".equals(backtick)) {\n                sql = sql.replaceAll(\"`\", backtick);\n            }\n            statement.execute(sql);\n            // 移除对应配置\n            mirrorDbConfig.getTableConfig().remove(ddl.getTable());\n            if (logger.isTraceEnabled()) {\n                logger.trace(\"Execute DDL sql: {} for database: {}\", ddl.getSql(), ddl.getDatabase());\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/clickhouse/src/main/java/com/alibaba/otter/canal/client/adapter/clickhouse/support/BatchExecutor.java",
    "content": "package com.alibaba.otter.canal.client.adapter.clickhouse.support;\n\nimport java.io.Closeable;\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.SQLException;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport javax.sql.DataSource;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * sql批量执行器\n *\n * @author rewerma 2018-11-7 下午06:45:49\n * @version 1.0.0\n */\npublic class BatchExecutor implements Closeable {\n\n    private static final Logger logger = LoggerFactory.getLogger(BatchExecutor.class);\n\n    private DataSource          dataSource;\n    private Connection          conn;\n    private AtomicInteger       idx    = new AtomicInteger(0);\n\n    public BatchExecutor(DataSource dataSource){\n        this.dataSource = dataSource;\n    }\n\n    public Connection getConn() {\n        if (conn == null) {\n            try {\n                conn = dataSource.getConnection();\n                this.conn.setAutoCommit(false);\n            } catch (SQLException e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n        return conn;\n    }\n\n    public static void setValue(List<Map<String, ?>> values, int type, Object value) {\n        Map<String, Object> valueItem = new HashMap<>();\n        valueItem.put(\"type\", type);\n        valueItem.put(\"value\", value);\n        values.add(valueItem);\n    }\n\n    public void execute(String sql, List<Map<String, ?>> values) throws SQLException {\n        PreparedStatement pstmt = getConn().prepareStatement(sql);\n        int len = values.size();\n        for (int i = 0; i < len; i++) {\n            int type = (Integer) values.get(i).get(\"type\");\n            Object value = values.get(i).get(\"value\");\n            SyncUtil.setPStmt(type, pstmt, value, i + 1);\n        }\n\n        pstmt.execute();\n        idx.incrementAndGet();\n        pstmt.close();\n    }\n\n    public void batchExecute(String sql, List<List<Map<String, ?>>> batchValues) throws SQLException {\n        PreparedStatement pstmt = getConn().prepareStatement(sql);\n        for (int i = 0; i < batchValues.size(); i++) {\n            List<Map<String, ?>> values = batchValues.get(i);\n            for (int j = 0; j < values.size(); j++) {\n                int type = (Integer) values.get(j).get(\"type\");\n                Object value = values.get(j).get(\"value\");\n                SyncUtil.setPStmt(type, pstmt, value, j + 1);\n            }\n            pstmt.addBatch();\n        }\n\n        pstmt.executeBatch();\n        idx.addAndGet(batchValues.size());\n        pstmt.close();\n    }\n\n    public void commit() throws SQLException {\n        getConn().commit();\n        if (logger.isTraceEnabled()) {\n            logger.trace(\"Batch executor commit \" + idx.get() + \" rows\");\n        }\n        idx.set(0);\n    }\n\n    public void rollback() throws SQLException {\n        getConn().rollback();\n        if (logger.isTraceEnabled()) {\n            logger.trace(\"Batch executor rollback \" + idx.get() + \" rows\");\n        }\n        idx.set(0);\n    }\n\n    @Override\n    public void close() {\n        if (conn != null) {\n            try {\n                conn.close();\n            } catch (SQLException e) {\n                logger.error(e.getMessage(), e);\n            } finally {\n                conn = null;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/clickhouse/src/main/java/com/alibaba/otter/canal/client/adapter/clickhouse/support/SingleDml.java",
    "content": "package com.alibaba.otter.canal.client.adapter.clickhouse.support;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.springframework.util.LinkedCaseInsensitiveMap;\n\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\n\npublic class SingleDml {\n\n    private String              destination;\n    private String              database;\n    private String              table;\n    private String              type;\n    private Map<String, Object> data;\n    private Map<String, Object> old;\n\n    public String getDestination() {\n        return destination;\n    }\n\n    public void setDestination(String destination) {\n        this.destination = destination;\n    }\n\n    public String getDatabase() {\n        return database;\n    }\n\n    public void setDatabase(String database) {\n        this.database = database;\n    }\n\n    public String getTable() {\n        return table;\n    }\n\n    public void setTable(String table) {\n        this.table = table;\n    }\n\n    public String getType() {\n        return type;\n    }\n\n    public void setType(String type) {\n        this.type = type;\n    }\n\n    public Map<String, Object> getData() {\n        return data;\n    }\n\n    public void setData(Map<String, Object> data) {\n        this.data = data;\n    }\n\n    public Map<String, Object> getOld() {\n        return old;\n    }\n\n    public void setOld(Map<String, Object> old) {\n        this.old = old;\n    }\n\n    public static List<SingleDml> dml2SingleDmls(Dml dml, boolean caseInsensitive) {\n        List<SingleDml> singleDmls = new ArrayList<>();\n        if (dml.getData() != null) {\n            int size = dml.getData().size();\n            for (int i = 0; i < size; i++) {\n                SingleDml singleDml = new SingleDml();\n                singleDml.setDestination(dml.getDestination());\n                singleDml.setDatabase(dml.getDatabase());\n                singleDml.setTable(dml.getTable());\n                singleDml.setType(dml.getType());\n                Map<String, Object> data = dml.getData().get(i);\n                if (caseInsensitive) {\n                    data = toCaseInsensitiveMap(data);\n                }\n                singleDml.setData(data);\n                if (dml.getOld() != null) {\n                    Map<String, Object> oldData = dml.getOld().get(i);\n                    if (caseInsensitive) {\n                        oldData = toCaseInsensitiveMap(oldData);\n                    }\n                    singleDml.setOld(oldData);\n                }\n                singleDmls.add(singleDml);\n            }\n        } else if (\"TRUNCATE\".equalsIgnoreCase(dml.getType())) {\n            SingleDml singleDml = new SingleDml();\n            singleDml.setDestination(dml.getDestination());\n            singleDml.setDatabase(dml.getDatabase());\n            singleDml.setTable(dml.getTable());\n            singleDml.setType(dml.getType());\n            singleDmls.add(singleDml);\n        }\n        return singleDmls;\n    }\n\n    public static List<SingleDml> dml2SingleDmls(Dml dml) {\n        return dml2SingleDmls(dml, false);\n    }\n\n    private static <V> LinkedCaseInsensitiveMap<V> toCaseInsensitiveMap(Map<String, V> data) {\n        LinkedCaseInsensitiveMap map = new LinkedCaseInsensitiveMap();\n        map.putAll(data);\n        return map;\n    }\n}\n"
  },
  {
    "path": "client-adapter/clickhouse/src/main/java/com/alibaba/otter/canal/client/adapter/clickhouse/support/SyncUtil.java",
    "content": "package com.alibaba.otter.canal.client.adapter.clickhouse.support;\n\nimport java.io.Reader;\nimport java.io.StringReader;\nimport java.math.BigDecimal;\nimport java.nio.charset.StandardCharsets;\nimport java.sql.*;\nimport java.util.Collection;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.druid.DbType;\nimport com.alibaba.otter.canal.client.adapter.clickhouse.config.MappingConfig;\nimport com.alibaba.otter.canal.client.adapter.support.Util;\n\npublic class SyncUtil {\n\n    private static final Logger logger = LoggerFactory.getLogger(SyncUtil.class);\n\n    public static Map<String, String> getColumnsMap(MappingConfig.DbMapping dbMapping, Map<String, Object> data) {\n        return getColumnsMap(dbMapping, data.keySet());\n    }\n\n    public static Map<String, String> getColumnsMap(MappingConfig.DbMapping dbMapping, Collection<String> columns) {\n        Map<String, String> columnsMap;\n        if (dbMapping.getMapAll()) {\n            if (dbMapping.getAllMapColumns() != null) {\n                return dbMapping.getAllMapColumns();\n            }\n            columnsMap = new LinkedHashMap<>();\n            for (String srcColumn : columns) {\n                boolean flag = true;\n                if (dbMapping.getTargetColumns() != null) {\n                    for (Map.Entry<String, String> entry : dbMapping.getTargetColumns().entrySet()) {\n                        if (srcColumn.equals(entry.getValue())) {\n                            columnsMap.put(entry.getKey(), srcColumn);\n                            flag = false;\n                            break;\n                        }\n                    }\n                }\n                if (flag) {\n                    columnsMap.put(srcColumn, srcColumn);\n                }\n            }\n            dbMapping.setAllMapColumns(columnsMap);\n        } else {\n            columnsMap = dbMapping.getTargetColumns();\n        }\n        return columnsMap;\n    }\n\n    /**\n     * 设置 preparedStatement\n     *\n     * @param type sqlType\n     * @param pstmt 需要设置的preparedStatement\n     * @param value 值\n     * @param i 索引号\n     */\n    public static void setPStmt(int type, PreparedStatement pstmt, Object value, int i) throws SQLException {\n        switch (type) {\n            case Types.BIT:\n            case Types.BOOLEAN:\n                if (value instanceof Boolean) {\n                    pstmt.setBoolean(i, (Boolean) value);\n                } else if (value instanceof String) {\n                    boolean v = !value.equals(\"0\");\n                    pstmt.setBoolean(i, v);\n                } else if (value instanceof Number) {\n                    boolean v = ((Number) value).intValue() != 0;\n                    pstmt.setBoolean(i, v);\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.CHAR:\n            case Types.NCHAR:\n            case Types.VARCHAR:\n            case Types.LONGVARCHAR:\n                if (value instanceof String) {\n                    pstmt.setString(i, (String) value);\n                } else if (value == null) {\n                    pstmt.setNull(i, type);\n                } else {\n                    pstmt.setString(i, value.toString());\n                }\n                break;\n            case Types.TINYINT:\n                // 向上提升一级，处理unsigned情况\n                if (value instanceof Number) {\n                    pstmt.setShort(i, ((Number) value).shortValue());\n                } else if (value instanceof String) {\n                    pstmt.setShort(i, Short.parseShort((String) value));\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.SMALLINT:\n                if (value instanceof Number) {\n                    pstmt.setInt(i, ((Number) value).intValue());\n                } else if (value instanceof String) {\n                    pstmt.setInt(i, Integer.parseInt((String) value));\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.INTEGER:\n                if (value instanceof Number) {\n                    pstmt.setLong(i, ((Number) value).longValue());\n                } else if (value instanceof String) {\n                    pstmt.setLong(i, Long.parseLong((String) value));\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.BIGINT:\n                if (value instanceof Number) {\n                    pstmt.setBigDecimal(i, new BigDecimal(value.toString()));\n                } else if (value instanceof String) {\n                    pstmt.setBigDecimal(i, new BigDecimal(value.toString()));\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.DECIMAL:\n            case Types.NUMERIC:\n                if (value instanceof BigDecimal) {\n                    pstmt.setBigDecimal(i, (BigDecimal) value);\n                } else if (value instanceof Byte) {\n                    pstmt.setInt(i, ((Byte) value).intValue());\n                } else if (value instanceof Short) {\n                    pstmt.setInt(i, ((Short) value).intValue());\n                } else if (value instanceof Integer) {\n                    pstmt.setInt(i, (Integer) value);\n                } else if (value instanceof Long) {\n                    pstmt.setLong(i, (Long) value);\n                } else if (value instanceof Float) {\n                    pstmt.setBigDecimal(i, new BigDecimal((float) value));\n                } else if (value instanceof Double) {\n                    pstmt.setBigDecimal(i, new BigDecimal((double) value));\n                } else if (value != null) {\n                    pstmt.setBigDecimal(i, new BigDecimal(value.toString()));\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.REAL:\n                if (value instanceof Number) {\n                    pstmt.setFloat(i, ((Number) value).floatValue());\n                } else if (value instanceof String) {\n                    pstmt.setFloat(i, Float.parseFloat((String) value));\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.FLOAT:\n            case Types.DOUBLE:\n                if (value instanceof Number) {\n                    pstmt.setDouble(i, ((Number) value).doubleValue());\n                } else if (value instanceof String) {\n                    pstmt.setDouble(i, Double.parseDouble((String) value));\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.BINARY:\n            case Types.VARBINARY:\n            case Types.LONGVARBINARY:\n            case Types.BLOB:\n                if (value instanceof Blob) {\n                    pstmt.setBlob(i, (Blob) value);\n                } else if (value instanceof byte[]) {\n                    pstmt.setBytes(i, (byte[]) value);\n                } else if (value instanceof String) {\n                    pstmt.setBytes(i, ((String) value).getBytes(StandardCharsets.ISO_8859_1));\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.CLOB:\n                if (value instanceof Clob) {\n                    pstmt.setClob(i, (Clob) value);\n                } else if (value instanceof byte[]) {\n                    pstmt.setBytes(i, (byte[]) value);\n                } else if (value instanceof String) {\n                    Reader clobReader = new StringReader((String) value);\n                    pstmt.setCharacterStream(i, clobReader);\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.DATE:\n                if (value instanceof Date) {\n                    pstmt.setDate(i, (Date) value);\n                } else if (value instanceof java.util.Date) {\n                    pstmt.setDate(i, new Date(((java.util.Date) value).getTime()));\n                } else if (value instanceof String) {\n                    String v = (String) value;\n                    if (!v.startsWith(\"0000-00-00\")) {\n                        java.util.Date date = Util.parseDate(v);\n                        if (date != null) {\n                            pstmt.setDate(i, new Date(date.getTime()));\n                        } else {\n                            pstmt.setNull(i, type);\n                        }\n                    } else {\n                        pstmt.setObject(i, value);\n                    }\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.TIME:\n                if (value instanceof Time) {\n                    pstmt.setTime(i, (Time) value);\n                } else if (value instanceof java.util.Date) {\n                    pstmt.setTime(i, new Time(((java.util.Date) value).getTime()));\n                } else if (value instanceof String) {\n                    String v = (String) value;\n                    java.util.Date date = Util.parseDate(v);\n                    if (date != null) {\n                        pstmt.setTime(i, new Time(date.getTime()));\n                    } else {\n                        pstmt.setNull(i, type);\n                    }\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.TIMESTAMP:\n                if (value instanceof Timestamp) {\n                    pstmt.setTimestamp(i, (Timestamp) value);\n                } else if (value instanceof java.util.Date) {\n                    pstmt.setTimestamp(i, new Timestamp(((java.util.Date) value).getTime()));\n                } else if (value instanceof String) {\n                    String v = (String) value;\n                    if (!v.startsWith(\"0000-00-00\")) {\n                        java.util.Date date = Util.parseDate(v);\n                        if (date != null) {\n                            pstmt.setTimestamp(i, new Timestamp(date.getTime()));\n                        } else {\n                            pstmt.setNull(i, type);\n                        }\n                    } else {\n                        pstmt.setObject(i, value);\n                    }\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            default:\n                pstmt.setObject(i, value, type);\n        }\n    }\n\n    public static String getDbTableName(MappingConfig.DbMapping dbMapping, String dbType) {\n        String result = \"\";\n        String backtick = getBacktickByDbType(dbType);\n        if (StringUtils.isNotEmpty(dbMapping.getTargetDb())) {\n            result += (backtick + dbMapping.getTargetDb() + backtick + \".\");\n        }\n        result += (backtick + dbMapping.getTargetTable() + backtick);\n        return result;\n    }\n\n    public static String getSourceDbTableName(MappingConfig.DbMapping dbMapping, String dbType) {\n        String result = \"\";\n        String backtick = getBacktickByDbType(dbType);\n        if (StringUtils.isNotEmpty(dbMapping.getDatabase())) {\n            result += (backtick + dbMapping.getDatabase() + backtick + \".\");\n        }\n\n        result += (backtick + dbMapping.getTable() + backtick);\n        return result;\n    }\n\n    /**\n     * 根据DbType返回反引号或空字符串\n     *\n     * @param dbTypeName DbType名称\n     * @return 反引号或空字符串\n     */\n    public static String getBacktickByDbType(String dbTypeName) {\n        DbType dbType = DbType.of(dbTypeName);\n        if (dbType == null) {\n            dbType = DbType.other;\n        }\n\n        // 只有当dbType为MySQL/MariaDB或OceanBase时返回反引号\n        switch (dbType) {\n            case mysql:\n            case mariadb:\n            case oceanbase:\n                return \"`\";\n            default:\n                return \"\";\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/clickhouse/src/main/resources/META-INF/canal/com.alibaba.otter.canal.client.adapter.OuterAdapter",
    "content": "clickhouse=com.alibaba.otter.canal.client.adapter.clickhouse.ClickHouseAdapter"
  },
  {
    "path": "client-adapter/clickhouse/src/main/resources/clickhouse/mytest_user.yml",
    "content": "dataSourceKey: defaultDS\ndestination: example\ngroupId: g1\nouterAdapterKey: clickhouse1\nconcurrent: true\ndbMapping:\n  database: mytest\n  table: user\n  targetTable: mytest.user\n  targetPk:\n    id: id\n#  mapAll: true\n  targetColumns:\n    id:\n    name:\n    role_id:\n    c_time:\n    test1:\n  etlCondition: \"where c_time>={}\"\n  commitBatch: 3000 # 批量提交的大小\n\n\n## Mirror schema synchronize config\n#dataSourceKey: defaultDS\n#destination: example\n#groupId: g1\n#outerAdapterKey: mysql1\n#concurrent: true\n#dbMapping:\n#  mirrorDb: true\n#  database: mytest\n"
  },
  {
    "path": "client-adapter/clickhouse/src/test/java/com/alibaba/otter/canal/client/adapter/clickhouse/ClickHouseBatchSyncServiceTest.java",
    "content": "package com.alibaba.otter.canal.client.adapter.clickhouse;\n\nimport java.util.*;\n\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.client.adapter.clickhouse.sync.Common;\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\n\n@Ignore\npublic class ClickHouseBatchSyncServiceTest {\n\n    private ClickHouseAdapter clickHouseAdapter;\n\n    @Before\n    public void init() {\n        clickHouseAdapter = Common.init();\n    }\n\n    @Test\n    public void insert() throws InterruptedException {\n        Dml dml = new Dml();\n        dml.setDestination(\"example\");\n        dml.setTs(new Date().getTime());\n        dml.setType(\"INSERT\");\n        dml.setDatabase(\"mytest\");\n        dml.setTable(\"user\");\n        List<Map<String, Object>> dataList = new ArrayList<>();\n        Map<String, Object> data = new LinkedHashMap<>();\n        dataList.add(data);\n        data.put(\"id\", 1L);\n        data.put(\"name\", \"Eric\");\n        data.put(\"role_id\", 1L);\n        data.put(\"c_time\", new Date());\n        data.put(\"test1\", \"sdfasdfawe中国asfwef\");\n        dml.setData(dataList);\n\n        clickHouseAdapter.sync(Collections.singletonList(dml));\n        Thread.sleep(10000L);\n    }\n\n    @Test\n    public void update() {\n        Dml dml = new Dml();\n        dml.setDestination(\"example\");\n        dml.setTs(new Date().getTime());\n        dml.setType(\"UPDATE\");\n        dml.setDatabase(\"mytest\");\n        dml.setTable(\"user\");\n        List<Map<String, Object>> dataList = new ArrayList<>();\n        Map<String, Object> data = new LinkedHashMap<>();\n        dataList.add(data);\n        data.put(\"id\", 1L);\n        data.put(\"name\", \"Eric2\");\n        dml.setData(dataList);\n        List<Map<String, Object>> oldList = new ArrayList<>();\n        Map<String, Object> old = new LinkedHashMap<>();\n        oldList.add(old);\n        old.put(\"name\", \"Eric\");\n        dml.setOld(oldList);\n\n        clickHouseAdapter.sync(Collections.singletonList(dml));\n    }\n\n    @Test\n    public void delete() {\n        Dml dml = new Dml();\n        dml.setDestination(\"example\");\n        dml.setTs(new Date().getTime());\n        dml.setType(\"DELETE\");\n        dml.setDatabase(\"mytest\");\n        dml.setTable(\"user\");\n        List<Map<String, Object>> dataList = new ArrayList<>();\n        Map<String, Object> data = new LinkedHashMap<>();\n        dataList.add(data);\n        data.put(\"id\", 1L);\n        data.put(\"name\", \"Eric2\");\n        dml.setData(dataList);\n\n        clickHouseAdapter.sync(Collections.singletonList(dml));\n    }\n\n    @Test\n    public void truncate() throws InterruptedException {\n        Dml dml = new Dml();\n        dml.setDestination(\"example\");\n        dml.setTs(new Date().getTime());\n        dml.setType(\"TRUNCATE\");\n        dml.setDatabase(\"mytest\");\n        dml.setTable(\"user\");\n        List<Map<String, Object>> dataList = new ArrayList<>();\n        Map<String, Object> data = new LinkedHashMap<>();\n        dataList.add(data);\n        data.put(\"id\", 1L);\n        data.put(\"name\", \"Eric2\");\n        dml.setData(dataList);\n        List<Map<String, Object>> oldList = new ArrayList<>();\n        Map<String, Object> old = new LinkedHashMap<>();\n        oldList.add(old);\n        old.put(\"name\", \"Eric\");\n        dml.setOld(oldList);\n\n        clickHouseAdapter.sync(Collections.singletonList(dml));\n        Thread.sleep(1000L);\n\n    }\n}\n"
  },
  {
    "path": "client-adapter/clickhouse/src/test/java/com/alibaba/otter/canal/client/adapter/clickhouse/ClickHouseBatchSyncThreadSafeTest.java",
    "content": "package com.alibaba.otter.canal.client.adapter.clickhouse;\n\nimport java.util.*;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.client.adapter.clickhouse.sync.Common;\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\n\nimport ch.qos.logback.classic.Level;\n\n/**\n * @author: Xander\n * @date: Created in 2023/11/13 22:27\n * @email: zhrunxin33@gmail.com\n * @description: Testing thread safe\n */\n\n@Ignore\npublic class ClickHouseBatchSyncThreadSafeTest {\n\n    private ClickHouseAdapter clickHouseAdapter;\n\n    private ExecutorService   executorService;\n\n    private String[]          operations = new String[] { \"INSERT\", \"UPDATE\" };\n\n    private String[]          tables     = new String[] { \"user\", \"customer\" };\n\n    @Before\n    public void init() {\n        clickHouseAdapter = Common.init();\n        Common.setLogLevel(Level.INFO);\n        executorService = Executors.newFixedThreadPool(5);\n    }\n\n    @Test\n    public void test01() throws InterruptedException, ExecutionException {\n        ArrayList<Future> list = new ArrayList();\n        AtomicInteger count = new AtomicInteger();\n        for (int i = 0; i < 10; i++) {\n            list.add(executorService.submit(() -> {\n                for (int j = 0; j < 300; j++) {\n                    Random random = new Random();\n                    int cou = count.incrementAndGet();\n                    // test insert\n                    String dmlType = operations[random.nextInt(1)];\n                    Dml dml = new Dml();\n                    dml.setDestination(\"example\");\n                    dml.setTs(new Date().getTime());\n                    dml.setType(dmlType);\n                    dml.setDatabase(\"mytest\");\n                    dml.setTable(tables[(int) Math.round(Math.random())]);\n                    List<Map<String, Object>> dataList = new ArrayList<>();\n                    Map<String, Object> data = new LinkedHashMap<>();\n                    dataList.add(data);\n                    data.put(\"id\", cou);\n                    data.put(\"name\", \"Eric\" + cou);\n                    data.put(\"role_id\", cou);\n                    data.put(\"c_time\", new Date());\n                    data.put(\"test1\", \"sdfasdfawe中国asfwef\");\n                    dml.setData(dataList);\n                    clickHouseAdapter.sync(Collections.singletonList(dml));\n                }\n            }));\n\n        }\n        for (Future future : list) {\n            future.get();\n        }\n        Thread.sleep(10000L); // waiting multiple threads execute successfully.\n    }\n\n}\n"
  },
  {
    "path": "client-adapter/clickhouse/src/test/java/com/alibaba/otter/canal/client/adapter/clickhouse/TestConstant.java",
    "content": "package com.alibaba.otter.canal.client.adapter.clickhouse;\n\nimport java.sql.SQLException;\n\nimport com.alibaba.druid.pool.DruidDataSource;\n\npublic class TestConstant {\n\n    public final static String          jdbcUrl      = \"jdbc:mysql://127.0.0.1:3306/mytest?useUnicode=true\";\n    public final static String          jdbcUser     = \"root\";\n    public final static String          jdbcPassword = \"121212\";\n\n    public final static DruidDataSource dataSource;\n\n    static {\n        dataSource = new DruidDataSource();\n        dataSource.setDriverClassName(\"com.mysql.jdbc.Driver\");\n        dataSource.setUrl(jdbcUrl);\n        dataSource.setUsername(jdbcUser);\n        dataSource.setPassword(jdbcPassword);\n        dataSource.setInitialSize(1);\n        dataSource.setMinIdle(1);\n        dataSource.setMaxActive(1);\n        dataSource.setMaxWait(60000);\n        dataSource.setTimeBetweenEvictionRunsMillis(60000);\n        dataSource.setMinEvictableIdleTimeMillis(300000);\n        dataSource.setPoolPreparedStatements(false);\n        dataSource.setMaxPoolPreparedStatementPerConnectionSize(20);\n        dataSource.setValidationQuery(\"select 1\");\n        try {\n            dataSource.init();\n        } catch (SQLException e) {\n            e.printStackTrace();\n        }\n    }\n\n}\n"
  },
  {
    "path": "client-adapter/clickhouse/src/test/java/com/alibaba/otter/canal/client/adapter/clickhouse/sync/Common.java",
    "content": "package com.alibaba.otter.canal.client.adapter.clickhouse.sync;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.client.adapter.clickhouse.ClickHouseAdapter;\nimport com.alibaba.otter.canal.client.adapter.clickhouse.TestConstant;\nimport com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;\nimport com.alibaba.otter.canal.client.adapter.support.OuterAdapterConfig;\n\nimport ch.qos.logback.classic.Level;\nimport ch.qos.logback.classic.Logger;\n\n/**\n * @author: Xander\n * @date: Created in 2023/11/13 0:16\n * @email: zhrunxin33@gmail.com @description：\n */\npublic class Common {\n\n    public static ClickHouseAdapter init() {\n        DatasourceConfig.DATA_SOURCES.put(\"defaultDS\", TestConstant.dataSource);\n\n        OuterAdapterConfig outerAdapterConfig = new OuterAdapterConfig();\n        outerAdapterConfig.setName(\"clickhouse\");\n        outerAdapterConfig.setKey(\"clickhouse1\");\n        Map<String, String> properties = new HashMap<>();\n        properties.put(\"jdbc.driveClassName\", \"ru.yandex.clickhouse.ClickHouseDriver\");\n        properties.put(\"jdbc.url\", \"jdbc:clickhouse://127.0.0.1:8123/default\");\n        properties.put(\"jdbc.username\", \"default\");\n        properties.put(\"jdbc.password\", \"123456\");\n        outerAdapterConfig.setProperties(properties);\n\n        ClickHouseAdapter adapter = new ClickHouseAdapter();\n        adapter.init(outerAdapterConfig, null);\n        return adapter;\n    }\n\n    /**\n     * set global log level\n     *\n     * @param logLevel\n     */\n    public static void setLogLevel(Level logLevel) {\n        ch.qos.logback.classic.Logger logger = (ch.qos.logback.classic.Logger) LoggerFactory\n            .getLogger(Logger.ROOT_LOGGER_NAME);\n        logger.setLevel(logLevel);\n    }\n}\n"
  },
  {
    "path": "client-adapter/clickhouse/src/test/resources/clickhouse/mytest_customer.yml",
    "content": "dataSourceKey: defaultDS\ndestination: example\ngroupId: g1\nouterAdapterKey: clickhouse1\nconcurrent: true\ndbMapping:\n  database: mytest\n  table: customer\n  targetTable: mytest.customer\n  targetPk:\n    id: id\n#  mapAll: true\n  targetColumns:\n    id:\n    name:\n    role_id:\n    c_time:\n    test1:\n  etlCondition: \"where c_time>={}\"\n  commitBatch: 3000 # 批量提交的大小\n\n\n## Mirror schema synchronize config\n#dataSourceKey: defaultDS\n#destination: example\n#groupId: g1\n#outerAdapterKey: mysql1\n#concurrent: true\n#dbMapping:\n#  mirrorDb: true\n#  database: mytest\n"
  },
  {
    "path": "client-adapter/clickhouse/src/test/resources/clickhouse/mytest_user.yml",
    "content": "dataSourceKey: defaultDS\ndestination: example\ngroupId: g1\nouterAdapterKey: clickhouse1\nconcurrent: true\ndbMapping:\n  database: mytest\n  table: user\n  targetTable: mytest.user\n  targetPk:\n    id: id\n#  mapAll: true\n  targetColumns:\n    id:\n    name:\n    role_id:\n    c_time:\n    test1:\n  etlCondition: \"where c_time>={}\"\n  commitBatch: 3000 # 批量提交的大小\n\n\n## Mirror schema synchronize config\n#dataSourceKey: defaultDS\n#destination: example\n#groupId: g1\n#outerAdapterKey: mysql1\n#concurrent: true\n#dbMapping:\n#  mirrorDb: true\n#  database: mytest\n"
  },
  {
    "path": "client-adapter/common/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>canal.client-adapter</artifactId>\n        <groupId>com.alibaba.otter</groupId>\n        <version>1.1.9-SNAPSHOT</version>\n        <relativePath>../pom.xml</relativePath>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>com.alibaba.otter</groupId>\n    <artifactId>client-adapter.common</artifactId>\n    <packaging>jar</packaging>\n    <name>canal client adapter common module for otter ${project.version}</name>\n    <dependencies>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>canal.protocol</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>connector.core</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>joda-time</groupId>\n            <artifactId>joda-time</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.powermock</groupId>\n            <artifactId>powermock-api-mockito</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.powermock</groupId>\n            <artifactId>powermock-module-junit4</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.mockito</groupId>\n            <artifactId>mockito-all</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.yaml</groupId>\n            <artifactId>snakeyaml</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.diffblue</groupId>\n            <artifactId>deeptestutils</artifactId>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/OuterAdapter.java",
    "content": "package com.alibaba.otter.canal.client.adapter;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\nimport com.alibaba.otter.canal.client.adapter.support.EtlResult;\nimport com.alibaba.otter.canal.client.adapter.support.OuterAdapterConfig;\nimport com.alibaba.otter.canal.client.adapter.support.SPI;\n\n/**\n * 外部适配器接口\n *\n * @author reweerma 2018-8-18 下午10:14:02\n * @version 1.0.0\n */\n@SPI(\"logger\")\npublic interface OuterAdapter {\n\n    /**\n     * 外部适配器初始化接口\n     *\n     * @param configuration 外部适配器配置信息\n     * @param envProperties 环境变量的配置属性\n     */\n    void init(OuterAdapterConfig configuration, Properties envProperties);\n\n    /**\n     * 往适配器中同步数据\n     *\n     * @param dmls 数据包\n     */\n    void sync(List<Dml> dmls);\n\n    /**\n     * 外部适配器销毁接口\n     */\n    void destroy();\n\n    /**\n     * Etl操作\n     *\n     * @param task 任务名, 对应配置名\n     * @param params etl筛选条件\n     */\n    default EtlResult etl(String task, List<String> params) {\n        throw new UnsupportedOperationException(\"unsupported operation\");\n    }\n\n    /**\n     * 计算总数\n     *\n     * @param task 任务名, 对应配置名\n     * @return 总数\n     */\n    default Map<String, Object> count(String task) {\n        throw new UnsupportedOperationException(\"unsupported operation\");\n    }\n\n    /**\n     * 通过task获取对应的destination\n     *\n     * @param task 任务名, 对应配置名\n     * @return destination\n     */\n    default String getDestination(String task) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/ProxyOuterAdapter.java",
    "content": "package com.alibaba.otter.canal.client.adapter;\n\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\nimport com.alibaba.otter.canal.client.adapter.support.EtlResult;\nimport com.alibaba.otter.canal.client.adapter.support.OuterAdapterConfig;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\n\npublic class ProxyOuterAdapter implements OuterAdapter {\n\n    private OuterAdapter outerAdapter;\n\n    public ProxyOuterAdapter(OuterAdapter outerAdapter) {\n        this.outerAdapter = outerAdapter;\n    }\n\n    private ClassLoader changeCL() {\n        ClassLoader cl = Thread.currentThread().getContextClassLoader();\n        Thread.currentThread().setContextClassLoader(outerAdapter.getClass().getClassLoader());\n        return cl;\n    }\n\n    private void revertCL(ClassLoader cl) {\n        Thread.currentThread().setContextClassLoader(cl);\n    }\n\n    @Override\n    public void init(OuterAdapterConfig configuration, Properties envProperties) {\n        ClassLoader cl = changeCL();\n        try {\n            outerAdapter.init(configuration, envProperties);\n        } finally {\n            revertCL(cl);\n        }\n    }\n\n    @Override\n    public void sync(List<Dml> dmls) {\n        ClassLoader cl = changeCL();\n        try {\n            outerAdapter.sync(dmls);\n        } finally {\n            revertCL(cl);\n        }\n    }\n\n    @Override\n    public void destroy() {\n        ClassLoader cl = changeCL();\n        try {\n            outerAdapter.destroy();\n        } finally {\n            revertCL(cl);\n        }\n    }\n\n    @Override\n    public EtlResult etl(String task, List<String> params) {\n        ClassLoader cl = changeCL();\n        try {\n            return OuterAdapter.super.etl(task, params);\n        } finally {\n            revertCL(cl);\n        }\n    }\n\n    @Override\n    public Map<String, Object> count(String task) {\n        ClassLoader cl = changeCL();\n        try {\n            return OuterAdapter.super.count(task);\n        } finally {\n            revertCL(cl);\n        }\n    }\n\n    @Override\n    public String getDestination(String task) {\n        ClassLoader cl = changeCL();\n        try {\n            return OuterAdapter.super.getDestination(task);\n        } finally {\n            revertCL(cl);\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/support/AbstractEtlService.java",
    "content": "package com.alibaba.otter.canal.client.adapter.support;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport javax.sql.DataSource;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.google.common.base.Joiner;\n\npublic abstract class AbstractEtlService {\n\n    protected Logger      logger       = LoggerFactory.getLogger(this.getClass());\n\n    private String        type;\n    private AdapterConfig config;\n    private final long    CNT_PER_TASK = 10000L;\n\n    public AbstractEtlService(String type, AdapterConfig config){\n        this.type = type;\n        this.config = config;\n    }\n\n    protected EtlResult importData(String sql, List<String> params) {\n        EtlResult etlResult = new EtlResult();\n        AtomicLong impCount = new AtomicLong();\n        List<String> errMsg = new ArrayList<>();\n        if (config == null) {\n            logger.warn(\"{} mapping config is null, etl go end \", type);\n            etlResult.setErrorMessage(type + \"mapping config is null, etl go end \");\n            return etlResult;\n        }\n\n        long start = System.currentTimeMillis();\n        try {\n            DruidDataSource dataSource = DatasourceConfig.DATA_SOURCES.get(config.getDataSourceKey());\n\n            List<Object> values = new ArrayList<>();\n            // 拼接条件\n            if (config.getMapping().getEtlCondition() != null && params != null) {\n                String etlCondition = config.getMapping().getEtlCondition();\n                for (String param : params) {\n                    etlCondition = etlCondition.replace(\"{}\", \"?\");\n                    values.add(param);\n                }\n\n                sql += \" \" + etlCondition;\n            }\n\n            if (logger.isDebugEnabled()) {\n                logger.debug(\"etl sql : {}\", sql);\n            }\n\n            // 获取总数\n            String countSql = \"SELECT COUNT(1) FROM ( \" + sql + \") _CNT \";\n            long cnt = (Long) Util.sqlRS(dataSource, countSql, values, rs -> {\n                Long count = null;\n                try {\n                    if (rs.next()) {\n                        count = ((Number) rs.getObject(1)).longValue();\n                    }\n                } catch (Exception e) {\n                    logger.error(e.getMessage(), e);\n                }\n                return count == null ? 0L : count;\n            });\n\n            // 当大于1万条记录时开启多线程\n            if (cnt >= 10000) {\n                int threadCount = Runtime.getRuntime().availableProcessors();\n\n                long offset;\n                long size = CNT_PER_TASK;\n                long workerCnt = cnt / size + (cnt % size == 0 ? 0 : 1);\n\n                if (logger.isDebugEnabled()) {\n                    logger.debug(\"workerCnt {} for cnt {} threadCount {}\", workerCnt, cnt, threadCount);\n                }\n\n                ExecutorService executor = Util.newFixedThreadPool(threadCount, 5000L);\n                List<Future<Boolean>> futures = new ArrayList<>();\n                for (long i = 0; i < workerCnt; i++) {\n                    offset = size * i;\n                    String sqlFinal = sql + \" LIMIT \" + offset + \",\" + size;\n                    Future<Boolean> future = executor.submit(() -> executeSqlImport(dataSource,\n                        sqlFinal,\n                        values,\n                        config.getMapping(),\n                        impCount,\n                        errMsg));\n                    futures.add(future);\n                }\n\n                for (Future<Boolean> future : futures) {\n                    future.get();\n                }\n                executor.shutdown();\n            } else {\n                executeSqlImport(dataSource, sql, values, config.getMapping(), impCount, errMsg);\n            }\n\n            logger.info(\"数据全量导入完成, 一共导入 {} 条数据, 耗时: {}\", impCount.get(), System.currentTimeMillis() - start);\n            etlResult.setResultMessage(\"导入\" + type + \" 数据：\" + impCount.get() + \" 条\");\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n            errMsg.add(type + \" 数据导入异常 =>\" + e.getMessage());\n        }\n        if (errMsg.isEmpty()) {\n            etlResult.setSucceeded(true);\n        } else {\n            etlResult.setErrorMessage(Joiner.on(\"\\n\").join(errMsg));\n        }\n        return etlResult;\n    }\n\n    protected abstract boolean executeSqlImport(DataSource ds, String sql, List<Object> values,\n                                                AdapterConfig.AdapterMapping mapping, AtomicLong impCount,\n                                                List<String> errMsg);\n\n}\n"
  },
  {
    "path": "client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/support/AdapterConfig.java",
    "content": "package com.alibaba.otter.canal.client.adapter.support;\n\npublic interface AdapterConfig {\n    String getDataSourceKey();\n\n    AdapterMapping getMapping();\n\n    interface AdapterMapping {\n        String getEtlCondition();\n    }\n}\n"
  },
  {
    "path": "client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/support/CanalClientConfig.java",
    "content": "package com.alibaba.otter.canal.client.adapter.support;\n\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\n\n/**\n * 配置信息类\n *\n * @author rewerma 2018-8-18 下午10:40:12\n * @version 1.0.0\n */\npublic class CanalClientConfig {\n\n    // 单机模式下canal server的ip:port\n    private String             canalServerHost;\n    // 集群模式下的zk地址,如果配置了单机地址则以单机为准!!\n    private String             zookeeperHosts;\n    // kafka or rocket mq 地址\n    private String             mqServers;\n    // 是否已flatMessage模式传输,只适用于mq模式\n    private Boolean            flatMessage   = true;\n    // 批大小\n    private Integer            batchSize;\n    // 同步分批提交大小\n    private Integer            syncBatchSize = 1000;\n    // 重试次数\n    private Integer            retries;\n    // 消费超时时间\n    private Long               timeout       = 500L;\n    // 模式 tcp kafka rocketMQ\n    private String             mode          = \"tcp\";\n    // aliyun ak/sk\n    private String             accessKey;\n    private String             secretKey;\n    // rabbitmq 账号密码\n    private String             username;\n    private String             password;\n    // rabbitmq vhost\n    private String             vhost         = \"/\";\n\n    private Properties         consumerProperties;\n\n    private Long               resourceOwnerId;\n    // 是否启用消息轨迹\n    private boolean            enableMessageTrace;\n    // 在使用阿里云商业化mq服务时，如果想使用云上消息轨迹功能，请设置此配置为true\n    private String             accessChannel;\n    // 用于使用开源RocketMQ时，设置自定义的消息轨迹topic\n    private String             customizedTraceTopic;\n    // 开源RocketMQ命名空间\n    private String             namespace;\n    // canal adapters 配置\n    private List<CanalAdapter> canalAdapters;\n\n    private Boolean terminateOnException = false;\n\n    public String getCanalServerHost() {\n        return canalServerHost;\n    }\n\n    public void setCanalServerHost(String canalServerHost) {\n        this.canalServerHost = canalServerHost;\n    }\n\n    public String getZookeeperHosts() {\n        return zookeeperHosts;\n    }\n\n    public void setZookeeperHosts(String zookeeperHosts) {\n        this.zookeeperHosts = zookeeperHosts;\n    }\n\n    public String getMqServers() {\n        return mqServers;\n    }\n\n    public void setMqServers(String mqServers) {\n        this.mqServers = mqServers;\n    }\n\n    public Boolean getFlatMessage() {\n        return flatMessage;\n    }\n\n    public void setFlatMessage(Boolean flatMessage) {\n        this.flatMessage = flatMessage;\n    }\n\n    public Integer getBatchSize() {\n        return batchSize;\n    }\n\n    public void setBatchSize(Integer batchSize) {\n        this.batchSize = batchSize;\n    }\n\n    public Integer getRetries() {\n        return retries;\n    }\n\n    public Integer getSyncBatchSize() {\n        return syncBatchSize;\n    }\n\n    public void setSyncBatchSize(Integer syncBatchSize) {\n        this.syncBatchSize = syncBatchSize;\n    }\n\n    public void setRetries(Integer retries) {\n        this.retries = retries;\n    }\n\n    public Long getTimeout() {\n        return timeout;\n    }\n\n    public void setTimeout(Long timeout) {\n        this.timeout = timeout;\n    }\n\n    public String getMode() {\n        return mode;\n    }\n\n    public void setMode(String mode) {\n        this.mode = mode;\n    }\n\n    public String getAccessKey() {\n        return accessKey;\n    }\n\n    public void setAccessKey(String accessKey) {\n        this.accessKey = accessKey;\n    }\n\n    public String getSecretKey() {\n        return secretKey;\n    }\n\n    public void setSecretKey(String secretKey) {\n        this.secretKey = secretKey;\n    }\n\n    public String getUsername() {\n        return username;\n    }\n\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    public String getVhost() {\n        return vhost;\n    }\n\n    public void setVhost(String vhost) {\n        this.vhost = vhost;\n    }\n\n    public Properties getConsumerProperties() {\n        return consumerProperties;\n    }\n\n    public void setConsumerProperties(Properties consumerProperties) {\n        this.consumerProperties = consumerProperties;\n    }\n\n    public Long getResourceOwnerId() {\n        return resourceOwnerId;\n    }\n\n    public void setResourceOwnerId(Long resourceOwnerId) {\n        this.resourceOwnerId = resourceOwnerId;\n    }\n\n    public List<CanalAdapter> getCanalAdapters() {\n        return canalAdapters;\n    }\n\n    public void setCanalAdapters(List<CanalAdapter> canalAdapters) {\n        this.canalAdapters = canalAdapters;\n    }\n\n    public boolean isEnableMessageTrace() {\n        return enableMessageTrace;\n    }\n\n    public void setEnableMessageTrace(boolean enableMessageTrace) {\n        this.enableMessageTrace = enableMessageTrace;\n    }\n\n    public String getAccessChannel() {\n        return accessChannel;\n    }\n\n    public void setAccessChannel(String accessChannel) {\n        this.accessChannel = accessChannel;\n    }\n\n    public String getCustomizedTraceTopic() {\n        return customizedTraceTopic;\n    }\n\n    public void setCustomizedTraceTopic(String customizedTraceTopic) {\n        this.customizedTraceTopic = customizedTraceTopic;\n    }\n\n    public String getNamespace() {\n        return namespace;\n    }\n\n    public void setNamespace(String namespace) {\n        this.namespace = namespace;\n    }\n\n    public Boolean getTerminateOnException() {\n        return terminateOnException;\n    }\n\n    public void setTerminateOnException(Boolean terminateOnException) {\n        this.terminateOnException = terminateOnException;\n    }\n\n    public static class CanalAdapter {\n\n        private String      instance; // 实例名\n\n        private List<Group> groups;   // 适配器分组列表\n\n        public String getInstance() {\n            return instance;\n        }\n\n        public void setInstance(String instance) {\n            if (instance != null) {\n                this.instance = instance.trim();\n            }\n        }\n\n        public List<Group> getGroups() {\n            return groups;\n        }\n\n        public void setGroups(List<Group> groups) {\n            this.groups = groups;\n        }\n    }\n\n    public static class Group {\n\n        // group id\n        private String                          groupId          = \"default\";\n        private List<OuterAdapterConfig>        outerAdapters;                           // 适配器列表\n        private Map<String, OuterAdapterConfig> outerAdaptersMap = new LinkedHashMap<>();\n\n        public String getGroupId() {\n            return groupId;\n        }\n\n        public void setGroupId(String groupId) {\n            this.groupId = groupId;\n        }\n\n        public List<OuterAdapterConfig> getOuterAdapters() {\n            return outerAdapters;\n        }\n\n        public void setOuterAdapters(List<OuterAdapterConfig> outerAdapters) {\n            this.outerAdapters = outerAdapters;\n        }\n\n        public Map<String, OuterAdapterConfig> getOuterAdaptersMap() {\n            return outerAdaptersMap;\n        }\n\n        public void setOuterAdaptersMap(Map<String, OuterAdapterConfig> outerAdaptersMap) {\n            this.outerAdaptersMap = outerAdaptersMap;\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/support/Constant.java",
    "content": "package com.alibaba.otter.canal.client.adapter.support;\n\npublic class Constant {\n\n    public static final String CONF_DIR = \"conf\";\n}\n"
  },
  {
    "path": "client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/support/DaemonThreadFactory.java",
    "content": "package com.alibaba.otter.canal.client.adapter.support;\n\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ThreadFactory;\n\npublic class DaemonThreadFactory implements ThreadFactory {\n\n    public static final ThreadFactory daemonThreadFactory = new DaemonThreadFactory();\n\n    public Thread newThread(Runnable r) {\n        Thread t = Executors.defaultThreadFactory().newThread(r);\n        t.setDaemon(true);\n        return t;\n    }\n}\n"
  },
  {
    "path": "client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/support/DatasourceConfig.java",
    "content": "package com.alibaba.otter.canal.client.adapter.support;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport com.alibaba.druid.pool.DruidDataSource;\n\n/**\n * 数据源配置\n *\n * @author rewerma @ 2018-10-20\n * @version 1.0.0\n */\npublic class DatasourceConfig {\n\n    public final static Map<String, DruidDataSource> DATA_SOURCES = new ConcurrentHashMap<>(); // key对应的数据源\n\n    private String                                   driver       = \"com.mysql.jdbc.Driver\";   // 默认为mysql jdbc驱动\n    private String                                   url;                                      // jdbc url\n    private String                                   database;                                 // jdbc database\n    private String                                   type         = \"mysql\";                   // 类型, 默认为mysql\n    private String                                   username;                                 // jdbc username\n    private String                                   password;                                 // jdbc password\n    private Integer                                  maxActive    = 3;                         // 连接池最大连接数,默认为3\n\n    public String getDriver() {\n        return driver;\n    }\n\n    public void setDriver(String driver) {\n        this.driver = driver;\n    }\n\n    public String getUrl() {\n        return url;\n    }\n\n    public void setUrl(String url) {\n        this.url = url;\n    }\n\n    public String getDatabase() {\n        return database;\n    }\n\n    public void setDatabase(String database) {\n        this.database = database;\n    }\n\n    public String getType() {\n        return type;\n    }\n\n    public void setType(String type) {\n        this.type = type;\n    }\n\n    public String getUsername() {\n        return username;\n    }\n\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    public Integer getMaxActive() {\n        return maxActive;\n    }\n\n    public void setMaxActive(Integer maxActive) {\n        this.maxActive = maxActive;\n    }\n}\n"
  },
  {
    "path": "client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/support/Dml.java",
    "content": "package com.alibaba.otter.canal.client.adapter.support;\n\nimport java.io.Serializable;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * DML操作转换对象\n *\n * @author rewerma 2018-8-19 下午11:30:49\n * @version 1.0.0\n */\npublic class Dml implements Serializable {\n\n    private static final long         serialVersionUID = 2611556444074013268L;\n\n    private String                    destination;                            // 对应canal的实例或者MQ的topic\n    private String                    groupId;                                // 对应mq的group id\n    private String                    database;                               // 数据库或schema\n    private String                    table;                                  // 表名\n    private List<String>              pkNames;\n    private Boolean                   isDdl;\n    private String                    type;                                   // 类型: INSERT UPDATE DELETE\n    // binlog executeTime\n    private Long                      es;                                     // 执行耗时\n    // dml build timeStamp\n    private Long                      ts;                                     // 同步时间\n    private String                    sql;                                    // 执行的sql, dml sql为空\n    private List<Map<String, Object>> data;                                   // 数据列表\n    private List<Map<String, Object>> old;                                    // 旧数据列表, 用于update, size和data的size一一对应\n\n    public String getDestination() {\n        return destination;\n    }\n\n    public void setDestination(String destination) {\n        this.destination = destination;\n    }\n\n    public String getGroupId() {\n        return groupId;\n    }\n\n    public void setGroupId(String groupId) {\n        this.groupId = groupId;\n    }\n\n    public String getDatabase() {\n        return database;\n    }\n\n    public void setDatabase(String database) {\n        this.database = database;\n    }\n\n    public String getTable() {\n        return table;\n    }\n\n    public void setTable(String table) {\n        this.table = table;\n    }\n\n    public List<String> getPkNames() {\n        return pkNames;\n    }\n\n    public void setPkNames(List<String> pkNames) {\n        this.pkNames = pkNames;\n    }\n\n    public Boolean getIsDdl() {\n        return isDdl;\n    }\n\n    public void setIsDdl(Boolean isDdl) {\n        this.isDdl = isDdl;\n    }\n\n    public String getType() {\n        return type;\n    }\n\n    public void setType(String type) {\n        this.type = type;\n    }\n\n    public Long getTs() {\n        return ts;\n    }\n\n    public void setTs(Long ts) {\n        this.ts = ts;\n    }\n\n    public String getSql() {\n        return sql;\n    }\n\n    public void setSql(String sql) {\n        this.sql = sql;\n    }\n\n    public List<Map<String, Object>> getData() {\n        return data;\n    }\n\n    public void setData(List<Map<String, Object>> data) {\n        this.data = data;\n    }\n\n    public List<Map<String, Object>> getOld() {\n        return old;\n    }\n\n    public void setOld(List<Map<String, Object>> old) {\n        this.old = old;\n    }\n\n    public Long getEs() {\n        return es;\n    }\n\n    public void setEs(Long es) {\n        this.es = es;\n    }\n\n    public void clear() {\n        database = null;\n        table = null;\n        type = null;\n        ts = null;\n        es = null;\n        data = null;\n        old = null;\n        sql = null;\n    }\n\n    @Override\n    public String toString() {\n        return \"Dml{\" + \"destination='\" + destination + '\\'' + \", database='\" + database + '\\'' + \", table='\" + table\n               + '\\'' + \", type='\" + type + '\\'' + \", es=\" + es + \", ts=\" + ts + \", sql='\" + sql + '\\'' + \", data=\"\n               + data + \", old=\" + old + '}';\n    }\n}\n"
  },
  {
    "path": "client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/support/EtlResult.java",
    "content": "package com.alibaba.otter.canal.client.adapter.support;\n\nimport java.io.Serializable;\n\n/**\n * ETL的结果对象\n *\n * @author rewerma @ 2018-10-20\n * @version 1.0.0\n */\npublic class EtlResult implements Serializable {\n\n    private static final long serialVersionUID = 4250522736289866505L;\n\n    private boolean           succeeded        = false;\n\n    private String            resultMessage;\n\n    private String            errorMessage;\n\n    public boolean getSucceeded() {\n        return succeeded;\n    }\n\n    public void setSucceeded(boolean succeeded) {\n        this.succeeded = succeeded;\n    }\n\n    public String getResultMessage() {\n        return resultMessage;\n    }\n\n    public void setResultMessage(String resultMessage) {\n        this.resultMessage = resultMessage;\n    }\n\n    public String getErrorMessage() {\n        return errorMessage;\n    }\n\n    public void setErrorMessage(String errorMessage) {\n        this.errorMessage = errorMessage;\n    }\n}\n"
  },
  {
    "path": "client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/support/ExtensionLoader.java",
    "content": "package com.alibaba.otter.canal.client.adapter.support;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.InputStreamReader;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.Arrays;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.regex.Pattern;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * SPI 类加载器\n *\n * @author rewerma 2018-8-19 下午11:30:49\n * @version 1.0.0\n */\npublic class ExtensionLoader<T> {\n\n    private static final Logger                                      logger                     = LoggerFactory\n        .getLogger(ExtensionLoader.class);\n\n    private static final String                                      SERVICES_DIRECTORY         = \"META-INF/services/\";\n\n    private static final String                                      CANAL_DIRECTORY            = \"META-INF/canal/\";\n\n    private static final String                                      DEFAULT_CLASSLOADER_POLICY = \"internal\";\n\n    private static final Pattern                                     NAME_SEPARATOR             = Pattern\n        .compile(\"\\\\s*[,]+\\\\s*\");\n\n    private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS          = new ConcurrentHashMap<>();\n\n    private static final ConcurrentMap<Class<?>, Object>             EXTENSION_INSTANCES        = new ConcurrentHashMap<>();\n\n    private static final ConcurrentMap<String, Object>               EXTENSION_KEY_INSTANCE     = new ConcurrentHashMap<>();\n\n    private final Class<?>                                           type;\n\n    private final String                                             classLoaderPolicy;\n\n    private final ConcurrentMap<Class<?>, String>                    cachedNames                = new ConcurrentHashMap<>();\n\n    private final Holder<Map<String, Class<?>>>                      cachedClasses              = new Holder<>();\n\n    private final ConcurrentMap<String, Holder<Object>>              cachedInstances            = new ConcurrentHashMap<>();\n\n    private String                                                   cachedDefaultName;\n\n    private ConcurrentHashMap<String, IllegalStateException>         exceptions                 = new ConcurrentHashMap<>();\n\n    private static <T> boolean withExtensionAnnotation(Class<T> type) {\n        return type.isAnnotationPresent(SPI.class);\n    }\n\n    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {\n        return getExtensionLoader(type, DEFAULT_CLASSLOADER_POLICY);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type, String classLoaderPolicy) {\n        if (type == null) throw new IllegalArgumentException(\"Extension type == null\");\n        if (!type.isInterface()) {\n            throw new IllegalArgumentException(\"Extension type(\" + type + \") is not interface!\");\n        }\n        if (!withExtensionAnnotation(type)) {\n            throw new IllegalArgumentException(\"Extension type(\" + type + \") is not extension, because WITHOUT @\"\n                                               + SPI.class.getSimpleName() + \" Annotation!\");\n        }\n\n        ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);\n        if (loader == null) {\n            EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type, classLoaderPolicy));\n            loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);\n        }\n        return loader;\n    }\n\n    private ExtensionLoader(Class<?> type, String classLoaderPolicy){\n        this.type = type;\n        this.classLoaderPolicy = classLoaderPolicy;\n    }\n\n    /**\n     * 返回指定名字的扩展\n     *\n     * @param name\n     * @return\n     */\n    @SuppressWarnings(\"unchecked\")\n    public T getExtension(String name) {\n        if (name == null || name.length() == 0) throw new IllegalArgumentException(\"Extension name == null\");\n        if (\"true\".equals(name)) {\n            return getDefaultExtension();\n        }\n        Holder<Object> holder = cachedInstances.get(name);\n        if (holder == null) {\n            cachedInstances.putIfAbsent(name, new Holder<>());\n            holder = cachedInstances.get(name);\n        }\n        Object instance = holder.get();\n        if (instance == null) {\n            synchronized (holder) {\n                instance = holder.get();\n                if (instance == null) {\n                    instance = createExtension(name);\n                    holder.set(instance);\n                }\n            }\n        }\n        return (T) instance;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public T getExtension(String name, String key) {\n        if (name == null || name.length() == 0) throw new IllegalArgumentException(\"Extension name == null\");\n        if (\"true\".equals(name)) {\n            return getDefaultExtension();\n        }\n        String extKey = name + \"-\" + StringUtils.trimToEmpty(key);\n        Holder<Object> holder = cachedInstances.get(extKey);\n        if (holder == null) {\n            cachedInstances.putIfAbsent(extKey, new Holder<>());\n            holder = cachedInstances.get(extKey);\n        }\n        Object instance = holder.get();\n        if (instance == null) {\n            synchronized (holder) {\n                instance = holder.get();\n                if (instance == null) {\n                    instance = createExtension(name, key);\n                    holder.set(instance);\n                }\n            }\n        }\n        return (T) instance;\n    }\n\n    /**\n     * 返回缺省的扩展，如果没有设置则返回<code>null</code>\n     */\n    public T getDefaultExtension() {\n        getExtensionClasses();\n        if (null == cachedDefaultName || cachedDefaultName.length() == 0 || \"true\".equals(cachedDefaultName)) {\n            return null;\n        }\n        return getExtension(cachedDefaultName);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private T createExtension(String name) {\n        Class<?> clazz = getExtensionClasses().get(name);\n        if (clazz == null) {\n            throw new IllegalStateException(\"Extension instance(name: \" + name + \", class: \" + type\n                                            + \")  could not be instantiated: class could not be found\");\n        }\n        try {\n            T instance = (T) EXTENSION_INSTANCES.get(clazz);\n            if (instance == null) {\n                EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance());\n                instance = (T) EXTENSION_INSTANCES.get(clazz);\n            }\n            return instance;\n        } catch (Throwable t) {\n            throw new IllegalStateException(\"Extension instance(name: \" + name + \", class: \" + type\n                                            + \")  could not be instantiated: \" + t.getMessage(),\n                t);\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private T createExtension(String name, String key) {\n        Class<?> clazz = getExtensionClasses().get(name);\n        if (clazz == null) {\n            throw new IllegalStateException(\"Extension instance(name: \" + name + \", class: \" + type\n                                            + \")  could not be instantiated: class could not be found\");\n        }\n        try {\n            T instance = (T) EXTENSION_KEY_INSTANCE.get(name + \"-\" + key);\n            if (instance == null) {\n                EXTENSION_KEY_INSTANCE.putIfAbsent(name + \"-\" + key, clazz.newInstance());\n                instance = (T) EXTENSION_KEY_INSTANCE.get(name + \"-\" + key);\n            }\n            return instance;\n        } catch (Throwable t) {\n            throw new IllegalStateException(\"Extension instance(name: \" + name + \", class: \" + type\n                                            + \")  could not be instantiated: \" + t.getMessage(),\n                t);\n        }\n    }\n\n    private Map<String, Class<?>> getExtensionClasses() {\n        Map<String, Class<?>> classes = cachedClasses.get();\n        if (classes == null) {\n            synchronized (cachedClasses) {\n                classes = cachedClasses.get();\n                if (classes == null) {\n                    classes = loadExtensionClasses();\n                    cachedClasses.set(classes);\n                }\n            }\n        }\n\n        return classes;\n    }\n\n    private String getJarDirectoryPath() {\n        URL url = Thread.currentThread().getContextClassLoader().getResource(\"\");\n        String dirtyPath;\n        if (url != null) {\n            dirtyPath = url.toString();\n        } else {\n            File file = new File(\"\");\n            dirtyPath = file.getAbsolutePath();\n        }\n        String jarPath = dirtyPath.replaceAll(\"^.*file:/\", \"\"); // removes\n                                                                // file:/ and\n                                                                // everything\n                                                                // before it\n        jarPath = jarPath.replaceAll(\"jar!.*\", \"jar\"); // removes everything\n                                                       // after .jar, if .jar\n                                                       // exists in dirtyPath\n        jarPath = jarPath.replaceAll(\"%20\", \" \"); // necessary if path has\n                                                  // spaces within\n        if (!jarPath.endsWith(\".jar\")) { // this is needed if you plan to run\n                                         // the app using Spring Tools Suit play\n                                         // button.\n            jarPath = jarPath.replaceAll(\"/classes/.*\", \"/classes/\");\n        }\n        Path path = Paths.get(jarPath).getParent(); // Paths - from java 8\n        if (path != null) {\n            return path.toString();\n        }\n        return null;\n    }\n\n    private Map<String, Class<?>> loadExtensionClasses() {\n        final SPI defaultAnnotation = type.getAnnotation(SPI.class);\n        if (defaultAnnotation != null) {\n            String value = defaultAnnotation.value();\n            if ((value = value.trim()).length() > 0) {\n                String[] names = NAME_SEPARATOR.split(value);\n                if (names.length > 1) {\n                    throw new IllegalStateException(\"more than 1 default extension name on extension \" + type.getName()\n                                                    + \": \" + Arrays.toString(names));\n                }\n                if (names.length == 1) cachedDefaultName = names[0];\n            }\n        }\n\n        Map<String, Class<?>> extensionClasses = new HashMap<>();\n\n        // 1. plugin folder，customized extension classLoader （jar_dir/plugin）\n        String dir = File.separator + this.getJarDirectoryPath() + File.separator + \"plugin\";\n\n        File externalLibDir = new File(dir);\n        if (!externalLibDir.exists()) {\n            externalLibDir = new File(File.separator + this.getJarDirectoryPath() + File.separator + \"canal-adapter\"\n                                      + File.separator + \"plugin\");\n        }\n        logger.info(\"extension classpath dir: \" + externalLibDir.getAbsolutePath());\n        if (externalLibDir.exists()) {\n            File[] files = externalLibDir.listFiles((dir1, name) -> name.endsWith(\".jar\"));\n            if (files != null) {\n                for (File f : files) {\n                    URL url;\n                    try {\n                        url = f.toURI().toURL();\n                    } catch (MalformedURLException e) {\n                        throw new RuntimeException(\"load extension jar failed!\", e);\n                    }\n\n                    ClassLoader parent = Thread.currentThread().getContextClassLoader();\n                    URLClassLoader localClassLoader;\n                    if (classLoaderPolicy == null || \"\".equals(classLoaderPolicy)\n                        || DEFAULT_CLASSLOADER_POLICY.equalsIgnoreCase(classLoaderPolicy)) {\n                        localClassLoader = new URLClassExtensionLoader(new URL[] { url });\n                    } else {\n                        localClassLoader = new URLClassLoader(new URL[] { url }, parent);\n                    }\n\n                    loadFile(extensionClasses, CANAL_DIRECTORY, localClassLoader);\n                    loadFile(extensionClasses, SERVICES_DIRECTORY, localClassLoader);\n                }\n            }\n        }\n        // 只加载外部spi, 不加载classpath\n        // 2. load inner extension class with default classLoader\n        // ClassLoader classLoader = findClassLoader();\n        // loadFile(extensionClasses, CANAL_DIRECTORY, classLoader);\n        // loadFile(extensionClasses, SERVICES_DIRECTORY, classLoader);\n\n        return extensionClasses;\n    }\n\n    private void loadFile(Map<String, Class<?>> extensionClasses, String dir, ClassLoader classLoader) {\n        String fileName = dir + type.getName();\n        try {\n            Enumeration<URL> urls;\n            if (classLoader != null) {\n                urls = classLoader.getResources(fileName);\n            } else {\n                urls = ClassLoader.getSystemResources(fileName);\n            }\n            if (urls != null) {\n                while (urls.hasMoreElements()) {\n                    URL url = urls.nextElement();\n                    try {\n                        try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8))) {\n                            String line;\n                            while ((line = reader.readLine()) != null) {\n                                final int ci = line.indexOf('#');\n                                if (ci >= 0) line = line.substring(0, ci);\n                                line = line.trim();\n                                if (line.length() > 0) {\n                                    try {\n                                        String name = null;\n                                        int i = line.indexOf('=');\n                                        if (i > 0) {\n                                            name = line.substring(0, i).trim();\n                                            line = line.substring(i + 1).trim();\n                                        }\n                                        if (line.length() > 0) {\n                                            Class<?> clazz = classLoader.loadClass(line);\n                                            // Class<?> clazz =\n                                            // Class.forName(line, true,\n                                            // classLoader);\n                                            if (!type.isAssignableFrom(clazz)) {\n                                                throw new IllegalStateException(\n                                                        \"Error when load extension class(interface: \" + type\n                                                                + \", class line: \" + clazz.getName()\n                                                                + \"), class \" + clazz.getName()\n                                                                + \"is not subtype of interface.\");\n                                            } else {\n                                                try {\n                                                    clazz.getConstructor(type);\n                                                } catch (NoSuchMethodException e) {\n                                                    clazz.getConstructor();\n                                                    String[] names = NAME_SEPARATOR.split(name);\n                                                    if (names != null && names.length > 0) {\n                                                        for (String n : names) {\n                                                            if (!cachedNames.containsKey(clazz)) {\n                                                                cachedNames.put(clazz, n);\n                                                            }\n                                                            Class<?> c = extensionClasses.get(n);\n                                                            if (c == null) {\n                                                                extensionClasses.put(n, clazz);\n                                                            } else if (c != clazz) {\n                                                                cachedNames.remove(clazz);\n                                                                throw new IllegalStateException(\n                                                                        \"Duplicate extension \" + type.getName() + \" name \"\n                                                                                + n + \" on \"\n                                                                                + c.getName() + \" and \"\n                                                                                + clazz.getName());\n                                                            }\n                                                        }\n                                                    }\n                                                }\n                                            }\n                                        }\n                                    } catch (Throwable t) {\n                                        IllegalStateException e = new IllegalStateException(\n                                                \"Failed to load extension class(interface: \" + type + \", class line: \"\n                                                        + line + \") in \" + url\n                                                        + \", cause: \"\n                                                        + t.getMessage(),\n                                                t);\n                                        exceptions.put(line, e);\n                                    }\n                                }\n                            } // end of while read lines\n                        }\n                    } catch (Throwable t) {\n                        logger.error(\"Exception when load extension class(interface: \" + type + \", class file: \" + url\n                                     + \") in \" + url,\n                            t);\n                    }\n                } // end of while urls\n            }\n        } catch (Throwable t) {\n            logger.error(\n                \"Exception when load extension class(interface: \" + type + \", description file: \" + fileName + \").\",\n                t);\n        }\n    }\n\n    @SuppressWarnings(\"unused\")\n    private static ClassLoader findClassLoader() {\n        return ExtensionLoader.class.getClassLoader();\n    }\n\n    @Override\n    public String toString() {\n        return this.getClass().getName() + \"[\" + type.getName() + \"]\";\n    }\n\n    private static class Holder<T> {\n\n        private volatile T value;\n\n        private void set(T value) {\n            this.value = value;\n        }\n\n        private T get() {\n            return value;\n        }\n\n    }\n}\n"
  },
  {
    "path": "client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/support/FileName2KeyMapping.java",
    "content": "package com.alibaba.otter.canal.client.adapter.support;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * Created by @author zhuchao on @date 2021/11/11.\n */\npublic class FileName2KeyMapping {\n\n    private static Map<String, String> MAP = new ConcurrentHashMap<>();\n\n    public static void register(String type, String fileName, String key) {\n        MAP.putIfAbsent(join(type, fileName), key);\n    }\n\n    public static void unregister(String type, String fileName) {\n        MAP.remove(join(type, fileName));\n    }\n\n    public static String getKey(String type, String fileName) {\n        return MAP.get(join(type, fileName));\n    }\n\n    private static String join(String type, String fileName) {\n        return type + \"|\" + fileName;\n    }\n}\n"
  },
  {
    "path": "client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/support/JdbcTypeUtil.java",
    "content": "package com.alibaba.otter.canal.client.adapter.support;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.sql.Date;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.sql.Time;\nimport java.sql.Timestamp;\nimport java.sql.Types;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * 类型转换工具类\n *\n * @author rewerma 2018-8-19 下午06:14:23\n * @version 1.0.0\n */\npublic class JdbcTypeUtil {\n\n    private static Logger logger = LoggerFactory.getLogger(JdbcTypeUtil.class);\n\n    public static Object getRSData(ResultSet rs, String columnName, int jdbcType) throws SQLException {\n        if (jdbcType == Types.BIT || jdbcType == Types.BOOLEAN) {\n            return rs.getByte(columnName);\n        } else {\n            return rs.getObject(columnName);\n        }\n    }\n\n    public static Class<?> jdbcType2javaType(int jdbcType) {\n        switch (jdbcType) {\n            case Types.BIT:\n            case Types.BOOLEAN:\n                // return Boolean.class;\n            case Types.TINYINT:\n                return Byte.TYPE;\n            case Types.SMALLINT:\n                return Short.class;\n            case Types.INTEGER:\n                return Integer.class;\n            case Types.BIGINT:\n                return Long.class;\n            case Types.DECIMAL:\n            case Types.NUMERIC:\n                return BigDecimal.class;\n            case Types.REAL:\n                return Float.class;\n            case Types.FLOAT:\n            case Types.DOUBLE:\n                return Double.class;\n            case Types.CHAR:\n            case Types.VARCHAR:\n            case Types.LONGVARCHAR:\n                return String.class;\n            case Types.BINARY:\n            case Types.VARBINARY:\n            case Types.LONGVARBINARY:\n            case Types.BLOB:\n                return byte[].class;\n            case Types.DATE:\n                return java.sql.Date.class;\n            case Types.TIME:\n                return Time.class;\n            case Types.TIMESTAMP:\n                return Timestamp.class;\n            default:\n                return String.class;\n        }\n    }\n\n    private static boolean isText(String columnType) {\n        return \"LONGTEXT\".equalsIgnoreCase(columnType) || \"MEDIUMTEXT\".equalsIgnoreCase(columnType)\n               || \"TEXT\".equalsIgnoreCase(columnType) || \"TINYTEXT\".equalsIgnoreCase(columnType);\n    }\n\n    public static Object typeConvert(String tableName ,String columnName, String value, int sqlType, String mysqlType) {\n        if (value == null\n            || (value.equals(\"\") && !(isText(mysqlType) || sqlType == Types.CHAR || sqlType == Types.VARCHAR || sqlType == Types.LONGVARCHAR))) {\n            return null;\n        }\n\n        try {\n            Object res;\n            switch (sqlType) {\n                case Types.INTEGER:\n                    res = Integer.parseInt(value);\n                    break;\n                case Types.SMALLINT:\n                    res = Short.parseShort(value);\n                    break;\n                case Types.BIT:\n                case Types.TINYINT:\n                    res = Byte.parseByte(value);\n                    break;\n                case Types.BIGINT:\n                    if (mysqlType.startsWith(\"bigint\") && mysqlType.endsWith(\"unsigned\")) {\n                        res = new BigInteger(value);\n                    } else {\n                        res = Long.parseLong(value);\n                    }\n                    break;\n                // case Types.BIT:\n                case Types.BOOLEAN:\n                    res = !\"0\".equals(value);\n                    break;\n                case Types.DOUBLE:\n                case Types.FLOAT:\n                    res = Double.parseDouble(value);\n                    break;\n                case Types.REAL:\n                    res = Float.parseFloat(value);\n                    break;\n                case Types.DECIMAL:\n                case Types.NUMERIC:\n                    res = new BigDecimal(value);\n                    break;\n                case Types.BINARY:\n                case Types.VARBINARY:\n                case Types.LONGVARBINARY:\n                case Types.BLOB:\n                    res = value.getBytes(\"ISO-8859-1\");\n                    break;\n                case Types.DATE:\n                    if (!value.startsWith(\"0000-00-00\")) {\n                        java.util.Date date = Util.parseDate(value);\n                        if (date != null) {\n                            res = new Date(date.getTime());\n                        } else {\n                            res = null;\n                        }\n                    } else {\n                        res = null;\n                    }\n                    break;\n                case Types.TIME: {\n                    java.util.Date date = Util.parseDate(value);\n                    if (date != null) {\n                        res = new Time(date.getTime());\n                    } else {\n                        res = null;\n                    }\n                    break;\n                }\n                case Types.TIMESTAMP:\n                    if (!value.startsWith(\"0000-00-00\")) {\n                        java.util.Date date = Util.parseDate(value);\n                        if (date != null) {\n                            res = new Timestamp(date.getTime());\n                        } else {\n                            res = null;\n                        }\n                    } else {\n                        res = null;\n                    }\n                    break;\n                case Types.CLOB:\n                default:\n                    res = value;\n                    break;\n            }\n            return res;\n        } catch (Exception e) {\n            logger.error(\"table: {} column: {}, failed convert type {} to {}\", tableName, columnName, value, sqlType);\n            return value;\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/support/MappingConfigsLoader.java",
    "content": "package com.alibaba.otter.canal.client.adapter.support;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URL;\nimport java.nio.charset.StandardCharsets;\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class MappingConfigsLoader {\n\n    public static Map<String, String> loadConfigs(String name) {\n        Map<String, String> configContentMap = new HashMap<>();\n\n        // 先取本地文件，再取类路径\n        File configDir = new File(\"..\" + File.separator + Constant.CONF_DIR + File.separator + name);\n        if (!configDir.exists()) {\n            URL url = MappingConfigsLoader.class.getClassLoader().getResource(\"\");\n            if (url != null) {\n                configDir = new File(url.getPath() + name + File.separator);\n            }\n        }\n\n        File[] files = configDir.listFiles();\n        if (files != null) {\n            for (File file : files) {\n                String fileName = file.getName();\n                if (!fileName.endsWith(\".yml\")) {\n                    continue;\n                }\n                try (InputStream in = new FileInputStream(file)) {\n                    byte[] bytes = new byte[in.available()];\n                    in.read(bytes);\n                    String configContent = new String(bytes, StandardCharsets.UTF_8);\n                    configContentMap.put(fileName, configContent);\n                } catch (IOException e) {\n                    throw new RuntimeException(\"Read \" + name + \"mapping config: \" + fileName + \" error. \", e);\n                }\n            }\n        }\n\n        return configContentMap;\n    }\n\n    public static String loadConfig(String name) {\n        // 先取本地文件，再取类路径\n        File filePath = new File(\"..\" + File.separator + Constant.CONF_DIR + File.separator + name);\n        if (!filePath.exists()) {\n            URL url = MappingConfigsLoader.class.getClassLoader().getResource(\"\");\n            if (url != null) {\n                filePath = new File(url.getPath() + name);\n            }\n        }\n        if (filePath.exists()) {\n            String fileName = filePath.getName();\n            if (!(fileName.endsWith(\".yml\") || fileName.endsWith(\".yaml\"))) {\n                return null;\n            }\n            try (InputStream in = new FileInputStream(filePath)) {\n                byte[] bytes = new byte[in.available()];\n                in.read(bytes);\n                return new String(bytes, StandardCharsets.UTF_8);\n            } catch (IOException e) {\n                throw new RuntimeException(\"Read mapping config: \" + filePath.getAbsolutePath() + \" error. \", e);\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/support/MessageUtil.java",
    "content": "package com.alibaba.otter.canal.client.adapter.support;\n\nimport java.util.*;\n\nimport com.alibaba.otter.canal.connector.core.consumer.CommonMessage;\nimport com.alibaba.otter.canal.protocol.CanalEntry;\nimport com.alibaba.otter.canal.protocol.Message;\n\n/**\n * Message对象解析工具类\n *\n * @author rewerma 2018-8-19 下午06:14:23\n * @version 1.0.0\n */\npublic class MessageUtil {\n\n    public static List<Dml> parse4Dml(String destination, String groupId, Message message) {\n        if (message == null) {\n            return null;\n        }\n        List<CanalEntry.Entry> entries = message.getEntries();\n        List<Dml> dmls = new ArrayList<>(entries.size());\n        for (CanalEntry.Entry entry : entries) {\n            if (entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONBEGIN\n                || entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONEND) {\n                continue;\n            }\n\n            CanalEntry.RowChange rowChange;\n            try {\n                rowChange = CanalEntry.RowChange.parseFrom(entry.getStoreValue());\n            } catch (Exception e) {\n                throw new RuntimeException(\"ERROR ## parser of eromanga-event has an error , data:\" + entry.toString(),\n                    e);\n            }\n\n            CanalEntry.EventType eventType = rowChange.getEventType();\n\n            final Dml dml = new Dml();\n            dml.setIsDdl(rowChange.getIsDdl());\n            dml.setDestination(destination);\n            dml.setGroupId(groupId);\n            dml.setDatabase(entry.getHeader().getSchemaName());\n            dml.setTable(entry.getHeader().getTableName());\n            dml.setType(eventType.toString());\n            dml.setEs(entry.getHeader().getExecuteTime());\n            dml.setIsDdl(rowChange.getIsDdl());\n            dml.setTs(System.currentTimeMillis());\n            dml.setSql(rowChange.getSql());\n            dmls.add(dml);\n            List<Map<String, Object>> data = new ArrayList<>();\n            List<Map<String, Object>> old = new ArrayList<>();\n\n            if (!rowChange.getIsDdl()) {\n                Set<String> updateSet = new HashSet<>();\n                dml.setPkNames(new ArrayList<>());\n                int i = 0;\n                for (CanalEntry.RowData rowData : rowChange.getRowDatasList()) {\n                    if (eventType != CanalEntry.EventType.INSERT && eventType != CanalEntry.EventType.UPDATE\n                        && eventType != CanalEntry.EventType.DELETE) {\n                        continue;\n                    }\n\n                    Map<String, Object> row = new LinkedHashMap<>();\n                    List<CanalEntry.Column> columns;\n\n                    if (eventType == CanalEntry.EventType.DELETE) {\n                        columns = rowData.getBeforeColumnsList();\n                    } else {\n                        columns = rowData.getAfterColumnsList();\n                    }\n\n                    for (CanalEntry.Column column : columns) {\n                        if (i == 0) {\n                            if (column.getIsKey()) {\n                                dml.getPkNames().add(column.getName());\n                            }\n                        }\n                        if (column.getIsNull()) {\n                            row.put(column.getName(), null);\n                        } else {\n                            row.put(column.getName(),\n                                JdbcTypeUtil.typeConvert(dml.getTable(),\n                                    column.getName(),\n                                    column.getValue(),\n                                    column.getSqlType(),\n                                    column.getMysqlType()));\n                        }\n                        // 获取update为true的字段\n                        if (column.getUpdated()) {\n                            updateSet.add(column.getName());\n                        }\n                    }\n                    if (!row.isEmpty()) {\n                        data.add(row);\n                    }\n\n                    if (eventType == CanalEntry.EventType.UPDATE) {\n                        Map<String, Object> rowOld = new LinkedHashMap<>();\n                        for (CanalEntry.Column column : rowData.getBeforeColumnsList()) {\n                            if (updateSet.contains(column.getName())) {\n                                if (column.getIsNull()) {\n                                    rowOld.put(column.getName(), null);\n                                } else {\n                                    rowOld.put(column.getName(),\n                                        JdbcTypeUtil.typeConvert(dml.getTable(),\n                                            column.getName(),\n                                            column.getValue(),\n                                            column.getSqlType(),\n                                            column.getMysqlType()));\n                                }\n                            }\n                        }\n                        // update操作将记录修改前的值\n                        if (!rowOld.isEmpty()) {\n                            old.add(rowOld);\n                        }\n                    }\n\n                    i++;\n                }\n                if (!data.isEmpty()) {\n                    dml.setData(data);\n                }\n                if (!old.isEmpty()) {\n                    dml.setOld(old);\n                }\n            }\n        }\n\n        return dmls;\n    }\n\n    public static List<Dml> flatMessage2Dml(String destination, String groupId, List<CommonMessage> commonMessages) {\n        if (commonMessages == null) {\n            return new ArrayList<>();\n        }\n        List<Dml> dmls = new ArrayList<>(commonMessages.size());\n        for (CommonMessage commonMessage : commonMessages) {\n            Dml dml = flatMessage2Dml(destination, groupId, commonMessage);\n            if (dml != null) {\n                dmls.add(dml);\n            }\n        }\n\n        return dmls;\n    }\n\n    public static Dml flatMessage2Dml(String destination, String groupId, CommonMessage commonMessage) {\n        if (commonMessage == null) {\n            return null;\n        }\n        Dml dml = new Dml();\n        dml.setDestination(destination);\n        dml.setGroupId(groupId);\n        dml.setDatabase(commonMessage.getDatabase());\n        dml.setTable(commonMessage.getTable());\n        dml.setPkNames(commonMessage.getPkNames());\n        dml.setIsDdl(commonMessage.getIsDdl());\n        dml.setType(commonMessage.getType());\n        dml.setTs(commonMessage.getTs());\n        dml.setEs(commonMessage.getEs());\n        dml.setSql(commonMessage.getSql());\n        // if (flatMessage.getSqlType() == null || flatMessage.getMysqlType() == null) {\n        // throw new RuntimeException(\"SqlType or mysqlType is null\");\n        // }\n        List<Map<String, Object>> data = commonMessage.getData();\n        if (data != null) {\n            dml.setData(data);\n        }\n        List<Map<String, Object>> old = commonMessage.getOld();\n        if (old != null) {\n            dml.setOld(old);\n        }\n        return dml;\n    }\n\n    private static List<Map<String, Object>> changeRows(String table, List<Map<String, String>> rows,\n                                                        Map<String, Integer> sqlTypes, Map<String, String> mysqlTypes) {\n        List<Map<String, Object>> result = new ArrayList<>();\n        for (Map<String, String> row : rows) {\n            Map<String, Object> resultRow = new LinkedHashMap<>();\n            for (Map.Entry<String, String> entry : row.entrySet()) {\n                String columnName = entry.getKey();\n                String columnValue = entry.getValue();\n\n                Integer sqlType = sqlTypes.get(columnName);\n                if (sqlType == null) {\n                    continue;\n                }\n\n                String mysqlType = mysqlTypes.get(columnName);\n                if (mysqlType == null) {\n                    continue;\n                }\n\n                Object finalValue = JdbcTypeUtil.typeConvert(table, columnName, columnValue, sqlType, mysqlType);\n                resultRow.put(columnName, finalValue);\n            }\n            result.add(resultRow);\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/support/OuterAdapterConfig.java",
    "content": "package com.alibaba.otter.canal.client.adapter.support;\n\nimport java.util.Map;\n\n/**\n * 外部适配器配置信息类\n *\n * @author rewerma 2018-8-18 下午10:15:12\n * @version 1.0.0\n */\npublic class OuterAdapterConfig {\n\n    private String              name;       // 适配器名称, 如: logger, hbase, es\n\n    private String              key;        // 适配器唯一键\n\n    private String              hosts;      // 适配器内部的地址, 比如对应es该参数可以填写es的server地址\n\n    private String              zkHosts;    // 适配器内部的ZK地址, 比如对应HBase该参数可以填写HBase对应的ZK地址\n\n    private Map<String, String> properties; // 其余参数, 可填写适配器中的所需的配置信息\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getKey() {\n        return key;\n    }\n\n    public void setKey(String key) {\n        this.key = key;\n    }\n\n    public String getHosts() {\n        return hosts;\n    }\n\n    public void setHosts(String hosts) {\n        this.hosts = hosts;\n    }\n\n    public Map<String, String> getProperties() {\n        return properties;\n    }\n\n    public void setProperties(Map<String, String> properties) {\n        this.properties = properties;\n    }\n\n    public String getZkHosts() {\n        return zkHosts;\n    }\n\n    public void setZkHosts(String zkHosts) {\n        this.zkHosts = zkHosts;\n    }\n}\n"
  },
  {
    "path": "client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/support/Result.java",
    "content": "package com.alibaba.otter.canal.client.adapter.support;\n\nimport java.io.Serializable;\nimport java.util.Date;\n\n/**\n * 用于rest的结果返回对象\n *\n * @author rewerma @ 2018-10-20\n * @version 1.0.0\n */\npublic class Result implements Serializable {\n\n    private static final long serialVersionUID = -3276409502352405716L;\n    private Integer           code             = 20000;\n    private Object            data;\n    private String            message;\n    private Date              sysTime;\n\n    public static Result createSuccess(String message) {\n        Result result = new Result();\n        result.setMessage(message);\n        return result;\n    }\n\n    public Integer getCode() {\n        return code;\n    }\n\n    public void setCode(Integer code) {\n        this.code = code;\n    }\n\n    public Object getData() {\n        return data;\n    }\n\n    public void setData(Object data) {\n        this.data = data;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n\n    public Date getSysTime() {\n        return sysTime;\n    }\n\n    public void setSysTime(Date sysTime) {\n        this.sysTime = sysTime;\n    }\n}\n"
  },
  {
    "path": "client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/support/SPI.java",
    "content": "package com.alibaba.otter.canal.client.adapter.support;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * SPI装载器注解\n *\n * @author rewerma @ 2018-10-20\n * @version 1.0.0\n */\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE })\npublic @interface SPI {\n\n    // Default SPI name\n    String value() default \"\";\n}\n"
  },
  {
    "path": "client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/support/URLClassExtensionLoader.java",
    "content": "package com.alibaba.otter.canal.client.adapter.support;\n\nimport java.io.IOException;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.util.Enumeration;\nimport java.util.NoSuchElementException;\n\npublic class URLClassExtensionLoader extends URLClassLoader {\n\n    public URLClassExtensionLoader(URL[] urls){\n        super(urls);\n    }\n\n    @Override\n    public Class<?> loadClass(String name) throws ClassNotFoundException {\n        Class<?> c = findLoadedClass(name);\n        if (c != null) {\n            return c;\n        }\n\n        if (name.startsWith(\"java.\") || name.startsWith(\"org.slf4j.\") || name.startsWith(\"org.apache.logging\")\n            || name.startsWith(\"org.apache.zookeeper.\") || name.startsWith(\"org.I0Itec.zkclient.\")\n            || name.startsWith(\"org.apache.commons.logging.\")\n            || name.startsWith(\"com.alibaba.druid\")\n            ) {\n            // || name.startsWith(\"org.apache.hadoop.\"))\n            // {\n            c = super.loadClass(name);\n        }\n        if (c != null) return c;\n\n        try {\n            // 先加载jar内的class，可避免jar冲突\n            c = findClass(name);\n        } catch (ClassNotFoundException e) {\n            c = null;\n        }\n        if (c != null) {\n            return c;\n        }\n\n        return super.loadClass(name);\n    }\n\n    @Override\n    public Enumeration<URL> getResources(String name) throws IOException {\n        @SuppressWarnings(\"unchecked\")\n        Enumeration<URL>[] tmp = (Enumeration<URL>[]) new Enumeration<?>[2];\n\n        tmp[0] = findResources(name); // local class\n        // path first\n        // tmp[1] = super.getResources(name);\n\n        return new CompoundEnumeration<>(tmp);\n    }\n\n    private static class CompoundEnumeration<E> implements Enumeration<E> {\n\n        private Enumeration<E>[] enums;\n        private int              index = 0;\n\n        public CompoundEnumeration(Enumeration<E>[] enums){\n            this.enums = enums;\n        }\n\n        private boolean next() {\n            while (this.index < this.enums.length) {\n                if (this.enums[this.index] != null && this.enums[this.index].hasMoreElements()) {\n                    return true;\n                }\n\n                ++this.index;\n            }\n\n            return false;\n        }\n\n        public boolean hasMoreElements() {\n            return this.next();\n        }\n\n        public E nextElement() {\n            if (!this.next()) {\n                throw new NoSuchElementException();\n            } else {\n                return this.enums[this.index].nextElement();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/support/Util.java",
    "content": "package com.alibaba.otter.canal.client.adapter.support;\n\nimport java.io.File;\nimport java.net.URL;\nimport java.sql.*;\nimport java.time.*;\nimport java.time.format.DateTimeFormatter;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.TimeZone;\nimport java.util.concurrent.SynchronousQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\n\nimport javax.sql.DataSource;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport org.apache.commons.lang.StringUtils;\nimport org.joda.time.DateTime;\nimport org.joda.time.DateTimeZone;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.google.common.cache.CacheBuilder;\nimport com.google.common.cache.CacheLoader;\nimport com.google.common.cache.LoadingCache;\n\npublic class Util {\n\n    private static final Logger logger                = LoggerFactory.getLogger(Util.class);\n\n    public static final String  AUTO_GENERATED_PREFIX = \"AUTO_GENERATED_\";\n\n    /**\n     * 通过DS执行sql\n     */\n    public static Object sqlRS(DataSource ds, String sql, Function<ResultSet, Object> fun) {\n        try (Connection conn = ds.getConnection();\n                Statement stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)) {\n\n            DruidDataSource druidDataSource = (DruidDataSource) ds;\n            if (\"postgresql\".equals(druidDataSource.getDbType())) {\n                conn.setAutoCommit(false);\n                stmt.setFetchSize(1000);\n            } else if (\"sqlserver\".equals(druidDataSource.getDbType())) {\n                stmt.setFetchSize(100);\n            } else {\n                stmt.setFetchSize(Integer.MIN_VALUE);\n            }\n\n            try (ResultSet rs = stmt.executeQuery(sql)) {\n                return fun.apply(rs);\n            }\n        } catch (Exception e) {\n            logger.error(\"sqlRs has error, sql: {} \", sql);\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static Object sqlRS(DataSource ds, String sql, List<Object> values, Function<ResultSet, Object> fun) {\n        try (Connection conn = ds.getConnection()) {\n            try (PreparedStatement pstmt = conn\n                .prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)) {\n                DruidDataSource druidDataSource = (DruidDataSource) ds;\n                if (\"postgresql\".equals(druidDataSource.getDbType())) {\n                    conn.setAutoCommit(false);\n                    pstmt.setFetchSize(1000);\n                } else {\n                    pstmt.setFetchSize(Integer.MIN_VALUE);\n                }\n                if (values != null) {\n                    for (int i = 0; i < values.size(); i++) {\n                        pstmt.setObject(i + 1, values.get(i));\n                    }\n                }\n                try (ResultSet rs = pstmt.executeQuery()) {\n                    return fun.apply(rs);\n                }\n            }\n        } catch (Exception e) {\n            logger.error(\"sqlRs has error, sql: {} \", sql);\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * sql执行获取resultSet\n     *\n     * @param conn sql connection\n     * @param sql sql\n     * @param consumer 回调方法\n     */\n    public static void sqlRS(Connection conn, String sql, Consumer<ResultSet> consumer) {\n        try (Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql)) {\n            consumer.accept(rs);\n        } catch (SQLException e) {\n            logger.error(e.getMessage(), e);\n        }\n    }\n\n    public static File getConfDirPath() {\n        return getConfDirPath(\"\");\n    }\n\n    public static File getConfDirPath(String subConf) {\n        URL url = Util.class.getClassLoader().getResource(\"\");\n        String path;\n        if (url != null) {\n            path = url.getPath();\n        } else {\n            path = new File(\"\").getAbsolutePath();\n        }\n        File file = null;\n        if (path != null) {\n            file = new File(\n                path + \"..\" + File.separator + Constant.CONF_DIR + File.separator + StringUtils.trimToEmpty(subConf));\n            if (!file.exists()) {\n                file = new File(path + StringUtils.trimToEmpty(subConf));\n            }\n        }\n        if (file == null || !file.exists()) {\n            throw new RuntimeException(\"Config dir not found.\");\n        }\n\n        return file;\n    }\n\n    public static String cleanColumn(String column) {\n        if (column == null) {\n            return null;\n        }\n        if (column.contains(\"`\")) {\n            column = column.replaceAll(\"`\", \"\");\n        }\n\n        if (column.contains(\"'\")) {\n            column = column.replaceAll(\"'\", \"\");\n        }\n\n        if (column.contains(\"\\\"\")) {\n            column = column.replaceAll(\"\\\"\", \"\");\n        }\n\n        return column;\n    }\n\n    public static ThreadPoolExecutor newFixedThreadPool(int nThreads, long keepAliveTime) {\n        return new ThreadPoolExecutor(nThreads,\n            nThreads,\n            keepAliveTime,\n            TimeUnit.MILLISECONDS,\n            new SynchronousQueue<>(),\n            (r, exe) -> {\n                if (!exe.isShutdown()) {\n                    try {\n                        exe.getQueue().put(r);\n                    } catch (InterruptedException e) {\n                        // ignore\n                    }\n                }\n            });\n    }\n\n    public static ThreadPoolExecutor newSingleThreadExecutor(long keepAliveTime) {\n        return new ThreadPoolExecutor(1,\n            1,\n            keepAliveTime,\n            TimeUnit.MILLISECONDS,\n            new SynchronousQueue<>(),\n            (r, exe) -> {\n                if (!exe.isShutdown()) {\n                    try {\n                        exe.getQueue().put(r);\n                    } catch (InterruptedException e) {\n                        // ignore\n                    }\n                }\n            });\n    }\n\n    public static ThreadPoolExecutor newFixedDaemonThreadPool(int nThreads, long keepAliveTime) {\n        return new ThreadPoolExecutor(nThreads,\n            nThreads,\n            keepAliveTime,\n            TimeUnit.MILLISECONDS,\n            new SynchronousQueue<>(),\n            DaemonThreadFactory.daemonThreadFactory,\n            (r, exe) -> {\n                if (!exe.isShutdown()) {\n                    try {\n                        exe.getQueue().put(r);\n                    } catch (InterruptedException e) {\n                        // ignore\n                    }\n                }\n            });\n    }\n\n    public static ThreadPoolExecutor newSingleDaemonThreadExecutor(long keepAliveTime) {\n        return new ThreadPoolExecutor(1,\n            1,\n            keepAliveTime,\n            TimeUnit.MILLISECONDS,\n            new SynchronousQueue<>(),\n            DaemonThreadFactory.daemonThreadFactory,\n            (r, exe) -> {\n                if (!exe.isShutdown()) {\n                    try {\n                        exe.getQueue().put(r);\n                    } catch (InterruptedException e) {\n                        // ignore\n                    }\n                }\n            });\n    }\n\n    public final static String  timeZone;    // 当前时区\n    private static DateTimeZone dateTimeZone;\n\n    static {\n        TimeZone localTimeZone = TimeZone.getDefault();\n        int rawOffset = localTimeZone.getRawOffset();\n        String symbol = \"+\";\n        if (rawOffset < 0) {\n            symbol = \"-\";\n        }\n        rawOffset = Math.abs(rawOffset);\n        int offsetHour = rawOffset / 3600000;\n        int offsetMinute = rawOffset % 3600000 / 60000;\n        String hour = String.format(\"%1$02d\", offsetHour);\n        String minute = String.format(\"%1$02d\", offsetMinute);\n        timeZone = symbol + hour + \":\" + minute;\n        dateTimeZone = DateTimeZone.forID(timeZone);\n        TimeZone.setDefault(TimeZone.getTimeZone(\"GMT\" + timeZone));\n    }\n\n    /**\n     * 通用日期时间字符解析\n     *\n     * @param datetimeStr 日期时间字符串\n     * @return Date\n     */\n    public static Date parseDate(String datetimeStr) {\n        if (StringUtils.isEmpty(datetimeStr)) {\n            return null;\n        }\n        datetimeStr = datetimeStr.trim();\n        if (datetimeStr.contains(\"-\")) {\n            if (datetimeStr.contains(\":\")) {\n                datetimeStr = datetimeStr.replace(\" \", \"T\");\n            }\n        } else if (datetimeStr.contains(\":\")) {\n            datetimeStr = \"T\" + datetimeStr;\n        }\n\n        DateTime dateTime = new DateTime(datetimeStr, dateTimeZone);\n\n        return dateTime.toDate();\n    }\n\n    private static LoadingCache<String, DateTimeFormatter> dateFormatterCache = CacheBuilder.newBuilder()\n        .build(new CacheLoader<String, DateTimeFormatter>() {\n\n            @Override\n            public DateTimeFormatter load(String key) {\n                return DateTimeFormatter.ofPattern(key);\n            }\n        });\n\n    public static Date parseDate2(String datetimeStr) {\n        if (StringUtils.isEmpty(datetimeStr)) {\n            return null;\n        }\n        try {\n            datetimeStr = datetimeStr.trim();\n            int len = datetimeStr.length();\n            if (datetimeStr.contains(\"-\") && datetimeStr.contains(\":\") && datetimeStr.contains(\".\")) {\n                // 包含日期+时间+毫秒\n                // 取毫秒位数\n                int msLen = len - datetimeStr.indexOf(\".\") - 1;\n                StringBuilder ms = new StringBuilder();\n                for (int i = 0; i < msLen; i++) {\n                    ms.append(\"S\");\n                }\n                String formatter = \"yyyy-MM-dd HH:mm:ss.\" + ms;\n\n                DateTimeFormatter dateTimeFormatter = dateFormatterCache.get(formatter);\n                LocalDateTime dateTime = LocalDateTime.parse(datetimeStr, dateTimeFormatter);\n                return Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant());\n            } else if (datetimeStr.contains(\"-\") && datetimeStr.contains(\":\")) {\n                // 包含日期+时间\n                // 判断包含时间位数\n                int i = datetimeStr.indexOf(\":\");\n                i = datetimeStr.indexOf(\":\", i + 1);\n                String formatter;\n                if (i > -1) {\n                    formatter = \"yyyy-MM-dd HH:mm:ss\";\n                } else {\n                    formatter = \"yyyy-MM-dd HH:mm\";\n                }\n\n                DateTimeFormatter dateTimeFormatter = dateFormatterCache.get(formatter);\n                LocalDateTime dateTime = LocalDateTime.parse(datetimeStr, dateTimeFormatter);\n                return Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant());\n            } else if (datetimeStr.contains(\"-\")) {\n                // 只包含日期\n                String formatter = \"yyyy-MM-dd\";\n                DateTimeFormatter dateTimeFormatter = dateFormatterCache.get(formatter);\n                LocalDate localDate = LocalDate.parse(datetimeStr, dateTimeFormatter);\n                return Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());\n            } else if (datetimeStr.contains(\":\")) {\n                // 只包含时间\n                String formatter;\n                if (datetimeStr.contains(\".\")) {\n                    // 包含毫秒\n                    int msLen = len - datetimeStr.indexOf(\".\") - 1;\n                    StringBuilder ms = new StringBuilder();\n                    for (int i = 0; i < msLen; i++) {\n                        ms.append(\"S\");\n                    }\n                    formatter = \"HH:mm:ss.\" + ms;\n                } else {\n                    // 判断包含时间位数\n                    int i = datetimeStr.indexOf(\":\");\n                    i = datetimeStr.indexOf(\":\", i + 1);\n                    if (i > -1) {\n                        formatter = \"HH:mm:ss\";\n                    } else {\n                        formatter = \"HH:mm\";\n                    }\n                }\n                DateTimeFormatter dateTimeFormatter = dateFormatterCache.get(formatter);\n                LocalTime localTime = LocalTime.parse(datetimeStr, dateTimeFormatter);\n                LocalDate localDate = LocalDate.of(1970, Month.JANUARY, 1);\n                LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);\n                return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());\n            }\n        } catch (Throwable e) {\n            logger.error(e.getMessage(), e);\n        }\n\n        return null;\n    }\n\n    /**\n     * Check if the time string has millisecond or microsecond units\n     * \n     * @param timeStr time string\n     * @return boolean\n     */\n    public static boolean isAccuracyOverSecond(String timeStr) {\n        if (StringUtils.isEmpty(timeStr)) {\n            return false;\n        }\n        String[] times = StringUtils.split(timeStr, \".\");\n        return times.length > 1 && !times[times.length - 1].isEmpty();\n    }\n\n    /**\n     * Check if the datetime string has microsecond or nanosecond units\n     * \n     * @param datetimeStr datetime string\n     * @return boolean\n     */\n    public static boolean isAccuracyOverMillisecond(String datetimeStr) {\n        if (StringUtils.isEmpty(datetimeStr)) {\n            return false;\n        }\n        String[] times = StringUtils.split(datetimeStr, \".\");\n        return times.length > 1 && times[times.length - 1].length() > 3;\n    }\n\n    /**\n     * MySQL has fractional seconds support for TIME, DATETIME, and TIMESTAMP\n     * values, with up to microseconds (6 digits) precision. ISO-8601 standard\n     * format is with up to nanoseconds (9 digits) precision, which is sufficient\n     * for storing MySQL time-related data.\n     * \n     * @param datetimeStr datetime string\n     * @return LocalDateTime\n     */\n    public static LocalDateTime parseISOLocalDateTime(String datetimeStr) {\n        if (StringUtils.isEmpty(datetimeStr)) {\n            return null;\n        }\n        datetimeStr = datetimeStr.trim();\n        try {\n            // Replace SPACE in middle with `T` to comply with ISO-8601 standard format\n            return LocalDateTime.parse(datetimeStr.replace(\" \", \"T\"));\n        } catch (Exception e) {\n            logger.error(\"Convert datetime string to ISOLocalDateTime fail:{}\", datetimeStr, e);\n        }\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/support/YamlUtils.java",
    "content": "package com.alibaba.otter.canal.client.adapter.support;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.MapConfigurationPropertySource;\nimport org.springframework.boot.env.YamlPropertySourceLoader;\nimport org.springframework.boot.origin.OriginTrackedValue;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.io.ByteArrayResource;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.PropertyPlaceholderHelper;\n\npublic class YamlUtils {\n\n    public static <T> T resourceYmlToObj(String resource, String prefix, Class<T> clazz) {\n        if (!StringUtils.startsWithIgnoreCase(resource, \"classpath:\")) {\n            resource = \"classpath:\" + resource;\n        }\n        ClassPathResource classPathResource = new ClassPathResource(resource);\n\n        String content;\n        try (InputStream inputStream = classPathResource.getInputStream()) {\n\n            ByteArrayOutputStream result = new ByteArrayOutputStream();\n            byte[] buffer = new byte[1024];\n            int length;\n            while ((length = inputStream.read(buffer)) != -1) {\n                result.write(buffer, 0, length);\n            }\n            content = result.toString(\"UTF-8\");\n        } catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n        return ymlToObj(prefix, content, clazz);\n    }\n\n    public static <T> T ymlToObj(String content, Class<T> clazz) {\n        return ymlToObj(\"\", content, clazz, null, null);\n    }\n\n    public static <T> T ymlToObj(String prefix, String content, Class<T> clazz) {\n        return ymlToObj(prefix, content, clazz, null, null);\n    }\n\n    public static <T> T ymlToObj(String prefix, String content, Class<T> clazz, String charset) {\n        return ymlToObj(prefix, content, clazz, charset, null);\n    }\n\n    public static <T> T ymlToObj(String prefix, String content, Class<T> clazz, String charset,\n                                 Properties baseProperties) {\n        try {\n            prefix = StringUtils.trimToEmpty(prefix);\n            byte[] contentBytes;\n            if (charset == null) {\n                contentBytes = content.getBytes(StandardCharsets.UTF_8);\n            } else {\n                contentBytes = content.getBytes(charset);\n            }\n            YamlPropertySourceLoader propertySourceLoader = new YamlPropertySourceLoader();\n            Resource configResource = new ByteArrayResource(contentBytes);\n            List<PropertySource<?>> propertySources = propertySourceLoader.load(\"manualBindConfig\", configResource);\n\n            if (propertySources == null || propertySources.isEmpty()) {\n                return null;\n            }\n\n            PropertySource<?> propertySource = propertySources.get(0);\n\n            Properties properties = new Properties();\n            if (baseProperties != null) {\n                properties.putAll(baseProperties);\n            }\n\n            properties.putAll((Map<?, ?>) propertySource.getSource());\n\n            for (Map.Entry<Object, Object> entry : properties.entrySet()) {\n                Object value = entry.getValue();\n                if (value instanceof OriginTrackedValue) {\n                    entry.setValue(((OriginTrackedValue) value).getValue());\n                }\n            }\n\n            ConfigurationPropertySource sources = new MapConfigurationPropertySource(properties);\n            PropertyPlaceholderHelper propertyPlaceholderHelper = new PropertyPlaceholderHelper(\"${\", \"}\");\n            Binder binder = new Binder(Arrays.asList(sources), value -> {\n                if (value instanceof String) {\n                    return propertyPlaceholderHelper.replacePlaceholders((String) value, baseProperties);\n                }\n                return value;\n            });\n            return binder.bind(prefix, Bindable.of(clazz)).get();\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/common/src/test/java/com/alibaba/otter/canal/client/adapter/support/JdbcTypeUtilTest.java",
    "content": "package com.alibaba.otter.canal.client.adapter.support;\n\nimport org.junit.Assert;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.junit.rules.ExpectedException;\nimport org.junit.rules.Timeout;\nimport org.junit.runner.RunWith;\nimport org.powermock.modules.junit4.PowerMockRunner;\n\n@RunWith(PowerMockRunner.class)\npublic class JdbcTypeUtilTest {\n\n  @Rule public final ExpectedException thrown = ExpectedException.none();\n\n  @Rule public final Timeout globalTimeout = new Timeout(10000);\n\n  /* testedClasses: JdbcTypeUtil */\n  // Test written by Diffblue Cover.\n  @Test\n  public void typeConvertInputNotNullNotNullNotNullNegativeNotNullOutput3() {\n\n    // Arrange\n    final String tableName = \"foo\";\n    final String columnName = \"foo\";\n    final String value = \"foo\";\n    final int sqlType = -4;\n    final String mysqlType = \"foo\";\n\n    // Act\n    final Object actual =\n        JdbcTypeUtil.typeConvert(tableName, columnName, value, sqlType, mysqlType);\n\n    // Assert result\n    Assert.assertArrayEquals(new byte[] {(byte)102, (byte)111, (byte)111}, ((byte[])actual));\n  }\n\n  // Test written by Diffblue Cover.\n  @Test\n  public void typeConvertInputNotNullNotNullNotNullNegativeNotNullOutputPositive() {\n\n    // Arrange\n    final String tableName = \"foo\";\n    final String columnName = \"foo\";\n    final String value = \"1234\";\n    final int sqlType = -5;\n    final String mysqlType = \"foo\";\n\n    // Act\n    final Object actual =\n        JdbcTypeUtil.typeConvert(tableName, columnName, value, sqlType, mysqlType);\n\n    // Assert result\n    Assert.assertEquals(1234L, actual);\n  }\n\n  // Test written by Diffblue Cover.\n  @Test\n  public void typeConvertInputNotNullNotNullNotNullNegativeNotNullOutputPositive2() {\n\n    // Arrange\n    final String tableName = \"?????????\";\n    final String columnName = \"?\";\n    final String value = \"2\";\n    final int sqlType = -5;\n    final String mysqlType = \"bigint\";\n\n    // Act\n    final Object actual =\n        JdbcTypeUtil.typeConvert(tableName, columnName, value, sqlType, mysqlType);\n\n    // Assert result\n    Assert.assertEquals(2L, actual);\n  }\n\n  // Test written by Diffblue Cover.\n  @Test\n  public void typeConvertInputNotNullNotNullNotNullPositiveNotNullOutputFalse() {\n\n    // Arrange\n    final String tableName = \"?????????\";\n    final String columnName = \"?\";\n    final String value = \"0\";\n    final int sqlType = 16;\n    final String mysqlType = \"bigint\\u046bunsigned\";\n\n    // Act\n    final Object actual =\n        JdbcTypeUtil.typeConvert(tableName, columnName, value, sqlType, mysqlType);\n\n    // Assert result\n    Assert.assertFalse((boolean)actual);\n  }\n\n  // Test written by Diffblue Cover.\n  @Test\n  public void typeConvertInputNotNullNotNullNotNullPositiveNotNullOutputNotNull() {\n\n    // Arrange\n    final String tableName = \"1\";\n    final String columnName = \"Bar\";\n    final String value = \"1\";\n    final int sqlType = 12;\n    final String mysqlType = \"2\";\n\n    // Act\n    final Object actual =\n        JdbcTypeUtil.typeConvert(tableName, columnName, value, sqlType, mysqlType);\n\n    // Assert result\n    Assert.assertEquals(\"1\", actual);\n  }\n\n  // Test written by Diffblue Cover.\n  @Test\n  public void typeConvertInputNotNullNotNullNotNullPositiveNotNullOutputPositive() {\n\n    // Arrange\n    final String tableName = \"foo\";\n    final String columnName = \"foo\";\n    final String value = \"3\";\n    final int sqlType = 4;\n    final String mysqlType = \"foo\";\n\n    // Act\n    final Object actual =\n        JdbcTypeUtil.typeConvert(tableName, columnName, value, sqlType, mysqlType);\n\n    // Assert result\n    Assert.assertEquals(3, actual);\n  }\n\n  // Test written by Diffblue Cover.\n  @Test\n  public void typeConvertInputNotNullNotNullNotNullPositiveNotNullOutputTrue() {\n\n    // Arrange\n    final String tableName = \"?????????\";\n    final String columnName = \"?\";\n    final String value = \"5\";\n    final int sqlType = 16;\n    final String mysqlType = \"bigintsunsigned\";\n\n    // Act\n    final Object actual =\n        JdbcTypeUtil.typeConvert(tableName, columnName, value, sqlType, mysqlType);\n\n    // Assert result\n    Assert.assertTrue((boolean)actual);\n  }\n\n  // Test written by Diffblue Cover.\n  @Test\n  public void typeConvertInputNotNullNotNullNotNullPositiveNotNullOutputZero2() {\n\n    // Arrange\n    final String tableName = \"?????????\";\n    final String columnName = \"?\";\n    final String value = \"0\";\n    final int sqlType = 7;\n    final String mysqlType = \"bigint\\u046bunsigned\";\n\n    // Act\n    final Object actual =\n        JdbcTypeUtil.typeConvert(tableName, columnName, value, sqlType, mysqlType);\n\n    // Assert result\n    Assert.assertEquals(0.0f, (float)actual, 0.0f);\n  }\n\n  // Test written by Diffblue Cover.\n  @Test\n  public void typeConvertInputNotNullNotNullNotNullPositiveNotNullOutputZero3() {\n\n    // Arrange\n    final String tableName = \"?????????\";\n    final String columnName = \"?\";\n    final String value = \"0\";\n    final int sqlType = 5;\n    final String mysqlType = \"bigintiunsigned\";\n\n    // Act\n    final Object actual =\n        JdbcTypeUtil.typeConvert(tableName, columnName, value, sqlType, mysqlType);\n\n    // Assert result\n    Assert.assertEquals((short)0, actual);\n  }\n}\n"
  },
  {
    "path": "client-adapter/common/src/test/java/com/alibaba/otter/canal/client/adapter/support/UtilTest.java",
    "content": "package com.alibaba.otter.canal.client.adapter.support;\n\nimport static org.mockito.AdditionalMatchers.or;\nimport static org.mockito.Matchers.isA;\nimport static org.mockito.Matchers.isNull;\n\nimport com.diffblue.deeptestutils.mock.DTUMemberMatcher;\nimport org.apache.commons.lang.StringUtils;\nimport org.junit.Assert;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.junit.rules.ExpectedException;\nimport org.junit.rules.Timeout;\nimport org.junit.runner.RunWith;\nimport org.powermock.api.mockito.PowerMockito;\nimport org.powermock.core.classloader.annotations.PowerMockIgnore;\nimport org.powermock.core.classloader.annotations.PrepareForTest;\nimport org.powermock.modules.junit4.PowerMockRunner;\n\nimport java.lang.reflect.Method;\nimport java.util.Date;\n\n@RunWith(PowerMockRunner.class)\n@PowerMockIgnore({\"javax.management.*\"})\npublic class UtilTest {\n\n  @Rule public final ExpectedException thrown = ExpectedException.none();\n\n  @Rule public final Timeout globalTimeout = new Timeout(10000);\n\n  /* testedClasses: Util */\n  // Test written by Diffblue Cover.\n  @Test\n  public void cleanColumnInputNotNullOutputNotNull() {\n\n    // Arrange\n    final String column = \"1234\";\n\n    // Act\n    final String actual = Util.cleanColumn(column);\n\n    // Assert result\n    Assert.assertEquals(\"1234\", actual);\n  }\n\n  // Test written by Diffblue Cover.\n  @Test\n  public void cleanColumnInputNullOutputNull() {\n\n    // Arrange\n    final String column = null;\n\n    // Act\n    final String actual = Util.cleanColumn(column);\n\n    // Assert result\n    Assert.assertNull(actual);\n  }\n\n  // Test written by Diffblue Cover.\n  @PrepareForTest(StringUtils.class)\n  @Test\n  public void parseDate2InputNotNullOutputNull() throws Exception {\n\n    // Setup mocks\n    PowerMockito.mockStatic(StringUtils.class);\n\n    // Arrange\n    final String datetimeStr = \"1a 2b 3c\";\n    final Method isEmptyMethod =\n        DTUMemberMatcher.method(StringUtils.class, \"isEmpty\", String.class);\n    PowerMockito.doReturn(true)\n        .when(StringUtils.class, isEmptyMethod)\n        .withArguments(or(isA(String.class), isNull(String.class)));\n\n    // Act\n    final Date actual = Util.parseDate2(datetimeStr);\n\n    // Assert result\n    Assert.assertNull(actual);\n  }\n\n  // Test written by Diffblue Cover.\n  @PrepareForTest(StringUtils.class)\n  @Test\n  public void parseDate2InputNotNullOutputNull2() throws Exception {\n\n    // Setup mocks\n    PowerMockito.mockStatic(StringUtils.class);\n\n    // Arrange\n    final String datetimeStr = \"1a 2b 3c\";\n    final Method isEmptyMethod =\n        DTUMemberMatcher.method(StringUtils.class, \"isEmpty\", String.class);\n    PowerMockito.doReturn(false)\n        .when(StringUtils.class, isEmptyMethod)\n        .withArguments(or(isA(String.class), isNull(String.class)));\n\n    // Act\n    final Date actual = Util.parseDate2(datetimeStr);\n\n    // Assert result\n    Assert.assertNull(actual);\n  }\n\n  // Test written by Diffblue Cover.\n  @PrepareForTest(StringUtils.class)\n  @Test\n  public void parseDateInputNotNullOutputNull() throws Exception {\n\n    // Setup mocks\n    PowerMockito.mockStatic(StringUtils.class);\n\n    // Arrange\n    final String datetimeStr = \"a/b/c\";\n    final Method isEmptyMethod =\n        DTUMemberMatcher.method(StringUtils.class, \"isEmpty\", String.class);\n    PowerMockito.doReturn(true)\n        .when(StringUtils.class, isEmptyMethod)\n        .withArguments(or(isA(String.class), isNull(String.class)));\n\n    // Act\n    final Date actual = Util.parseDate(datetimeStr);\n\n    // Assert result\n    Assert.assertNull(actual);\n  }\n}\n"
  },
  {
    "path": "client-adapter/common/src/test/java/com/alibaba/otter/canal/client/adapter/support/YamlUtilsTest.java",
    "content": "package com.alibaba.otter.canal.client.adapter.support;\n\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.springframework.beans.factory.annotation.Value;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Properties;\n\npublic class YamlUtilsTest {\n\n\n\n    @Test\n    public void testLoadConfigToYml() {\n        String configStr=\"dataSourceKey: defaultDS\\n\"\n            + \"destination: example\\n\"\n            + \"groupId: g1\\n\"\n            + \"outerAdapterKey: mysql1\\n\"\n            + \"concurrent: true\\n\"\n            + \"dbMapping:\\n\"\n            + \"  _id: _id\\n\"\n            + \"  database: mytest\\n\"\n            + \"  table: user\\n\"\n            + \"  targetTable: mytest2.user\\n\"\n            + \"  targetPk:\\n\"\n            + \"    id: id\\n\"\n            + \"#  mapAll: true\\n\"\n            + \"  targetColumns:\\n\"\n            + \"    id:\\n\"\n            + \"    name:\\n\"\n            + \"    role_id:\\n\"\n            + \"    c_time:\\n\"\n            + \"    test1:\\n\"\n            + \"  etlCondition: \\\"where c_time>={}\\\"\\n\"\n            + \"  commitBatch: 3000 # 批量提交的大小\";\n\n        MappingConfig config = YamlUtils.ymlToObj(null, configStr, MappingConfig.class, null, new Properties());\n\n        Assert.assertNotNull(config);\n        Assert.assertEquals(config.getDbMapping().getId(), \"_id\");\n        Assert.assertEquals(config.getDestination(), \"example\");\n        Assert.assertEquals(config.getOuterAdapterKey(), \"mysql1\");\n        Assert.assertEquals(config.getDbMapping().getDatabase(), \"mytest\");\n        Assert.assertEquals(config.getDbMapping().getTargetColumns().size(), 5);\n    }\n\n    private static class MappingConfig {\n        private String    dataSourceKey;\n\n        private String    destination;\n\n        private String    groupId;\n\n        private String    outerAdapterKey;\n\n        private boolean   concurrent = false;\n\n        private DbMapping dbMapping;\n\n        public String getDataSourceKey() {\n            return dataSourceKey;\n        }\n\n        public void setDataSourceKey(String dataSourceKey) {\n            this.dataSourceKey = dataSourceKey;\n        }\n\n        public String getDestination() {\n            return destination;\n        }\n\n        public void setDestination(String destination) {\n            this.destination = destination;\n        }\n\n        public String getGroupId() {\n            return groupId;\n        }\n\n        public void setGroupId(String groupId) {\n            this.groupId = groupId;\n        }\n\n        public String getOuterAdapterKey() {\n            return outerAdapterKey;\n        }\n\n        public void setOuterAdapterKey(String outerAdapterKey) {\n            this.outerAdapterKey = outerAdapterKey;\n        }\n\n        public boolean isConcurrent() {\n            return concurrent;\n        }\n\n        public void setConcurrent(boolean concurrent) {\n            this.concurrent = concurrent;\n        }\n\n        public DbMapping getDbMapping() {\n            return dbMapping;\n        }\n\n        public void setDbMapping(DbMapping dbMapping) {\n            this.dbMapping = dbMapping;\n        }\n    }\n\n    private static class DbMapping {\n\n        @Value(\"${_id}\")\n        private String id ;\n        private boolean             mirrorDb        = false;                 // 是否镜像库\n        private String              database;                                // 数据库名或schema名\n        private String              table;                                   // 表名\n        private Map<String, String> targetPk        = new LinkedHashMap<>(); // 目标表主键字段\n        private boolean             mapAll          = false;                 // 映射所有字段\n        private String              targetDb;                                // 目标库名\n        private String              targetTable;                             // 目标表名\n        private Map<String, String> targetColumns;                           // 目标表字段映射\n\n        private boolean             caseInsensitive = false;                 // 目标表不区分大小写，默认是否\n\n        private String              etlCondition;                            // etl条件sql\n\n        private int                 readBatch       = 5000;\n        private int                 commitBatch     = 5000;                  // etl等批量提交大小\n\n        private Map<String, String> allMapColumns;\n\n        public boolean isMirrorDb() {\n            return mirrorDb;\n        }\n\n        public void setMirrorDb(boolean mirrorDb) {\n            this.mirrorDb = mirrorDb;\n        }\n\n        public String getDatabase() {\n            return database;\n        }\n\n        public void setDatabase(String database) {\n            this.database = database;\n        }\n\n        public String getTable() {\n            return table;\n        }\n\n        public void setTable(String table) {\n            this.table = table;\n        }\n\n        public Map<String, String> getTargetPk() {\n            return targetPk;\n        }\n\n        public void setTargetPk(Map<String, String> targetPk) {\n            this.targetPk = targetPk;\n        }\n\n        public boolean isMapAll() {\n            return mapAll;\n        }\n\n        public void setMapAll(boolean mapAll) {\n            this.mapAll = mapAll;\n        }\n\n        public String getTargetDb() {\n            return targetDb;\n        }\n\n        public void setTargetDb(String targetDb) {\n            this.targetDb = targetDb;\n        }\n\n        public String getTargetTable() {\n            return targetTable;\n        }\n\n        public void setTargetTable(String targetTable) {\n            this.targetTable = targetTable;\n        }\n\n        public Map<String, String> getTargetColumns() {\n            return targetColumns;\n        }\n\n        public void setTargetColumns(Map<String, String> targetColumns) {\n            this.targetColumns = targetColumns;\n        }\n\n        public boolean isCaseInsensitive() {\n            return caseInsensitive;\n        }\n\n        public void setCaseInsensitive(boolean caseInsensitive) {\n            this.caseInsensitive = caseInsensitive;\n        }\n\n        public String getEtlCondition() {\n            return etlCondition;\n        }\n\n        public void setEtlCondition(String etlCondition) {\n            this.etlCondition = etlCondition;\n        }\n\n        public int getReadBatch() {\n            return readBatch;\n        }\n\n        public void setReadBatch(int readBatch) {\n            this.readBatch = readBatch;\n        }\n\n        public int getCommitBatch() {\n            return commitBatch;\n        }\n\n        public void setCommitBatch(int commitBatch) {\n            this.commitBatch = commitBatch;\n        }\n\n        public Map<String, String> getAllMapColumns() {\n            return allMapColumns;\n        }\n\n        public void setAllMapColumns(Map<String, String> allMapColumns) {\n            this.allMapColumns = allMapColumns;\n        }\n\n        public String getId() {\n            return id;\n        }\n\n        public void setId(String id) {\n            this.id = id;\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/es6x/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>canal.client-adapter</artifactId>\n        <groupId>com.alibaba.otter</groupId>\n        <version>1.1.9-SNAPSHOT</version>\n        <relativePath>../pom.xml</relativePath>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>com.alibaba.otter</groupId>\n    <artifactId>client-adapter.es6x</artifactId>\n    <packaging>jar</packaging>\n    <name>canal client adapter es v6x module for otter ${project.version}</name>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>client-adapter.common</artifactId>\n            <version>${project.version}</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>client-adapter.escore</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.elasticsearch</groupId>\n            <artifactId>elasticsearch</artifactId>\n            <version>6.8.22</version>\n        </dependency>\n        <dependency>\n            <groupId>org.elasticsearch.client</groupId>\n            <artifactId>transport</artifactId>\n            <version>6.8.22</version>\n        </dependency>\n        <dependency>\n            <groupId>org.elasticsearch.client</groupId>\n            <artifactId>elasticsearch-rest-client</artifactId>\n            <version>6.8.22</version>\n        </dependency>\n        <dependency>\n            <groupId>org.elasticsearch.client</groupId>\n            <artifactId>elasticsearch-rest-high-level-client</artifactId>\n            <version>6.8.22</version>\n        </dependency>\n\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-assembly-plugin</artifactId>\n                <version>2.4</version>\n                <configuration>\n                    <descriptorRefs>\n                        <descriptorRef>jar-with-dependencies</descriptorRef>\n                    </descriptorRefs>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>make-assembly</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>single</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-antrun-plugin</artifactId>\n                <version>1.8</version>\n                <executions>\n                    <execution>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>run</goal>\n                        </goals>\n                        <configuration>\n                            <tasks>\n                                <copy todir=\"${project.basedir}/../launcher/target/classes/es6\" overwrite=\"true\">\n                                    <fileset dir=\"${project.basedir}/target/classes/es6\" erroronmissingdir=\"true\">\n                                        <include name=\"*.yml\" />\n                                    </fileset>\n                                </copy>\n                            </tasks>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "client-adapter/es6x/src/main/java/com/alibaba/otter/canal/client/adapter/es6x/ES6xAdapter.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es6x;\n\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport javax.sql.DataSource;\n\nimport org.elasticsearch.action.search.SearchResponse;\n\nimport com.alibaba.otter.canal.client.adapter.es.core.ESAdapter;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig;\nimport com.alibaba.otter.canal.client.adapter.es6x.etl.ESEtlService;\nimport com.alibaba.otter.canal.client.adapter.es6x.support.ES6xTemplate;\nimport com.alibaba.otter.canal.client.adapter.es6x.support.ESConnection;\nimport com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;\nimport com.alibaba.otter.canal.client.adapter.support.EtlResult;\nimport com.alibaba.otter.canal.client.adapter.support.OuterAdapterConfig;\nimport com.alibaba.otter.canal.client.adapter.support.SPI;\n\n/**\n * ES 6.x 外部适配器\n *\n * @author rewerma 2019-09-23\n * @version 1.0.0\n */\n@SPI(\"es6\")\npublic class ES6xAdapter extends ESAdapter {\n\n    private ESConnection esConnection;\n\n    public ESConnection getEsConnection() {\n        return esConnection;\n    }\n\n    @Override\n    public void init(OuterAdapterConfig configuration, Properties envProperties) {\n        try {\n            Map<String, String> properties = configuration.getProperties();\n\n            String[] hostArray = configuration.getHosts().split(\",\");\n            String mode = properties.get(\"mode\");\n            if (\"rest\".equalsIgnoreCase(mode) || \"http\".equalsIgnoreCase(mode)) {\n                esConnection = new ESConnection(hostArray, properties, ESConnection.ESClientMode.REST);\n            } else {\n                esConnection = new ESConnection(hostArray, properties, ESConnection.ESClientMode.TRANSPORT);\n            }\n            this.esTemplate = new ES6xTemplate(esConnection);\n\n            envProperties.put(\"es.version\", \"es6\");\n            super.init(configuration, envProperties);\n        } catch (Throwable e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    @Override\n    public Map<String, Object> count(String task) {\n        ESSyncConfig config = esSyncConfig.get(task);\n        ESSyncConfig.ESMapping mapping = config.getEsMapping();\n        SearchResponse response = this.esConnection.new ESSearchRequest(mapping.getIndex(), mapping.getType()).size(0)\n            .getResponse();\n\n        long rowCount = response.getHits().getTotalHits();\n        Map<String, Object> res = new LinkedHashMap<>();\n        res.put(\"esIndex\", mapping.getIndex());\n        res.put(\"count\", rowCount);\n        return res;\n    }\n\n    @Override\n    public EtlResult etl(String task, List<String> params) {\n        EtlResult etlResult = new EtlResult();\n        ESSyncConfig config = esSyncConfig.get(task);\n        if (config != null) {\n            DataSource dataSource = DatasourceConfig.DATA_SOURCES.get(config.getDataSourceKey());\n            ESEtlService esEtlService = new ESEtlService(esConnection, config);\n            if (dataSource != null) {\n                return esEtlService.importData(params);\n            } else {\n                etlResult.setSucceeded(false);\n                etlResult.setErrorMessage(\"DataSource not found\");\n                return etlResult;\n            }\n        } else {\n            StringBuilder resultMsg = new StringBuilder();\n            boolean resSuccess = true;\n            for (ESSyncConfig configTmp : esSyncConfig.values()) {\n                // 取所有的destination为task的配置\n                if (configTmp.getDestination().equals(task)) {\n                    ESEtlService esEtlService = new ESEtlService(esConnection, configTmp);\n                    EtlResult etlRes = esEtlService.importData(params);\n                    if (!etlRes.getSucceeded()) {\n                        resSuccess = false;\n                        resultMsg.append(etlRes.getErrorMessage()).append(\"\\n\");\n                    } else {\n                        resultMsg.append(etlRes.getResultMessage()).append(\"\\n\");\n                    }\n                }\n            }\n            if (resultMsg.length() > 0) {\n                etlResult.setSucceeded(resSuccess);\n                if (resSuccess) {\n                    etlResult.setResultMessage(resultMsg.toString());\n                } else {\n                    etlResult.setErrorMessage(resultMsg.toString());\n                }\n                return etlResult;\n            }\n        }\n        etlResult.setSucceeded(false);\n        etlResult.setErrorMessage(\"Task not found\");\n        return etlResult;\n    }\n\n    @Override\n    public void destroy() {\n        super.destroy();\n        if (esConnection != null) {\n            esConnection.close();\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/es6x/src/main/java/com/alibaba/otter/canal/client/adapter/es6x/etl/ESEtlService.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es6x.etl;\n\nimport java.sql.SQLException;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport javax.sql.DataSource;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.elasticsearch.action.search.SearchResponse;\nimport org.elasticsearch.index.query.QueryBuilders;\nimport org.elasticsearch.search.SearchHit;\n\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig.ESMapping;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem.FieldItem;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESBulkResponse;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESIndexRequest;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESUpdateRequest;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESTemplate;\nimport com.alibaba.otter.canal.client.adapter.es6x.support.ES6xTemplate;\nimport com.alibaba.otter.canal.client.adapter.es6x.support.ESConnection;\nimport com.alibaba.otter.canal.client.adapter.es6x.support.ESConnection.ESSearchRequest;\nimport com.alibaba.otter.canal.client.adapter.support.AbstractEtlService;\nimport com.alibaba.otter.canal.client.adapter.support.AdapterConfig;\nimport com.alibaba.otter.canal.client.adapter.support.EtlResult;\nimport com.alibaba.otter.canal.client.adapter.support.Util;\n\n/**\n * ES ETL Service\n *\n * @author rewerma 2018-11-01\n * @version 1.0.0\n */\npublic class ESEtlService extends AbstractEtlService {\n\n    private ESConnection esConnection;\n    private ESTemplate   esTemplate;\n    private ESSyncConfig config;\n\n    public ESEtlService(ESConnection esConnection, ESSyncConfig config){\n        super(\"ES\", config);\n        this.esConnection = esConnection;\n        this.esTemplate = new ES6xTemplate(esConnection);\n        this.config = config;\n    }\n\n    public EtlResult importData(List<String> params) {\n        ESMapping mapping = config.getEsMapping();\n        logger.info(\"start etl to import data to index: {}\", mapping.getIndex());\n        String sql = mapping.getSql();\n        return importData(sql, params);\n    }\n\n    protected boolean executeSqlImport(DataSource ds, String sql, List<Object> values,\n                                       AdapterConfig.AdapterMapping adapterMapping, AtomicLong impCount,\n                                       List<String> errMsg) {\n        try {\n            ESMapping mapping = (ESMapping) adapterMapping;\n            Util.sqlRS(ds, sql, values, rs -> {\n                int count = 0;\n                try {\n                    ESBulkRequest esBulkRequest = this.esConnection.new ES6xBulkRequest();\n\n                    long batchBegin = System.currentTimeMillis();\n                    while (rs.next()) {\n                        Map<String, Object> esFieldData = new LinkedHashMap<>();\n                        Object idVal = null;\n                        for (FieldItem fieldItem : mapping.getSchemaItem().getSelectFields().values()) {\n\n                            String fieldName = fieldItem.getFieldName();\n                            if (mapping.getSkips().contains(fieldName)) {\n                                continue;\n                            }\n\n                            // 如果是主键字段则不插入\n                if (fieldItem.getFieldName().equals(mapping.getId())) {\n                    idVal = esTemplate.getValFromRS(mapping, rs, fieldName, fieldName);\n                } else {\n                    Object val = esTemplate.getValFromRS(mapping, rs, fieldName, fieldName);\n                    esFieldData.put(Util.cleanColumn(fieldName), val);\n                }\n\n            }\n\n            if (!mapping.getRelations().isEmpty()) {\n                mapping.getRelations().forEach((relationField, relationMapping) -> {\n                    Map<String, Object> relations = new HashMap<>();\n                    relations.put(\"name\", relationMapping.getName());\n                    if (StringUtils.isNotEmpty(relationMapping.getParent())) {\n                        FieldItem parentFieldItem = mapping.getSchemaItem()\n                            .getSelectFields()\n                            .get(relationMapping.getParent());\n                        Object parentVal;\n                        try {\n                            parentVal = esTemplate.getValFromRS(mapping,\n                                rs,\n                                parentFieldItem.getFieldName(),\n                                parentFieldItem.getFieldName());\n                        } catch (SQLException e) {\n                            throw new RuntimeException(e);\n                        }\n                        if (parentVal != null) {\n                            relations.put(\"parent\", parentVal.toString());\n                            esFieldData.put(\"$parent_routing\", parentVal.toString());\n\n                        }\n                    }\n                    esFieldData.put(Util.cleanColumn(relationField), relations);\n                });\n            }\n\n            if (idVal != null) {\n                String parentVal = (String) esFieldData.remove(\"$parent_routing\");\n                if (mapping.isUpsert()) {\n                    ESUpdateRequest esUpdateRequest = this.esConnection.new ES6xUpdateRequest(mapping.getIndex(),\n                        mapping.getType(),\n                        idVal.toString()).setDoc(esFieldData).setDocAsUpsert(true);\n\n                    if (StringUtils.isNotEmpty(parentVal)) {\n                        esUpdateRequest.setRouting(parentVal);\n                    }\n\n                    esBulkRequest.add(esUpdateRequest);\n                } else {\n                    ESIndexRequest esIndexRequest = this.esConnection.new ES6xIndexRequest(mapping.getIndex(),\n                        mapping.getType(),\n                        idVal.toString()).setSource(esFieldData);\n                    if (StringUtils.isNotEmpty(parentVal)) {\n                        esIndexRequest.setRouting(parentVal);\n                    }\n                    esBulkRequest.add(esIndexRequest);\n                }\n            } else {\n                idVal = esFieldData.get(mapping.getPk());\n                ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.getIndex(),\n                    mapping.getType()).setQuery(QueryBuilders.termQuery(mapping.getPk(), idVal)).size(10000);\n                SearchResponse response = esSearchRequest.getResponse();\n                for (SearchHit hit : response.getHits()) {\n                    ESUpdateRequest esUpdateRequest = this.esConnection.new ES6xUpdateRequest(mapping.getIndex(),\n                        mapping.getType(),\n                        hit.getId()).setDoc(esFieldData);\n                    esBulkRequest.add(esUpdateRequest);\n                }\n            }\n\n            if (esBulkRequest.numberOfActions() % mapping.getCommitBatch() == 0 && esBulkRequest.numberOfActions() > 0) {\n                long esBatchBegin = System.currentTimeMillis();\n                ESBulkResponse rp = esBulkRequest.bulk();\n                if (rp.hasFailures()) {\n                    rp.processFailBulkResponse(\"全量数据 etl 异常 \");\n                }\n\n                if (logger.isTraceEnabled()) {\n                    logger.trace(\"全量数据批量导入批次耗时: {}, es执行时间: {}, 批次大小: {}, index; {}\",\n                        (System.currentTimeMillis() - batchBegin),\n                        (System.currentTimeMillis() - esBatchBegin),\n                        esBulkRequest.numberOfActions(),\n                        mapping.getIndex());\n                }\n                batchBegin = System.currentTimeMillis();\n                esBulkRequest.resetBulk();\n            }\n            count++;\n            impCount.incrementAndGet();\n        }\n\n        if (esBulkRequest.numberOfActions() > 0) {\n            long esBatchBegin = System.currentTimeMillis();\n            ESBulkResponse rp = esBulkRequest.bulk();\n            if (rp.hasFailures()) {\n                rp.processFailBulkResponse(\"全量数据 etl 异常 \");\n            }\n            if (logger.isTraceEnabled()) {\n                logger.trace(\"全量数据批量导入最后批次耗时: {}, es执行时间: {}, 批次大小: {}, index; {}\",\n                    (System.currentTimeMillis() - batchBegin),\n                    (System.currentTimeMillis() - esBatchBegin),\n                    esBulkRequest.numberOfActions(),\n                    mapping.getIndex());\n            }\n        }\n    } catch (Exception e) {\n        logger.error(e.getMessage(), e);\n        errMsg.add(mapping.getIndex() + \" etl failed! ==>\" + e.getMessage());\n        throw new RuntimeException(e);\n    }\n    return count;\n}           );\n\n            return true;\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/es6x/src/main/java/com/alibaba/otter/canal/client/adapter/es6x/support/ES6xTemplate.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es6x.support;\n\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\nimport javax.sql.DataSource;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.elasticsearch.action.search.SearchResponse;\nimport org.elasticsearch.cluster.metadata.MappingMetaData;\nimport org.elasticsearch.index.query.BoolQueryBuilder;\nimport org.elasticsearch.index.query.QueryBuilders;\nimport org.elasticsearch.search.SearchHit;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig.ESMapping;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem.ColumnItem;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem.FieldItem;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESBulkResponse;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESDeleteRequest;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESIndexRequest;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESUpdateRequest;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESSyncUtil;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESTemplate;\nimport com.alibaba.otter.canal.client.adapter.es6x.support.ESConnection.ESSearchRequest;\nimport com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;\nimport com.alibaba.otter.canal.client.adapter.support.Util;\n\npublic class ES6xTemplate implements ESTemplate {\n\n    private static final Logger                               logger         = LoggerFactory\n        .getLogger(ESTemplate.class);\n\n    private static final int                                  MAX_BATCH_SIZE = 1000;\n\n    private ESConnection                                      esConnection;\n\n    private ESBulkRequest                                     esBulkRequest;\n\n    // es 字段类型本地缓存\n    private static ConcurrentMap<String, Map<String, String>> esFieldTypes   = new ConcurrentHashMap<>();\n\n    public ES6xTemplate(ESConnection esConnection){\n        this.esConnection = esConnection;\n        this.esBulkRequest = this.esConnection.new ES6xBulkRequest();\n    }\n\n    public ESBulkRequest getBulk() {\n        return esBulkRequest;\n    }\n\n    public void resetBulkRequestBuilder() {\n        this.esBulkRequest.resetBulk();\n    }\n\n    @Override\n    public void insert(ESSyncConfig.ESMapping mapping, Object pkVal, Map<String, Object> esFieldData) {\n        if (mapping.getId() != null) {\n            String parentVal = (String) esFieldData.remove(\"$parent_routing\");\n            if (mapping.isUpsert()) {\n                ESUpdateRequest updateRequest = esConnection.new ES6xUpdateRequest(mapping.getIndex(),\n                    mapping.getType(),\n                    pkVal.toString()).setDoc(esFieldData).setDocAsUpsert(true);\n                if (StringUtils.isNotEmpty(parentVal)) {\n                    updateRequest.setRouting(parentVal);\n                }\n                getBulk().add(updateRequest);\n            } else {\n                ESIndexRequest indexRequest = esConnection.new ES6xIndexRequest(mapping.getIndex(),\n                    mapping.getType(),\n                    pkVal.toString()).setSource(esFieldData);\n                if (StringUtils.isNotEmpty(parentVal)) {\n                    indexRequest.setRouting(parentVal);\n                }\n                getBulk().add(indexRequest);\n            }\n            commitBulk();\n        } else {\n            ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.getIndex(),\n                mapping.getType()).setQuery(QueryBuilders.termQuery(mapping.getPk(), pkVal)).size(10000);\n            SearchResponse response = esSearchRequest.getResponse();\n\n            for (SearchHit hit : response.getHits()) {\n                ESUpdateRequest esUpdateRequest = this.esConnection.new ES6xUpdateRequest(mapping.getIndex(),\n                    mapping.getType(),\n                    hit.getId()).setDoc(esFieldData);\n                getBulk().add(esUpdateRequest);\n                commitBulk();\n            }\n        }\n    }\n\n    @Override\n    public void update(ESSyncConfig.ESMapping mapping, Object pkVal, Map<String, Object> esFieldData) {\n        Map<String, Object> esFieldDataTmp = new LinkedHashMap<>(esFieldData.size());\n        esFieldData.forEach((k, v) -> esFieldDataTmp.put(Util.cleanColumn(k), v));\n        append4Update(mapping, pkVal, esFieldDataTmp);\n        commitBulk();\n    }\n\n    @Override\n    public void updateByQuery(ESSyncConfig config, Map<String, Object> paramsTmp, Map<String, Object> esFieldData) {\n        if (paramsTmp.isEmpty()) {\n            return;\n        }\n        ESMapping mapping = config.getEsMapping();\n        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();\n        paramsTmp.forEach((fieldName, value) -> queryBuilder.must(QueryBuilders.termsQuery(fieldName, value)));\n\n        // 查询sql批量更新\n        DataSource ds = DatasourceConfig.DATA_SOURCES.get(config.getDataSourceKey());\n        StringBuilder sql = new StringBuilder(\"SELECT * FROM (\" + mapping.getSql() + \") _v WHERE \");\n        List<Object> values = new ArrayList<>();\n        paramsTmp.forEach((fieldName, value) -> {\n            sql.append(\"_v.\").append(fieldName).append(\"=? AND \");\n            values.add(value);\n        });\n        // TODO 直接外部包裹sql会导致全表扫描性能低, 待优化拼接内部where条件\n        int len = sql.length();\n        sql.delete(len - 4, len);\n        Integer syncCount = (Integer) Util.sqlRS(ds, sql.toString(), values, rs -> {\n            int count = 0;\n            try {\n                while (rs.next()) {\n                    Object idVal = getIdValFromRS(mapping, rs);\n                    append4Update(mapping, idVal, esFieldData);\n                    commitBulk();\n                    count++;\n                }\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n            return count;\n        });\n        if (logger.isTraceEnabled()) {\n            logger.trace(\"Update ES by query affected {} records\", syncCount);\n        }\n    }\n\n    @Override\n    public void delete(ESSyncConfig.ESMapping mapping, Object pkVal, Map<String, Object> esFieldData) {\n        if (mapping.getId() != null) {\n            ESDeleteRequest esDeleteRequest = this.esConnection.new ES6xDeleteRequest(mapping.getIndex(),\n                mapping.getType(),\n                pkVal.toString());\n            getBulk().add(esDeleteRequest);\n            commitBulk();\n        } else {\n            ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.getIndex(),\n                mapping.getType()).setQuery(QueryBuilders.termQuery(mapping.getPk(), pkVal)).size(10000);\n            SearchResponse response = esSearchRequest.getResponse();\n            for (SearchHit hit : response.getHits()) {\n                ESUpdateRequest esUpdateRequest = this.esConnection.new ES6xUpdateRequest(mapping.getIndex(),\n                    mapping.getType(),\n                    hit.getId()).setDoc(esFieldData);\n                getBulk().add(esUpdateRequest);\n                commitBulk();\n            }\n        }\n    }\n\n    @Override\n    public void commit() {\n        if (getBulk().numberOfActions() > 0) {\n            ESBulkResponse response = getBulk().bulk();\n            if (response.hasFailures()) {\n                response.processFailBulkResponse(\"ES sync commit error \");\n            }\n            resetBulkRequestBuilder();\n        }\n    }\n\n    @Override\n    public Object getValFromRS(ESSyncConfig.ESMapping mapping, ResultSet resultSet, String fieldName,\n                               String columnName) throws SQLException {\n        fieldName = Util.cleanColumn(fieldName);\n        columnName = Util.cleanColumn(columnName);\n        String esType = getEsType(mapping, fieldName);\n\n        Object value = resultSet.getObject(columnName);\n        if (value instanceof Boolean) {\n            if (!\"boolean\".equals(esType)) {\n                value = resultSet.getByte(columnName);\n            }\n        }\n\n        // 如果是对象类型\n        if (mapping.getObjFields().containsKey(fieldName)) {\n            return ESSyncUtil.convertToEsObj(value, mapping.getObjFields().get(fieldName));\n        } else {\n            return ESSyncUtil.typeConvert(value, esType);\n        }\n    }\n\n    @Override\n    public Object getESDataFromRS(ESSyncConfig.ESMapping mapping, ResultSet resultSet,\n                                  Map<String, Object> esFieldData) throws SQLException {\n        SchemaItem schemaItem = mapping.getSchemaItem();\n        String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();\n        Object resultIdVal = null;\n        for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {\n            Object value = getValFromRS(mapping, resultSet, fieldItem.getFieldName(), fieldItem.getFieldName());\n\n            if (fieldItem.getFieldName().equals(idFieldName)) {\n                resultIdVal = value;\n            }\n\n            if (!fieldItem.getFieldName().equals(mapping.getId())\n                    && !mapping.getSkips().contains(fieldItem.getFieldName())) {\n                esFieldData.put(Util.cleanColumn(fieldItem.getFieldName()), value);\n            }\n        }\n\n        // 添加父子文档关联信息\n        putRelationDataFromRS(mapping, schemaItem, resultSet, esFieldData);\n\n        return resultIdVal;\n    }\n\n    @Override\n    public Object getIdValFromRS(ESSyncConfig.ESMapping mapping, ResultSet resultSet) throws SQLException {\n        SchemaItem schemaItem = mapping.getSchemaItem();\n        String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();\n        Object resultIdVal = null;\n        for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {\n            Object value = getValFromRS(mapping, resultSet, fieldItem.getFieldName(), fieldItem.getFieldName());\n\n            if (fieldItem.getFieldName().equals(idFieldName)) {\n                resultIdVal = value;\n                break;\n            }\n        }\n        return resultIdVal;\n    }\n\n    @Override\n    public Object getESDataFromRS(ESSyncConfig.ESMapping mapping, ResultSet resultSet, Map<String, Object> dmlOld,\n                                  Map<String, Object> esFieldData) throws SQLException {\n        SchemaItem schemaItem = mapping.getSchemaItem();\n        String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();\n        Object resultIdVal = null;\n        for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {\n            if (fieldItem.getFieldName().equals(idFieldName)) {\n                resultIdVal = getValFromRS(mapping, resultSet, fieldItem.getFieldName(), fieldItem.getFieldName());\n            }\n\n            for (ColumnItem columnItem : fieldItem.getColumnItems()) {\n                if (dmlOld.containsKey(columnItem.getColumnName())\n                        && !mapping.getSkips().contains(fieldItem.getFieldName())) {\n                    esFieldData.put(Util.cleanColumn(fieldItem.getFieldName()),\n                            getValFromRS(mapping, resultSet, fieldItem.getFieldName(), fieldItem.getFieldName()));\n                    break;\n                }\n            }\n        }\n\n        // 添加父子文档关联信息\n        putRelationDataFromRS(mapping, schemaItem, resultSet, esFieldData);\n\n        return resultIdVal;\n    }\n\n    @Override\n    public Object getValFromData(ESSyncConfig.ESMapping mapping, Map<String, Object> dmlData, String fieldName,\n                                 String columnName) {\n        String esType = getEsType(mapping, fieldName);\n        Object value = dmlData.get(columnName);\n        if (value instanceof Byte) {\n            if (\"boolean\".equals(esType)) {\n                value = ((Byte) value).intValue() != 0;\n            }\n        }\n\n        // 如果是对象类型\n        if (mapping.getObjFields().containsKey(fieldName)) {\n            return ESSyncUtil.convertToEsObj(value, mapping.getObjFields().get(fieldName));\n        } else {\n            return ESSyncUtil.typeConvert(value, esType);\n        }\n    }\n\n    @Override\n    public Object getESDataFromDmlData(ESSyncConfig.ESMapping mapping, Map<String, Object> dmlData,\n                                       Map<String, Object> esFieldData) {\n        SchemaItem schemaItem = mapping.getSchemaItem();\n        String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();\n        Object resultIdVal = null;\n        for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {\n            String columnName = fieldItem.getColumnItems().iterator().next().getColumnName();\n            Object value = getValFromData(mapping, dmlData, fieldItem.getFieldName(), columnName);\n\n            if (fieldItem.getFieldName().equals(idFieldName)) {\n                resultIdVal = value;\n            }\n\n            if (!fieldItem.getFieldName().equals(mapping.getId())\n                    && !mapping.getSkips().contains(fieldItem.getFieldName())) {\n                esFieldData.put(Util.cleanColumn(fieldItem.getFieldName()), value);\n            }\n        }\n\n        // 添加父子文档关联信息\n        putRelationData(mapping, schemaItem, dmlData, esFieldData);\n        return resultIdVal;\n    }\n\n    @Override\n    public Object getESDataFromDmlData(ESSyncConfig.ESMapping mapping,String owner, Map<String, Object> dmlData,\n                                       Map<String, Object> dmlOld, Map<String, Object> esFieldData) {\n        SchemaItem schemaItem = mapping.getSchemaItem();\n        String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();\n        Object resultIdVal = null;\n        for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {\n            ColumnItem columnItem = fieldItem.getColumnItems().iterator().next();\n            if (!columnItem.getOwner().equals(owner)) {\n                continue;\n            }\n            String columnName = columnItem.getColumnName();\n\n            if (fieldItem.getFieldName().equals(idFieldName)) {\n                resultIdVal = getValFromData(mapping, dmlData, fieldItem.getFieldName(), columnName);\n            }\n\n            if (dmlOld.containsKey(columnName) && !mapping.getSkips().contains(fieldItem.getFieldName())) {\n                esFieldData.put(Util.cleanColumn(fieldItem.getFieldName()),\n                        getValFromData(mapping, dmlData, fieldItem.getFieldName(), columnName));\n            }\n        }\n\n        // 添加父子文档关联信息\n        putRelationData(mapping, schemaItem, dmlOld, esFieldData);\n        return resultIdVal;\n    }\n\n    /**\n     * 如果大于批量数则提交批次\n     */\n    private void commitBulk() {\n        if (getBulk().numberOfActions() >= MAX_BATCH_SIZE) {\n            commit();\n        }\n    }\n\n    private void append4Update(ESMapping mapping, Object pkVal, Map<String, Object> esFieldData) {\n        if (mapping.getId() != null) {\n            String parentVal = (String) esFieldData.remove(\"$parent_routing\");\n            if (mapping.isUpsert()) {\n                ESUpdateRequest esUpdateRequest = this.esConnection.new ES6xUpdateRequest(mapping.getIndex(),\n                    mapping.getType(),\n                    pkVal.toString()).setDoc(esFieldData).setDocAsUpsert(true);\n                if (StringUtils.isNotEmpty(parentVal)) {\n                    esUpdateRequest.setRouting(parentVal);\n                }\n                getBulk().add(esUpdateRequest);\n            } else {\n                ESUpdateRequest esUpdateRequest = this.esConnection.new ES6xUpdateRequest(mapping.getIndex(),\n                    mapping.getType(),\n                    pkVal.toString()).setDoc(esFieldData);\n                if (StringUtils.isNotEmpty(parentVal)) {\n                    esUpdateRequest.setRouting(parentVal);\n                }\n                getBulk().add(esUpdateRequest);\n            }\n        } else {\n            ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.getIndex(),\n                mapping.getType()).setQuery(QueryBuilders.termQuery(mapping.getPk(), pkVal)).size(10000);\n            SearchResponse response = esSearchRequest.getResponse();\n            for (SearchHit hit : response.getHits()) {\n                ESUpdateRequest esUpdateRequest = this.esConnection.new ES6xUpdateRequest(mapping.getIndex(),\n                    mapping.getType(),\n                    hit.getId()).setDoc(esFieldData);\n                getBulk().add(esUpdateRequest);\n            }\n        }\n    }\n\n    /**\n     * 获取es mapping中的属性类型\n     *\n     * @param mapping mapping配置\n     * @param fieldName 属性名\n     * @return 类型\n     */\n    @SuppressWarnings(\"unchecked\")\n    private String getEsType(ESMapping mapping, String fieldName) {\n        String key = mapping.getIndex() + \"-\" + mapping.getType();\n        Map<String, String> fieldType = esFieldTypes.get(key);\n        if (fieldType != null) {\n            return fieldType.get(fieldName);\n        } else {\n            MappingMetaData mappingMetaData = esConnection.getMapping(mapping.getIndex(), mapping.getType());\n\n            if (mappingMetaData == null) {\n                throw new IllegalArgumentException(\"Not found the mapping info of index: \" + mapping.getIndex());\n            }\n\n            fieldType = new LinkedHashMap<>();\n\n            Map<String, Object> sourceMap = mappingMetaData.getSourceAsMap();\n            Map<String, Object> esMapping = (Map<String, Object>) sourceMap.get(\"properties\");\n            for (Map.Entry<String, Object> entry : esMapping.entrySet()) {\n                Map<String, Object> value = (Map<String, Object>) entry.getValue();\n                if (value.containsKey(\"properties\")) {\n                    fieldType.put(entry.getKey(), \"object\");\n                } else {\n                    fieldType.put(entry.getKey(), (String) value.get(\"type\"));\n                }\n            }\n            esFieldTypes.put(key, fieldType);\n\n            return fieldType.get(fieldName);\n        }\n    }\n\n    private void putRelationDataFromRS(ESMapping mapping, SchemaItem schemaItem, ResultSet resultSet,\n                                       Map<String, Object> esFieldData) {\n        // 添加父子文档关联信息\n        if (!mapping.getRelations().isEmpty()) {\n            mapping.getRelations().forEach((relationField, relationMapping) -> {\n                Map<String, Object> relations = new HashMap<>();\n                relations.put(\"name\", relationMapping.getName());\n                if (StringUtils.isNotEmpty(relationMapping.getParent())) {\n                    FieldItem parentFieldItem = schemaItem.getSelectFields().get(relationMapping.getParent());\n                    Object parentVal;\n                    try {\n                        parentVal = getValFromRS(mapping,\n                                resultSet,\n                                parentFieldItem.getFieldName(),\n                                parentFieldItem.getFieldName());\n                    } catch (SQLException e) {\n                        throw new RuntimeException(e);\n                    }\n                    if (parentVal != null) {\n                        relations.put(\"parent\", parentVal.toString());\n                        esFieldData.put(\"$parent_routing\", parentVal.toString());\n\n                    }\n                }\n                esFieldData.put(relationField, relations);\n            });\n        }\n    }\n\n    private void putRelationData(ESMapping mapping, SchemaItem schemaItem, Map<String, Object> dmlData,\n                                 Map<String, Object> esFieldData) {\n        // 添加父子文档关联信息\n        if (!mapping.getRelations().isEmpty()) {\n            mapping.getRelations().forEach((relationField, relationMapping) -> {\n                Map<String, Object> relations = new HashMap<>();\n                relations.put(\"name\", relationMapping.getName());\n                if (StringUtils.isNotEmpty(relationMapping.getParent())) {\n                    FieldItem parentFieldItem = schemaItem.getSelectFields().get(relationMapping.getParent());\n                    String columnName = parentFieldItem.getColumnItems().iterator().next().getColumnName();\n                    Object parentVal = getValFromData(mapping, dmlData, parentFieldItem.getFieldName(), columnName);\n                    if (parentVal != null) {\n                        relations.put(\"parent\", parentVal.toString());\n                        esFieldData.put(\"$parent_routing\", parentVal.toString());\n\n                    }\n                }\n                esFieldData.put(relationField, relations);\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/es6x/src/main/java/com/alibaba/otter/canal/client/adapter/es6x/support/ESConnection.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es6x.support;\n\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.net.UnknownHostException;\nimport java.util.Arrays;\nimport java.util.Map;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.http.HttpHost;\nimport org.apache.http.auth.AuthScope;\nimport org.apache.http.auth.UsernamePasswordCredentials;\nimport org.apache.http.client.CredentialsProvider;\nimport org.apache.http.impl.client.BasicCredentialsProvider;\nimport org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest;\nimport org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse;\nimport org.elasticsearch.action.bulk.BulkItemResponse;\nimport org.elasticsearch.action.bulk.BulkRequest;\nimport org.elasticsearch.action.bulk.BulkRequestBuilder;\nimport org.elasticsearch.action.bulk.BulkResponse;\nimport org.elasticsearch.action.delete.DeleteRequest;\nimport org.elasticsearch.action.delete.DeleteRequestBuilder;\nimport org.elasticsearch.action.index.IndexRequest;\nimport org.elasticsearch.action.index.IndexRequestBuilder;\nimport org.elasticsearch.action.search.SearchRequest;\nimport org.elasticsearch.action.search.SearchRequestBuilder;\nimport org.elasticsearch.action.search.SearchResponse;\nimport org.elasticsearch.action.update.UpdateRequest;\nimport org.elasticsearch.action.update.UpdateRequestBuilder;\nimport org.elasticsearch.client.RequestOptions;\nimport org.elasticsearch.client.RestClient;\nimport org.elasticsearch.client.RestClientBuilder;\nimport org.elasticsearch.client.RestHighLevelClient;\nimport org.elasticsearch.client.RestHighLevelClientExt;\nimport org.elasticsearch.client.transport.TransportClient;\nimport org.elasticsearch.cluster.metadata.MappingMetaData;\nimport org.elasticsearch.common.collect.ImmutableOpenMap;\nimport org.elasticsearch.common.settings.Settings;\nimport org.elasticsearch.common.transport.TransportAddress;\nimport org.elasticsearch.index.query.QueryBuilder;\nimport org.elasticsearch.rest.RestStatus;\nimport org.elasticsearch.search.builder.SearchSourceBuilder;\nimport org.elasticsearch.transport.client.PreBuiltTransportClient;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest;\n\n/**\n * ES 连接器, Transport Rest 两种方式\n *\n * @author rewerma 2019-08-01\n * @version 1.0.0\n */\npublic class ESConnection {\n\n    private static final Logger logger = LoggerFactory.getLogger(ESConnection.class);\n\n    public enum ESClientMode {\n        TRANSPORT, REST\n    }\n\n    private ESClientMode        mode;\n\n    private TransportClient     transportClient;\n\n    private RestHighLevelClient restHighLevelClient;\n\n    public ESConnection(String[] hosts, Map<String, String> properties, ESClientMode mode) throws UnknownHostException{\n        this.mode = mode;\n        if (mode == ESClientMode.TRANSPORT) {\n            Settings.Builder settingBuilder = Settings.builder();\n            settingBuilder.put(\"cluster.name\", properties.get(\"cluster.name\"));\n            Settings settings = settingBuilder.build();\n            transportClient = new PreBuiltTransportClient(settings);\n            for (String host : hosts) {\n                int i = host.indexOf(\":\");\n                transportClient.addTransportAddress(new TransportAddress(InetAddress.getByName(host.substring(0, i)),\n                    Integer.parseInt(host.substring(i + 1))));\n            }\n        } else {\n            HttpHost[] httpHosts = Arrays.stream(hosts).map(this::createHttpHost).toArray(HttpHost[]::new);\n            RestClientBuilder restClientBuilder = RestClient.builder(httpHosts);\n            String nameAndPwd = properties.get(\"security.auth\");\n            if (StringUtils.isNotEmpty(nameAndPwd) && nameAndPwd.contains(\":\")) {\n                String[] nameAndPwdArr = nameAndPwd.split(\":\");\n                final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();\n                credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(nameAndPwdArr[0],\n                    nameAndPwdArr[1]));\n                restClientBuilder.setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider));\n            }\n            restHighLevelClient = new RestHighLevelClient(restClientBuilder);\n        }\n    }\n\n    public void close() {\n        if (mode == ESClientMode.TRANSPORT) {\n            transportClient.close();\n        } else {\n            try {\n                restHighLevelClient.close();\n            } catch (IOException e) {\n                throw new RuntimeException(e);\n            }\n        }\n    }\n\n    public MappingMetaData getMapping(String index, String type) {\n        MappingMetaData mappingMetaData = null;\n        if (mode == ESClientMode.TRANSPORT) {\n            ImmutableOpenMap<String, MappingMetaData> mappings;\n            try {\n                mappings = transportClient.admin()\n                    .cluster()\n                    .prepareState()\n                    .execute()\n                    .actionGet()\n                    .getState()\n                    .getMetaData()\n                    .getIndices()\n                    .get(index)\n                    .getMappings();\n            } catch (NullPointerException e) {\n                throw new IllegalArgumentException(\"Not found the mapping info of index: \" + index);\n            }\n            mappingMetaData = mappings.get(type);\n\n        } else {\n            ImmutableOpenMap<String, ImmutableOpenMap<String, MappingMetaData>> mappings;\n            try {\n                GetMappingsRequest request = new GetMappingsRequest();\n                request.indices(index);\n                GetMappingsResponse response;\n                // try {\n                // response = restHighLevelClient\n                // .indices()\n                // .getMapping(request, RequestOptions.DEFAULT);\n                // // 6.4以下版本直接使用该接口会报错\n                // } catch (Exception e) {\n                // logger.warn(\"Low ElasticSearch version for getMapping\");\n                response = RestHighLevelClientExt.getMapping(restHighLevelClient, request, RequestOptions.DEFAULT);\n                // }\n\n                mappings = response.mappings();\n            } catch (NullPointerException e) {\n                throw new IllegalArgumentException(\"Not found the mapping info of index: \" + index);\n            } catch (IOException e) {\n                logger.error(e.getMessage(), e);\n                return null;\n            }\n\n            //通过别名查询mapping返回的是真实索引名称，mappings.get(index)返回null，为兼容别名情况修改如下：\n            ImmutableOpenMap<String, MappingMetaData> esIndex = mappings.get(index);\n            if(esIndex == null){\n                esIndex = mappings.valuesIt().next();\n            }\n            mappingMetaData = esIndex.get(type);\n        }\n        return mappingMetaData;\n    }\n\n    public class ES6xIndexRequest implements ESBulkRequest.ESIndexRequest {\n\n        private IndexRequestBuilder indexRequestBuilder;\n\n        private IndexRequest        indexRequest;\n\n        public ES6xIndexRequest(String index, String type, String id){\n            if (mode == ESClientMode.TRANSPORT) {\n                indexRequestBuilder = transportClient.prepareIndex(index, type, id);\n            } else {\n                indexRequest = new IndexRequest(index, type, id);\n            }\n        }\n\n        public ES6xIndexRequest setSource(Map<String, ?> source) {\n            if (mode == ESClientMode.TRANSPORT) {\n                indexRequestBuilder.setSource(source);\n            } else {\n                indexRequest.source(source);\n            }\n            return this;\n        }\n\n        public ES6xIndexRequest setRouting(String routing) {\n            if (mode == ESClientMode.TRANSPORT) {\n                indexRequestBuilder.setRouting(routing);\n            } else {\n                indexRequest.routing(routing);\n            }\n            return this;\n        }\n\n        public IndexRequestBuilder getIndexRequestBuilder() {\n            return indexRequestBuilder;\n        }\n\n        public void setIndexRequestBuilder(IndexRequestBuilder indexRequestBuilder) {\n            this.indexRequestBuilder = indexRequestBuilder;\n        }\n\n        public IndexRequest getIndexRequest() {\n            return indexRequest;\n        }\n\n        public void setIndexRequest(IndexRequest indexRequest) {\n            this.indexRequest = indexRequest;\n        }\n    }\n\n    public class ES6xUpdateRequest implements ESBulkRequest.ESUpdateRequest {\n\n        private UpdateRequestBuilder updateRequestBuilder;\n\n        private UpdateRequest        updateRequest;\n\n        public ES6xUpdateRequest(String index, String type, String id){\n            if (mode == ESClientMode.TRANSPORT) {\n                updateRequestBuilder = transportClient.prepareUpdate(index, type, id);\n            } else {\n                updateRequest = new UpdateRequest(index, type, id);\n            }\n        }\n\n        public ES6xUpdateRequest setDoc(Map source) {\n            if (mode == ESClientMode.TRANSPORT) {\n                updateRequestBuilder.setDoc(source);\n            } else {\n                updateRequest.doc(source);\n            }\n            return this;\n        }\n\n        public ES6xUpdateRequest setDocAsUpsert(boolean shouldUpsertDoc) {\n            if (mode == ESClientMode.TRANSPORT) {\n                updateRequestBuilder.setDocAsUpsert(shouldUpsertDoc);\n            } else {\n                updateRequest.docAsUpsert(shouldUpsertDoc);\n            }\n            return this;\n        }\n\n        public ES6xUpdateRequest setRouting(String routing) {\n            if (mode == ESClientMode.TRANSPORT) {\n                updateRequestBuilder.setRouting(routing);\n            } else {\n                updateRequest.routing(routing);\n            }\n            return this;\n        }\n\n        public UpdateRequestBuilder getUpdateRequestBuilder() {\n            return updateRequestBuilder;\n        }\n\n        public void setUpdateRequestBuilder(UpdateRequestBuilder updateRequestBuilder) {\n            this.updateRequestBuilder = updateRequestBuilder;\n        }\n\n        public UpdateRequest getUpdateRequest() {\n            return updateRequest;\n        }\n\n        public void setUpdateRequest(UpdateRequest updateRequest) {\n            this.updateRequest = updateRequest;\n        }\n    }\n\n    public class ES6xDeleteRequest implements ESBulkRequest.ESDeleteRequest {\n\n        private DeleteRequestBuilder deleteRequestBuilder;\n\n        private DeleteRequest        deleteRequest;\n\n        public ES6xDeleteRequest(String index, String type, String id){\n            if (mode == ESClientMode.TRANSPORT) {\n                deleteRequestBuilder = transportClient.prepareDelete(index, type, id);\n            } else {\n                deleteRequest = new DeleteRequest(index, type, id);\n            }\n        }\n\n        public DeleteRequestBuilder getDeleteRequestBuilder() {\n            return deleteRequestBuilder;\n        }\n\n        public void setDeleteRequestBuilder(DeleteRequestBuilder deleteRequestBuilder) {\n            this.deleteRequestBuilder = deleteRequestBuilder;\n        }\n\n        public DeleteRequest getDeleteRequest() {\n            return deleteRequest;\n        }\n\n        public void setDeleteRequest(DeleteRequest deleteRequest) {\n            this.deleteRequest = deleteRequest;\n        }\n    }\n\n    public class ESSearchRequest {\n\n        private SearchRequestBuilder searchRequestBuilder;\n\n        private SearchRequest        searchRequest;\n\n        private SearchSourceBuilder  sourceBuilder;\n\n        public ESSearchRequest(String index, String... types){\n            if (mode == ESClientMode.TRANSPORT) {\n                searchRequestBuilder = transportClient.prepareSearch(index).setTypes(types);\n            } else {\n                searchRequest = new SearchRequest(index).types(types);\n                sourceBuilder = new SearchSourceBuilder();\n            }\n        }\n\n        public ESSearchRequest setQuery(QueryBuilder queryBuilder) {\n            if (mode == ESClientMode.TRANSPORT) {\n                searchRequestBuilder.setQuery(queryBuilder);\n            } else {\n                sourceBuilder.query(queryBuilder);\n            }\n            return this;\n        }\n\n        public ESSearchRequest size(int size) {\n            if (mode == ESClientMode.TRANSPORT) {\n                searchRequestBuilder.setSize(size);\n            } else {\n                sourceBuilder.size(size);\n            }\n            return this;\n        }\n\n        public SearchResponse getResponse() {\n            if (mode == ESClientMode.TRANSPORT) {\n                return searchRequestBuilder.get();\n            } else {\n                searchRequest.source(sourceBuilder);\n                try {\n                    return restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);\n                } catch (IOException e) {\n                    throw new RuntimeException(e);\n                }\n            }\n        }\n\n        public SearchRequestBuilder getSearchRequestBuilder() {\n            return searchRequestBuilder;\n        }\n\n        public void setSearchRequestBuilder(SearchRequestBuilder searchRequestBuilder) {\n            this.searchRequestBuilder = searchRequestBuilder;\n        }\n\n        public SearchRequest getSearchRequest() {\n            return searchRequest;\n        }\n\n        public void setSearchRequest(SearchRequest searchRequest) {\n            this.searchRequest = searchRequest;\n        }\n    }\n\n    public class ES6xBulkRequest implements ESBulkRequest {\n\n        private BulkRequestBuilder bulkRequestBuilder;\n\n        private BulkRequest        bulkRequest;\n\n        public ES6xBulkRequest(){\n            if (mode == ESClientMode.TRANSPORT) {\n                bulkRequestBuilder = transportClient.prepareBulk();\n            } else {\n                bulkRequest = new BulkRequest();\n            }\n        }\n\n        public void resetBulk() {\n            if (mode == ESClientMode.TRANSPORT) {\n                bulkRequestBuilder = transportClient.prepareBulk();\n            } else {\n                bulkRequest = new BulkRequest();\n            }\n        }\n\n        public ES6xBulkRequest add(ESIndexRequest esIndexRequest) {\n            ES6xIndexRequest eir = (ES6xIndexRequest) esIndexRequest;\n            if (mode == ESClientMode.TRANSPORT) {\n                bulkRequestBuilder.add(eir.indexRequestBuilder);\n            } else {\n                bulkRequest.add(eir.indexRequest);\n            }\n            return this;\n        }\n\n        public ES6xBulkRequest add(ESUpdateRequest esUpdateRequest) {\n            ES6xUpdateRequest eur = (ES6xUpdateRequest) esUpdateRequest;\n            if (mode == ESClientMode.TRANSPORT) {\n                bulkRequestBuilder.add(eur.updateRequestBuilder);\n            } else {\n                bulkRequest.add(eur.updateRequest);\n            }\n            return this;\n        }\n\n        public ES6xBulkRequest add(ESDeleteRequest esDeleteRequest) {\n            ES6xDeleteRequest edr = (ES6xDeleteRequest) esDeleteRequest;\n            if (mode == ESClientMode.TRANSPORT) {\n                bulkRequestBuilder.add(edr.deleteRequestBuilder);\n            } else {\n                bulkRequest.add(edr.deleteRequest);\n            }\n            return this;\n        }\n\n        public int numberOfActions() {\n            if (mode == ESClientMode.TRANSPORT) {\n                return bulkRequestBuilder.numberOfActions();\n            } else {\n                return bulkRequest.numberOfActions();\n            }\n        }\n\n        @SuppressWarnings(\"deprecation\")\n        public ESBulkResponse bulk() {\n            if (mode == ESClientMode.TRANSPORT) {\n                BulkResponse responses = bulkRequestBuilder.execute().actionGet();\n                return new ES6xBulkResponse(responses);\n            } else {\n                try {\n                    BulkResponse responses = restHighLevelClient.bulk(bulkRequest);\n                    return new ES6xBulkResponse(responses);\n                } catch (IOException e) {\n                    throw new RuntimeException(e);\n                }\n            }\n        }\n\n        public BulkRequestBuilder getBulkRequestBuilder() {\n            return bulkRequestBuilder;\n        }\n\n        public void setBulkRequestBuilder(BulkRequestBuilder bulkRequestBuilder) {\n            this.bulkRequestBuilder = bulkRequestBuilder;\n        }\n\n        public BulkRequest getBulkRequest() {\n            return bulkRequest;\n        }\n\n        public void setBulkRequest(BulkRequest bulkRequest) {\n            this.bulkRequest = bulkRequest;\n        }\n    }\n\n    public static class ES6xBulkResponse implements ESBulkRequest.ESBulkResponse {\n\n        private BulkResponse bulkResponse;\n\n        public ES6xBulkResponse(BulkResponse bulkResponse){\n            this.bulkResponse = bulkResponse;\n        }\n\n        @Override\n        public boolean hasFailures() {\n            return bulkResponse.hasFailures();\n        }\n\n        @Override\n        public void processFailBulkResponse(String errorMsg) {\n            for (BulkItemResponse itemResponse : bulkResponse.getItems()) {\n                if (!itemResponse.isFailed()) {\n                    continue;\n                }\n\n                if (itemResponse.getFailure().getStatus() == RestStatus.NOT_FOUND) {\n                    logger.error(itemResponse.getFailureMessage());\n                } else {\n                    throw new RuntimeException(errorMsg + itemResponse.getFailureMessage());\n                }\n            }\n        }\n    }\n\n    // ------ get/set ------\n    public ESClientMode getMode() {\n        return mode;\n    }\n\n    public void setMode(ESClientMode mode) {\n        this.mode = mode;\n    }\n\n    public TransportClient getTransportClient() {\n        return transportClient;\n    }\n\n    public void setTransportClient(TransportClient transportClient) {\n        this.transportClient = transportClient;\n    }\n\n    public RestHighLevelClient getRestHighLevelClient() {\n        return restHighLevelClient;\n    }\n\n    public void setRestHighLevelClient(RestHighLevelClient restHighLevelClient) {\n        this.restHighLevelClient = restHighLevelClient;\n    }\n\n    private HttpHost createHttpHost(String uriStr) {\n        URI uri = URI.create(uriStr);\n        if (!org.springframework.util.StringUtils.hasLength(uri.getUserInfo())) {\n            return HttpHost.create(uri.toString());\n        }\n        try {\n            return HttpHost.create(new URI(uri.getScheme(), null, uri.getHost(), uri.getPort(), uri.getPath(),\n                                           uri.getQuery(), uri.getFragment()).toString());\n        } catch (URISyntaxException ex) {\n            throw new IllegalStateException(ex);\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/es6x/src/main/java/org/elasticsearch/client/RequestConvertersExt.java",
    "content": "package org.elasticsearch.client;\n\nimport java.io.IOException;\n\nimport org.apache.http.client.methods.HttpGet;\nimport org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest;\nimport org.elasticsearch.common.Strings;\n\n/**\n * RequestConverters扩展\n *\n * @author rewerma 2019-08-01\n * @version 1.0.0\n */\npublic class RequestConvertersExt {\n\n    /**\n     * 修改 getMappings 去掉request参数\n     *\n     * @param getMappingsRequest\n     * @return\n     * @throws IOException\n     */\n    static Request getMappings(GetMappingsRequest getMappingsRequest) throws IOException {\n        String[] indices = getMappingsRequest.indices() == null ? Strings.EMPTY_ARRAY : getMappingsRequest.indices();\n        String[] types = getMappingsRequest.types() == null ? Strings.EMPTY_ARRAY : getMappingsRequest.types();\n\n        return new Request(HttpGet.METHOD_NAME, RequestConverters.endpoint(indices, \"_mapping\", types));\n    }\n}\n"
  },
  {
    "path": "client-adapter/es6x/src/main/java/org/elasticsearch/client/RestHighLevelClientExt.java",
    "content": "package org.elasticsearch.client;\n\nimport static java.util.Collections.emptySet;\n\nimport java.io.IOException;\n\nimport org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest;\nimport org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse;\n\n/**\n * RestHighLevelClient扩展\n *\n * @author rewerma 2019-08-01\n * @version 1.0.0\n */\npublic class RestHighLevelClientExt {\n\n    public static GetMappingsResponse getMapping(RestHighLevelClient restHighLevelClient,\n                                                 GetMappingsRequest getMappingsRequest,\n                                                 RequestOptions options) throws IOException {\n        return restHighLevelClient.performRequestAndParseEntity(getMappingsRequest,\n            RequestConvertersExt::getMappings,\n            options,\n            GetMappingsResponse::fromXContent,\n            emptySet());\n\n    }\n\n}\n"
  },
  {
    "path": "client-adapter/es6x/src/main/resources/META-INF/canal/com.alibaba.otter.canal.client.adapter.OuterAdapter",
    "content": "es6=com.alibaba.otter.canal.client.adapter.es6x.ES6xAdapter\n"
  },
  {
    "path": "client-adapter/es6x/src/main/resources/es6/biz_order.yml",
    "content": "dataSourceKey: defaultDS\ndestination: example\ngroupId: g1\nesMapping:\n  _index: customer\n  _type: _doc\n  _id: _id\n  relations:\n    customer_order:\n      name: order\n      parent: customer_id\n  sql: \"select concat('oid_', t.id) as _id,\n        t.customer_id,\n        t.id as order_id,\n        t.serial_code as order_serial,\n        t.c_time as order_time\n        from biz_order t\"\n  skips:\n    - customer_id\n  etlCondition: \"where t.c_time>={}\"\n  commitBatch: 3000\n"
  },
  {
    "path": "client-adapter/es6x/src/main/resources/es6/customer.yml",
    "content": "dataSourceKey: defaultDS\ndestination: example\ngroupId: g1\nesMapping:\n  _index: customer\n  _type: _doc\n  _id: id\n  relations:\n    customer_order:\n      name: customer\n  sql: \"select t.id, t.name, t.email from customer t\"\n  etlCondition: \"where t.c_time>={}\"\n  commitBatch: 3000\n\n\n#{\n#  \"mappings\":{\n#    \"_doc\":{\n#      \"properties\":{\n#        \"id\": {\n#          \"type\": \"long\"\n#        },\n#        \"name\": {\n#          \"type\": \"text\"\n#        },\n#        \"email\": {\n#          \"type\": \"text\"\n#        },\n#        \"order_id\": {\n#          \"type\": \"long\"\n#        },\n#        \"order_serial\": {\n#          \"type\": \"text\"\n#        },\n#        \"order_time\": {\n#          \"type\": \"date\"\n#        },\n#        \"customer_order\":{\n#          \"type\":\"join\",\n#          \"relations\":{\n#            \"customer\":\"order\"\n#          }\n#        }\n#      }\n#    }\n#  }\n#}\n"
  },
  {
    "path": "client-adapter/es6x/src/main/resources/es6/mytest_user.yml",
    "content": "dataSourceKey: defaultDS\ndestination: example\ngroupId: g1\nesMapping:\n  _index: mytest_user\n  _type: _doc\n  _id: _id\n  upsert: true\n#  pk: id\n  sql: \"select a.id as _id, a.name as _name, a.role_id as _role_id, b.role_name as _role_name,\n        a.c_time as _c_time from user a\n        left join role b on b.id=a.role_id\"\n#  objFields:\n#    _labels: array:;\n  etlCondition: \"where a.c_time>={}\"\n  commitBatch: 3000\n"
  },
  {
    "path": "client-adapter/es6x/src/test/java/com/alibaba/otter/canal/client/adapter/es6x/test/ConfigLoadTest.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es6x.test;\n\nimport java.util.Map;\n\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfigLoader;\nimport com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;\n\n@Ignore\npublic class ConfigLoadTest {\n\n    @Before\n    public void before() {\n        // AdapterConfigs.put(\"es\", \"mytest_user.yml\");\n        // 加载数据源连接池\n        DatasourceConfig.DATA_SOURCES.put(\"defaultDS\", TestConstant.dataSource);\n    }\n\n    @Test\n    public void testLoad() {\n        Map<String, ESSyncConfig> configMap = ESSyncConfigLoader.load(null);\n        ESSyncConfig config = configMap.get(\"mytest_user.yml\");\n        config.validate();\n        Assert.assertNotNull(config);\n        Assert.assertEquals(\"defaultDS\", config.getDataSourceKey());\n        ESSyncConfig.ESMapping esMapping = config.getEsMapping();\n        Assert.assertEquals(\"mytest_user\", esMapping.getIndex());\n        Assert.assertEquals(\"_doc\", esMapping.getType());\n        Assert.assertEquals(\"id\", esMapping.getId());\n        Assert.assertNotNull(esMapping.getSql());\n\n        // Map<String, List<ESSyncConfig>> dbTableEsSyncConfig =\n        // ESSyncConfigLoader.getDbTableEsSyncConfig();\n        // Assert.assertFalse(dbTableEsSyncConfig.isEmpty());\n    }\n}\n"
  },
  {
    "path": "client-adapter/es6x/src/test/java/com/alibaba/otter/canal/client/adapter/es6x/test/ESTest.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es6x.test;\n\nimport java.net.InetAddress;\nimport java.net.UnknownHostException;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.elasticsearch.action.bulk.BulkItemResponse;\nimport org.elasticsearch.action.bulk.BulkRequestBuilder;\nimport org.elasticsearch.action.bulk.BulkResponse;\nimport org.elasticsearch.action.search.SearchResponse;\nimport org.elasticsearch.client.transport.TransportClient;\nimport org.elasticsearch.common.settings.Settings;\nimport org.elasticsearch.common.transport.TransportAddress;\nimport org.elasticsearch.index.query.QueryBuilders;\nimport org.elasticsearch.rest.RestStatus;\nimport org.elasticsearch.search.SearchHit;\nimport org.elasticsearch.transport.client.PreBuiltTransportClient;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\n@Ignore\npublic class ESTest {\n\n    private TransportClient transportClient;\n\n    @Before\n    public void init() throws UnknownHostException {\n        Settings.Builder settingBuilder = Settings.builder();\n        settingBuilder.put(\"cluster.name\", TestConstant.clusterName);\n        Settings settings = settingBuilder.build();\n        transportClient = new PreBuiltTransportClient(settings);\n        String[] hostArray = TestConstant.esHosts.split(\",\");\n        for (String host : hostArray) {\n            int i = host.indexOf(\":\");\n            transportClient.addTransportAddress(new TransportAddress(InetAddress.getByName(host.substring(0, i)),\n                Integer.parseInt(host.substring(i + 1))));\n        }\n    }\n\n    @Test\n    public void test01() {\n        SearchResponse response = transportClient.prepareSearch(\"test\")\n            .setTypes(\"osm\")\n            .setQuery(QueryBuilders.termQuery(\"_id\", \"1\"))\n            .setSize(10000)\n            .get();\n        for (SearchHit hit : response.getHits()) {\n            System.out.println(hit.getSourceAsMap().get(\"data\").getClass());\n        }\n    }\n\n    @Test\n    public void test02() {\n        Map<String, Object> esFieldData = new LinkedHashMap<>();\n        esFieldData.put(\"userId\", 2L);\n        esFieldData.put(\"eventId\", 4L);\n        esFieldData.put(\"eventName\", \"网络异常\");\n        esFieldData.put(\"description\", \"第四个事件信息\");\n\n        Map<String, Object> relations = new LinkedHashMap<>();\n        esFieldData.put(\"user_event\", relations);\n        relations.put(\"name\", \"event\");\n        relations.put(\"parent\", \"2\");\n\n        BulkRequestBuilder bulkRequestBuilder = transportClient.prepareBulk();\n        bulkRequestBuilder\n            .add(transportClient.prepareIndex(\"test\", \"osm\", \"2_4\").setRouting(\"2\").setSource(esFieldData));\n        commit(bulkRequestBuilder);\n    }\n\n    @Test\n    public void test03() {\n        Map<String, Object> esFieldData = new LinkedHashMap<>();\n        esFieldData.put(\"userId\", 2L);\n        esFieldData.put(\"eventName\", \"网络异常1\");\n\n        Map<String, Object> relations = new LinkedHashMap<>();\n        esFieldData.put(\"user_event\", relations);\n        relations.put(\"name\", \"event\");\n        relations.put(\"parent\", \"2\");\n\n        BulkRequestBuilder bulkRequestBuilder = transportClient.prepareBulk();\n        bulkRequestBuilder.add(transportClient.prepareUpdate(\"test\", \"osm\", \"2_4\").setRouting(\"2\").setDoc(esFieldData));\n        commit(bulkRequestBuilder);\n    }\n\n    @Test\n    public void test04() {\n        BulkRequestBuilder bulkRequestBuilder = transportClient.prepareBulk();\n        bulkRequestBuilder.add(transportClient.prepareDelete(\"test\", \"osm\", \"2_4\"));\n        commit(bulkRequestBuilder);\n    }\n\n    private void commit(BulkRequestBuilder bulkRequestBuilder) {\n        if (bulkRequestBuilder.numberOfActions() > 0) {\n            BulkResponse response = bulkRequestBuilder.execute().actionGet();\n            if (response.hasFailures()) {\n                for (BulkItemResponse itemResponse : response.getItems()) {\n                    if (!itemResponse.isFailed()) {\n                        continue;\n                    }\n\n                    if (itemResponse.getFailure().getStatus() == RestStatus.NOT_FOUND) {\n                        System.out.println(itemResponse.getFailureMessage());\n                    } else {\n                        System.out.println(\"ES bulk commit error\" + itemResponse.getFailureMessage());\n                    }\n                }\n            }\n        }\n    }\n\n    @After\n    public void after() {\n        transportClient.close();\n    }\n}\n"
  },
  {
    "path": "client-adapter/es6x/src/test/java/com/alibaba/otter/canal/client/adapter/es6x/test/SqlParseTest.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es6x.test;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem.FieldItem;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem.TableItem;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SqlParser;\n\npublic class SqlParseTest {\n\n    @Test\n    public void parseTest() {\n        String sql = \"select a.id, CASE WHEN a.id <= 500 THEN '1' else '2' end as id2, \"\n                     + \"concat(a.name,'_test') as name, a.role_id, b.name as role_name, c.labels from user a \"\n                     + \"left join role b on a.role_id=b.id \"\n                     + \"left join (select user_id, group_concat(label,',') as labels from user_label \"\n                     + \"group by user_id) c on c.user_id=a.id\";\n        SchemaItem schemaItem = SqlParser.parse(sql);\n\n        // 通过表名找 TableItem\n        List<TableItem> tableItems = schemaItem.getTableItemAliases().get(\"user_label\".toLowerCase());\n        tableItems.forEach(tableItem -> Assert.assertEquals(\"c\", tableItem.getAlias()));\n\n        TableItem tableItem = tableItems.get(0);\n        Assert.assertFalse(tableItem.isMain());\n        Assert.assertTrue(tableItem.isSubQuery());\n        // 通过字段名找 FieldItem\n        List<FieldItem> fieldItems = schemaItem.getColumnFields().get(tableItem.getAlias() + \".labels\".toLowerCase());\n        fieldItems.forEach(\n            fieldItem -> Assert.assertEquals(\"c.labels\", fieldItem.getOwner() + \".\" + fieldItem.getFieldName()));\n\n        // 获取当前表关联条件字段\n        Map<FieldItem, List<FieldItem>> relationTableFields = tableItem.getRelationTableFields();\n        relationTableFields.keySet()\n            .forEach(fieldItem -> Assert.assertEquals(\"user_id\", fieldItem.getColumn().getColumnName()));\n\n        // 获取关联字段在select中的对应字段\n        // List<FieldItem> relationSelectFieldItem =\n        // tableItem.getRelationKeyFieldItems();\n        // relationSelectFieldItem.forEach(fieldItem -> Assert.assertEquals(\"c.labels\",\n        // fieldItem.getOwner() + \".\" + fieldItem.getColumn().getColumnName()));\n    }\n}\n"
  },
  {
    "path": "client-adapter/es6x/src/test/java/com/alibaba/otter/canal/client/adapter/es6x/test/TestConstant.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es6x.test;\n\nimport java.sql.SQLException;\n\nimport com.alibaba.druid.pool.DruidDataSource;\n\npublic class TestConstant {\n\n    public final static String    jdbcUrl      = \"jdbc:mysql://127.0.0.1:3306/mytest?useUnicode=true\";\n    public final static String    jdbcUser     = \"root\";\n    public final static String    jdbcPassword = \"121212\";\n\n    public final static String    esHosts      = \"127.0.0.1:9300\";\n    public final static String    clusterName  = \"elasticsearch\";\n\n    public final static DruidDataSource dataSource;\n\n    static {\n        dataSource = new DruidDataSource();\n        dataSource.setDriverClassName(\"com.mysql.jdbc.Driver\");\n        dataSource.setUrl(jdbcUrl);\n        dataSource.setUsername(jdbcUser);\n        dataSource.setPassword(jdbcPassword);\n        dataSource.setInitialSize(1);\n        dataSource.setMinIdle(1);\n        dataSource.setMaxActive(1);\n        dataSource.setMaxWait(60000);\n        dataSource.setTimeBetweenEvictionRunsMillis(60000);\n        dataSource.setMinEvictableIdleTimeMillis(300000);\n        dataSource.setPoolPreparedStatements(false);\n        dataSource.setMaxPoolPreparedStatementPerConnectionSize(20);\n        dataSource.setValidationQuery(\"select 1\");\n        try {\n            dataSource.init();\n        } catch (SQLException e) {\n            e.printStackTrace();\n        }\n    }\n\n}\n"
  },
  {
    "path": "client-adapter/es6x/src/test/java/com/alibaba/otter/canal/client/adapter/es6x/test/sync/Common.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es6x.test.sync;\n\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport javax.sql.DataSource;\n\nimport com.alibaba.otter.canal.client.adapter.es6x.ES6xAdapter;\nimport com.alibaba.otter.canal.client.adapter.es6x.test.TestConstant;\nimport com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;\nimport com.alibaba.otter.canal.client.adapter.support.OuterAdapterConfig;\n\npublic class Common {\n\n    public static ES6xAdapter init() {\n        DatasourceConfig.DATA_SOURCES.put(\"defaultDS\", TestConstant.dataSource);\n\n        OuterAdapterConfig outerAdapterConfig = new OuterAdapterConfig();\n        outerAdapterConfig.setName(\"es\");\n        outerAdapterConfig.setHosts(TestConstant.esHosts);\n        Map<String, String> properties = new HashMap<>();\n        properties.put(\"cluster.name\", TestConstant.clusterName);\n        outerAdapterConfig.setProperties(properties);\n\n        ES6xAdapter esAdapter = new ES6xAdapter();\n        esAdapter.init(outerAdapterConfig, new Properties());\n        return esAdapter;\n    }\n\n    public static void sqlExe(DataSource dataSource, String sql) {\n        Connection conn = null;\n        Statement stmt = null;\n        try {\n            conn = dataSource.getConnection();\n            conn.setAutoCommit(false);\n            stmt = conn.createStatement();\n            stmt.execute(sql);\n            conn.commit();\n        } catch (Exception e) {\n            if (conn != null) {\n                try {\n                    conn.rollback();\n                } catch (SQLException e1) {\n                    // ignore\n                }\n            }\n            e.printStackTrace();\n        } finally {\n            if (stmt != null) {\n                try {\n                    stmt.close();\n                } catch (SQLException e) {\n                    // ignore\n                }\n            }\n            if (conn != null) {\n                try {\n                    conn.close();\n                } catch (SQLException e) {\n                    // ignore\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/es6x/src/test/java/com/alibaba/otter/canal/client/adapter/es6x/test/sync/LabelSyncJoinSub2Test.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es6x.test.sync;\n\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.elasticsearch.action.get.GetResponse;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig;\nimport com.alibaba.otter.canal.client.adapter.es6x.ES6xAdapter;\nimport com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\n\n@Ignore\npublic class LabelSyncJoinSub2Test {\n\n    private ES6xAdapter esAdapter;\n\n    @Before\n    public void init() {\n        // AdapterConfigs.put(\"es\", \"mytest_user_join_sub2.yml\");\n        esAdapter = Common.init();\n    }\n\n    /**\n     * 带函数子查询从表插入\n     */\n    @Test\n    public void test01() {\n        DataSource ds = DatasourceConfig.DATA_SOURCES.get(\"defaultDS\");\n        Common.sqlExe(ds, \"delete from label where id=1 or id=2\");\n        Common.sqlExe(ds, \"insert into label (id,user_id,label) values (1,1,'a')\");\n        Common.sqlExe(ds, \"insert into label (id,user_id,label) values (2,1,'b')\");\n\n        Dml dml = new Dml();\n        dml.setDestination(\"example\");\n        dml.setTs(new Date().getTime());\n        dml.setType(\"INSERT\");\n        dml.setDatabase(\"mytest\");\n        dml.setTable(\"label\");\n        List<Map<String, Object>> dataList = new ArrayList<>();\n        Map<String, Object> data = new LinkedHashMap<>();\n        dataList.add(data);\n        data.put(\"id\", 2L);\n        data.put(\"user_id\", 1L);\n        data.put(\"label\", \"b\");\n        dml.setData(dataList);\n\n        String database = dml.getDatabase();\n        String table = dml.getTable();\n        Map<String, ESSyncConfig> esSyncConfigs = esAdapter.getDbTableEsSyncConfig().get(database + \"-\" + table);\n\n        esAdapter.getEsSyncService().sync(esSyncConfigs.values(), dml);\n\n        GetResponse response = esAdapter.getEsConnection()\n            .getTransportClient()\n            .prepareGet(\"mytest_user\", \"_doc\", \"1\")\n            .get();\n        Assert.assertEquals(\"b;a_\", response.getSource().get(\"_labels\"));\n    }\n\n    /**\n     * 带函数子查询从表更新\n     */\n    @Test\n    public void test02() {\n        DataSource ds = DatasourceConfig.DATA_SOURCES.get(\"defaultDS\");\n        Common.sqlExe(ds, \"update label set label='aa' where id=1\");\n\n        Dml dml = new Dml();\n        dml.setDestination(\"example\");\n        dml.setTs(new Date().getTime());\n        dml.setType(\"UPDATE\");\n        dml.setDatabase(\"mytest\");\n        dml.setTable(\"label\");\n        List<Map<String, Object>> dataList = new ArrayList<>();\n        Map<String, Object> data = new LinkedHashMap<>();\n        dataList.add(data);\n        data.put(\"id\", 1L);\n        data.put(\"user_id\", 1L);\n        data.put(\"label\", \"aa\");\n        dml.setData(dataList);\n\n        List<Map<String, Object>> oldList = new ArrayList<>();\n        Map<String, Object> old = new LinkedHashMap<>();\n        oldList.add(old);\n        old.put(\"label\", \"v\");\n        dml.setOld(oldList);\n\n        String database = dml.getDatabase();\n        String table = dml.getTable();\n        Map<String, ESSyncConfig> esSyncConfigs = esAdapter.getDbTableEsSyncConfig().get(database + \"-\" + table);\n\n        esAdapter.getEsSyncService().sync(esSyncConfigs.values(), dml);\n\n        GetResponse response = esAdapter.getEsConnection()\n            .getTransportClient()\n            .prepareGet(\"mytest_user\", \"_doc\", \"1\")\n            .get();\n        Assert.assertEquals(\"b;aa_\", response.getSource().get(\"_labels\"));\n    }\n\n    /**\n     * 带函数子查询从表删除\n     */\n    @Test\n    public void test03() {\n        DataSource ds = DatasourceConfig.DATA_SOURCES.get(\"defaultDS\");\n        Common.sqlExe(ds, \"delete from label where id=1\");\n\n        Dml dml = new Dml();\n        dml.setDestination(\"example\");\n        dml.setTs(new Date().getTime());\n        dml.setType(\"DELETE\");\n        dml.setDatabase(\"mytest\");\n        dml.setTable(\"label\");\n        List<Map<String, Object>> dataList = new ArrayList<>();\n        Map<String, Object> data = new LinkedHashMap<>();\n        dataList.add(data);\n        data.put(\"id\", 1L);\n        data.put(\"user_id\", 1L);\n        data.put(\"label\", \"a\");\n        dml.setData(dataList);\n\n        String database = dml.getDatabase();\n        String table = dml.getTable();\n        Map<String, ESSyncConfig> esSyncConfigs = esAdapter.getDbTableEsSyncConfig().get(database + \"-\" + table);\n\n        esAdapter.getEsSyncService().sync(esSyncConfigs.values(), dml);\n\n        GetResponse response = esAdapter.getEsConnection()\n            .getTransportClient()\n            .prepareGet(\"mytest_user\", \"_doc\", \"1\")\n            .get();\n        Assert.assertEquals(\"b_\", response.getSource().get(\"_labels\"));\n    }\n}\n"
  },
  {
    "path": "client-adapter/es6x/src/test/java/com/alibaba/otter/canal/client/adapter/es6x/test/sync/LabelSyncJoinSubTest.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es6x.test.sync;\n\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.elasticsearch.action.get.GetResponse;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig;\nimport com.alibaba.otter.canal.client.adapter.es6x.ES6xAdapter;\nimport com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\n\n@Ignore\npublic class LabelSyncJoinSubTest {\n\n    private ES6xAdapter esAdapter;\n\n    @Before\n    public void init() {\n        // AdapterConfigs.put(\"es\", \"mytest_user_join_sub.yml\");\n        esAdapter = Common.init();\n    }\n\n    /**\n     * 子查询从表插入\n     */\n    @Test\n    public void test01() {\n        DataSource ds = DatasourceConfig.DATA_SOURCES.get(\"defaultDS\");\n        Common.sqlExe(ds, \"delete from label where id=1 or id=2\");\n        Common.sqlExe(ds, \"insert into label (id,user_id,label) values (1,1,'a')\");\n        Common.sqlExe(ds, \"insert into label (id,user_id,label) values (2,1,'b')\");\n\n        Dml dml = new Dml();\n        dml.setDestination(\"example\");\n        dml.setTs(new Date().getTime());\n        dml.setType(\"INSERT\");\n        dml.setDatabase(\"mytest\");\n        dml.setTable(\"label\");\n        List<Map<String, Object>> dataList = new ArrayList<>();\n        Map<String, Object> data = new LinkedHashMap<>();\n        dataList.add(data);\n        data.put(\"id\", 2L);\n        data.put(\"user_id\", 1L);\n        data.put(\"label\", \"b\");\n        dml.setData(dataList);\n\n        String database = dml.getDatabase();\n        String table = dml.getTable();\n        Map<String, ESSyncConfig> esSyncConfigs = esAdapter.getDbTableEsSyncConfig().get(database + \"-\" + table);\n\n        esAdapter.getEsSyncService().sync(esSyncConfigs.values(), dml);\n\n        GetResponse response = esAdapter.getEsConnection()\n            .getTransportClient()\n            .prepareGet(\"mytest_user\", \"_doc\", \"1\")\n            .get();\n        Assert.assertEquals(\"b;a\", response.getSource().get(\"_labels\"));\n    }\n\n    /**\n     * 子查询从表更新\n     */\n    @Test\n    public void test02() {\n        DataSource ds = DatasourceConfig.DATA_SOURCES.get(\"defaultDS\");\n        Common.sqlExe(ds, \"update label set label='aa' where id=1\");\n\n        Dml dml = new Dml();\n        dml.setDestination(\"example\");\n        dml.setTs(new Date().getTime());\n        dml.setType(\"UPDATE\");\n        dml.setDatabase(\"mytest\");\n        dml.setTable(\"label\");\n        List<Map<String, Object>> dataList = new ArrayList<>();\n        Map<String, Object> data = new LinkedHashMap<>();\n        dataList.add(data);\n        data.put(\"id\", 1L);\n        data.put(\"user_id\", 1L);\n        data.put(\"label\", \"aa\");\n        dml.setData(dataList);\n\n        List<Map<String, Object>> oldList = new ArrayList<>();\n        Map<String, Object> old = new LinkedHashMap<>();\n        oldList.add(old);\n        old.put(\"label\", \"a\");\n        dml.setOld(oldList);\n\n        String database = dml.getDatabase();\n        String table = dml.getTable();\n        Map<String, ESSyncConfig> esSyncConfigs = esAdapter.getDbTableEsSyncConfig().get(database + \"-\" + table);\n\n        esAdapter.getEsSyncService().sync(esSyncConfigs.values(), dml);\n\n        GetResponse response = esAdapter.getEsConnection()\n            .getTransportClient()\n            .prepareGet(\"mytest_user\", \"_doc\", \"1\")\n            .get();\n        Assert.assertEquals(\"b;aa\", response.getSource().get(\"_labels\"));\n    }\n\n    /**\n     * 子查询从表删除\n     */\n    @Test\n    public void test03() {\n        DataSource ds = DatasourceConfig.DATA_SOURCES.get(\"defaultDS\");\n        Common.sqlExe(ds, \"delete from label where id=1\");\n\n        Dml dml = new Dml();\n        dml.setDestination(\"example\");\n        dml.setTs(new Date().getTime());\n        dml.setType(\"DELETE\");\n        dml.setDatabase(\"mytest\");\n        dml.setTable(\"label\");\n        List<Map<String, Object>> dataList = new ArrayList<>();\n        Map<String, Object> data = new LinkedHashMap<>();\n        dataList.add(data);\n        data.put(\"id\", 1L);\n        data.put(\"user_id\", 1L);\n        data.put(\"label\", \"a\");\n        dml.setData(dataList);\n\n        String database = dml.getDatabase();\n        String table = dml.getTable();\n        Map<String, ESSyncConfig> esSyncConfigs = esAdapter.getDbTableEsSyncConfig().get(database + \"-\" + table);\n\n        esAdapter.getEsSyncService().sync(esSyncConfigs.values(), dml);\n\n        GetResponse response = esAdapter.getEsConnection()\n            .getTransportClient()\n            .prepareGet(\"mytest_user\", \"_doc\", \"1\")\n            .get();\n        Assert.assertEquals(\"b\", response.getSource().get(\"_labels\"));\n    }\n}\n"
  },
  {
    "path": "client-adapter/es6x/src/test/java/com/alibaba/otter/canal/client/adapter/es6x/test/sync/RoleSyncJoinOne2Test.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es6x.test.sync;\n\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.elasticsearch.action.get.GetResponse;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig;\nimport com.alibaba.otter.canal.client.adapter.es6x.ES6xAdapter;\nimport com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\n\n@Ignore\npublic class RoleSyncJoinOne2Test {\n\n    private ES6xAdapter esAdapter;\n\n    @Before\n    public void init() {\n        // AdapterConfigs.put(\"es\", \"mytest_user_join_one2.yml\");\n        esAdapter = Common.init();\n    }\n\n    /**\n     * 带函数非子查询从表插入\n     */\n    @Test\n    public void test01() {\n        DataSource ds = DatasourceConfig.DATA_SOURCES.get(\"defaultDS\");\n        Common.sqlExe(ds, \"delete from role where id=1\");\n        Common.sqlExe(ds, \"insert into role (id,role_name) values (1,'admin')\");\n\n        Dml dml = new Dml();\n        dml.setDestination(\"example\");\n        dml.setTs(new Date().getTime());\n        dml.setType(\"INSERT\");\n        dml.setDatabase(\"mytest\");\n        dml.setTable(\"role\");\n        List<Map<String, Object>> dataList = new ArrayList<>();\n        Map<String, Object> data = new LinkedHashMap<>();\n        dataList.add(data);\n        data.put(\"id\", 1L);\n        data.put(\"role_name\", \"admin\");\n        dml.setData(dataList);\n\n        String database = dml.getDatabase();\n        String table = dml.getTable();\n        Map<String, ESSyncConfig> esSyncConfigs = esAdapter.getDbTableEsSyncConfig().get(database + \"-\" + table);\n\n        esAdapter.getEsSyncService().sync(esSyncConfigs.values(), dml);\n\n        GetResponse response = esAdapter.getEsConnection()\n            .getTransportClient()\n            .prepareGet(\"mytest_user\", \"_doc\", \"1\")\n            .get();\n        Assert.assertEquals(\"admin_\", response.getSource().get(\"_role_name\"));\n    }\n\n    /**\n     * 带函数非子查询从表更新\n     */\n    @Test\n    public void test02() {\n        DataSource ds = DatasourceConfig.DATA_SOURCES.get(\"defaultDS\");\n        Common.sqlExe(ds, \"update role set role_name='admin3' where id=1\");\n\n        Dml dml = new Dml();\n        dml.setDestination(\"example\");\n        dml.setTs(new Date().getTime());\n        dml.setType(\"UPDATE\");\n        dml.setDatabase(\"mytest\");\n        dml.setTable(\"role\");\n        List<Map<String, Object>> dataList = new ArrayList<>();\n        Map<String, Object> data = new LinkedHashMap<>();\n        dataList.add(data);\n        data.put(\"id\", 1L);\n        data.put(\"role_name\", \"admin3\");\n        dml.setData(dataList);\n\n        List<Map<String, Object>> oldList = new ArrayList<>();\n        Map<String, Object> old = new LinkedHashMap<>();\n        oldList.add(old);\n        old.put(\"role_name\", \"admin\");\n        dml.setOld(oldList);\n\n        String database = dml.getDatabase();\n        String table = dml.getTable();\n        Map<String, ESSyncConfig> esSyncConfigs = esAdapter.getDbTableEsSyncConfig().get(database + \"-\" + table);\n\n        esAdapter.getEsSyncService().sync(esSyncConfigs.values(), dml);\n\n        GetResponse response = esAdapter.getEsConnection()\n            .getTransportClient()\n            .prepareGet(\"mytest_user\", \"_doc\", \"1\")\n            .get();\n        Assert.assertEquals(\"admin3_\", response.getSource().get(\"_role_name\"));\n    }\n}\n"
  },
  {
    "path": "client-adapter/es6x/src/test/java/com/alibaba/otter/canal/client/adapter/es6x/test/sync/RoleSyncJoinOneTest.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es6x.test.sync;\n\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.elasticsearch.action.get.GetResponse;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig;\nimport com.alibaba.otter.canal.client.adapter.es6x.ES6xAdapter;\nimport com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\n\n@Ignore\npublic class RoleSyncJoinOneTest {\n\n    private ES6xAdapter esAdapter;\n\n    @Before\n    public void init() {\n        // AdapterConfigs.put(\"es\", \"mytest_user_join_one.yml\");\n        esAdapter = Common.init();\n    }\n\n    /**\n     * 非子查询从表插入\n     */\n    @Test\n    public void test01() {\n        DataSource ds = DatasourceConfig.DATA_SOURCES.get(\"defaultDS\");\n        Common.sqlExe(ds, \"delete from role where id=1\");\n        Common.sqlExe(ds, \"insert into role (id,role_name) values (1,'admin')\");\n\n        Dml dml = new Dml();\n        dml.setDestination(\"example\");\n        dml.setTs(new Date().getTime());\n        dml.setType(\"INSERT\");\n        dml.setDatabase(\"mytest\");\n        dml.setTable(\"role\");\n        List<Map<String, Object>> dataList = new ArrayList<>();\n        Map<String, Object> data = new LinkedHashMap<>();\n        dataList.add(data);\n        data.put(\"id\", 1L);\n        data.put(\"role_name\", \"admin\");\n\n        dml.setData(dataList);\n\n        String database = dml.getDatabase();\n        String table = dml.getTable();\n        Map<String, ESSyncConfig> esSyncConfigs = esAdapter.getDbTableEsSyncConfig().get(database + \"-\" + table);\n\n        esAdapter.getEsSyncService().sync(esSyncConfigs.values(), dml);\n\n        GetResponse response = esAdapter.getEsConnection()\n            .getTransportClient()\n            .prepareGet(\"mytest_user\", \"_doc\", \"1\")\n            .get();\n        Assert.assertEquals(\"admin\", response.getSource().get(\"_role_name\"));\n    }\n\n    /**\n     * 非子查询从表更新\n     */\n    @Test\n    public void test02() {\n        DataSource ds = DatasourceConfig.DATA_SOURCES.get(\"defaultDS\");\n        Common.sqlExe(ds, \"update role set role_name='admin2' where id=1\");\n\n        Dml dml = new Dml();\n        dml.setDestination(\"example\");\n        dml.setTs(new Date().getTime());\n        dml.setType(\"UPDATE\");\n        dml.setDatabase(\"mytest\");\n        dml.setTable(\"role\");\n        List<Map<String, Object>> dataList = new ArrayList<>();\n        Map<String, Object> data = new LinkedHashMap<>();\n        dataList.add(data);\n        data.put(\"id\", 1L);\n        data.put(\"role_name\", \"admin2\");\n        dml.setData(dataList);\n\n        List<Map<String, Object>> oldList = new ArrayList<>();\n        Map<String, Object> old = new LinkedHashMap<>();\n        oldList.add(old);\n        old.put(\"role_name\", \"admin\");\n        dml.setOld(oldList);\n\n        String database = dml.getDatabase();\n        String table = dml.getTable();\n        Map<String, ESSyncConfig> esSyncConfigs = esAdapter.getDbTableEsSyncConfig().get(database + \"-\" + table);\n\n        esAdapter.getEsSyncService().sync(esSyncConfigs.values(), dml);\n\n        GetResponse response = esAdapter.getEsConnection()\n            .getTransportClient()\n            .prepareGet(\"mytest_user\", \"_doc\", \"1\")\n            .get();\n        Assert.assertEquals(\"admin2\", response.getSource().get(\"_role_name\"));\n    }\n\n    /**\n     * 主表更新外键值\n     */\n    @Test\n    public void test03() {\n        DataSource ds = DatasourceConfig.DATA_SOURCES.get(\"defaultDS\");\n        Common.sqlExe(ds, \"delete from role where id=2\");\n        Common.sqlExe(ds, \"insert into role (id,role_name) values (2,'operator')\");\n        Common.sqlExe(ds, \"update user set role_id=2 where id=1\");\n\n        Dml dml = new Dml();\n        dml.setDestination(\"example\");\n        dml.setTs(new Date().getTime());\n        dml.setType(\"UPDATE\");\n        dml.setDatabase(\"mytest\");\n        dml.setTable(\"user\");\n        List<Map<String, Object>> dataList = new ArrayList<>();\n        Map<String, Object> data = new LinkedHashMap<>();\n        dataList.add(data);\n        data.put(\"id\", 1L);\n        data.put(\"role_id\", 2L);\n        dml.setData(dataList);\n        List<Map<String, Object>> oldList = new ArrayList<>();\n        Map<String, Object> old = new LinkedHashMap<>();\n        oldList.add(old);\n        old.put(\"role_id\", 1L);\n        dml.setOld(oldList);\n\n        String database = dml.getDatabase();\n        String table = dml.getTable();\n        Map<String, ESSyncConfig> esSyncConfigs = esAdapter.getDbTableEsSyncConfig().get(database + \"-\" + table);\n\n        esAdapter.getEsSyncService().sync(esSyncConfigs.values(), dml);\n\n        GetResponse response = esAdapter.getEsConnection()\n            .getTransportClient()\n            .prepareGet(\"mytest_user\", \"_doc\", \"1\")\n            .get();\n        Assert.assertEquals(\"operator\", response.getSource().get(\"_role_name\"));\n\n        Common.sqlExe(ds, \"update user set role_id=1 where id=1\");\n\n        Dml dml2 = new Dml();\n        dml2.setDestination(\"example\");\n        dml2.setTs(new Date().getTime());\n        dml2.setType(\"UPDATE\");\n        dml2.setDatabase(\"mytest\");\n        dml2.setTable(\"user\");\n        List<Map<String, Object>> dataList2 = new ArrayList<>();\n        Map<String, Object> data2 = new LinkedHashMap<>();\n        dataList2.add(data2);\n        data2.put(\"id\", 1L);\n        data2.put(\"role_id\", 1L);\n        dml2.setData(dataList2);\n        List<Map<String, Object>> oldList2 = new ArrayList<>();\n        Map<String, Object> old2 = new LinkedHashMap<>();\n        oldList2.add(old2);\n        old2.put(\"role_id\", 2L);\n        dml2.setOld(oldList2);\n\n        esAdapter.getEsSyncService().sync(esSyncConfigs.values(), dml2);\n\n        GetResponse response2 = esAdapter.getEsConnection()\n            .getTransportClient()\n            .prepareGet(\"mytest_user\", \"_doc\", \"1\")\n            .get();\n        Assert.assertEquals(\"admin2\", response2.getSource().get(\"_role_name\"));\n    }\n\n    /**\n     * 非子查询从表删除\n     */\n    @Test\n    public void test04() {\n        DataSource ds = DatasourceConfig.DATA_SOURCES.get(\"defaultDS\");\n        Common.sqlExe(ds, \"delete from role where id=1\");\n\n        Dml dml = new Dml();\n        dml.setDestination(\"example\");\n        dml.setTs(new Date().getTime());\n        dml.setType(\"DELETE\");\n        dml.setDatabase(\"mytest\");\n        dml.setTable(\"role\");\n        List<Map<String, Object>> dataList = new ArrayList<>();\n        Map<String, Object> data = new LinkedHashMap<>();\n        dataList.add(data);\n        data.put(\"id\", 1L);\n        data.put(\"role_name\", \"admin\");\n\n        dml.setData(dataList);\n\n        String database = dml.getDatabase();\n        String table = dml.getTable();\n        Map<String, ESSyncConfig> esSyncConfigs = esAdapter.getDbTableEsSyncConfig().get(database + \"-\" + table);\n\n        esAdapter.getEsSyncService().sync(esSyncConfigs.values(), dml);\n\n        GetResponse response = esAdapter.getEsConnection()\n            .getTransportClient()\n            .prepareGet(\"mytest_user\", \"_doc\", \"1\")\n            .get();\n        Assert.assertNull(response.getSource().get(\"_role_name\"));\n    }\n}\n"
  },
  {
    "path": "client-adapter/es6x/src/test/java/com/alibaba/otter/canal/client/adapter/es6x/test/sync/UserSyncJoinOneTest.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es6x.test.sync;\n\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.elasticsearch.action.get.GetResponse;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig;\nimport com.alibaba.otter.canal.client.adapter.es6x.ES6xAdapter;\nimport com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\n\n@Ignore\npublic class UserSyncJoinOneTest {\n\n    private ES6xAdapter esAdapter;\n\n    @Before\n    public void init() {\n        // AdapterConfigs.put(\"es\", \"mytest_user_join_one.yml\");\n        esAdapter = Common.init();\n    }\n\n    /**\n     * 主表带函数插入\n     */\n    @Test\n    public void test01() {\n        DataSource ds = DatasourceConfig.DATA_SOURCES.get(\"defaultDS\");\n        Common.sqlExe(ds, \"delete from user where id=1\");\n        Common.sqlExe(ds, \"insert into user (id,name,role_id) values (1,'Eric',1)\");\n\n        Dml dml = new Dml();\n        dml.setDestination(\"example\");\n        dml.setTs(new Date().getTime());\n        dml.setType(\"INSERT\");\n        dml.setDatabase(\"mytest\");\n        dml.setTable(\"user\");\n        List<Map<String, Object>> dataList = new ArrayList<>();\n        Map<String, Object> data = new LinkedHashMap<>();\n        dataList.add(data);\n        data.put(\"id\", 1L);\n        data.put(\"name\", \"Eric\");\n        data.put(\"role_id\", 1L);\n        data.put(\"c_time\", new Date());\n        dml.setData(dataList);\n\n        String database = dml.getDatabase();\n        String table = dml.getTable();\n        Map<String, ESSyncConfig> esSyncConfigs = esAdapter.getDbTableEsSyncConfig().get(database + \"-\" + table);\n\n        esAdapter.getEsSyncService().sync(esSyncConfigs.values(), dml);\n\n        GetResponse response = esAdapter.getEsConnection()\n            .getTransportClient()\n            .prepareGet(\"mytest_user\", \"_doc\", \"1\")\n            .get();\n        Assert.assertEquals(\"Eric_\", response.getSource().get(\"_name\"));\n    }\n\n    /**\n     * 主表带函数更新\n     */\n    @Test\n    public void test02() {\n        DataSource ds = DatasourceConfig.DATA_SOURCES.get(\"defaultDS\");\n        Common.sqlExe(ds, \"update user set name='Eric2' where id=1\");\n\n        Dml dml = new Dml();\n        dml.setDestination(\"example\");\n        dml.setTs(new Date().getTime());\n        dml.setType(\"UPDATE\");\n        dml.setDatabase(\"mytest\");\n        dml.setTable(\"user\");\n        List<Map<String, Object>> dataList = new ArrayList<>();\n        Map<String, Object> data = new LinkedHashMap<>();\n        dataList.add(data);\n        data.put(\"id\", 1L);\n        data.put(\"name\", \"Eric2\");\n        dml.setData(dataList);\n        List<Map<String, Object>> oldList = new ArrayList<>();\n        Map<String, Object> old = new LinkedHashMap<>();\n        oldList.add(old);\n        old.put(\"name\", \"Eric\");\n        dml.setOld(oldList);\n\n        String database = dml.getDatabase();\n        String table = dml.getTable();\n        Map<String, ESSyncConfig> esSyncConfigs = esAdapter.getDbTableEsSyncConfig().get(database + \"-\" + table);\n\n        esAdapter.getEsSyncService().sync(esSyncConfigs.values(), dml);\n\n        GetResponse response = esAdapter.getEsConnection()\n            .getTransportClient()\n            .prepareGet(\"mytest_user\", \"_doc\", \"1\")\n            .get();\n        Assert.assertEquals(\"Eric2_\", response.getSource().get(\"_name\"));\n    }\n}\n"
  },
  {
    "path": "client-adapter/es6x/src/test/java/com/alibaba/otter/canal/client/adapter/es6x/test/sync/UserSyncSingleTest.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es6x.test.sync;\n\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.elasticsearch.action.get.GetResponse;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig;\nimport com.alibaba.otter.canal.client.adapter.es6x.ES6xAdapter;\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\n\n@Ignore\npublic class UserSyncSingleTest {\n\n    private ES6xAdapter esAdapter;\n\n    @Before\n    public void init() {\n        // AdapterConfigs.put(\"es\", \"mytest_user_single.yml\");\n        esAdapter = Common.init();\n    }\n\n    /**\n     * 单表插入\n     */\n    @Test\n    public void test01() {\n        Dml dml = new Dml();\n        dml.setDestination(\"example\");\n        dml.setTs(new Date().getTime());\n        dml.setType(\"INSERT\");\n        dml.setDatabase(\"mytest\");\n        dml.setTable(\"user\");\n        List<Map<String, Object>> dataList = new ArrayList<>();\n        Map<String, Object> data = new LinkedHashMap<>();\n        dataList.add(data);\n        data.put(\"id\", 1L);\n        data.put(\"name\", \"Eric\");\n        data.put(\"role_id\", 1L);\n        data.put(\"c_time\", new Date());\n        dml.setData(dataList);\n\n        String database = dml.getDatabase();\n        String table = dml.getTable();\n        Map<String, ESSyncConfig> esSyncConfigs = esAdapter.getDbTableEsSyncConfig().get(database + \"-\" + table);\n\n        esAdapter.getEsSyncService().sync(esSyncConfigs.values(), dml);\n\n        GetResponse response = esAdapter.getEsConnection()\n            .getTransportClient()\n            .prepareGet(\"mytest_user\", \"_doc\", \"1\")\n            .get();\n        Assert.assertEquals(\"Eric\", response.getSource().get(\"_name\"));\n    }\n\n    /**\n     * 单表更新\n     */\n    @Test\n    public void test02() {\n        Dml dml = new Dml();\n        dml.setDestination(\"example\");\n        dml.setTs(new Date().getTime());\n        dml.setType(\"UPDATE\");\n        dml.setDatabase(\"mytest\");\n        dml.setTable(\"user\");\n        List<Map<String, Object>> dataList = new ArrayList<>();\n        Map<String, Object> data = new LinkedHashMap<>();\n        dataList.add(data);\n        data.put(\"id\", 1L);\n        data.put(\"name\", \"Eric2\");\n        dml.setData(dataList);\n        List<Map<String, Object>> oldList = new ArrayList<>();\n        Map<String, Object> old = new LinkedHashMap<>();\n        oldList.add(old);\n        old.put(\"name\", \"Eric\");\n        dml.setOld(oldList);\n\n        String database = dml.getDatabase();\n        String table = dml.getTable();\n        Map<String, ESSyncConfig> esSyncConfigs = esAdapter.getDbTableEsSyncConfig().get(database + \"-\" + table);\n\n        esAdapter.getEsSyncService().sync(esSyncConfigs.values(), dml);\n\n        GetResponse response = esAdapter.getEsConnection()\n            .getTransportClient()\n            .prepareGet(\"mytest_user\", \"_doc\", \"1\")\n            .get();\n        Assert.assertEquals(\"Eric2\", response.getSource().get(\"_name\"));\n    }\n\n    /**\n     * 单表删除\n     */\n    @Test\n    public void test03() {\n        Dml dml = new Dml();\n        dml.setDestination(\"example\");\n        dml.setTs(new Date().getTime());\n        dml.setType(\"DELETE\");\n        dml.setDatabase(\"mytest\");\n        dml.setTable(\"user\");\n        List<Map<String, Object>> dataList = new ArrayList<>();\n        Map<String, Object> data = new LinkedHashMap<>();\n        dataList.add(data);\n        data.put(\"id\", 1L);\n        data.put(\"name\", \"Eric\");\n        data.put(\"role_id\", 1L);\n        data.put(\"c_time\", new Date());\n        dml.setData(dataList);\n\n        String database = dml.getDatabase();\n        String table = dml.getTable();\n        Map<String, ESSyncConfig> esSyncConfigs = esAdapter.getDbTableEsSyncConfig().get(database + \"-\" + table);\n\n        esAdapter.getEsSyncService().sync(esSyncConfigs.values(), dml);\n\n        GetResponse response = esAdapter.getEsConnection()\n            .getTransportClient()\n            .prepareGet(\"mytest_user\", \"_doc\", \"1\")\n            .get();\n        Assert.assertNull(response.getSource());\n    }\n\n    // @After\n    // public void after() {\n    // esAdapter.destroy();\n    // DatasourceConfig.DATA_SOURCES.values().forEach(DruidDataSource::close);\n    // }\n}\n"
  },
  {
    "path": "client-adapter/es6x/src/test/java/com/alibaba/otter/canal/client/adapter/es6x/test/sync/db_schema.sql",
    "content": "-- ----------------------------\n-- Table structure for label\n-- ----------------------------\nDROP TABLE IF EXISTS `label`;\nCREATE TABLE `label` (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT,\n  `user_id` bigint(20) NOT NULL,\n  `label` varchar(30) NOT NULL,\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;\n\n-- ----------------------------\n-- Table structure for role\n-- ----------------------------\nDROP TABLE IF EXISTS `role`;\nCREATE TABLE `role` (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT,\n  `role_name` varchar(30) NOT NULL,\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;\n\n-- ----------------------------\n-- Table structure for user\n-- ----------------------------\nDROP TABLE IF EXISTS `user`;\nCREATE TABLE `user` (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT,\n  `name` varchar(30) NOT NULL,\n  `c_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,\n  `role_id` bigint(20) DEFAULT NULL,\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;\n\ninsert into user (id,name,role_id) values (1,'Eric',1);\ninsert into role (id,role_name) values (1,'admin');\ninsert into role (id,role_name) values (2,'operator');\ninsert into label (id,user_id,label) values (1,1,'a');\ninsert into label (id,user_id,label) values (2,1,'b');\ncommit;"
  },
  {
    "path": "client-adapter/es6x/src/test/java/com/alibaba/otter/canal/client/adapter/es6x/test/sync/es_mapping.json",
    "content": "{\n  \"_doc\": {\n    \"properties\": {\n      \"_name\": {\n        \"type\": \"text\"\n      },\n      \"_role_id\": {\n        \"type\": \"long\"\n      },\n      \"_role_name\": {\n        \"type\": \"text\"\n      },\n      \"_labels\": {\n        \"type\": \"text\"\n      },\n      \"_c_time\": {\n        \"type\": \"date\"\n      }\n    }\n  }\n}"
  },
  {
    "path": "client-adapter/es6x/src/test/resources/es6/mytest_user_single.yml",
    "content": "dataSourceKey: defaultDS\ndestination: example\nesMapping:\n  _index: mytest_user\n  _type: _doc\n  _id: _id\n  sql: \"select a.id as _id, a.name as _name, a.role_id as _role_id, a.c_time as _c_time from user a\"\n  commitBatch: 3000"
  },
  {
    "path": "client-adapter/es6x/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"ERROR\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>"
  },
  {
    "path": "client-adapter/es6x/src/test/resources/logback-test.xml",
    "content": "<configuration scan=\"true\" scanPeriod=\" 5 seconds\">\n\t<jmxConfigurator />\n\t<appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n\t\t<encoder>\n\t\t\t<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{56} - %msg%n\n\t\t\t</pattern>\n\t\t</encoder>\n\t</appender>\n\n\t<root level=\"TRACE\">\n\t\t<appender-ref ref=\"STDOUT\"/>\n\t</root>\n</configuration>"
  },
  {
    "path": "client-adapter/es7x/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>canal.client-adapter</artifactId>\n        <groupId>com.alibaba.otter</groupId>\n        <version>1.1.9-SNAPSHOT</version>\n        <relativePath>../pom.xml</relativePath>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>com.alibaba.otter</groupId>\n    <artifactId>client-adapter.es7x</artifactId>\n    <packaging>jar</packaging>\n    <name>canal client adapter es v7x module for otter ${project.version}</name>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>client-adapter.common</artifactId>\n            <version>${project.version}</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>client-adapter.escore</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.elasticsearch</groupId>\n            <artifactId>elasticsearch</artifactId>\n            <version>7.3.0</version>\n        </dependency>\n        <dependency>\n            <groupId>org.elasticsearch.client</groupId>\n            <artifactId>transport</artifactId>\n            <version>7.3.0</version>\n        </dependency>\n        <dependency>\n            <groupId>org.elasticsearch.client</groupId>\n            <artifactId>elasticsearch-rest-client</artifactId>\n            <version>7.3.0</version>\n        </dependency>\n        <dependency>\n            <groupId>org.elasticsearch.client</groupId>\n            <artifactId>elasticsearch-rest-high-level-client</artifactId>\n            <version>7.3.0</version>\n        </dependency>\n\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-assembly-plugin</artifactId>\n                <version>2.4</version>\n                <configuration>\n                    <descriptorRefs>\n                        <descriptorRef>jar-with-dependencies</descriptorRef>\n                    </descriptorRefs>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>make-assembly</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>single</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-antrun-plugin</artifactId>\n                <version>1.8</version>\n                <executions>\n                    <execution>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>run</goal>\n                        </goals>\n                        <configuration>\n                            <tasks>\n                                <copy todir=\"${project.basedir}/../launcher/target/classes/es7\" overwrite=\"true\">\n                                    <fileset dir=\"${project.basedir}/target/classes/es7\" erroronmissingdir=\"true\">\n                                        <include name=\"*.yml\" />\n                                    </fileset>\n                                </copy>\n                            </tasks>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "client-adapter/es7x/src/main/java/com/alibaba/otter/canal/client/adapter/es7x/ES7xAdapter.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es7x;\n\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport javax.sql.DataSource;\n\nimport org.elasticsearch.action.search.SearchResponse;\n\nimport com.alibaba.otter.canal.client.adapter.es.core.ESAdapter;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig;\nimport com.alibaba.otter.canal.client.adapter.es7x.etl.ESEtlService;\nimport com.alibaba.otter.canal.client.adapter.es7x.support.ES7xTemplate;\nimport com.alibaba.otter.canal.client.adapter.es7x.support.ESConnection;\nimport com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;\nimport com.alibaba.otter.canal.client.adapter.support.EtlResult;\nimport com.alibaba.otter.canal.client.adapter.support.OuterAdapterConfig;\nimport com.alibaba.otter.canal.client.adapter.support.SPI;\n\n/**\n * ES 7.x 外部适配器\n *\n * @author rewerma 2019-09-23\n * @version 1.0.0\n */\n@SPI(\"es7\")\npublic class ES7xAdapter extends ESAdapter {\n\n    private ESConnection esConnection;\n\n    public ESConnection getEsConnection() {\n        return esConnection;\n    }\n\n    @Override\n    public void init(OuterAdapterConfig configuration, Properties envProperties) {\n        try {\n            Map<String, String> properties = configuration.getProperties();\n\n            String[] hostArray = configuration.getHosts().split(\",\");\n            String mode = properties.get(\"mode\");\n            if (\"rest\".equalsIgnoreCase(mode) || \"http\".equalsIgnoreCase(mode)) {\n                esConnection = new ESConnection(hostArray, properties, ESConnection.ESClientMode.REST);\n            } else {\n                esConnection = new ESConnection(hostArray, properties, ESConnection.ESClientMode.TRANSPORT);\n            }\n            this.esTemplate = new ES7xTemplate(esConnection);\n\n            envProperties.put(\"es.version\", \"es7\");\n            super.init(configuration, envProperties);\n        } catch (Throwable e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    @Override\n    public Map<String, Object> count(String task) {\n        ESSyncConfig config = esSyncConfig.get(task);\n        ESSyncConfig.ESMapping mapping = config.getEsMapping();\n        SearchResponse response = this.esConnection.new ESSearchRequest(mapping.getIndex()).size(0).getResponse();\n\n        long rowCount = response.getHits().getTotalHits().value;\n        Map<String, Object> res = new LinkedHashMap<>();\n        res.put(\"esIndex\", mapping.getIndex());\n        res.put(\"count\", rowCount);\n        return res;\n    }\n\n    @Override\n    public EtlResult etl(String task, List<String> params) {\n        EtlResult etlResult = new EtlResult();\n        ESSyncConfig config = esSyncConfig.get(task);\n        if (config != null) {\n            DataSource dataSource = DatasourceConfig.DATA_SOURCES.get(config.getDataSourceKey());\n            ESEtlService esEtlService = new ESEtlService(esConnection, config);\n            if (dataSource != null) {\n                return esEtlService.importData(params);\n            } else {\n                etlResult.setSucceeded(false);\n                etlResult.setErrorMessage(\"DataSource not found\");\n                return etlResult;\n            }\n        } else {\n            StringBuilder resultMsg = new StringBuilder();\n            boolean resSuccess = true;\n            for (ESSyncConfig configTmp : esSyncConfig.values()) {\n                // 取所有的destination为task的配置\n                if (configTmp.getDestination().equals(task)) {\n                    ESEtlService esEtlService = new ESEtlService(esConnection, configTmp);\n                    EtlResult etlRes = esEtlService.importData(params);\n                    if (!etlRes.getSucceeded()) {\n                        resSuccess = false;\n                        resultMsg.append(etlRes.getErrorMessage()).append(\"\\n\");\n                    } else {\n                        resultMsg.append(etlRes.getResultMessage()).append(\"\\n\");\n                    }\n                }\n            }\n            if (resultMsg.length() > 0) {\n                etlResult.setSucceeded(resSuccess);\n                if (resSuccess) {\n                    etlResult.setResultMessage(resultMsg.toString());\n                } else {\n                    etlResult.setErrorMessage(resultMsg.toString());\n                }\n                return etlResult;\n            }\n        }\n        etlResult.setSucceeded(false);\n        etlResult.setErrorMessage(\"Task not found\");\n        return etlResult;\n    }\n\n    @Override\n    public void destroy() {\n        super.destroy();\n        if (esConnection != null) {\n            esConnection.close();\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/es7x/src/main/java/com/alibaba/otter/canal/client/adapter/es7x/etl/ESEtlService.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es7x.etl;\n\nimport java.sql.SQLException;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport javax.sql.DataSource;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.elasticsearch.action.search.SearchResponse;\nimport org.elasticsearch.index.query.QueryBuilders;\nimport org.elasticsearch.search.SearchHit;\n\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig.ESMapping;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem.FieldItem;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESBulkResponse;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESIndexRequest;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESUpdateRequest;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESTemplate;\nimport com.alibaba.otter.canal.client.adapter.es7x.support.ES7xTemplate;\nimport com.alibaba.otter.canal.client.adapter.es7x.support.ESConnection;\nimport com.alibaba.otter.canal.client.adapter.es7x.support.ESConnection.ESSearchRequest;\nimport com.alibaba.otter.canal.client.adapter.support.AbstractEtlService;\nimport com.alibaba.otter.canal.client.adapter.support.AdapterConfig;\nimport com.alibaba.otter.canal.client.adapter.support.EtlResult;\nimport com.alibaba.otter.canal.client.adapter.support.Util;\n\n/**\n * ES ETL Service\n *\n * @author rewerma 2018-11-01\n * @version 1.0.0\n */\npublic class ESEtlService extends AbstractEtlService {\n\n    private ESConnection esConnection;\n    private ESTemplate   esTemplate;\n    private ESSyncConfig config;\n\n    public ESEtlService(ESConnection esConnection, ESSyncConfig config){\n        super(\"ES\", config);\n        this.esConnection = esConnection;\n        this.esTemplate = new ES7xTemplate(esConnection);\n        this.config = config;\n    }\n\n    public EtlResult importData(List<String> params) {\n        ESMapping mapping = config.getEsMapping();\n        logger.info(\"start etl to import data to index: {}\", mapping.getIndex());\n        String sql = mapping.getSql();\n        return importData(sql, params);\n    }\n\n    protected boolean executeSqlImport(DataSource ds, String sql, List<Object> values,\n                                       AdapterConfig.AdapterMapping adapterMapping, AtomicLong impCount,\n                                       List<String> errMsg) {\n        try {\n            ESMapping mapping = (ESMapping) adapterMapping;\n            Util.sqlRS(ds, sql, values, rs -> {\n                int count = 0;\n                try {\n                    ESBulkRequest esBulkRequest = this.esConnection.new ES7xBulkRequest();\n\n                    long batchBegin = System.currentTimeMillis();\n                    while (rs.next()) {\n                        Map<String, Object> esFieldData = new LinkedHashMap<>();\n                        Object idVal = null;\n                        for (FieldItem fieldItem : mapping.getSchemaItem().getSelectFields().values()) {\n\n                            String fieldName = fieldItem.getFieldName();\n                            if (mapping.getSkips().contains(fieldName)) {\n                                continue;\n                            }\n\n                            // 如果是主键字段则不插入\n                            if (fieldItem.getFieldName().equals(mapping.getId())) {\n                                idVal = esTemplate.getValFromRS(mapping, rs, fieldName, fieldName);\n                            } else {\n                                Object val = esTemplate.getValFromRS(mapping, rs, fieldName, fieldName);\n                                esFieldData.put(Util.cleanColumn(fieldName), val);\n                            }\n\n                        }\n\n                        if (!mapping.getRelations().isEmpty()) {\n                            mapping.getRelations().forEach((relationField, relationMapping) -> {\n                                Map<String, Object> relations = new HashMap<>();\n                                relations.put(\"name\", relationMapping.getName());\n                                if (StringUtils.isNotEmpty(relationMapping.getParent())) {\n                                    FieldItem parentFieldItem = mapping.getSchemaItem()\n                                        .getSelectFields()\n                                        .get(relationMapping.getParent());\n                                    Object parentVal;\n                                    try {\n                                        parentVal = esTemplate.getValFromRS(mapping,\n                                            rs,\n                                            parentFieldItem.getFieldName(),\n                                            parentFieldItem.getFieldName());\n                                    } catch (SQLException e) {\n                                        throw new RuntimeException(e);\n                                    }\n                                    if (parentVal != null) {\n                                        relations.put(\"parent\", parentVal.toString());\n                                        esFieldData.put(\"$parent_routing\", parentVal.toString());\n\n                                    }\n                                }\n                                esFieldData.put(Util.cleanColumn(relationField), relations);\n                            });\n                        }\n\n                        if (idVal != null) {\n                            String parentVal = (String) esFieldData.remove(\"$parent_routing\");\n                            if (mapping.isUpsert()) {\n                                ESUpdateRequest esUpdateRequest = this.esConnection.new ES7xUpdateRequest(\n                                    mapping.getIndex(),\n                                    idVal.toString()).setDoc(esFieldData).setDocAsUpsert(true);\n\n                                if (StringUtils.isNotEmpty(parentVal)) {\n                                    esUpdateRequest.setRouting(parentVal);\n                                }\n\n                                esBulkRequest.add(esUpdateRequest);\n                            } else {\n                                ESIndexRequest esIndexRequest = this.esConnection.new ES7xIndexRequest(\n                                    mapping.getIndex(),\n                                    idVal.toString()).setSource(esFieldData);\n                                if (StringUtils.isNotEmpty(parentVal)) {\n                                    esIndexRequest.setRouting(parentVal);\n                                }\n                                esBulkRequest.add(esIndexRequest);\n                            }\n                        } else {\n                            idVal = esFieldData.get(mapping.getPk());\n                            ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.getIndex())\n                                .setQuery(QueryBuilders.termQuery(mapping.getPk(), idVal))\n                                .size(10000);\n                            SearchResponse response = esSearchRequest.getResponse();\n                            for (SearchHit hit : response.getHits()) {\n                                ESUpdateRequest esUpdateRequest = this.esConnection.new ES7xUpdateRequest(\n                                    mapping.getIndex(),\n                                    hit.getId()).setDoc(esFieldData);\n                                esBulkRequest.add(esUpdateRequest);\n                            }\n                        }\n\n                        if (esBulkRequest.numberOfActions() % mapping.getCommitBatch() == 0\n                            && esBulkRequest.numberOfActions() > 0) {\n                            long esBatchBegin = System.currentTimeMillis();\n                            ESBulkResponse rp = esBulkRequest.bulk();\n                            if (rp.hasFailures()) {\n                                rp.processFailBulkResponse(\"全量数据 etl 异常 \");\n                            }\n\n                            if (logger.isTraceEnabled()) {\n                                logger.trace(\"全量数据批量导入批次耗时: {}, es执行时间: {}, 批次大小: {}, index; {}\",\n                                    (System.currentTimeMillis() - batchBegin),\n                                    (System.currentTimeMillis() - esBatchBegin),\n                                    esBulkRequest.numberOfActions(),\n                                    mapping.getIndex());\n                            }\n                            batchBegin = System.currentTimeMillis();\n                            esBulkRequest.resetBulk();\n                        }\n                        count++;\n                        impCount.incrementAndGet();\n                    }\n\n                    if (esBulkRequest.numberOfActions() > 0) {\n                        long esBatchBegin = System.currentTimeMillis();\n                        ESBulkResponse rp = esBulkRequest.bulk();\n                        if (rp.hasFailures()) {\n                            rp.processFailBulkResponse(\"全量数据 etl 异常 \");\n                        }\n                        if (logger.isTraceEnabled()) {\n                            logger.trace(\"全量数据批量导入最后批次耗时: {}, es执行时间: {}, 批次大小: {}, index; {}\",\n                                (System.currentTimeMillis() - batchBegin),\n                                (System.currentTimeMillis() - esBatchBegin),\n                                esBulkRequest.numberOfActions(),\n                                mapping.getIndex());\n                        }\n                    }\n                } catch (Exception e) {\n                    logger.error(e.getMessage(), e);\n                    errMsg.add(mapping.getIndex() + \" etl failed! ==>\" + e.getMessage());\n                    throw new RuntimeException(e);\n                }\n                return count;\n            });\n\n            return true;\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/es7x/src/main/java/com/alibaba/otter/canal/client/adapter/es7x/support/ES7xTemplate.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es7x.support;\n\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\nimport javax.sql.DataSource;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.elasticsearch.action.search.SearchResponse;\nimport org.elasticsearch.cluster.metadata.MappingMetaData;\nimport org.elasticsearch.index.query.BoolQueryBuilder;\nimport org.elasticsearch.index.query.QueryBuilders;\nimport org.elasticsearch.search.SearchHit;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig.ESMapping;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem.ColumnItem;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem.FieldItem;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESBulkResponse;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESDeleteRequest;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESIndexRequest;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESUpdateRequest;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESSyncUtil;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESTemplate;\nimport com.alibaba.otter.canal.client.adapter.es7x.support.ESConnection.ESSearchRequest;\nimport com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;\nimport com.alibaba.otter.canal.client.adapter.support.Util;\n\npublic class ES7xTemplate implements ESTemplate {\n\n    private static final Logger                               logger         = LoggerFactory\n        .getLogger(ESTemplate.class);\n\n    private static final int                                  MAX_BATCH_SIZE = 1000;\n    // es 字段类型本地缓存\n    private static ConcurrentMap<String, Map<String, String>> esFieldTypes   = new ConcurrentHashMap<>();\n    private ESConnection                                      esConnection;\n    private ESBulkRequest                                     esBulkRequest;\n\n    public ES7xTemplate(ESConnection esConnection){\n        this.esConnection = esConnection;\n        this.esBulkRequest = this.esConnection.new ES7xBulkRequest();\n    }\n\n    public ESBulkRequest getBulk() {\n        return esBulkRequest;\n    }\n\n    public void resetBulkRequestBuilder() {\n        this.esBulkRequest.resetBulk();\n    }\n\n    @Override\n    public void insert(ESMapping mapping, Object pkVal, Map<String, Object> esFieldData) {\n        if (mapping.getId() != null) {\n            String parentVal = (String) esFieldData.remove(\"$parent_routing\");\n            if (mapping.isUpsert()) {\n                ESUpdateRequest updateRequest = esConnection.new ES7xUpdateRequest(mapping.getIndex(), pkVal.toString())\n                    .setDoc(esFieldData)\n                    .setDocAsUpsert(true);\n                if (StringUtils.isNotEmpty(parentVal)) {\n                    updateRequest.setRouting(parentVal);\n                }\n                getBulk().add(updateRequest);\n            } else {\n                ESIndexRequest indexRequest = esConnection.new ES7xIndexRequest(mapping.getIndex(), pkVal.toString())\n                    .setSource(esFieldData);\n                if (StringUtils.isNotEmpty(parentVal)) {\n                    indexRequest.setRouting(parentVal);\n                }\n                getBulk().add(indexRequest);\n            }\n            commitBulk();\n        } else {\n            ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.getIndex())\n                .setQuery(QueryBuilders.termQuery(mapping.getPk(), pkVal))\n                .size(10000);\n            SearchResponse response = esSearchRequest.getResponse();\n\n            for (SearchHit hit : response.getHits()) {\n                ESUpdateRequest esUpdateRequest = this.esConnection.new ES7xUpdateRequest(mapping.getIndex(),\n                    hit.getId()).setDoc(esFieldData);\n                getBulk().add(esUpdateRequest);\n                commitBulk();\n            }\n        }\n    }\n\n    @Override\n    public void update(ESMapping mapping, Object pkVal, Map<String, Object> esFieldData) {\n        Map<String, Object> esFieldDataTmp = new LinkedHashMap<>(esFieldData.size());\n        esFieldData.forEach((k, v) -> esFieldDataTmp.put(Util.cleanColumn(k), v));\n        append4Update(mapping, pkVal, esFieldDataTmp);\n        commitBulk();\n    }\n\n    @Override\n    public void updateByQuery(ESSyncConfig config, Map<String, Object> paramsTmp, Map<String, Object> esFieldData) {\n        if (paramsTmp.isEmpty()) {\n            return;\n        }\n        ESMapping mapping = config.getEsMapping();\n        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();\n        paramsTmp.forEach((fieldName, value) -> queryBuilder.must(QueryBuilders.termsQuery(fieldName, value)));\n\n        // 查询sql批量更新\n        DataSource ds = DatasourceConfig.DATA_SOURCES.get(config.getDataSourceKey());\n        StringBuilder sql = new StringBuilder(\"SELECT * FROM (\" + mapping.getSql() + \") _v WHERE \");\n        List<Object> values = new ArrayList<>();\n        paramsTmp.forEach((fieldName, value) -> {\n            sql.append(\"_v.\").append(fieldName).append(\"=? AND \");\n            values.add(value);\n        });\n        // TODO 直接外部包裹sql会导致全表扫描性能低, 待优化拼接内部where条件\n        int len = sql.length();\n        sql.delete(len - 4, len);\n        Integer syncCount = (Integer) Util.sqlRS(ds, sql.toString(), values, rs -> {\n            int count = 0;\n            try {\n                while (rs.next()) {\n                    Object idVal = getIdValFromRS(mapping, rs);\n                    append4Update(mapping, idVal, esFieldData);\n                    commitBulk();\n                    count++;\n                }\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n            return count;\n        });\n        if (logger.isTraceEnabled()) {\n            logger.trace(\"Update ES by query affected {} records\", syncCount);\n        }\n    }\n\n    @Override\n    public void delete(ESMapping mapping, Object pkVal, Map<String, Object> esFieldData) {\n        if (mapping.getId() != null) {\n            ESDeleteRequest esDeleteRequest = this.esConnection.new ES7xDeleteRequest(mapping.getIndex(),\n                pkVal.toString());\n            getBulk().add(esDeleteRequest);\n            commitBulk();\n        } else {\n            ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.getIndex())\n                .setQuery(QueryBuilders.termQuery(mapping.getPk(), pkVal))\n                .size(10000);\n            SearchResponse response = esSearchRequest.getResponse();\n            for (SearchHit hit : response.getHits()) {\n                ESUpdateRequest esUpdateRequest = this.esConnection.new ES7xUpdateRequest(mapping.getIndex(),\n                    hit.getId()).setDoc(esFieldData);\n                getBulk().add(esUpdateRequest);\n                commitBulk();\n            }\n        }\n    }\n\n    @Override\n    public void commit() {\n        if (getBulk().numberOfActions() > 0) {\n            ESBulkResponse response = getBulk().bulk();\n            if (response.hasFailures()) {\n                response.processFailBulkResponse(\"ES sync commit error \");\n            }\n            resetBulkRequestBuilder();\n        }\n    }\n\n    @Override\n    public Object getValFromRS(ESMapping mapping, ResultSet resultSet, String fieldName,\n                               String columnName) throws SQLException {\n        fieldName = Util.cleanColumn(fieldName);\n        columnName = Util.cleanColumn(columnName);\n        String esType = getEsType(mapping, fieldName);\n\n        Object value = resultSet.getObject(columnName);\n        if (value instanceof Boolean) {\n            if (!\"boolean\".equals(esType)) {\n                value = resultSet.getByte(columnName);\n            }\n        }\n\n        // 如果是对象类型\n        if (mapping.getObjFields().containsKey(fieldName)) {\n            return ESSyncUtil.convertToEsObj(value, mapping.getObjFields().get(fieldName));\n        } else {\n            return ESSyncUtil.typeConvert(value, esType);\n        }\n    }\n\n    @Override\n    public Object getESDataFromRS(ESMapping mapping, ResultSet resultSet,\n                                  Map<String, Object> esFieldData) throws SQLException {\n        SchemaItem schemaItem = mapping.getSchemaItem();\n        String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();\n        Object resultIdVal = null;\n        for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {\n            Object value = getValFromRS(mapping, resultSet, fieldItem.getFieldName(), fieldItem.getFieldName());\n\n            if (fieldItem.getFieldName().equals(idFieldName)) {\n                resultIdVal = value;\n            }\n\n            if (!fieldItem.getFieldName().equals(mapping.getId())\n                && !mapping.getSkips().contains(fieldItem.getFieldName())) {\n                esFieldData.put(Util.cleanColumn(fieldItem.getFieldName()), value);\n            }\n        }\n\n        // 添加父子文档关联信息\n        putRelationDataFromRS(mapping, schemaItem, resultSet, esFieldData);\n\n        return resultIdVal;\n    }\n\n    @Override\n    public Object getIdValFromRS(ESMapping mapping, ResultSet resultSet) throws SQLException {\n        SchemaItem schemaItem = mapping.getSchemaItem();\n        String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();\n        Object resultIdVal = null;\n        for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {\n            Object value = getValFromRS(mapping, resultSet, fieldItem.getFieldName(), fieldItem.getFieldName());\n\n            if (fieldItem.getFieldName().equals(idFieldName)) {\n                resultIdVal = value;\n                break;\n            }\n        }\n        return resultIdVal;\n    }\n\n    @Override\n    public Object getESDataFromRS(ESMapping mapping, ResultSet resultSet, Map<String, Object> dmlOld,\n                                  Map<String, Object> esFieldData) throws SQLException {\n        SchemaItem schemaItem = mapping.getSchemaItem();\n        String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();\n        Object resultIdVal = null;\n        for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {\n            if (fieldItem.getFieldName().equals(idFieldName)) {\n                resultIdVal = getValFromRS(mapping, resultSet, fieldItem.getFieldName(), fieldItem.getFieldName());\n            }\n\n            for (ColumnItem columnItem : fieldItem.getColumnItems()) {\n                if (dmlOld.containsKey(columnItem.getColumnName())\n                    && !mapping.getSkips().contains(fieldItem.getFieldName())) {\n                    esFieldData.put(Util.cleanColumn(fieldItem.getFieldName()),\n                        getValFromRS(mapping, resultSet, fieldItem.getFieldName(), fieldItem.getFieldName()));\n                    break;\n                }\n            }\n        }\n\n        // 添加父子文档关联信息\n        putRelationDataFromRS(mapping, schemaItem, resultSet, esFieldData);\n\n        return resultIdVal;\n    }\n\n    @Override\n    public Object getValFromData(ESMapping mapping, Map<String, Object> dmlData, String fieldName, String columnName) {\n        String esType = getEsType(mapping, fieldName);\n        Object value = dmlData.get(columnName);\n        if (value instanceof Byte) {\n            if (\"boolean\".equals(esType)) {\n                value = ((Byte) value).intValue() != 0;\n            }\n        }\n\n        // 如果是对象类型\n        if (mapping.getObjFields().containsKey(fieldName)) {\n            return ESSyncUtil.convertToEsObj(value, mapping.getObjFields().get(fieldName));\n        } else {\n            return ESSyncUtil.typeConvert(value, esType);\n        }\n    }\n\n    @Override\n    public Object getESDataFromDmlData(ESMapping mapping, Map<String, Object> dmlData,\n                                       Map<String, Object> esFieldData) {\n        SchemaItem schemaItem = mapping.getSchemaItem();\n        String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();\n        Object resultIdVal = null;\n        for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {\n            String columnName = fieldItem.getColumnItems().iterator().next().getColumnName();\n            Object value = getValFromData(mapping, dmlData, fieldItem.getFieldName(), columnName);\n\n            if (fieldItem.getFieldName().equals(idFieldName)) {\n                resultIdVal = value;\n            }\n\n            if (!fieldItem.getFieldName().equals(mapping.getId())\n                && !mapping.getSkips().contains(fieldItem.getFieldName())) {\n                esFieldData.put(Util.cleanColumn(fieldItem.getFieldName()), value);\n            }\n        }\n\n        // 添加父子文档关联信息\n        putRelationData(mapping, schemaItem, dmlData, esFieldData);\n        return resultIdVal;\n    }\n\n    @Override\n    public Object getESDataFromDmlData(ESMapping mapping, String owner, Map<String, Object> dmlData,\n                                       Map<String, Object> dmlOld, Map<String, Object> esFieldData) {\n        SchemaItem schemaItem = mapping.getSchemaItem();\n        String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();\n        Object resultIdVal = null;\n        for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {\n            ColumnItem columnItem = fieldItem.getColumnItems().iterator().next();\n            if (columnItem.getOwner() == null || columnItem.getColumnName() == null) {\n                continue;\n            }\n\n            if (!columnItem.getOwner().equals(owner)) {\n                continue;\n            }\n\n            String columnName = columnItem.getColumnName();\n            if (fieldItem.getFieldName().equals(idFieldName)) {\n                resultIdVal = getValFromData(mapping, dmlData, fieldItem.getFieldName(), columnName);\n            }\n\n            if (dmlOld.containsKey(columnName) && !mapping.getSkips().contains(fieldItem.getFieldName())) {\n                esFieldData.put(Util.cleanColumn(fieldItem.getFieldName()),\n                    getValFromData(mapping, dmlData, fieldItem.getFieldName(), columnName));\n            }\n        }\n\n        // 添加父子文档关联信息\n        putRelationData(mapping, schemaItem, dmlOld, esFieldData);\n        return resultIdVal;\n    }\n\n    /**\n     * 如果大于批量数则提交批次\n     */\n    private void commitBulk() {\n        if (getBulk().numberOfActions() >= MAX_BATCH_SIZE) {\n            commit();\n        }\n    }\n\n    private void append4Update(ESMapping mapping, Object pkVal, Map<String, Object> esFieldData) {\n        if (mapping.getId() != null) {\n            String parentVal = (String) esFieldData.remove(\"$parent_routing\");\n            if (mapping.isUpsert()) {\n                ESUpdateRequest esUpdateRequest = this.esConnection.new ES7xUpdateRequest(mapping.getIndex(),\n                    pkVal.toString()).setDoc(esFieldData).setDocAsUpsert(true);\n                if (StringUtils.isNotEmpty(parentVal)) {\n                    esUpdateRequest.setRouting(parentVal);\n                }\n                getBulk().add(esUpdateRequest);\n            } else {\n                ESUpdateRequest esUpdateRequest = this.esConnection.new ES7xUpdateRequest(mapping.getIndex(),\n                    pkVal.toString()).setDoc(esFieldData);\n                if (StringUtils.isNotEmpty(parentVal)) {\n                    esUpdateRequest.setRouting(parentVal);\n                }\n                getBulk().add(esUpdateRequest);\n            }\n        } else {\n            ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.getIndex())\n                .setQuery(QueryBuilders.termQuery(mapping.getPk(), pkVal))\n                .size(10000);\n            SearchResponse response = esSearchRequest.getResponse();\n            for (SearchHit hit : response.getHits()) {\n                ESUpdateRequest esUpdateRequest = this.esConnection.new ES7xUpdateRequest(mapping.getIndex(),\n                    hit.getId()).setDoc(esFieldData);\n                getBulk().add(esUpdateRequest);\n            }\n        }\n    }\n\n    /**\n     * 获取es mapping中的属性类型\n     *\n     * @param mapping mapping配置\n     * @param fieldName 属性名\n     * @return 类型\n     */\n    @SuppressWarnings(\"unchecked\")\n    private String getEsType(ESMapping mapping, String fieldName) {\n        String key = mapping.getIndex() + \"-\" + mapping.getType();\n        Map<String, String> fieldType = esFieldTypes.get(key);\n        if (fieldType != null) {\n            return fieldType.get(fieldName);\n        } else {\n            MappingMetaData mappingMetaData = esConnection.getMapping(mapping.getIndex());\n\n            if (mappingMetaData == null) {\n                throw new IllegalArgumentException(\"Not found the mapping info of index: \" + mapping.getIndex());\n            }\n\n            fieldType = new LinkedHashMap<>();\n\n            Map<String, Object> sourceMap = mappingMetaData.getSourceAsMap();\n            Map<String, Object> esMapping = (Map<String, Object>) sourceMap.get(\"properties\");\n            for (Map.Entry<String, Object> entry : esMapping.entrySet()) {\n                Map<String, Object> value = (Map<String, Object>) entry.getValue();\n                if (value.containsKey(\"properties\")) {\n                    fieldType.put(entry.getKey(), \"object\");\n                } else {\n                    fieldType.put(entry.getKey(), (String) value.get(\"type\"));\n                }\n            }\n            esFieldTypes.put(key, fieldType);\n\n            return fieldType.get(fieldName);\n        }\n    }\n\n    private void putRelationDataFromRS(ESMapping mapping, SchemaItem schemaItem, ResultSet resultSet,\n                                       Map<String, Object> esFieldData) {\n        // 添加父子文档关联信息\n        if (!mapping.getRelations().isEmpty()) {\n            mapping.getRelations().forEach((relationField, relationMapping) -> {\n                Map<String, Object> relations = new HashMap<>();\n                relations.put(\"name\", relationMapping.getName());\n                if (StringUtils.isNotEmpty(relationMapping.getParent())) {\n                    FieldItem parentFieldItem = schemaItem.getSelectFields().get(relationMapping.getParent());\n                    Object parentVal;\n                    try {\n                        parentVal = getValFromRS(mapping,\n                            resultSet,\n                            parentFieldItem.getFieldName(),\n                            parentFieldItem.getFieldName());\n                    } catch (SQLException e) {\n                        throw new RuntimeException(e);\n                    }\n                    if (parentVal != null) {\n                        relations.put(\"parent\", parentVal.toString());\n                        esFieldData.put(\"$parent_routing\", parentVal.toString());\n\n                    }\n                }\n                esFieldData.put(relationField, relations);\n            });\n        }\n    }\n\n    private void putRelationData(ESMapping mapping, SchemaItem schemaItem, Map<String, Object> dmlData,\n                                 Map<String, Object> esFieldData) {\n        // 添加父子文档关联信息\n        if (!mapping.getRelations().isEmpty()) {\n            mapping.getRelations().forEach((relationField, relationMapping) -> {\n                Map<String, Object> relations = new HashMap<>();\n                relations.put(\"name\", relationMapping.getName());\n                if (StringUtils.isNotEmpty(relationMapping.getParent())) {\n                    FieldItem parentFieldItem = schemaItem.getSelectFields().get(relationMapping.getParent());\n                    String columnName = parentFieldItem.getColumnItems().iterator().next().getColumnName();\n                    Object parentVal = getValFromData(mapping, dmlData, parentFieldItem.getFieldName(), columnName);\n                    if (parentVal != null) {\n                        relations.put(\"parent\", parentVal.toString());\n                        esFieldData.put(\"$parent_routing\", parentVal.toString());\n\n                    }\n                }\n                esFieldData.put(relationField, relations);\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/es7x/src/main/java/com/alibaba/otter/canal/client/adapter/es7x/support/ESConnection.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es7x.support;\n\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.net.UnknownHostException;\nimport java.util.Arrays;\nimport java.util.Map;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.http.HttpHost;\nimport org.apache.http.auth.AuthScope;\nimport org.apache.http.auth.UsernamePasswordCredentials;\nimport org.apache.http.client.CredentialsProvider;\nimport org.apache.http.impl.client.BasicCredentialsProvider;\nimport org.elasticsearch.action.bulk.BulkItemResponse;\nimport org.elasticsearch.action.bulk.BulkRequest;\nimport org.elasticsearch.action.bulk.BulkRequestBuilder;\nimport org.elasticsearch.action.bulk.BulkResponse;\nimport org.elasticsearch.action.delete.DeleteRequest;\nimport org.elasticsearch.action.delete.DeleteRequestBuilder;\nimport org.elasticsearch.action.index.IndexRequest;\nimport org.elasticsearch.action.index.IndexRequestBuilder;\nimport org.elasticsearch.action.search.SearchRequest;\nimport org.elasticsearch.action.search.SearchRequestBuilder;\nimport org.elasticsearch.action.search.SearchResponse;\nimport org.elasticsearch.action.update.UpdateRequest;\nimport org.elasticsearch.action.update.UpdateRequestBuilder;\nimport org.elasticsearch.client.RequestOptions;\nimport org.elasticsearch.client.RestClient;\nimport org.elasticsearch.client.RestClientBuilder;\nimport org.elasticsearch.client.RestHighLevelClient;\nimport org.elasticsearch.client.indices.GetMappingsRequest;\nimport org.elasticsearch.client.indices.GetMappingsResponse;\nimport org.elasticsearch.client.transport.TransportClient;\nimport org.elasticsearch.cluster.metadata.MappingMetaData;\nimport org.elasticsearch.common.settings.Settings;\nimport org.elasticsearch.common.transport.TransportAddress;\nimport org.elasticsearch.index.query.QueryBuilder;\nimport org.elasticsearch.rest.RestStatus;\nimport org.elasticsearch.search.builder.SearchSourceBuilder;\nimport org.elasticsearch.transport.client.PreBuiltTransportClient;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest;\n\n/**\n * ES 连接器, Transport Rest 两种方式\n *\n * @author rewerma 2019-08-01\n * @version 1.0.0\n */\npublic class ESConnection {\n\n    private static final Logger logger = LoggerFactory.getLogger(ESConnection.class);\n    private ESClientMode        mode;\n    @SuppressWarnings(\"deprecation\")\n    private TransportClient     transportClient;\n    private RestHighLevelClient restHighLevelClient;\n\n    public ESConnection(String[] hosts, Map<String, String> properties, ESClientMode mode) throws UnknownHostException{\n        this.mode = mode;\n        if (mode == ESClientMode.TRANSPORT) {\n            Settings.Builder settingBuilder = Settings.builder();\n            settingBuilder.put(\"cluster.name\", properties.get(\"cluster.name\"));\n            Settings settings = settingBuilder.build();\n            transportClient = new PreBuiltTransportClient(settings);\n            for (String host : hosts) {\n                int i = host.indexOf(\":\");\n                transportClient.addTransportAddress(new TransportAddress(InetAddress.getByName(host.substring(0, i)),\n                    Integer.parseInt(host.substring(i + 1))));\n            }\n        } else {\n            HttpHost[] httpHosts = Arrays.stream(hosts).map(this::createHttpHost).toArray(HttpHost[]::new);\n            RestClientBuilder restClientBuilder = RestClient.builder(httpHosts);\n            String nameAndPwd = properties.get(\"security.auth\");\n            if (StringUtils.isNotEmpty(nameAndPwd) && nameAndPwd.contains(\":\")) {\n                String[] nameAndPwdArr = nameAndPwd.split(\":\");\n                final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();\n                credentialsProvider.setCredentials(AuthScope.ANY,\n                    new UsernamePasswordCredentials(nameAndPwdArr[0], nameAndPwdArr[1]));\n                restClientBuilder.setHttpClientConfigCallback(\n                    httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider));\n            }\n            restHighLevelClient = new RestHighLevelClient(restClientBuilder);\n        }\n    }\n\n    public void close() {\n        if (mode == ESClientMode.TRANSPORT) {\n            transportClient.close();\n        } else {\n            try {\n                restHighLevelClient.close();\n            } catch (IOException e) {\n                throw new RuntimeException(e);\n            }\n        }\n    }\n\n    public MappingMetaData getMapping(String index) {\n        MappingMetaData mappingMetaData = null;\n        if (mode == ESClientMode.TRANSPORT) {\n            try {\n                mappingMetaData = transportClient.admin()\n                    .cluster()\n                    .prepareState()\n                    .execute()\n                    .actionGet()\n                    .getState()\n                    .getMetaData()\n                    .getIndices()\n                    .get(index)\n                    .mapping();\n            } catch (NullPointerException e) {\n                throw new IllegalArgumentException(\"Not found the mapping info of index: \" + index);\n            }\n        } else {\n            Map<String, MappingMetaData> mappings;\n            try {\n                GetMappingsRequest request = new GetMappingsRequest();\n                request.indices(index);\n                GetMappingsResponse response = restHighLevelClient.indices()\n                    .getMapping(request, RequestOptions.DEFAULT);\n\n                mappings = response.mappings();\n            } catch (NullPointerException e) {\n                throw new IllegalArgumentException(\"Not found the mapping info of index: \" + index);\n            } catch (IOException e) {\n                logger.error(e.getMessage(), e);\n                return null;\n            }\n\n            // 通过别名查询mapping返回的是真实索引名称，mappings.get(index)返回null，为兼容别名情况修改如下：\n            mappingMetaData = mappings.get(index);\n            if (mappingMetaData == null && !mappings.isEmpty()) {\n                // 如果通过索引名找不到，可能是别名，取第一个映射\n                mappingMetaData = mappings.values().iterator().next();\n            }\n\n            // 如果还是null，说明索引不存在或没有mapping\n            if (mappingMetaData == null) {\n                throw new IllegalArgumentException(\"Not found the mapping info of index: \" + index);\n            }\n        }\n        return mappingMetaData;\n    }\n\n    // ------ get/set ------\n    public ESClientMode getMode() {\n        return mode;\n    }\n\n    public void setMode(ESClientMode mode) {\n        this.mode = mode;\n    }\n\n    public TransportClient getTransportClient() {\n        return transportClient;\n    }\n\n    public void setTransportClient(TransportClient transportClient) {\n        this.transportClient = transportClient;\n    }\n\n    public RestHighLevelClient getRestHighLevelClient() {\n        return restHighLevelClient;\n    }\n\n    public void setRestHighLevelClient(RestHighLevelClient restHighLevelClient) {\n        this.restHighLevelClient = restHighLevelClient;\n    }\n\n    private HttpHost createHttpHost(String uriStr) {\n        URI uri = URI.create(uriStr);\n        if (!org.springframework.util.StringUtils.hasLength(uri.getUserInfo())) {\n            return HttpHost.create(uri.toString());\n        }\n        try {\n            return HttpHost.create(new URI(uri\n                .getScheme(), null, uri.getHost(), uri.getPort(), uri.getPath(), uri.getQuery(), uri.getFragment())\n                    .toString());\n        } catch (URISyntaxException ex) {\n            throw new IllegalStateException(ex);\n        }\n    }\n\n    public enum ESClientMode {\n                              TRANSPORT, REST\n    }\n\n    public static class ES7xBulkResponse implements ESBulkRequest.ESBulkResponse {\n\n        private BulkResponse bulkResponse;\n\n        public ES7xBulkResponse(BulkResponse bulkResponse){\n            this.bulkResponse = bulkResponse;\n        }\n\n        @Override\n        public boolean hasFailures() {\n            return bulkResponse.hasFailures();\n        }\n\n        @Override\n        public void processFailBulkResponse(String errorMsg) {\n            for (BulkItemResponse itemResponse : bulkResponse.getItems()) {\n                if (!itemResponse.isFailed()) {\n                    continue;\n                }\n\n                if (itemResponse.getFailure().getStatus() == RestStatus.NOT_FOUND) {\n                    logger.error(itemResponse.getFailureMessage());\n                } else {\n                    throw new RuntimeException(errorMsg + itemResponse.getFailureMessage());\n                }\n            }\n        }\n    }\n\n    public class ES7xIndexRequest implements ESBulkRequest.ESIndexRequest {\n\n        private IndexRequestBuilder indexRequestBuilder;\n\n        private IndexRequest        indexRequest;\n\n        public ES7xIndexRequest(String index, String id){\n            if (mode == ESClientMode.TRANSPORT) {\n                indexRequestBuilder = transportClient.prepareIndex();\n                indexRequestBuilder.setIndex(index);\n                indexRequestBuilder.setId(id);\n            } else {\n                indexRequest = new IndexRequest(index);\n                indexRequest.id(id);\n            }\n        }\n\n        public ES7xIndexRequest setSource(Map<String, ?> source) {\n            if (mode == ESClientMode.TRANSPORT) {\n                indexRequestBuilder.setSource(source);\n            } else {\n                indexRequest.source(source);\n            }\n            return this;\n        }\n\n        public ES7xIndexRequest setRouting(String routing) {\n            if (mode == ESClientMode.TRANSPORT) {\n                indexRequestBuilder.setRouting(routing);\n            } else {\n                indexRequest.routing(routing);\n            }\n            return this;\n        }\n\n        public IndexRequestBuilder getIndexRequestBuilder() {\n            return indexRequestBuilder;\n        }\n\n        public void setIndexRequestBuilder(IndexRequestBuilder indexRequestBuilder) {\n            this.indexRequestBuilder = indexRequestBuilder;\n        }\n\n        public IndexRequest getIndexRequest() {\n            return indexRequest;\n        }\n\n        public void setIndexRequest(IndexRequest indexRequest) {\n            this.indexRequest = indexRequest;\n        }\n    }\n\n    public class ES7xUpdateRequest implements ESBulkRequest.ESUpdateRequest {\n\n        private UpdateRequestBuilder updateRequestBuilder;\n\n        private UpdateRequest        updateRequest;\n\n        public ES7xUpdateRequest(String index, String id){\n            if (mode == ESClientMode.TRANSPORT) {\n                updateRequestBuilder = transportClient.prepareUpdate();\n                updateRequestBuilder.setIndex(index);\n                updateRequestBuilder.setId(id);\n            } else {\n                updateRequest = new UpdateRequest(index, id);\n            }\n        }\n\n        public ES7xUpdateRequest setDoc(Map source) {\n            if (mode == ESClientMode.TRANSPORT) {\n                updateRequestBuilder.setDoc(source);\n            } else {\n                updateRequest.doc(source);\n            }\n            return this;\n        }\n\n        public ES7xUpdateRequest setDocAsUpsert(boolean shouldUpsertDoc) {\n            if (mode == ESClientMode.TRANSPORT) {\n                updateRequestBuilder.setDocAsUpsert(shouldUpsertDoc);\n            } else {\n                updateRequest.docAsUpsert(shouldUpsertDoc);\n            }\n            return this;\n        }\n\n        public ES7xUpdateRequest setRouting(String routing) {\n            if (mode == ESClientMode.TRANSPORT) {\n                updateRequestBuilder.setRouting(routing);\n            } else {\n                updateRequest.routing(routing);\n            }\n            return this;\n        }\n\n        public UpdateRequestBuilder getUpdateRequestBuilder() {\n            return updateRequestBuilder;\n        }\n\n        public void setUpdateRequestBuilder(UpdateRequestBuilder updateRequestBuilder) {\n            this.updateRequestBuilder = updateRequestBuilder;\n        }\n\n        public UpdateRequest getUpdateRequest() {\n            return updateRequest;\n        }\n\n        public void setUpdateRequest(UpdateRequest updateRequest) {\n            this.updateRequest = updateRequest;\n        }\n    }\n\n    public class ES7xDeleteRequest implements ESBulkRequest.ESDeleteRequest {\n\n        private DeleteRequestBuilder deleteRequestBuilder;\n\n        private DeleteRequest        deleteRequest;\n\n        public ES7xDeleteRequest(String index, String id){\n            if (mode == ESClientMode.TRANSPORT) {\n                deleteRequestBuilder = transportClient.prepareDelete();\n                deleteRequestBuilder.setIndex(index);\n                deleteRequestBuilder.setId(id);\n            } else {\n                deleteRequest = new DeleteRequest(index, id);\n            }\n        }\n\n        public DeleteRequestBuilder getDeleteRequestBuilder() {\n            return deleteRequestBuilder;\n        }\n\n        public void setDeleteRequestBuilder(DeleteRequestBuilder deleteRequestBuilder) {\n            this.deleteRequestBuilder = deleteRequestBuilder;\n        }\n\n        public DeleteRequest getDeleteRequest() {\n            return deleteRequest;\n        }\n\n        public void setDeleteRequest(DeleteRequest deleteRequest) {\n            this.deleteRequest = deleteRequest;\n        }\n    }\n\n    public class ESSearchRequest {\n\n        private SearchRequestBuilder searchRequestBuilder;\n\n        private SearchRequest        searchRequest;\n\n        private SearchSourceBuilder  sourceBuilder;\n\n        public ESSearchRequest(String index){\n            if (mode == ESClientMode.TRANSPORT) {\n                searchRequestBuilder = transportClient.prepareSearch(index);\n            } else {\n                searchRequest = new SearchRequest(index);\n                sourceBuilder = new SearchSourceBuilder();\n            }\n        }\n\n        public ESSearchRequest setQuery(QueryBuilder queryBuilder) {\n            if (mode == ESClientMode.TRANSPORT) {\n                searchRequestBuilder.setQuery(queryBuilder);\n            } else {\n                sourceBuilder.query(queryBuilder);\n            }\n            return this;\n        }\n\n        public ESSearchRequest size(int size) {\n            if (mode == ESClientMode.TRANSPORT) {\n                searchRequestBuilder.setSize(size);\n            } else {\n                sourceBuilder.size(size);\n            }\n            return this;\n        }\n\n        public SearchResponse getResponse() {\n            if (mode == ESClientMode.TRANSPORT) {\n                return searchRequestBuilder.get();\n            } else {\n                searchRequest.source(sourceBuilder);\n                try {\n                    return restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);\n                } catch (IOException e) {\n                    throw new RuntimeException(e);\n                }\n            }\n        }\n\n        public SearchRequestBuilder getSearchRequestBuilder() {\n            return searchRequestBuilder;\n        }\n\n        public void setSearchRequestBuilder(SearchRequestBuilder searchRequestBuilder) {\n            this.searchRequestBuilder = searchRequestBuilder;\n        }\n\n        public SearchRequest getSearchRequest() {\n            return searchRequest;\n        }\n\n        public void setSearchRequest(SearchRequest searchRequest) {\n            this.searchRequest = searchRequest;\n        }\n    }\n\n    public class ES7xBulkRequest implements ESBulkRequest {\n\n        private BulkRequestBuilder bulkRequestBuilder;\n\n        private BulkRequest        bulkRequest;\n\n        public ES7xBulkRequest(){\n            if (mode == ESClientMode.TRANSPORT) {\n                bulkRequestBuilder = transportClient.prepareBulk();\n            } else {\n                bulkRequest = new BulkRequest();\n            }\n        }\n\n        public void resetBulk() {\n            if (mode == ESClientMode.TRANSPORT) {\n                bulkRequestBuilder = transportClient.prepareBulk();\n            } else {\n                bulkRequest = new BulkRequest();\n            }\n        }\n\n        public ES7xBulkRequest add(ESIndexRequest esIndexRequest) {\n            ES7xIndexRequest eir = (ES7xIndexRequest) esIndexRequest;\n            if (mode == ESClientMode.TRANSPORT) {\n                bulkRequestBuilder.add(eir.indexRequestBuilder);\n            } else {\n                bulkRequest.add(eir.indexRequest);\n            }\n            return this;\n        }\n\n        public ES7xBulkRequest add(ESUpdateRequest esUpdateRequest) {\n            ES7xUpdateRequest eur = (ES7xUpdateRequest) esUpdateRequest;\n            if (mode == ESClientMode.TRANSPORT) {\n                bulkRequestBuilder.add(eur.updateRequestBuilder);\n            } else {\n                bulkRequest.add(eur.updateRequest);\n            }\n            return this;\n        }\n\n        public ES7xBulkRequest add(ESDeleteRequest esDeleteRequest) {\n            ES7xDeleteRequest edr = (ES7xDeleteRequest) esDeleteRequest;\n            if (mode == ESClientMode.TRANSPORT) {\n                bulkRequestBuilder.add(edr.deleteRequestBuilder);\n            } else {\n                bulkRequest.add(edr.deleteRequest);\n            }\n            return this;\n        }\n\n        public int numberOfActions() {\n            if (mode == ESClientMode.TRANSPORT) {\n                return bulkRequestBuilder.numberOfActions();\n            } else {\n                return bulkRequest.numberOfActions();\n            }\n        }\n\n        public ESBulkResponse bulk() {\n            if (mode == ESClientMode.TRANSPORT) {\n                BulkResponse responses = bulkRequestBuilder.execute().actionGet();\n                return new ES7xBulkResponse(responses);\n            } else {\n                try {\n                    BulkResponse responses = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);\n                    return new ES7xBulkResponse(responses);\n                } catch (IOException e) {\n                    throw new RuntimeException(e);\n                }\n            }\n        }\n\n        public BulkRequestBuilder getBulkRequestBuilder() {\n            return bulkRequestBuilder;\n        }\n\n        public void setBulkRequestBuilder(BulkRequestBuilder bulkRequestBuilder) {\n            this.bulkRequestBuilder = bulkRequestBuilder;\n        }\n\n        public BulkRequest getBulkRequest() {\n            return bulkRequest;\n        }\n\n        public void setBulkRequest(BulkRequest bulkRequest) {\n            this.bulkRequest = bulkRequest;\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/es7x/src/main/resources/META-INF/canal/com.alibaba.otter.canal.client.adapter.OuterAdapter",
    "content": "es7=com.alibaba.otter.canal.client.adapter.es7x.ES7xAdapter\n"
  },
  {
    "path": "client-adapter/es7x/src/main/resources/es7/biz_order.yml",
    "content": "dataSourceKey: defaultDS\ndestination: example\ngroupId: g1\nesMapping:\n  _index: customer\n  _id: _id\n  relations:\n    customer_order:\n      name: order\n      parent: customer_id\n  sql: \"select concat('oid_', t.id) as _id,\n        t.customer_id,\n        t.id as order_id,\n        t.serial_code as order_serial,\n        t.c_time as order_time\n        from biz_order t\"\n  skips:\n    - customer_id\n  etlCondition: \"where t.c_time>={}\"\n  commitBatch: 3000\n"
  },
  {
    "path": "client-adapter/es7x/src/main/resources/es7/customer.yml",
    "content": "dataSourceKey: defaultDS\ndestination: example\ngroupId: g1\nesMapping:\n  _index: customer\n  _id: id\n  relations:\n    customer_order:\n      name: customer\n  sql: \"select t.id, t.name, t.email from customer t\"\n  etlCondition: \"where t.c_time>={}\"\n  commitBatch: 3000\n\n\n#{\n#  \"mappings\":{\n#    \"_doc\":{\n#      \"properties\":{\n#        \"id\": {\n#          \"type\": \"long\"\n#        },\n#        \"name\": {\n#          \"type\": \"text\"\n#        },\n#        \"email\": {\n#          \"type\": \"text\"\n#        },\n#        \"order_id\": {\n#          \"type\": \"long\"\n#        },\n#        \"order_serial\": {\n#          \"type\": \"text\"\n#        },\n#        \"order_time\": {\n#          \"type\": \"date\"\n#        },\n#        \"customer_order\":{\n#          \"type\":\"join\",\n#          \"relations\":{\n#            \"customer\":\"order\"\n#          }\n#        }\n#      }\n#    }\n#  }\n#}\n"
  },
  {
    "path": "client-adapter/es7x/src/main/resources/es7/mytest_user.yml",
    "content": "dataSourceKey: defaultDS\ndestination: example\ngroupId: g1\nesMapping:\n  _index: mytest_user\n  _id: _id\n#  upsert: true\n#  pk: id\n  sql: \"select a.id as _id, a.name, a.role_id, b.role_name,\n        a.c_time from user a\n        left join role b on b.id=a.role_id\"\n#  objFields:\n#    _labels: array:;\n  etlCondition: \"where a.c_time>={}\"\n  commitBatch: 3000\n"
  },
  {
    "path": "client-adapter/es7x/src/test/java/com/alibaba/otter/canal/client/adapter/es7x/test/ES7xTest.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es7x.test;\n\nimport java.net.InetAddress;\nimport java.net.UnknownHostException;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.elasticsearch.action.bulk.BulkItemResponse;\nimport org.elasticsearch.action.bulk.BulkRequestBuilder;\nimport org.elasticsearch.action.bulk.BulkResponse;\nimport org.elasticsearch.action.search.SearchResponse;\nimport org.elasticsearch.client.transport.TransportClient;\nimport org.elasticsearch.common.settings.Settings;\nimport org.elasticsearch.common.transport.TransportAddress;\nimport org.elasticsearch.index.query.QueryBuilders;\nimport org.elasticsearch.rest.RestStatus;\nimport org.elasticsearch.search.SearchHit;\nimport org.elasticsearch.transport.client.PreBuiltTransportClient;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\n@Ignore\npublic class ES7xTest {\n\n    @SuppressWarnings(\"deprecation\")\n    private TransportClient transportClient;\n\n    @Before\n    public void init() throws UnknownHostException {\n        Settings.Builder settingBuilder = Settings.builder();\n        settingBuilder.put(\"cluster.name\", TestConstant.clusterName);\n        Settings settings = settingBuilder.build();\n        transportClient = new PreBuiltTransportClient(settings);\n        String[] hostArray = TestConstant.esHosts.split(\",\");\n        for (String host : hostArray) {\n            int i = host.indexOf(\":\");\n            transportClient.addTransportAddress(new TransportAddress(InetAddress.getByName(host.substring(0, i)),\n                Integer.parseInt(host.substring(i + 1))));\n        }\n    }\n\n    @Test\n    public void test01() {\n        SearchResponse response = transportClient.prepareSearch(\"test\")\n            .setQuery(QueryBuilders.termQuery(\"_id\", \"1\"))\n            .setSize(10000)\n            .get();\n        for (SearchHit hit : response.getHits()) {\n            System.out.println(hit.getSourceAsMap().get(\"data\").getClass());\n        }\n    }\n\n    @Test\n    public void test02() {\n        Map<String, Object> esFieldData = new LinkedHashMap<>();\n        esFieldData.put(\"userId\", 2L);\n        esFieldData.put(\"eventId\", 4L);\n        esFieldData.put(\"eventName\", \"网络异常\");\n        esFieldData.put(\"description\", \"第四个事件信息\");\n\n        Map<String, Object> relations = new LinkedHashMap<>();\n        esFieldData.put(\"user_event\", relations);\n        relations.put(\"name\", \"event\");\n        relations.put(\"parent\", \"2\");\n\n        BulkRequestBuilder bulkRequestBuilder = transportClient.prepareBulk();\n        bulkRequestBuilder.add(transportClient.prepareIndex(\"test\", \"osm\", \"2_4\")\n            .setRouting(\"2\")\n            .setSource(esFieldData));\n        commit(bulkRequestBuilder);\n    }\n\n    @Test\n    public void test03() {\n        Map<String, Object> esFieldData = new LinkedHashMap<>();\n        esFieldData.put(\"userId\", 2L);\n        esFieldData.put(\"eventName\", \"网络异常1\");\n\n        Map<String, Object> relations = new LinkedHashMap<>();\n        esFieldData.put(\"user_event\", relations);\n        relations.put(\"name\", \"event\");\n        relations.put(\"parent\", \"2\");\n\n        BulkRequestBuilder bulkRequestBuilder = transportClient.prepareBulk();\n        bulkRequestBuilder.add(transportClient.prepareUpdate(\"test\", \"osm\", \"2_4\").setRouting(\"2\").setDoc(esFieldData));\n        commit(bulkRequestBuilder);\n    }\n\n    @Test\n    public void test04() {\n        BulkRequestBuilder bulkRequestBuilder = transportClient.prepareBulk();\n        bulkRequestBuilder.add(transportClient.prepareDelete(\"test\", \"osm\", \"2_4\"));\n        commit(bulkRequestBuilder);\n    }\n\n    private void commit(BulkRequestBuilder bulkRequestBuilder) {\n        if (bulkRequestBuilder.numberOfActions() > 0) {\n            BulkResponse response = bulkRequestBuilder.execute().actionGet();\n            if (response.hasFailures()) {\n                for (BulkItemResponse itemResponse : response.getItems()) {\n                    if (!itemResponse.isFailed()) {\n                        continue;\n                    }\n\n                    if (itemResponse.getFailure().getStatus() == RestStatus.NOT_FOUND) {\n                        System.out.println(itemResponse.getFailureMessage());\n                    } else {\n                        System.out.println(\"ES bulk commit error\" + itemResponse.getFailureMessage());\n                    }\n                }\n            }\n        }\n    }\n\n    @After\n    public void after() {\n        transportClient.close();\n    }\n}\n"
  },
  {
    "path": "client-adapter/es7x/src/test/java/com/alibaba/otter/canal/client/adapter/es7x/test/ESConnectionTest.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es7x.test;\n\nimport java.net.UnknownHostException;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.elasticsearch.cluster.metadata.MappingMetaData;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.springframework.util.Assert;\n\nimport com.alibaba.otter.canal.client.adapter.es7x.support.ESConnection;\n\n@Ignore\npublic class ESConnectionTest {\n\n    ESConnection esConnection;\n\n    @Before\n    public void init() throws UnknownHostException {\n        String[] hosts = new String[] { \"127.0.0.1:9200\" };\n        Map<String, String> properties = new HashMap<>();\n        properties.put(\"cluster.name\", \"elasticsearch\");\n        esConnection = new ESConnection(hosts, properties, ESConnection.ESClientMode.REST);\n    }\n\n    @Test\n    public void test01() {\n        MappingMetaData mappingMetaData = esConnection.getMapping(\"mytest_user\");\n\n        Map<String, Object> sourceMap = mappingMetaData.getSourceAsMap();\n        Map<String, Object> esMapping = (Map<String, Object>) sourceMap.get(\"properties\");\n        for (Map.Entry<String, Object> entry : esMapping.entrySet()) {\n            Map<String, Object> value = (Map<String, Object>) entry.getValue();\n            if (value.containsKey(\"properties\")) {\n                System.out.println(entry.getKey() + \" object\");\n            } else {\n                System.out.println(entry.getKey() + \" \" + value.get(\"type\"));\n                Assert.notNull(entry.getKey(), \"null column name\");\n                Assert.notNull(value.get(\"type\"), \"null column type\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/es7x/src/test/java/com/alibaba/otter/canal/client/adapter/es7x/test/TestConstant.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es7x.test;\n\nimport java.sql.SQLException;\n\nimport com.alibaba.druid.pool.DruidDataSource;\n\npublic class TestConstant {\n\n    public final static String    jdbcUrl      = \"jdbc:mysql://127.0.0.1:3306/mytest?useUnicode=true\";\n    public final static String    jdbcUser     = \"root\";\n    public final static String    jdbcPassword = \"121212\";\n\n    public final static String    esHosts      = \"127.0.0.1:9300\";\n    public final static String    clusterName  = \"elasticsearch\";\n\n    public final static DruidDataSource dataSource;\n\n    static {\n        dataSource = new DruidDataSource();\n        dataSource.setDriverClassName(\"com.mysql.jdbc.Driver\");\n        dataSource.setUrl(jdbcUrl);\n        dataSource.setUsername(jdbcUser);\n        dataSource.setPassword(jdbcPassword);\n        dataSource.setInitialSize(1);\n        dataSource.setMinIdle(1);\n        dataSource.setMaxActive(1);\n        dataSource.setMaxWait(60000);\n        dataSource.setTimeBetweenEvictionRunsMillis(60000);\n        dataSource.setMinEvictableIdleTimeMillis(300000);\n        dataSource.setPoolPreparedStatements(false);\n        dataSource.setMaxPoolPreparedStatementPerConnectionSize(20);\n        dataSource.setValidationQuery(\"select 1\");\n        try {\n            dataSource.init();\n        } catch (SQLException e) {\n            e.printStackTrace();\n        }\n    }\n\n}\n"
  },
  {
    "path": "client-adapter/es8x/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>canal.client-adapter</artifactId>\n        <groupId>com.alibaba.otter</groupId>\n        <version>1.1.9-SNAPSHOT</version>\n        <relativePath>../pom.xml</relativePath>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>com.alibaba.otter</groupId>\n    <artifactId>client-adapter.es8x</artifactId>\n    <packaging>jar</packaging>\n    <name>canal client adapter es v8x module for otter ${project.version}</name>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>client-adapter.common</artifactId>\n            <version>${project.version}</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>client-adapter.escore</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>co.elastic.clients</groupId>\n            <artifactId>elasticsearch-java</artifactId>\n            <version>8.6.2</version>\n        </dependency>\n        <!--<dependency>\n            <groupId>org.elasticsearch.client</groupId>\n            <artifactId>elasticsearch-rest-client</artifactId>\n            <version>8.6.2</version>\n        </dependency>-->\n        <dependency>\n            <groupId>org.elasticsearch.client</groupId>\n            <artifactId>elasticsearch-rest-high-level-client</artifactId>\n            <version>7.17.9</version>\n        </dependency>\n\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-assembly-plugin</artifactId>\n                <version>2.4</version>\n                <configuration>\n                    <descriptorRefs>\n                        <descriptorRef>jar-with-dependencies</descriptorRef>\n                    </descriptorRefs>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>make-assembly</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>single</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-antrun-plugin</artifactId>\n                <version>1.8</version>\n                <executions>\n                    <execution>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>run</goal>\n                        </goals>\n                        <configuration>\n                            <tasks>\n                                <copy todir=\"${project.basedir}/../launcher/target/classes/es8\" overwrite=\"true\">\n                                    <fileset dir=\"${project.basedir}/target/classes/es8\" erroronmissingdir=\"true\">\n                                        <include name=\"*.yml\" />\n                                    </fileset>\n                                </copy>\n                            </tasks>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "client-adapter/es8x/src/main/java/com/alibaba/otter/canal/client/adapter/es8x/ES8xAdapter.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es8x;\n\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport javax.sql.DataSource;\n\nimport org.elasticsearch.action.search.SearchResponse;\n\nimport com.alibaba.otter.canal.client.adapter.es.core.ESAdapter;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig;\nimport com.alibaba.otter.canal.client.adapter.es8x.etl.ESEtlService;\nimport com.alibaba.otter.canal.client.adapter.es8x.support.ES8xTemplate;\nimport com.alibaba.otter.canal.client.adapter.es8x.support.ESConnection;\nimport com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;\nimport com.alibaba.otter.canal.client.adapter.support.EtlResult;\nimport com.alibaba.otter.canal.client.adapter.support.OuterAdapterConfig;\nimport com.alibaba.otter.canal.client.adapter.support.SPI;\n\n/**\n * ES 8.x 外部适配器\n *\n * @author ymz 2013-02-23\n * @version 1.0.0\n */\n@SPI(\"es8\")\npublic class ES8xAdapter extends ESAdapter {\n\n    private ESConnection esConnection;\n\n    public ESConnection getEsConnection() {\n        return esConnection;\n    }\n\n    @Override\n    public void init(OuterAdapterConfig configuration, Properties envProperties) {\n        try {\n            Map<String, String> properties = configuration.getProperties();\n\n            String[] hostArray = configuration.getHosts().split(\",\");\n            esConnection = new ESConnection(hostArray, properties);\n\n            this.esTemplate = new ES8xTemplate(esConnection);\n\n            envProperties.put(\"es.version\", \"es8\");\n            super.init(configuration, envProperties);\n        } catch (Throwable e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    @Override\n    public Map<String, Object> count(String task) {\n        ESSyncConfig config = esSyncConfig.get(task);\n        ESSyncConfig.ESMapping mapping = config.getEsMapping();\n        SearchResponse response = this.esConnection.new ESSearchRequest(mapping.getIndex()).size(0).getResponse();\n\n        long rowCount = response.getHits().getTotalHits().value;\n        Map<String, Object> res = new LinkedHashMap<>();\n        res.put(\"esIndex\", mapping.getIndex());\n        res.put(\"count\", rowCount);\n        return res;\n    }\n\n    @Override\n    public EtlResult etl(String task, List<String> params) {\n        EtlResult etlResult = new EtlResult();\n        ESSyncConfig config = esSyncConfig.get(task);\n        if (config != null) {\n            DataSource dataSource = DatasourceConfig.DATA_SOURCES.get(config.getDataSourceKey());\n            ESEtlService esEtlService = new ESEtlService(esConnection, config);\n            if (dataSource != null) {\n                return esEtlService.importData(params);\n            } else {\n                etlResult.setSucceeded(false);\n                etlResult.setErrorMessage(\"DataSource not found\");\n                return etlResult;\n            }\n        } else {\n            StringBuilder resultMsg = new StringBuilder();\n            boolean resSuccess = true;\n            for (ESSyncConfig configTmp : esSyncConfig.values()) {\n                // 取所有的destination为task的配置\n                if (configTmp.getDestination().equals(task)) {\n                    ESEtlService esEtlService = new ESEtlService(esConnection, configTmp);\n                    EtlResult etlRes = esEtlService.importData(params);\n                    if (!etlRes.getSucceeded()) {\n                        resSuccess = false;\n                        resultMsg.append(etlRes.getErrorMessage()).append(\"\\n\");\n                    } else {\n                        resultMsg.append(etlRes.getResultMessage()).append(\"\\n\");\n                    }\n                }\n            }\n            if (resultMsg.length() > 0) {\n                etlResult.setSucceeded(resSuccess);\n                if (resSuccess) {\n                    etlResult.setResultMessage(resultMsg.toString());\n                } else {\n                    etlResult.setErrorMessage(resultMsg.toString());\n                }\n                return etlResult;\n            }\n        }\n        etlResult.setSucceeded(false);\n        etlResult.setErrorMessage(\"Task not found\");\n        return etlResult;\n    }\n\n    @Override\n    public void destroy() {\n        super.destroy();\n        if (esConnection != null) {\n            esConnection.close();\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/es8x/src/main/java/com/alibaba/otter/canal/client/adapter/es8x/etl/ESEtlService.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es8x.etl;\n\nimport java.sql.SQLException;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport javax.sql.DataSource;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.elasticsearch.action.search.SearchResponse;\nimport org.elasticsearch.index.query.QueryBuilders;\nimport org.elasticsearch.search.SearchHit;\n\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig.ESMapping;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem.FieldItem;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESBulkResponse;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESIndexRequest;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESUpdateRequest;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESTemplate;\nimport com.alibaba.otter.canal.client.adapter.es8x.support.ES8xTemplate;\nimport com.alibaba.otter.canal.client.adapter.es8x.support.ESConnection;\nimport com.alibaba.otter.canal.client.adapter.es8x.support.ESConnection.ESSearchRequest;\nimport com.alibaba.otter.canal.client.adapter.support.AbstractEtlService;\nimport com.alibaba.otter.canal.client.adapter.support.AdapterConfig;\nimport com.alibaba.otter.canal.client.adapter.support.EtlResult;\nimport com.alibaba.otter.canal.client.adapter.support.Util;\n\n/**\n * ES ETL Service\n *\n * @author rewerma 2018-11-01\n * @version 1.0.0\n */\npublic class ESEtlService extends AbstractEtlService {\n\n    private ESConnection esConnection;\n    private ESTemplate   esTemplate;\n    private ESSyncConfig config;\n\n    public ESEtlService(ESConnection esConnection, ESSyncConfig config){\n        super(\"ES\", config);\n        this.esConnection = esConnection;\n        this.esTemplate = new ES8xTemplate(esConnection);\n        this.config = config;\n    }\n\n    public EtlResult importData(List<String> params) {\n        ESMapping mapping = config.getEsMapping();\n        logger.info(\"start etl to import data to index: {}\", mapping.getIndex());\n        String sql = mapping.getSql();\n        return importData(sql, params);\n    }\n\n    protected boolean executeSqlImport(DataSource ds, String sql, List<Object> values,\n                                       AdapterConfig.AdapterMapping adapterMapping, AtomicLong impCount,\n                                       List<String> errMsg) {\n        try {\n            ESMapping mapping = (ESMapping) adapterMapping;\n            Util.sqlRS(ds, sql, values, rs -> {\n                int count = 0;\n                try {\n                    ESBulkRequest esBulkRequest = this.esConnection.new ES8xBulkRequest();\n\n                    long batchBegin = System.currentTimeMillis();\n                    while (rs.next()) {\n                        Map<String, Object> esFieldData = new LinkedHashMap<>();\n                        Object idVal = null;\n                        for (FieldItem fieldItem : mapping.getSchemaItem().getSelectFields().values()) {\n\n                            String fieldName = fieldItem.getFieldName();\n                            if (mapping.getSkips().contains(fieldName)) {\n                                continue;\n                            }\n\n                            // 如果是主键字段则不插入\n                            if (fieldItem.getFieldName().equals(mapping.getId())) {\n                                idVal = esTemplate.getValFromRS(mapping, rs, fieldName, fieldName);\n                            } else {\n                                Object val = esTemplate.getValFromRS(mapping, rs, fieldName, fieldName);\n                                esFieldData.put(Util.cleanColumn(fieldName), val);\n                            }\n\n                        }\n\n                        if (!mapping.getRelations().isEmpty()) {\n                            mapping.getRelations().forEach((relationField, relationMapping) -> {\n                                Map<String, Object> relations = new HashMap<>();\n                                relations.put(\"name\", relationMapping.getName());\n                                if (StringUtils.isNotEmpty(relationMapping.getParent())) {\n                                    FieldItem parentFieldItem = mapping.getSchemaItem()\n                                        .getSelectFields()\n                                        .get(relationMapping.getParent());\n                                    Object parentVal;\n                                    try {\n                                        parentVal = esTemplate.getValFromRS(mapping,\n                                            rs,\n                                            parentFieldItem.getFieldName(),\n                                            parentFieldItem.getFieldName());\n                                    } catch (SQLException e) {\n                                        throw new RuntimeException(e);\n                                    }\n                                    if (parentVal != null) {\n                                        relations.put(\"parent\", parentVal.toString());\n                                        esFieldData.put(\"$parent_routing\", parentVal.toString());\n\n                                    }\n                                }\n                                esFieldData.put(Util.cleanColumn(relationField), relations);\n                            });\n                        }\n\n                        if (idVal != null) {\n                            String parentVal = (String) esFieldData.remove(\"$parent_routing\");\n                            if (mapping.isUpsert()) {\n                                ESUpdateRequest esUpdateRequest = this.esConnection.new ES8xUpdateRequest(\n                                    mapping.getIndex(),\n                                    idVal.toString()).setDoc(esFieldData).setDocAsUpsert(true);\n\n                                if (StringUtils.isNotEmpty(parentVal)) {\n                                    esUpdateRequest.setRouting(parentVal);\n                                }\n\n                                esBulkRequest.add(esUpdateRequest);\n                            } else {\n                                ESIndexRequest esIndexRequest = this.esConnection.new ES8xIndexRequest(\n                                    mapping.getIndex(),\n                                    idVal.toString()).setSource(esFieldData);\n                                if (StringUtils.isNotEmpty(parentVal)) {\n                                    esIndexRequest.setRouting(parentVal);\n                                }\n                                esBulkRequest.add(esIndexRequest);\n                            }\n                        } else {\n                            idVal = esFieldData.get(mapping.getPk());\n                            ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.getIndex())\n                                .setQuery(QueryBuilders.termQuery(mapping.getPk(), idVal))\n                                .size(10000);\n                            SearchResponse response = esSearchRequest.getResponse();\n                            for (SearchHit hit : response.getHits()) {\n                                ESUpdateRequest esUpdateRequest = this.esConnection.new ES8xUpdateRequest(\n                                    mapping.getIndex(),\n                                    hit.getId()).setDoc(esFieldData);\n                                esBulkRequest.add(esUpdateRequest);\n                            }\n                        }\n\n                        if (esBulkRequest.numberOfActions() % mapping.getCommitBatch() == 0\n                            && esBulkRequest.numberOfActions() > 0) {\n                            long esBatchBegin = System.currentTimeMillis();\n                            ESBulkResponse rp = esBulkRequest.bulk();\n                            if (rp.hasFailures()) {\n                                rp.processFailBulkResponse(\"全量数据 etl 异常 \");\n                            }\n\n                            if (logger.isTraceEnabled()) {\n                                logger.trace(\"全量数据批量导入批次耗时: {}, es执行时间: {}, 批次大小: {}, index; {}\",\n                                    (System.currentTimeMillis() - batchBegin),\n                                    (System.currentTimeMillis() - esBatchBegin),\n                                    esBulkRequest.numberOfActions(),\n                                    mapping.getIndex());\n                            }\n                            batchBegin = System.currentTimeMillis();\n                            esBulkRequest.resetBulk();\n                        }\n                        count++;\n                        impCount.incrementAndGet();\n                    }\n\n                    if (esBulkRequest.numberOfActions() > 0) {\n                        long esBatchBegin = System.currentTimeMillis();\n                        ESBulkResponse rp = esBulkRequest.bulk();\n                        if (rp.hasFailures()) {\n                            rp.processFailBulkResponse(\"全量数据 etl 异常 \");\n                        }\n                        if (logger.isTraceEnabled()) {\n                            logger.trace(\"全量数据批量导入最后批次耗时: {}, es执行时间: {}, 批次大小: {}, index; {}\",\n                                (System.currentTimeMillis() - batchBegin),\n                                (System.currentTimeMillis() - esBatchBegin),\n                                esBulkRequest.numberOfActions(),\n                                mapping.getIndex());\n                        }\n                    }\n                } catch (Exception e) {\n                    logger.error(e.getMessage(), e);\n                    errMsg.add(mapping.getIndex() + \" etl failed! ==>\" + e.getMessage());\n                    throw new RuntimeException(e);\n                }\n                return count;\n            });\n\n            return true;\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/es8x/src/main/java/com/alibaba/otter/canal/client/adapter/es8x/support/ES8xTemplate.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es8x.support;\n\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\nimport javax.sql.DataSource;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.elasticsearch.action.search.SearchResponse;\nimport org.elasticsearch.cluster.metadata.MappingMetadata;\nimport org.elasticsearch.index.query.BoolQueryBuilder;\nimport org.elasticsearch.index.query.QueryBuilders;\nimport org.elasticsearch.search.SearchHit;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig.ESMapping;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem.ColumnItem;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem.FieldItem;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESBulkResponse;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESDeleteRequest;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESIndexRequest;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESUpdateRequest;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESSyncUtil;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESTemplate;\nimport com.alibaba.otter.canal.client.adapter.es8x.support.ESConnection.ESSearchRequest;\nimport com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;\nimport com.alibaba.otter.canal.client.adapter.support.Util;\n\npublic class ES8xTemplate implements ESTemplate {\n\n    private static final Logger                               logger         = LoggerFactory\n        .getLogger(ESTemplate.class);\n\n    private static final int                                  MAX_BATCH_SIZE = 1000;\n    // es 字段类型本地缓存\n    private static ConcurrentMap<String, Map<String, String>> esFieldTypes   = new ConcurrentHashMap<>();\n    private ESConnection                                      esConnection;\n    private ESBulkRequest                                     esBulkRequest;\n\n    public ES8xTemplate(ESConnection esConnection){\n        this.esConnection = esConnection;\n        this.esBulkRequest = this.esConnection.new ES8xBulkRequest();\n    }\n\n    public ESBulkRequest getBulk() {\n        return esBulkRequest;\n    }\n\n    public void resetBulkRequestBuilder() {\n        this.esBulkRequest.resetBulk();\n    }\n\n    @Override\n    public void insert(ESMapping mapping, Object pkVal, Map<String, Object> esFieldData) {\n        if (mapping.getId() != null) {\n            String parentVal = (String) esFieldData.remove(\"$parent_routing\");\n            if (mapping.isUpsert()) {\n                ESUpdateRequest updateRequest = esConnection.new ES8xUpdateRequest(mapping.getIndex(), pkVal.toString())\n                    .setDoc(esFieldData)\n                    .setDocAsUpsert(true);\n                if (StringUtils.isNotEmpty(parentVal)) {\n                    updateRequest.setRouting(parentVal);\n                }\n                getBulk().add(updateRequest);\n            } else {\n                ESIndexRequest indexRequest = esConnection.new ES8xIndexRequest(mapping.getIndex(), pkVal.toString())\n                    .setSource(esFieldData);\n                if (StringUtils.isNotEmpty(parentVal)) {\n                    indexRequest.setRouting(parentVal);\n                }\n                getBulk().add(indexRequest);\n            }\n            commitBulk();\n        } else {\n            ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.getIndex())\n                .setQuery(QueryBuilders.termQuery(mapping.getPk(), pkVal))\n                .size(10000);\n            SearchResponse response = esSearchRequest.getResponse();\n\n            for (SearchHit hit : response.getHits()) {\n                ESUpdateRequest esUpdateRequest = this.esConnection.new ES8xUpdateRequest(mapping.getIndex(),\n                    hit.getId()).setDoc(esFieldData);\n                getBulk().add(esUpdateRequest);\n                commitBulk();\n            }\n        }\n    }\n\n    @Override\n    public void update(ESMapping mapping, Object pkVal, Map<String, Object> esFieldData) {\n        Map<String, Object> esFieldDataTmp = new LinkedHashMap<>(esFieldData.size());\n        esFieldData.forEach((k, v) -> esFieldDataTmp.put(Util.cleanColumn(k), v));\n        append4Update(mapping, pkVal, esFieldDataTmp);\n        commitBulk();\n    }\n\n    @Override\n    public void updateByQuery(ESSyncConfig config, Map<String, Object> paramsTmp, Map<String, Object> esFieldData) {\n        if (paramsTmp.isEmpty()) {\n            return;\n        }\n        ESMapping mapping = config.getEsMapping();\n        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();\n        paramsTmp.forEach((fieldName, value) -> queryBuilder.must(QueryBuilders.termsQuery(fieldName, value)));\n\n        // 查询sql批量更新\n        DataSource ds = DatasourceConfig.DATA_SOURCES.get(config.getDataSourceKey());\n        StringBuilder sql = new StringBuilder(\"SELECT * FROM (\" + mapping.getSql() + \") _v WHERE \");\n        List<Object> values = new ArrayList<>();\n        paramsTmp.forEach((fieldName, value) -> {\n            sql.append(\"_v.\").append(fieldName).append(\"=? AND \");\n            values.add(value);\n        });\n        // TODO 直接外部包裹sql会导致全表扫描性能低, 待优化拼接内部where条件\n        int len = sql.length();\n        sql.delete(len - 4, len);\n        Integer syncCount = (Integer) Util.sqlRS(ds, sql.toString(), values, rs -> {\n            int count = 0;\n            try {\n                while (rs.next()) {\n                    Object idVal = getIdValFromRS(mapping, rs);\n                    append4Update(mapping, idVal, esFieldData);\n                    commitBulk();\n                    count++;\n                }\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n            return count;\n        });\n        if (logger.isTraceEnabled()) {\n            logger.trace(\"Update ES by query affected {} records\", syncCount);\n        }\n    }\n\n    @Override\n    public void delete(ESMapping mapping, Object pkVal, Map<String, Object> esFieldData) {\n        if (mapping.getId() != null) {\n            ESDeleteRequest esDeleteRequest = this.esConnection.new ES8xDeleteRequest(mapping.getIndex(),\n                pkVal.toString());\n            getBulk().add(esDeleteRequest);\n            commitBulk();\n        } else {\n            ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.getIndex())\n                .setQuery(QueryBuilders.termQuery(mapping.getPk(), pkVal))\n                .size(10000);\n            SearchResponse response = esSearchRequest.getResponse();\n            for (SearchHit hit : response.getHits()) {\n                ESUpdateRequest esUpdateRequest = this.esConnection.new ES8xUpdateRequest(mapping.getIndex(),\n                    hit.getId()).setDoc(esFieldData);\n                getBulk().add(esUpdateRequest);\n                commitBulk();\n            }\n        }\n    }\n\n    @Override\n    public void commit() {\n        if (getBulk().numberOfActions() > 0) {\n            ESBulkResponse response = getBulk().bulk();\n            if (response.hasFailures()) {\n                response.processFailBulkResponse(\"ES sync commit error \");\n            }\n            resetBulkRequestBuilder();\n        }\n    }\n\n    @Override\n    public Object getValFromRS(ESMapping mapping, ResultSet resultSet, String fieldName,\n                               String columnName) throws SQLException {\n        fieldName = Util.cleanColumn(fieldName);\n        columnName = Util.cleanColumn(columnName);\n        String esType = getEsType(mapping, fieldName);\n\n        Object value = resultSet.getObject(columnName);\n        if (value instanceof Boolean) {\n            if (!\"boolean\".equals(esType)) {\n                value = resultSet.getByte(columnName);\n            }\n        }\n\n        // 如果是对象类型\n        if (mapping.getObjFields().containsKey(fieldName)) {\n            return ESSyncUtil.convertToEsObj(value, mapping.getObjFields().get(fieldName));\n        } else {\n            return ESSyncUtil.typeConvert(value, esType);\n        }\n    }\n\n    @Override\n    public Object getESDataFromRS(ESMapping mapping, ResultSet resultSet,\n                                  Map<String, Object> esFieldData) throws SQLException {\n        SchemaItem schemaItem = mapping.getSchemaItem();\n        String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();\n        Object resultIdVal = null;\n        for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {\n            Object value = getValFromRS(mapping, resultSet, fieldItem.getFieldName(), fieldItem.getFieldName());\n\n            if (fieldItem.getFieldName().equals(idFieldName)) {\n                resultIdVal = value;\n            }\n\n            if (!fieldItem.getFieldName().equals(mapping.getId())\n                && !mapping.getSkips().contains(fieldItem.getFieldName())) {\n                esFieldData.put(Util.cleanColumn(fieldItem.getFieldName()), value);\n            }\n        }\n\n        // 添加父子文档关联信息\n        putRelationDataFromRS(mapping, schemaItem, resultSet, esFieldData);\n\n        return resultIdVal;\n    }\n\n    @Override\n    public Object getIdValFromRS(ESMapping mapping, ResultSet resultSet) throws SQLException {\n        SchemaItem schemaItem = mapping.getSchemaItem();\n        String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();\n        Object resultIdVal = null;\n        for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {\n            Object value = getValFromRS(mapping, resultSet, fieldItem.getFieldName(), fieldItem.getFieldName());\n\n            if (fieldItem.getFieldName().equals(idFieldName)) {\n                resultIdVal = value;\n                break;\n            }\n        }\n        return resultIdVal;\n    }\n\n    @Override\n    public Object getESDataFromRS(ESMapping mapping, ResultSet resultSet, Map<String, Object> dmlOld,\n                                  Map<String, Object> esFieldData) throws SQLException {\n        SchemaItem schemaItem = mapping.getSchemaItem();\n        String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();\n        Object resultIdVal = null;\n        for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {\n            if (fieldItem.getFieldName().equals(idFieldName)) {\n                resultIdVal = getValFromRS(mapping, resultSet, fieldItem.getFieldName(), fieldItem.getFieldName());\n            }\n\n            for (ColumnItem columnItem : fieldItem.getColumnItems()) {\n                if (dmlOld.containsKey(columnItem.getColumnName())\n                    && !mapping.getSkips().contains(fieldItem.getFieldName())) {\n                    esFieldData.put(Util.cleanColumn(fieldItem.getFieldName()),\n                        getValFromRS(mapping, resultSet, fieldItem.getFieldName(), fieldItem.getFieldName()));\n                    break;\n                }\n            }\n        }\n\n        // 添加父子文档关联信息\n        putRelationDataFromRS(mapping, schemaItem, resultSet, esFieldData);\n\n        return resultIdVal;\n    }\n\n    @Override\n    public Object getValFromData(ESMapping mapping, Map<String, Object> dmlData, String fieldName, String columnName) {\n        String esType = getEsType(mapping, fieldName);\n        Object value = dmlData.get(columnName);\n        if (value instanceof Byte) {\n            if (\"boolean\".equals(esType)) {\n                value = ((Byte) value).intValue() != 0;\n            }\n        }\n\n        // 如果是对象类型\n        if (mapping.getObjFields().containsKey(fieldName)) {\n            return ESSyncUtil.convertToEsObj(value, mapping.getObjFields().get(fieldName));\n        } else {\n            return ESSyncUtil.typeConvert(value, esType);\n        }\n    }\n\n    @Override\n    public Object getESDataFromDmlData(ESMapping mapping, Map<String, Object> dmlData,\n                                       Map<String, Object> esFieldData) {\n        SchemaItem schemaItem = mapping.getSchemaItem();\n        String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();\n        Object resultIdVal = null;\n        for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {\n            String columnName = fieldItem.getColumnItems().iterator().next().getColumnName();\n            Object value = getValFromData(mapping, dmlData, fieldItem.getFieldName(), columnName);\n\n            if (fieldItem.getFieldName().equals(idFieldName)) {\n                resultIdVal = value;\n            }\n\n            if (!fieldItem.getFieldName().equals(mapping.getId())\n                && !mapping.getSkips().contains(fieldItem.getFieldName())) {\n                esFieldData.put(Util.cleanColumn(fieldItem.getFieldName()), value);\n            }\n        }\n\n        // 添加父子文档关联信息\n        putRelationData(mapping, schemaItem, dmlData, esFieldData);\n        return resultIdVal;\n    }\n\n    @Override\n    public Object getESDataFromDmlData(ESMapping mapping, String owner, Map<String, Object> dmlData,\n                                       Map<String, Object> dmlOld, Map<String, Object> esFieldData) {\n        SchemaItem schemaItem = mapping.getSchemaItem();\n        String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();\n        Object resultIdVal = null;\n        for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {\n            ColumnItem columnItem = fieldItem.getColumnItems().iterator().next();\n            if (!columnItem.getOwner().equals(owner)) {\n                continue;\n            }\n            String columnName = columnItem.getColumnName();\n\n            if (fieldItem.getFieldName().equals(idFieldName)) {\n                resultIdVal = getValFromData(mapping, dmlData, fieldItem.getFieldName(), columnName);\n            }\n\n            if (dmlOld.containsKey(columnName) && !mapping.getSkips().contains(fieldItem.getFieldName())) {\n                esFieldData.put(Util.cleanColumn(fieldItem.getFieldName()),\n                    getValFromData(mapping, dmlData, fieldItem.getFieldName(), columnName));\n            }\n        }\n\n        // 添加父子文档关联信息\n        putRelationData(mapping, schemaItem, dmlOld, esFieldData);\n        return resultIdVal;\n    }\n\n    /**\n     * 如果大于批量数则提交批次\n     */\n    private void commitBulk() {\n        if (getBulk().numberOfActions() >= MAX_BATCH_SIZE) {\n            commit();\n        }\n    }\n\n    private void append4Update(ESMapping mapping, Object pkVal, Map<String, Object> esFieldData) {\n        if (mapping.getId() != null) {\n            String parentVal = (String) esFieldData.remove(\"$parent_routing\");\n            if (mapping.isUpsert()) {\n                ESUpdateRequest esUpdateRequest = this.esConnection.new ES8xUpdateRequest(mapping.getIndex(),\n                    pkVal.toString()).setDoc(esFieldData).setDocAsUpsert(true);\n                if (StringUtils.isNotEmpty(parentVal)) {\n                    esUpdateRequest.setRouting(parentVal);\n                }\n                getBulk().add(esUpdateRequest);\n            } else {\n                ESUpdateRequest esUpdateRequest = this.esConnection.new ES8xUpdateRequest(mapping.getIndex(),\n                    pkVal.toString()).setDoc(esFieldData);\n                if (StringUtils.isNotEmpty(parentVal)) {\n                    esUpdateRequest.setRouting(parentVal);\n                }\n                getBulk().add(esUpdateRequest);\n            }\n        } else {\n            ESSearchRequest esSearchRequest = this.esConnection.new ESSearchRequest(mapping.getIndex())\n                .setQuery(QueryBuilders.termQuery(mapping.getPk(), pkVal))\n                .size(10000);\n            SearchResponse response = esSearchRequest.getResponse();\n            for (SearchHit hit : response.getHits()) {\n                ESUpdateRequest esUpdateRequest = this.esConnection.new ES8xUpdateRequest(mapping.getIndex(),\n                    hit.getId()).setDoc(esFieldData);\n                getBulk().add(esUpdateRequest);\n            }\n        }\n    }\n\n    /**\n     * 获取es mapping中的属性类型\n     *\n     * @param mapping mapping配置\n     * @param fieldName 属性名\n     * @return 类型\n     */\n    @SuppressWarnings(\"unchecked\")\n    private String getEsType(ESMapping mapping, String fieldName) {\n        String key = mapping.getIndex() + \"-\" + mapping.getType();\n        Map<String, String> fieldType = esFieldTypes.get(key);\n        if (fieldType != null) {\n            return fieldType.get(fieldName);\n        } else {\n            MappingMetadata mappingMetaData = esConnection.getMapping(mapping.getIndex());\n\n            if (mappingMetaData == null) {\n                throw new IllegalArgumentException(\"Not found the mapping info of index: \" + mapping.getIndex());\n            }\n\n            fieldType = new LinkedHashMap<>();\n\n            Map<String, Object> sourceMap = mappingMetaData.getSourceAsMap();\n            Map<String, Object> esMapping = (Map<String, Object>) sourceMap.get(\"properties\");\n            for (Map.Entry<String, Object> entry : esMapping.entrySet()) {\n                Map<String, Object> value = (Map<String, Object>) entry.getValue();\n                if (value.containsKey(\"properties\")) {\n                    fieldType.put(entry.getKey(), \"object\");\n                } else {\n                    fieldType.put(entry.getKey(), (String) value.get(\"type\"));\n                }\n            }\n            esFieldTypes.put(key, fieldType);\n\n            return fieldType.get(fieldName);\n        }\n    }\n\n    private void putRelationDataFromRS(ESMapping mapping, SchemaItem schemaItem, ResultSet resultSet,\n                                       Map<String, Object> esFieldData) {\n        // 添加父子文档关联信息\n        if (!mapping.getRelations().isEmpty()) {\n            mapping.getRelations().forEach((relationField, relationMapping) -> {\n                Map<String, Object> relations = new HashMap<>();\n                relations.put(\"name\", relationMapping.getName());\n                if (StringUtils.isNotEmpty(relationMapping.getParent())) {\n                    FieldItem parentFieldItem = schemaItem.getSelectFields().get(relationMapping.getParent());\n                    Object parentVal;\n                    try {\n                        parentVal = getValFromRS(mapping,\n                            resultSet,\n                            parentFieldItem.getFieldName(),\n                            parentFieldItem.getFieldName());\n                    } catch (SQLException e) {\n                        throw new RuntimeException(e);\n                    }\n                    if (parentVal != null) {\n                        relations.put(\"parent\", parentVal.toString());\n                        esFieldData.put(\"$parent_routing\", parentVal.toString());\n\n                    }\n                }\n                esFieldData.put(relationField, relations);\n            });\n        }\n    }\n\n    private void putRelationData(ESMapping mapping, SchemaItem schemaItem, Map<String, Object> dmlData,\n                                 Map<String, Object> esFieldData) {\n        // 添加父子文档关联信息\n        if (!mapping.getRelations().isEmpty()) {\n            mapping.getRelations().forEach((relationField, relationMapping) -> {\n                Map<String, Object> relations = new HashMap<>();\n                relations.put(\"name\", relationMapping.getName());\n                if (StringUtils.isNotEmpty(relationMapping.getParent())) {\n                    FieldItem parentFieldItem = schemaItem.getSelectFields().get(relationMapping.getParent());\n                    String columnName = parentFieldItem.getColumnItems().iterator().next().getColumnName();\n                    Object parentVal = getValFromData(mapping, dmlData, parentFieldItem.getFieldName(), columnName);\n                    if (parentVal != null) {\n                        relations.put(\"parent\", parentVal.toString());\n                        esFieldData.put(\"$parent_routing\", parentVal.toString());\n\n                    }\n                }\n                esFieldData.put(relationField, relations);\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/es8x/src/main/java/com/alibaba/otter/canal/client/adapter/es8x/support/ESConnection.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es8x.support;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.net.UnknownHostException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.security.KeyStore;\nimport java.security.cert.Certificate;\nimport java.security.cert.CertificateFactory;\nimport java.util.Arrays;\nimport java.util.Map;\n\nimport javax.net.ssl.SSLContext;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.http.HttpHost;\nimport org.apache.http.auth.AuthScope;\nimport org.apache.http.auth.UsernamePasswordCredentials;\nimport org.apache.http.client.CredentialsProvider;\nimport org.apache.http.impl.client.BasicCredentialsProvider;\nimport org.apache.http.ssl.SSLContextBuilder;\nimport org.apache.http.ssl.SSLContexts;\nimport org.elasticsearch.action.bulk.BulkItemResponse;\nimport org.elasticsearch.action.bulk.BulkRequest;\nimport org.elasticsearch.action.bulk.BulkRequestBuilder;\nimport org.elasticsearch.action.bulk.BulkResponse;\nimport org.elasticsearch.action.delete.DeleteRequest;\nimport org.elasticsearch.action.delete.DeleteRequestBuilder;\nimport org.elasticsearch.action.index.IndexRequest;\nimport org.elasticsearch.action.index.IndexRequestBuilder;\nimport org.elasticsearch.action.search.SearchRequest;\nimport org.elasticsearch.action.search.SearchRequestBuilder;\nimport org.elasticsearch.action.search.SearchResponse;\nimport org.elasticsearch.action.update.UpdateRequest;\nimport org.elasticsearch.action.update.UpdateRequestBuilder;\nimport org.elasticsearch.client.*;\nimport org.elasticsearch.client.indices.GetMappingsRequest;\nimport org.elasticsearch.client.indices.GetMappingsResponse;\nimport org.elasticsearch.cluster.metadata.MappingMetadata;\nimport org.elasticsearch.index.query.QueryBuilder;\nimport org.elasticsearch.rest.RestStatus;\nimport org.elasticsearch.search.builder.SearchSourceBuilder;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest;\n\n/**\n * ES 连接器, 只支持 Rest 方式\n *\n * @author ymz 2023-03-02\n * @version 1.0.0\n */\npublic class ESConnection {\n\n    private static final Logger logger = LoggerFactory.getLogger(ESConnection.class);\n\n    private RestHighLevelClient restHighLevelClient;\n\n    public ESConnection(String[] hosts, Map<String, String> properties) throws UnknownHostException{\n        String caPath = properties.get(\"security.ca.path\");\n        if (StringUtils.isNotEmpty(caPath)) {\n            connectEsWithCa(hosts, properties, caPath);\n        } else {\n            connectEsWithoutCa(hosts, properties);\n        }\n    }\n\n    private void connectEsWithCa(String[] hosts, Map<String, String> properties, String caPath) {\n        Path caCertificatePath = Paths.get(caPath);\n        try (InputStream is = Files.newInputStream(caCertificatePath)) {\n            CertificateFactory factory = CertificateFactory.getInstance(\"X.509\");\n            Certificate trustedCa = factory.generateCertificate(is);\n            KeyStore trustStore = KeyStore.getInstance(\"pkcs12\");\n            trustStore.load(null, null);\n            trustStore.setCertificateEntry(\"ca\", trustedCa);\n            SSLContextBuilder sslContextBuilder = SSLContexts.custom().loadTrustMaterial(trustStore, null);\n            final SSLContext sslContext = sslContextBuilder.build();\n\n            HttpHost[] httpHosts = Arrays.stream(hosts).map(this::createHttpHost).toArray(HttpHost[]::new);\n            RestClientBuilder restClientBuilder = RestClient.builder(httpHosts);\n            String nameAndPwd = properties.get(\"security.auth\");\n            if (StringUtils.isNotEmpty(nameAndPwd) && nameAndPwd.contains(\":\")) {\n                String[] nameAndPwdArr = nameAndPwd.split(\":\");\n                final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();\n                credentialsProvider.setCredentials(AuthScope.ANY,\n                    new UsernamePasswordCredentials(nameAndPwdArr[0], nameAndPwdArr[1]));\n                restClientBuilder.setHttpClientConfigCallback(httpClientBuilder -> {\n                    httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);\n                    return httpClientBuilder.setSSLContext(sslContext);\n                });\n            }\n            restHighLevelClient = new RestHighLevelClientBuilder(restClientBuilder.build())\n                .setApiCompatibilityMode(true)\n                .build();\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    private void connectEsWithoutCa(String[] hosts, Map<String, String> properties) {\n        HttpHost[] httpHosts = Arrays.stream(hosts).map(this::createHttpHost).toArray(HttpHost[]::new);\n        RestClientBuilder restClientBuilder = RestClient.builder(httpHosts);\n        String nameAndPwd = properties.get(\"security.auth\");\n        if (StringUtils.isNotEmpty(nameAndPwd) && nameAndPwd.contains(\":\")) {\n            String[] nameAndPwdArr = nameAndPwd.split(\":\");\n            final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();\n            credentialsProvider.setCredentials(AuthScope.ANY,\n                new UsernamePasswordCredentials(nameAndPwdArr[0], nameAndPwdArr[1]));\n            restClientBuilder.setHttpClientConfigCallback(\n                httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider));\n        }\n        restHighLevelClient = new RestHighLevelClientBuilder(restClientBuilder.build()).setApiCompatibilityMode(true)\n            .build();\n    }\n\n    public void close() {\n        try {\n            restHighLevelClient.close();\n        } catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public MappingMetadata getMapping(String index) {\n        MappingMetadata mappingMetaData = null;\n\n        Map<String, MappingMetadata> mappings;\n        try {\n            GetMappingsRequest request = new GetMappingsRequest();\n            request.indices(index);\n            GetMappingsResponse response = restHighLevelClient.indices().getMapping(request, RequestOptions.DEFAULT);\n\n            mappings = response.mappings();\n        } catch (NullPointerException e) {\n            throw new IllegalArgumentException(\"Not found the mapping info of index: \" + index);\n        } catch (IOException e) {\n            logger.error(e.getMessage(), e);\n            return null;\n        }\n\n        // 通过别名查询mapping返回的是真实索引名称，mappings.get(index)返回null，为兼容别名情况修改如下：\n        mappingMetaData = mappings.get(index);\n        if (mappingMetaData == null && !mappings.isEmpty()) {\n            // 如果通过索引名找不到，可能是别名，取第一个映射\n            mappingMetaData = mappings.values().iterator().next();\n        }\n\n        // 如果还是null，说明索引不存在或没有mapping\n        if (mappingMetaData == null) {\n            throw new IllegalArgumentException(\"Not found the mapping info of index: \" + index);\n        }\n\n        return mappingMetaData;\n    }\n\n    public RestHighLevelClient getRestHighLevelClient() {\n        return restHighLevelClient;\n    }\n\n    public void setRestHighLevelClient(RestHighLevelClient restHighLevelClient) {\n        this.restHighLevelClient = restHighLevelClient;\n    }\n\n    private HttpHost createHttpHost(String uriStr) {\n        URI uri = URI.create(uriStr);\n        if (!org.springframework.util.StringUtils.hasLength(uri.getUserInfo())) {\n            return HttpHost.create(uri.toString());\n        }\n        try {\n            return HttpHost.create(new URI(uri\n                .getScheme(), null, uri.getHost(), uri.getPort(), uri.getPath(), uri.getQuery(), uri.getFragment())\n                    .toString());\n        } catch (URISyntaxException ex) {\n            throw new IllegalStateException(ex);\n        }\n    }\n\n    public static class ES8xBulkResponse implements ESBulkRequest.ESBulkResponse {\n\n        private BulkResponse bulkResponse;\n\n        public ES8xBulkResponse(BulkResponse bulkResponse){\n            this.bulkResponse = bulkResponse;\n        }\n\n        @Override\n        public boolean hasFailures() {\n            return bulkResponse.hasFailures();\n        }\n\n        @Override\n        public void processFailBulkResponse(String errorMsg) {\n            for (BulkItemResponse itemResponse : bulkResponse.getItems()) {\n                if (!itemResponse.isFailed()) {\n                    continue;\n                }\n\n                if (itemResponse.getFailure().getStatus() == RestStatus.NOT_FOUND) {\n                    logger.error(itemResponse.getFailureMessage());\n                } else {\n                    throw new RuntimeException(errorMsg + itemResponse.getFailureMessage());\n                }\n            }\n        }\n    }\n\n    public class ES8xIndexRequest implements ESBulkRequest.ESIndexRequest {\n\n        private IndexRequestBuilder indexRequestBuilder;\n\n        private IndexRequest        indexRequest;\n\n        public ES8xIndexRequest(String index, String id){\n            indexRequest = new IndexRequest(index);\n            indexRequest.id(id);\n\n        }\n\n        public ES8xIndexRequest setSource(Map<String, ?> source) {\n\n            indexRequest.source(source);\n\n            return this;\n        }\n\n        public ES8xIndexRequest setRouting(String routing) {\n\n            indexRequest.routing(routing);\n\n            return this;\n        }\n\n        public IndexRequestBuilder getIndexRequestBuilder() {\n            return indexRequestBuilder;\n        }\n\n        public void setIndexRequestBuilder(IndexRequestBuilder indexRequestBuilder) {\n            this.indexRequestBuilder = indexRequestBuilder;\n        }\n\n        public IndexRequest getIndexRequest() {\n            return indexRequest;\n        }\n\n        public void setIndexRequest(IndexRequest indexRequest) {\n            this.indexRequest = indexRequest;\n        }\n    }\n\n    public class ES8xUpdateRequest implements ESBulkRequest.ESUpdateRequest {\n\n        private UpdateRequestBuilder updateRequestBuilder;\n\n        private UpdateRequest        updateRequest;\n\n        public ES8xUpdateRequest(String index, String id){\n\n            updateRequest = new UpdateRequest(index, id);\n        }\n\n        public ES8xUpdateRequest setDoc(Map source) {\n\n            updateRequest.doc(source);\n\n            return this;\n        }\n\n        public ES8xUpdateRequest setDocAsUpsert(boolean shouldUpsertDoc) {\n\n            updateRequest.docAsUpsert(shouldUpsertDoc);\n\n            return this;\n        }\n\n        public ES8xUpdateRequest setRouting(String routing) {\n\n            updateRequest.routing(routing);\n\n            return this;\n        }\n\n        public UpdateRequestBuilder getUpdateRequestBuilder() {\n            return updateRequestBuilder;\n        }\n\n        public void setUpdateRequestBuilder(UpdateRequestBuilder updateRequestBuilder) {\n            this.updateRequestBuilder = updateRequestBuilder;\n        }\n\n        public UpdateRequest getUpdateRequest() {\n            return updateRequest;\n        }\n\n        public void setUpdateRequest(UpdateRequest updateRequest) {\n            this.updateRequest = updateRequest;\n        }\n    }\n\n    public class ES8xDeleteRequest implements ESBulkRequest.ESDeleteRequest {\n\n        private DeleteRequestBuilder deleteRequestBuilder;\n\n        private DeleteRequest        deleteRequest;\n\n        public ES8xDeleteRequest(String index, String id){\n\n            deleteRequest = new DeleteRequest(index, id);\n\n        }\n\n        public DeleteRequestBuilder getDeleteRequestBuilder() {\n            return deleteRequestBuilder;\n        }\n\n        public void setDeleteRequestBuilder(DeleteRequestBuilder deleteRequestBuilder) {\n            this.deleteRequestBuilder = deleteRequestBuilder;\n        }\n\n        public DeleteRequest getDeleteRequest() {\n            return deleteRequest;\n        }\n\n        public void setDeleteRequest(DeleteRequest deleteRequest) {\n            this.deleteRequest = deleteRequest;\n        }\n    }\n\n    public class ESSearchRequest {\n\n        private SearchRequestBuilder searchRequestBuilder;\n\n        private SearchRequest        searchRequest;\n\n        private SearchSourceBuilder  sourceBuilder;\n\n        public ESSearchRequest(String index){\n\n            searchRequest = new SearchRequest(index);\n            sourceBuilder = new SearchSourceBuilder();\n\n        }\n\n        public ESSearchRequest setQuery(QueryBuilder queryBuilder) {\n\n            sourceBuilder.query(queryBuilder);\n\n            return this;\n        }\n\n        public ESSearchRequest size(int size) {\n\n            sourceBuilder.size(size);\n\n            return this;\n        }\n\n        public SearchResponse getResponse() {\n\n            searchRequest.source(sourceBuilder);\n            try {\n                return restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);\n            } catch (IOException e) {\n                throw new RuntimeException(e);\n            }\n\n        }\n\n        public SearchRequestBuilder getSearchRequestBuilder() {\n            return searchRequestBuilder;\n        }\n\n        public void setSearchRequestBuilder(SearchRequestBuilder searchRequestBuilder) {\n            this.searchRequestBuilder = searchRequestBuilder;\n        }\n\n        public SearchRequest getSearchRequest() {\n            return searchRequest;\n        }\n\n        public void setSearchRequest(SearchRequest searchRequest) {\n            this.searchRequest = searchRequest;\n        }\n    }\n\n    public class ES8xBulkRequest implements ESBulkRequest {\n\n        private BulkRequestBuilder bulkRequestBuilder;\n\n        private BulkRequest        bulkRequest;\n\n        public ES8xBulkRequest(){\n            bulkRequest = new BulkRequest();\n        }\n\n        public void resetBulk() {\n\n            bulkRequest = new BulkRequest();\n\n        }\n\n        public ES8xBulkRequest add(ESIndexRequest esIndexRequest) {\n            ES8xIndexRequest eir = (ES8xIndexRequest) esIndexRequest;\n\n            bulkRequest.add(eir.indexRequest);\n\n            return this;\n        }\n\n        public ES8xBulkRequest add(ESUpdateRequest esUpdateRequest) {\n            ES8xUpdateRequest eur = (ES8xUpdateRequest) esUpdateRequest;\n\n            bulkRequest.add(eur.updateRequest);\n\n            return this;\n        }\n\n        public ES8xBulkRequest add(ESDeleteRequest esDeleteRequest) {\n            ES8xDeleteRequest edr = (ES8xDeleteRequest) esDeleteRequest;\n\n            bulkRequest.add(edr.deleteRequest);\n\n            return this;\n        }\n\n        public int numberOfActions() {\n            return bulkRequest.numberOfActions();\n        }\n\n        public ESBulkResponse bulk() {\n            try {\n                BulkResponse responses = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);\n                return new ES8xBulkResponse(responses);\n            } catch (IOException e) {\n                throw new RuntimeException(e);\n            }\n\n        }\n\n        public BulkRequestBuilder getBulkRequestBuilder() {\n            return bulkRequestBuilder;\n        }\n\n        public void setBulkRequestBuilder(BulkRequestBuilder bulkRequestBuilder) {\n            this.bulkRequestBuilder = bulkRequestBuilder;\n        }\n\n        public BulkRequest getBulkRequest() {\n            return bulkRequest;\n        }\n\n        public void setBulkRequest(BulkRequest bulkRequest) {\n            this.bulkRequest = bulkRequest;\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/es8x/src/main/resources/META-INF/canal/com.alibaba.otter.canal.client.adapter.OuterAdapter",
    "content": "es8=com.alibaba.otter.canal.client.adapter.es8x.ES8xAdapter\n"
  },
  {
    "path": "client-adapter/es8x/src/main/resources/es8/biz_order.yml",
    "content": "dataSourceKey: defaultDS\ndestination: example\ngroupId: g1\nesMapping:\n  _index: customer\n  _id: _id\n  relations:\n    customer_order:\n      name: order\n      parent: customer_id\n  sql: \"select concat('oid_', t.id) as _id,\n        t.customer_id,\n        t.id as order_id,\n        t.serial_code as order_serial,\n        t.c_time as order_time\n        from biz_order t\"\n  skips:\n    - customer_id\n  etlCondition: \"where t.c_time>={}\"\n  commitBatch: 3000\n"
  },
  {
    "path": "client-adapter/es8x/src/main/resources/es8/customer.yml",
    "content": "dataSourceKey: defaultDS\ndestination: example\ngroupId: g1\nesMapping:\n  _index: customer\n  _id: id\n  relations:\n    customer_order:\n      name: customer\n  sql: \"select t.id, t.name, t.email from customer t\"\n  etlCondition: \"where t.c_time>={}\"\n  commitBatch: 3000\n\n\n#{\n#  \"mappings\":{\n#    \"_doc\":{\n#      \"properties\":{\n#        \"id\": {\n#          \"type\": \"long\"\n#        },\n#        \"name\": {\n#          \"type\": \"text\"\n#        },\n#        \"email\": {\n#          \"type\": \"text\"\n#        },\n#        \"order_id\": {\n#          \"type\": \"long\"\n#        },\n#        \"order_serial\": {\n#          \"type\": \"text\"\n#        },\n#        \"order_time\": {\n#          \"type\": \"date\"\n#        },\n#        \"customer_order\":{\n#          \"type\":\"join\",\n#          \"relations\":{\n#            \"customer\":\"order\"\n#          }\n#        }\n#      }\n#    }\n#  }\n#}\n"
  },
  {
    "path": "client-adapter/es8x/src/main/resources/es8/mytest_user.yml",
    "content": "dataSourceKey: defaultDS\ndestination: example\ngroupId: g1\nesMapping:\n  _index: mytest_user\n  _id: _id\n  #  upsert: true\n  #  pk: id\n  sql: \"select a.id as _id, a.name, a.role_id, b.role_name,\n        a.c_time from user a\n        left join role b on b.id=a.role_id\"\n  #  objFields:\n  #    _labels: array:;\n  etlCondition: \"where a.c_time>={}\"\n  commitBatch: 3000\n"
  },
  {
    "path": "client-adapter/es8x/src/test/java/com/alibaba/otter/canal/client/adapter/es8x/test/ESConnectionTest.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es8x.test;\n\nimport com.alibaba.otter.canal.client.adapter.es8x.support.ESConnection;\nimport org.elasticsearch.cluster.metadata.MappingMetadata;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.springframework.util.Assert;\n\nimport java.net.UnknownHostException;\nimport java.util.HashMap;\nimport java.util.Map;\n\n@Ignore\npublic class ESConnectionTest {\n\n    ESConnection esConnection;\n\n    @Before\n    public void init() throws UnknownHostException {\n        String[] hosts = new String[]{\"127.0.0.1:9200\"};\n        Map<String, String> properties = new HashMap<>();\n        properties.put(\"cluster.name\", \"elasticsearch\");\n        esConnection = new ESConnection(hosts, properties);\n    }\n\n    @Test\n    public void test01() {\n        MappingMetadata mappingMetaData = esConnection.getMapping(\"mytest_user\");\n\n        Map<String, Object> sourceMap = mappingMetaData.getSourceAsMap();\n        Map<String, Object> esMapping = (Map<String, Object>) sourceMap.get(\"properties\");\n        for (Map.Entry<String, Object> entry : esMapping.entrySet()) {\n            Map<String, Object> value = (Map<String, Object>) entry.getValue();\n            if (value.containsKey(\"properties\")) {\n                System.out.println(entry.getKey() + \" object\");\n            } else {\n                System.out.println(entry.getKey() + \" \" + value.get(\"type\"));\n                Assert.notNull(entry.getKey(), \"null column name\");\n                Assert.notNull(value.get(\"type\"), \"null column type\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/es8x/src/test/java/com/alibaba/otter/canal/client/adapter/es8x/test/TestConstant.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es8x.test;\n\nimport com.alibaba.druid.pool.DruidDataSource;\n\nimport java.sql.SQLException;\n\npublic class TestConstant {\n\n    public final static String jdbcUrl = \"jdbc:mysql://127.0.0.1:3306/mytest?useUnicode=true\";\n    public final static String jdbcUser = \"root\";\n    public final static String jdbcPassword = \"121212\";\n\n    public final static String esHosts = \"127.0.0.1:9300\";\n    public final static String clusterName = \"elasticsearch\";\n\n    public final static DruidDataSource dataSource;\n\n    static {\n        dataSource = new DruidDataSource();\n        dataSource.setDriverClassName(\"com.mysql.jdbc.Driver\");\n        dataSource.setUrl(jdbcUrl);\n        dataSource.setUsername(jdbcUser);\n        dataSource.setPassword(jdbcPassword);\n        dataSource.setInitialSize(1);\n        dataSource.setMinIdle(1);\n        dataSource.setMaxActive(1);\n        dataSource.setMaxWait(60000);\n        dataSource.setTimeBetweenEvictionRunsMillis(60000);\n        dataSource.setMinEvictableIdleTimeMillis(300000);\n        dataSource.setPoolPreparedStatements(false);\n        dataSource.setMaxPoolPreparedStatementPerConnectionSize(20);\n        dataSource.setValidationQuery(\"select 1\");\n        try {\n            dataSource.init();\n        } catch (SQLException e) {\n            e.printStackTrace();\n        }\n    }\n\n}\n"
  },
  {
    "path": "client-adapter/escore/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>canal.client-adapter</artifactId>\n        <groupId>com.alibaba.otter</groupId>\n        <version>1.1.9-SNAPSHOT</version>\n        <relativePath>../pom.xml</relativePath>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>com.alibaba.otter</groupId>\n    <artifactId>client-adapter.escore</artifactId>\n    <packaging>jar</packaging>\n    <name>canal client adapter escore module for otter ${project.version}</name>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>client-adapter.common</artifactId>\n            <version>${project.version}</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid</artifactId>\n            <scope>provided</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.h2database</groupId>\n            <artifactId>h2</artifactId>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "client-adapter/escore/src/main/java/com/alibaba/otter/canal/client/adapter/es/core/ESAdapter.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es.core;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.apache.commons.lang.StringUtils;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.alibaba.otter.canal.client.adapter.OuterAdapter;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfigLoader;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SqlParser;\nimport com.alibaba.otter.canal.client.adapter.es.core.monitor.ESConfigMonitor;\nimport com.alibaba.otter.canal.client.adapter.es.core.service.ESSyncService;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESTemplate;\nimport com.alibaba.otter.canal.client.adapter.support.*;\n\n/**\n * ES外部适配器\n *\n * @author rewerma 2018-10-20\n * @version 1.0.0\n */\npublic abstract class ESAdapter implements OuterAdapter {\n\n    protected Map<String, ESSyncConfig>              esSyncConfig        = new ConcurrentHashMap<>(); // 文件名对应配置\n    protected Map<String, Map<String, ESSyncConfig>> dbTableEsSyncConfig = new ConcurrentHashMap<>(); // schema-table对应配置\n\n    protected ESTemplate                             esTemplate;\n\n    protected ESSyncService                          esSyncService;\n\n    protected ESConfigMonitor                        esConfigMonitor;\n\n    protected Properties                             envProperties;\n\n    protected OuterAdapterConfig                     configuration;\n\n    public ESSyncService getEsSyncService() {\n        return esSyncService;\n    }\n\n    public Map<String, ESSyncConfig> getEsSyncConfig() {\n        return esSyncConfig;\n    }\n\n    public Map<String, Map<String, ESSyncConfig>> getDbTableEsSyncConfig() {\n        return dbTableEsSyncConfig;\n    }\n\n    @Override\n    public void init(OuterAdapterConfig configuration, Properties envProperties) {\n        try {\n            this.envProperties = envProperties;\n            this.configuration = configuration;\n            Map<String, ESSyncConfig> esSyncConfigTmp = ESSyncConfigLoader.load(envProperties);\n            // 过滤不匹配的key的配置\n            esSyncConfigTmp.forEach((key, config) -> {\n                addConfig(key, config);\n            });\n\n            esSyncService = new ESSyncService(esTemplate);\n\n            esConfigMonitor = new ESConfigMonitor();\n            esConfigMonitor.init(this, envProperties);\n        } catch (Throwable e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    @Override\n    public void sync(List<Dml> dmls) {\n        if (dmls == null || dmls.isEmpty()) {\n            return;\n        }\n        for (Dml dml : dmls) {\n            if (!dml.getIsDdl()) {\n                sync(dml);\n            }\n        }\n        esSyncService.commit(); // 批次统一提交\n\n    }\n\n    private void sync(Dml dml) {\n        String database = dml.getDatabase();\n        String table = dml.getTable();\n        Map<String, ESSyncConfig> configMap;\n        if (envProperties != null && !\"tcp\".equalsIgnoreCase(envProperties.getProperty(\"canal.conf.mode\"))) {\n            configMap = dbTableEsSyncConfig\n                .get(StringUtils.trimToEmpty(dml.getDestination()) + \"-\" + StringUtils.trimToEmpty(dml.getGroupId())\n                     + \"_\" + database + \"-\" + table);\n        } else {\n            configMap = dbTableEsSyncConfig\n                .get(StringUtils.trimToEmpty(dml.getDestination()) + \"_\" + database + \"-\" + table);\n        }\n\n        if (configMap != null && !configMap.values().isEmpty()) {\n            esSyncService.sync(configMap.values(), dml);\n        }\n    }\n\n    @Override\n    public abstract EtlResult etl(String task, List<String> params);\n\n    @Override\n    public abstract Map<String, Object> count(String task);\n\n    @Override\n    public void destroy() {\n        if (esConfigMonitor != null) {\n            esConfigMonitor.destroy();\n        }\n    }\n\n    @Override\n    public String getDestination(String task) {\n        ESSyncConfig config = esSyncConfig.get(task);\n        if (config != null) {\n            return config.getDestination();\n        }\n        return null;\n    }\n\n    private void addSyncConfigToCache(String configName, ESSyncConfig config) {\n        Properties envProperties = this.envProperties;\n        SchemaItem schemaItem = SqlParser.parse(config.getEsMapping().getSql());\n        config.getEsMapping().setSchemaItem(schemaItem);\n\n        DruidDataSource dataSource = DatasourceConfig.DATA_SOURCES.get(config.getDataSourceKey());\n        if (dataSource == null || dataSource.getUrl() == null) {\n            throw new RuntimeException(\"No data source found: \" + config.getDataSourceKey());\n        }\n        Pattern pattern = Pattern.compile(\".*:(.*)://.*/(.*)\\\\?.*$\");\n        Matcher matcher = pattern.matcher(dataSource.getUrl());\n        if (!matcher.find()) {\n            throw new RuntimeException(\"Not found the schema of jdbc-url: \" + config.getDataSourceKey());\n        }\n        String schema = matcher.group(2);\n        schemaItem.getAliasTableItems().values().forEach(tableItem -> {\n            Map<String, ESSyncConfig> esSyncConfigMap;\n            String schemaKey = tableItem.getSchema() == null ? schema : tableItem.getSchema();\n            if (envProperties != null && !\"tcp\".equalsIgnoreCase(envProperties.getProperty(\"canal.conf.mode\"))) {\n                esSyncConfigMap = dbTableEsSyncConfig\n                    .computeIfAbsent(StringUtils.trimToEmpty(config.getDestination()) + \"-\"\n                                     + StringUtils.trimToEmpty(config.getGroupId()) + \"_\" + schemaKey + \"-\"\n                                     + tableItem.getTableName(),\n                        k -> new ConcurrentHashMap<>());\n            } else {\n                esSyncConfigMap = dbTableEsSyncConfig.computeIfAbsent(\n                    StringUtils.trimToEmpty(config.getDestination()) + \"_\" + schemaKey + \"-\" + tableItem.getTableName(),\n                    k -> new ConcurrentHashMap<>());\n            }\n\n            esSyncConfigMap.put(configName, config);\n        });\n    }\n\n    public boolean addConfig(String fileName, ESSyncConfig config) {\n        if (match(config)) {\n            esSyncConfig.put(fileName, config);\n            addSyncConfigToCache(fileName, config);\n            FileName2KeyMapping.register(getClass().getAnnotation(SPI.class).value(), fileName, configuration.getKey());\n            return true;\n        }\n        return false;\n    }\n\n    public void updateConfig(String fileName, ESSyncConfig config) {\n        if (config.getOuterAdapterKey() != null && !config.getOuterAdapterKey().equals(configuration.getKey())) {\n            // 理论上不允许改这个 因为本身就是通过这个关联起Adapter和Config的\n            throw new RuntimeException(\"not allow to change outAdapterKey\");\n        }\n        esSyncConfig.put(fileName, config);\n        addSyncConfigToCache(fileName, config);\n    }\n\n    public void deleteConfig(String fileName) {\n        esSyncConfig.remove(fileName);\n        for (Map<String, ESSyncConfig> configMap : dbTableEsSyncConfig.values()) {\n            if (configMap != null) {\n                configMap.remove(fileName);\n            }\n        }\n        FileName2KeyMapping.unregister(getClass().getAnnotation(SPI.class).value(), fileName);\n    }\n\n    private boolean match(ESSyncConfig config) {\n        boolean sameMatch = config.getOuterAdapterKey() != null\n                            && config.getOuterAdapterKey().equalsIgnoreCase(configuration.getKey());\n        boolean prefixMatch = config.getOuterAdapterKey() == null && configuration.getKey()\n            .startsWith(StringUtils\n                .join(new String[] { Util.AUTO_GENERATED_PREFIX, config.getDestination(), config.getGroupId() }, '-'));\n        return sameMatch || prefixMatch;\n    }\n}\n"
  },
  {
    "path": "client-adapter/escore/src/main/java/com/alibaba/otter/canal/client/adapter/es/core/config/ESSyncConfig.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es.core.config;\n\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.alibaba.otter.canal.client.adapter.support.AdapterConfig;\nimport org.springframework.beans.factory.annotation.Value;\n\n/**\n * ES 映射配置\n *\n * @author rewerma 2018-11-01\n * @version 1.0.0\n */\npublic class ESSyncConfig implements AdapterConfig {\n\n    private String    dataSourceKey;    // 数据源key\n\n    private String    outerAdapterKey;  // adapter key\n\n    private String    groupId;          // group id\n\n    private String    destination;      // canal destination\n\n    private ESMapping esMapping;\n\n    private String    esVersion = \"es6\";\n\n    public void validate() {\n        if (esMapping.index == null) {\n            throw new NullPointerException(\"esMapping._index\");\n        }\n        if (\"es6\".equals(esVersion) && esMapping.type == null) {\n            throw new NullPointerException(\"esMapping._type\");\n        }\n        if (esMapping.id == null && esMapping.getPk() == null) {\n            throw new NullPointerException(\"esMapping._id or esMapping.pk\");\n        }\n        if (esMapping.sql == null) {\n            throw new NullPointerException(\"esMapping.sql\");\n        }\n    }\n\n    public String getDataSourceKey() {\n        return dataSourceKey;\n    }\n\n    public void setDataSourceKey(String dataSourceKey) {\n        this.dataSourceKey = dataSourceKey;\n    }\n\n    public String getOuterAdapterKey() {\n        return outerAdapterKey;\n    }\n\n    public void setOuterAdapterKey(String outerAdapterKey) {\n        this.outerAdapterKey = outerAdapterKey;\n    }\n\n    public String getGroupId() {\n        return groupId;\n    }\n\n    public void setGroupId(String groupId) {\n        this.groupId = groupId;\n    }\n\n    public String getDestination() {\n        return destination;\n    }\n\n    public void setDestination(String destination) {\n        this.destination = destination;\n    }\n\n    public ESMapping getEsMapping() {\n        return esMapping;\n    }\n\n    public void setEsMapping(ESMapping esMapping) {\n        this.esMapping = esMapping;\n    }\n\n    public ESMapping getMapping() {\n        return esMapping;\n    }\n\n    public String getEsVersion() {\n        return esVersion;\n    }\n\n    public void setEsVersion(String esVersion) {\n        this.esVersion = esVersion;\n    }\n\n    public static class ESMapping implements AdapterMapping {\n\n        @Value(\"${_index}\")\n        private String index;\n\n        @Value(\"${_type}\")\n        private String type;\n\n        @Value(\"${_id}\")\n        private String id;\n        private boolean                      upsert          = false;\n        private String                       pk;\n        private Map<String, RelationMapping> relations       = new LinkedHashMap<>();\n        private String                       sql;\n        // 对象字段, 例: objFields:\n        // - _labels: array:;\n        private Map<String, String>          objFields       = new LinkedHashMap<>();\n        private List<String>                 skips           = new ArrayList<>();\n        private int                          commitBatch     = 1000;\n        private String                       etlCondition;\n        private boolean                      syncByTimestamp = false;                // 是否按时间戳定时同步\n        private Long                         syncInterval;                           // 同步时间间隔\n\n        private SchemaItem                   schemaItem;                             // sql解析结果模型\n\n        public String getIndex() {\n            return index;\n        }\n\n        public void setIndex(String index) {\n            this.index = index;\n        }\n\n        public String getType() {\n            return type;\n        }\n\n        public void setType(String type) {\n            this.type = type;\n        }\n\n        public String getId() {\n            return id;\n        }\n\n        public void setId(String id) {\n            this.id = id;\n        }\n\n        public boolean isUpsert() {\n            return upsert;\n        }\n\n        public void setUpsert(boolean upsert) {\n            this.upsert = upsert;\n        }\n\n        public String getPk() {\n            return pk;\n        }\n\n        public void setPk(String pk) {\n            this.pk = pk;\n        }\n\n        public Map<String, String> getObjFields() {\n            return objFields;\n        }\n\n        public void setObjFields(Map<String, String> objFields) {\n            this.objFields = objFields;\n        }\n\n        public List<String> getSkips() {\n            return skips;\n        }\n\n        public void setSkips(List<String> skips) {\n            this.skips = skips;\n        }\n\n        public Map<String, RelationMapping> getRelations() {\n            return relations;\n        }\n\n        public void setRelations(Map<String, RelationMapping> relations) {\n            this.relations = relations;\n        }\n\n        public String getSql() {\n            return sql;\n        }\n\n        public void setSql(String sql) {\n            this.sql = sql;\n        }\n\n        public int getCommitBatch() {\n            return commitBatch;\n        }\n\n        public void setCommitBatch(int commitBatch) {\n            this.commitBatch = commitBatch;\n        }\n\n        public String getEtlCondition() {\n            return etlCondition;\n        }\n\n        public void setEtlCondition(String etlCondition) {\n            this.etlCondition = etlCondition;\n        }\n\n        public Long getSyncInterval() {\n            return syncInterval;\n        }\n\n        public void setSyncInterval(Long syncInterval) {\n            this.syncInterval = syncInterval;\n        }\n\n        public boolean isSyncByTimestamp() {\n            return syncByTimestamp;\n        }\n\n        public void setSyncByTimestamp(boolean syncByTimestamp) {\n            this.syncByTimestamp = syncByTimestamp;\n        }\n\n        public SchemaItem getSchemaItem() {\n            return schemaItem;\n        }\n\n        public void setSchemaItem(SchemaItem schemaItem) {\n            this.schemaItem = schemaItem;\n        }\n    }\n\n    public static class RelationMapping {\n\n        private String name;\n        private String parent;\n\n        public String getName() {\n            return name;\n        }\n\n        public void setName(String name) {\n            this.name = name;\n        }\n\n        public String getParent() {\n            return parent;\n        }\n\n        public void setParent(String parent) {\n            this.parent = parent;\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/escore/src/main/java/com/alibaba/otter/canal/client/adapter/es/core/config/ESSyncConfigLoader.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es.core.config;\n\nimport com.alibaba.otter.canal.client.adapter.support.YamlUtils;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.client.adapter.support.MappingConfigsLoader;\n\n/**\n * ES 配置装载器\n *\n * @author rewerma 2018-11-01\n * @version 1.0.0\n */\npublic class ESSyncConfigLoader {\n\n    private static Logger logger = LoggerFactory.getLogger(ESSyncConfigLoader.class);\n\n    public static synchronized Map<String, ESSyncConfig> load(Properties envProperties) {\n        logger.info(\"## Start loading es mapping config ... \");\n\n        Map<String, ESSyncConfig> esSyncConfig = new LinkedHashMap<>();\n\n        String esv = envProperties.getProperty(\"es.version\");\n        Map<String, String> configContentMap = MappingConfigsLoader.loadConfigs(esv);\n        configContentMap.forEach((fileName, content) -> {\n            ESSyncConfig config = YamlUtils.ymlToObj(null, content, ESSyncConfig.class, null, envProperties);\n            if (config == null) {\n                return;\n            }\n            config.setEsVersion(esv);\n            try {\n                config.validate();\n            } catch (Exception e) {\n                throw new RuntimeException(\"ERROR Config: \" + fileName + \" \" + e.getMessage(), e);\n            }\n            esSyncConfig.put(fileName, config);\n        });\n\n        logger.info(\"## ES mapping config loaded\");\n        return esSyncConfig;\n    }\n}\n"
  },
  {
    "path": "client-adapter/escore/src/main/java/com/alibaba/otter/canal/client/adapter/es/core/config/SchemaItem.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es.core.config;\n\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\n\n/**\n * ES 映射配置视图\n *\n * @author rewerma 2018-11-01\n * @version 1.0.0\n */\npublic class SchemaItem {\n\n    private Map<String, TableItem>                aliasTableItems = new LinkedHashMap<>(); // 别名对应表名\n    private Map<String, FieldItem>                selectFields    = new LinkedHashMap<>(); // 查询字段\n    private String                                sql;\n\n    private volatile Map<String, List<TableItem>> tableItemAliases;\n    private volatile Map<String, List<FieldItem>> columnFields;\n    private volatile Boolean                      allFieldsSimple;\n\n    public void init() {\n        this.getTableItemAliases();\n        this.getColumnFields();\n        this.isAllFieldsSimple();\n        aliasTableItems.values().forEach(tableItem -> {\n            tableItem.getRelationTableFields();\n            tableItem.getRelationSelectFieldItems();\n        });\n    }\n\n    public Map<String, TableItem> getAliasTableItems() {\n        return aliasTableItems;\n    }\n\n    public void setAliasTableItems(Map<String, TableItem> aliasTableItems) {\n        this.aliasTableItems = aliasTableItems;\n    }\n\n    public String getSql() {\n        return sql;\n    }\n\n    public void setSql(String sql) {\n        this.sql = sql;\n    }\n\n    public Map<String, FieldItem> getSelectFields() {\n        return selectFields;\n    }\n\n    public void setSelectFields(Map<String, FieldItem> selectFields) {\n        this.selectFields = selectFields;\n    }\n\n    public String toSql() {\n        // todo\n        return null;\n    }\n\n    public Map<String, List<TableItem>> getTableItemAliases() {\n        if (tableItemAliases == null) {\n            synchronized (SchemaItem.class) {\n                if (tableItemAliases == null) {\n                    tableItemAliases = new LinkedHashMap<>();\n                    aliasTableItems.forEach((alias, tableItem) -> {\n                        List<TableItem> aliases = tableItemAliases\n                            .computeIfAbsent(tableItem.getTableName().toLowerCase(), k -> new ArrayList<>());\n                        aliases.add(tableItem);\n                    });\n                }\n            }\n        }\n        return tableItemAliases;\n    }\n\n    public Map<String, List<FieldItem>> getColumnFields() {\n        if (columnFields == null) {\n            synchronized (SchemaItem.class) {\n                if (columnFields == null) {\n                    columnFields = new LinkedHashMap<>();\n                    getSelectFields()\n                        .forEach((fieldName, fieldItem) -> fieldItem.getColumnItems().forEach(columnItem -> {\n                            // TableItem tableItem = getAliasTableItems().get(columnItem.getOwner());\n                            // if (!tableItem.isSubQuery()) {\n                            //当数据列并非原始列时，columnName是空的，例如concat('px',id)\n                            if(columnItem.getColumnName() != null) {\n                                List<FieldItem> fieldItems = columnFields.computeIfAbsent(\n                                        columnItem.getOwner() + \".\" + columnItem.getColumnName(),\n                                        k -> new ArrayList<>());\n                                fieldItems.add(fieldItem);\n                            }\n                            // } else {\n                            // tableItem.getSubQueryFields().forEach(subQueryField -> {\n                            // List<FieldItem> fieldItems = columnFields.computeIfAbsent(\n                            // columnItem.getOwner() + \".\" + subQueryField.getColumn().getColumnName(),\n                            // k -> new ArrayList<>());\n                            // fieldItems.add(fieldItem);\n                            // });\n                            // }\n                        }));\n                }\n            }\n        }\n        return columnFields;\n    }\n\n    public boolean isAllFieldsSimple() {\n        if (allFieldsSimple == null) {\n            synchronized (SchemaItem.class) {\n                if (allFieldsSimple == null) {\n                    allFieldsSimple = true;\n\n                    for (FieldItem fieldItem : getSelectFields().values()) {\n                        if (fieldItem.isMethod() || fieldItem.isBinaryOp()) {\n                            allFieldsSimple = false;\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n\n        return allFieldsSimple;\n    }\n\n    public TableItem getMainTable() {\n        if (!aliasTableItems.isEmpty()) {\n            return aliasTableItems.values().iterator().next();\n        } else {\n            return null;\n        }\n    }\n\n    public FieldItem getIdFieldItem(ESSyncConfig.ESMapping mapping) {\n        if (mapping.getId() != null) {\n            return getSelectFields().get(mapping.getId());\n        } else {\n            return getSelectFields().get(mapping.getPk());\n        }\n    }\n\n    public static class TableItem {\n\n        private SchemaItem                               schemaItem;\n\n        private String                                   schema;\n        private String                                   tableName;\n        private String                                   alias;\n        private String                                   subQuerySql;\n        private List<FieldItem>                          subQueryFields = new ArrayList<>();\n        private List<RelationFieldsPair>                 relationFields = new ArrayList<>();\n\n        private boolean                                  main;\n        private boolean                                  subQuery;\n\n        private volatile Map<FieldItem, List<FieldItem>> relationTableFields;               // 当前表关联条件字段对应主表查询字段\n        private volatile List<FieldItem>                 relationSelectFieldItems;          // 子表所在主表的查询字段\n\n        public TableItem(SchemaItem schemaItem){\n            this.schemaItem = schemaItem;\n        }\n\n        public SchemaItem getSchemaItem() {\n            return schemaItem;\n        }\n\n        public void setSchemaItem(SchemaItem schemaItem) {\n            this.schemaItem = schemaItem;\n        }\n\n        public String getSchema() {\n            return schema;\n        }\n\n        public void setSchema(String schema) {\n            this.schema = schema;\n        }\n\n        public String getTableName() {\n            return tableName;\n        }\n\n        public void setTableName(String tableName) {\n            this.tableName = tableName;\n        }\n\n        public String getAlias() {\n            return alias;\n        }\n\n        public void setAlias(String alias) {\n            this.alias = alias;\n        }\n\n        public String getSubQuerySql() {\n            return subQuerySql;\n        }\n\n        public void setSubQuerySql(String subQuerySql) {\n            this.subQuerySql = subQuerySql;\n        }\n\n        public boolean isMain() {\n            return main;\n        }\n\n        public void setMain(boolean main) {\n            this.main = main;\n        }\n\n        public boolean isSubQuery() {\n            return subQuery;\n        }\n\n        public void setSubQuery(boolean subQuery) {\n            this.subQuery = subQuery;\n        }\n\n        public List<FieldItem> getSubQueryFields() {\n            return subQueryFields;\n        }\n\n        public void setSubQueryFields(List<FieldItem> subQueryFields) {\n            this.subQueryFields = subQueryFields;\n        }\n\n        public List<RelationFieldsPair> getRelationFields() {\n            return relationFields;\n        }\n\n        public void setRelationFields(List<RelationFieldsPair> relationFields) {\n            this.relationFields = relationFields;\n        }\n\n        public Map<FieldItem, List<FieldItem>> getRelationTableFields() {\n            if (relationTableFields == null) {\n                synchronized (SchemaItem.class) {\n                    if (relationTableFields == null) {\n                        relationTableFields = new LinkedHashMap<>();\n\n                        getRelationFields().forEach(relationFieldsPair -> {\n                            FieldItem leftFieldItem = relationFieldsPair.getLeftFieldItem();\n                            FieldItem rightFieldItem = relationFieldsPair.getRightFieldItem();\n                            FieldItem currentTableRelField = null;\n                            if (getAlias().equals(leftFieldItem.getOwner())) {\n                                currentTableRelField = leftFieldItem;\n                            } else if (getAlias().equals(rightFieldItem.getOwner())) {\n                                currentTableRelField = rightFieldItem;\n                            }\n\n                            if (currentTableRelField != null) {\n                                List<FieldItem> selectFieldItem = getSchemaItem().getColumnFields()\n                                    .get(leftFieldItem.getOwner() + \".\" + leftFieldItem.getColumn().getColumnName());\n                                if (selectFieldItem != null && !selectFieldItem.isEmpty()) {\n                                    relationTableFields.put(currentTableRelField, selectFieldItem);\n                                } else {\n                                    selectFieldItem = getSchemaItem().getColumnFields()\n                                        .get(rightFieldItem.getOwner() + \".\"\n                                             + rightFieldItem.getColumn().getColumnName());\n                                    if (selectFieldItem != null && !selectFieldItem.isEmpty()) {\n                                        relationTableFields.put(currentTableRelField, selectFieldItem);\n                                    } else {\n                                        throw new UnsupportedOperationException(\n                                            \"Relation condition column must in select columns.\");\n                                    }\n                                }\n                            }\n                        });\n                    }\n                }\n            }\n            return relationTableFields;\n        }\n\n        public List<FieldItem> getRelationSelectFieldItems() {\n            if (relationSelectFieldItems == null) {\n                synchronized (SchemaItem.class) {\n                    if (relationSelectFieldItems == null) {\n                        List<FieldItem> relationSelectFieldItemsTmp = new ArrayList<>();\n                        for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {\n                            if (fieldItem.getOwners().contains(getAlias())) {\n                                relationSelectFieldItemsTmp.add(fieldItem);\n                            }\n                        }\n                        relationSelectFieldItems = relationSelectFieldItemsTmp;\n                    }\n                }\n            }\n            return relationSelectFieldItems;\n        }\n    }\n\n    public static class RelationFieldsPair {\n\n        private FieldItem leftFieldItem;\n        private FieldItem rightFieldItem;\n\n        public RelationFieldsPair(FieldItem leftFieldItem, FieldItem rightFieldItem){\n            this.leftFieldItem = leftFieldItem;\n            this.rightFieldItem = rightFieldItem;\n        }\n\n        public FieldItem getLeftFieldItem() {\n            return leftFieldItem;\n        }\n\n        public void setLeftFieldItem(FieldItem leftFieldItem) {\n            this.leftFieldItem = leftFieldItem;\n        }\n\n        public FieldItem getRightFieldItem() {\n            return rightFieldItem;\n        }\n\n        public void setRightFieldItem(FieldItem rightFieldItem) {\n            this.rightFieldItem = rightFieldItem;\n        }\n    }\n\n    public static class FieldItem {\n\n        private String           fieldName;\n        private String           expr;\n        private List<ColumnItem> columnItems = new ArrayList<>();\n        private List<String>     owners      = new ArrayList<>();\n\n        private boolean          method;\n        private boolean          binaryOp;\n\n        public String getFieldName() {\n            return fieldName;\n        }\n\n        public void setFieldName(String fieldName) {\n            this.fieldName = fieldName;\n        }\n\n        public String getExpr() {\n            return expr;\n        }\n\n        public void setExpr(String expr) {\n            this.expr = expr;\n        }\n\n        public List<ColumnItem> getColumnItems() {\n            return columnItems;\n        }\n\n        public void setColumnItems(List<ColumnItem> columnItems) {\n            this.columnItems = columnItems;\n        }\n\n        public boolean isMethod() {\n            return method;\n        }\n\n        public void setMethod(boolean method) {\n            this.method = method;\n        }\n\n        public boolean isBinaryOp() {\n            return binaryOp;\n        }\n\n        public void setBinaryOp(boolean binaryOp) {\n            this.binaryOp = binaryOp;\n        }\n\n        public List<String> getOwners() {\n            return owners;\n        }\n\n        public void setOwners(List<String> owners) {\n            this.owners = owners;\n        }\n\n        public void addColumn(ColumnItem columnItem) {\n            columnItems.add(columnItem);\n        }\n\n        public ColumnItem getColumn() {\n            if (!columnItems.isEmpty()) {\n                return columnItems.get(0);\n            } else {\n                return null;\n            }\n        }\n\n        public String getOwner() {\n            if (!owners.isEmpty()) {\n                return owners.get(0);\n            } else {\n                return null;\n            }\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (o == null || getClass() != o.getClass()) return false;\n\n            FieldItem fieldItem = (FieldItem) o;\n\n            return fieldName != null ? fieldName.equals(fieldItem.fieldName) : fieldItem.fieldName == null;\n        }\n\n        @Override\n        public int hashCode() {\n            return fieldName != null ? fieldName.hashCode() : 0;\n        }\n    }\n\n    public static class ColumnItem {\n\n        private String owner;\n        private String columnName;\n\n        public String getOwner() {\n            return owner;\n        }\n\n        public void setOwner(String owner) {\n            this.owner = owner;\n        }\n\n        public String getColumnName() {\n            return columnName;\n        }\n\n        public void setColumnName(String columnName) {\n            this.columnName = columnName;\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/escore/src/main/java/com/alibaba/otter/canal/client/adapter/es/core/config/SqlParser.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es.core.config;\n\nimport static com.alibaba.druid.sql.ast.expr.SQLBinaryOperator.BooleanAnd;\nimport static com.alibaba.druid.sql.ast.expr.SQLBinaryOperator.Equality;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.stream.Collectors;\n\nimport com.alibaba.druid.sql.SQLUtils;\nimport com.alibaba.druid.sql.ast.SQLExpr;\nimport com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;\nimport com.alibaba.druid.sql.ast.expr.SQLCaseExpr;\nimport com.alibaba.druid.sql.ast.expr.SQLCharExpr;\nimport com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;\nimport com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;\nimport com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;\nimport com.alibaba.druid.sql.ast.statement.SQLExprTableSource;\nimport com.alibaba.druid.sql.ast.statement.SQLJoinTableSource;\nimport com.alibaba.druid.sql.ast.statement.SQLSelectGroupByClause;\nimport com.alibaba.druid.sql.ast.statement.SQLSelectItem;\nimport com.alibaba.druid.sql.ast.statement.SQLSelectStatement;\nimport com.alibaba.druid.sql.ast.statement.SQLSubqueryTableSource;\nimport com.alibaba.druid.sql.ast.statement.SQLTableSource;\nimport com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock;\nimport com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;\nimport com.alibaba.druid.sql.parser.ParserException;\nimport com.alibaba.druid.sql.parser.SQLStatementParser;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem.ColumnItem;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem.FieldItem;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem.RelationFieldsPair;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem.TableItem;\n\n/**\n * ES同步指定sql格式解析\n *\n * @author rewerma 2018-10-26 下午03:45:49\n * @version 1.0.0\n */\npublic class SqlParser {\n\n    /**\n     * 解析sql\n     *\n     * @param sql sql\n     * @return 视图对象\n     */\n    public static SchemaItem parse(String sql) {\n        try {\n            SQLStatementParser parser = new MySqlStatementParser(sql);\n            SQLSelectStatement statement = (SQLSelectStatement) parser.parseStatement();\n            MySqlSelectQueryBlock sqlSelectQueryBlock = (MySqlSelectQueryBlock) statement.getSelect().getQuery();\n\n            SchemaItem schemaItem = new SchemaItem();\n            schemaItem.setSql(SQLUtils.toMySqlString(sqlSelectQueryBlock));\n            SQLTableSource sqlTableSource = sqlSelectQueryBlock.getFrom();\n            List<TableItem> tableItems = new ArrayList<>();\n            SqlParser.visitSelectTable(schemaItem, sqlTableSource, tableItems, null);\n            tableItems.forEach(tableItem -> schemaItem.getAliasTableItems().put(tableItem.getAlias(), tableItem));\n\n            List<FieldItem> fieldItems = collectSelectQueryFields(sqlSelectQueryBlock);\n            fieldItems.forEach(fieldItem -> schemaItem.getSelectFields().put(fieldItem.getFieldName(), fieldItem));\n\n            schemaItem.init();\n\n            if (schemaItem.getAliasTableItems().isEmpty() || schemaItem.getSelectFields().isEmpty()) {\n                throw new ParserException(\"Parse sql error\");\n            }\n            return schemaItem;\n        } catch (Exception e) {\n            throw new ParserException();\n        }\n    }\n\n    /**\n     * 归集字段\n     *\n     * @param sqlSelectQueryBlock sqlSelectQueryBlock\n     * @return 字段属性列表\n     */\n    private static List<FieldItem> collectSelectQueryFields(MySqlSelectQueryBlock sqlSelectQueryBlock) {\n        return sqlSelectQueryBlock.getSelectList().stream().map(selectItem -> {\n            FieldItem fieldItem = new FieldItem();\n            fieldItem.setFieldName(selectItem.getAlias());\n            fieldItem.setExpr(selectItem.toString());\n            visitColumn(selectItem.getExpr(), fieldItem);\n            return fieldItem;\n        }).collect(Collectors.toList());\n    }\n\n    /**\n     * 解析字段\n     *\n     * @param expr sql expr\n     * @param fieldItem 字段属性\n     */\n    private static void visitColumn(SQLExpr expr, FieldItem fieldItem) {\n        if (expr instanceof SQLIdentifierExpr) {\n            // 无owner\n            SQLIdentifierExpr identifierExpr = (SQLIdentifierExpr) expr;\n            if (fieldItem.getFieldName() == null) {\n                fieldItem.setFieldName(identifierExpr.getName());\n                fieldItem.setExpr(identifierExpr.toString());\n            }\n            ColumnItem columnItem = new ColumnItem();\n            columnItem.setColumnName(identifierExpr.getName());\n            fieldItem.getOwners().add(null);\n            fieldItem.addColumn(columnItem);\n        } else if (expr instanceof SQLPropertyExpr) {\n            // 有owner\n            SQLPropertyExpr sqlPropertyExpr = (SQLPropertyExpr) expr;\n            if (fieldItem.getFieldName() == null) {\n                fieldItem.setFieldName(sqlPropertyExpr.getName());\n                fieldItem.setExpr(sqlPropertyExpr.toString());\n            }\n            fieldItem.getOwners().add(sqlPropertyExpr.getOwnernName());\n            ColumnItem columnItem = new ColumnItem();\n            columnItem.setColumnName(sqlPropertyExpr.getName());\n            columnItem.setOwner(sqlPropertyExpr.getOwnernName());\n            fieldItem.addColumn(columnItem);\n        } else if (expr instanceof SQLMethodInvokeExpr) {\n            SQLMethodInvokeExpr methodInvokeExpr = (SQLMethodInvokeExpr) expr;\n            fieldItem.setMethod(true);\n            for (SQLExpr sqlExpr : methodInvokeExpr.getArguments()) {\n                visitColumn(sqlExpr, fieldItem);\n            }\n        } else if (expr instanceof SQLBinaryOpExpr) {\n            SQLBinaryOpExpr sqlBinaryOpExpr = (SQLBinaryOpExpr) expr;\n            fieldItem.setBinaryOp(true);\n            visitColumn(sqlBinaryOpExpr.getLeft(), fieldItem);\n            visitColumn(sqlBinaryOpExpr.getRight(), fieldItem);\n        } else if (expr instanceof SQLCaseExpr) {\n            SQLCaseExpr sqlCaseExpr = (SQLCaseExpr) expr;\n            fieldItem.setMethod(true);\n            sqlCaseExpr.getItems().forEach(item -> visitColumn(item.getConditionExpr(), fieldItem));\n        } else if (expr instanceof SQLCharExpr) {\n            SQLCharExpr sqlCharExpr = (SQLCharExpr) expr;\n            String owner = null;\n            String columnName = null;\n            if (sqlCharExpr.getParent() instanceof SQLCaseExpr.Item) {\n                owner = ((SQLPropertyExpr) ((SQLCaseExpr.Item) sqlCharExpr.getParent()).getValueExpr()).getOwnernName();\n                columnName = ((SQLPropertyExpr) ((SQLCaseExpr.Item) sqlCharExpr.getParent()).getValueExpr()).getName();\n            }\n            if (fieldItem.getFieldName() == null) {\n                fieldItem.setFieldName(columnName);\n                fieldItem.setExpr(sqlCharExpr.toString());\n            }\n            ColumnItem columnItem = new ColumnItem();\n            columnItem.setColumnName(columnName);\n            columnItem.setOwner(owner);\n            fieldItem.getOwners().add(owner);\n            fieldItem.addColumn(columnItem);\n        }\n    }\n\n    /**\n     * 解析表\n     *\n     * @param schemaItem 视图对象\n     * @param sqlTableSource sqlTableSource\n     * @param tableItems 表对象列表\n     * @param tableItemTmp 表对象(临时)\n     */\n    private static void visitSelectTable(SchemaItem schemaItem, SQLTableSource sqlTableSource,\n                                         List<TableItem> tableItems, TableItem tableItemTmp) {\n        if (sqlTableSource instanceof SQLExprTableSource) {\n            SQLExprTableSource sqlExprTableSource = (SQLExprTableSource) sqlTableSource;\n            TableItem tableItem;\n            if (tableItemTmp != null) {\n                tableItem = tableItemTmp;\n            } else {\n                tableItem = new TableItem(schemaItem);\n            }\n            tableItem.setSchema(sqlExprTableSource.getSchema());\n            tableItem.setTableName(sqlExprTableSource.getTableName());\n            if (tableItem.getAlias() == null) {\n                tableItem.setAlias(sqlExprTableSource.getAlias());\n            }\n            if (tableItems.isEmpty()) {\n                // 第一张表为主表\n                tableItem.setMain(true);\n            }\n            tableItems.add(tableItem);\n        } else if (sqlTableSource instanceof SQLJoinTableSource) {\n            SQLJoinTableSource sqlJoinTableSource = (SQLJoinTableSource) sqlTableSource;\n            SQLTableSource leftTableSource = sqlJoinTableSource.getLeft();\n            visitSelectTable(schemaItem, leftTableSource, tableItems, null);\n            SQLTableSource rightTableSource = sqlJoinTableSource.getRight();\n            TableItem rightTableItem = new TableItem(schemaItem);\n            // 解析on条件字段\n            visitOnCondition(sqlJoinTableSource.getCondition(), rightTableItem);\n            visitSelectTable(schemaItem, rightTableSource, tableItems, rightTableItem);\n\n        } else if (sqlTableSource instanceof SQLSubqueryTableSource) {\n            SQLSubqueryTableSource subQueryTableSource = (SQLSubqueryTableSource) sqlTableSource;\n            MySqlSelectQueryBlock sqlSelectQuery = (MySqlSelectQueryBlock) subQueryTableSource.getSelect().getQuery();\n            TableItem tableItem;\n            if (tableItemTmp != null) {\n                tableItem = tableItemTmp;\n            } else {\n                tableItem = new TableItem(schemaItem);\n            }\n            tableItem.setAlias(subQueryTableSource.getAlias());\n            tableItem.setSubQuerySql(SQLUtils.toMySqlString(sqlSelectQuery));\n            tableItem.setSubQuery(true);\n            tableItem.setSubQueryFields(collectSelectQueryFields(sqlSelectQuery));\n            visitSelectTable(schemaItem, sqlSelectQuery.getFrom(), tableItems, tableItem);\n        }\n    }\n\n    /**\n     * 解析on条件\n     *\n     * @param expr sql expr\n     * @param tableItem 表对象\n     */\n    private static void visitOnCondition(SQLExpr expr, TableItem tableItem) {\n        if (!(expr instanceof SQLBinaryOpExpr)) {\n            throw new UnsupportedOperationException();\n        }\n        SQLBinaryOpExpr sqlBinaryOpExpr = (SQLBinaryOpExpr) expr;\n        if (sqlBinaryOpExpr.getOperator() == BooleanAnd) {\n            visitOnCondition(sqlBinaryOpExpr.getLeft(), tableItem);\n            visitOnCondition(sqlBinaryOpExpr.getRight(), tableItem);\n        } else if (sqlBinaryOpExpr.getOperator() == Equality) {\n            FieldItem leftFieldItem = new FieldItem();\n            visitColumn(sqlBinaryOpExpr.getLeft(), leftFieldItem);\n            if (leftFieldItem.getColumnItems().size() != 1 || leftFieldItem.isMethod() || leftFieldItem.isBinaryOp()) {\n                throw new UnsupportedOperationException(\"Unsupported for complex of on-condition\");\n            }\n            FieldItem rightFieldItem = new FieldItem();\n            visitColumn(sqlBinaryOpExpr.getRight(), rightFieldItem);\n            if (rightFieldItem.getColumnItems().size() != 1 || rightFieldItem.isMethod() || rightFieldItem.isBinaryOp()) {\n                throw new UnsupportedOperationException(\"Unsupported for complex of on-condition\");\n            }\n            tableItem.getRelationFields().add(new RelationFieldsPair(leftFieldItem, rightFieldItem));\n        } else {\n            throw new UnsupportedOperationException(\"Unsupported for complex of on-condition\");\n        }\n    }\n\n    public static MySqlSelectQueryBlock parseSQLSelectQueryBlock(String sql) {\n        if (sql == null || \"\".equals(sql)) {\n            return null;\n        }\n        SQLStatementParser parser = new MySqlStatementParser(sql);\n        SQLSelectStatement statement = (SQLSelectStatement) parser.parseStatement();\n        return (MySqlSelectQueryBlock) statement.getSelect().getQuery();\n    }\n\n    public static String parse4SQLSelectItem(MySqlSelectQueryBlock sqlSelectQueryBlock) {\n        List<SQLSelectItem> selectItems = sqlSelectQueryBlock.getSelectList();\n        StringBuilder subSql = new StringBuilder();\n        int i = 0;\n        for (SQLSelectItem sqlSelectItem : selectItems) {\n            if (i != 0) {\n                subSql.append(\",\");\n            } else {\n                i++;\n            }\n            subSql.append(SQLUtils.toMySqlString(sqlSelectItem));\n        }\n        return subSql.toString();\n    }\n\n    public static String parse4FromTableSource(MySqlSelectQueryBlock sqlSelectQueryBlock) {\n        SQLTableSource sqlTableSource = sqlSelectQueryBlock.getFrom();\n        return SQLUtils.toMySqlString(sqlTableSource);\n    }\n\n    public static String parse4WhereItem(MySqlSelectQueryBlock sqlSelectQueryBlock) {\n        SQLExpr sqlExpr = sqlSelectQueryBlock.getWhere();\n        if (sqlExpr != null) {\n            return SQLUtils.toMySqlString(sqlExpr);\n        }\n        return null;\n    }\n\n    public static String parse4GroupBy(MySqlSelectQueryBlock sqlSelectQueryBlock) {\n        SQLSelectGroupByClause expr = sqlSelectQueryBlock.getGroupBy();\n        if (expr != null) {\n            return SQLUtils.toMySqlString(expr);\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "client-adapter/escore/src/main/java/com/alibaba/otter/canal/client/adapter/es/core/monitor/ESConfigMonitor.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es.core.monitor;\n\nimport java.io.File;\nimport java.util.Properties;\n\nimport org.apache.commons.io.filefilter.FileFilterUtils;\nimport org.apache.commons.io.monitor.FileAlterationListenerAdaptor;\nimport org.apache.commons.io.monitor.FileAlterationMonitor;\nimport org.apache.commons.io.monitor.FileAlterationObserver;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.client.adapter.es.core.ESAdapter;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig;\nimport com.alibaba.otter.canal.client.adapter.support.MappingConfigsLoader;\nimport com.alibaba.otter.canal.client.adapter.support.Util;\nimport com.alibaba.otter.canal.client.adapter.support.YamlUtils;\n\n;\n\npublic class ESConfigMonitor {\n\n    private static final Logger   logger = LoggerFactory.getLogger(ESConfigMonitor.class);\n\n    private String                adapterName;\n\n    private ESAdapter             esAdapter;\n\n    private Properties            envProperties;\n\n    private FileAlterationMonitor fileMonitor;\n\n    public void init(ESAdapter esAdapter, Properties envProperties) {\n        this.esAdapter = esAdapter;\n        this.envProperties = envProperties;\n        this.adapterName = envProperties.getProperty(\"es.version\");\n        File confDir = Util.getConfDirPath(adapterName);\n        try {\n            FileAlterationObserver observer = new FileAlterationObserver(confDir,\n                    FileFilterUtils.and(FileFilterUtils.fileFileFilter(), FileFilterUtils.suffixFileFilter(\"yml\")));\n            FileListener listener = new FileListener();\n            observer.addListener(listener);\n            fileMonitor = new FileAlterationMonitor(3000, observer);\n            fileMonitor.start();\n\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n        }\n    }\n\n    public void destroy() {\n        try {\n            fileMonitor.stop();\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n        }\n    }\n\n    private class FileListener extends FileAlterationListenerAdaptor {\n\n        @Override\n        public void onFileCreate(File file) {\n            super.onFileCreate(file);\n            try {\n                // 加载新增的配置文件\n                String configContent = MappingConfigsLoader.loadConfig(adapterName + File.separator + file.getName());\n                ESSyncConfig config = YamlUtils.ymlToObj(null,\n                    configContent,\n                    ESSyncConfig.class,\n                    null,\n                    envProperties);\n                if (config != null) {\n                    // 这里要记得设置esVersion bugfix\n                    config.setEsVersion(adapterName);\n                    config.validate();\n                    boolean result = esAdapter.addConfig(file.getName(), config);\n                    if (result) {\n                        logger.info(\"Add a new es mapping config: {} to canal adapter\",\n                                file.getName());\n                    }\n                }\n            } catch (Exception e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n\n        @Override\n        public void onFileChange(File file) {\n            super.onFileChange(file);\n\n            try {\n                if (esAdapter.getEsSyncConfig().containsKey(file.getName())) {\n                    // 加载配置文件\n                    String configContent = MappingConfigsLoader.loadConfig(adapterName + File.separator\n                                                                           + file.getName());\n                    if (configContent == null) {\n                        onFileDelete(file);\n                        return;\n                    }\n                    ESSyncConfig config = YamlUtils.ymlToObj(null,\n                        configContent,\n                        ESSyncConfig.class,\n                        null,\n                        envProperties);\n                    if (config == null) {\n                        return;\n                    }\n                    // 这里要记得设置esVersion bugfix\n                    config.setEsVersion(adapterName);\n                    config.validate();\n                    esAdapter.updateConfig(file.getName(), config);\n                    logger.info(\"Change a es mapping config: {} of canal adapter\", file.getName());\n                }\n            } catch (Exception e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n\n        @Override\n        public void onFileDelete(File file) {\n            super.onFileDelete(file);\n\n            try {\n                if (esAdapter.getEsSyncConfig().containsKey(file.getName())) {\n                    esAdapter.deleteConfig(file.getName());\n                    logger.info(\"Delete a es mapping config: {} of canal adapter\", file.getName());\n                }\n            } catch (Exception e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/escore/src/main/java/com/alibaba/otter/canal/client/adapter/es/core/service/ESSyncService.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es.core.service;\n\nimport java.util.*;\n\nimport javax.sql.DataSource;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock;\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.JSONWriter;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig.ESMapping;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem.ColumnItem;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem.FieldItem;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem.TableItem;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SqlParser;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESSyncUtil;\nimport com.alibaba.otter.canal.client.adapter.es.core.support.ESTemplate;\nimport com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\nimport com.alibaba.otter.canal.client.adapter.support.Util;\n\n/**\n * ES 同步 Service\n *\n * @author rewerma 2018-11-01\n * @version 1.0.0\n */\npublic class ESSyncService {\n\n    private static Logger logger = LoggerFactory.getLogger(ESSyncService.class);\n\n    private ESTemplate    esTemplate;\n\n    public ESSyncService(ESTemplate esTemplate){\n        this.esTemplate = esTemplate;\n    }\n\n    public void sync(Collection<ESSyncConfig> esSyncConfigs, Dml dml) {\n        long begin = System.currentTimeMillis();\n        if (esSyncConfigs != null) {\n            if (logger.isTraceEnabled()) {\n                logger.trace(\"Destination: {}, database:{}, table:{}, type:{}, affected index count: {}\",\n                    dml.getDestination(),\n                    dml.getDatabase(),\n                    dml.getTable(),\n                    dml.getType(),\n                    esSyncConfigs.size());\n            }\n\n            for (ESSyncConfig config : esSyncConfigs) {\n                if (logger.isTraceEnabled()) {\n                    logger.trace(\"Prepared to sync index: {}, destination: {}\",\n                        config.getEsMapping().getIndex(),\n                        dml.getDestination());\n                }\n                this.sync(config, dml);\n                if (logger.isTraceEnabled()) {\n                    logger.trace(\"Sync completed: {}, destination: {}\",\n                        config.getEsMapping().getIndex(),\n                        dml.getDestination());\n                }\n            }\n            if (logger.isTraceEnabled()) {\n                logger.trace(\"Sync elapsed time: {} ms, affected indexes count：{}, destination: {}\",\n                    (System.currentTimeMillis() - begin),\n                    esSyncConfigs.size(),\n                    dml.getDestination());\n            }\n            if (logger.isDebugEnabled()) {\n                StringBuilder configIndexes = new StringBuilder();\n                esSyncConfigs\n                    .forEach(esSyncConfig -> configIndexes.append(esSyncConfig.getEsMapping().getIndex()).append(\" \"));\n                logger.debug(\"DML: {} \\nAffected indexes: {}\",\n                    JSON.toJSONString(dml, JSONWriter.Feature.WriteNulls),\n                    configIndexes.toString());\n            }\n        }\n    }\n\n    public void sync(ESSyncConfig config, Dml dml) {\n        try {\n            // 如果是按时间戳定时更新则返回\n            if (config.getEsMapping().isSyncByTimestamp()) {\n                return;\n            }\n\n            long begin = System.currentTimeMillis();\n\n            String type = dml.getType();\n            if (type != null && type.equalsIgnoreCase(\"INSERT\")) {\n                insert(config, dml);\n            } else if (type != null && type.equalsIgnoreCase(\"UPDATE\")) {\n                update(config, dml);\n            } else if (type != null && type.equalsIgnoreCase(\"DELETE\")) {\n                delete(config, dml);\n            } else {\n                return;\n            }\n\n            if (logger.isTraceEnabled()) {\n                logger.trace(\"Sync elapsed time: {} ms,destination: {}, es index: {}\",\n                    (System.currentTimeMillis() - begin),\n                    dml.getDestination(),\n                    config.getEsMapping().getIndex());\n            }\n        } catch (Throwable e) {\n            logger.error(\"sync error, es index: {}, DML : {}\", config.getEsMapping().getIndex(), dml);\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * 插入操作dml\n     *\n     * @param config es配置\n     * @param dml dml数据\n     */\n    private void insert(ESSyncConfig config, Dml dml) {\n        List<Map<String, Object>> dataList = dml.getData();\n        if (dataList == null || dataList.isEmpty()) {\n            return;\n        }\n        SchemaItem schemaItem = config.getEsMapping().getSchemaItem();\n        for (Map<String, Object> data : dataList) {\n            if (data == null || data.isEmpty()) {\n                continue;\n            }\n\n            if (schemaItem.getAliasTableItems().size() == 1 && schemaItem.isAllFieldsSimple()) {\n                // ------单表 & 所有字段都为简单字段------\n                singleTableSimpleFiledInsert(config, dml, data);\n            } else {\n                // ------是主表 查询sql来插入------\n                if (schemaItem.getMainTable().getTableName().equalsIgnoreCase(dml.getTable())) {\n                    mainTableInsert(config, dml, data);\n                }\n\n                // 从表的操作\n                for (TableItem tableItem : schemaItem.getAliasTableItems().values()) {\n                    if (tableItem.isMain()) {\n                        continue;\n                    }\n                    if (!tableItem.getTableName().equals(dml.getTable())) {\n                        continue;\n                    }\n                    // 关联条件出现在主表查询条件是否为简单字段\n                    boolean allFieldsSimple = true;\n                    for (FieldItem fieldItem : tableItem.getRelationSelectFieldItems()) {\n                        if (fieldItem.isMethod() || fieldItem.isBinaryOp()) {\n                            allFieldsSimple = false;\n                            break;\n                        }\n                    }\n                    // 所有查询字段均为简单字段\n                    if (allFieldsSimple) {\n                        // 不是子查询\n                        if (!tableItem.isSubQuery()) {\n                            // ------关联表简单字段插入------\n                            Map<String, Object> esFieldData = new LinkedHashMap<>();\n                            for (FieldItem fieldItem : tableItem.getRelationSelectFieldItems()) {\n                                Object value = esTemplate.getValFromData(config.getEsMapping(),\n                                    data,\n                                    fieldItem.getFieldName(),\n                                    fieldItem.getColumn().getColumnName());\n                                esFieldData.put(Util.cleanColumn(fieldItem.getFieldName()), value);\n                            }\n\n                            joinTableSimpleFieldOperation(config, dml, data, tableItem, esFieldData);\n                        } else {\n                            // ------关联子表简单字段插入------\n                            subTableSimpleFieldOperation(config, dml, data, null, tableItem);\n                        }\n                    } else {\n                        // ------关联子表复杂字段插入 执行全sql更新es------\n                        wholeSqlOperation(config, dml, data, null, tableItem);\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * 更新操作dml\n     *\n     * @param config es配置\n     * @param dml dml数据\n     */\n    private void update(ESSyncConfig config, Dml dml) {\n        List<Map<String, Object>> dataList = dml.getData();\n        List<Map<String, Object>> oldList = dml.getOld();\n        if (dataList == null || dataList.isEmpty() || oldList == null || oldList.isEmpty()) {\n            return;\n        }\n        SchemaItem schemaItem = config.getEsMapping().getSchemaItem();\n        int i = 0;\n        for (Map<String, Object> data : dataList) {\n            Map<String, Object> old = oldList.get(i);\n            if (data == null || data.isEmpty() || old == null || old.isEmpty()) {\n                continue;\n            }\n\n            if (schemaItem.getAliasTableItems().size() == 1 && schemaItem.isAllFieldsSimple()) {\n                // ------单表 & 所有字段都为简单字段------\n                singleTableSimpleFiledUpdate(config, schemaItem.getMainTable().getAlias(), dml, data, old);\n            } else {\n                // ------主表 查询sql来更新------\n                if (schemaItem.getMainTable().getTableName().equalsIgnoreCase(dml.getTable())) {\n                    ESMapping mapping = config.getEsMapping();\n                    String idFieldName = mapping.getId() == null ? mapping.getPk() : mapping.getId();\n                    FieldItem idFieldItem = schemaItem.getSelectFields().get(idFieldName);\n\n                    boolean idFieldSimple = true;\n                    if (idFieldItem.isMethod() || idFieldItem.isBinaryOp()) {\n                        idFieldSimple = false;\n                    }\n\n                    boolean allUpdateFieldSimple = true;\n                    out: for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {\n                        for (ColumnItem columnItem : fieldItem.getColumnItems()) {\n                            if (old.containsKey(columnItem.getColumnName())) {\n                                if (fieldItem.isMethod() || fieldItem.isBinaryOp()) {\n                                    allUpdateFieldSimple = false;\n                                    break out;\n                                }\n                            }\n                        }\n                    }\n\n                    // 不支持主键更新!!\n\n                    // 判断是否有外键更新\n                    boolean fkChanged = false;\n                    for (TableItem tableItem : schemaItem.getAliasTableItems().values()) {\n                        if (tableItem.isMain()) {\n                            continue;\n                        }\n                        boolean changed = false;\n                        for (List<FieldItem> fieldItems : tableItem.getRelationTableFields().values()) {\n                            for (FieldItem fieldItem : fieldItems) {\n                                if (old.containsKey(fieldItem.getColumn().getColumnName())) {\n                                    fkChanged = true;\n                                    changed = true;\n                                    break;\n                                }\n                            }\n                        }\n                        // 如果外键有修改,则更新所对应该表的所有查询条件数据\n                        if (changed) {\n                            for (FieldItem fieldItem : tableItem.getRelationSelectFieldItems()) {\n                                fieldItem.getColumnItems()\n                                    .forEach(columnItem -> old.put(columnItem.getColumnName(), null));\n                            }\n                        }\n                    }\n\n                    // 判断主键和所更新的字段是否全为简单字段\n                    if (idFieldSimple && allUpdateFieldSimple && !fkChanged) {\n                        singleTableSimpleFiledUpdate(config, schemaItem.getMainTable().getAlias(), dml, data, old);\n                    } else {\n                        mainTableUpdate(config, dml, data, old);\n                    }\n                }\n\n                // 从表的操作\n                for (TableItem tableItem : schemaItem.getAliasTableItems().values()) {\n                    if (tableItem.isMain()) {\n                        continue;\n                    }\n                    if (!tableItem.getTableName().equals(dml.getTable())) {\n                        continue;\n                    }\n\n                    // 关联条件出现在主表查询条件是否为简单字段\n                    boolean allFieldsSimple = true;\n                    for (FieldItem fieldItem : tableItem.getRelationSelectFieldItems()) {\n                        if (fieldItem.isMethod() || fieldItem.isBinaryOp()) {\n                            allFieldsSimple = false;\n                            break;\n                        }\n                    }\n\n                    // 所有查询字段均为简单字段\n                    if (allFieldsSimple) {\n                        // 不是子查询\n                        if (!tableItem.isSubQuery()) {\n                            // ------关联表简单字段更新------\n                            Map<String, Object> esFieldData = new LinkedHashMap<>();\n                            for (FieldItem fieldItem : tableItem.getRelationSelectFieldItems()) {\n                                if (old.containsKey(fieldItem.getColumn().getColumnName())) {\n                                    Object value = esTemplate.getValFromData(config.getEsMapping(),\n                                        data,\n                                        fieldItem.getFieldName(),\n                                        fieldItem.getColumn().getColumnName());\n                                    esFieldData.put(Util.cleanColumn(fieldItem.getFieldName()), value);\n                                }\n                            }\n                            joinTableSimpleFieldOperation(config, dml, data, tableItem, esFieldData);\n                        } else {\n                            // ------关联子表简单字段更新------\n                            subTableSimpleFieldOperation(config, dml, data, old, tableItem);\n                        }\n                    } else {\n                        // ------关联子表复杂字段更新 执行全sql更新es------\n                        wholeSqlOperation(config, dml, data, old, tableItem);\n                    }\n                }\n            }\n\n            i++;\n        }\n    }\n\n    /**\n     * 删除操作dml\n     *\n     * @param config es配置\n     * @param dml dml数据\n     */\n    private void delete(ESSyncConfig config, Dml dml) {\n        List<Map<String, Object>> dataList = dml.getData();\n        if (dataList == null || dataList.isEmpty()) {\n            return;\n        }\n        SchemaItem schemaItem = config.getEsMapping().getSchemaItem();\n\n        for (Map<String, Object> data : dataList) {\n            if (data == null || data.isEmpty()) {\n                continue;\n            }\n\n            ESMapping mapping = config.getEsMapping();\n\n            // ------是主表------\n            if (schemaItem.getMainTable().getTableName().equalsIgnoreCase(dml.getTable())) {\n                if (mapping.getId() != null) {\n                    FieldItem idFieldItem = schemaItem.getIdFieldItem(mapping);\n                    // 主键为简单字段\n                    if (!idFieldItem.isMethod() && !idFieldItem.isBinaryOp()) {\n                        Object idVal = esTemplate.getValFromData(mapping,\n                            data,\n                            idFieldItem.getFieldName(),\n                            idFieldItem.getColumn().getColumnName());\n\n                        if (logger.isTraceEnabled()) {\n                            logger.trace(\"Main table delete es index, destination:{}, table: {}, index: {}, id: {}\",\n                                config.getDestination(),\n                                dml.getTable(),\n                                mapping.getIndex(),\n                                idVal);\n                        }\n                        esTemplate.delete(mapping, idVal, null);\n                    } else {\n                        // ------主键带函数, 查询sql获取主键删除------\n                        // FIXME 删除时反查sql为空记录, 无法获获取 id field 值\n                        mainTableDelete(config, dml, data);\n                    }\n                } else {\n                    FieldItem pkFieldItem = schemaItem.getIdFieldItem(mapping);\n                    if (!pkFieldItem.isMethod() && !pkFieldItem.isBinaryOp()) {\n                        Map<String, Object> esFieldData = new LinkedHashMap<>();\n                        Object pkVal = esTemplate.getESDataFromDmlData(mapping, data, esFieldData);\n\n                        if (logger.isTraceEnabled()) {\n                            logger.trace(\"Main table delete es index, destination:{}, table: {}, index: {}, pk: {}\",\n                                config.getDestination(),\n                                dml.getTable(),\n                                mapping.getIndex(),\n                                pkVal);\n                        }\n                        esFieldData.remove(pkFieldItem.getFieldName());\n                        esFieldData.keySet().forEach(key -> esFieldData.put(key, null));\n                        esTemplate.delete(mapping, pkVal, esFieldData);\n                    } else {\n                        // ------主键带函数, 查询sql获取主键删除------\n                        mainTableDelete(config, dml, data);\n                    }\n                }\n\n            }\n\n            // 从表的操作\n            for (TableItem tableItem : schemaItem.getAliasTableItems().values()) {\n                if (tableItem.isMain()) {\n                    continue;\n                }\n                if (!tableItem.getTableName().equals(dml.getTable())) {\n                    continue;\n                }\n\n                // 关联条件出现在主表查询条件是否为简单字段\n                boolean allFieldsSimple = true;\n                for (FieldItem fieldItem : tableItem.getRelationSelectFieldItems()) {\n                    if (fieldItem.isMethod() || fieldItem.isBinaryOp()) {\n                        allFieldsSimple = false;\n                        break;\n                    }\n                }\n\n                // 所有查询字段均为简单字段\n                if (allFieldsSimple) {\n                    // 不是子查询\n                    if (!tableItem.isSubQuery()) {\n                        // ------关联表简单字段更新为null------\n                        Map<String, Object> esFieldData = new LinkedHashMap<>();\n                        for (FieldItem fieldItem : tableItem.getRelationSelectFieldItems()) {\n                            esFieldData.put(Util.cleanColumn(fieldItem.getFieldName()), null);\n                        }\n                        joinTableSimpleFieldOperation(config, dml, data, tableItem, esFieldData);\n                    } else {\n                        // ------关联子表简单字段更新------\n                        subTableSimpleFieldOperation(config, dml, data, null, tableItem);\n                    }\n                } else {\n                    // ------关联子表复杂字段更新 执行全sql更新es------\n                    wholeSqlOperation(config, dml, data, null, tableItem);\n                }\n            }\n        }\n    }\n\n    /**\n     * 单表简单字段insert\n     *\n     * @param config es配置\n     * @param dml dml信息\n     * @param data 单行dml数据\n     */\n    private void singleTableSimpleFiledInsert(ESSyncConfig config, Dml dml, Map<String, Object> data) {\n        ESMapping mapping = config.getEsMapping();\n        Map<String, Object> esFieldData = new LinkedHashMap<>();\n        Object idVal = esTemplate.getESDataFromDmlData(mapping, data, esFieldData);\n\n        if (logger.isTraceEnabled()) {\n            logger.trace(\"Single table insert to es index, destination:{}, table: {}, index: {}, id: {}\",\n                config.getDestination(),\n                dml.getTable(),\n                mapping.getIndex(),\n                idVal);\n        }\n        esTemplate.insert(mapping, idVal, esFieldData);\n    }\n\n    /**\n     * 主表(单表)复杂字段insert\n     *\n     * @param config es配置\n     * @param dml dml信息\n     * @param data 单行dml数据\n     */\n    private void mainTableInsert(ESSyncConfig config, Dml dml, Map<String, Object> data) {\n        ESMapping mapping = config.getEsMapping();\n        String sql = mapping.getSql();\n        String condition = ESSyncUtil.pkConditionSql(mapping, data);\n        sql = ESSyncUtil.appendCondition(sql, condition);\n        DataSource ds = DatasourceConfig.DATA_SOURCES.get(config.getDataSourceKey());\n        if (logger.isTraceEnabled()) {\n            logger.trace(\"Main table insert to es index by query sql, destination:{}, table: {}, index: {}, sql: {}\",\n                config.getDestination(),\n                dml.getTable(),\n                mapping.getIndex(),\n                sql.replace(\"\\n\", \" \"));\n        }\n        Util.sqlRS(ds, sql, rs -> {\n            try {\n                while (rs.next()) {\n                    Map<String, Object> esFieldData = new LinkedHashMap<>();\n                    Object idVal = esTemplate.getESDataFromRS(mapping, rs, esFieldData);\n\n                    if (logger.isTraceEnabled()) {\n                        logger.trace(\n                            \"Main table insert to es index by query sql, destination:{}, table: {}, index: {}, id: {}\",\n                            config.getDestination(),\n                            dml.getTable(),\n                            mapping.getIndex(),\n                            idVal);\n                    }\n                    esTemplate.insert(mapping, idVal, esFieldData);\n                }\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n            return 0;\n        });\n    }\n\n    private void mainTableDelete(ESSyncConfig config, Dml dml, Map<String, Object> data) {\n        ESMapping mapping = config.getEsMapping();\n        String sql = mapping.getSql();\n        String condition = ESSyncUtil.pkConditionSql(mapping, data);\n        sql = ESSyncUtil.appendCondition(sql, condition);\n        DataSource ds = DatasourceConfig.DATA_SOURCES.get(config.getDataSourceKey());\n        if (logger.isTraceEnabled()) {\n            logger.trace(\"Main table delete es index by query sql, destination:{}, table: {}, index: {}, sql: {}\",\n                config.getDestination(),\n                dml.getTable(),\n                mapping.getIndex(),\n                sql.replace(\"\\n\", \" \"));\n        }\n        Util.sqlRS(ds, sql, rs -> {\n            try {\n                Map<String, Object> esFieldData = null;\n                if (mapping.getPk() != null) {\n                    esFieldData = new LinkedHashMap<>();\n                    esTemplate.getESDataFromDmlData(mapping, data, esFieldData);\n                    esFieldData.remove(mapping.getPk());\n                    for (String key : esFieldData.keySet()) {\n                        esFieldData.put(Util.cleanColumn(key), null);\n                    }\n                }\n                while (rs.next()) {\n                    Object idVal = esTemplate.getIdValFromRS(mapping, rs);\n\n                    if (logger.isTraceEnabled()) {\n                        logger.trace(\n                            \"Main table delete to es index by query sql, destination:{}, table: {}, index: {}, id: {}\",\n                            config.getDestination(),\n                            dml.getTable(),\n                            mapping.getIndex(),\n                            idVal);\n                    }\n                    esTemplate.delete(mapping, idVal, esFieldData);\n                }\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n            return 0;\n        });\n    }\n\n    /**\n     * 关联表主表简单字段operation\n     *\n     * @param config es配置\n     * @param dml dml信息\n     * @param data 单行dml数据\n     * @param tableItem 当前表配置\n     */\n    private void joinTableSimpleFieldOperation(ESSyncConfig config, Dml dml, Map<String, Object> data,\n                                               TableItem tableItem, Map<String, Object> esFieldData) {\n        ESMapping mapping = config.getEsMapping();\n\n        Map<String, Object> paramsTmp = new LinkedHashMap<>();\n        for (Map.Entry<FieldItem, List<FieldItem>> entry : tableItem.getRelationTableFields().entrySet()) {\n            for (FieldItem fieldItem : entry.getValue()) {\n                if (fieldItem.getColumnItems().size() == 1) {\n                    Object value = esTemplate.getValFromData(mapping,\n                        data,\n                        fieldItem.getFieldName(),\n                        entry.getKey().getColumn().getColumnName());\n\n                    String fieldName = fieldItem.getFieldName();\n                    // 判断是否是主键\n                    if (fieldName.equals(mapping.getId())) {\n                        fieldName = \"_id\";\n                    }\n                    paramsTmp.put(fieldName, value);\n                }\n            }\n        }\n\n        if (logger.isDebugEnabled()) {\n            logger.trace(\"Join table update es index by foreign key, destination:{}, table: {}, index: {}\",\n                config.getDestination(),\n                dml.getTable(),\n                mapping.getIndex());\n        }\n        esTemplate.updateByQuery(config, paramsTmp, esFieldData);\n    }\n\n    /**\n     * 关联子查询, 主表简单字段operation\n     *\n     * @param config es配置\n     * @param dml dml信息\n     * @param data 单行dml数据\n     * @param old 单行old数据\n     * @param tableItem 当前表配置\n     */\n    private void subTableSimpleFieldOperation(ESSyncConfig config, Dml dml, Map<String, Object> data,\n                                              Map<String, Object> old, TableItem tableItem) {\n        ESMapping mapping = config.getEsMapping();\n\n        MySqlSelectQueryBlock queryBlock = SqlParser.parseSQLSelectQueryBlock(tableItem.getSubQuerySql());\n        StringBuilder sql = new StringBuilder();\n        sql.append(\"SELECT \")\n            .append(SqlParser.parse4SQLSelectItem(queryBlock))\n            .append(\" FROM \")\n            .append(SqlParser.parse4FromTableSource(queryBlock));\n\n        String whereSql = SqlParser.parse4WhereItem(queryBlock);\n        if (whereSql != null) {\n            sql.append(\" WHERE \").append(whereSql);\n        } else {\n            sql.append(\" WHERE 1=1 \");\n        }\n\n        List<Object> values = new ArrayList<>();\n\n        for (FieldItem fkFieldItem : tableItem.getRelationTableFields().keySet()) {\n            String columnName = fkFieldItem.getColumn().getColumnName();\n            Object value = esTemplate.getValFromData(mapping, data, fkFieldItem.getFieldName(), columnName);\n            sql.append(\" AND \").append(columnName).append(\"=? \");\n            values.add(value);\n        }\n\n        String groupSql = SqlParser.parse4GroupBy(queryBlock);\n        if (groupSql != null) {\n            sql.append(groupSql);\n        }\n\n        DataSource ds = DatasourceConfig.DATA_SOURCES.get(config.getDataSourceKey());\n        if (logger.isTraceEnabled()) {\n            logger.trace(\"Join table update es index by query sql, destination:{}, table: {}, index: {}, sql: {}\",\n                config.getDestination(),\n                dml.getTable(),\n                mapping.getIndex(),\n                sql.toString().replace(\"\\n\", \" \"));\n        }\n        Util.sqlRS(ds, sql.toString(), values, rs -> {\n            try {\n                while (rs.next()) {\n                    Map<String, Object> esFieldData = new LinkedHashMap<>();\n\n                    for (FieldItem fieldItem : tableItem.getRelationSelectFieldItems()) {\n                        if (old != null) {\n                            out: for (FieldItem fieldItem1 : tableItem.getSubQueryFields()) {\n                                for (ColumnItem columnItem0 : fieldItem.getColumnItems()) {\n                                    if (fieldItem1.getFieldName().equals(columnItem0.getColumnName()))\n                                        for (ColumnItem columnItem : fieldItem1.getColumnItems()) {\n                                            if (old.containsKey(columnItem.getColumnName())) {\n                                                Object val = esTemplate.getValFromRS(mapping,\n                                                    rs,\n                                                    fieldItem.getFieldName(),\n                                                    fieldItem.getColumn().getColumnName());\n                                                esFieldData.put(Util.cleanColumn(fieldItem.getFieldName()), val);\n                                                break out;\n                                            }\n                                        }\n                                }\n                            }\n                        } else {\n                            Object val = esTemplate.getValFromRS(mapping,\n                                rs,\n                                fieldItem.getFieldName(),\n                                fieldItem.getColumn().getColumnName());\n                            esFieldData.put(Util.cleanColumn(fieldItem.getFieldName()), val);\n                        }\n                    }\n\n                    Map<String, Object> paramsTmp = new LinkedHashMap<>();\n                    for (Map.Entry<FieldItem, List<FieldItem>> entry : tableItem.getRelationTableFields().entrySet()) {\n                        for (FieldItem fieldItem : entry.getValue()) {\n                            if (fieldItem.getColumnItems().size() == 1) {\n                                Object value = esTemplate.getValFromRS(mapping,\n                                    rs,\n                                    fieldItem.getFieldName(),\n                                    entry.getKey().getColumn().getColumnName());\n                                String fieldName = fieldItem.getFieldName();\n                                // 判断是否是主键\n                                if (fieldName.equals(mapping.getId())) {\n                                    fieldName = \"_id\";\n                                }\n                                paramsTmp.put(fieldName, value);\n                            }\n                        }\n                    }\n\n                    if (logger.isDebugEnabled()) {\n                        logger.trace(\"Join table update es index by query sql, destination:{}, table: {}, index: {}\",\n                            config.getDestination(),\n                            dml.getTable(),\n                            mapping.getIndex());\n                    }\n                    esTemplate.updateByQuery(config, paramsTmp, esFieldData);\n                }\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n            return 0;\n        });\n    }\n\n    /**\n     * 关联(子查询), 主表复杂字段operation, 全sql执行\n     *\n     * @param config es配置\n     * @param dml dml信息\n     * @param data 单行dml数据\n     * @param tableItem 当前表配置\n     */\n    private void wholeSqlOperation(ESSyncConfig config, Dml dml, Map<String, Object> data, Map<String, Object> old,\n                                   TableItem tableItem) {\n        ESMapping mapping = config.getEsMapping();\n        // 防止最后出现groupby 导致sql解析异常\n        String[] sqlSplit = mapping.getSql().split(\"GROUP\\\\ BY(?!(.*)ON)\");\n        String sqlNoWhere = sqlSplit[0];\n\n        String sqlGroupBy = \"\";\n\n        if (sqlSplit.length > 1) {\n            sqlGroupBy = \"GROUP BY \" + sqlSplit[1];\n        }\n\n        StringBuilder sql = new StringBuilder(sqlNoWhere + \" WHERE \");\n\n        for (FieldItem fkFieldItem : tableItem.getRelationTableFields().keySet()) {\n            String columnName = fkFieldItem.getColumn().getColumnName();\n            Object value = esTemplate.getValFromData(mapping, data, fkFieldItem.getFieldName(), columnName);\n            ESSyncUtil.appendCondition(sql, value, tableItem.getAlias(), columnName);\n        }\n        int len = sql.length();\n        sql.delete(len - 5, len);\n        sql.append(sqlGroupBy);\n\n        DataSource ds = DatasourceConfig.DATA_SOURCES.get(config.getDataSourceKey());\n        if (logger.isTraceEnabled()) {\n            logger.trace(\"Join table update es index by query whole sql, destination:{}, table: {}, index: {}, sql: {}\",\n                config.getDestination(),\n                dml.getTable(),\n                mapping.getIndex(),\n                sql.toString().replace(\"\\n\", \" \"));\n        }\n        Util.sqlRS(ds, sql.toString(), rs -> {\n            try {\n                while (rs.next()) {\n                    Map<String, Object> esFieldData = new LinkedHashMap<>();\n                    for (FieldItem fieldItem : tableItem.getRelationSelectFieldItems()) {\n                        if (old != null) {\n                            // 从表子查询\n                            out: for (FieldItem fieldItem1 : tableItem.getSubQueryFields()) {\n                                for (ColumnItem columnItem0 : fieldItem.getColumnItems()) {\n                                    if (fieldItem1.getFieldName().equals(columnItem0.getColumnName()))\n                                        for (ColumnItem columnItem : fieldItem1.getColumnItems()) {\n                                            if (old.containsKey(columnItem.getColumnName())) {\n                                                Object val = esTemplate.getValFromRS(mapping,\n                                                    rs,\n                                                    fieldItem.getFieldName(),\n                                                    fieldItem.getFieldName());\n                                                esFieldData.put(fieldItem.getFieldName(), val);\n                                                break out;\n                                            }\n                                        }\n                                }\n                            }\n                            // 从表非子查询\n                            for (FieldItem fieldItem1 : tableItem.getRelationSelectFieldItems()) {\n                                if (fieldItem1.equals(fieldItem)) {\n                                    for (ColumnItem columnItem : fieldItem1.getColumnItems()) {\n                                        if (old.containsKey(columnItem.getColumnName())) {\n                                            Object val = esTemplate.getValFromRS(mapping,\n                                                rs,\n                                                fieldItem.getFieldName(),\n                                                fieldItem.getFieldName());\n                                            esFieldData.put(Util.cleanColumn(fieldItem.getFieldName()), val);\n                                            break;\n                                        }\n                                    }\n                                }\n                            }\n                        } else {\n                            Object val = esTemplate\n                                .getValFromRS(mapping, rs, fieldItem.getFieldName(), fieldItem.getFieldName());\n                            esFieldData.put(Util.cleanColumn(fieldItem.getFieldName()), val);\n                        }\n                    }\n\n                    Map<String, Object> paramsTmp = new LinkedHashMap<>();\n                    for (Map.Entry<FieldItem, List<FieldItem>> entry : tableItem.getRelationTableFields().entrySet()) {\n                        for (FieldItem fieldItem : entry.getValue()) {\n                            Object value = esTemplate\n                                .getValFromRS(mapping, rs, fieldItem.getFieldName(), fieldItem.getFieldName());\n                            String fieldName = fieldItem.getFieldName();\n                            // 判断是否是主键\n                            if (fieldName.equals(mapping.getId())) {\n                                fieldName = \"_id\";\n                            }\n                            paramsTmp.put(fieldName, value);\n                        }\n                    }\n\n                    if (logger.isDebugEnabled()) {\n                        logger.trace(\n                            \"Join table update es index by query whole sql, destination:{}, table: {}, index: {}\",\n                            config.getDestination(),\n                            dml.getTable(),\n                            mapping.getIndex());\n                    }\n                    esTemplate.updateByQuery(config, paramsTmp, esFieldData);\n                }\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n            return 0;\n        });\n    }\n\n    /**\n     * 单表简单字段update\n     *\n     * @param config es配置\n     * @param dml dml信息\n     * @param data 单行data数据\n     * @param old 单行old数据\n     */\n    private void singleTableSimpleFiledUpdate(ESSyncConfig config, String owner, Dml dml, Map<String, Object> data,\n                                              Map<String, Object> old) {\n        ESMapping mapping = config.getEsMapping();\n        Map<String, Object> esFieldData = new LinkedHashMap<>();\n\n        Object idVal = esTemplate.getESDataFromDmlData(mapping, owner, data, old, esFieldData);\n\n        if (logger.isTraceEnabled()) {\n            logger.trace(\"Main table update to es index, destination:{}, table: {}, index: {}, id: {}\",\n                config.getDestination(),\n                dml.getTable(),\n                mapping.getIndex(),\n                idVal);\n        }\n        esTemplate.update(mapping, idVal, esFieldData);\n    }\n\n    /**\n     * 主表(单表)复杂字段update\n     *\n     * @param config es配置\n     * @param dml dml信息\n     * @param data 单行dml数据\n     */\n    private void mainTableUpdate(ESSyncConfig config, Dml dml, Map<String, Object> data, Map<String, Object> old) {\n        ESMapping mapping = config.getEsMapping();\n        String sql = mapping.getSql();\n        String condition = ESSyncUtil.pkConditionSql(mapping, data);\n        sql = ESSyncUtil.appendCondition(sql, condition);\n        DataSource ds = DatasourceConfig.DATA_SOURCES.get(config.getDataSourceKey());\n        if (logger.isTraceEnabled()) {\n            logger.trace(\"Main table update to es index by query sql, destination:{}, table: {}, index: {}, sql: {}\",\n                config.getDestination(),\n                dml.getTable(),\n                mapping.getIndex(),\n                sql.replace(\"\\n\", \" \"));\n        }\n        Util.sqlRS(ds, sql, rs -> {\n            try {\n                while (rs.next()) {\n                    Map<String, Object> esFieldData = new LinkedHashMap<>();\n                    Object idVal = esTemplate.getESDataFromRS(mapping, rs, old, esFieldData);\n\n                    if (logger.isTraceEnabled()) {\n                        logger.trace(\n                            \"Main table update to es index by query sql, destination:{}, table: {}, index: {}, id: {}\",\n                            config.getDestination(),\n                            dml.getTable(),\n                            mapping.getIndex(),\n                            idVal);\n                    }\n                    esTemplate.update(mapping, idVal, esFieldData);\n                }\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n            return 0;\n        });\n    }\n\n    /**\n     * 提交批次\n     */\n    public void commit() {\n        esTemplate.commit();\n    }\n}\n"
  },
  {
    "path": "client-adapter/escore/src/main/java/com/alibaba/otter/canal/client/adapter/es/core/support/ESBulkRequest.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es.core.support;\n\nimport java.util.Map;\n\npublic interface ESBulkRequest {\n\n    void resetBulk();\n\n    ESBulkRequest add(ESIndexRequest esIndexRequest);\n\n    ESBulkRequest add(ESUpdateRequest esUpdateRequest);\n\n    ESBulkRequest add(ESDeleteRequest esDeleteRequest);\n\n    int numberOfActions();\n\n    ESBulkResponse bulk();\n\n    interface ESIndexRequest {\n\n        ESIndexRequest setSource(Map<String, ?> source);\n\n        ESIndexRequest setRouting(String routing);\n    }\n\n    interface ESUpdateRequest {\n\n        ESUpdateRequest setDoc(Map source);\n\n        ESUpdateRequest setDocAsUpsert(boolean shouldUpsertDoc);\n\n        ESUpdateRequest setRouting(String routing);\n    }\n\n    interface ESDeleteRequest {\n    }\n\n    interface ESBulkResponse {\n        boolean hasFailures();\n\n        void processFailBulkResponse(String errorMsg);\n    }\n}\n"
  },
  {
    "path": "client-adapter/escore/src/main/java/com/alibaba/otter/canal/client/adapter/es/core/support/ESSyncUtil.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es.core.support;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.math.BigDecimal;\nimport java.nio.charset.StandardCharsets;\nimport java.sql.Blob;\nimport java.sql.SQLException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.apache.commons.codec.binary.Base64;\nimport org.joda.time.DateTime;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig.ESMapping;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem.ColumnItem;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem.TableItem;\nimport com.alibaba.otter.canal.client.adapter.support.Util;\n\n/**\n * ES 同步工具同类\n *\n * @author rewerma 2018-11-01\n * @version 1.0.0\n */\npublic class ESSyncUtil {\n\n    private static Logger logger = LoggerFactory.getLogger(ESSyncUtil.class);\n\n    public static Object convertToEsObj(Object val, String fieldInfo) {\n        if (val == null) {\n            return null;\n        }\n        if (fieldInfo.startsWith(\"array:\")) {\n            String separator = fieldInfo.substring(\"array:\".length()).trim();\n            String[] values = val.toString().split(separator);\n            return Arrays.asList(values);\n        } else if (fieldInfo.startsWith(\"object\")) {\n            if (val instanceof String){\n                return JSON.parse(val.toString());\n            }\n            return JSON.parse(new String((byte[])val));\n        }\n        return null;\n    }\n\n    /**\n     * 类型转换为Mapping中对应的类型\n     */\n    public static Object typeConvert(Object val, String esType) {\n        if (val == null) {\n            return null;\n        }\n        if (esType == null) {\n            return val;\n        }\n        Object res = null;\n        switch (esType) {\n            case \"integer\":\n                if (val instanceof Number) {\n                    res = ((Number) val).intValue();\n                } else {\n                    res = Integer.parseInt(val.toString());\n                }\n                break;\n            case \"long\":\n                if (val instanceof Number) {\n                    res = ((Number) val).longValue();\n                } else {\n                    res = Long.parseLong(val.toString());\n                }\n                break;\n            case \"short\":\n                if (val instanceof Number) {\n                    res = ((Number) val).shortValue();\n                } else {\n                    res = Short.parseShort(val.toString());\n                }\n                break;\n            case \"byte\":\n                if (val instanceof Number) {\n                    res = ((Number) val).byteValue();\n                } else {\n                    res = Byte.parseByte(val.toString());\n                }\n                break;\n            case \"double\":\n                if (val instanceof Number) {\n                    res = ((Number) val).doubleValue();\n                } else {\n                    res = Double.parseDouble(val.toString());\n                }\n                break;\n            case \"float\":\n            case \"half_float\":\n                if (val instanceof Number) {\n                    res = ((Number) val).floatValue();\n                } else {\n                    res = Float.parseFloat(val.toString());\n                }\n                break;\n            case \"scaled_float\":\n                // scaled_float 需要保持高精度，使用 BigDecimal 进行处理\n                if (val instanceof BigDecimal) {\n                    res = val; // 保持 BigDecimal 精度\n                } else if (val instanceof Number) {\n                    res = new BigDecimal(val.toString());\n                } else {\n                    res = new BigDecimal(val.toString());\n                }\n                break;\n            case \"boolean\":\n                if (val instanceof Boolean) {\n                    res = val;\n                } else if (val instanceof Number) {\n                    int v = ((Number) val).intValue();\n                    res = v != 0;\n                } else {\n                    res = Boolean.parseBoolean(val.toString());\n                }\n                break;\n            case \"date\":\n                if (val instanceof java.sql.Time) {\n                    DateTime dateTime = new DateTime(((java.sql.Time) val).getTime());\n                    if (dateTime.getMillisOfSecond() != 0) {\n                        res = dateTime.toString(\"HH:mm:ss.SSS\");\n                    } else {\n                        res = dateTime.toString(\"HH:mm:ss\");\n                    }\n                } else if (val instanceof java.sql.Timestamp) {\n                    DateTime dateTime = new DateTime(((java.sql.Timestamp) val).getTime());\n                    if (dateTime.getMillisOfSecond() != 0) {\n                        res = dateTime.toString(\"yyyy-MM-dd'T'HH:mm:ss.SSS\" + Util.timeZone);\n                    } else {\n                        res = dateTime.toString(\"yyyy-MM-dd'T'HH:mm:ss\" + Util.timeZone);\n                    }\n                } else if (val instanceof java.sql.Date || val instanceof Date) {\n                    DateTime dateTime;\n                    if (val instanceof java.sql.Date) {\n                        dateTime = new DateTime(((java.sql.Date) val).getTime());\n                    } else {\n                        dateTime = new DateTime(((Date) val).getTime());\n                    }\n                    if (dateTime.getHourOfDay() == 0 && dateTime.getMinuteOfHour() == 0 && dateTime.getSecondOfMinute() == 0\n                            && dateTime.getMillisOfSecond() == 0) {\n                        res = dateTime.toString(\"yyyy-MM-dd\");\n                    } else {\n                        if (dateTime.getMillisOfSecond() != 0) {\n                            res = dateTime.toString(\"yyyy-MM-dd'T'HH:mm:ss.SSS\" + Util.timeZone);\n                        } else {\n                            res = dateTime.toString(\"yyyy-MM-dd'T'HH:mm:ss\" + Util.timeZone);\n                        }\n                    }\n                } else if (val instanceof Long) {\n                    DateTime dateTime = new DateTime(((Long) val).longValue());\n                    if (dateTime.getHourOfDay() == 0 && dateTime.getMinuteOfHour() == 0 && dateTime.getSecondOfMinute() == 0\n                            && dateTime.getMillisOfSecond() == 0) {\n                        res = dateTime.toString(\"yyyy-MM-dd\");\n                    } else if (dateTime.getMillisOfSecond() != 0) {\n                        res = dateTime.toString(\"yyyy-MM-dd'T'HH:mm:ss.SSS\" + Util.timeZone);\n                    } else {\n                        res = dateTime.toString(\"yyyy-MM-dd'T'HH:mm:ss\" + Util.timeZone);\n                    }\n                } else if (val instanceof String) {\n                    String v = ((String) val).trim();\n                    if (v.length() > 18 && v.charAt(4) == '-' && v.charAt(7) == '-' && v.charAt(10) == ' '\n                            && v.charAt(13) == ':' && v.charAt(16) == ':') {\n                        String dt = v.substring(0, 10) + \"T\" + v.substring(11);\n                        Date date = Util.parseDate(dt);\n                        if (date != null) {\n                            DateTime dateTime = new DateTime(date);\n                            if (dateTime.getMillisOfSecond() != 0) {\n                                res = dateTime.toString(\"yyyy-MM-dd'T'HH:mm:ss.SSS\" + Util.timeZone);\n                            } else {\n                                res = dateTime.toString(\"yyyy-MM-dd'T'HH:mm:ss\" + Util.timeZone);\n                            }\n                        }\n                    } else if (v.length() == 10 && v.charAt(4) == '-' && v.charAt(7) == '-') {\n                        Date date = Util.parseDate(v);\n                        if (date != null) {\n                            DateTime dateTime = new DateTime(date);\n                            res = dateTime.toString(\"yyyy-MM-dd\");\n                        }\n                    }\n                }\n                break;\n            case \"binary\":\n                if (val instanceof byte[]) {\n                    Base64 base64 = new Base64();\n                    res = base64.encodeAsString((byte[]) val);\n                } else if (val instanceof Blob) {\n                    byte[] b = blobToBytes((Blob) val);\n                    Base64 base64 = new Base64();\n                    res = base64.encodeAsString(b);\n                } else if (val instanceof String) {\n                    // 对应canal中的单字节编码\n                    byte[] b = ((String) val).getBytes(StandardCharsets.ISO_8859_1);\n                    Base64 base64 = new Base64();\n                    res = base64.encodeAsString(b);\n                }\n                break;\n            case \"geo_point\":\n                if (!(val instanceof String)) {\n                    logger.error(\"es type is geo_point, but source type is not String\");\n                    return val;\n                }\n\n                if (!((String) val).contains(\",\")) {\n                    logger.error(\"es type is geo_point, source value not contains ',' separator\");\n                    return val;\n                }\n\n                String[] point = ((String) val).split(\",\");\n                Map<String, Double> location = new HashMap<>();\n                location.put(\"lat\", Double.valueOf(point[0].trim()));\n                location.put(\"lon\", Double.valueOf(point[1].trim()));\n                return location;\n            case \"array\":\n                if (\"\".equals(val.toString().trim())) {\n                    res = new ArrayList<>();\n                } else {\n                    String value = val.toString();\n                    String separator = \",\";\n                    if (!value.contains(\",\")) {\n                        if (value.contains(\";\")) {\n                            separator = \";\";\n                        } else if (value.contains(\"|\")) {\n                            separator = \"\\\\|\";\n                        } else if (value.contains(\"-\")) {\n                            separator = \"-\";\n                        }\n                    }\n                    String[] values = value.split(separator);\n                    return Arrays.asList(values);\n                }\n                break;\n            case \"object\":\n                if (\"\".equals(val.toString().trim())) {\n                    res = new HashMap<>();\n                } else {\n                    res = JSON.parseObject(val.toString(), Map.class);\n                }\n                break;\n            default:\n                // 其他类全以字符串处理\n                res = val.toString();\n                break;\n        }\n\n        return res;\n    }\n\n    /**\n     * Blob转byte[]\n     */\n    private static byte[] blobToBytes(Blob blob) {\n        try (InputStream is = blob.getBinaryStream()) {\n            byte[] b = new byte[(int) blob.length()];\n            if (is.read(b) != -1) {\n                return b;\n            } else {\n                return new byte[0];\n            }\n        } catch (IOException | SQLException e) {\n            logger.error(e.getMessage());\n            return null;\n        }\n    }\n\n    /**\n     * 拼接主键条件\n     *\n     * @param mapping\n     * @param data\n     * @return\n     */\n    public static String pkConditionSql(ESMapping mapping, Map<String, Object> data) {\n        Set<ColumnItem> idColumns = new LinkedHashSet<>();\n        SchemaItem schemaItem = mapping.getSchemaItem();\n\n        TableItem mainTable = schemaItem.getMainTable();\n\n        for (ColumnItem idColumnItem : schemaItem.getIdFieldItem(mapping).getColumnItems()) {\n            if ((mainTable.getAlias() == null && idColumnItem.getOwner() == null)\n                || (mainTable.getAlias() != null && mainTable.getAlias().equals(idColumnItem.getOwner()))) {\n                idColumns.add(idColumnItem);\n            }\n        }\n\n        if (idColumns.isEmpty()) {\n            throw new RuntimeException(\"Not found primary key field in main table\");\n        }\n\n        // 拼接condition\n        StringBuilder condition = new StringBuilder(\" \");\n        for (ColumnItem idColumn : idColumns) {\n            Object idVal = data.get(idColumn.getColumnName());\n            if (mainTable.getAlias() != null) condition.append(mainTable.getAlias()).append(\".\");\n            condition.append(idColumn.getColumnName()).append(\"=\");\n            if (idVal instanceof String) {\n                condition.append(\"'\").append(idVal).append(\"' AND \");\n            } else {\n                condition.append(idVal).append(\" AND \");\n            }\n        }\n\n        if (condition.toString().endsWith(\"AND \")) {\n            int len2 = condition.length();\n            condition.delete(len2 - 4, len2);\n        }\n        return condition.toString();\n    }\n\n    public static String appendCondition(String sql, String condition) {\n        return sql + \" WHERE \" + condition + \" \";\n    }\n\n    public static void appendCondition(StringBuilder sql, Object value, String owner, String columnName) {\n        if (value instanceof String) {\n            sql.append(owner).append(\".\").append(columnName).append(\"='\").append(value).append(\"'  AND \");\n        } else {\n            sql.append(owner).append(\".\").append(columnName).append(\"=\").append(value).append(\"  AND \");\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/escore/src/main/java/com/alibaba/otter/canal/client/adapter/es/core/support/ESTemplate.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es.core.support;\n\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.util.Map;\n\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig;\nimport com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig.ESMapping;\n\npublic interface ESTemplate {\n\n    /**\n     * 插入数据\n     *\n     * @param mapping 配置对象\n     * @param pkVal 主键值\n     * @param esFieldData 数据Map\n     */\n    void insert(ESMapping mapping, Object pkVal, Map<String, Object> esFieldData);\n\n    /**\n     * 根据主键更新数据\n     *\n     * @param mapping 配置对象\n     * @param pkVal 主键值\n     * @param esFieldData 数据Map\n     */\n    void update(ESMapping mapping, Object pkVal, Map<String, Object> esFieldData);\n\n    /**\n     * update by query\n     *\n     * @param config 配置对象\n     * @param paramsTmp sql查询条件\n     * @param esFieldData 数据Map\n     */\n    void updateByQuery(ESSyncConfig config, Map<String, Object> paramsTmp, Map<String, Object> esFieldData);\n\n    /**\n     * 通过主键删除数据\n     *\n     * @param mapping 配置对象\n     * @param pkVal 主键值\n     * @param esFieldData 数据Map\n     */\n    void delete(ESMapping mapping, Object pkVal, Map<String, Object> esFieldData);\n\n    /**\n     * 提交批次\n     */\n    void commit();\n\n    Object getValFromRS(ESMapping mapping, ResultSet resultSet, String fieldName,\n                        String columnName) throws SQLException;\n\n    Object getESDataFromRS(ESMapping mapping, ResultSet resultSet, Map<String, Object> esFieldData) throws SQLException;\n\n    Object getIdValFromRS(ESMapping mapping, ResultSet resultSet) throws SQLException;\n\n    Object getESDataFromRS(ESMapping mapping, ResultSet resultSet, Map<String, Object> dmlOld, Map<String, Object> esFieldData) throws SQLException;\n\n    Object getValFromData(ESMapping mapping, Map<String, Object> dmlData, String fieldName, String columnName);\n\n    Object getESDataFromDmlData(ESMapping mapping, Map<String, Object> dmlData, Map<String, Object> esFieldData);\n\n    Object getESDataFromDmlData(ESMapping mapping,String owner, Map<String, Object> dmlData, Map<String, Object> dmlOld, Map<String, Object> esFieldData);\n}\n"
  },
  {
    "path": "client-adapter/escore/src/test/java/com/alibaba/otter/canal/client/adapter/es/core/support/ESSyncUtilTest.java",
    "content": "package com.alibaba.otter.canal.client.adapter.es.core.support;\n\nimport java.math.BigDecimal;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\n/**\n * ESSyncUtil 测试类\n * \n * @author jianghang\n */\npublic class ESSyncUtilTest {\n\n    @Test\n    public void testScaledFloatPrecision() {\n        // 测试高精度 decimal 转换为 scaled_float\n        BigDecimal originalValue = new BigDecimal(\"1234567890.12345678901234567890\");\n\n        // 转换为 scaled_float\n        Object result = ESSyncUtil.typeConvert(originalValue, \"scaled_float\");\n\n        // 验证结果仍然是 BigDecimal，保持精度\n        Assert.assertTrue(\"scaled_float 转换结果应该是 BigDecimal 类型\", result instanceof BigDecimal);\n        Assert.assertEquals(\"scaled_float 转换应该保持原始精度\", originalValue, result);\n\n        // 验证 toString 表示\n        Assert.assertEquals(\"scaled_float 精度应该保持完整\", \"1234567890.12345678901234567890\", result.toString());\n    }\n\n    @Test\n    public void testScaledFloatFromString() {\n        // 测试字符串转换为 scaled_float\n        String originalString = \"9876543210.98765432109876543210\";\n\n        // 转换为 scaled_float\n        Object result = ESSyncUtil.typeConvert(originalString, \"scaled_float\");\n\n        // 验证结果是 BigDecimal\n        Assert.assertTrue(\"scaled_float 字符串转换结果应该是 BigDecimal 类型\", result instanceof BigDecimal);\n\n        // 验证值正确\n        BigDecimal expected = new BigDecimal(originalString);\n        Assert.assertEquals(\"scaled_float 字符串转换应该正确解析\", expected, result);\n    }\n\n    @Test\n    public void testScaledFloatFromDouble() {\n        // 测试 double 转换为 scaled_float（注意：double 本身有精度限制）\n        Double originalDouble = 1234567890.1234567890;\n\n        // 转换为 scaled_float\n        Object result = ESSyncUtil.typeConvert(originalDouble, \"scaled_float\");\n\n        // 验证结果是 BigDecimal\n        Assert.assertTrue(\"scaled_float double 转换结果应该是 BigDecimal 类型\", result instanceof BigDecimal);\n\n        // 验证值正确（由于 double 精度限制，这里验证转换过程正确）\n        BigDecimal expected = new BigDecimal(originalDouble.toString());\n        Assert.assertEquals(\"scaled_float double 转换应该正确处理\", expected, result);\n    }\n\n    @Test\n    public void testOtherFloatTypes() {\n        // 测试其他浮点类型仍然正常工作\n        BigDecimal value = new BigDecimal(\"123.45\");\n\n        // 测试 float 类型\n        Object floatResult = ESSyncUtil.typeConvert(value, \"float\");\n        Assert.assertTrue(\"float 转换结果应该是 Float 类型\", floatResult instanceof Float);\n\n        // 测试 half_float 类型\n        Object halfFloatResult = ESSyncUtil.typeConvert(value, \"half_float\");\n        Assert.assertTrue(\"half_float 转换结果应该是 Float 类型\", halfFloatResult instanceof Float);\n    }\n}\n"
  },
  {
    "path": "client-adapter/hbase/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>canal.client-adapter</artifactId>\n        <groupId>com.alibaba.otter</groupId>\n        <version>1.1.9-SNAPSHOT</version>\n        <relativePath>../pom.xml</relativePath>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>com.alibaba.otter</groupId>\n    <artifactId>client-adapter.hbase</artifactId>\n    <packaging>jar</packaging>\n    <name>canal client adapter hbase module for otter ${project.version}</name>\n    <dependencies>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>client-adapter.common</artifactId>\n            <version>${project.version}</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.hbase</groupId>\n            <artifactId>hbase-shaded-client</artifactId>\n            <exclusions>\n                <exclusion>\n                    <groupId>org.slf4j</groupId>\n                    <artifactId>slf4j-log4j12</artifactId>\n                </exclusion>\n                <exclusion>\n                    <groupId>jdk.tools</groupId>\n                    <artifactId>jdk.tools</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <dependency>\n            <groupId>com.google.guava</groupId>\n            <artifactId>guava</artifactId>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-assembly-plugin</artifactId>\n                <version>2.4</version>\n                <configuration>\n                    <descriptorRefs>\n                        <descriptorRef>jar-with-dependencies</descriptorRef>\n                    </descriptorRefs>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>make-assembly</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>single</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-antrun-plugin</artifactId>\n                <version>1.8</version>\n                <executions>\n                    <execution>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>run</goal>\n                        </goals>\n                        <configuration>\n                            <tasks>\n                                <copy todir=\"${project.basedir}/../launcher/target/classes/hbase\" overwrite=\"true\">\n                                    <fileset dir=\"${project.basedir}/target/classes/hbase\" erroronmissingdir=\"true\">\n                                        <include name=\"*.yml\" />\n                                    </fileset>\n                                </copy>\n                            </tasks>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "client-adapter/hbase/src/main/java/com/alibaba/otter/canal/client/adapter/hbase/HbaseAdapter.java",
    "content": "package com.alibaba.otter.canal.client.adapter.hbase;\n\nimport com.alibaba.otter.canal.client.adapter.OuterAdapter;\nimport com.alibaba.otter.canal.client.adapter.hbase.config.MappingConfig;\nimport com.alibaba.otter.canal.client.adapter.hbase.config.MappingConfigLoader;\nimport com.alibaba.otter.canal.client.adapter.hbase.monitor.HbaseConfigMonitor;\nimport com.alibaba.otter.canal.client.adapter.hbase.service.HbaseEtlService;\nimport com.alibaba.otter.canal.client.adapter.hbase.service.HbaseSyncService;\nimport com.alibaba.otter.canal.client.adapter.hbase.support.HbaseTemplate;\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\nimport com.alibaba.otter.canal.client.adapter.support.EtlResult;\nimport com.alibaba.otter.canal.client.adapter.support.FileName2KeyMapping;\nimport com.alibaba.otter.canal.client.adapter.support.OuterAdapterConfig;\nimport com.alibaba.otter.canal.client.adapter.support.SPI;\nimport com.alibaba.otter.canal.client.adapter.support.Util;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.concurrent.ConcurrentHashMap;\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.hadoop.conf.Configuration;\nimport org.apache.hadoop.hbase.HBaseConfiguration;\nimport org.apache.hadoop.hbase.TableName;\nimport org.apache.hadoop.hbase.client.HTable;\nimport org.apache.hadoop.hbase.client.Result;\nimport org.apache.hadoop.hbase.client.ResultScanner;\nimport org.apache.hadoop.hbase.client.Scan;\nimport org.apache.hadoop.hbase.filter.FirstKeyOnlyFilter;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * HBase外部适配器\n *\n * @author machengyuan 2018-8-21 下午8:45:38\n * @version 1.0.0\n */\n@SPI(\"hbase\")\npublic class HbaseAdapter implements OuterAdapter {\n\n    private static Logger                           logger             = LoggerFactory.getLogger(HbaseAdapter.class);\n\n    private Map<String, MappingConfig>              hbaseMapping       = new ConcurrentHashMap<>();                  // 文件名对应配置\n    private Map<String, Map<String, MappingConfig>> mappingConfigCache = new ConcurrentHashMap<>();                  // 库名-表名对应配置\n\n    private HbaseSyncService                        hbaseSyncService;\n    private HbaseTemplate                           hbaseTemplate;\n\n    private HbaseConfigMonitor                      configMonitor;\n\n    private Properties                              envProperties;\n\n    private OuterAdapterConfig                      configuration;\n\n    public Map<String, MappingConfig> getHbaseMapping() {\n        return hbaseMapping;\n    }\n\n    public Map<String, Map<String, MappingConfig>> getMappingConfigCache() {\n        return mappingConfigCache;\n    }\n\n    @Override\n    public void init(OuterAdapterConfig configuration, Properties envProperties) {\n        try {\n            this.envProperties = envProperties;\n            this.configuration = configuration;\n            Map<String, MappingConfig> hbaseMappingTmp = MappingConfigLoader.load(envProperties);\n            // 过滤不匹配的key的配置\n            hbaseMappingTmp.forEach((key, config) -> {\n                addConfig(key, config);\n            });\n\n            Map<String, String> properties = configuration.getProperties();\n\n            Configuration hbaseConfig = HBaseConfiguration.create();\n            properties.forEach(hbaseConfig::set);\n            hbaseTemplate = new HbaseTemplate(hbaseConfig);\n            hbaseSyncService = new HbaseSyncService(hbaseTemplate);\n\n            configMonitor = new HbaseConfigMonitor();\n            configMonitor.init(this, envProperties);\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    @Override\n    public void sync(List<Dml> dmls) {\n        if (dmls == null || dmls.isEmpty()) {\n            return;\n        }\n        for (Dml dml : dmls) {\n            sync(dml);\n        }\n    }\n\n    private void sync(Dml dml) {\n        if (dml == null) {\n            return;\n        }\n        String destination = StringUtils.trimToEmpty(dml.getDestination());\n        String groupId = StringUtils.trimToEmpty(dml.getGroupId());\n        String database = dml.getDatabase();\n        String table = dml.getTable();\n        Map<String, MappingConfig> configMap;\n        if (envProperties != null && !\"tcp\".equalsIgnoreCase(envProperties.getProperty(\"canal.conf.mode\"))) {\n            configMap = mappingConfigCache.get(destination + \"-\" + groupId + \"_\" + database + \"-\" + table);\n        } else {\n            configMap = mappingConfigCache.get(destination + \"_\" + database + \"-\" + table);\n        }\n        if (configMap != null) {\n            List<MappingConfig> configs = new ArrayList<>();\n            configMap.values().forEach(config -> {\n                if (StringUtils.isNotEmpty(config.getGroupId())) {\n                    if (config.getGroupId().equals(dml.getGroupId())) {\n                        configs.add(config);\n                    }\n                } else {\n                    configs.add(config);\n                }\n            });\n            if (!configs.isEmpty()) {\n                configs.forEach(config -> hbaseSyncService.sync(config, dml));\n            }\n        }\n    }\n\n    @Override\n    public EtlResult etl(String task, List<String> params) {\n        EtlResult etlResult = new EtlResult();\n        MappingConfig config = hbaseMapping.get(task);\n        HbaseEtlService hbaseEtlService = new HbaseEtlService(hbaseTemplate, config);\n        if (config != null) {\n            return hbaseEtlService.importData(params);\n        } else {\n            StringBuilder resultMsg = new StringBuilder();\n            boolean resSucc = true;\n            for (MappingConfig configTmp : hbaseMapping.values()) {\n                // 取所有的destination为task的配置\n                if (configTmp.getDestination().equals(task)) {\n                    EtlResult etlRes = hbaseEtlService.importData(params);\n                    if (!etlRes.getSucceeded()) {\n                        resSucc = false;\n                        resultMsg.append(etlRes.getErrorMessage()).append(\"\\n\");\n                    } else {\n                        resultMsg.append(etlRes.getResultMessage()).append(\"\\n\");\n                    }\n                }\n            }\n            if (resultMsg.length() > 0) {\n                etlResult.setSucceeded(resSucc);\n                if (resSucc) {\n                    etlResult.setResultMessage(resultMsg.toString());\n                } else {\n                    etlResult.setErrorMessage(resultMsg.toString());\n                }\n                return etlResult;\n            }\n        }\n        etlResult.setSucceeded(false);\n        etlResult.setErrorMessage(\"Task not found\");\n        return etlResult;\n    }\n\n    @Override\n    public Map<String, Object> count(String task) {\n        MappingConfig config = hbaseMapping.get(task);\n        String hbaseTable = config.getHbaseMapping().getHbaseTable();\n        long rowCount = 0L;\n        try {\n            HTable table = (HTable) hbaseTemplate.getConnection().getTable(TableName.valueOf(hbaseTable));\n            Scan scan = new Scan();\n            scan.setFilter(new FirstKeyOnlyFilter());\n            ResultScanner resultScanner = table.getScanner(scan);\n            for (Result result : resultScanner) {\n                rowCount += result.size();\n            }\n        } catch (IOException e) {\n            logger.error(e.getMessage(), e);\n        }\n        Map<String, Object> res = new LinkedHashMap<>();\n        res.put(\"hbaseTable\", hbaseTable);\n        res.put(\"count\", rowCount);\n        return res;\n    }\n\n    @Override\n    public void destroy() {\n        if (configMonitor != null) {\n            configMonitor.destroy();\n        }\n        try {\n            hbaseTemplate.close();\n        } catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    @Override\n    public String getDestination(String task) {\n        MappingConfig config = hbaseMapping.get(task);\n        if (config != null && config.getHbaseMapping() != null) {\n            return config.getDestination();\n        }\n        return null;\n    }\n\n    private void addSyncConfigToCache(String configName, MappingConfig mappingConfig) {\n        String k;\n        if (envProperties != null && !\"tcp\"\n                .equalsIgnoreCase(envProperties.getProperty(\"canal.conf.mode\"))) {\n            k = StringUtils.trimToEmpty(mappingConfig.getDestination()) + \"-\" + StringUtils\n                    .trimToEmpty(mappingConfig.getGroupId()) + \"_\" + mappingConfig.getHbaseMapping()\n                    .getDatabase() + \"-\" + mappingConfig.getHbaseMapping().getTable();\n        } else {\n            k = StringUtils.trimToEmpty(mappingConfig.getDestination()) + \"_\" + mappingConfig\n                    .getHbaseMapping().getDatabase() + \"-\" + mappingConfig.getHbaseMapping()\n                    .getTable();\n        }\n        Map<String, MappingConfig> configMap = mappingConfigCache\n                .computeIfAbsent(k, k1 -> new ConcurrentHashMap<>());\n        configMap.put(configName, mappingConfig);\n    }\n\n    public boolean addConfig(String fileName, MappingConfig config) {\n        if (match(config)) {\n            hbaseMapping.put(fileName, config);\n            addSyncConfigToCache(fileName, config);\n            FileName2KeyMapping.register(getClass().getAnnotation(SPI.class).value(), fileName,\n                    configuration.getKey());\n            return true;\n        }\n        return false;\n    }\n\n    public void updateConfig(String fileName, MappingConfig config) {\n        if (config.getOuterAdapterKey() != null && !config.getOuterAdapterKey()\n                .equals(configuration.getKey())) {\n            // 理论上不允许改这个 因为本身就是通过这个关联起Adapter和Config的\n            throw new RuntimeException(\"not allow to change outAdapterKey\");\n        }\n        hbaseMapping.put(fileName, config);\n        addSyncConfigToCache(fileName, config);\n    }\n\n    public void deleteConfig(String fileName) {\n        hbaseMapping.remove(fileName);\n        for (Map<String, MappingConfig> configMap : mappingConfigCache.values()) {\n            if (configMap != null) {\n                configMap.remove(fileName);\n            }\n        }\n        FileName2KeyMapping.unregister(getClass().getAnnotation(SPI.class).value(), fileName);\n    }\n\n    private boolean match(MappingConfig config) {\n        boolean sameMatch = config.getOuterAdapterKey() != null && config.getOuterAdapterKey()\n                .equalsIgnoreCase(configuration.getKey());\n        boolean prefixMatch = config.getOuterAdapterKey() == null && configuration.getKey()\n                .startsWith(StringUtils\n                        .join(new String[]{Util.AUTO_GENERATED_PREFIX, config.getDestination(),\n                                config.getGroupId()}, '-'));\n        return sameMatch || prefixMatch;\n    }\n}\n"
  },
  {
    "path": "client-adapter/hbase/src/main/java/com/alibaba/otter/canal/client/adapter/hbase/config/MappingConfig.java",
    "content": "package com.alibaba.otter.canal.client.adapter.hbase.config;\n\nimport com.alibaba.otter.canal.client.adapter.support.AdapterConfig;\n\nimport java.util.*;\n\n/**\n * HBase表映射配置\n *\n * @author rewerma 2018-8-21 下午06:45:49\n * @version 1.0.0\n */\npublic class MappingConfig implements AdapterConfig {\n\n    private String       dataSourceKey;   // 数据源key\n\n    private String       outerAdapterKey; // adapter key\n\n    private String       groupId;         // groupId\n\n    private String       destination;     // canal实例或MQ的topic\n\n    private HbaseMapping hbaseMapping;    // hbase映射配置\n\n    public String getDataSourceKey() {\n        return dataSourceKey;\n    }\n\n    public void setDataSourceKey(String dataSourceKey) {\n        this.dataSourceKey = dataSourceKey;\n    }\n\n    public String getGroupId() {\n        return groupId;\n    }\n\n    public void setGroupId(String groupId) {\n        this.groupId = groupId;\n    }\n\n    public String getOuterAdapterKey() {\n        return outerAdapterKey;\n    }\n\n    public void setOuterAdapterKey(String outerAdapterKey) {\n        this.outerAdapterKey = outerAdapterKey;\n    }\n\n    public String getDestination() {\n        return destination;\n    }\n\n    public void setDestination(String destination) {\n        this.destination = destination;\n    }\n\n    public HbaseMapping getHbaseMapping() {\n        return hbaseMapping;\n    }\n\n    public void setHbaseMapping(HbaseMapping hbaseMapping) {\n        this.hbaseMapping = hbaseMapping;\n    }\n\n    public AdapterMapping getMapping() {\n        return hbaseMapping;\n    }\n\n    public void validate() {\n        if (hbaseMapping.database == null || hbaseMapping.database.isEmpty()) {\n            throw new NullPointerException(\"hbaseMapping.database\");\n        }\n        if (hbaseMapping.table == null || hbaseMapping.table.isEmpty()) {\n            throw new NullPointerException(\"hbaseMapping.table\");\n        }\n        if (hbaseMapping.hbaseTable == null || hbaseMapping.hbaseTable.isEmpty()) {\n            throw new NullPointerException(\"hbaseMapping.hbaseTable\");\n        }\n        if (hbaseMapping.mode == null) {\n            throw new NullPointerException(\"hbaseMapping.mode\");\n        }\n        if (hbaseMapping.rowKey != null && hbaseMapping.rowKeyColumn != null) {\n            throw new RuntimeException(\"已配置了复合主键作为RowKey，无需再指定RowKey列\");\n        }\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n\n        MappingConfig config = (MappingConfig) o;\n\n        return hbaseMapping != null ? hbaseMapping.equals(config.hbaseMapping) : config.hbaseMapping == null;\n    }\n\n    @Override\n    public int hashCode() {\n        return hbaseMapping != null ? hbaseMapping.hashCode() : 0;\n    }\n\n    public static class ColumnItem {\n\n        private boolean isRowKey = false;\n        private Integer rowKeyLen;\n        private String  column;\n        private String  family;\n        private String  qualifier;\n        private String  type;\n\n        public boolean isRowKey() {\n            return isRowKey;\n        }\n\n        public void setRowKey(boolean rowKey) {\n            isRowKey = rowKey;\n        }\n\n        public Integer getRowKeyLen() {\n            return rowKeyLen;\n        }\n\n        public void setRowKeyLen(Integer rowKeyLen) {\n            this.rowKeyLen = rowKeyLen;\n        }\n\n        public String getColumn() {\n            return column;\n        }\n\n        public void setColumn(String column) {\n            this.column = column;\n        }\n\n        public String getFamily() {\n            return family;\n        }\n\n        public void setFamily(String family) {\n            this.family = family;\n        }\n\n        public String getQualifier() {\n            return qualifier;\n        }\n\n        public void setQualifier(String qualifier) {\n            this.qualifier = qualifier;\n        }\n\n        public String getType() {\n            return type;\n        }\n\n        public void setType(String type) {\n            this.type = type;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (o == null || getClass() != o.getClass()) return false;\n            ColumnItem that = (ColumnItem) o;\n            return Objects.equals(column, that.column);\n        }\n\n        @Override\n        public int hashCode() {\n\n            return Objects.hash(column);\n        }\n    }\n\n    public enum Mode {\n                      STRING(\"STRING\"), NATIVE(\"NATIVE\"), PHOENIX(\"PHOENIX\");\n\n        private String type;\n\n        public String getType() {\n            return type;\n        }\n\n        Mode(String type){\n            this.type = type;\n        }\n    }\n\n    public static class HbaseMapping implements AdapterMapping {\n\n        private Mode                    mode               = Mode.STRING;           // hbase默认转换格式\n        private String                  database;                                   // 数据库名或schema名\n        private String                  table;                                      // 表面名\n        private String                  hbaseTable;                                 // hbase表名\n        private String                  family             = \"CF\";                  // 默认统一column family\n        private boolean                 uppercaseQualifier = true;                  // 是否转大写\n        private boolean                 autoCreateTable    = false;                 // 同步时HBase中表不存在的情况下自动建表\n        private String                  rowKey;                                     // 指定复合主键为rowKey\n        private Map<String, String>     columns;                                    // 字段映射\n        private List<String>            excludeColumns;                             // 不映射的字段\n        private ColumnItem              rowKeyColumn;                               // rowKey字段\n        private String                  etlCondition;                               // etl条件sql\n\n        private Map<String, ColumnItem> columnItems        = new LinkedHashMap<>(); // 转换后的字段映射列表\n        private Set<String>             families           = new LinkedHashSet<>(); // column family列表\n        private int                     readBatch          = 5000;\n        private int                     commitBatch        = 5000;                  // etl等批量提交大小\n\n        public Mode getMode() {\n            return mode;\n        }\n\n        public void setMode(Mode mode) {\n            this.mode = mode;\n        }\n\n        public String getDatabase() {\n            return database;\n        }\n\n        public void setDatabase(String database) {\n            this.database = database;\n        }\n\n        public String getTable() {\n            return table;\n        }\n\n        public void setTable(String table) {\n            this.table = table;\n        }\n\n        public String getHbaseTable() {\n            return hbaseTable;\n        }\n\n        public void setHbaseTable(String hbaseTable) {\n            this.hbaseTable = hbaseTable;\n        }\n\n        public Map<String, String> getColumns() {\n            return columns;\n        }\n\n        public boolean isAutoCreateTable() {\n            return autoCreateTable;\n        }\n\n        public void setAutoCreateTable(boolean autoCreateTable) {\n            this.autoCreateTable = autoCreateTable;\n        }\n\n        public int getReadBatch() {\n            return readBatch;\n        }\n\n        public void setReadBatch(int readBatch) {\n            this.readBatch = readBatch;\n        }\n\n        public int getCommitBatch() {\n            return commitBatch;\n        }\n\n        public void setCommitBatch(int commitBatch) {\n            this.commitBatch = commitBatch;\n        }\n\n        public String getRowKey() {\n            return rowKey;\n        }\n\n        public void setRowKey(String rowKey) {\n            this.rowKey = rowKey;\n        }\n\n        public String getEtlCondition() {\n            return etlCondition;\n        }\n\n        public void setEtlCondition(String etlCondition) {\n            this.etlCondition = etlCondition;\n        }\n\n        public void setColumns(Map<String, String> columns) {\n            this.columns = columns;\n\n            if (columns != null) {\n                for (Map.Entry<String, String> columnField : columns.entrySet()) {\n                    String field = columnField.getValue();\n                    String type = null;\n                    if (field != null) {\n                        // 解析类型\n                        int i = field.indexOf(\"$\");\n                        if (i > -1) {\n                            type = field.substring(i + 1);\n                            field = field.substring(0, i);\n                        }\n                    }\n                    ColumnItem columnItem = new ColumnItem();\n                    columnItem.setColumn(columnField.getKey());\n                    columnItem.setType(type);\n                    if (field != null && field.toUpperCase().startsWith(\"ROWKEY\")) {\n                        int idx = field.toUpperCase().indexOf(\"LEN:\");\n                        if (idx > -1) {\n                            String len = field.substring(idx + 4);\n                            try {\n                                columnItem.setRowKeyLen(Integer.parseInt(len));\n                            } catch (Exception e) {\n                                // ignore\n                            }\n                        }\n                        columnItem.setRowKey(true);\n                        rowKeyColumn = columnItem;\n                    } else {\n                        if (field == null || field.equals(\"\")) {\n                            columnItem.setFamily(family);\n                            columnItem.setQualifier(columnField.getKey());\n                        } else {\n                            int len = field.indexOf(\":\");\n                            if (len > -1) {\n                                columnItem.setFamily(field.substring(0, len));\n                                columnItem.setQualifier(field.substring(len + 1));\n                            } else {\n                                columnItem.setFamily(family);\n                                columnItem.setQualifier(field);\n                            }\n                        }\n                        if (uppercaseQualifier) {\n                            columnItem.setQualifier(columnItem.getQualifier().toUpperCase());\n                        }\n                        families.add(columnItem.getFamily());\n                    }\n\n                    columnItems.put(columnField.getKey(), columnItem);\n                }\n            } else {\n                this.columns = new LinkedHashMap<>();\n            }\n        }\n\n        public List<String> getExcludeColumns() {\n            return excludeColumns;\n        }\n\n        public void setExcludeColumns(List<String> excludeColumns) {\n            this.excludeColumns = excludeColumns;\n        }\n\n        public String getFamily() {\n            return family;\n        }\n\n        public void setFamily(String family) {\n            this.family = family;\n            if (family == null) {\n                this.family = \"CF\";\n            }\n        }\n\n        public boolean isUppercaseQualifier() {\n            return uppercaseQualifier;\n        }\n\n        public void setUppercaseQualifier(boolean uppercaseQualifier) {\n            this.uppercaseQualifier = uppercaseQualifier;\n        }\n\n        public ColumnItem getRowKeyColumn() {\n            return rowKeyColumn;\n        }\n\n        public void setRowKeyColumn(ColumnItem rowKeyColumn) {\n            this.rowKeyColumn = rowKeyColumn;\n        }\n\n        public Map<String, ColumnItem> getColumnItems() {\n            return columnItems;\n        }\n\n        public void setColumnItems(Map<String, ColumnItem> columnItems) {\n            this.columnItems = columnItems;\n        }\n\n        public Set<String> getFamilies() {\n            return families;\n        }\n\n        public void setFamilies(Set<String> families) {\n            this.families = families;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (o == null || getClass() != o.getClass()) return false;\n\n            HbaseMapping hbaseMapping = (HbaseMapping) o;\n\n            if (table != null ? !table.equals(hbaseMapping.table) : hbaseMapping.table != null) return false;\n            return hbaseTable != null ? hbaseTable.equals(hbaseMapping.hbaseTable) : hbaseMapping.hbaseTable == null;\n        }\n\n        @Override\n        public int hashCode() {\n            int result = table != null ? table.hashCode() : 0;\n            result = 31 * result + (hbaseTable != null ? hbaseTable.hashCode() : 0);\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/hbase/src/main/java/com/alibaba/otter/canal/client/adapter/hbase/config/MappingConfigLoader.java",
    "content": "package com.alibaba.otter.canal.client.adapter.hbase.config;\n\nimport com.alibaba.otter.canal.client.adapter.support.YamlUtils;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.client.adapter.support.MappingConfigsLoader;\n\n/**\n * HBase表映射配置加载器\n *\n * @author rewerma 2018-8-21 下午06:45:49\n * @version 1.0.0\n */\npublic class MappingConfigLoader {\n\n    private static Logger logger = LoggerFactory.getLogger(MappingConfigLoader.class);\n\n    /**\n     * 加载HBase表映射配置\n     *\n     * @return 配置名/配置文件名--对象\n     */\n    public static Map<String, MappingConfig> load(Properties envProperties) {\n        logger.info(\"## Start loading hbase mapping config ... \");\n\n        Map<String, MappingConfig> result = new LinkedHashMap<>();\n\n        Map<String, String> configContentMap = MappingConfigsLoader.loadConfigs(\"hbase\");\n        configContentMap.forEach((fileName, content) -> {\n            MappingConfig config = YamlUtils.ymlToObj(null, content, MappingConfig.class, null, envProperties);\n            if (config == null) {\n                return;\n            }\n            try {\n                config.validate();\n            } catch (Exception e) {\n                throw new RuntimeException(\"ERROR load Config: \" + fileName + \" \" + e.getMessage(), e);\n            }\n            result.put(fileName, config);\n        });\n\n        logger.info(\"## Hbase mapping config loaded\");\n        return result;\n    }\n}\n"
  },
  {
    "path": "client-adapter/hbase/src/main/java/com/alibaba/otter/canal/client/adapter/hbase/monitor/HbaseConfigMonitor.java",
    "content": "package com.alibaba.otter.canal.client.adapter.hbase.monitor;\n\nimport com.alibaba.otter.canal.client.adapter.hbase.HbaseAdapter;\nimport com.alibaba.otter.canal.client.adapter.hbase.config.MappingConfig;\nimport com.alibaba.otter.canal.client.adapter.support.MappingConfigsLoader;\nimport com.alibaba.otter.canal.client.adapter.support.Util;\nimport com.alibaba.otter.canal.client.adapter.support.YamlUtils;\nimport java.io.File;\nimport java.util.Properties;\nimport org.apache.commons.io.filefilter.FileFilterUtils;\nimport org.apache.commons.io.monitor.FileAlterationListenerAdaptor;\nimport org.apache.commons.io.monitor.FileAlterationMonitor;\nimport org.apache.commons.io.monitor.FileAlterationObserver;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class HbaseConfigMonitor {\n\n    private static final Logger   logger      = LoggerFactory.getLogger(HbaseConfigMonitor.class);\n\n    private static final String   adapterName = \"hbase\";\n\n    private HbaseAdapter          hbaseAdapter;\n\n    private Properties            envProperties;\n\n    private FileAlterationMonitor fileMonitor;\n\n    public void init(HbaseAdapter hbaseAdapter, Properties envProperties) {\n        this.hbaseAdapter = hbaseAdapter;\n        this.envProperties = envProperties;\n        File confDir = Util.getConfDirPath(adapterName);\n        try {\n            FileAlterationObserver observer = new FileAlterationObserver(confDir,\n                    FileFilterUtils.and(FileFilterUtils.fileFileFilter(), FileFilterUtils.suffixFileFilter(\"yml\")));\n            FileListener listener = new FileListener();\n            observer.addListener(listener);\n            fileMonitor = new FileAlterationMonitor(3000, observer);\n            fileMonitor.start();\n\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n        }\n    }\n\n    public void destroy() {\n        try {\n            fileMonitor.stop();\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n        }\n    }\n\n    private class FileListener extends FileAlterationListenerAdaptor {\n\n        @Override\n        public void onFileCreate(File file) {\n            super.onFileCreate(file);\n            try {\n                // 加载新增的配置文件\n                String configContent = MappingConfigsLoader.loadConfig(adapterName + File.separator + file.getName());\n                MappingConfig config = YamlUtils.ymlToObj(null, configContent, MappingConfig.class, null, envProperties);\n                if (config == null) {\n                    return;\n                }\n                config.validate();\n                boolean result = hbaseAdapter.addConfig(file.getName(), config);\n                if (result) {\n                    logger.info(\"Add a new hbase mapping config: {} to canal adapter\",\n                            file.getName());\n                }\n            } catch (Exception e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n\n        @Override\n        public void onFileChange(File file) {\n            super.onFileChange(file);\n\n            try {\n                if (hbaseAdapter.getHbaseMapping().containsKey(file.getName())) {\n                    // 加载配置文件\n                    String configContent = MappingConfigsLoader\n                        .loadConfig(adapterName + File.separator + file.getName());\n                    if (configContent == null) {\n                        onFileDelete(file);\n                        return;\n                    }\n                    MappingConfig config = YamlUtils.ymlToObj(null, configContent, MappingConfig.class, null, envProperties);\n                    if (config == null) {\n                        return;\n                    }\n                    config.validate();\n                    hbaseAdapter.updateConfig(file.getName(), config);\n                }\n            } catch (Exception e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n\n        @Override\n        public void onFileDelete(File file) {\n            super.onFileDelete(file);\n\n            try {\n                if (hbaseAdapter.getHbaseMapping().containsKey(file.getName())) {\n                    hbaseAdapter.deleteConfig(file.getName());\n                    logger.info(\"Delete a hbase mapping config: {} of canal adapter\", file.getName());\n                }\n            } catch (Exception e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/hbase/src/main/java/com/alibaba/otter/canal/client/adapter/hbase/service/HbaseEtlService.java",
    "content": "package com.alibaba.otter.canal.client.adapter.hbase.service;\n\nimport java.sql.Timestamp;\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport javax.sql.DataSource;\n\nimport org.apache.hadoop.hbase.util.Bytes;\n\nimport com.alibaba.otter.canal.client.adapter.hbase.config.MappingConfig;\nimport com.alibaba.otter.canal.client.adapter.hbase.support.HRow;\nimport com.alibaba.otter.canal.client.adapter.hbase.support.HbaseTemplate;\nimport com.alibaba.otter.canal.client.adapter.hbase.support.PhType;\nimport com.alibaba.otter.canal.client.adapter.hbase.support.PhTypeUtil;\nimport com.alibaba.otter.canal.client.adapter.hbase.support.Type;\nimport com.alibaba.otter.canal.client.adapter.hbase.support.TypeUtil;\nimport com.alibaba.otter.canal.client.adapter.support.AbstractEtlService;\nimport com.alibaba.otter.canal.client.adapter.support.AdapterConfig;\nimport com.alibaba.otter.canal.client.adapter.support.EtlResult;\nimport com.alibaba.otter.canal.client.adapter.support.JdbcTypeUtil;\nimport com.alibaba.otter.canal.client.adapter.support.Util;\nimport com.google.common.base.Joiner;\n\n/**\n * HBase ETL 操作业务类\n *\n * @author rewerma @ 2018-10-20\n * @version 1.0.0\n */\npublic class HbaseEtlService extends AbstractEtlService {\n\n    private HbaseTemplate hbaseTemplate;\n    private MappingConfig config;\n\n    public HbaseEtlService(HbaseTemplate hbaseTemplate, MappingConfig config){\n        super(\"HBase\", config);\n        this.hbaseTemplate = hbaseTemplate;\n        this.config = config;\n    }\n\n    /**\n     * 建表\n     */\n    private void createTable() {\n        try {\n            // 判断hbase表是否存在，不存在则建表\n            MappingConfig.HbaseMapping hbaseMapping = config.getHbaseMapping();\n            if (!hbaseTemplate.tableExists(hbaseMapping.getHbaseTable())) {\n                hbaseTemplate.createTable(hbaseMapping.getHbaseTable(), hbaseMapping.getFamily());\n            }\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * 导入数据\n     *\n     * @param params 筛选条件\n     * @return 导入结果\n     */\n    public EtlResult importData(List<String> params) {\n        EtlResult etlResult = new EtlResult();\n        List<String> errMsg = new ArrayList<>();\n        try {\n            MappingConfig.HbaseMapping hbaseMapping = config.getHbaseMapping();\n\n            if (params != null && params.size() == 1 && \"rebuild\".equalsIgnoreCase(params.get(0))) {\n                logger.info(hbaseMapping.getHbaseTable() + \" rebuild is starting!\");\n                // 如果表存在则删除\n                if (hbaseTemplate.tableExists(hbaseMapping.getHbaseTable())) {\n                    hbaseTemplate.disableTable(hbaseMapping.getHbaseTable());\n                    hbaseTemplate.deleteTable(hbaseMapping.getHbaseTable());\n                }\n                params = null;\n            } else {\n                logger.info(hbaseMapping.getHbaseTable() + \" etl is starting!\");\n            }\n            createTable();\n\n            // 拼接sql\n            String sql = \"SELECT * FROM `\" + config.getHbaseMapping().getDatabase() + \"`.`\" + hbaseMapping.getTable()\n                         + \"`\";\n\n            return super.importData(sql, params);\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n            errMsg.add(\"HBase etl error ==>\" + e.getMessage());\n        }\n        etlResult.setErrorMessage(Joiner.on(\"\\n\").join(errMsg));\n        return etlResult;\n    }\n\n    /**\n     * 执行导入\n     */\n    protected boolean executeSqlImport(DataSource ds, String sql, List<Object> values,\n                                       AdapterConfig.AdapterMapping mapping, AtomicLong impCount, List<String> errMsg) {\n        MappingConfig.HbaseMapping hbaseMapping = (MappingConfig.HbaseMapping) mapping;\n        try {\n            Util.sqlRS(ds, sql, values, rs -> {\n                int i = 1;\n\n                try {\n                    boolean complete = false;\n                    List<HRow> rows = new ArrayList<>();\n                    String[] rowKeyColumns = null;\n                    if (hbaseMapping.getRowKey() != null) {\n                        rowKeyColumns = hbaseMapping.getRowKey().trim().split(\",\");\n                    }\n                    while (rs.next()) {\n                        int cc = rs.getMetaData().getColumnCount();\n                        int[] jdbcTypes = new int[cc];\n                        Class<?>[] classes = new Class[cc];\n                        for (int j = 1; j <= cc; j++) {\n                            int jdbcType = rs.getMetaData().getColumnType(j);\n                            jdbcTypes[j - 1] = jdbcType;\n                            classes[j - 1] = JdbcTypeUtil.jdbcType2javaType(jdbcType);\n                        }\n                        HRow row = new HRow();\n\n                        if (rowKeyColumns != null) {\n                            // 取rowKey字段拼接\n                StringBuilder rowKeyVale = new StringBuilder();\n                for (String rowKeyColumnName : rowKeyColumns) {\n                    Object obj = rs.getObject(rowKeyColumnName);\n                    if (obj != null) {\n                        rowKeyVale.append(obj.toString());\n                    }\n                    rowKeyVale.append(\"|\");\n                }\n                int len = rowKeyVale.length();\n                if (len > 0) {\n                    rowKeyVale.delete(len - 1, len);\n                }\n                row.setRowKey(Bytes.toBytes(rowKeyVale.toString()));\n            }\n\n            for (int j = 1; j <= cc; j++) {\n                String columnName = rs.getMetaData().getColumnName(j);\n\n                Object val = JdbcTypeUtil.getRSData(rs, columnName, jdbcTypes[j - 1]);\n                if (val == null) {\n                    continue;\n                }\n\n                MappingConfig.ColumnItem columnItem = hbaseMapping.getColumnItems().get(columnName);\n                // 没有配置映射\n                if (columnItem == null) {\n                    String family = hbaseMapping.getFamily();\n                    String qualifile = columnName;\n                    if (hbaseMapping.isUppercaseQualifier()) {\n                        qualifile = qualifile.toUpperCase();\n                    }\n                    if (MappingConfig.Mode.STRING == hbaseMapping.getMode()) {\n                        if (hbaseMapping.getRowKey() == null && j == 1) {\n                            row.setRowKey(Bytes.toBytes(val.toString()));\n                        } else {\n                            row.addCell(family, qualifile, Bytes.toBytes(val.toString()));\n                        }\n                    } else if (MappingConfig.Mode.NATIVE == hbaseMapping.getMode()) {\n                        Type type = Type.getType(classes[j - 1]);\n                        if (hbaseMapping.getRowKey() == null && j == 1) {\n                            row.setRowKey(TypeUtil.toBytes(val, type));\n                        } else {\n                            row.addCell(family, qualifile, TypeUtil.toBytes(val, type));\n                        }\n                    } else if (MappingConfig.Mode.PHOENIX == hbaseMapping.getMode()) {\n                        PhType phType = PhType.getType(classes[j - 1]);\n                        if (hbaseMapping.getRowKey() == null && j == 1) {\n                            row.setRowKey(PhTypeUtil.toBytes(val, phType));\n                        } else {\n                            row.addCell(family, qualifile, PhTypeUtil.toBytes(val, phType));\n                        }\n                    }\n                } else {\n                    // 如果不需要类型转换\n                    if (columnItem.getType() == null || \"\".equals(columnItem.getType())) {\n                        if (val instanceof java.sql.Date) {\n                            SimpleDateFormat dateFmt = new SimpleDateFormat(\"yyyy-MM-dd\");\n                            val = dateFmt.format((Date) val);\n                        } else if (val instanceof Timestamp) {\n                            SimpleDateFormat datetimeFmt = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n                            val = datetimeFmt.format((Date) val);\n                        }\n\n                        byte[] valBytes = Bytes.toBytes(val.toString());\n                        if (columnItem.isRowKey()) {\n                            if (columnItem.getRowKeyLen() != null) {\n                                valBytes = Bytes.toBytes(limitLenNum(columnItem.getRowKeyLen(), val));\n                                row.setRowKey(valBytes);\n                            } else {\n                                row.setRowKey(valBytes);\n                            }\n                        } else {\n                            row.addCell(columnItem.getFamily(), columnItem.getQualifier(), valBytes);\n                        }\n                    } else {\n                        if (MappingConfig.Mode.STRING == hbaseMapping.getMode()) {\n                            byte[] valBytes = Bytes.toBytes(val.toString());\n                            if (columnItem.isRowKey()) {\n                                if (columnItem.getRowKeyLen() != null) {\n                                    valBytes = Bytes.toBytes(limitLenNum(columnItem.getRowKeyLen(), val));\n                                }\n                                row.setRowKey(valBytes);\n                            } else {\n                                row.addCell(columnItem.getFamily(), columnItem.getQualifier(), valBytes);\n                            }\n                        } else if (MappingConfig.Mode.NATIVE == hbaseMapping.getMode()) {\n                            Type type = Type.getType(columnItem.getType());\n                            if (columnItem.isRowKey()) {\n                                if (columnItem.getRowKeyLen() != null) {\n                                    String v = limitLenNum(columnItem.getRowKeyLen(), val);\n                                    row.setRowKey(Bytes.toBytes(v));\n                                } else {\n                                    row.setRowKey(TypeUtil.toBytes(val, type));\n                                }\n                            } else {\n                                row.addCell(columnItem.getFamily(),\n                                    columnItem.getQualifier(),\n                                    TypeUtil.toBytes(val, type));\n                            }\n                        } else if (MappingConfig.Mode.PHOENIX == hbaseMapping.getMode()) {\n                            PhType phType = PhType.getType(columnItem.getType());\n                            if (columnItem.isRowKey()) {\n                                row.setRowKey(PhTypeUtil.toBytes(val, phType));\n                            } else {\n                                row.addCell(columnItem.getFamily(),\n                                    columnItem.getQualifier(),\n                                    PhTypeUtil.toBytes(val, phType));\n                            }\n                        }\n                    }\n                }\n            }\n\n            if (row.getRowKey() == null) throw new RuntimeException(\"RowKey 值为空\");\n\n            rows.add(row);\n            complete = false;\n            if (i % hbaseMapping.getCommitBatch() == 0 && !rows.isEmpty()) {\n                hbaseTemplate.puts(hbaseMapping.getHbaseTable(), rows);\n                rows.clear();\n                complete = true;\n            }\n            i++;\n            impCount.incrementAndGet();\n            if (logger.isDebugEnabled()) {\n                logger.debug(\"successful import count:\" + impCount.get());\n            }\n        }\n\n        if (!complete && !rows.isEmpty()) {\n            hbaseTemplate.puts(hbaseMapping.getHbaseTable(), rows);\n        }\n\n    } catch (Exception e) {\n        logger.error(hbaseMapping.getHbaseTable() + \" etl failed! ==>\" + e.getMessage(), e);\n        errMsg.add(hbaseMapping.getHbaseTable() + \" etl failed! ==>\" + e.getMessage());\n        // throw new RuntimeException(e);\n    }\n    return i;\n}           );\n            return true;\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n            return false;\n        }\n    }\n\n    private static String limitLenNum(int len, Object val) {\n        if (val == null) {\n            return null;\n        }\n        if (val instanceof Number) {\n            return String.format(\"%0\" + len + \"d\", (Number) ((Number) val).longValue());\n        } else if (val instanceof String) {\n            return String.format(\"%0\" + len + \"d\", Long.parseLong((String) val));\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "client-adapter/hbase/src/main/java/com/alibaba/otter/canal/client/adapter/hbase/service/HbaseSyncService.java",
    "content": "package com.alibaba.otter.canal.client.adapter.hbase.service;\n\nimport java.util.*;\n\nimport org.apache.hadoop.hbase.util.Bytes;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.JSONWriter.Feature;\nimport com.alibaba.otter.canal.client.adapter.hbase.config.MappingConfig;\nimport com.alibaba.otter.canal.client.adapter.hbase.support.*;\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\n\n/**\n * HBase同步操作业务\n *\n * @author rewerma 2018-8-21 下午06:45:49\n * @version 1.0.0\n */\npublic class HbaseSyncService {\n\n    private static Logger logger = LoggerFactory.getLogger(HbaseSyncService.class);\n\n    private HbaseTemplate hbaseTemplate;                                           // HBase操作模板\n\n    public HbaseSyncService(HbaseTemplate hbaseTemplate){\n        this.hbaseTemplate = hbaseTemplate;\n    }\n\n    public void sync(MappingConfig config, Dml dml) {\n        if (config != null) {\n            String type = dml.getType();\n            if (type != null && type.equalsIgnoreCase(\"INSERT\")) {\n                insert(config, dml);\n            } else if (type != null && type.equalsIgnoreCase(\"UPDATE\")) {\n                update(config, dml);\n            } else if (type != null && type.equalsIgnoreCase(\"DELETE\")) {\n                delete(config, dml);\n            }\n            if (logger.isDebugEnabled()) {\n                logger.debug(\"DML: {}\", JSON.toJSONString(dml, Feature.WriteNulls));\n            }\n        }\n    }\n\n    /**\n     * 插入操作\n     *\n     * @param config 配置项\n     * @param dml DML数据\n     */\n    private void insert(MappingConfig config, Dml dml) {\n        List<Map<String, Object>> data = dml.getData();\n        if (data == null || data.isEmpty()) {\n            return;\n        }\n\n        MappingConfig.HbaseMapping hbaseMapping = config.getHbaseMapping();\n\n        // if (!validHTable(config)) {\n        // logger.error(\"HBase table '{}' not exists\",\n        // hbaseMapping.getHbaseTable());\n        // return;\n        // }\n        int i = 1;\n        boolean complete = false;\n        List<HRow> rows = new ArrayList<>();\n        for (Map<String, Object> r : data) {\n            HRow hRow = new HRow();\n\n            // 拼接复合rowKey\n            if (hbaseMapping.getRowKey() != null) {\n                String[] rowKeyColumns = hbaseMapping.getRowKey().trim().split(\",\");\n                String rowKeyVale = getRowKeys(rowKeyColumns, r);\n                // params.put(\"rowKey\", Bytes.toBytes(rowKeyVale));\n                hRow.setRowKey(Bytes.toBytes(rowKeyVale));\n            }\n\n            convertData2Row(hbaseMapping, hRow, r);\n            if (hRow.getRowKey() == null) {\n                throw new RuntimeException(\"empty rowKey\");\n            }\n            rows.add(hRow);\n            complete = false;\n            if (i % config.getHbaseMapping().getCommitBatch() == 0 && !rows.isEmpty()) {\n                hbaseTemplate.puts(hbaseMapping.getHbaseTable(), rows);\n                rows.clear();\n                complete = true;\n            }\n            i++;\n        }\n        if (!complete && !rows.isEmpty()) {\n            hbaseTemplate.puts(hbaseMapping.getHbaseTable(), rows);\n        }\n\n    }\n\n    /**\n     * 将Map数据转换为HRow行数据\n     *\n     * @param hbaseMapping hbase映射配置\n     * @param hRow 行对象\n     * @param data Map数据\n     */\n    private static void convertData2Row(MappingConfig.HbaseMapping hbaseMapping, HRow hRow, Map<String, Object> data) {\n        Map<String, MappingConfig.ColumnItem> columnItems = hbaseMapping.getColumnItems();\n        int i = 0;\n        for (Map.Entry<String, Object> entry : data.entrySet()) {\n            if (hbaseMapping.getExcludeColumns() != null && hbaseMapping.getExcludeColumns().contains(entry.getKey())) {\n                continue;\n            }\n            if (entry.getValue() != null) {\n                MappingConfig.ColumnItem columnItem = columnItems.get(entry.getKey());\n\n                byte[] bytes = typeConvert(columnItem, hbaseMapping, entry.getValue());\n\n                if (columnItem == null) {\n                    String familyName = hbaseMapping.getFamily();\n                    String qualifier = entry.getKey();\n                    if (hbaseMapping.isUppercaseQualifier()) {\n                        qualifier = qualifier.toUpperCase();\n                    }\n\n                    if (hbaseMapping.getRowKey() == null && i == 0) {\n                        hRow.setRowKey(bytes);\n                    } else {\n                        hRow.addCell(familyName, qualifier, bytes);\n                    }\n                } else {\n                    if (columnItem.isRowKey()) {\n                        if (columnItem.getRowKeyLen() != null && entry.getValue() != null) {\n                            if (entry.getValue() instanceof Number) {\n                                String v = String.format(\"%0\" + columnItem.getRowKeyLen() + \"d\",\n                                    ((Number) entry.getValue()).longValue());\n                                bytes = Bytes.toBytes(v);\n                            } else {\n                                try {\n                                    String v = String.format(\"%0\" + columnItem.getRowKeyLen() + \"d\",\n                                        Integer.parseInt((String) entry.getValue()));\n                                    bytes = Bytes.toBytes(v);\n                                } catch (Exception e) {\n                                    logger.error(e.getMessage(), e);\n                                }\n                            }\n                        }\n                        hRow.setRowKey(bytes);\n                    } else {\n                        hRow.addCell(columnItem.getFamily(), columnItem.getQualifier(), bytes);\n                    }\n                }\n            }\n            i++;\n        }\n    }\n\n    /**\n     * 更新操作\n     *\n     * @param config 配置对象\n     * @param dml dml对象\n     */\n    private void update(MappingConfig config, Dml dml) {\n        List<Map<String, Object>> data = dml.getData();\n        List<Map<String, Object>> old = dml.getOld();\n        if (old == null || old.isEmpty() || data == null || data.isEmpty()) {\n            return;\n        }\n\n        MappingConfig.HbaseMapping hbaseMapping = config.getHbaseMapping();\n\n        // if (!validHTable(config)) {\n        // logger.error(\"HBase table '{}' not exists\",\n        // hbaseMapping.getHbaseTable());\n        // return;\n        // }\n\n        MappingConfig.ColumnItem rowKeyColumn = hbaseMapping.getRowKeyColumn();\n        int index = 0;\n        int i = 1;\n        boolean complete = false;\n        List<HRow> rows = new ArrayList<>();\n        out: for (Map<String, Object> r : data) {\n            byte[] rowKeyBytes;\n\n            if (hbaseMapping.getRowKey() != null) {\n                String[] rowKeyColumns = hbaseMapping.getRowKey().trim().split(\",\");\n\n                // 判断是否有复合主键修改\n                for (String updateColumn : old.get(index).keySet()) {\n                    for (String rowKeyColumnName : rowKeyColumns) {\n                        if (rowKeyColumnName.equalsIgnoreCase(updateColumn)) {\n                            // 调用删除插入操作\n                            deleteAndInsert(config, dml);\n                            continue out;\n                        }\n                    }\n                }\n\n                String rowKeyVale = getRowKeys(rowKeyColumns, r);\n                rowKeyBytes = Bytes.toBytes(rowKeyVale);\n            } else if (rowKeyColumn == null) {\n                rowKeyBytes = typeConvert(null, hbaseMapping, r.values().iterator().next());\n            } else {\n                rowKeyBytes = getRowKeyBytes(hbaseMapping, rowKeyColumn, r);\n            }\n            if (rowKeyBytes == null) throw new RuntimeException(\"rowKey值为空\");\n\n            Map<String, MappingConfig.ColumnItem> columnItems = hbaseMapping.getColumnItems();\n            HRow hRow = new HRow(rowKeyBytes);\n            for (String updateColumn : old.get(index).keySet()) {\n                if (hbaseMapping.getExcludeColumns() != null\n                    && hbaseMapping.getExcludeColumns().contains(updateColumn)) {\n                    continue;\n                }\n                MappingConfig.ColumnItem columnItem = columnItems.get(updateColumn);\n                if (columnItem == null) {\n                    String family = hbaseMapping.getFamily();\n                    String qualifier = updateColumn;\n                    if (hbaseMapping.isUppercaseQualifier()) {\n                        qualifier = qualifier.toUpperCase();\n                    }\n\n                    Object newVal = r.get(updateColumn);\n\n                    if (newVal == null) {\n                        hRow.addCell(family, qualifier, null);\n                    } else {\n                        hRow.addCell(family, qualifier, typeConvert(null, hbaseMapping, newVal));\n                    }\n                } else {\n                    // 排除修改id的情况\n                    if (columnItem.isRowKey()) continue;\n\n                    Object newVal = r.get(updateColumn);\n                    if (newVal == null) {\n                        hRow.addCell(columnItem.getFamily(), columnItem.getQualifier(), null);\n                    } else {\n                        hRow.addCell(columnItem.getFamily(),\n                            columnItem.getQualifier(),\n                            typeConvert(columnItem, hbaseMapping, newVal));\n                    }\n                }\n            }\n            rows.add(hRow);\n            complete = false;\n            if (i % config.getHbaseMapping().getCommitBatch() == 0 && !rows.isEmpty()) {\n                hbaseTemplate.puts(hbaseMapping.getHbaseTable(), rows);\n                rows.clear();\n                complete = true;\n            }\n            i++;\n            index++;\n        }\n        if (!complete && !rows.isEmpty()) {\n            hbaseTemplate.puts(hbaseMapping.getHbaseTable(), rows);\n        }\n    }\n\n    private void delete(MappingConfig config, Dml dml) {\n        List<Map<String, Object>> data = dml.getData();\n        if (data == null || data.isEmpty()) {\n            return;\n        }\n\n        MappingConfig.HbaseMapping hbaseMapping = config.getHbaseMapping();\n\n        // if (!validHTable(config)) {\n        // logger.error(\"HBase table '{}' not exists\",\n        // hbaseMapping.getHbaseTable());\n        // return;\n        // }\n\n        MappingConfig.ColumnItem rowKeyColumn = hbaseMapping.getRowKeyColumn();\n        boolean complete = false;\n        int i = 1;\n        Set<byte[]> rowKeys = new HashSet<>();\n        for (Map<String, Object> r : data) {\n            byte[] rowKeyBytes;\n\n            if (hbaseMapping.getRowKey() != null) {\n                String[] rowKeyColumns = hbaseMapping.getRowKey().trim().split(\",\");\n                String rowKeyVale = getRowKeys(rowKeyColumns, r);\n                rowKeyBytes = Bytes.toBytes(rowKeyVale);\n            } else if (rowKeyColumn == null) {\n                // 如果不需要类型转换\n                rowKeyBytes = typeConvert(null, hbaseMapping, r.values().iterator().next());\n            } else {\n                rowKeyBytes = getRowKeyBytes(hbaseMapping, rowKeyColumn, r);\n            }\n            if (rowKeyBytes == null) throw new RuntimeException(\"rowKey值为空\");\n            rowKeys.add(rowKeyBytes);\n            complete = false;\n            if (i % config.getHbaseMapping().getCommitBatch() == 0 && !rowKeys.isEmpty()) {\n                hbaseTemplate.deletes(hbaseMapping.getHbaseTable(), rowKeys);\n                rowKeys.clear();\n                complete = true;\n            }\n            i++;\n        }\n        if (!complete && !rowKeys.isEmpty()) {\n            hbaseTemplate.deletes(hbaseMapping.getHbaseTable(), rowKeys);\n        }\n    }\n\n    private void deleteAndInsert(MappingConfig config, Dml dml) {\n        List<Map<String, Object>> data = dml.getData();\n        List<Map<String, Object>> old = dml.getOld();\n        if (old == null || old.isEmpty() || data == null || data.isEmpty()) {\n            return;\n        }\n        MappingConfig.HbaseMapping hbaseMapping = config.getHbaseMapping();\n\n        String[] rowKeyColumns = hbaseMapping.getRowKey().trim().split(\",\");\n\n        int index = 0;\n        int i = 1;\n        boolean complete = false;\n        Set<byte[]> rowKeys = new HashSet<>();\n        List<HRow> rows = new ArrayList<>();\n        for (Map<String, Object> r : data) {\n            // 拼接老的rowKey\n            List<String> updateSubRowKey = new ArrayList<>();\n            for (String rowKeyColumnName : rowKeyColumns) {\n                for (String updateColumn : old.get(index).keySet()) {\n                    if (rowKeyColumnName.equalsIgnoreCase(updateColumn)) {\n                        updateSubRowKey.add(rowKeyColumnName);\n                    }\n                }\n            }\n            if (updateSubRowKey.isEmpty()) {\n                throw new RuntimeException(\"没有更新复合主键的RowKey\");\n            }\n            StringBuilder oldRowKey = new StringBuilder();\n            StringBuilder newRowKey = new StringBuilder();\n            for (String rowKeyColumnName : rowKeyColumns) {\n                newRowKey.append(r.get(rowKeyColumnName).toString()).append(\"|\");\n                if (!updateSubRowKey.contains(rowKeyColumnName)) {\n                    // 从data取\n                    oldRowKey.append(r.get(rowKeyColumnName).toString()).append(\"|\");\n                } else {\n                    // 从old取\n                    oldRowKey.append(old.get(index).get(rowKeyColumnName).toString()).append(\"|\");\n                }\n            }\n            int len = newRowKey.length();\n            newRowKey.delete(len - 1, len);\n            len = oldRowKey.length();\n            oldRowKey.delete(len - 1, len);\n            byte[] newRowKeyBytes = Bytes.toBytes(newRowKey.toString());\n            byte[] oldRowKeyBytes = Bytes.toBytes(oldRowKey.toString());\n\n            rowKeys.add(oldRowKeyBytes);\n            HRow row = new HRow(newRowKeyBytes);\n            convertData2Row(hbaseMapping, row, r);\n            rows.add(row);\n            complete = false;\n            if (i % config.getHbaseMapping().getCommitBatch() == 0 && !rows.isEmpty()) {\n                hbaseTemplate.deletes(hbaseMapping.getHbaseTable(), rowKeys);\n\n                hbaseTemplate.puts(hbaseMapping.getHbaseTable(), rows);\n                rowKeys.clear();\n                rows.clear();\n                complete = true;\n            }\n            i++;\n            index++;\n        }\n        if (!complete && !rows.isEmpty()) {\n            hbaseTemplate.deletes(hbaseMapping.getHbaseTable(), rowKeys);\n            hbaseTemplate.puts(hbaseMapping.getHbaseTable(), rows);\n        }\n    }\n\n    /**\n     * 根据对应的类型进行转换\n     *\n     * @param columnItem 列项配置\n     * @param hbaseMapping hbase映射配置\n     * @param value 值\n     * @return 复合字段rowKey\n     */\n    private static byte[] typeConvert(MappingConfig.ColumnItem columnItem, MappingConfig.HbaseMapping hbaseMapping,\n                                      Object value) {\n        if (value == null) {\n            return null;\n        }\n        byte[] bytes = null;\n        if (columnItem == null || columnItem.getType() == null || \"\".equals(columnItem.getType())) {\n            if (MappingConfig.Mode.STRING == hbaseMapping.getMode()) {\n                bytes = Bytes.toBytes(value.toString());\n            } else if (MappingConfig.Mode.NATIVE == hbaseMapping.getMode()) {\n                bytes = TypeUtil.toBytes(value);\n            } else if (MappingConfig.Mode.PHOENIX == hbaseMapping.getMode()) {\n                PhType phType = PhType.getType(value.getClass());\n                bytes = PhTypeUtil.toBytes(value, phType);\n            }\n        } else {\n            if (hbaseMapping.getMode() == MappingConfig.Mode.STRING) {\n                bytes = Bytes.toBytes(value.toString());\n            } else if (hbaseMapping.getMode() == MappingConfig.Mode.NATIVE) {\n                Type type = Type.getType(columnItem.getType());\n                bytes = TypeUtil.toBytes(value, type);\n            } else if (hbaseMapping.getMode() == MappingConfig.Mode.PHOENIX) {\n                PhType phType = PhType.getType(columnItem.getType());\n                bytes = PhTypeUtil.toBytes(value, phType);\n            }\n        }\n        return bytes;\n    }\n\n    /**\n     * 获取复合字段作为rowKey的拼接\n     *\n     * @param rowKeyColumns 复合rowK对应的字段\n     * @param data 数据\n     * @return\n     */\n    private static String getRowKeys(String[] rowKeyColumns, Map<String, Object> data) {\n        StringBuilder rowKeyValue = new StringBuilder();\n        for (String rowKeyColumnName : rowKeyColumns) {\n            Object obj = data.get(rowKeyColumnName);\n            if (obj != null) {\n                rowKeyValue.append(obj.toString());\n            }\n            rowKeyValue.append(\"|\");\n        }\n        int len = rowKeyValue.length();\n        if (len > 0) {\n            rowKeyValue.delete(len - 1, len);\n        }\n        return rowKeyValue.toString();\n    }\n\n    private static byte[] getRowKeyBytes(MappingConfig.HbaseMapping hbaseMapping, MappingConfig.ColumnItem rowKeyColumn,\n                                         Map<String, Object> rowData) {\n        Object val = rowData.get(rowKeyColumn.getColumn());\n        String v = null;\n        if (rowKeyColumn.getRowKeyLen() != null) {\n            if (val instanceof Number) {\n                v = String.format(\"%0\" + rowKeyColumn.getRowKeyLen() + \"d\", (Number) ((Number) val).longValue());\n            } else if (val instanceof String) {\n                v = String.format(\"%0\" + rowKeyColumn.getRowKeyLen() + \"d\", Long.parseLong((String) val));\n            }\n        }\n        if (v != null) {\n            return Bytes.toBytes(v);\n        } else {\n            return typeConvert(rowKeyColumn, hbaseMapping, val);\n        }\n    }\n\n}\n"
  },
  {
    "path": "client-adapter/hbase/src/main/java/com/alibaba/otter/canal/client/adapter/hbase/support/HRow.java",
    "content": "package com.alibaba.otter.canal.client.adapter.hbase.support;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * HBase操作对象类\n *\n * @author machengyuan 2018-8-21 下午10:12:34\n * @version 1.0.0\n */\npublic class HRow {\n\n    private byte[]      rowKey;\n    private List<HCell> cells = new ArrayList<>();\n\n    public HRow(){\n    }\n\n    public HRow(byte[] rowKey){\n        this.rowKey = rowKey;\n    }\n\n    public byte[] getRowKey() {\n        return rowKey;\n    }\n\n    public void setRowKey(byte[] rowKey) {\n        this.rowKey = rowKey;\n    }\n\n    public List<HCell> getCells() {\n        return cells;\n    }\n\n    public void setCells(List<HCell> cells) {\n        this.cells = cells;\n    }\n\n    public void addCell(String family, String qualifier, byte[] value) {\n        HCell hCell = new HCell(family, qualifier, value);\n        cells.add(hCell);\n    }\n\n    public static class HCell {\n\n        private String family;\n        private String qualifier;\n        private byte[] value;\n\n        public HCell(){\n        }\n\n        public HCell(String family, String qualifier, byte[] value){\n            this.family = family;\n            this.qualifier = qualifier;\n            this.value = value;\n        }\n\n        public String getFamily() {\n            return family;\n        }\n\n        public void setFamily(String family) {\n            this.family = family;\n        }\n\n        public String getQualifier() {\n            return qualifier;\n        }\n\n        public void setQualifier(String qualifier) {\n            this.qualifier = qualifier;\n        }\n\n        public byte[] getValue() {\n            return value;\n        }\n\n        public void setValue(byte[] value) {\n            this.value = value;\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/hbase/src/main/java/com/alibaba/otter/canal/client/adapter/hbase/support/HbaseTemplate.java",
    "content": "package com.alibaba.otter.canal.client.adapter.hbase.support;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.apache.hadoop.conf.Configuration;\nimport org.apache.hadoop.hbase.HColumnDescriptor;\nimport org.apache.hadoop.hbase.HTableDescriptor;\nimport org.apache.hadoop.hbase.TableName;\nimport org.apache.hadoop.hbase.client.Connection;\nimport org.apache.hadoop.hbase.client.ConnectionFactory;\nimport org.apache.hadoop.hbase.client.Delete;\nimport org.apache.hadoop.hbase.client.HBaseAdmin;\nimport org.apache.hadoop.hbase.client.HTable;\nimport org.apache.hadoop.hbase.client.Put;\nimport org.apache.hadoop.hbase.util.Bytes;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * HBase操作模板\n *\n * @author machengyuan 2018-8-21 下午10:12:34\n * @version 1.0.0\n */\npublic class HbaseTemplate {\n\n    private Logger        logger = LoggerFactory.getLogger(this.getClass());\n\n    private Configuration hbaseConfig;                                      // hbase配置对象\n    private Connection    conn;                                             // hbase连接\n\n    public HbaseTemplate(Configuration hbaseConfig){\n        this.hbaseConfig = hbaseConfig;\n        initConn();\n    }\n\n    private void initConn() {\n        try {\n            this.conn = ConnectionFactory.createConnection(hbaseConfig);\n        } catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public Connection getConnection() {\n        if (conn == null || conn.isAborted() || conn.isClosed()) {\n            initConn();\n        }\n        return conn;\n    }\n\n    public boolean tableExists(String tableName) {\n        try (HBaseAdmin admin = (HBaseAdmin) getConnection().getAdmin()) {\n\n            return admin.tableExists(TableName.valueOf(tableName));\n        } catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public void createTable(String tableName, String... familyNames) {\n        try (HBaseAdmin admin = (HBaseAdmin) getConnection().getAdmin()) {\n\n            HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(tableName));\n            // 添加列簇\n            if (familyNames != null) {\n                for (String familyName : familyNames) {\n                    HColumnDescriptor hcd = new HColumnDescriptor(familyName);\n                    desc.addFamily(hcd);\n                }\n            }\n            admin.createTable(desc);\n        } catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public void disableTable(String tableName) {\n        try (HBaseAdmin admin = (HBaseAdmin) getConnection().getAdmin()) {\n            admin.disableTable(tableName);\n        } catch (IOException e) {\n            logger.error(e.getMessage(), e);\n            throw new RuntimeException(e);\n        }\n    }\n\n    public void deleteTable(String tableName) {\n        try (HBaseAdmin admin = (HBaseAdmin) getConnection().getAdmin()) {\n            if (admin.isTableEnabled(tableName)) {\n                disableTable(tableName);\n            }\n            admin.deleteTable(tableName);\n        } catch (IOException e) {\n            logger.error(e.getMessage(), e);\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * 插入一行数据\n     *\n     * @param tableName 表名\n     * @param hRow 行数据对象\n     * @return 是否成功\n     */\n    public Boolean put(String tableName, HRow hRow) {\n        boolean flag = false;\n        try {\n            HTable table = (HTable) getConnection().getTable(TableName.valueOf(tableName));\n            Put put = new Put(hRow.getRowKey());\n            for (HRow.HCell hCell : hRow.getCells()) {\n                put.addColumn(Bytes.toBytes(hCell.getFamily()), Bytes.toBytes(hCell.getQualifier()), hCell.getValue());\n            }\n            table.put(put);\n            flag = true;\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n            throw new RuntimeException(e);\n        }\n        return flag;\n\n    }\n\n    /**\n     * 批量插入\n     *\n     * @param tableName 表名\n     * @param rows 行数据对象集合\n     * @return 是否成功\n     */\n    public Boolean puts(String tableName, List<HRow> rows) {\n        boolean flag = false;\n        try {\n            HTable table = (HTable) getConnection().getTable(TableName.valueOf(tableName));\n            List<Put> puts = new ArrayList<>();\n            for (HRow hRow : rows) {\n                Put put = new Put(hRow.getRowKey());\n                for (HRow.HCell hCell : hRow.getCells()) {\n                    put.addColumn(Bytes.toBytes(hCell.getFamily()),\n                        Bytes.toBytes(hCell.getQualifier()),\n                        hCell.getValue());\n                }\n                puts.add(put);\n            }\n            if (!puts.isEmpty()) {\n                table.put(puts);\n            }\n            flag = true;\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n            throw new RuntimeException(e);\n        }\n        return flag;\n    }\n\n    /**\n     * 批量删除数据\n     *\n     * @param tableName 表名\n     * @param rowKeys rowKey集合\n     * @return 是否成功\n     */\n    public Boolean deletes(String tableName, Set<byte[]> rowKeys) {\n        boolean flag = false;\n        try {\n            HTable table = (HTable) getConnection().getTable(TableName.valueOf(tableName));\n            List<Delete> deletes = new ArrayList<>();\n            for (byte[] rowKey : rowKeys) {\n                Delete delete = new Delete(rowKey);\n                deletes.add(delete);\n            }\n            if (!deletes.isEmpty()) {\n                table.delete(deletes);\n            }\n            flag = true;\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n            throw new RuntimeException(e);\n        }\n        return flag;\n    }\n\n    public void close() throws IOException {\n        if (conn != null) {\n            conn.close();\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/hbase/src/main/java/com/alibaba/otter/canal/client/adapter/hbase/support/PhType.java",
    "content": "package com.alibaba.otter.canal.client.adapter.hbase.support;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.sql.Time;\nimport java.sql.Timestamp;\nimport java.util.Date;\n\n/**\n * Phoenix类型\n *\n * @author machengyuan 2018-8-21 下午06:12:34\n * @version 1.0.0\n */\npublic enum PhType {\n                    DEFAULT, UNSIGNED_INT, UNSIGNED_LONG, UNSIGNED_TINYINT, UNSIGNED_SMALLINT, UNSIGNED_FLOAT,\n                    UNSIGNED_DOUBLE, INTEGER, BIGINT, TINYINT, SMALLINT, FLOAT, DOUBLE, DECIMAL, BOOLEAN, UNSIGNED_TIME,\n                    UNSIGNED_DATE, UNSIGNED_TIMESTAMP, TIME, DATE, TIMESTAMP, VARCHAR, VARBINARY;\n\n    private static Logger logger = LoggerFactory.getLogger(PhType.class);\n\n    public static PhType getType(Class<?> javaType) {\n        if (javaType == null) return DEFAULT;\n        PhType phType;\n        if (Integer.class == javaType || int.class == javaType) {\n            phType = INTEGER;\n        } else if (Long.class == javaType || long.class == javaType) {\n            phType = BIGINT;\n        } else if (Byte.class == javaType || byte.class == javaType) {\n            phType = TINYINT;\n        } else if (Short.class == javaType || short.class == javaType) {\n            phType = SMALLINT;\n        } else if (Float.class == javaType || float.class == javaType) {\n            phType = FLOAT;\n        } else if (Double.class == javaType || double.class == javaType) {\n            phType = DOUBLE;\n        } else if (Boolean.class == javaType || boolean.class == javaType) {\n            phType = BOOLEAN;\n        } else if (java.sql.Date.class == javaType) {\n            phType = DATE;\n        } else if (Time.class == javaType) {\n            phType = DATE;\n        } else if (Timestamp.class == javaType) {\n            phType = TIMESTAMP;\n        } else if (Date.class == javaType) {\n            phType = DATE;\n        } else if (byte[].class == javaType) {\n            phType = VARBINARY;\n        } else if (String.class == javaType) {\n            phType = VARCHAR;\n        } else if (BigDecimal.class == javaType) {\n            phType = DECIMAL;\n        } else if (BigInteger.class == javaType) {\n            phType = UNSIGNED_LONG;\n        } else {\n            phType = DEFAULT;\n        }\n        return phType;\n    }\n\n    public static PhType getType(String type) {\n        if (type == null) return DEFAULT;\n        try {\n            return PhType.valueOf(type.toUpperCase());\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n            return DEFAULT;\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/hbase/src/main/java/com/alibaba/otter/canal/client/adapter/hbase/support/PhTypeUtil.java",
    "content": "package com.alibaba.otter.canal.client.adapter.hbase.support;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.math.MathContext;\nimport java.math.RoundingMode;\nimport java.sql.Timestamp;\nimport java.util.Date;\n\nimport org.apache.hadoop.hbase.util.Bytes;\n\nimport com.alibaba.otter.canal.client.adapter.support.Util;\nimport com.google.common.math.LongMath;\n\n/**\n * Phoenix类型转换工具类\n *\n * @author machengyuan 2018-8-21 下午06:14:26\n * @version 1.0.0\n */\npublic class PhTypeUtil {\n\n    public static byte[] toBytes(Object v, PhType phType) {\n        if (v == null) return null;\n        byte[] b = null;\n        if (phType == PhType.DEFAULT) {\n            PhType phType1 = PhType.getType(v.getClass());\n            if (phType1 != null && phType1 != PhType.DEFAULT) {\n                toBytes(v, phType1);\n            }\n        } else if (phType == PhType.INTEGER) {\n            b = new byte[Bytes.SIZEOF_INT];\n            encodeInt(((Number) v).intValue(), b, 0);\n        } else if (phType == PhType.UNSIGNED_INT) {\n            b = new byte[Bytes.SIZEOF_INT];\n            encodeUnsignedInt(((Number) v).intValue(), b, 0);\n        } else if (phType == PhType.BIGINT) {\n            b = new byte[Bytes.SIZEOF_LONG];\n            encodeLong(((Number) v).longValue(), b, 0);\n        } else if (phType == PhType.UNSIGNED_LONG) {\n            b = new byte[Bytes.SIZEOF_LONG];\n            encodeUnsignedLong(((Number) v).longValue(), b, 0);\n        } else if (phType == PhType.SMALLINT) {\n            b = new byte[Bytes.SIZEOF_SHORT];\n            encodeShort(((Number) v).shortValue(), b, 0);\n        } else if (phType == PhType.UNSIGNED_SMALLINT) {\n            b = new byte[Bytes.SIZEOF_SHORT];\n            encodeUnsignedShort(((Number) v).shortValue(), b, 0);\n        } else if (phType == PhType.TINYINT) {\n            b = new byte[Bytes.SIZEOF_BYTE];\n            encodeByte(((Number) v).byteValue(), b, 0);\n        } else if (phType == PhType.UNSIGNED_TINYINT) {\n            b = new byte[Bytes.SIZEOF_BYTE];\n            encodeUnsignedByte(((Number) v).byteValue(), b, 0);\n        } else if (phType == PhType.FLOAT) {\n            b = new byte[Bytes.SIZEOF_FLOAT];\n            encodeFloat(((Number) v).floatValue(), b, 0);\n        } else if (phType == PhType.UNSIGNED_FLOAT) {\n            b = new byte[Bytes.SIZEOF_FLOAT];\n            encodeUnsignedFloat(((Number) v).floatValue(), b, 0);\n        } else if (phType == PhType.DOUBLE) {\n            b = new byte[Bytes.SIZEOF_DOUBLE];\n            encodeDouble(((Number) v).doubleValue(), b, 0);\n        } else if (phType == PhType.UNSIGNED_DOUBLE) {\n            b = new byte[Bytes.SIZEOF_DOUBLE];\n            encodeUnsignedDouble(((Number) v).doubleValue(), b, 0);\n        } else if (phType == PhType.BOOLEAN) {\n            if ((Boolean) v) {\n                b = new byte[] { 1 };\n            } else {\n                b = new byte[] { 0 };\n            }\n        } else if (phType == PhType.TIME || phType == PhType.DATE) {\n            b = new byte[Bytes.SIZEOF_LONG];\n            encodeDate(v, b, 0);\n        } else if (phType == PhType.TIMESTAMP) {\n            b = new byte[Bytes.SIZEOF_LONG + Bytes.SIZEOF_INT];\n            encodeTimestamp(v, b, 0);\n        } else if (phType == PhType.UNSIGNED_TIME || phType == PhType.UNSIGNED_DATE) {\n            b = new byte[Bytes.SIZEOF_LONG];\n            encodeUnsignedDate(v, b, 0);\n        } else if (phType == PhType.UNSIGNED_TIMESTAMP) {\n            b = new byte[Bytes.SIZEOF_LONG + Bytes.SIZEOF_INT];\n            encodeUnsignedTimestamp(v, b, 0);\n        } else if (phType == PhType.VARBINARY) {\n            b = (byte[]) v;\n        } else if (phType == PhType.VARCHAR) {\n            b = Bytes.toBytes(v.toString());\n        } else if (phType == PhType.DECIMAL) {\n            if (v instanceof BigDecimal) {\n                b = encodeDecimal(v);\n            } else if (v instanceof Number) {\n                b = encodeDecimal(new BigDecimal(v.toString()));\n            }\n        }\n        return b;\n    }\n\n    public static Object toObject(byte[] b, PhType phType) {\n        if (b == null) return null;\n        Object v = null;\n        if (phType == PhType.INTEGER) {\n            v = decodeInt(b, 0);\n        } else if (phType == PhType.UNSIGNED_INT) {\n            v = decodeUnsignedInt(b, 0);\n        } else if (phType == PhType.BIGINT) {\n            v = decodeLong(b, 0);\n        } else if (phType == PhType.UNSIGNED_LONG) {\n            v = decodeUnsignedLong(b, 0);\n        } else if (phType == PhType.SMALLINT) {\n            v = decodeShort(b, 0);\n        } else if (phType == PhType.UNSIGNED_SMALLINT) {\n            v = decodeUnsignedShort(b, 0);\n        } else if (phType == PhType.TINYINT) {\n            v = decodeByte(b, 0);\n        } else if (phType == PhType.UNSIGNED_TINYINT) {\n            v = decodeUnsignedByte(b, 0);\n        } else if (phType == PhType.FLOAT) {\n            v = decodeFloat(b, 0);\n        } else if (phType == PhType.UNSIGNED_FLOAT) {\n            v = decodeUnsignedFloat(b, 0);\n        } else if (phType == PhType.DOUBLE) {\n            v = decodeDouble(b, 0);\n        } else if (phType == PhType.UNSIGNED_DOUBLE) {\n            v = decodeUnsignedDouble(b, 0);\n        } else if (phType == PhType.BOOLEAN) {\n            checkForSufficientLength(b, 0, Bytes.SIZEOF_BOOLEAN);\n            if (b[0] == 1) {\n                v = true;\n            } else if (b[0] == 0) {\n                v = false;\n            }\n        } else if (phType == PhType.DATE) {\n            v = new java.sql.Date(decodeLong(b, 0));\n        } else if (phType == PhType.TIME) {\n            v = new java.sql.Time(decodeLong(b, 0));\n        } else if (phType == PhType.TIMESTAMP) {\n            long millisDeserialized = decodeLong(b, 0);\n            Timestamp ts = new Timestamp(millisDeserialized);\n            int nanosDeserialized = decodeUnsignedInt(b, Bytes.SIZEOF_LONG);\n            ts.setNanos(nanosDeserialized < 1000000 ? ts.getNanos() + nanosDeserialized : nanosDeserialized);\n            v = ts;\n        } else if (phType == PhType.UNSIGNED_TIME || phType == PhType.UNSIGNED_DATE) {\n            v = new Date(decodeUnsignedLong(b, 0));\n        } else if (phType == PhType.UNSIGNED_TIMESTAMP) {\n            long millisDeserialized = decodeUnsignedLong(b, 0);\n            Timestamp ts = new Timestamp(millisDeserialized);\n            int nanosDeserialized = decodeUnsignedInt(b, Bytes.SIZEOF_LONG);\n            ts.setNanos(nanosDeserialized < 1000000 ? ts.getNanos() + nanosDeserialized : nanosDeserialized);\n            v = ts;\n        } else if (phType == PhType.VARBINARY) {\n            v = b;\n        } else if (phType == PhType.VARCHAR || phType == PhType.DEFAULT) {\n            v = Bytes.toString(b);\n        } else if (phType == PhType.DECIMAL) {\n            v = decodeDecimal(b, 0, b.length);\n        }\n\n        return v;\n    }\n\n    private static int decodeInt(byte[] bytes, int o) {\n        checkForSufficientLength(bytes, o, Bytes.SIZEOF_INT);\n        int v;\n        v = bytes[o] ^ 0x80; // Flip sign bit back\n        for (int i = 1; i < Bytes.SIZEOF_INT; i++) {\n            v = (v << 8) + (bytes[o + i] & 0xff);\n        }\n        return v;\n    }\n\n    private static int encodeInt(int v, byte[] b, int o) {\n        checkForSufficientLength(b, o, Bytes.SIZEOF_INT);\n        b[o + 0] = (byte) ((v >> 24) ^ 0x80); // Flip sign bit so that INTEGER\n                                              // is binary comparable\n        b[o + 1] = (byte) (v >> 16);\n        b[o + 2] = (byte) (v >> 8);\n        b[o + 3] = (byte) v;\n        return Bytes.SIZEOF_INT;\n    }\n\n    private static int decodeUnsignedInt(byte[] b, int o) {\n        checkForSufficientLength(b, o, Bytes.SIZEOF_INT);\n\n        int v = Bytes.toInt(b, o);\n        if (v < 0) {\n            throw new RuntimeException();\n        }\n        return v;\n    }\n\n    private static int encodeUnsignedInt(int v, byte[] b, int o) {\n        checkForSufficientLength(b, o, Bytes.SIZEOF_INT);\n        if (v < 0) {\n            throw new RuntimeException();\n        }\n        Bytes.putInt(b, o, v);\n        return Bytes.SIZEOF_INT;\n    }\n\n    private static long decodeLong(byte[] bytes, int o) {\n        checkForSufficientLength(bytes, o, Bytes.SIZEOF_LONG);\n        long v;\n        byte b = bytes[o];\n        v = b ^ 0x80; // Flip sign bit back\n        for (int i = 1; i < Bytes.SIZEOF_LONG; i++) {\n            b = bytes[o + i];\n            v = (v << 8) + (b & 0xff);\n        }\n        return v;\n    }\n\n    private static int encodeLong(long v, byte[] b, int o) {\n        checkForSufficientLength(b, o, Bytes.SIZEOF_LONG);\n        b[o + 0] = (byte) ((v >> 56) ^ 0x80); // Flip sign bit so that INTEGER\n                                              // is binary comparable\n        b[o + 1] = (byte) (v >> 48);\n        b[o + 2] = (byte) (v >> 40);\n        b[o + 3] = (byte) (v >> 32);\n        b[o + 4] = (byte) (v >> 24);\n        b[o + 5] = (byte) (v >> 16);\n        b[o + 6] = (byte) (v >> 8);\n        b[o + 7] = (byte) v;\n        return Bytes.SIZEOF_LONG;\n    }\n\n    private static long decodeUnsignedLong(byte[] b, int o) {\n        checkForSufficientLength(b, o, Bytes.SIZEOF_LONG);\n        long v = 0;\n        for (int i = o; i < o + Bytes.SIZEOF_LONG; i++) {\n            v <<= 8;\n            v ^= b[i] & 0xFF;\n        }\n\n        if (v < 0) {\n            throw new RuntimeException();\n        }\n        return v;\n    }\n\n    private static int encodeUnsignedLong(long v, byte[] b, int o) {\n        checkForSufficientLength(b, o, Bytes.SIZEOF_LONG);\n        if (v < 0) {\n            throw new RuntimeException();\n        }\n        Bytes.putLong(b, o, v);\n        return Bytes.SIZEOF_LONG;\n    }\n\n    private static short decodeShort(byte[] b, int o) {\n        checkForSufficientLength(b, o, Bytes.SIZEOF_SHORT);\n        int v;\n        v = b[o] ^ 0x80; // Flip sign bit back\n        for (int i = 1; i < Bytes.SIZEOF_SHORT; i++) {\n            v = (v << 8) + (b[o + i] & 0xff);\n        }\n        return (short) v;\n    }\n\n    private static int encodeShort(short v, byte[] b, int o) {\n        checkForSufficientLength(b, o, Bytes.SIZEOF_SHORT);\n        b[o + 0] = (byte) ((v >> 8) ^ 0x80); // Flip sign bit so that Short is\n                                             // binary comparable\n        b[o + 1] = (byte) v;\n        return Bytes.SIZEOF_SHORT;\n    }\n\n    private static short decodeUnsignedShort(byte[] b, int o) {\n        checkForSufficientLength(b, o, Bytes.SIZEOF_SHORT);\n        short v = Bytes.toShort(b, o);\n        if (v < 0) {\n            throw new RuntimeException();\n        }\n        return v;\n    }\n\n    private static int encodeUnsignedShort(short v, byte[] b, int o) {\n        checkForSufficientLength(b, o, Bytes.SIZEOF_SHORT);\n        if (v < 0) {\n            throw new RuntimeException();\n        }\n        Bytes.putShort(b, o, v);\n        return Bytes.SIZEOF_SHORT;\n    }\n\n    private static byte decodeByte(byte[] b, int o) {\n        checkForSufficientLength(b, o, Bytes.SIZEOF_BYTE);\n        int v;\n        v = b[o] ^ 0x80; // Flip sign bit back\n        return (byte) v;\n    }\n\n    private static int encodeByte(byte v, byte[] b, int o) {\n        checkForSufficientLength(b, o, Bytes.SIZEOF_BYTE);\n        b[o] = (byte) (v ^ 0x80); // Flip sign bit so that Short is binary\n                                  // comparable\n        return Bytes.SIZEOF_BYTE;\n    }\n\n    private static byte decodeUnsignedByte(byte[] b, int o) {\n        checkForSufficientLength(b, o, Bytes.SIZEOF_BYTE);\n        byte v = b[o];\n        if (v < 0) {\n            throw new RuntimeException();\n        }\n        return v;\n    }\n\n    private static int encodeUnsignedByte(byte v, byte[] b, int o) {\n        if (v < 0) {\n            throw new RuntimeException();\n        }\n        Bytes.putByte(b, o, v);\n        return Bytes.SIZEOF_BYTE;\n    }\n\n    private static float decodeFloat(byte[] b, int o) {\n        checkForSufficientLength(b, o, Bytes.SIZEOF_INT);\n        int value;\n        value = Bytes.toInt(b, o);\n        value--;\n        value ^= (~value >> Integer.SIZE - 1) | Integer.MIN_VALUE;\n        return Float.intBitsToFloat(value);\n    }\n\n    private static int encodeFloat(float v, byte[] b, int o) {\n        checkForSufficientLength(b, o, Bytes.SIZEOF_FLOAT);\n        int i = Float.floatToIntBits(v);\n        i = (i ^ ((i >> Integer.SIZE - 1) | Integer.MIN_VALUE)) + 1;\n        Bytes.putInt(b, o, i);\n        return Bytes.SIZEOF_FLOAT;\n    }\n\n    private static float decodeUnsignedFloat(byte[] b, int o) {\n        checkForSufficientLength(b, o, Bytes.SIZEOF_FLOAT);\n        float v = Bytes.toFloat(b, o);\n        if (v < 0) {\n            throw new RuntimeException();\n        }\n        return v;\n    }\n\n    private static int encodeUnsignedFloat(float v, byte[] b, int o) {\n        checkForSufficientLength(b, o, Bytes.SIZEOF_FLOAT);\n        if (v < 0) {\n            throw new RuntimeException();\n        }\n        Bytes.putFloat(b, o, v);\n        return Bytes.SIZEOF_FLOAT;\n    }\n\n    private static double decodeDouble(byte[] bytes, int o) {\n        checkForSufficientLength(bytes, o, Bytes.SIZEOF_LONG);\n        long l;\n        l = Bytes.toLong(bytes, o);\n        l--;\n        l ^= (~l >> Long.SIZE - 1) | Long.MIN_VALUE;\n        return Double.longBitsToDouble(l);\n    }\n\n    private static int encodeDouble(double v, byte[] b, int o) {\n        checkForSufficientLength(b, o, Bytes.SIZEOF_LONG);\n        long l = Double.doubleToLongBits(v);\n        l = (l ^ ((l >> Long.SIZE - 1) | Long.MIN_VALUE)) + 1;\n        Bytes.putLong(b, o, l);\n        return Bytes.SIZEOF_LONG;\n    }\n\n    private static double decodeUnsignedDouble(byte[] b, int o) {\n        checkForSufficientLength(b, o, Bytes.SIZEOF_DOUBLE);\n        double v = Bytes.toDouble(b, o);\n        if (v < 0) {\n            throw new RuntimeException();\n        }\n        return v;\n    }\n\n    private static int encodeUnsignedDouble(double v, byte[] b, int o) {\n        checkForSufficientLength(b, o, Bytes.SIZEOF_DOUBLE);\n        if (v < 0) {\n            throw new RuntimeException();\n        }\n        Bytes.putDouble(b, o, v);\n        return Bytes.SIZEOF_DOUBLE;\n    }\n\n    private static int encodeDate(Object v, byte[] b, int o) {\n        if (v instanceof Date) {\n            encodeLong(((Date) v).getTime(), b, 0);\n        } else if (v instanceof String) {\n            String dateStr = (String) v;\n            Date date;\n            try {\n                date = Util.parseDate(dateStr);\n                if (date != null) {\n                    encodeLong(date.getTime(), b, 0);\n                }\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n        }\n        return Bytes.SIZEOF_LONG;\n    }\n\n    private static int encodeTimestamp(Object v, byte[] b, int o) {\n        if (v instanceof Timestamp) {\n            Timestamp ts = (Timestamp) v;\n            encodeLong(ts.getTime(), b, o);\n            Bytes.putInt(b, Bytes.SIZEOF_LONG, ts.getNanos() % 1000000);\n        } else {\n            encodeDate(v, b, o);\n        }\n        return Bytes.SIZEOF_LONG + Bytes.SIZEOF_INT;\n    }\n\n    private static int encodeUnsignedDate(Object v, byte[] b, int o) {\n        if (v instanceof Date) {\n            encodeUnsignedLong(((Date) v).getTime(), b, 0);\n        } else if (v instanceof String) {\n            String dateStr = (String) v;\n            Date date;\n            try {\n                date = Util.parseDate(dateStr);\n                if (date != null) {\n                    encodeUnsignedLong(date.getTime(), b, 0);\n                }\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n        }\n        return Bytes.SIZEOF_LONG;\n    }\n\n    private static int encodeUnsignedTimestamp(Object v, byte[] b, int o) {\n        if (v instanceof Timestamp) {\n            Timestamp ts = (Timestamp) v;\n            encodeUnsignedLong(ts.getTime(), b, o);\n            Bytes.putInt(b, Bytes.SIZEOF_LONG, ts.getNanos() % 1000000);\n        } else {\n            encodeUnsignedDate(v, b, o);\n        }\n        return Bytes.SIZEOF_LONG + Bytes.SIZEOF_INT;\n    }\n\n    private static byte[] encodeDecimal(Object object) {\n        if (object == null) {\n            return new byte[0];\n        }\n        BigDecimal v = (BigDecimal) object;\n        v = v.round(DEFAULT_MATH_CONTEXT).stripTrailingZeros();\n        int len = getLength(v);\n        byte[] result = new byte[Math.min(len, 21)];\n        decimalToBytes(v, result, 0, len);\n        return result;\n    }\n\n    private static BigDecimal decodeDecimal(byte[] bytes, int offset, int length) {\n        if (length == 1 && bytes[offset] == ZERO_BYTE) {\n            return BigDecimal.ZERO;\n        }\n        int signum = ((bytes[offset] & 0x80) == 0) ? -1 : 1;\n        int scale;\n        int index;\n        int digitOffset;\n        long multiplier = 100L;\n        int begIndex = offset + 1;\n        if (signum == 1) {\n            scale = (byte) (((bytes[offset] & 0x7F) - 65) * -2);\n            index = offset + length;\n            digitOffset = POS_DIGIT_OFFSET;\n        } else {\n            scale = (byte) ((~bytes[offset] - 65 - 128) * -2);\n            index = offset + length - (bytes[offset + length - 1] == NEG_TERMINAL_BYTE ? 1 : 0);\n            digitOffset = -NEG_DIGIT_OFFSET;\n        }\n        length = index - offset;\n        long l = signum * bytes[--index] - digitOffset;\n        if (l % 10 == 0) { // trailing zero\n            scale--; // drop trailing zero and compensate in the scale\n            l /= 10;\n            multiplier = 10;\n        }\n        // Use long arithmetic for as long as we can\n        while (index > begIndex) {\n            if (l >= MAX_LONG_FOR_DESERIALIZE || multiplier >= Long.MAX_VALUE / 100) {\n                multiplier = LongMath.divide(multiplier, 100L, RoundingMode.UNNECESSARY);\n                break; // Exit loop early so we don't overflow our multiplier\n            }\n            int digit100 = signum * bytes[--index] - digitOffset;\n            l += digit100 * multiplier;\n            multiplier = LongMath.checkedMultiply(multiplier, 100);\n        }\n\n        BigInteger bi;\n        // If still more digits, switch to BigInteger arithmetic\n        if (index > begIndex) {\n            bi = BigInteger.valueOf(l);\n            BigInteger biMultiplier = BigInteger.valueOf(multiplier).multiply(ONE_HUNDRED);\n            do {\n                int digit100 = signum * bytes[--index] - digitOffset;\n                bi = bi.add(biMultiplier.multiply(BigInteger.valueOf(digit100)));\n                biMultiplier = biMultiplier.multiply(ONE_HUNDRED);\n            } while (index > begIndex);\n            if (signum == -1) {\n                bi = bi.negate();\n            }\n        } else {\n            bi = BigInteger.valueOf(l * signum);\n        }\n        // Update the scale based on the precision\n        scale += (length - 2) * 2;\n        BigDecimal v = new BigDecimal(bi, scale);\n        return v;\n    }\n\n    private static int getLength(BigDecimal v) {\n        int signum = v.signum();\n        if (signum == 0) { // Special case for zero\n            return 1;\n        }\n        return (signum < 0 ? 2 : 1) + (v.precision() + 1 + (v.scale() % 2 == 0 ? 0 : 1)) / 2;\n    }\n\n    private static final int         MAX_PRECISION            = 38;\n    private static final MathContext DEFAULT_MATH_CONTEXT     = new MathContext(MAX_PRECISION, RoundingMode.HALF_UP);\n    private static final Integer     MAX_BIG_DECIMAL_BYTES    = 21;\n    private static final byte        ZERO_BYTE                = (byte) 0x80;\n    private static final byte        NEG_TERMINAL_BYTE        = (byte) 102;\n    private static final int         EXP_BYTE_OFFSET          = 65;\n    private static final int         POS_DIGIT_OFFSET         = 1;\n    private static final int         NEG_DIGIT_OFFSET         = 101;\n    private static final BigInteger  MAX_LONG                 = BigInteger.valueOf(Long.MAX_VALUE);\n    private static final BigInteger  MIN_LONG                 = BigInteger.valueOf(Long.MIN_VALUE);\n    private static final BigInteger  ONE_HUNDRED              = BigInteger.valueOf(100);\n    private static final long        MAX_LONG_FOR_DESERIALIZE = Long.MAX_VALUE / 1000;\n\n    private static int decimalToBytes(BigDecimal v, byte[] result, final int offset, int length) {\n        int signum = v.signum();\n        if (signum == 0) {\n            result[offset] = ZERO_BYTE;\n            return 1;\n        }\n        int index = offset + length;\n        int scale = v.scale();\n        int expOffset = scale % 2 * (scale < 0 ? -1 : 1);\n        int multiplyBy;\n        BigInteger divideBy;\n        if (expOffset == 0) {\n            multiplyBy = 1;\n            divideBy = ONE_HUNDRED;\n        } else {\n            multiplyBy = 10;\n            divideBy = BigInteger.TEN;\n        }\n        // Normalize the scale based on what is necessary to end up with a base\n        // 100\n        // decimal (i.e. 10.123e3)\n        int digitOffset;\n        BigInteger compareAgainst;\n        if (signum == 1) {\n            digitOffset = POS_DIGIT_OFFSET;\n            compareAgainst = MAX_LONG;\n            scale -= (length - 2) * 2;\n            result[offset] = (byte) ((-(scale + expOffset) / 2 + EXP_BYTE_OFFSET) | 0x80);\n        } else {\n            digitOffset = NEG_DIGIT_OFFSET;\n            compareAgainst = MIN_LONG;\n            // Scale adjustment shouldn't include terminal byte in length\n            scale -= (length - 2 - 1) * 2;\n            result[offset] = (byte) (~(-(scale + expOffset) / 2 + EXP_BYTE_OFFSET + 128) & 0x7F);\n            if (length <= MAX_BIG_DECIMAL_BYTES) {\n                result[--index] = NEG_TERMINAL_BYTE;\n            } else {\n                // Adjust length and offset down because we don't have enough\n                // room\n                length = MAX_BIG_DECIMAL_BYTES;\n                index = offset + length;\n            }\n        }\n        BigInteger bi = v.unscaledValue();\n        // Use BigDecimal arithmetic until we can fit into a long\n        while (bi.compareTo(compareAgainst) * signum > 0) {\n            BigInteger[] dandr = bi.divideAndRemainder(divideBy);\n            bi = dandr[0];\n            int digit = dandr[1].intValue();\n            result[--index] = (byte) (digit * multiplyBy + digitOffset);\n            multiplyBy = 1;\n            divideBy = ONE_HUNDRED;\n        }\n        long l = bi.longValue();\n        do {\n            long divBy = 100 / multiplyBy;\n            long digit = l % divBy;\n            l /= divBy;\n            result[--index] = (byte) (digit * multiplyBy + digitOffset);\n            multiplyBy = 1;\n        } while (l != 0);\n\n        return length;\n    }\n\n    private static void checkForSufficientLength(byte[] b, int offset, int requiredLength) {\n        if (b.length < offset + requiredLength) {\n            throw new RuntimeException(\n                \"Expected length of at least \" + requiredLength + \" bytes, but had \" + (b.length - offset));\n        }\n    }\n\n}\n"
  },
  {
    "path": "client-adapter/hbase/src/main/java/com/alibaba/otter/canal/client/adapter/hbase/support/Type.java",
    "content": "package com.alibaba.otter.canal.client.adapter.hbase.support;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.util.Date;\n\n/**\n * Java类型\n *\n * @author machengyuan 2018-8-21 下午06:11:36\n * @version 1.0.0\n */\npublic enum Type {\n                  DEFAULT, STRING, INTEGER, LONG, SHORT, BOOLEAN, FLOAT, DOUBLE, BIGDECIMAL, DATE, BYTE, BYTES;\n\n    private static Logger logger = LoggerFactory.getLogger(Type.class);\n\n    public static Type getType(String type) {\n        if (type == null) {\n            return DEFAULT;\n        }\n        try {\n            return Type.valueOf(type);\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n            return DEFAULT;\n        }\n    }\n\n    public static Type getType(Class<?> javaType) {\n        if (javaType == null) {\n            return DEFAULT;\n        }\n        Type type;\n        if (Integer.class == javaType || int.class == javaType) {\n            type = INTEGER;\n        } else if (Long.class == javaType || long.class == javaType) {\n            type = LONG;\n        } else if (Byte.class == javaType || byte.class == javaType) {\n            type = BYTE;\n        } else if (Short.class == javaType || short.class == javaType) {\n            type = SHORT;\n        } else if (Float.class == javaType || float.class == javaType) {\n            type = FLOAT;\n        } else if (Double.class == javaType || double.class == javaType) {\n            type = DOUBLE;\n        } else if (Boolean.class == javaType || boolean.class == javaType) {\n            type = BOOLEAN;\n        } else if (Date.class == javaType) {\n            type = DATE;\n        } else if (byte[].class == javaType) {\n            type = BYTES;\n        } else if (String.class == javaType) {\n            type = STRING;\n        } else if (BigDecimal.class == javaType) {\n            type = BIGDECIMAL;\n        } else if (BigInteger.class == javaType) {\n            type = LONG;\n        } else {\n            type = DEFAULT;\n        }\n        return type;\n    }\n}\n"
  },
  {
    "path": "client-adapter/hbase/src/main/java/com/alibaba/otter/canal/client/adapter/hbase/support/TypeUtil.java",
    "content": "package com.alibaba.otter.canal.client.adapter.hbase.support;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.sql.Time;\nimport java.sql.Timestamp;\nimport java.util.Date;\n\nimport org.apache.hadoop.hbase.util.Bytes;\n\n/**\n * Java类型转换工具类\n *\n * @author machengyuan 2018-8-21 下午06:12:34\n * @version 1.0.0\n */\npublic class TypeUtil {\n\n    public static byte[] toBytes(Object obj) {\n        if (obj == null) {\n            return null;\n        }\n        byte[] bytes;\n        Class<?> clazz = obj.getClass();\n        if (clazz == String.class) {\n            bytes = Bytes.toBytes((String) obj);\n        } else if (clazz == Integer.class || clazz == int.class) {\n            bytes = Bytes.toBytes((Integer) obj);\n        } else if (clazz == Long.class || clazz == long.class) {\n            bytes = Bytes.toBytes((Long) obj);\n        } else if (clazz == Short.class || clazz == short.class) {\n            bytes = Bytes.toBytes((Short) obj);\n        } else if (clazz == Boolean.class || clazz == boolean.class) {\n            bytes = Bytes.toBytes((Boolean) obj);\n        } else if (clazz == Float.class || clazz == float.class) {\n            bytes = Bytes.toBytes((Float) obj);\n        } else if (clazz == Double.class || clazz == double.class) {\n            bytes = Bytes.toBytes((Double) obj);\n        } else if (clazz == Byte.class || clazz == byte.class) {\n            bytes = new byte[] { (byte) obj };\n        } else if (clazz == BigDecimal.class) {\n            bytes = Bytes.toBytes((BigDecimal) obj);\n        } else if (clazz == BigInteger.class) {\n            bytes = Bytes.toBytes(((BigInteger) obj).longValue());\n        } else if (clazz == Date.class) {\n            bytes = Bytes.toBytes(((Date) obj).getTime());\n        } else if (clazz == byte[].class) {\n            bytes = (byte[]) obj;\n        } else {\n            // 其余类型统一转换为string\n            bytes = Bytes.toBytes(obj.toString());\n        }\n        return bytes;\n    }\n\n    public static byte[] toBytes(Object v, Type type) {\n        if (v == null) {\n            return null;\n        }\n        byte[] b = null;\n        if (type == Type.DEFAULT) {\n            Type type1 = Type.getType(v.getClass());\n            if (type1 != null && type1 != Type.DEFAULT) {\n                b = toBytes(v, type1);\n            }\n        } else if (type == Type.STRING) {\n            b = Bytes.toBytes(v.toString());\n        } else if (type == Type.INTEGER) {\n            b = Bytes.toBytes(((Number) v).intValue());\n        } else if (type == Type.LONG) {\n            b = Bytes.toBytes(((Number) v).longValue());\n        } else if (type == Type.SHORT) {\n            b = Bytes.toBytes(((Number) v).shortValue());\n        } else if (type == Type.BYTE) {\n            b = Bytes.toBytes(((Number) v).byteValue());\n        } else if (type == Type.FLOAT) {\n            b = Bytes.toBytes(((Number) v).floatValue());\n        } else if (type == Type.DOUBLE) {\n            b = Bytes.toBytes(((Number) v).doubleValue());\n        } else if (type == Type.BOOLEAN) {\n            b = Bytes.toBytes(((Boolean) v));\n        } else if (type == Type.DATE) {\n            b = Bytes.toBytes(((Date) v).getTime());\n        } else if (type == Type.BYTES) {\n            b = (byte[]) v;\n        } else if (type == Type.BIGDECIMAL) {\n            if (v instanceof BigDecimal) {\n                b = Bytes.toBytes((BigDecimal) v);\n            } else {\n                b = Bytes.toBytes(new BigDecimal(v.toString()));\n            }\n        }\n        return b;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public static <T> T toObject(byte[] bytes, Class<T> clazz) {\n        if (bytes == null) {\n            return null;\n        }\n        Object res;\n        if (String.class == clazz) {\n            res = Bytes.toString(bytes);\n        } else if (Integer.class == clazz || int.class == clazz) {\n            res = Bytes.toInt(bytes);\n        } else if (Long.class == clazz || long.class == clazz) {\n            res = Bytes.toLong(bytes);\n        } else if (Short.class == clazz || short.class == clazz) {\n            res = Bytes.toShort(bytes);\n        } else if (Boolean.class == clazz || boolean.class == clazz) {\n            res = Bytes.toBoolean(bytes);\n        } else if (Float.class == clazz || float.class == clazz) {\n            res = Bytes.toFloat(bytes);\n        } else if (Double.class == clazz || double.class == clazz) {\n            res = Bytes.toDouble(bytes);\n        } else if (Byte.class == clazz || byte.class == clazz) {\n            res = bytes[0];\n        } else if (BigDecimal.class == clazz) {\n            res = Bytes.toBigDecimal(bytes);\n        } else if (BigInteger.class == clazz) {\n            res = Bytes.toLong(bytes);\n        } else if (java.sql.Date.class == clazz) {\n            long ts = Bytes.toLong(bytes);\n            res = new java.sql.Date(ts);\n        } else if (Time.class == clazz) {\n            long ts = Bytes.toLong(bytes);\n            res = new Time(ts);\n        } else if (Timestamp.class == clazz) {\n            long ts = Bytes.toLong(bytes);\n            res = new Timestamp(ts);\n        } else if (Date.class == clazz) {\n            long ts = Bytes.toLong(bytes);\n            res = new Date(ts);\n        } else {\n            throw new IllegalArgumentException(\"mismatch class type\");\n        }\n        return (T) res;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public static <T> T toObject(byte[] bytes, Type type) {\n        if (bytes == null) {\n            return null;\n        }\n        Object res = null;\n        if (type == Type.STRING || type == Type.DEFAULT) {\n            res = Bytes.toString(bytes);\n        } else if (type == Type.INTEGER) {\n            if (bytes.length == Bytes.SIZEOF_INT) {\n                res = Bytes.toInt(bytes);\n            }\n        } else if (type == Type.LONG) {\n            if (bytes.length == Bytes.SIZEOF_LONG) {\n                res = Bytes.toLong(bytes);\n            }\n        } else if (type == Type.SHORT) {\n            if (bytes.length == Bytes.SIZEOF_SHORT) {\n                res = Bytes.toShort(bytes);\n            }\n        } else if (type == Type.BYTE) {\n            if (bytes.length == Bytes.SIZEOF_BYTE) {\n                res = bytes[0];\n            }\n        } else if (type == Type.FLOAT) {\n            if (bytes.length == Bytes.SIZEOF_FLOAT) {\n                res = Bytes.toFloat(bytes);\n            }\n        } else if (type == Type.DOUBLE) {\n            if (bytes.length == Bytes.SIZEOF_DOUBLE) {\n                res = Bytes.toDouble(bytes);\n            }\n        } else if (type == Type.BOOLEAN) {\n            if (bytes.length == Bytes.SIZEOF_BOOLEAN) {\n                res = Bytes.toBoolean(bytes);\n            }\n        } else if (type == Type.DATE) {\n            if (bytes.length == Bytes.SIZEOF_LONG) {\n                res = new Date(Bytes.toLong(bytes));\n            }\n        } else if (type == Type.BYTES) {\n            res = bytes;\n        } else if (type == Type.BIGDECIMAL) {\n            res = Bytes.toBigDecimal(bytes);\n        } else {\n            throw new IllegalArgumentException(\"mismatch class type\");\n        }\n        return (T) res;\n    }\n}\n"
  },
  {
    "path": "client-adapter/hbase/src/main/resources/META-INF/canal/com.alibaba.otter.canal.client.adapter.OuterAdapter",
    "content": "hbase=com.alibaba.otter.canal.client.adapter.hbase.HbaseAdapter"
  },
  {
    "path": "client-adapter/hbase/src/main/resources/hbase/mytest_person2.yml",
    "content": "dataSourceKey: defaultDS\ndestination: example\ngroupId: g1\nhbaseMapping:\n  mode: STRING  #NATIVE   #PHOENIX\n  database: mytest  # 数据库名\n  table: person2     # 数据库表名\n  hbaseTable: MYTEST.PERSON2   # HBase表名\n  family: CF  # 默认统一Family名称\n  uppercaseQualifier: true  # 字段名转大写, 默认为true\n  etlCondition: \"where c_time>={}\"\n  commitBatch: 3000 # 批量提交的大小\n  #rowKey: id,type  # 复合字段rowKey不能和columns中的rowKey重复\n  columns:\n    # 数据库字段:HBase对应字段\n    id: ROWKEY LEN:15\n    name: NAME\n    email: EMAIL\n    type:\n    c_time: C_TIME\n    birthday: BIRTHDAY\n#  excludeColumns:\n#    - lat   # 忽略字段\n\n# -- NATIVE类型\n# $DEFAULT\n# $STRING\n# $INTEGER\n# $LONG\n# $SHORT\n# $BOOLEAN\n# $FLOAT\n# $DOUBLE\n# $BIGDECIMAL\n# $DATE\n# $BYTE\n# $BYTES\n\n# -- PHOENIX类型\n# $DEFAULT                  对应PHOENIX里的VARCHAR\n# $UNSIGNED_INT             对应PHOENIX里的UNSIGNED_INT           4字节\n# $UNSIGNED_LONG            对应PHOENIX里的UNSIGNED_LONG          8字节\n# $UNSIGNED_TINYINT         对应PHOENIX里的UNSIGNED_TINYINT       1字节\n# $UNSIGNED_SMALLINT        对应PHOENIX里的UNSIGNED_SMALLINT      2字节\n# $UNSIGNED_FLOAT           对应PHOENIX里的UNSIGNED_FLOAT         4字节\n# $UNSIGNED_DOUBLE          对应PHOENIX里的UNSIGNED_DOUBLE        8字节\n# $INTEGER                  对应PHOENIX里的INTEGER                4字节\n# $BIGINT                   对应PHOENIX里的BIGINT                 8字节\n# $TINYINT                  对应PHOENIX里的TINYINT                1字节\n# $SMALLINT                 对应PHOENIX里的SMALLINT               2字节\n# $FLOAT                    对应PHOENIX里的FLOAT                  4字节\n# $DOUBLE                    对应PHOENIX里的DOUBLE                 8字节\n# $BOOLEAN                  对应PHOENIX里的BOOLEAN                1字节\n# $TIME                     对应PHOENIX里的TIME                   8字节\n# $DATE                     对应PHOENIX里的DATE                   8字节\n# $TIMESTAMP                对应PHOENIX里的TIMESTAMP              12字节\n# $UNSIGNED_TIME            对应PHOENIX里的UNSIGNED_TIME          8字节\n# $UNSIGNED_DATE            对应PHOENIX里的UNSIGNED_DATE          8字节\n# $UNSIGNED_TIMESTAMP       对应PHOENIX里的UNSIGNED_TIMESTAMP     12字节\n# $VARCHAR                  对应PHOENIX里的VARCHAR                动态长度\n# $VARBINARY                对应PHOENIX里的VARBINARY              动态长度\n# $DECIMAL                  对应PHOENIX里的DECIMAL                动态长度\n"
  },
  {
    "path": "client-adapter/hbase/src/test/java/com/alibaba/otter/canal/client/adapter/hbase/test/HBaseConnectionTest.java",
    "content": "package com.alibaba.otter.canal.client.adapter.hbase.test;\n\nimport com.alibaba.otter.canal.client.adapter.hbase.support.HbaseTemplate;\nimport org.apache.hadoop.conf.Configuration;\nimport org.apache.hadoop.hbase.HBaseConfiguration;\nimport org.junit.Test;\n\npublic class HBaseConnectionTest {\n\n    @Test\n    public void test01() {\n        Configuration hbaseConfig = HBaseConfiguration.create();\n        hbaseConfig.set(\"hbase.zookeeper.quorum\", \"127.0.0.1\");\n        hbaseConfig.set(\"hbase.zookeeper.property.clientPort\", \"2181\");\n        hbaseConfig.set(\"zookeeper.znode.parent\", \"/hbase\");\n        HbaseTemplate hbaseTemplate = new HbaseTemplate(hbaseConfig);\n        System.out.println(hbaseTemplate.tableExists(\"ttt\"));\n    }\n}\n"
  },
  {
    "path": "client-adapter/kudu/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>canal.client-adapter</artifactId>\n        <groupId>com.alibaba.otter</groupId>\n        <version>1.1.9-SNAPSHOT</version>\n        <relativePath>../pom.xml</relativePath>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>com.alibaba.otter</groupId>\n    <artifactId>client-adapter.kudu</artifactId>\n    <packaging>jar</packaging>\n    <name>canal client adapter kudu module for otter ${project.version}</name>\n    <dependencies>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>client-adapter.common</artifactId>\n            <version>${project.version}</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.kudu</groupId>\n            <artifactId>kudu-client</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-assembly-plugin</artifactId>\n                <version>2.4</version>\n                <configuration>\n                    <descriptorRefs>\n                        <descriptorRef>jar-with-dependencies</descriptorRef>\n                    </descriptorRefs>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>make-assembly</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>single</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-antrun-plugin</artifactId>\n                <version>1.8</version>\n                <executions>\n                    <execution>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>run</goal>\n                        </goals>\n                        <configuration>\n                            <tasks>\n                                <copy todir=\"${project.basedir}/../launcher/target/classes/kudu\" overwrite=\"true\">\n                                    <fileset dir=\"${project.basedir}/target/classes/kudu\" erroronmissingdir=\"true\">\n                                        <include name=\"*.yml\" />\n                                    </fileset>\n                                </copy>\n                            </tasks>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "client-adapter/kudu/src/main/java/com/alibaba/otter/canal/client/adapter/kudu/KuduAdapter.java",
    "content": "package com.alibaba.otter.canal.client.adapter.kudu;\n\nimport com.alibaba.otter.canal.client.adapter.OuterAdapter;\nimport com.alibaba.otter.canal.client.adapter.kudu.config.KuduMappingConfig;\nimport com.alibaba.otter.canal.client.adapter.kudu.config.KuduMappingConfigLoader;\nimport com.alibaba.otter.canal.client.adapter.kudu.monitor.KuduConfigMonitor;\nimport com.alibaba.otter.canal.client.adapter.kudu.service.KuduEtlService;\nimport com.alibaba.otter.canal.client.adapter.kudu.service.KuduSyncService;\nimport com.alibaba.otter.canal.client.adapter.kudu.support.KuduTemplate;\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\nimport com.alibaba.otter.canal.client.adapter.support.EtlResult;\nimport com.alibaba.otter.canal.client.adapter.support.FileName2KeyMapping;\nimport com.alibaba.otter.canal.client.adapter.support.OuterAdapterConfig;\nimport com.alibaba.otter.canal.client.adapter.support.SPI;\nimport com.alibaba.otter.canal.client.adapter.support.Util;\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.concurrent.ConcurrentHashMap;\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * @author liuyadong\n * @description kudu适配器主类\n */\n@SPI(\"kudu\")\npublic class KuduAdapter implements OuterAdapter {\n\n    private static Logger                               logger             = LoggerFactory.getLogger(KuduAdapter.class);\n\n    private Map<String, KuduMappingConfig>              kuduMapping        = new ConcurrentHashMap<>();                 // 文件名对应配置\n    private Map<String, Map<String, KuduMappingConfig>> mappingConfigCache = new ConcurrentHashMap<>();                 // 库名-表名对应配置\n\n    private KuduTemplate                                kuduTemplate;\n\n    private KuduSyncService                             kuduSyncService;\n\n    private KuduConfigMonitor                           kuduConfigMonitor;\n\n    private Properties                                  envProperties;\n\n    private OuterAdapterConfig                          configuration;\n\n    public Map<String, KuduMappingConfig> getKuduMapping() {\n        return kuduMapping;\n    }\n\n    public Map<String, Map<String, KuduMappingConfig>> getMappingConfigCache() {\n        return mappingConfigCache;\n    }\n\n    @Override\n    public void init(OuterAdapterConfig configuration, Properties envProperties) {\n        this.envProperties = envProperties;\n        this.configuration = configuration;\n        Map<String, KuduMappingConfig> kuduMappingTmp = KuduMappingConfigLoader.load(envProperties);\n        // 过滤不匹配的key的配置,获取连接key，key为配置文件名称\n        kuduMappingTmp.forEach((key, config) -> {\n            addConfig(key, config);\n        });\n        // 判断目标字段是否为空\n        if (kuduMapping.isEmpty()) {\n            throw new RuntimeException(\"No kudu adapter found for config key: \" + configuration.getKey());\n        }\n\n        Map<String, String> properties = configuration.getProperties();\n\n        String kudu_master = properties.get(\"kudu.master.address\");\n        kuduTemplate = new KuduTemplate(kudu_master);\n        kuduSyncService = new KuduSyncService(kuduTemplate);\n\n        kuduConfigMonitor = new KuduConfigMonitor();\n        kuduConfigMonitor.init(this, envProperties);\n    }\n\n    @Override\n    public void sync(List<Dml> dmls) {\n        if (dmls == null || dmls.isEmpty()) {\n            return;\n        }\n        for (Dml dml : dmls) {\n            if (dml == null) {\n                return;\n            }\n            String destination = StringUtils.trimToEmpty(dml.getDestination());\n            String groupId = StringUtils.trimToEmpty(dml.getGroupId());\n            String database = dml.getDatabase();\n            String table = dml.getTable();\n            Map<String, KuduMappingConfig> configMap;\n            if (envProperties != null && !\"tcp\".equalsIgnoreCase(envProperties.getProperty(\"canal.conf.mode\"))) {\n                configMap = mappingConfigCache.get(destination + \"-\" + groupId + \"_\" + database + \"-\" + table);\n            } else {\n                configMap = mappingConfigCache.get(destination + \"_\" + database + \"-\" + table);\n            }\n            if (configMap != null) {\n                List<KuduMappingConfig> configs = new ArrayList<>();\n                configMap.values().forEach(config -> {\n                    if (StringUtils.isNotEmpty(config.getGroupId())) {\n                        if (config.getGroupId().equals(dml.getGroupId())) {\n                            configs.add(config);\n                        }\n                    } else {\n                        configs.add(config);\n                    }\n                });\n                if (!configs.isEmpty()) {\n                    configs.forEach(config -> kuduSyncService.sync(config, dml));\n                } else {\n                    logger.error(\"groupID didn't mach,please check your gruopId \");\n                }\n            } else {\n                logger.error(\"{} config didn't get,please check your map key \", destination + \"_\" + database + \"-\"\n                                                                                + table);\n            }\n        }\n    }\n\n    @Override\n    public void destroy() {\n        if (kuduConfigMonitor != null) {\n            kuduConfigMonitor.destroy();\n        }\n        // 加入kudu client 关闭钩子\n        kuduTemplate.closeKuduClient();\n    }\n\n    @Override\n    public EtlResult etl(String task, List<String> params) {\n        EtlResult etlResult = new EtlResult();\n        KuduMappingConfig config = kuduMapping.get(task);\n        KuduEtlService hbaseEtlService = new KuduEtlService(kuduTemplate, config);\n        if (config != null) {\n            return hbaseEtlService.importData(params);\n        } else {\n            StringBuilder resultMsg = new StringBuilder();\n            boolean resSucc = true;\n            for (KuduMappingConfig configTmp : kuduMapping.values()) {\n                // 取所有的destination为task的配置\n                if (configTmp.getDestination().equals(task)) {\n                    EtlResult etlRes = hbaseEtlService.importData(params);\n                    if (!etlRes.getSucceeded()) {\n                        resSucc = false;\n                        resultMsg.append(etlRes.getErrorMessage()).append(\"\\n\");\n                    } else {\n                        resultMsg.append(etlRes.getResultMessage()).append(\"\\n\");\n                    }\n                }\n            }\n            if (resultMsg.length() > 0) {\n                etlResult.setSucceeded(resSucc);\n                if (resSucc) {\n                    etlResult.setResultMessage(resultMsg.toString());\n                } else {\n                    etlResult.setErrorMessage(resultMsg.toString());\n                }\n                return etlResult;\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public Map<String, Object> count(String task) {\n        Map<String, Object> res = new LinkedHashMap<>();\n        KuduMappingConfig config = kuduMapping.get(task);\n        if (config != null && config.getKuduMapping() != null) {\n            String tableName = config.getKuduMapping().getTargetTable();\n            long rowCount = kuduTemplate.countRow(tableName);\n            res.put(\"kuduTable\", tableName);\n            res.put(\"count\", rowCount);\n        }\n        return res;\n    }\n\n    @Override\n    public String getDestination(String task) {\n        KuduMappingConfig config = kuduMapping.get(task);\n        if (config != null && config.getKuduMapping() != null) {\n            return config.getDestination();\n        }\n        return null;\n    }\n\n    private void addSyncConfigToCache(String configName, KuduMappingConfig mappingConfig) {\n        String k;\n        if (envProperties != null && !\"tcp\".equalsIgnoreCase(envProperties.getProperty(\"canal.conf.mode\"))) {\n            k = StringUtils.trimToEmpty(mappingConfig.getDestination()) + \"-\"\n                    + StringUtils.trimToEmpty(mappingConfig.getGroupId()) + \"_\"\n                    + mappingConfig.getKuduMapping().getDatabase() + \"-\" + mappingConfig.getKuduMapping().getTable();\n        } else {\n            k = StringUtils.trimToEmpty(mappingConfig.getDestination()) + \"_\"\n                    + mappingConfig.getKuduMapping().getDatabase() + \"-\" + mappingConfig.getKuduMapping().getTable();\n        }\n        Map<String, KuduMappingConfig> configMap = mappingConfigCache.computeIfAbsent(k,\n                k1 -> new ConcurrentHashMap<>());\n        configMap.put(configName, mappingConfig);\n    }\n\n    public boolean addConfig(String fileName, KuduMappingConfig config) {\n        if (match(config)) {\n            kuduMapping.put(fileName, config);\n            addSyncConfigToCache(fileName, config);\n            FileName2KeyMapping.register(getClass().getAnnotation(SPI.class).value(), fileName,\n                    configuration.getKey());\n            return true;\n        }\n        return false;\n    }\n\n    public void updateConfig(String fileName, KuduMappingConfig config) {\n        if (config.getOuterAdapterKey() != null && !config.getOuterAdapterKey()\n                .equals(configuration.getKey())) {\n            // 理论上不允许改这个 因为本身就是通过这个关联起Adapter和Config的\n            throw new RuntimeException(\"not allow to change outAdapterKey\");\n        }\n        kuduMapping.put(fileName, config);\n        addSyncConfigToCache(fileName, config);\n    }\n\n    public void deleteConfig(String fileName) {\n        kuduMapping.remove(fileName);\n        for (Map<String, KuduMappingConfig> configMap : mappingConfigCache.values()) {\n            if (configMap != null) {\n                configMap.remove(fileName);\n            }\n        }\n        FileName2KeyMapping.unregister(getClass().getAnnotation(SPI.class).value(), fileName);\n    }\n\n    private boolean match(KuduMappingConfig config) {\n        boolean sameMatch = config.getOuterAdapterKey() != null && config.getOuterAdapterKey()\n                .equalsIgnoreCase(configuration.getKey());\n        boolean prefixMatch = config.getOuterAdapterKey() == null && configuration.getKey()\n                .startsWith(StringUtils\n                        .join(new String[]{Util.AUTO_GENERATED_PREFIX, config.getDestination(),\n                                config.getGroupId()}, '-'));\n        return sameMatch || prefixMatch;\n    }\n}\n"
  },
  {
    "path": "client-adapter/kudu/src/main/java/com/alibaba/otter/canal/client/adapter/kudu/config/KuduMappingConfig.java",
    "content": "package com.alibaba.otter.canal.client.adapter.kudu.config;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.apache.commons.lang.StringUtils;\n\nimport com.alibaba.otter.canal.client.adapter.support.AdapterConfig;\n\n/**\n * @author liuyadong\n * @description kudu配置文件映射\n */\npublic class KuduMappingConfig implements AdapterConfig {\n\n    private String      dataSourceKey;     // 数据源key\n\n    private String      destination;       // canal实例或MQ的topic\n\n    private String      groupId;           // groupId\n\n    private String      outerAdapterKey;   // 对应适配器的key\n\n    private boolean     concurrent = false; // 是否并行同步\n\n    private KuduMapping kuduMapping;       // db映射配置\n\n    @Override\n    public String getDataSourceKey() {\n        return dataSourceKey;\n    }\n\n    @Override\n    public AdapterMapping getMapping() {\n        return kuduMapping;\n    }\n\n    public void setDataSourceKey(String dataSourceKey) {\n        this.dataSourceKey = dataSourceKey;\n    }\n\n    public String getGroupId() {\n        return groupId;\n    }\n\n    public void setGroupId(String groupId) {\n        this.groupId = groupId;\n    }\n\n    public String getOuterAdapterKey() {\n        return outerAdapterKey;\n    }\n\n    public void setOuterAdapterKey(String outerAdapterKey) {\n        this.outerAdapterKey = outerAdapterKey;\n    }\n\n    public boolean getConcurrent() {\n        return concurrent;\n    }\n\n    public void setConcurrent(boolean concurrent) {\n        this.concurrent = concurrent;\n    }\n\n    public KuduMapping getKuduMapping() {\n        return kuduMapping;\n    }\n\n    public void setKuduMapping(KuduMapping kuduMapping) {\n        this.kuduMapping = kuduMapping;\n    }\n\n    public String getDestination() {\n        return destination;\n    }\n\n    public void setDestination(String destination) {\n        this.destination = destination;\n    }\n\n    public void validate() {\n        if (kuduMapping.database == null || kuduMapping.database.isEmpty()) {\n            throw new NullPointerException(\"KuduMapping.database\");\n        }\n    }\n\n    public static class KuduMapping implements AdapterMapping {\n\n        private String              database;                           // 数据库名或schema名\n        private String              table;                              // 表名\n        private Map<String, String> targetPk    = new LinkedHashMap<>(); // 目标表主键字段\n        private boolean             mapAll      = false;                // 映射所有字段\n        private String              targetDb;                           // 目标库名\n        private String              targetTable;                        // 目标表名\n        private Map<String, String> targetColumns;                      // 目标表字段映射\n\n        private String              etlCondition;                       // etl条件sql\n\n        private int                 readBatch   = 5000;\n        private int                 commitBatch = 5000;                 // etl等批量提交大小\n\n        private Map<String, String> allMapColumns;\n\n        public String getDatabase() {\n            return database;\n        }\n\n        public void setDatabase(String database) {\n            this.database = database;\n        }\n\n        public String getTable() {\n            return table;\n        }\n\n        public void setTable(String table) {\n            this.table = table;\n        }\n\n        public Map<String, String> getTargetPk() {\n            return targetPk;\n        }\n\n        public void setTargetPk(Map<String, String> targetPk) {\n            this.targetPk = targetPk;\n        }\n\n        public Boolean getMapAll() {\n            return mapAll;\n        }\n\n        public void setMapAll(Boolean mapAll) {\n            this.mapAll = mapAll;\n        }\n\n        public String getTargetDb() {\n            return targetDb;\n        }\n\n        public void setTargetDb(String targetDb) {\n            this.targetDb = targetDb;\n        }\n\n        public String getTargetTable() {\n            return targetTable;\n        }\n\n        public void setTargetTable(String targetTable) {\n            this.targetTable = targetTable;\n        }\n\n        public Map<String, String> getTargetColumns() {\n            if (targetColumns != null) {\n                targetColumns.forEach((key, value) -> {\n                    if (StringUtils.isEmpty(value)) {\n                        targetColumns.put(key, key);\n                    }\n                });\n            }\n            return targetColumns;\n        }\n\n        public void setTargetColumns(Map<String, String> targetColumns) {\n            this.targetColumns = targetColumns;\n        }\n\n        public String getEtlCondition() {\n            return etlCondition;\n        }\n\n        public void setEtlCondition(String etlCondition) {\n            this.etlCondition = etlCondition;\n        }\n\n        public int getReadBatch() {\n            return readBatch;\n        }\n\n        public void setReadBatch(int readBatch) {\n            this.readBatch = readBatch;\n        }\n\n        public int getCommitBatch() {\n            return commitBatch;\n        }\n\n        public void setCommitBatch(int commitBatch) {\n            this.commitBatch = commitBatch;\n        }\n\n        public Map<String, String> getAllMapColumns() {\n            return allMapColumns;\n        }\n\n        public void setAllMapColumns(Map<String, String> allMapColumns) {\n            this.allMapColumns = allMapColumns;\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/kudu/src/main/java/com/alibaba/otter/canal/client/adapter/kudu/config/KuduMappingConfigLoader.java",
    "content": "package com.alibaba.otter.canal.client.adapter.kudu.config;\n\nimport com.alibaba.otter.canal.client.adapter.support.YamlUtils;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.client.adapter.support.MappingConfigsLoader;\n\n/**\n * @author liuyadong\n * @description kudu表信息加载\n */\npublic class KuduMappingConfigLoader {\n\n    private static Logger logger = LoggerFactory.getLogger(KuduMappingConfigLoader.class);\n\n    /**\n     * 加载HBase表映射配置\n     *\n     * @return 配置名/配置文件名--对象\n     */\n    public static Map<String, KuduMappingConfig> load(Properties envProperties) {\n        logger.info(\"## Start loading kudu mapping config ... \");\n\n        Map<String, KuduMappingConfig> result = new LinkedHashMap<>();\n\n        Map<String, String> configContentMap = MappingConfigsLoader.loadConfigs(\"kudu\");\n        configContentMap.forEach((fileName, content) -> {\n            KuduMappingConfig config = YamlUtils.ymlToObj(null, content, KuduMappingConfig.class, null, envProperties);\n            if (config == null) {\n                return;\n            }\n            try {\n                config.validate();\n            } catch (Exception e) {\n                throw new RuntimeException(\"ERROR load Config: \" + fileName + \" \" + e.getMessage(), e);\n            }\n            result.put(fileName, config);\n        });\n\n        logger.info(\"## kudu mapping config loaded\");\n        return result;\n    }\n}\n"
  },
  {
    "path": "client-adapter/kudu/src/main/java/com/alibaba/otter/canal/client/adapter/kudu/monitor/KuduConfigMonitor.java",
    "content": "package com.alibaba.otter.canal.client.adapter.kudu.monitor;\n\nimport com.alibaba.otter.canal.client.adapter.kudu.KuduAdapter;\nimport com.alibaba.otter.canal.client.adapter.kudu.config.KuduMappingConfig;\nimport com.alibaba.otter.canal.client.adapter.support.MappingConfigsLoader;\nimport com.alibaba.otter.canal.client.adapter.support.Util;\nimport com.alibaba.otter.canal.client.adapter.support.YamlUtils;\nimport java.io.File;\nimport java.util.Properties;\nimport org.apache.commons.io.filefilter.FileFilterUtils;\nimport org.apache.commons.io.monitor.FileAlterationListenerAdaptor;\nimport org.apache.commons.io.monitor.FileAlterationMonitor;\nimport org.apache.commons.io.monitor.FileAlterationObserver;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * @author liuyadong\n * @description 配置文件监听\n */\npublic class KuduConfigMonitor {\n\n    private static final Logger   logger      = LoggerFactory.getLogger(KuduConfigMonitor.class);\n\n    private static final String   adapterName = \"kudu\";\n\n    private KuduAdapter           kuduAdapter;\n\n    private Properties            envProperties;\n\n    private FileAlterationMonitor fileMonitor;\n\n    public void init(KuduAdapter kuduAdapter, Properties envProperties) {\n        this.kuduAdapter = kuduAdapter;\n        this.envProperties = envProperties;\n        File confDir = Util.getConfDirPath(adapterName);\n        try {\n            FileAlterationObserver observer = new FileAlterationObserver(confDir,\n                FileFilterUtils.and(FileFilterUtils.fileFileFilter(), FileFilterUtils.suffixFileFilter(\"yml\")));\n            FileListener listener = new FileListener();\n            observer.addListener(listener);\n            fileMonitor = new FileAlterationMonitor(3000, observer);\n            fileMonitor.start();\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n        }\n    }\n\n    /**\n     * 停止监听配置文件\n     */\n    public void destroy() {\n        try {\n            fileMonitor.stop();\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n        }\n    }\n\n    /**\n     * 配置文件监听\n     */\n    private class FileListener extends FileAlterationListenerAdaptor {\n\n        @Override\n        public void onFileCreate(File file) {\n            super.onFileCreate(file);\n\n            try {\n                // 加载新增的配置文件\n                String configContent = MappingConfigsLoader.loadConfig(adapterName + File.separator + file.getName());\n                KuduMappingConfig config = YamlUtils\n                    .ymlToObj(null, configContent, KuduMappingConfig.class, null, envProperties);\n                if (config == null) {\n                    return;\n                }\n                config.validate();\n                boolean result = kuduAdapter.addConfig(file.getName(), config);\n                if (result) {\n                    logger.info(\"Add a new kudu mapping config: {} to canal adapter\", file.getName());\n                }\n            } catch (Exception e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n\n        @Override\n        public void onFileChange(File file) {\n            super.onFileChange(file);\n\n            try {\n                if (kuduAdapter.getKuduMapping().containsKey(file.getName())) {\n                    // 加载配置文件\n                    String configContent = MappingConfigsLoader\n                        .loadConfig(adapterName + File.separator + file.getName());\n                    if (configContent == null) {\n                        onFileDelete(file);\n                        return;\n                    }\n                    KuduMappingConfig config = YamlUtils\n                        .ymlToObj(null, configContent, KuduMappingConfig.class, null, envProperties);\n                    if (config == null) {\n                        return;\n                    }\n                    config.validate();\n                    kuduAdapter.updateConfig(file.getName(), config);\n                }\n            } catch (Exception e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n\n        @Override\n        public void onFileDelete(File file) {\n            super.onFileDelete(file);\n\n            try {\n                if (kuduAdapter.getKuduMapping().containsKey(file.getName())) {\n                    kuduAdapter.deleteConfig(file.getName());\n                    logger.info(\"Delete a hbase mapping config: {} of canal adapter\", file.getName());\n                }\n            } catch (Exception e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/kudu/src/main/java/com/alibaba/otter/canal/client/adapter/kudu/service/KuduEtlService.java",
    "content": "package com.alibaba.otter.canal.client.adapter.kudu.service;\n\nimport java.sql.ResultSetMetaData;\nimport java.sql.SQLException;\nimport java.util.*;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport javax.sql.DataSource;\n\nimport org.apache.kudu.client.KuduException;\n\nimport com.alibaba.otter.canal.client.adapter.kudu.config.KuduMappingConfig;\nimport com.alibaba.otter.canal.client.adapter.kudu.support.KuduTemplate;\nimport com.alibaba.otter.canal.client.adapter.kudu.support.SyncUtil;\nimport com.alibaba.otter.canal.client.adapter.support.AbstractEtlService;\nimport com.alibaba.otter.canal.client.adapter.support.AdapterConfig;\nimport com.alibaba.otter.canal.client.adapter.support.EtlResult;\nimport com.alibaba.otter.canal.client.adapter.support.Util;\nimport com.google.common.base.Joiner;\n\n/**\n * @author liuyadong\n * @description kudu 拉取历史数据\n */\npublic class KuduEtlService extends AbstractEtlService {\n\n    private KuduTemplate      kuduTemplate;\n    private KuduMappingConfig config;\n\n    public KuduEtlService(KuduTemplate kuduTemplate, KuduMappingConfig config){\n        super(\"kudu\", config);\n        this.kuduTemplate = kuduTemplate;\n        this.config = config;\n    }\n\n    public EtlResult importData(List<String> params) {\n        EtlResult etlResult = new EtlResult();\n        List<String> errMsg = new ArrayList<>();\n\n        KuduMappingConfig.KuduMapping kuduMapping = config.getKuduMapping();\n        boolean flag = kuduTemplate.tableExists(kuduMapping.getTargetTable());\n        // 表不存在，停止导入\n        if (!flag) {\n            logger.info(\"{} is don't exist , please check your kudu table !\", kuduMapping.getTargetTable());\n            errMsg.add(kuduMapping.getTargetTable() + \" is don't hava,please check your kudu table !\");\n            etlResult.setErrorMessage(Joiner.on(\"\\n\").join(errMsg));\n            return etlResult;\n        }\n        logger.info(\"{} etl is starting!\", kuduMapping.getTargetTable());\n        String sql = \"SELECT * FROM \" + SyncUtil.getDbTableName(kuduMapping);\n        return importData(sql, params);\n    }\n\n    @Override\n    protected boolean executeSqlImport(DataSource ds, String sql, List<Object> values,\n                                       AdapterConfig.AdapterMapping mapping, AtomicLong impCount, List<String> errMsg) {\n        KuduMappingConfig.KuduMapping kuduMapping = (KuduMappingConfig.KuduMapping) mapping;\n        // 获取字段元数据\n        Map<String, String> columnsMap = new LinkedHashMap<>();// 需要同步的字段\n\n        try {\n            Util.sqlRS(ds, \"SELECT * FROM \" + SyncUtil.getDbTableName(kuduMapping) + \" LIMIT 1\", rs -> {\n                try {\n                    ResultSetMetaData rsd = rs.getMetaData();\n                    int columnCount = rsd.getColumnCount();\n                    List<String> columns = new ArrayList<>();\n                    for (int i = 1; i <= columnCount; i++) {\n                        columns.add(rsd.getColumnName(i).toLowerCase());\n                    }\n                    columnsMap.putAll(SyncUtil.getColumnsMap(kuduMapping, columns));\n                    return true;\n                } catch (Exception e) {\n                    logger.error(e.getMessage(), e);\n                    return false;\n                }\n            });\n            // 写入数据\n            logger.info(\"etl select data sql is :{}\", sql);\n            Util.sqlRS(ds, sql, values, rs -> {\n                int idx = 1;\n                try {\n                    List<Map<String, Object>> dataList = new ArrayList<>();\n                    while (rs.next()) {\n                        Map<String, Object> data = new HashMap<>();\n                        for (Map.Entry<String, String> entry : columnsMap.entrySet()) {\n                            String mysqlColumnName = entry.getKey();// mysql字段名\n                            String kuduColumnName = entry.getValue();// kudu字段名\n                            if (kuduColumnName == null) {\n                                kuduColumnName = mysqlColumnName;\n                            }\n                            Object value = rs.getObject(kuduColumnName);\n                            if (value != null) {\n                                data.put(kuduColumnName, value);\n                            } else {\n                                data.put(kuduColumnName, null);\n                            }\n                        }\n                        dataList.add(data);\n                        idx++;\n                        impCount.incrementAndGet();\n                        if (logger.isDebugEnabled()) {\n                            logger.debug(\"successful import count:\" + impCount.get());\n                        }\n                        if (idx % kuduMapping.getCommitBatch() == 0) {\n                            kuduTemplate.upsert(kuduMapping.getTargetTable(), dataList);\n                            dataList.clear();\n                        }\n                    }\n                    if (!dataList.isEmpty()) {\n                        kuduTemplate.upsert(kuduMapping.getTargetTable(), dataList);\n                    }\n                    return true;\n\n                } catch (SQLException | KuduException e) {\n                    e.printStackTrace();\n                    logger.error(kuduMapping.getTargetTable() + \" etl failed! ==>\" + e.getMessage(), e);\n                    errMsg.add(kuduMapping.getTargetTable() + \" etl failed! ==>\" + e.getMessage());\n                    return false;\n                }\n            });\n            return true;\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n            return false;\n        }\n\n    }\n}\n"
  },
  {
    "path": "client-adapter/kudu/src/main/java/com/alibaba/otter/canal/client/adapter/kudu/service/KuduSyncService.java",
    "content": "package com.alibaba.otter.canal.client.adapter.kudu.service;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.kudu.client.KuduException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.JSONWriter.Feature;\nimport com.alibaba.otter.canal.client.adapter.kudu.config.KuduMappingConfig;\nimport com.alibaba.otter.canal.client.adapter.kudu.support.KuduTemplate;\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\n\n/**\n * @author liuyadong\n * @description kudu实时同步\n */\npublic class KuduSyncService {\n\n    private static Logger logger = LoggerFactory.getLogger(KuduSyncService.class);\n\n    private KuduTemplate  kuduTemplate;\n\n    // 源库表字段类型缓存: instance.schema.table -> <columnName, jdbcType>\n    // private Map<String, Map<String, Integer>> columnsTypeCache = new\n    // ConcurrentHashMap<>();\n\n    public KuduSyncService(KuduTemplate kuduTemplate){\n        this.kuduTemplate = kuduTemplate;\n    }\n\n    // public Map<String, Map<String, Integer>> getColumnsTypeCache() {\n    // return columnsTypeCache;\n    // }\n\n    /**\n     * 同步事件处理\n     *\n     * @param config\n     * @param dml\n     */\n    public void sync(KuduMappingConfig config, Dml dml) {\n        if (config != null) {\n            String type = dml.getType();\n            if (type != null && type.equalsIgnoreCase(\"INSERT\")) {\n                insert(config, dml);\n            } else if (type != null && type.equalsIgnoreCase(\"UPDATE\")) {\n                upsert(config, dml);\n            } else if (type != null && type.equalsIgnoreCase(\"DELETE\")) {\n                delete(config, dml);\n            }\n            if (logger.isDebugEnabled()) {\n                logger.debug(\"DML: {}\", JSON.toJSONString(dml, Feature.WriteNulls));\n            }\n        }\n    }\n\n    /**\n     * 删除事件\n     *\n     * @param config\n     * @param dml\n     */\n    private void delete(KuduMappingConfig config, Dml dml) {\n        KuduMappingConfig.KuduMapping kuduMapping = config.getKuduMapping();\n        String configTable = kuduMapping.getTable();\n        String configDatabase = kuduMapping.getDatabase();\n        String table = dml.getTable();\n        String database = dml.getDatabase();\n        if (configTable.equals(table) && configDatabase.equals(database)) {\n            List<Map<String, Object>> data = dml.getData();\n            if (data == null || data.isEmpty()) {\n                return;\n            }\n            // 判定主键映射\n            String pkId = \"\";\n            Map<String, String> targetPk = kuduMapping.getTargetPk();\n            for (Map.Entry<String, String> entry : targetPk.entrySet()) {\n                String mysqlID = entry.getKey().toLowerCase();\n                String kuduID = entry.getValue();\n                if (kuduID == null) {\n                    pkId = mysqlID;\n                } else {\n                    pkId = kuduID;\n                }\n            }\n            // 切割联合主键\n            List<String> pkIds = Arrays.asList(pkId.split(\",\"));\n            try {\n                int idx = 1;\n                boolean completed = false;\n                List<Map<String, Object>> dataList = new ArrayList<>();\n\n                for (Map<String, Object> item : data) {\n                    Map<String, Object> primaryKeyMap = new HashMap<>();\n                    for (Map.Entry<String, Object> entry : item.entrySet()) {\n                        String columnName = entry.getKey().toLowerCase();\n                        Object value = entry.getValue();\n                        if (pkIds.contains(columnName)) {\n                            primaryKeyMap.put(columnName, value);\n                        }\n                    }\n                    dataList.add(primaryKeyMap);\n                    idx++;\n                    if (idx % kuduMapping.getCommitBatch() == 0) {\n                        kuduTemplate.delete(kuduMapping.getTargetTable(), dataList);\n                        dataList.clear();\n                        completed = true;\n                    }\n                }\n                if (!completed) {\n                    kuduTemplate.delete(kuduMapping.getTargetTable(), dataList);\n                }\n            } catch (KuduException e) {\n                logger.error(e.getMessage());\n                logger.error(\"DML: {}\", JSON.toJSONString(dml, Feature.WriteNulls));\n            }\n        }\n    }\n\n    /**\n     * 更新插入事件\n     *\n     * @param config\n     * @param dml\n     */\n    private void upsert(KuduMappingConfig config, Dml dml) {\n        KuduMappingConfig.KuduMapping kuduMapping = config.getKuduMapping();\n        String configTable = kuduMapping.getTable();\n        String configDatabase = kuduMapping.getDatabase();\n        String table = dml.getTable();\n        String database = dml.getDatabase();\n        if (configTable.equals(table) && configDatabase.equals(database)) {\n            List<Map<String, Object>> data = dml.getData();\n            if (data == null || data.isEmpty()) {\n                return;\n            }\n            try {\n                int idx = 1;\n                boolean completed = false;\n                List<Map<String, Object>> dataList = new ArrayList<>();\n\n                for (Map<String, Object> entry : data) {\n                    dataList.add(entry);\n                    idx++;\n                    if (idx % kuduMapping.getCommitBatch() == 0) {\n                        kuduTemplate.upsert(kuduMapping.getTargetTable(), dataList);\n                        dataList.clear();\n                        completed = true;\n                    }\n                }\n                if (!completed) {\n                    kuduTemplate.upsert(kuduMapping.getTargetTable(), dataList);\n                }\n            } catch (KuduException e) {\n                logger.error(e.getMessage());\n                logger.error(\"DML: {}\", JSON.toJSONString(dml, Feature.WriteNulls));\n            }\n        }\n\n    }\n\n    /**\n     * 插入事件\n     *\n     * @param config\n     * @param dml\n     */\n    private void insert(KuduMappingConfig config, Dml dml) {\n        KuduMappingConfig.KuduMapping kuduMapping = config.getKuduMapping();\n        String configTable = kuduMapping.getTable();\n        String configDatabase = kuduMapping.getDatabase();\n        String table = dml.getTable();\n        String database = dml.getDatabase();\n        if (configTable.equals(table) && configDatabase.equals(database)) {\n            List<Map<String, Object>> data = dml.getData();\n            if (data == null || data.isEmpty()) {\n                return;\n            }\n            try {\n                int idx = 1;\n                boolean completed = false;\n                List<Map<String, Object>> dataList = new ArrayList<>();\n\n                for (Map<String, Object> entry : data) {\n                    dataList.add(entry);\n                    idx++;\n                    if (idx % kuduMapping.getCommitBatch() == 0) {\n                        kuduTemplate.insert(kuduMapping.getTargetTable(), dataList);\n                        dataList.clear();\n                        completed = true;\n                    }\n                }\n                if (!completed) {\n                    kuduTemplate.insert(kuduMapping.getTargetTable(), dataList);\n                }\n            } catch (KuduException e) {\n                logger.error(e.getMessage());\n                logger.error(\"DML: {}\", JSON.toJSONString(dml, Feature.WriteNulls));\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "client-adapter/kudu/src/main/java/com/alibaba/otter/canal/client/adapter/kudu/support/KuduTemplate.java",
    "content": "package com.alibaba.otter.canal.client.adapter.kudu.support;\n\nimport java.io.IOException;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Arrays;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.kudu.ColumnSchema;\nimport org.apache.kudu.Schema;\nimport org.apache.kudu.Type;\nimport org.apache.kudu.client.Delete;\nimport org.apache.kudu.client.Insert;\nimport org.apache.kudu.client.KuduClient;\nimport org.apache.kudu.client.KuduException;\nimport org.apache.kudu.client.KuduScanner;\nimport org.apache.kudu.client.KuduSession;\nimport org.apache.kudu.client.KuduTable;\nimport org.apache.kudu.client.OperationResponse;\nimport org.apache.kudu.client.PartialRow;\nimport org.apache.kudu.client.SessionConfiguration;\nimport org.apache.kudu.client.Upsert;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * @author liuyadong\n * @description kudu 操作工具类\n */\npublic class KuduTemplate {\n\n    private Logger           logger          = LoggerFactory.getLogger(this.getClass());\n\n    private KuduClient       kuduClient;\n    private String           masters;\n\n    private final static int OPERATION_BATCH = 500;\n\n    private SimpleDateFormat sdf             = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n\n    public KuduTemplate(String master_str){\n        this.masters = master_str;\n        checkClient();\n    }\n\n    /**\n     * 检车连接\n     */\n    private void checkClient() {\n        if (kuduClient == null) {\n            // kudu master 以逗号分隔\n            List<String> masterList = Arrays.asList(masters.split(\",\"));\n            kuduClient = new KuduClient.KuduClientBuilder(masterList).defaultOperationTimeoutMs(60000)\n                .defaultSocketReadTimeoutMs(60000)\n                .defaultAdminOperationTimeoutMs(60000)\n                .build();\n        }\n    }\n\n    /**\n     * 查询表是否存在\n     *\n     * @param tableName\n     * @return\n     */\n    public boolean tableExists(String tableName) {\n        this.checkClient();\n        try {\n            return kuduClient.tableExists(tableName);\n        } catch (KuduException e) {\n            logger.error(\"kudu table exists check fail,message :{}\", e.getMessage());\n            return true;\n        }\n    }\n\n    /**\n     * 删除行\n     *\n     * @param tableName\n     * @param dataList\n     * @throws KuduException\n     */\n    public void delete(String tableName, List<Map<String, Object>> dataList) throws KuduException {\n        this.checkClient();\n        KuduTable kuduTable = kuduClient.openTable(tableName);\n        KuduSession session = kuduClient.newSession();\n        try {\n            session.setFlushMode(SessionConfiguration.FlushMode.MANUAL_FLUSH);\n            session.setMutationBufferSpace(OPERATION_BATCH);\n            // 获取元数据结构\n            Map<String, Type> metaMap = new HashMap<>();\n            Schema schema = kuduTable.getSchema();\n            for (ColumnSchema columnSchema : schema.getColumns()) {\n                String colName = columnSchema.getName().toLowerCase();\n                Type type = columnSchema.getType();\n                metaMap.put(colName, type);\n            }\n            int uncommit = 0;\n            for (Map<String, Object> data : dataList) {\n                Delete delete = kuduTable.newDelete();\n                PartialRow row = delete.getRow();\n                for (Map.Entry<String, Object> entry : data.entrySet()) {\n                    String name = entry.getKey().toLowerCase();\n                    Type type = metaMap.get(name);\n                    Object value = entry.getValue();\n                    fillRow(row, name, value, type); // 填充行数据\n                }\n                session.apply(delete);\n                // 对于手工提交, 需要buffer在未满的时候flush,这里采用了buffer一半时即提交\n                uncommit = uncommit + 1;\n                if (uncommit > OPERATION_BATCH / 3 * 2) {\n                    List<OperationResponse> delete_option = session.flush();\n                    if (delete_option.size() > 0) {\n                        OperationResponse response = delete_option.get(0);\n                        if (response.hasRowError()) {\n                            logger.error(\"delete row fail table name is :{} \", tableName);\n                            logger.error(\"error list is :{}\", response.getRowError().getMessage());\n                        }\n                    }\n                    uncommit = 0;\n                }\n            }\n            List<OperationResponse> delete_option = session.flush();\n            if (delete_option.size() > 0) {\n                OperationResponse response = delete_option.get(0);\n                if (response.hasRowError()) {\n                    logger.error(\"delete row fail table name is :{} \", tableName);\n                    logger.error(\"error list is :{}\", response.getRowError().getMessage());\n                }\n            }\n\n        } catch (KuduException e) {\n            logger.error(\"error message is :{}\", dataList.toString());\n            throw e;\n        } finally {\n            if (!session.isClosed()) {\n                session.close();\n            }\n        }\n    }\n\n    /**\n     * 更新/插入字段\n     *\n     * @param tableName\n     * @param dataList\n     * @throws KuduException\n     */\n    public void upsert(String tableName, List<Map<String, Object>> dataList) throws KuduException {\n        this.checkClient();\n        KuduTable kuduTable = kuduClient.openTable(tableName);\n        KuduSession session = kuduClient.newSession();\n        try {\n            session.setFlushMode(SessionConfiguration.FlushMode.MANUAL_FLUSH);\n            session.setMutationBufferSpace(OPERATION_BATCH);\n            // 获取元数据结构\n            Map<String, Type> metaMap = new HashMap<>();\n            Schema schema = kuduTable.getSchema();\n            for (ColumnSchema columnSchema : schema.getColumns()) {\n                String colName = columnSchema.getName().toLowerCase();\n                Type type = columnSchema.getType();\n                metaMap.put(colName, type);\n            }\n            int uncommit = 0;\n            for (Map<String, Object> data : dataList) {\n                Upsert upsert = kuduTable.newUpsert();\n                PartialRow row = upsert.getRow();\n                for (Map.Entry<String, Object> entry : data.entrySet()) {\n                    String name = entry.getKey().toLowerCase();\n                    Type type = metaMap.get(name);\n                    Object value = entry.getValue();\n                    fillRow(row, name, value, type); // 填充行数据\n                }\n                session.apply(upsert);\n                // 对于手工提交, 需要buffer在未满的时候flush,这里采用了buffer一半时即提交\n                uncommit = uncommit + 1;\n                if (uncommit > OPERATION_BATCH / 3 * 2) {\n                    List<OperationResponse> update_option = session.flush();\n                    if (update_option.size() > 0) {\n                        OperationResponse response = update_option.get(0);\n                        if (response.hasRowError()) {\n                            logger.error(\"update row fail table name is :{} \", tableName);\n                            logger.error(\"update list is :{}\", response.getRowError().getMessage());\n                        }\n                    }\n                    uncommit = 0;\n                }\n            }\n            List<OperationResponse> update_option = session.flush();\n            if (update_option.size() > 0) {\n                OperationResponse response = update_option.get(0);\n                if (response.hasRowError()) {\n                    logger.error(\"update row fail table name is :{} \", tableName);\n                    logger.error(\"update list is :{}\", response.getRowError().getMessage());\n                }\n            }\n        } catch (KuduException e) {\n            logger.error(\"error message is :{}\", dataList.toString());\n            throw e;\n        } finally {\n            if (!session.isClosed()) {\n                session.close();\n            }\n        }\n\n    }\n\n    /**\n     * 插入数据\n     *\n     * @param tableName\n     * @param dataList\n     * @throws KuduException\n     */\n    public void insert(String tableName, List<Map<String, Object>> dataList) throws KuduException {\n        this.checkClient();\n        KuduTable kuduTable = kuduClient.openTable(tableName);// 打开表\n        KuduSession session = kuduClient.newSession(); // 创建写session,kudu必须通过session写入\n        try {\n            session.setFlushMode(SessionConfiguration.FlushMode.MANUAL_FLUSH); // 采取Flush方式\n                                                                               // 手动刷新\n            session.setMutationBufferSpace(OPERATION_BATCH);\n            // 获取元数据结构\n            Map<String, Type> metaMap = new HashMap<>();\n            Schema schema = kuduTable.getSchema();\n            for (ColumnSchema columnSchema : schema.getColumns()) {\n                String colName = columnSchema.getName().toLowerCase();\n                Type type = columnSchema.getType();\n                metaMap.put(colName, type);\n            }\n            int uncommit = 0;\n            for (Map<String, Object> data : dataList) {\n                Insert insert = kuduTable.newInsert();\n                PartialRow row = insert.getRow();\n                for (Map.Entry<String, Object> entry : data.entrySet()) {\n                    String name = entry.getKey().toLowerCase();\n                    Type type = metaMap.get(name);\n                    Object value = entry.getValue();\n                    fillRow(row, name, value, type); // 填充行数据\n                }\n                session.apply(insert);\n                // 对于手工提交, 需要buffer在未满的时候flush,这里采用了buffer一半时即提交\n                uncommit = uncommit + 1;\n                if (uncommit > OPERATION_BATCH / 3 * 2) {\n                    List<OperationResponse> insert_option = session.flush();\n                    if (insert_option.size() > 0) {\n                        OperationResponse response = insert_option.get(0);\n                        if (response.hasRowError()) {\n                            logger.error(\"insert row fail table name is :{} \", tableName);\n                            logger.error(\"insert list is :{}\", response.getRowError().getMessage());\n                        }\n                    }\n                    uncommit = 0;\n                }\n            }\n            List<OperationResponse> insert_option = session.flush();\n            if (insert_option.size() > 0) {\n                OperationResponse response = insert_option.get(0);\n                if (response.hasRowError()) {\n                    logger.error(\"insert row fail table name is :{} \", tableName);\n                    logger.error(\"insert list is :{}\", response.getRowError().getMessage());\n                }\n            }\n        } catch (KuduException e) {\n            logger.error(\"error message is :{}\", dataList.toString());\n            throw e;\n        } finally {\n            if (!session.isClosed()) {\n                session.close();\n            }\n        }\n\n    }\n\n    /**\n     * 统计kudu表数据\n     *\n     * @param tableName\n     * @return\n     */\n    public long countRow(String tableName) {\n        this.checkClient();\n        long rowCount = 0L;\n        try {\n            KuduTable kuduTable = kuduClient.openTable(tableName);\n            // 创建scanner扫描\n            KuduScanner scanner = kuduClient.newScannerBuilder(kuduTable).build();\n            // 遍历数据\n            while (scanner.hasMoreRows()) {\n                while (scanner.nextRows().hasNext()) {\n                    rowCount++;\n                }\n            }\n        } catch (KuduException e) {\n            e.printStackTrace();\n        }\n        return rowCount;\n    }\n\n    /**\n     * 关闭钩子\n     *\n     * @throws IOException\n     */\n    public void closeKuduClient() {\n        if (kuduClient != null) {\n            try {\n                kuduClient.close();\n            } catch (Exception e) {\n                logger.error(\"ShutdownHook Close KuduClient Error! error message {}\", e.getMessage());\n            }\n        }\n    }\n\n    /**\n     * 封装kudu行数据\n     *\n     * @param row\n     * @param rawVal\n     * @param type\n     */\n    private void fillRow(PartialRow row, String colName, Object rawVal, Type type) {\n        String rowValue = \"0\";\n        if (!(rawVal == null || \"\".equals(rawVal))) {\n            rowValue = rawVal + \"\";\n        } else {\n            return;\n        }\n        if (type == null) {\n            logger.warn(\"got unknown type {} for column '{}'-- ignoring this column\", type, colName);\n            return;\n        }\n        try {\n            switch (type) {\n                case INT8:\n                    row.addByte(colName, Byte.parseByte(rowValue));\n                    break;\n                case INT16:\n                    row.addShort(colName, Short.parseShort(rowValue));\n                    break;\n                case INT32:\n                    row.addInt(colName, Integer.parseInt(rowValue));\n                    break;\n                case INT64:\n                    row.addLong(colName, Long.parseLong(rowValue));\n                    break;\n                case BINARY:\n                    row.addBinary(colName, rowValue.getBytes());\n                    break;\n                case STRING:\n                    row.addString(colName, rowValue);\n                    break;\n                case BOOL:\n                    if (!(\"true\".equalsIgnoreCase(rowValue) || \"false\".equalsIgnoreCase(rowValue))) {\n                        return;\n                    }\n                    row.addBoolean(colName, Boolean.parseBoolean(rowValue));\n                    break;\n                case FLOAT:\n                    row.addFloat(colName, Float.parseFloat(rowValue));\n                    break;\n                case DOUBLE:\n                    row.addDouble(colName, Double.parseDouble(rowValue));\n                    break;\n                case UNIXTIME_MICROS:\n                    if (\"0\".equals(rowValue)) {\n                        try {\n                            Date parse = sdf.parse(\"2099-11-11 11:11:11\");\n                            row.addLong(colName, parse.getTime());\n                        } catch (ParseException e) {\n                            logger.warn(\"date column is null\");\n                        }\n                    } else {\n                        try {\n                            Date parse = rowValue.length() > 19 ? sdf.parse(rowValue.substring(0, 19)) : sdf.parse(rowValue);\n                            row.addLong(colName, parse.getTime());\n                        } catch (ParseException e) {\n                            logger.warn(\"date format error, error data is :{}\", rowValue);\n                            try {\n                                Date parse = sdf.parse(\"2099-11-11 11:11:11\");\n                                row.addLong(colName, parse.getTime());\n                            } catch (ParseException ie) {\n                                logger.warn(\"date column is null\");\n                            }\n                        }\n                    }\n                    break;\n                default:\n                    logger.warn(\"got unknown type {} for column '{}'-- ignoring this column\", type, colName);\n            }\n        } catch (NumberFormatException e) {\n            logger.error(e.getMessage());\n            logger.error(\"column parse fail==> column name=>{},column type=>{},column value=>{}\", colName, type, rawVal);\n        }\n    }\n\n    /**\n     * kudu数据类型映射\n     *\n     * @param\n     */\n    private Type toKuduType(String mysqlType) throws IllegalArgumentException {\n\n        switch (mysqlType) {\n            case \"varchar\":\n                return Type.STRING;\n            case \"int\":\n                return Type.INT8;\n            case \"decimal\":\n                return Type.DOUBLE;\n            case \"double\":\n                return Type.DOUBLE;\n            case \"datetime\":\n                return Type.STRING;\n            case \"timestamp\":\n                return Type.STRING;\n            default:\n                throw new IllegalArgumentException(\"The provided data type doesn't map to know any known one.\");\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/kudu/src/main/java/com/alibaba/otter/canal/client/adapter/kudu/support/SyncUtil.java",
    "content": "package com.alibaba.otter.canal.client.adapter.kudu.support;\n\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.lang.StringUtils;\n\nimport com.alibaba.otter.canal.client.adapter.kudu.config.KuduMappingConfig;\n\n/**\n * @author liuyadong\n * @description 工具\n */\npublic class SyncUtil {\n\n    /**\n     * 获取源数据库 元数据结构\n     *\n     * @param kuduMapping\n     * @return\n     */\n    public static String getDbTableName(KuduMappingConfig.KuduMapping kuduMapping) {\n        String result = \"\";\n        if (StringUtils.isNotEmpty(kuduMapping.getTable())) {\n            result += kuduMapping.getDatabase() + \".\";\n        }\n        result += kuduMapping.getTable();\n        return result;\n    }\n\n    /**\n     * 过滤转换字段\n     *\n     * @param kuduMapping\n     * @param columns\n     * @return\n     */\n    public static Map<String, String> getColumnsMap(KuduMappingConfig.KuduMapping kuduMapping, List<String> columns) {\n        Map<String, String> columnsMap;\n        if (kuduMapping.getMapAll()) {\n            if (kuduMapping.getAllMapColumns() != null) {\n                return kuduMapping.getAllMapColumns();\n            }\n            columnsMap = new LinkedHashMap<>();\n            for (String srcColumn : columns) {\n                boolean flag = true;\n                if (kuduMapping.getTargetColumns() != null) {\n                    for (Map.Entry<String, String> entry : kuduMapping.getTargetColumns().entrySet()) {\n                        if (srcColumn.equals(entry.getValue())) {\n                            columnsMap.put(entry.getKey(), srcColumn);\n                            flag = false;\n                            break;\n                        }\n                    }\n                }\n                if (flag) {\n                    columnsMap.put(srcColumn, srcColumn);\n                }\n            }\n            kuduMapping.setAllMapColumns(columnsMap);\n        } else {\n            columnsMap = kuduMapping.getTargetColumns();\n        }\n        return columnsMap;\n    }\n\n}\n"
  },
  {
    "path": "client-adapter/kudu/src/main/resources/META-INF.canal/com.alibaba.otter.canal.client.adapter.OuterAdapter",
    "content": "kudu=com.alibaba.otter.canal.client.adapter.kudu.KuduAdapter"
  },
  {
    "path": "client-adapter/kudu/src/main/resources/kudu/kudutest_user.yml",
    "content": "dataSourceKey: defaultDS\ndestination: test_instance\nouterAdapterKey: kudu\ngroupId: g1\nkuduMapping:\n  database: test\n  table: test\n  targetTable: test\n  targetPk:\n    id: id\n  mapAll: true\n  targetColumns:\n    id:\n    name:\n    role_id:\n    c_time:\n    test1:\n  etlCondition:\n  commitBatch: 3000 # 批量提交的大小"
  },
  {
    "path": "client-adapter/kudu/src/test/java/com/alibaba/otter/canal/client/adapter/kudu/test/KuduConnectionTest.java",
    "content": "package com.alibaba.otter.canal.client.adapter.kudu.test;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.apache.kudu.client.KuduClient;\nimport org.apache.kudu.client.KuduException;\nimport org.apache.kudu.client.KuduTable;\nimport org.junit.Test;\n\npublic class KuduConnectionTest {\n\n    @Test\n    public void test01() {\n        List<String> masterList = Arrays.asList(\"10.6.36.102:7051,10.6.36.187:7051,10.6.36.229:7051\".split(\",\"));\n        KuduClient kuduClient = new KuduClient.KuduClientBuilder(masterList).defaultOperationTimeoutMs(60000)\n            .defaultSocketReadTimeoutMs(30000)\n            .defaultAdminOperationTimeoutMs(60000)\n            .build();\n        try {\n            List<String> tablesList = kuduClient.getTablesList().getTablesList();\n            System.out.println(tablesList.toString());\n            KuduTable web_white_list = kuduClient.openTable(\"web_white_list\");\n\n        } catch (KuduException e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/kudu/src/test/java/com/alibaba/otter/canal/client/adapter/kudu/test/TestConfig.java",
    "content": "package com.alibaba.otter.canal.client.adapter.kudu.test;\n\nimport java.util.Map;\n\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.client.adapter.kudu.config.KuduMappingConfig;\nimport com.alibaba.otter.canal.client.adapter.kudu.config.KuduMappingConfigLoader;\nimport com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;\n\n/**\n * @description\n */\npublic class TestConfig {\n\n    @Before\n    public void before() {\n        // 加载数据源连接池\n        DatasourceConfig.DATA_SOURCES.put(\"defaultDS\", TestConstant.dataSource);\n    }\n\n    @Test\n    public void testLoad() {\n        Map<String, KuduMappingConfig> configMap = KuduMappingConfigLoader.load(null);\n        Assert.assertFalse(configMap.isEmpty());\n    }\n}\n"
  },
  {
    "path": "client-adapter/kudu/src/test/java/com/alibaba/otter/canal/client/adapter/kudu/test/TestConstant.java",
    "content": "package com.alibaba.otter.canal.client.adapter.kudu.test;\n\nimport java.sql.SQLException;\n\nimport com.alibaba.druid.pool.DruidDataSource;\n\npublic class TestConstant {\n\n    public final static String          jdbcUrl      = \"jdbc:mysql://10.0.9.5:3306/canal_manager?useUnicode=true\";\n    public final static String          jdbcUser     = \"axtest\";\n    public final static String          jdbcPassword = \"axtest123\";\n\n    public final static DruidDataSource dataSource;\n\n    static {\n        dataSource = new DruidDataSource();\n        dataSource.setDriverClassName(\"com.mysql.jdbc.Driver\");\n        dataSource.setUrl(jdbcUrl);\n        dataSource.setUsername(jdbcUser);\n        dataSource.setPassword(jdbcPassword);\n        dataSource.setInitialSize(1);\n        dataSource.setMinIdle(1);\n        dataSource.setMaxActive(1);\n        dataSource.setMaxWait(60000);\n        dataSource.setTimeBetweenEvictionRunsMillis(60000);\n        dataSource.setMinEvictableIdleTimeMillis(300000);\n        dataSource.setPoolPreparedStatements(false);\n        dataSource.setMaxPoolPreparedStatementPerConnectionSize(20);\n        dataSource.setValidationQuery(\"select 1\");\n        try {\n            dataSource.init();\n        } catch (SQLException e) {\n            e.printStackTrace();\n        }\n    }\n\n}\n"
  },
  {
    "path": "client-adapter/kudu/src/test/java/com/alibaba/otter/canal/client/adapter/kudu/test/sync/Common.java",
    "content": "package com.alibaba.otter.canal.client.adapter.kudu.test.sync;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport com.alibaba.otter.canal.client.adapter.kudu.KuduAdapter;\nimport com.alibaba.otter.canal.client.adapter.kudu.test.TestConstant;\nimport com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;\nimport com.alibaba.otter.canal.client.adapter.support.OuterAdapterConfig;\n\n/**\n * @description\n */\npublic class Common {\n\n    public static KuduAdapter init() {\n        DatasourceConfig.DATA_SOURCES.put(\"defaultDS\", TestConstant.dataSource);\n\n        OuterAdapterConfig outerAdapterConfig = new OuterAdapterConfig();\n        outerAdapterConfig.setName(\"kudu\");\n        outerAdapterConfig.setKey(\"kudu\");\n        Map<String, String> properties = new HashMap<>();\n        properties.put(\"kudu.master.address\", \"10.6.36.102,10.6.36.187,10.6.36.229\");\n        outerAdapterConfig.setProperties(properties);\n\n        KuduAdapter adapter = new KuduAdapter();\n        adapter.init(outerAdapterConfig, null);\n        return adapter;\n    }\n}\n"
  },
  {
    "path": "client-adapter/kudu/src/test/java/com/alibaba/otter/canal/client/adapter/kudu/test/sync/TestSyncKudu.java",
    "content": "package com.alibaba.otter.canal.client.adapter.kudu.test.sync;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.client.adapter.kudu.KuduAdapter;\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\n\n/**\n * @description\n */\npublic class TestSyncKudu {\n\n    private KuduAdapter kuduAdapter;\n\n    @Before\n    public void init() {\n        kuduAdapter = Common.init();\n    }\n\n    @Test\n    public void testEtl() {\n        List<String> param = new ArrayList<>();\n        kuduAdapter.etl(\"kudutest_user.yml\", param);\n    }\n\n    @Test\n    public void testCount() {\n        kuduAdapter.count(\"kudutest_user.yml\");\n    }\n\n    @Test\n    public void testSync() {\n        Dml dml = new Dml();\n        dml.setDestination(\"example\");\n        dml.setGroupId(\"g1\");\n        dml.setTs(new Date().getTime());\n        dml.setType(\"DELETE\");\n        dml.setDatabase(\"test1\");\n        dml.setTable(\"user\");\n        List<Map<String, Object>> dataList = new ArrayList<>();\n        Map<String, Object> data = new LinkedHashMap<>();\n        dataList.add(data);\n        data.put(\"id\", 1L);\n        data.put(\"name\", \"liuyadong\");\n        data.put(\"role_id\", 1L);\n        data.put(\"c_time\", new Date());\n        dml.setData(dataList);\n\n        kuduAdapter.sync(Collections.singletonList(dml));\n    }\n}\n"
  },
  {
    "path": "client-adapter/launcher/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>canal.client-adapter</artifactId>\n        <groupId>com.alibaba.otter</groupId>\n        <version>1.1.9-SNAPSHOT</version>\n        <relativePath>../pom.xml</relativePath>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>com.alibaba.otter</groupId>\n    <artifactId>client-adapter.launcher</artifactId>\n    <packaging>jar</packaging>\n    <name>canal client adapter launcher module for otter ${project.version}</name>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <version>2.5.15</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>client-adapter.common</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.yaml</groupId>\n            <artifactId>snakeyaml</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-context</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.curator</groupId>\n            <artifactId>curator-recipes</artifactId>\n        </dependency>\n        <!-- jdbc -->\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.postgresql</groupId>\n            <artifactId>postgresql</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.oracle.database.jdbc</groupId>\n            <artifactId>ojdbc6</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.microsoft.sqlserver</groupId>\n            <artifactId>mssql-jdbc</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.hbase</groupId>\n            <artifactId>hbase-shaded-client</artifactId>\n            <scope>runtime</scope>\n        </dependency>\n        <dependency>\n            <groupId>ru.yandex.clickhouse</groupId>\n            <artifactId>clickhouse-jdbc</artifactId>\n        </dependency>\n\n        <!-- prometheus hotspot exporter -->\n        <dependency>\n            <groupId>io.prometheus</groupId>\n            <artifactId>simpleclient_hotspot</artifactId>\n            <version>0.4.0</version>\n        </dependency>\n        <dependency>\n            <groupId>io.prometheus</groupId>\n            <artifactId>simpleclient_httpserver</artifactId>\n            <version>0.4.0</version>\n        </dependency>\n\n        <!-- outer adapter jar with dependencies-->\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>client-adapter.logger</artifactId>\n            <version>${project.version}</version>\n            <exclusions>\n                <exclusion>\n                    <artifactId>*</artifactId>\n                    <groupId>*</groupId>\n                </exclusion>\n            </exclusions>\n            <classifier>jar-with-dependencies</classifier>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>client-adapter.hbase</artifactId>\n            <version>${project.version}</version>\n            <exclusions>\n                <exclusion>\n                    <artifactId>*</artifactId>\n                    <groupId>*</groupId>\n                </exclusion>\n            </exclusions>\n            <classifier>jar-with-dependencies</classifier>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>client-adapter.es6x</artifactId>\n            <version>${project.version}</version>\n            <exclusions>\n                <exclusion>\n                    <artifactId>*</artifactId>\n                    <groupId>*</groupId>\n                </exclusion>\n            </exclusions>\n            <classifier>jar-with-dependencies</classifier>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>client-adapter.es7x</artifactId>\n            <version>${project.version}</version>\n            <exclusions>\n                <exclusion>\n                    <artifactId>*</artifactId>\n                    <groupId>*</groupId>\n                </exclusion>\n            </exclusions>\n            <classifier>jar-with-dependencies</classifier>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>client-adapter.es8x</artifactId>\n            <version>${project.version}</version>\n            <exclusions>\n                <exclusion>\n                    <artifactId>*</artifactId>\n                    <groupId>*</groupId>\n                </exclusion>\n            </exclusions>\n            <classifier>jar-with-dependencies</classifier>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>client-adapter.rdb</artifactId>\n            <version>${project.version}</version>\n            <exclusions>\n                <exclusion>\n                    <artifactId>*</artifactId>\n                    <groupId>*</groupId>\n                </exclusion>\n            </exclusions>\n            <classifier>jar-with-dependencies</classifier>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>client-adapter.tablestore</artifactId>\n            <version>${project.version}</version>\n            <exclusions>\n                <exclusion>\n                    <artifactId>*</artifactId>\n                    <groupId>*</groupId>\n                </exclusion>\n            </exclusions>\n            <classifier>jar-with-dependencies</classifier>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>client-adapter.clickhouse</artifactId>\n            <version>${project.version}</version>\n            <exclusions>\n                <exclusion>\n                    <artifactId>*</artifactId>\n                    <groupId>*</groupId>\n                </exclusion>\n            </exclusions>\n            <classifier>jar-with-dependencies</classifier>\n            <scope>provided</scope>\n        </dependency>\n        <!-- connector plugin -->\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>connector.tcp</artifactId>\n            <version>${project.version}</version>\n            <exclusions>\n                <exclusion>\n                    <artifactId>*</artifactId>\n                    <groupId>*</groupId>\n                </exclusion>\n            </exclusions>\n            <classifier>jar-with-dependencies</classifier>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>connector.kafka</artifactId>\n            <version>${project.version}</version>\n            <exclusions>\n                <exclusion>\n                    <artifactId>*</artifactId>\n                    <groupId>*</groupId>\n                </exclusion>\n            </exclusions>\n            <classifier>jar-with-dependencies</classifier>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>connector.rocketmq</artifactId>\n            <version>${project.version}</version>\n            <exclusions>\n                <exclusion>\n                    <artifactId>*</artifactId>\n                    <groupId>*</groupId>\n                </exclusion>\n            </exclusions>\n            <classifier>jar-with-dependencies</classifier>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>connector.rabbitmq</artifactId>\n            <version>${project.version}</version>\n            <exclusions>\n                <exclusion>\n                    <artifactId>*</artifactId>\n                    <groupId>*</groupId>\n                </exclusion>\n            </exclusions>\n            <classifier>jar-with-dependencies</classifier>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>connector.pulsarmq</artifactId>\n            <version>${project.version}</version>\n            <exclusions>\n                <exclusion>\n                    <artifactId>*</artifactId>\n                    <groupId>*</groupId>\n                </exclusion>\n            </exclusions>\n            <classifier>jar-with-dependencies</classifier>\n            <scope>provided</scope>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-dependency-plugin</artifactId>\n                <version>2.10</version>\n                <executions>\n                    <execution>\n                        <id>copy-dependencies-to-canal-client-service</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>copy-dependencies</goal>\n                        </goals>\n                        <configuration>\n                            <includeClassifiers>jar-with-dependencies</includeClassifiers>\n                            <outputDirectory>${project.basedir}/target/canal-adapter/plugin</outputDirectory>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-assembly-plugin</artifactId>\n                <version>2.2.1</version>\n                <executions>\n                    <execution>\n                        <id>assemble</id>\n                        <goals>\n                            <goal>single</goal>\n                        </goals>\n                        <phase>package</phase>\n                    </execution>\n                </executions>\n                <configuration>\n                    <appendAssemblyId>false</appendAssemblyId>\n                    <attach>false</attach>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-jar-plugin</artifactId>\n                <version>3.0.2</version>\n                <configuration>\n                    <archive>\n                        <manifest>\n                            <addClasspath>true</addClasspath>\n                            <classpathPrefix>lib/</classpathPrefix>\n                            <mainClass>com.alibaba.otter.canal.adapter.launcher.CanalAdapterApplication</mainClass>\n                        </manifest>\n                    </archive>\n                    <excludes>\n                        <exclude>**/*.properties</exclude>\n                        <exclude>**/*.xml</exclude>\n                        <exclude>**/*.yml</exclude>\n                        <exclude>static/**</exclude>\n                        <exclude>templates/**</exclude>\n                    </excludes>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n    <profiles>\n        <profile>\n            <id>dev</id>\n            <activation>\n                <activeByDefault>true</activeByDefault>\n                <property>\n                    <name>env</name>\n                    <value>!release</value>\n                </property>\n            </activation>\n\n            <build>\n                <plugins>\n                    <plugin>\n                        <artifactId>maven-assembly-plugin</artifactId>\n                        <configuration>\n                            <descriptors>\n                                <descriptor>${basedir}/src/main/assembly/dev.xml</descriptor>\n                            </descriptors>\n                            <finalName>canal-adapter</finalName>\n                            <outputDirectory>${project.build.directory}</outputDirectory>\n                        </configuration>\n                    </plugin>\n                </plugins>\n            </build>\n\n        </profile>\n\n        <profile>\n            <id>release</id>\n            <activation>\n                <property>\n                    <name>env</name>\n                    <value>release</value>\n                </property>\n            </activation>\n\n            <build>\n                <plugins>\n                    <plugin>\n                        <artifactId>maven-assembly-plugin</artifactId>\n                        <configuration>\n                            <descriptors>\n                                <descriptor>${basedir}/src/main/assembly/release.xml</descriptor>\n                            </descriptors>\n                            <finalName>canal.adapter-${project.version}</finalName>\n                            <outputDirectory>${project.basedir}/../../target</outputDirectory>\n                        </configuration>\n                    </plugin>\n                </plugins>\n            </build>\n        </profile>\n    </profiles>\n</project>\n"
  },
  {
    "path": "client-adapter/launcher/src/main/assembly/dev.xml",
    "content": "<assembly xmlns=\"http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd\">\n\t<id>dist</id>\n\t<formats>\n\t\t<format>dir</format>\n\t</formats>\n\t<includeBaseDirectory>false</includeBaseDirectory>\n\t<fileSets>\n        <fileSet>\n            <directory>.</directory>\n            <outputDirectory>/</outputDirectory>\n            <includes>\n                <include>README*</include>\n            </includes>\n        </fileSet>\n        <fileSet>\n            <directory>./src/main/bin</directory>\n            <outputDirectory>bin</outputDirectory>\n            <includes>\n                <include>**/*</include>\n            </includes>\n            <fileMode>0755</fileMode>\n        </fileSet>\n        <fileSet>\n            <directory>./src/main/resources</directory>\n            <outputDirectory>/conf</outputDirectory>\n            <includes>\n                <include>**/*</include>\n\n            </includes>\n        </fileSet>\n        <fileSet>\n            <directory>../es6x/src/main/resources/es6</directory>\n            <outputDirectory>/conf/es6</outputDirectory>\n            <includes>\n                <include>**/*</include>\n            </includes>\n        </fileSet>\n        <fileSet>\n            <directory>../es7x/src/main/resources/es7</directory>\n            <outputDirectory>/conf/es7</outputDirectory>\n            <includes>\n                <include>**/*</include>\n            </includes>\n        </fileSet>\n        <fileSet>\n            <directory>../es8x/src/main/resources/es8</directory>\n            <outputDirectory>/conf/es8</outputDirectory>\n            <includes>\n                <include>**/*</include>\n            </includes>\n        </fileSet>\n        <fileSet>\n            <directory>../hbase/src/main/resources/hbase</directory>\n            <outputDirectory>/conf/hbase</outputDirectory>\n            <includes>\n                <include>**/*</include>\n            </includes>\n        </fileSet>\n        <fileSet>\n            <directory>../kudu/src/main/resources/kudu</directory>\n            <outputDirectory>/conf/kudu</outputDirectory>\n            <includes>\n                <include>**/*</include>\n            </includes>\n        </fileSet>\n        <fileSet>\n            <directory>../rdb/src/main/resources/</directory>\n            <outputDirectory>/conf</outputDirectory>\n            <excludes>\n                <exclude>META-INF/**</exclude>\n            </excludes>\n        </fileSet>\n        <fileSet>\n            <directory>../tablestore/src/main/resources/</directory>\n            <outputDirectory>/conf</outputDirectory>\n            <excludes>\n                <exclude>META-INF/**</exclude>\n            </excludes>\n        </fileSet>\n        <fileSet>\n            <directory>target</directory>\n            <outputDirectory>logs</outputDirectory>\n            <excludes>\n                <exclude>**/*</exclude>\n            </excludes>\n        </fileSet>\n    </fileSets>\n    <dependencySets>\n        <dependencySet>\n            <outputDirectory>lib</outputDirectory>\n            <excludes>\n                <exclude>junit:junit</exclude>\n            </excludes>\n        </dependencySet>\n    </dependencySets>\n</assembly>\n"
  },
  {
    "path": "client-adapter/launcher/src/main/assembly/release.xml",
    "content": "<assembly xmlns=\"http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0\"\n          xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n          xsi:schemaLocation=\"http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd\">\n    <id>dist</id>\n    <formats>\n        <format>tar.gz</format>\n    </formats>\n    <includeBaseDirectory>false</includeBaseDirectory>\n    <fileSets>\n        <fileSet>\n            <directory>.</directory>\n            <outputDirectory>/</outputDirectory>\n            <includes>\n                <include>README*</include>\n            </includes>\n        </fileSet>\n        <fileSet>\n            <directory>./src/main/bin</directory>\n            <outputDirectory>bin</outputDirectory>\n            <includes>\n                <include>**/*</include>\n            </includes>\n            <fileMode>0755</fileMode>\n        </fileSet>\n        <fileSet>\n            <directory>./src/main/resources</directory>\n            <outputDirectory>/conf</outputDirectory>\n            <includes>\n                <include>**/*</include>\n\n            </includes>\n        </fileSet>\n        <fileSet>\n            <directory>../es6x/src/main/resources/es6</directory>\n            <outputDirectory>/conf/es6</outputDirectory>\n            <includes>\n                <include>**/*</include>\n            </includes>\n        </fileSet>\n        <fileSet>\n            <directory>../es7x/src/main/resources/es7</directory>\n            <outputDirectory>/conf/es7</outputDirectory>\n            <includes>\n                <include>**/*</include>\n            </includes>\n        </fileSet>\n        <fileSet>\n            <directory>../es8x/src/main/resources/es8</directory>\n            <outputDirectory>/conf/es8</outputDirectory>\n            <includes>\n                <include>**/*</include>\n            </includes>\n        </fileSet>\n        <fileSet>\n            <directory>../hbase/src/main/resources/hbase</directory>\n            <outputDirectory>/conf/hbase</outputDirectory>\n            <includes>\n                <include>**/*</include>\n            </includes>\n        </fileSet>\n        <fileSet>\n            <directory>../kudu/src/main/resources/kudu</directory>\n            <outputDirectory>/conf/kudu</outputDirectory>\n            <includes>\n                <include>**/*</include>\n            </includes>\n        </fileSet>\n        <fileSet>\n            <directory>../rdb/src/main/resources/</directory>\n            <outputDirectory>/conf</outputDirectory>\n            <excludes>\n                <exclude>META-INF/**</exclude>\n            </excludes>\n        </fileSet>\n        <fileSet>\n            <directory>../tablestore/src/main/resources/</directory>\n            <outputDirectory>/conf</outputDirectory>\n            <excludes>\n                <exclude>META-INF/**</exclude>\n            </excludes>\n        </fileSet>\n        <fileSet>\n            <directory>target</directory>\n            <outputDirectory>logs</outputDirectory>\n            <excludes>\n                <exclude>**/*</exclude>\n            </excludes>\n        </fileSet>\n        <fileSet>\n            <directory>${project.basedir}/target/canal-adapter/plugin</directory>\n            <outputDirectory>/plugin/</outputDirectory>\n        </fileSet>\n    </fileSets>\n    <dependencySets>\n        <dependencySet>\n            <outputDirectory>lib</outputDirectory>\n            <excludes>\n                <exclude>junit:junit</exclude>\n            </excludes>\n        </dependencySet>\n    </dependencySets>\n</assembly>\n"
  },
  {
    "path": "client-adapter/launcher/src/main/bin/restart.sh",
    "content": "#!/bin/bash\n\nargs=$@\n\ncase $(uname) in\nLinux)\n  bin_abs_path=$(readlink -f $(dirname $0))\n  ;;\n*)\n  bin_abs_path=$(cd $(dirname $0) ||exit ; pwd)\n  ;;\nesac\n\nsh \"$bin_abs_path\"/stop.sh $args\nsh \"$bin_abs_path\"/startup.sh $args\n"
  },
  {
    "path": "client-adapter/launcher/src/main/bin/startup.bat",
    "content": "@echo off\n@if not \"%ECHO%\" == \"\"  echo %ECHO%\n@if \"%OS%\" == \"Windows_NT\"  setlocal\n\nset ENV_PATH=.\\\nif \"%OS%\" == \"Windows_NT\" set ENV_PATH=%~dp0%\n\nset conf_dir=%ENV_PATH%\\..\\conf\n\nset CLASSPATH=%conf_dir%\nset CLASSPATH=%conf_dir%\\..\\lib\\*;%CLASSPATH%\n\nset JAVA_MEM_OPTS= -Xms128m -Xmx512m -XX:PermSize=128m\nset JAVA_OPTS_EXT= -Djava.awt.headless=true -Djava.net.preferIPv4Stack=false -Dapplication.codeset=UTF-8 -Dfile.encoding=UTF-8\nset ADAPTER_OPTS= -DappName=canal-adapter\n\nset JAVA_OPTS= %JAVA_MEM_OPTS% %JAVA_OPTS_EXT% %ADAPTER_OPTS%\n\nset CMD_STR= java %JAVA_OPTS% -classpath \"%CLASSPATH%\" com.alibaba.otter.canal.adapter.launcher.CanalAdapterApplication\necho start cmd : %CMD_STR%\n\njava %JAVA_OPTS% -classpath \"%CLASSPATH%\" com.alibaba.otter.canal.adapter.launcher.CanalAdapterApplication\n"
  },
  {
    "path": "client-adapter/launcher/src/main/bin/startup.sh",
    "content": "#!/bin/bash\n\ncurrent_path=`pwd`\ncase \"`uname`\" in\n    Linux)\n\t\tbin_abs_path=$(readlink -f $(dirname $0))\n\t\t;;\n\t*)\n\t\tbin_abs_path=`cd $(dirname $0); pwd`\n\t\t;;\nesac\n\nbase=${bin_abs_path}/..\njaas_conf=$base/conf/jaas.conf\n\nexport LANG=en_US.UTF-8\nexport BASE=$base\n\nif [ -f $base/bin/adapter.pid ] ; then\n\techo \"found adapter.pid , Please run stop.sh first ,then startup.sh\" 2>&2\n    exit 1\nfi\n\nif [ ! -d $base/logs ] ; then\n\tmkdir -p $base/logs\nfi\n\n## set java path\nif [ -z \"$JAVA\" ] ; then\n  JAVA=$(which java)\nfi\n\nALIBABA_JAVA=\"/usr/alibaba/java/bin/java\"\nTAOBAO_JAVA=\"/opt/taobao/java/bin/java\"\nif [ -z \"$JAVA\" ]; then\n  if [ -f $ALIBABA_JAVA ] ; then\n  \tJAVA=$ALIBABA_JAVA\n  elif [ -f $TAOBAO_JAVA ] ; then\n  \tJAVA=$TAOBAO_JAVA\n  else\n  \techo \"Cannot find a Java JDK. Please set either set JAVA or put java (>=1.5) in your PATH.\" 2>&2\n    exit 1\n  fi\nfi\n\ncase \"$#\"\nin\n0 )\n  ;;\n2 )\n  if [ \"$1\" = \"debug\" ]; then\n    DEBUG_PORT=$2\n    DEBUG_SUSPEND=\"n\"\n    JAVA_DEBUG_OPT=\"-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=$DEBUG_PORT,server=y,suspend=$DEBUG_SUSPEND\"\n  fi\n  ;;\n* )\n  echo \"THE PARAMETERS MUST BE TWO OR LESS.PLEASE CHECK AGAIN.\"\n  exit;;\nesac\n\nJAVA_VERSION=`$JAVA -version 2>&1 |awk 'NR==1{ gsub(/\"/,\"\"); print $3 }' | awk  -F '.' '{print $1}'`\n\nJAVA_OPTS=\"$JAVA_OPTS -Xss1m -XX:+AggressiveOpts -XX:-UseBiasedLocking -XX:-OmitStackTraceInFastThrow\"\nJAVA_OPTS=\"$JAVA_OPTS -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$base/logs\"\n\nif [ $JAVA_VERSION -ge 11 ] ; then\n  #JAVA_OPTS=\"$JAVA_OPTS -Xlog:gc*:$base_log/gc.log:time \"\n  JAVA_OPTS=\"$JAVA_OPTS -Xlog:gc*:file=$base/logs/adapter/gc.log::filecount=5,filesize=32M\"\nelse\n  JAVA_OPTS=\"$JAVA_OPTS -Xloggc:$base/logs/canal/gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=32M\"\n  JAVA_OPTS=\"$JAVA_OPTS -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:-PrintHeapAtGC -XX:+PrintGCApplicationStoppedTime\"\n  JAVA_OPTS=\"$JAVA_OPTS -XX:+UseFastAccessorMethods -XX:-PrintReferenceGC -XX:+PrintAdaptiveSizePolicy -XX:+PrintTenuringDistribution\"\n  JAVA_OPTS=\"$JAVA_OPTS -XX:+PrintSafepointStatistics -XX:PrintSafepointStatisticsCount=1 -XX:+SafepointTimeout -XX:SafepointTimeoutDelay=2000\"\n  JAVA_OPTS=\"$JAVA_OPTS -XX:+UseCountedLoopSafepoints -XX:+DisableExplicitGC -XX:+ExplicitGCInvokesConcurrent -XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses\"\nfi\n\nOS_ARCH=`file -L $JAVA | grep 64-bit`\nif [ -n \"$OS_ARCH\" ]; then\n  if [ $JAVA_VERSION -ge 11 ] ; then\n    # For G1\n    JAVA_OPTS=\"-server -Xms2g -Xmx3g -XX:+UseG1GC -XX:MaxGCPauseMillis=250 -XX:+UseGCOverheadLimit -XX:+ExplicitGCInvokesConcurrent $JAVA_OPTS\"\n  else\n\t  JAVA_OPTS=\"-server -Xms2g -Xmx3g -Xmn1g -XX:SurvivorRatio=2 -XX:PermSize=96m -XX:MaxPermSize=256m -XX:MaxTenuringThreshold=15 -XX:+DisableExplicitGC $JAVA_OPTS\"\n\t  ## JDK 1.8 2c4g [-XX:ConcGCThreads=1 -XX:ParallelGCThreads=2], 4c8g [-XX:ConcGCThreads=2 -XX:ParallelGCThreads=4]\n    #JAVA_OPTS=\"$JAVA_OPTS -XX:InitialRAMPercentage=45.0 -XX:MinRAMPercentage=45.0 -XX:MaxRAMPercentage=45.0\"\n    #JAVA_OPTS=\"$JAVA_OPTS -XX:-UseParallelGC -XX:+UseConcMarkSweepGC -XX:ConcGCThreads=2 -XX:ParallelGCThreads=4\"\n    #JAVA_OPTS=\"$JAVA_OPTS -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70\"\n    #JAVA_OPTS=\"-server -XX:NewRatio=1 -XX:SurvivorRatio=2 -XX:MetaspaceSize=96m -XX:MaxMetaspaceSize=128m \"\n\tfi\nelse\n\tJAVA_OPTS=\"-server -Xms1024m -Xmx1024m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:MaxPermSize=128m $JAVA_OPTS\"\nfi\n\nJAVA_OPTS=\" $JAVA_OPTS -Djava.awt.headless=true -Djava.net.preferIPv4Stack=false -Dfile.encoding=UTF-8\"\nADAPTER_OPTS=\"-DappName=canal-adapter\"\nif [ -f \"$jaas_conf\" ]; then\n  ADAPTER_OPTS=\"$ADAPTER_OPTS -Djava.security.auth.login.config=$jaas_conf\"\nfi\n\nfor i in $base/lib/*;\n    do CLASSPATH=$i:\"$CLASSPATH\";\ndone\n\nCLASSPATH=\"$base/conf:$CLASSPATH\";\n\necho \"cd to $bin_abs_path for workaround relative path\"\ncd $bin_abs_path\n\necho CLASSPATH :$CLASSPATH\n$JAVA $JAVA_OPTS $JAVA_DEBUG_OPT $ADAPTER_OPTS -classpath .:$CLASSPATH com.alibaba.otter.canal.adapter.launcher.CanalAdapterApplication 1>>/dev/null 2>&1 &\necho $! > $base/bin/adapter.pid\n\necho \"cd to $current_path for continue\"\ncd $current_path\n"
  },
  {
    "path": "client-adapter/launcher/src/main/bin/stop.sh",
    "content": "#!/bin/bash\n\ncygwin=false;\nlinux=false;\ncase \"`uname`\" in\n    CYGWIN*)\n        cygwin=true\n        ;;\n    Linux*)\n    \tlinux=true\n    \t;;\nesac\n\nget_pid() {\t\n\tSTR=$1\n\tPID=$2\n    if $cygwin; then\n        JAVA_CMD=\"$JAVA_HOME\\bin\\java\"\n        JAVA_CMD=`cygpath --path --unix $JAVA_CMD`\n        JAVA_PID=`ps |grep $JAVA_CMD |awk '{print $1}'`\n    else\n    \tif $linux; then\n\t        if [ ! -z \"$PID\" ]; then\n\t        \tJAVA_PID=`ps -C java -f --width 1000|grep \"$STR\"|grep \"$PID\"|grep -v grep|awk '{print $2}'`\n\t\t    else \n\t\t        JAVA_PID=`ps -C java -f --width 1000|grep \"$STR\"|grep -v grep|awk '{print $2}'`\n\t        fi\n\t    else\n\t    \tif [ ! -z \"$PID\" ]; then\n\t        \tJAVA_PID=`ps aux |grep \"$STR\"|grep \"$PID\"|grep -v grep|awk '{print $2}'`\n\t\t    else \n\t\t        JAVA_PID=`ps aux |grep \"$STR\"|grep -v grep|awk '{print $2}'`\n\t        fi\n\t    fi\n    fi\n    echo $JAVA_PID;\n}\n\nbase=`dirname $0`/..\npidfile=$base/bin/adapter.pid\nif [ ! -f \"$pidfile\" ];then\n\techo \"canal-adapter is not running. exists\"\n\texit\nfi\n\npid=`cat $pidfile`\nif [ \"$pid\" == \"\" ] ; then\n\tpid=`get_pid \"appName=canal-adapter\"`\nfi\n\necho -e \"`hostname`: stopping canal $pid ... \"\nkill $pid\n\nLOOPS=0\nwhile (true); \ndo \n\tgpid=`get_pid \"appName=canal-adapter\" \"$pid\"`\n    if [ \"$gpid\" == \"\" ] ; then\n    \techo \"Oook! cost:$LOOPS\"\n    \t`rm $pidfile`\n    \tbreak;\n    fi\n    let LOOPS=LOOPS+1\n    sleep 1\ndone"
  },
  {
    "path": "client-adapter/launcher/src/main/java/com/alibaba/otter/canal/adapter/launcher/CanalAdapterApplication.java",
    "content": "package com.alibaba.otter.canal.adapter.launcher;\n\nimport org.springframework.boot.Banner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;\n\n/**\n * 启动入口\n *\n * @author rewerma @ 2018-10-20\n * @version 1.0.0\n */\n@SpringBootApplication(exclude= { DataSourceAutoConfiguration.class})\npublic class CanalAdapterApplication {\n\n    public static void main(String[] args) {\n        // 支持rocketmq client 配置日志路径\n        System.setProperty(\"rocketmq.client.logUseSlf4j\",\"true\");\n\n        SpringApplication application = new SpringApplication(CanalAdapterApplication.class);\n        application.setBannerMode(Banner.Mode.OFF);\n        application.run(args);\n    }\n}\n"
  },
  {
    "path": "client-adapter/launcher/src/main/java/com/alibaba/otter/canal/adapter/launcher/common/EtlLock.java",
    "content": "package com.alibaba.otter.canal.adapter.launcher.common;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.locks.ReentrantLock;\n\nimport javax.annotation.PostConstruct;\nimport javax.annotation.Resource;\n\nimport org.apache.curator.framework.CuratorFramework;\nimport org.apache.curator.framework.recipes.locks.InterProcessMutex;\nimport org.springframework.stereotype.Component;\n\nimport com.alibaba.otter.canal.adapter.launcher.config.CuratorClient;\n\n/**\n * Etl 同步锁\n *\n * @author rewerma @ 2018-10-20\n * @version 1.0.0\n */\n@Component\npublic class EtlLock {\n\n    private static final Map<String, ReentrantLock>     LOCAL_LOCK       = new ConcurrentHashMap<>();\n\n    private static final Map<String, InterProcessMutex> DISTRIBUTED_LOCK = new ConcurrentHashMap<>();\n\n    private Mode                                        mode             = Mode.LOCAL;\n\n    @Resource\n    private CuratorClient                               curatorClient;\n\n    @PostConstruct\n    public void init() {\n        CuratorFramework curator = curatorClient.getCurator();\n        if (curator != null) {\n            mode = Mode.DISTRIBUTED;\n        } else {\n            mode = Mode.LOCAL;\n        }\n    }\n\n    private ReentrantLock getLock(String key) {\n        ReentrantLock lock = LOCAL_LOCK.get(key);\n        if (lock == null) {\n            synchronized (EtlLock.class) {\n                lock = LOCAL_LOCK.get(key);\n                if (lock == null) {\n                    lock = new ReentrantLock();\n                    LOCAL_LOCK.put(key, lock);\n                }\n            }\n        }\n        return lock;\n    }\n\n    private InterProcessMutex getRemoteLock(String key) {\n        InterProcessMutex lock = DISTRIBUTED_LOCK.get(key);\n        if (lock == null) {\n            synchronized (EtlLock.class) {\n                lock = DISTRIBUTED_LOCK.get(key);\n                if (lock == null) {\n                    lock = new InterProcessMutex(curatorClient.getCurator(), key);\n                    DISTRIBUTED_LOCK.put(key, lock);\n                }\n            }\n        }\n        return lock;\n    }\n\n    public void lock(String key) throws Exception {\n        if (mode == Mode.LOCAL) {\n            getLock(key).lock();\n        } else {\n            InterProcessMutex lock = getRemoteLock(key);\n            lock.acquire();\n        }\n    }\n\n    public boolean tryLock(String key, long timeout, TimeUnit unit) {\n        try {\n            if (mode == Mode.LOCAL) {\n                return getLock(key).tryLock(timeout, unit);\n            } else {\n                InterProcessMutex lock = getRemoteLock(key);\n                return lock.acquire(timeout, unit);\n            }\n        } catch (Exception e) {\n            return false;\n        }\n    }\n\n    public boolean tryLock(String key) {\n        try {\n            if (mode == Mode.LOCAL) {\n                return getLock(key).tryLock();\n            } else {\n                InterProcessMutex lock = getRemoteLock(key);\n                return lock.acquire(500, TimeUnit.MILLISECONDS);\n            }\n        } catch (Exception e) {\n            return false;\n        }\n    }\n\n    public void unlock(String key) {\n        if (mode == Mode.LOCAL) {\n            getLock(key).unlock();\n        } else {\n            InterProcessMutex lock = getRemoteLock(key);\n            try {\n                lock.release();\n            } catch (Exception e) {\n                // ignore\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/launcher/src/main/java/com/alibaba/otter/canal/adapter/launcher/common/Mode.java",
    "content": "package com.alibaba.otter.canal.adapter.launcher.common;\n\npublic enum Mode {\n                  LOCAL, // 本地模式\n                  DISTRIBUTED // 分布式\n}\n"
  },
  {
    "path": "client-adapter/launcher/src/main/java/com/alibaba/otter/canal/adapter/launcher/common/SyncSwitch.java",
    "content": "package com.alibaba.otter.canal.adapter.launcher.common;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\n\nimport javax.annotation.PostConstruct;\nimport javax.annotation.Resource;\n\nimport org.apache.curator.framework.CuratorFramework;\nimport org.apache.curator.framework.recipes.cache.NodeCache;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.data.Stat;\nimport org.springframework.stereotype.Component;\n\nimport com.alibaba.otter.canal.adapter.launcher.config.AdapterCanalConfig;\nimport com.alibaba.otter.canal.adapter.launcher.config.CuratorClient;\nimport com.alibaba.otter.canal.common.utils.BooleanMutex;\n\n/**\n * 同步开关\n *\n * @author rewerma @ 2018-10-20\n * @version 1.0.0\n */\n@Component\npublic class SyncSwitch {\n\n    private static final String                    SYN_SWITCH_ZK_NODE = \"/sync-switch/\";\n\n    private static final Map<String, BooleanMutex> LOCAL_LOCK         = new ConcurrentHashMap<>();\n\n    private static final Map<String, BooleanMutex> DISTRIBUTED_LOCK   = new ConcurrentHashMap<>();\n\n    private Mode                                   mode               = Mode.LOCAL;\n\n    @Resource\n    private AdapterCanalConfig                     adapterCanalConfig;\n    @Resource\n    private CuratorClient                          curatorClient;\n\n    @PostConstruct\n    public void init() {\n        CuratorFramework curator = curatorClient.getCurator();\n        if (curator != null) {\n            mode = Mode.DISTRIBUTED;\n            DISTRIBUTED_LOCK.clear();\n            for (String destination : adapterCanalConfig.DESTINATIONS) {\n                // 对应每个destination注册锁\n                BooleanMutex mutex = new BooleanMutex(true);\n                initMutex(curator, destination, mutex);\n                DISTRIBUTED_LOCK.put(destination, mutex);\n                startListen(destination, mutex);\n            }\n        } else {\n            mode = Mode.LOCAL;\n            LOCAL_LOCK.clear();\n            for (String destination : adapterCanalConfig.DESTINATIONS) {\n                // 对应每个destination注册锁\n                LOCAL_LOCK.put(destination, new BooleanMutex(true));\n            }\n        }\n    }\n\n    public synchronized void refresh() {\n        for (String destination : adapterCanalConfig.DESTINATIONS) {\n            BooleanMutex booleanMutex;\n            if (mode == Mode.DISTRIBUTED) {\n                CuratorFramework curator = curatorClient.getCurator();\n                booleanMutex = DISTRIBUTED_LOCK.get(destination);\n                if (booleanMutex == null) {\n                    BooleanMutex mutex = new BooleanMutex(true);\n                    initMutex(curator, destination, mutex);\n                    DISTRIBUTED_LOCK.put(destination, mutex);\n                    startListen(destination, mutex);\n                }\n            } else {\n                booleanMutex = LOCAL_LOCK.get(destination);\n                if (booleanMutex == null) {\n                    LOCAL_LOCK.put(destination, new BooleanMutex(true));\n                }\n            }\n        }\n    }\n\n    @SuppressWarnings(\"resource\")\n    private synchronized void startListen(String destination, BooleanMutex mutex) {\n        try {\n            String path = SYN_SWITCH_ZK_NODE + destination;\n            CuratorFramework curator = curatorClient.getCurator();\n            NodeCache nodeCache = new NodeCache(curator, path);\n            nodeCache.start();\n            nodeCache.getListenable().addListener(() -> initMutex(curator, destination, mutex));\n        } catch (Exception e) {\n            throw new RuntimeException(e.getMessage());\n        }\n    }\n\n    private synchronized void initMutex(CuratorFramework curator, String destination, BooleanMutex mutex) {\n        try {\n            String path = SYN_SWITCH_ZK_NODE + destination;\n            Stat stat = curator.checkExists().forPath(path);\n            if (stat == null) {\n                if (!mutex.state()) {\n                    mutex.set(true);\n                }\n            } else {\n                String data = new String(curator.getData().forPath(path), StandardCharsets.UTF_8);\n                if (\"on\".equals(data)) {\n                    if (!mutex.state()) {\n                        mutex.set(true);\n                    }\n                } else {\n                    if (mutex.state()) {\n                        mutex.set(false);\n                    }\n                }\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(e.getMessage());\n        }\n    }\n\n    public synchronized void off(String destination) {\n        if (mode == Mode.LOCAL) {\n            BooleanMutex mutex = LOCAL_LOCK.get(destination);\n            if (mutex != null && mutex.state()) {\n                mutex.set(false);\n            }\n        } else {\n            try {\n                String path = SYN_SWITCH_ZK_NODE + destination;\n                try {\n                    curatorClient.getCurator()\n                        .create()\n                        .creatingParentContainersIfNeeded()\n                        .withMode(CreateMode.PERSISTENT)\n                        .forPath(path, \"off\".getBytes(StandardCharsets.UTF_8));\n                } catch (Exception e) {\n                    curatorClient.getCurator().setData().forPath(path, \"off\".getBytes(StandardCharsets.UTF_8));\n                }\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n        }\n    }\n\n    public synchronized void on(String destination) {\n        if (mode == Mode.LOCAL) {\n            BooleanMutex mutex = LOCAL_LOCK.get(destination);\n            if (mutex != null && !mutex.state()) {\n                mutex.set(true);\n            }\n        } else {\n            try {\n                String path = SYN_SWITCH_ZK_NODE + destination;\n                try {\n                    curatorClient.getCurator()\n                        .create()\n                        .creatingParentContainersIfNeeded()\n                        .withMode(CreateMode.PERSISTENT)\n                        .forPath(path, \"on\".getBytes(StandardCharsets.UTF_8));\n                } catch (Exception e) {\n                    curatorClient.getCurator().setData().forPath(path, \"on\".getBytes(StandardCharsets.UTF_8));\n                }\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n        }\n    }\n\n    public synchronized void release(String destination) {\n        if (mode == Mode.LOCAL) {\n            BooleanMutex mutex = LOCAL_LOCK.get(destination);\n            if (mutex != null && !mutex.state()) {\n                mutex.set(true);\n            }\n        }\n        if (mode == Mode.DISTRIBUTED) {\n            BooleanMutex mutex = DISTRIBUTED_LOCK.get(destination);\n            if (mutex != null && !mutex.state()) {\n                mutex.set(true);\n            }\n        }\n    }\n\n    public boolean status(String destination) {\n        if (mode == Mode.LOCAL) {\n            BooleanMutex mutex = LOCAL_LOCK.get(destination);\n            if (mutex != null) {\n                return mutex.state();\n            } else {\n                return false;\n            }\n        } else {\n            BooleanMutex mutex = DISTRIBUTED_LOCK.get(destination);\n            if (mutex != null) {\n                return mutex.state();\n            } else {\n                return false;\n            }\n        }\n    }\n\n    public void get(String destination) throws InterruptedException {\n        if (mode == Mode.LOCAL) {\n            BooleanMutex mutex = LOCAL_LOCK.get(destination);\n            if (mutex != null) {\n                mutex.get();\n            }\n        } else {\n            BooleanMutex mutex = DISTRIBUTED_LOCK.get(destination);\n            if (mutex != null) {\n                mutex.get();\n            }\n        }\n    }\n\n    public void get(String destination, long timeout, TimeUnit unit) throws InterruptedException, TimeoutException {\n        if (mode == Mode.LOCAL) {\n            BooleanMutex mutex = LOCAL_LOCK.get(destination);\n            if (mutex != null) {\n                mutex.get(timeout, unit);\n            }\n        } else {\n            BooleanMutex mutex = DISTRIBUTED_LOCK.get(destination);\n            if (mutex != null) {\n                mutex.get(timeout, unit);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "client-adapter/launcher/src/main/java/com/alibaba/otter/canal/adapter/launcher/config/AdapterCanalConfig.java",
    "content": "package com.alibaba.otter.canal.adapter.launcher.config;\n\nimport java.sql.SQLException;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.stereotype.Component;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.alibaba.otter.canal.client.adapter.support.CanalClientConfig;\nimport com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;\n\n/**\n * canal 的相关配置类\n *\n * @author rewerma @ 2018-10-20\n * @version 1.0.0\n */\n@Component\n@ConfigurationProperties(prefix = \"canal.conf\")\npublic class AdapterCanalConfig extends CanalClientConfig {\n\n    public final Set<String>              DESTINATIONS = new LinkedHashSet<>();\n\n    private Map<String, DatasourceConfig> srcDataSources;\n\n    @Override\n    public void setCanalAdapters(List<CanalAdapter> canalAdapters) {\n        super.setCanalAdapters(canalAdapters);\n\n        if (canalAdapters != null) {\n            synchronized (DESTINATIONS) {\n                DESTINATIONS.clear();\n                for (CanalAdapter canalAdapter : canalAdapters) {\n                    if (canalAdapter.getInstance() != null) {\n                        DESTINATIONS.add(canalAdapter.getInstance());\n                    }\n                }\n            }\n        }\n    }\n\n    public Map<String, DatasourceConfig> getSrcDataSources() {\n        return srcDataSources;\n    }\n\n    @SuppressWarnings(\"resource\")\n    public void setSrcDataSources(Map<String, DatasourceConfig> srcDataSources) {\n        this.srcDataSources = srcDataSources;\n\n        if (srcDataSources != null) {\n            for (Map.Entry<String, DatasourceConfig> entry : srcDataSources.entrySet()) {\n                DatasourceConfig datasourceConfig = entry.getValue();\n                // 加载数据源连接池\n                DruidDataSource ds = new DruidDataSource();\n                ds.setDriverClassName(datasourceConfig.getDriver());\n                ds.setUrl(datasourceConfig.getUrl());\n                ds.setUsername(datasourceConfig.getUsername());\n                ds.setPassword(datasourceConfig.getPassword());\n                ds.setInitialSize(1);\n                ds.setMinIdle(1);\n                ds.setMaxActive(datasourceConfig.getMaxActive());\n                ds.setMaxWait(60000);\n                ds.setTimeBetweenEvictionRunsMillis(60000);\n                ds.setMinEvictableIdleTimeMillis(300000);\n                ds.setValidationQuery(\"select 1\");\n                try {\n                    ds.init();\n                } catch (SQLException e) {\n                    throw new RuntimeException(e.getMessage(), e);\n                }\n                DatasourceConfig.DATA_SOURCES.put(entry.getKey(), ds);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/launcher/src/main/java/com/alibaba/otter/canal/adapter/launcher/config/AdapterConfigHolder.java",
    "content": "package com.alibaba.otter.canal.adapter.launcher.config;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport com.alibaba.otter.canal.adapter.launcher.monitor.remote.ConfigItem;\n\n/**\n * @author L.J.R @ 2019-09-03\n * @version 1.1.4\n */\npublic class AdapterConfigHolder {\n\n    private volatile long adapterConfigTimestamp = 0;\n\n    private final Map<String, ConfigItem> adapterConfigs = new ConcurrentHashMap<>();\n\n    private static AdapterConfigHolder adapterConfigHolder;\n\n    private AdapterConfigHolder() {\n    }\n\n    public synchronized static AdapterConfigHolder getInstance() {\n        if (adapterConfigHolder == null) {\n            adapterConfigHolder = new AdapterConfigHolder();\n        }\n        return adapterConfigHolder;\n    }\n\n    public void setAdapterConfigTimestamp(long configTimestamp) {\n        this.adapterConfigTimestamp = configTimestamp;\n    }\n\n    public long getAdapterConfigTimestamp() {\n        return adapterConfigTimestamp;\n    }\n\n    public Map<String, ConfigItem> getAdapterConfigs() {\n        return this.adapterConfigs;\n    }\n}\n"
  },
  {
    "path": "client-adapter/launcher/src/main/java/com/alibaba/otter/canal/adapter/launcher/config/BootstrapConfiguration.java",
    "content": "package com.alibaba.otter.canal.adapter.launcher.config;\n\nimport javax.annotation.PostConstruct;\nimport javax.annotation.PreDestroy;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.env.Environment;\n\nimport com.alibaba.otter.canal.adapter.launcher.monitor.remote.RemoteConfigLoader;\nimport com.alibaba.otter.canal.adapter.launcher.monitor.remote.RemoteConfigLoaderFactory;\n\n/**\n * Bootstrap级别配置加载\n *\n * @author rewerma @ 2019-01-05\n * @version 1.0.0\n */\npublic class BootstrapConfiguration {\n\n    @Autowired\n    private Environment        env;\n\n    private RemoteConfigLoader remoteConfigLoader = null;\n\n    @PostConstruct\n    public void loadRemoteConfig() {\n        remoteConfigLoader = RemoteConfigLoaderFactory.getRemoteConfigLoader(env);\n        if (remoteConfigLoader != null) {\n            remoteConfigLoader.loadRemoteConfig();\n            remoteConfigLoader.loadRemoteAdapterConfigs();\n            remoteConfigLoader.startMonitor(); // 启动监听\n        }\n    }\n\n    @PreDestroy\n    public synchronized void destroy() {\n        if (remoteConfigLoader != null) {\n            remoteConfigLoader.destroy();\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/launcher/src/main/java/com/alibaba/otter/canal/adapter/launcher/config/CuratorClient.java",
    "content": "package com.alibaba.otter.canal.adapter.launcher.config;\n\nimport javax.annotation.PostConstruct;\nimport javax.annotation.Resource;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.curator.framework.CuratorFramework;\nimport org.apache.curator.framework.CuratorFrameworkFactory;\nimport org.apache.curator.retry.ExponentialBackoffRetry;\nimport org.springframework.stereotype.Component;\n\n/**\n * curator 配置类\n *\n * @author rewerma @ 2018-10-20\n * @version 1.0.0\n */\n@Component\npublic class CuratorClient {\n\n    @Resource\n    private AdapterCanalConfig adapterCanalConfig;\n\n    private CuratorFramework   curator = null;\n\n    @PostConstruct\n    public void init() {\n        if (StringUtils.isNotEmpty(adapterCanalConfig.getZookeeperHosts())) {\n            curator = CuratorFrameworkFactory.builder()\n                .connectString(adapterCanalConfig.getZookeeperHosts())\n                .retryPolicy(new ExponentialBackoffRetry(1000, 3))\n                .sessionTimeoutMs(6000)\n                .connectionTimeoutMs(3000)\n                .namespace(\"canal-adapter\")\n                .build();\n            curator.start();\n        }\n    }\n\n    public CuratorFramework getCurator() {\n        return curator;\n    }\n}\n"
  },
  {
    "path": "client-adapter/launcher/src/main/java/com/alibaba/otter/canal/adapter/launcher/config/DruidConfig.java",
    "content": "package com.alibaba.otter.canal.adapter.launcher.config;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport com.alibaba.druid.support.http.StatViewServlet;\n\n@Configuration\npublic class DruidConfig {\n\n    @Bean\n    public ServletRegistrationBean<StatViewServlet> statViewServlet(){\n        ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>( new StatViewServlet(),\"/druid/*\");\n        Map<String,String> initParams = new HashMap<>();\n        initParams.put(\"allow\",\"\");\n        bean.setInitParameters(initParams);\n        return  bean;\n    }\n}\n"
  },
  {
    "path": "client-adapter/launcher/src/main/java/com/alibaba/otter/canal/adapter/launcher/config/SpringContext.java",
    "content": "package com.alibaba.otter.canal.adapter.launcher.config;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.stereotype.Component;\n\n/**\n * spring util配置类\n *\n * @author rewerma @ 2018-10-20\n * @version 1.0.0\n */\n@Component\npublic class SpringContext implements ApplicationContextAware {\n\n    private static ApplicationContext context;\n\n    /*\n     * 注入ApplicationContext\n     */\n    public void setApplicationContext(final ApplicationContext context) throws BeansException {\n        // 在加载Spring时自动获得context\n        SpringContext.context = context;\n    }\n\n    public static Object getBean(final String beanName) {\n        return SpringContext.context.getBean(beanName);\n    }\n\n    public static Object getBean(final Class<?> clz) {\n        return context.getBean(clz);\n    }\n}\n"
  },
  {
    "path": "client-adapter/launcher/src/main/java/com/alibaba/otter/canal/adapter/launcher/loader/AdapterProcessor.java",
    "content": "package com.alibaba.otter.canal.adapter.launcher.loader;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\n\nimport com.alibaba.otter.canal.protocol.exception.CanalClientException;\nimport org.apache.commons.lang.exception.ExceptionUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.adapter.launcher.common.SyncSwitch;\nimport com.alibaba.otter.canal.adapter.launcher.config.SpringContext;\nimport com.alibaba.otter.canal.client.adapter.OuterAdapter;\nimport com.alibaba.otter.canal.client.adapter.support.CanalClientConfig;\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\nimport com.alibaba.otter.canal.client.adapter.support.MessageUtil;\nimport com.alibaba.otter.canal.client.adapter.support.Util;\nimport com.alibaba.otter.canal.connector.core.config.CanalConstants;\nimport com.alibaba.otter.canal.connector.core.consumer.CommonMessage;\nimport com.alibaba.otter.canal.connector.core.spi.CanalMsgConsumer;\nimport com.alibaba.otter.canal.connector.core.spi.ExtensionLoader;\nimport com.alibaba.otter.canal.connector.core.spi.ProxyCanalMsgConsumer;\n\n/**\n * 适配处理器\n *\n * @author rewerma 2020-02-01\n * @version 1.0.0\n */\npublic class AdapterProcessor {\n\n    private static final Logger             logger                    = LoggerFactory.getLogger(AdapterProcessor.class);\n\n    private static final String             CONNECTOR_SPI_DIR         = \"/plugin\";\n    private static final String             CONNECTOR_STANDBY_SPI_DIR = \"/canal-adapter/plugin\";\n\n    private CanalMsgConsumer                canalMsgConsumer;\n\n    private String                          canalDestination;                                                           // canal实例\n    private String                          groupId                   = null;                                           // groupId\n    private List<List<OuterAdapter>>        canalOuterAdapters;                                                         // 外部适配器\n    private CanalClientConfig               canalClientConfig;                                                          // 配置\n    private ExecutorService                 groupInnerExecutorService;                                                  // 组内工作线程池\n    private volatile boolean                running                   = false;                                          // 是否运行中\n    private Thread                          thread                    = null;\n    private Thread.UncaughtExceptionHandler handler                   = (t, e) -> logger\n        .error(\"parse events has an error\", e);\n\n    private SyncSwitch                      syncSwitch;\n\n    public AdapterProcessor(CanalClientConfig canalClientConfig, String destination, String groupId,\n                            List<List<OuterAdapter>> canalOuterAdapters){\n        this.canalClientConfig = canalClientConfig;\n        this.canalDestination = destination;\n        this.groupId = groupId;\n        this.canalOuterAdapters = canalOuterAdapters;\n\n        this.groupInnerExecutorService = Util.newFixedThreadPool(canalOuterAdapters.size(), 5000L);\n        syncSwitch = (SyncSwitch) SpringContext.getBean(SyncSwitch.class);\n\n        // load connector consumer\n        ExtensionLoader<CanalMsgConsumer> loader = new ExtensionLoader<>(CanalMsgConsumer.class);\n        // see https://github.com/alibaba/canal/pull/5175\n        String key = destination + \"_\" + groupId;\n        canalMsgConsumer = new ProxyCanalMsgConsumer(loader.getExtension(canalClientConfig.getMode().toLowerCase(),\n            key,\n            CONNECTOR_SPI_DIR,\n            CONNECTOR_STANDBY_SPI_DIR));\n\n        Properties properties = canalClientConfig.getConsumerProperties();\n        properties.put(CanalConstants.CANAL_MQ_FLAT_MESSAGE, canalClientConfig.getFlatMessage());\n        properties.put(CanalConstants.CANAL_ALIYUN_ACCESS_KEY, canalClientConfig.getAccessKey());\n        properties.put(CanalConstants.CANAL_ALIYUN_SECRET_KEY, canalClientConfig.getSecretKey());\n        canalMsgConsumer.init(properties, canalDestination, groupId);\n    }\n\n    public void start() {\n        if (!running) {\n            thread = new Thread(this::process);\n            thread.setUncaughtExceptionHandler(handler);\n            thread.start();\n            running = true;\n        }\n    }\n\n    public void writeOut(final List<CommonMessage> commonMessages) {\n        List<Future<Boolean>> futures = new ArrayList<>();\n        // 组间适配器并行运行\n        // 当 canalOuterAdapters 初始化失败时，消息将会全部丢失\n        canalOuterAdapters.forEach(outerAdapters -> {\n            futures.add(groupInnerExecutorService.submit(() -> {\n                try {\n                    // 组内适配器穿行运行，尽量不要配置组内适配器\n                    outerAdapters.forEach(adapter -> {\n                        long begin = System.currentTimeMillis();\n                        List<Dml> dmls = MessageUtil.flatMessage2Dml(canalDestination, groupId, commonMessages);\n                        batchSync(dmls, adapter);\n\n                        if (logger.isDebugEnabled()) {\n                            logger.debug(\"{} elapsed time: {}\",\n                                adapter.getClass().getName(),\n                                (System.currentTimeMillis() - begin));\n                        }\n                    });\n                    return true;\n                } catch (Exception e) {\n                    logger.error(e.getMessage(), e);\n                    return false;\n                }\n            }));\n\n            // 等待所有适配器写入完成\n            // 由于是组间并发操作，所以将阻塞直到耗时最久的工作组操作完成\n            RuntimeException exception = null;\n            for (Future<Boolean> future : futures) {\n                try {\n                    if (!future.get()) {\n                        exception = new RuntimeException(\"Outer adapter sync failed! \");\n                    }\n                } catch (Exception e) {\n                    exception = new RuntimeException(e);\n                }\n            }\n            if (exception != null) {\n                throw exception;\n            }\n        });\n    }\n\n    /**\n     * 分批同步\n     *\n     * @param dmls\n     * @param adapter\n     */\n    private void batchSync(List<Dml> dmls, OuterAdapter adapter) {\n        // 分批同步\n        if (dmls.size() <= canalClientConfig.getSyncBatchSize()) {\n            adapter.sync(dmls);\n        } else {\n            int len = 0;\n            List<Dml> dmlsBatch = new ArrayList<>();\n            for (Dml dml : dmls) {\n                dmlsBatch.add(dml);\n                if (dml.getData() == null || dml.getData().isEmpty()) {\n                    len += 1;\n                } else {\n                    len += dml.getData().size();\n                }\n                if (len >= canalClientConfig.getSyncBatchSize()) {\n                    adapter.sync(dmlsBatch);\n                    dmlsBatch.clear();\n                    len = 0;\n                }\n            }\n            if (!dmlsBatch.isEmpty()) {\n                adapter.sync(dmlsBatch);\n            }\n        }\n    }\n\n    private void process() {\n        while (!running) { // waiting until running == true\n            while (!running) {\n                try {\n                    Thread.sleep(1000);\n                } catch (InterruptedException e) {\n                }\n            }\n        }\n\n        int retry = canalClientConfig.getRetries() == null\n                    || canalClientConfig.getRetries() == 0 ? 1 : canalClientConfig.getRetries();\n        if (retry == -1) {\n            // 重试次数-1代表异常时一直阻塞重试\n            retry = Integer.MAX_VALUE;\n        }\n\n        while (running) {\n            try {\n                syncSwitch.get(canalDestination);\n\n                logger.info(\"=============> Start to connect destination: {} <=============\", this.canalDestination);\n                canalMsgConsumer.connect();\n                logger.info(\"=============> Subscribe destination: {} succeed <=============\", this.canalDestination);\n                out: while (running) {\n                    try {\n                        syncSwitch.get(canalDestination, 1L, TimeUnit.MINUTES);\n                    } catch (TimeoutException e) {\n                        break;\n                    }\n                    if (!running) {\n                        break;\n                    }\n\n                    for (int i = 0; i < retry; i++) {\n                        if (!running) {\n                            break;\n                        }\n                        try {\n                            if (logger.isDebugEnabled()) {\n                                logger.debug(\"destination: {} \", canalDestination);\n                            }\n                            long begin = System.currentTimeMillis();\n                            List<CommonMessage> commonMessages = canalMsgConsumer\n                                .getMessage(this.canalClientConfig.getTimeout(), TimeUnit.MILLISECONDS);\n                            writeOut(commonMessages);\n                            canalMsgConsumer.ack();\n                            if (logger.isDebugEnabled()) {\n                                logger.debug(\"destination: {} elapsed time: {} ms\",\n                                    canalDestination,\n                                    System.currentTimeMillis() - begin);\n                            }\n                            break;\n                        } catch (Exception e) {\n                            Throwable th = e.getCause();\n                            // Handle source error when getting message\n                            if (th instanceof CanalClientException) {\n                                String message = ExceptionUtils.getRootCauseMessage(th);\n                                if (message.contains(\"end of stream when reading header\")\n                                    || message.contains(\"Connection reset by peer\") || message.contains(\"Broken pipe\")) {\n                                    logger.error(\"Sync failed, reconnect to canal instance. Error: {}\", message);\n                                    break out;\n                                }\n                            }\n                            // Handle sink error\n                            if (i != retry - 1) {\n                                canalMsgConsumer.rollback(); // 处理失败, 回滚数据\n                                logger.error(e.getMessage() + \" Error sync and rollback, execute times: \" + (i + 1));\n                            } else {\n                                if (canalClientConfig.getTerminateOnException()) {\n                                    canalMsgConsumer.rollback();\n                                    logger.error(\"Retry fail, turn switch off and abort data transfer.\");\n                                    syncSwitch.off(canalDestination);\n                                    logger.error(\"finish turn off switch of destination:\" + canalDestination);\n                                } else {\n                                    canalMsgConsumer.ack();\n                                    logger.error(e.getMessage() + \" Error sync but ACK!\", e);\n                                }\n                            }\n                            Thread.sleep(500);\n                        }\n                    }\n                }\n\n                canalMsgConsumer.disconnect();\n            } catch (Throwable e) {\n                logger.error(\"process error!\", e);\n            }\n\n            if (running) { // is reconnect\n                try {\n                    Thread.sleep(1000);\n                } catch (InterruptedException e) {\n                    // ignore\n                }\n            }\n        }\n    }\n\n    public void stop() {\n        try {\n            if (!running) {\n                return;\n            }\n\n            running = false;\n\n            syncSwitch.release(canalDestination);\n\n            logger.info(\"destination {} is waiting for adapters' worker thread die!\", canalDestination);\n            if (thread != null) {\n                try {\n                    thread.join();\n                } catch (InterruptedException e) {\n                    // ignore\n                }\n            }\n            groupInnerExecutorService.shutdown();\n            logger.info(\"destination {} adapters worker thread dead!\", canalDestination);\n            canalOuterAdapters.forEach(outerAdapters -> outerAdapters.forEach(OuterAdapter::destroy));\n            logger.info(\"destination {} all adapters destroyed!\", canalDestination);\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/launcher/src/main/java/com/alibaba/otter/canal/adapter/launcher/loader/CanalAdapterLoader.java",
    "content": "package com.alibaba.otter.canal.adapter.launcher.loader;\r\n\r\nimport java.util.HashMap;\r\nimport java.util.List;\r\nimport java.util.Map;\r\nimport java.util.Properties;\r\nimport java.util.concurrent.CopyOnWriteArrayList;\r\nimport java.util.concurrent.ExecutorService;\r\nimport java.util.concurrent.Executors;\r\nimport java.util.concurrent.TimeUnit;\r\n\r\nimport org.apache.commons.lang.StringUtils;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\nimport org.springframework.core.env.EnumerablePropertySource;\r\nimport org.springframework.core.env.Environment;\r\nimport org.springframework.core.env.PropertySource;\r\nimport org.springframework.core.env.StandardEnvironment;\r\nimport org.springframework.util.CollectionUtils;\r\n\r\nimport com.alibaba.otter.canal.adapter.launcher.config.SpringContext;\r\nimport com.alibaba.otter.canal.client.adapter.OuterAdapter;\r\nimport com.alibaba.otter.canal.client.adapter.ProxyOuterAdapter;\r\nimport com.alibaba.otter.canal.client.adapter.support.CanalClientConfig;\r\nimport com.alibaba.otter.canal.client.adapter.support.ExtensionLoader;\r\nimport com.alibaba.otter.canal.client.adapter.support.OuterAdapterConfig;\r\nimport com.alibaba.otter.canal.client.adapter.support.Util;\r\n\r\n/**\r\n * 外部适配器的加载器\r\n *\r\n * @version 1.0.0\r\n */\r\npublic class CanalAdapterLoader {\r\n\r\n    private static final Logger           logger                 = LoggerFactory.getLogger(CanalAdapterLoader.class);\r\n\r\n    private CanalClientConfig             canalClientConfig;\r\n\r\n    private Map<String, AdapterProcessor> canalAdapterProcessors = new HashMap<>();\r\n\r\n    private ExtensionLoader<OuterAdapter> loader;\r\n\r\n    public CanalAdapterLoader(CanalClientConfig canalClientConfig){\r\n        this.canalClientConfig = canalClientConfig;\r\n    }\r\n\r\n    /**\r\n     * 初始化canal-client\r\n     */\r\n    public void init() {\r\n        loader = ExtensionLoader.getExtensionLoader(OuterAdapter.class);\r\n\r\n        for (CanalClientConfig.CanalAdapter canalAdapter : canalClientConfig.getCanalAdapters()) {\r\n            for (CanalClientConfig.Group group : canalAdapter.getGroups()) {\r\n                int autoGenId = 0;\r\n                List<List<OuterAdapter>> canalOuterAdapterGroups = new CopyOnWriteArrayList<>();\r\n                List<OuterAdapter> canalOuterAdapters = new CopyOnWriteArrayList<>();\r\n\r\n                for (OuterAdapterConfig config : group.getOuterAdapters()) {\r\n                    // 保证一定有key\r\n                    if (StringUtils.isEmpty(config.getKey())) {\r\n                        String key = StringUtils.join(\r\n                            new String[] { Util.AUTO_GENERATED_PREFIX, canalAdapter.getInstance(), group.getGroupId(),\r\n                                           String.valueOf(autoGenId) },\r\n                            '-');\r\n                        //gen keyId\r\n                        config.setKey(key);\r\n                    }\r\n                    autoGenId++;\r\n                    loadAdapter(config, canalOuterAdapters);\r\n                }\r\n                canalOuterAdapterGroups.add(canalOuterAdapters);\r\n                // canalOuterAdapters 存在初始化失败的情况，导致canalOuterAdapters的数量，可能小于group.getOuterAdapters\r\n                // 由于group下的 所有OuterAdapter实例都会重复消费同一批消息，因此不允许部分adapter初始化成功，必须全部初始化成功才允许消费\r\n                if(CollectionUtils.isEmpty(canalOuterAdapters) || canalOuterAdapters.size() != group.getOuterAdapters().size() ){\r\n                    String msg = String.format(\"instance=%s,groupId=%s Load OuterAdapters is Empty，pls check rdb.yml\",\r\n                                canalAdapter.getInstance(),group.getGroupId());\r\n                        throw new RuntimeException(msg);\r\n                 }\r\n                AdapterProcessor adapterProcessor = canalAdapterProcessors.computeIfAbsent(\r\n                    canalAdapter.getInstance() + \"|\" + StringUtils.trimToEmpty(group.getGroupId()),\r\n                    f -> new AdapterProcessor(canalClientConfig,\r\n                        canalAdapter.getInstance(),\r\n                        group.getGroupId(),\r\n                        canalOuterAdapterGroups));\r\n                adapterProcessor.start();\r\n                logger.info(\"Start adapter for canal-client mq topic: {} succeed\",\r\n                    canalAdapter.getInstance() + \"-\" + group.getGroupId());\r\n            }\r\n        }\r\n    }\r\n\r\n    private void loadAdapter(OuterAdapterConfig config, List<OuterAdapter> canalOutConnectors) {\r\n        try {\r\n            OuterAdapter adapter;\r\n            adapter = new ProxyOuterAdapter(loader.getExtension(config.getName(), config.getKey()));\r\n\r\n            Environment env = (Environment) SpringContext.getBean(Environment.class);\r\n            Properties evnProperties = null;\r\n            if (env instanceof StandardEnvironment) {\r\n                evnProperties = new Properties();\r\n                for (PropertySource<?> propertySource : ((StandardEnvironment) env).getPropertySources()) {\r\n                    if (propertySource instanceof EnumerablePropertySource) {\r\n                        String[] names = ((EnumerablePropertySource<?>) propertySource).getPropertyNames();\r\n                        for (String name : names) {\r\n                            Object val = env.getProperty(name);\r\n                            if (val != null) {\r\n                                evnProperties.put(name, val);\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            adapter.init(config, evnProperties);\r\n            // rdb文件解析异常时，canalOuterAdapters 无法正常加载\r\n            canalOutConnectors.add(adapter);\r\n            logger.info(\"Load canal adapter: {} succeed\", config.getName());\r\n        } catch (Exception e) {\r\n            logger.error(\"Load canal adapter: {} failed\", config.getName(), e);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 销毁所有适配器 为防止canal实例太多造成销毁阻塞, 并行销毁\r\n     */\r\n    public void destroy() {\r\n        if (!canalAdapterProcessors.isEmpty()) {\r\n            ExecutorService stopExecutorService = Executors.newFixedThreadPool(canalAdapterProcessors.size());\r\n            for (AdapterProcessor adapterProcessor : canalAdapterProcessors.values()) {\r\n                stopExecutorService.execute(adapterProcessor::stop);\r\n            }\r\n            stopExecutorService.shutdown();\r\n            try {\r\n                while (!stopExecutorService.awaitTermination(1, TimeUnit.SECONDS)) {\r\n                    // ignore\r\n                }\r\n            } catch (InterruptedException e) {\r\n                // ignore\r\n            }\r\n        }\r\n        logger.info(\"All canal adapters destroyed\");\r\n    }\r\n}\r\n"
  },
  {
    "path": "client-adapter/launcher/src/main/java/com/alibaba/otter/canal/adapter/launcher/loader/CanalAdapterService.java",
    "content": "package com.alibaba.otter.canal.adapter.launcher.loader;\n\nimport javax.annotation.PostConstruct;\nimport javax.annotation.PreDestroy;\nimport javax.annotation.Resource;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.cloud.context.config.annotation.RefreshScope;\nimport org.springframework.cloud.context.refresh.ContextRefresher;\nimport org.springframework.core.env.Environment;\nimport org.springframework.stereotype.Component;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.alibaba.otter.canal.adapter.launcher.common.SyncSwitch;\nimport com.alibaba.otter.canal.adapter.launcher.config.AdapterCanalConfig;\nimport com.alibaba.otter.canal.adapter.launcher.config.SpringContext;\nimport com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;\n\n/**\n * 适配器启动业务类\n *\n * @author rewerma @ 2018-10-20\n * @version 1.0.0\n */\n@Component\n@RefreshScope\npublic class CanalAdapterService {\n\n    private static final Logger logger  = LoggerFactory.getLogger(CanalAdapterService.class);\n\n    private CanalAdapterLoader  adapterLoader;\n\n    @Resource\n    private ContextRefresher    contextRefresher;\n\n    @Resource\n    private AdapterCanalConfig  adapterCanalConfig;\n    @Resource\n    private Environment         env;\n\n    // 注入bean保证优先注册\n    @Resource\n    private SpringContext       springContext;\n    @Resource\n    private SyncSwitch          syncSwitch;\n\n    private volatile boolean    running = false;\n\n    @PostConstruct\n    public synchronized void init() {\n        if (running) {\n            return;\n        }\n        try {\n            syncSwitch.refresh();\n            logger.info(\"## syncSwitch refreshed.\");\n            logger.info(\"## start the canal client adapters.\");\n            adapterLoader = new CanalAdapterLoader(adapterCanalConfig);\n            adapterLoader.init();\n            running = true;\n            logger.info(\"## the canal client adapters are running now ......\");\n        } catch (Exception e) {\n            logger.error(\"## something goes wrong when starting up the canal client adapters:\", e);\n        }\n    }\n\n    @PreDestroy\n    public synchronized void destroy() {\n        if (!running) {\n            return;\n        }\n        try {\n            running = false;\n            logger.info(\"## stop the canal client adapters\");\n\n            if (adapterLoader != null) {\n                adapterLoader.destroy();\n                adapterLoader = null;\n            }\n            for (DruidDataSource druidDataSource : DatasourceConfig.DATA_SOURCES.values()) {\n                try {\n                    druidDataSource.close();\n                } catch (Exception e) {\n                    logger.error(e.getMessage(), e);\n                }\n            }\n            DatasourceConfig.DATA_SOURCES.clear();\n        } catch (Throwable e) {\n            logger.warn(\"## something goes wrong when stopping canal client adapters:\", e);\n        } finally {\n            logger.info(\"## canal client adapters are down.\");\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/launcher/src/main/java/com/alibaba/otter/canal/adapter/launcher/monitor/ApplicationConfigMonitor.java",
    "content": "package com.alibaba.otter.canal.adapter.launcher.monitor;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.InputStreamReader;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Map;\n\nimport javax.annotation.PostConstruct;\nimport javax.annotation.PreDestroy;\nimport javax.annotation.Resource;\n\nimport org.apache.commons.io.filefilter.FileFilterUtils;\nimport org.apache.commons.io.monitor.FileAlterationListenerAdaptor;\nimport org.apache.commons.io.monitor.FileAlterationMonitor;\nimport org.apache.commons.io.monitor.FileAlterationObserver;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.cloud.context.refresh.ContextRefresher;\nimport org.springframework.stereotype.Component;\nimport org.yaml.snakeyaml.Yaml;\n\nimport com.alibaba.otter.canal.adapter.launcher.loader.CanalAdapterService;\nimport com.alibaba.otter.canal.client.adapter.support.Util;\n\n@Component\npublic class ApplicationConfigMonitor {\n\n    private static final Logger   logger = LoggerFactory.getLogger(ApplicationConfigMonitor.class);\n\n    @Resource\n    private ContextRefresher      contextRefresher;\n\n    @Resource\n    private CanalAdapterService   canalAdapterService;\n\n    private FileAlterationMonitor fileMonitor;\n\n    @PostConstruct\n    public void init() {\n        File confDir = Util.getConfDirPath();\n        try {\n            FileAlterationObserver observer = new FileAlterationObserver(confDir,\n                FileFilterUtils.and(FileFilterUtils.fileFileFilter(),\n                    FileFilterUtils.prefixFileFilter(\"application\"),\n                    FileFilterUtils.suffixFileFilter(\"yml\")));\n            FileListener listener = new FileListener();\n            observer.addListener(listener);\n            fileMonitor = new FileAlterationMonitor(3000, observer);\n            fileMonitor.start();\n\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n        }\n    }\n\n    @PreDestroy\n    public void destroy() {\n        try {\n            fileMonitor.stop();\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n        }\n    }\n\n    private class FileListener extends FileAlterationListenerAdaptor {\n\n        @Override\n        public void onFileChange(File file) {\n            super.onFileChange(file);\n            try {\n                // 检查yml格式\n                new Yaml().loadAs(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8), Map.class);\n\n                canalAdapterService.destroy();\n\n                // refresh context\n                contextRefresher.refresh();\n\n                try {\n                    Thread.sleep(2000);\n                } catch (InterruptedException e) {\n                    // ignore\n                }\n                canalAdapterService.init();\n                logger.info(\"## adapter application config reloaded.\");\n            } catch (Exception e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/launcher/src/main/java/com/alibaba/otter/canal/adapter/launcher/monitor/remote/ConfigItem.java",
    "content": "package com.alibaba.otter.canal.adapter.launcher.monitor.remote;\n\n/**\n * 配置对应对象\n *\n * @author rewerma 2019-01-25 下午05:20:16\n * @version 1.0.0\n */\npublic class ConfigItem {\n\n    private Long   id;\n    private String category;\n    private String name;\n    private String content;\n    private long   modifiedTime;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public String getCategory() {\n        return category;\n    }\n\n    public void setCategory(String category) {\n        this.category = category;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getContent() {\n        return content;\n    }\n\n    public void setContent(String content) {\n        this.content = content;\n    }\n\n    public long getModifiedTime() {\n        return modifiedTime;\n    }\n\n    public void setModifiedTime(long modifiedTime) {\n        this.modifiedTime = modifiedTime;\n    }\n}\n"
  },
  {
    "path": "client-adapter/launcher/src/main/java/com/alibaba/otter/canal/adapter/launcher/monitor/remote/DbRemoteConfigLoader.java",
    "content": "package com.alibaba.otter.canal.adapter.launcher.monitor.remote;\n\nimport java.io.FileOutputStream;\nimport java.io.OutputStreamWriter;\nimport java.nio.charset.StandardCharsets;\nimport java.sql.Connection;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.alibaba.otter.canal.adapter.launcher.config.AdapterConfigHolder;\nimport com.alibaba.otter.canal.common.utils.CommonUtils;\nimport com.alibaba.otter.canal.common.utils.NamedThreadFactory;\nimport com.google.common.base.Joiner;\n\n/**\n * 基于数据库的远程配置装载器\n *\n * @author rewerma 2019-01-25 下午05:20:16\n * @version 1.0.0\n */\npublic class DbRemoteConfigLoader implements RemoteConfigLoader {\n\n    private static final Logger      logger                    = LoggerFactory.getLogger(DbRemoteConfigLoader.class);\n\n    private DruidDataSource          dataSource;\n\n    private AdapterConfigHolder      remoteAdapterConfigHolder = AdapterConfigHolder.getInstance();\n\n    private ScheduledExecutorService executor                  = Executors.newScheduledThreadPool(2,\n        new NamedThreadFactory(\"remote-adapter-config-scan\"));\n\n    private RemoteAdapterMonitor     remoteAdapterMonitor      = new RemoteAdapterMonitorImpl();\n\n    public DbRemoteConfigLoader(String driverName, String jdbcUrl, String jdbcUsername, String jdbcPassword){\n        dataSource = new DruidDataSource();\n        if (StringUtils.isEmpty(driverName)) {\n            driverName = \"com.mysql.jdbc.Driver\";\n        }\n        dataSource.setDriverClassName(driverName);\n        dataSource.setUrl(jdbcUrl);\n        dataSource.setUsername(jdbcUsername);\n        dataSource.setPassword(jdbcPassword);\n        dataSource.setInitialSize(1);\n        dataSource.setMinIdle(1);\n        dataSource.setMaxActive(1);\n        dataSource.setMaxWait(60000);\n        dataSource.setTimeBetweenEvictionRunsMillis(60000);\n        dataSource.setMinEvictableIdleTimeMillis(300000);\n        try {\n            dataSource.init();\n        } catch (SQLException e) {\n            throw new RuntimeException(e.getMessage(), e);\n        }\n    }\n\n    /**\n     * 加载远程application.yml配置\n     */\n    @Override\n    public void loadRemoteConfig() {\n        try {\n            // 加载远程adapter配置\n            ConfigItem configItem = getRemoteAdapterConfig();\n            if (configItem != null) {\n                if (configItem.getModifiedTime() != remoteAdapterConfigHolder.getAdapterConfigTimestamp()) {\n                    remoteAdapterConfigHolder.setAdapterConfigTimestamp(configItem.getModifiedTime());\n                    overrideLocalCanalConfig(configItem.getContent());\n                    logger.info(\"## Loaded remote adapter config: application.yml\");\n                }\n            }\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n        }\n    }\n\n    /**\n     * 获取远程application.yml配置\n     *\n     * @return 配置对象\n     */\n    private ConfigItem getRemoteAdapterConfig() {\n        String sql = \"select name, content, modified_time from canal_config where id=2\";\n        try (Connection conn = dataSource.getConnection();\n                Statement stmt = conn.createStatement();\n                ResultSet rs = stmt.executeQuery(sql)) {\n            if (rs.next()) {\n                ConfigItem configItem = new ConfigItem();\n                configItem.setId(2L);\n                configItem.setName(rs.getString(\"name\"));\n                configItem.setContent(rs.getString(\"content\"));\n                configItem.setModifiedTime(rs.getTimestamp(\"modified_time\").getTime());\n                return configItem;\n            }\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n        }\n        return null;\n    }\n\n    /**\n     * 覆盖本地application.yml文件\n     *\n     * @param content 文件内容\n     */\n    private void overrideLocalCanalConfig(String content) {\n\n        try (OutputStreamWriter writer = new OutputStreamWriter(\n            new FileOutputStream(CommonUtils.getConfPath() + \"application.yml\"),\n            StandardCharsets.UTF_8)) {\n            writer.write(content);\n            writer.flush();\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n        }\n    }\n\n    /**\n     * 加载adapter配置\n     */\n    @Override\n    public void loadRemoteAdapterConfigs() {\n        try {\n            // 加载远程adapter配置\n            loadModifiedAdapterConfigs();\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n        }\n    }\n\n    /**\n     * 加载有变动的adapter配置\n     */\n    private void loadModifiedAdapterConfigs() {\n        Map<String, ConfigItem> remoteConfigStatus = new HashMap<>();\n        String sql = \"select id, category, name, modified_time from canal_adapter_config\";\n        try (Connection conn = dataSource.getConnection();\n                Statement stmt = conn.createStatement();\n                ResultSet rs = stmt.executeQuery(sql)) {\n            while (rs.next()) {\n                ConfigItem configItem = new ConfigItem();\n                configItem.setId(rs.getLong(\"id\"));\n                configItem.setCategory(rs.getString(\"category\"));\n                configItem.setName(rs.getString(\"name\"));\n                configItem.setModifiedTime(rs.getTimestamp(\"modified_time\").getTime());\n                remoteConfigStatus.put(configItem.getCategory() + \"/\" + configItem.getName(), configItem);\n            }\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n        }\n\n        if (!remoteConfigStatus.isEmpty()) {\n            List<Long> changedIds = new ArrayList<>();\n\n            for (ConfigItem remoteConfigStat : remoteConfigStatus.values()) {\n                ConfigItem currentConfig = remoteAdapterConfigHolder.getAdapterConfigs()\n                    .get(remoteConfigStat.getCategory() + \"/\" + remoteConfigStat.getName());\n                if (currentConfig == null) {\n                    // 新增\n                    changedIds.add(remoteConfigStat.getId());\n                } else {\n                    // 修改\n                    if (currentConfig.getModifiedTime() != remoteConfigStat.getModifiedTime()) {\n                        changedIds.add(remoteConfigStat.getId());\n                    }\n                }\n            }\n            if (!changedIds.isEmpty()) {\n                String contentsSql = \"select id, category, name, content, modified_time from canal_adapter_config  where id in (\"\n                                     + Joiner.on(\",\").join(changedIds) + \")\";\n                try (Connection conn = dataSource.getConnection();\n                        Statement stmt = conn.createStatement();\n                        ResultSet rs = stmt.executeQuery(contentsSql)) {\n                    while (rs.next()) {\n                        ConfigItem configItemNew = new ConfigItem();\n                        configItemNew.setId(rs.getLong(\"id\"));\n                        configItemNew.setCategory(rs.getString(\"category\"));\n                        configItemNew.setName(rs.getString(\"name\"));\n                        configItemNew.setContent(rs.getString(\"content\"));\n                        configItemNew.setModifiedTime(rs.getTimestamp(\"modified_time\").getTime());\n\n                        remoteAdapterConfigHolder.getAdapterConfigs()\n                            .put(configItemNew.getCategory() + \"/\" + configItemNew.getName(), configItemNew);\n                        remoteAdapterMonitor.onModify(configItemNew);\n                    }\n\n                } catch (Exception e) {\n                    logger.error(e.getMessage(), e);\n                }\n            }\n        }\n\n        for (ConfigItem configItem : remoteAdapterConfigHolder.getAdapterConfigs().values()) {\n            if (!remoteConfigStatus.containsKey(configItem.getCategory() + \"/\" + configItem.getName())) {\n                // 删除\n                remoteAdapterConfigHolder.getAdapterConfigs()\n                    .remove(configItem.getCategory() + \"/\" + configItem.getName());\n                remoteAdapterMonitor.onDelete(configItem.getCategory() + \"/\" + configItem.getName());\n            }\n        }\n    }\n\n    /**\n     * 启动监听数据库变化\n     */\n    @Override\n    public void startMonitor() {\n        // 监听application.yml变化\n        executor.scheduleWithFixedDelay(() -> {\n            try {\n                loadRemoteConfig();\n            } catch (Throwable e) {\n                logger.error(\"scan remote application.yml failed\", e);\n            }\n        }, 10, 3, TimeUnit.SECONDS);\n\n        // 监听adapter变化\n        executor.scheduleWithFixedDelay(() -> {\n            try {\n                loadRemoteAdapterConfigs();\n            } catch (Throwable e) {\n                logger.error(\"scan remote adapter configs failed\", e);\n            }\n        }, 10, 3, TimeUnit.SECONDS);\n    }\n\n    /**\n     * 销毁\n     */\n    @Override\n    public void destroy() {\n        executor.shutdownNow();\n        try {\n            dataSource.close();\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/launcher/src/main/java/com/alibaba/otter/canal/adapter/launcher/monitor/remote/RemoteAdapterMonitor.java",
    "content": "package com.alibaba.otter.canal.adapter.launcher.monitor.remote;\n\n/**\n * 远程配置监听器接口\n *\n * @author rewerma 2019-01-25 下午05:20:16\n * @version 1.0.0\n */\npublic interface RemoteAdapterMonitor {\n\n    /**\n     * 新增配置事件\n     *\n     * @param configItem 配置项\n     */\n    void onAdd(ConfigItem configItem);\n\n    /**\n     * 修改配置事件\n     *\n     * @param configItem 配置项\n     */\n    void onModify(ConfigItem configItem);\n\n    /**\n     * 删除配置事件\n     *\n     * @param name 配置名\n     */\n    void onDelete(String name);\n}\n"
  },
  {
    "path": "client-adapter/launcher/src/main/java/com/alibaba/otter/canal/adapter/launcher/monitor/remote/RemoteAdapterMonitorImpl.java",
    "content": "package com.alibaba.otter.canal.adapter.launcher.monitor.remote;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.OutputStreamWriter;\nimport java.nio.charset.StandardCharsets;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.common.utils.CommonUtils;\n\n/**\n * 远程配置监听器实现\n *\n * @author rewerma 2019-01-25 下午05:20:16\n * @version 1.0.0\n */\npublic class RemoteAdapterMonitorImpl implements RemoteAdapterMonitor {\n\n    private static final Logger logger = LoggerFactory.getLogger(RemoteAdapterMonitorImpl.class);\n\n    @Override\n    public void onAdd(ConfigItem configItem) {\n        this.onModify(configItem);\n    }\n\n    @Override\n    public void onModify(ConfigItem configItem) {\n        String confPath = CommonUtils.getConfPath();\n        String category = configItem.getCategory();\n        File categoryDir = new File(confPath + category);\n        if (!categoryDir.isDirectory()) {\n            boolean mkDirs = categoryDir.mkdirs();\n            if (!mkDirs) {\n                logger.info(\"## Create adapter category dir error: {}\", category);\n                return;\n            }\n        }\n        String name = configItem.getName();\n        try (OutputStreamWriter writer = new OutputStreamWriter(\n            new FileOutputStream(confPath + category + \"/\" + configItem.getName()),\n            StandardCharsets.UTF_8)) {\n            writer.write(configItem.getContent());\n            writer.flush();\n            logger.info(\"## Loaded remote adapter config: {}/{}\", category, name);\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n        }\n    }\n\n    @Override\n    public void onDelete(String name) {\n        File file = new File(CommonUtils.getConfPath() + name);\n        if (file.exists()) {\n            CommonUtils.deleteDir(file);\n            logger.info(\"## Deleted and reloaded remote adapter config: {}\", name);\n        }\n    }\n\n}\n"
  },
  {
    "path": "client-adapter/launcher/src/main/java/com/alibaba/otter/canal/adapter/launcher/monitor/remote/RemoteConfigLoader.java",
    "content": "package com.alibaba.otter.canal.adapter.launcher.monitor.remote;\n\n/**\n * 远程配置装载器接口\n *\n * @author rewerma 2019-01-25 下午05:20:16\n * @version 1.0.0\n */\npublic interface RemoteConfigLoader {\n\n    /**\n     * 加载远程application.yml配置到本地\n     */\n    void loadRemoteConfig();\n\n    /**\n     * 加载adapter配置\n     */\n    void loadRemoteAdapterConfigs();\n\n    /**\n     * 启动监听数据库变化\n     */\n    void startMonitor();\n\n    /**\n     * 销毁\n     */\n    void destroy();\n}\n"
  },
  {
    "path": "client-adapter/launcher/src/main/java/com/alibaba/otter/canal/adapter/launcher/monitor/remote/RemoteConfigLoaderFactory.java",
    "content": "package com.alibaba.otter.canal.adapter.launcher.monitor.remote;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.core.env.Environment;\n\n/**\n * 远程配置装载器工厂类\n *\n * @author rewerma 2019-01-25 下午05:20:16\n * @version 1.0.0\n */\npublic class RemoteConfigLoaderFactory {\n\n    private static final Logger logger = LoggerFactory.getLogger(RemoteConfigLoaderFactory.class);\n\n    public static RemoteConfigLoader getRemoteConfigLoader(Environment env) {\n        try {\n            String jdbcUrl = env.getProperty(\"canal.manager.jdbc.url\");\n            if (!StringUtils.isEmpty(jdbcUrl)) {\n                // load remote config\n                String driverName = env.getProperty(\"canal.manager.jdbc.driverName\");\n                String jdbcUsername = env.getProperty(\"canal.manager.jdbc.username\");\n                String jdbcPassword = env.getProperty(\"canal.manager.jdbc.password\");\n                return new DbRemoteConfigLoader(driverName, jdbcUrl, jdbcUsername, jdbcPassword);\n            }\n            // 可扩展其它远程配置加载器\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "client-adapter/launcher/src/main/java/com/alibaba/otter/canal/adapter/launcher/prometheus/CanalAdapterExports.java",
    "content": "package com.alibaba.otter.canal.adapter.launcher.prometheus;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * @author sunxien\n * @date 2025/5/19\n * @since 1.0.0-SNAPSHOT\n */\npublic class CanalAdapterExports {\n\n    private static final Logger logger = LoggerFactory.getLogger(CanalAdapterExports.class);\n\n    private CanalAdapterExports() {\n    }\n\n    private static class SingletonHolder {\n        private static final CanalAdapterExports SINGLETON = new CanalAdapterExports();\n    }\n\n    public static CanalAdapterExports instance() {\n        return SingletonHolder.SINGLETON;\n    }\n\n    public void initialize() {\n        // TODO\n    }\n\n    public void terminate() {\n        // TODO\n    }\n}\n"
  },
  {
    "path": "client-adapter/launcher/src/main/java/com/alibaba/otter/canal/adapter/launcher/prometheus/PrometheusService.java",
    "content": "package com.alibaba.otter.canal.adapter.launcher.prometheus;\n\nimport java.io.IOException;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.DisposableBean;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.stereotype.Component;\n\nimport io.prometheus.client.exporter.HTTPServer;\nimport io.prometheus.client.hotspot.DefaultExports;\n\n/**\n * @author sunxien\n * @date 2025/5/19\n * @since 1.0.0-SNAPSHOT\n */\n@Component\npublic class PrometheusService implements InitializingBean, DisposableBean {\n\n    private static final Logger logger = LoggerFactory.getLogger(PrometheusService.class);\n\n    private final CanalAdapterExports adapterExports;\n    private volatile boolean running = false;\n\n    /**\n     * <pre>\n     * Canal Server admin port: 11110\n     * Canal Server tcp port: 11111\n     * Canal Server metric port: 11112\n     * Canal Adapter metric port: 11113\n     * </pre>\n     */\n    private int port = 11113;\n    private HTTPServer httpServer;\n\n    private PrometheusService() {\n        this.adapterExports = CanalAdapterExports.instance();\n    }\n\n    private static class SingletonHolder {\n        private static final PrometheusService SINGLETON = new PrometheusService();\n    }\n\n    public static PrometheusService getInstance() {\n        return SingletonHolder.SINGLETON;\n    }\n\n    @Override\n    public void afterPropertiesSet() throws Exception {\n        PrometheusService.getInstance().initialize();\n    }\n\n    @Override\n    public void destroy() throws Exception {\n        PrometheusService.getInstance().terminate();\n    }\n\n    public void initialize() {\n        try {\n            logger.info(\"Starting prometheus HTTPServer on port {}....\", port);\n            // TODO 2.Https?\n            httpServer = new HTTPServer(port);\n            logger.info(\"Start prometheus HTTPServer on port {} success\", port);\n        } catch (IOException e) {\n            logger.error(\"Unable to start prometheus HTTPServer on port {}.\", port, e);\n            return;\n        }\n        try {\n            // JVM exports\n            DefaultExports.initialize();\n            // adapterExports.initialize();\n            this.running = true;\n        } catch (Throwable t) {\n            logger.error(\"Unable to initialize adapter exports. (Register the default Hotspot collectors)\", t);\n        }\n    }\n\n    public void terminate() {\n        try {\n            this.running = false;\n            adapterExports.terminate();\n            if (httpServer != null) {\n                httpServer.stop();\n                logger.info(\"Stop prometheus HTTPServer on port {} success\", port);\n            }\n        } catch (Throwable t) {\n            logger.error(\"Something happened while terminating prometheus HTTPServer.\", t);\n        }\n    }\n\n    public boolean isRunning() {\n        return running;\n    }\n\n    public void setServerPort(int port) {\n        this.port = port;\n    }\n}\n"
  },
  {
    "path": "client-adapter/launcher/src/main/java/com/alibaba/otter/canal/adapter/launcher/rest/CommonRest.java",
    "content": "package com.alibaba.otter.canal.adapter.launcher.rest;\n\nimport com.alibaba.otter.canal.adapter.launcher.common.EtlLock;\nimport com.alibaba.otter.canal.adapter.launcher.common.SyncSwitch;\nimport com.alibaba.otter.canal.adapter.launcher.config.AdapterCanalConfig;\nimport com.alibaba.otter.canal.client.adapter.OuterAdapter;\nimport com.alibaba.otter.canal.client.adapter.support.EtlResult;\nimport com.alibaba.otter.canal.client.adapter.support.ExtensionLoader;\nimport com.alibaba.otter.canal.client.adapter.support.FileName2KeyMapping;\nimport com.alibaba.otter.canal.client.adapter.support.Result;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport javax.annotation.PostConstruct;\nimport javax.annotation.Resource;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.PutMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * 适配器操作Rest\n *\n * @author rewerma @ 2018-10-20\n * @version 1.0.0\n */\n@RestController\npublic class CommonRest {\n\n    private static Logger                 logger           = LoggerFactory.getLogger(CommonRest.class);\n\n    private static final String           ETL_LOCK_ZK_NODE = \"/sync-etl/\";\n\n    private ExtensionLoader<OuterAdapter> loader;\n\n    @Resource\n    private SyncSwitch                    syncSwitch;\n    @Resource\n    private EtlLock                       etlLock;\n\n    @Resource\n    private AdapterCanalConfig            adapterCanalConfig;\n\n    @PostConstruct\n    public void init() {\n        loader = ExtensionLoader.getExtensionLoader(OuterAdapter.class);\n    }\n\n    /**\n     * ETL curl http://127.0.0.1:8081/etl/rdb/oracle1/mytest_user.yml -X POST\n     *\n     * @param type 类型 hbase, es\n     * @param key adapter key\n     * @param task 任务名对应配置文件名 mytest_user.yml\n     * @param params etl where条件参数, 为空全部导入\n     */\n    @PostMapping(\"/etl/{type}/{key}/{task}\")\n    public EtlResult etl(@PathVariable String type, @PathVariable String key, @PathVariable String task,\n                         @RequestParam(name = \"params\", required = false) String params) {\n        if (key == null) {\n            key = FileName2KeyMapping.getKey(type, task);\n        }\n        OuterAdapter adapter = loader.getExtension(type, key);\n        String destination = adapter.getDestination(task);\n        String lockKey = destination == null ? task : destination;\n\n        boolean locked = etlLock.tryLock(ETL_LOCK_ZK_NODE + type + \"-\" + lockKey);\n        if (!locked) {\n            EtlResult result = new EtlResult();\n            result.setSucceeded(false);\n            result.setErrorMessage(task + \" 有其他进程正在导入中, 请稍后再试\");\n            return result;\n        }\n        try {\n\n            boolean oriSwitchStatus;\n            if (destination != null) {\n                oriSwitchStatus = syncSwitch.status(destination);\n                if (oriSwitchStatus) {\n                    syncSwitch.off(destination);\n                }\n            } else {\n                // task可能为destination，直接锁task\n                oriSwitchStatus = syncSwitch.status(task);\n                if (oriSwitchStatus) {\n                    syncSwitch.off(task);\n                }\n            }\n            try {\n                List<String> paramArray = null;\n                if (params != null) {\n                    paramArray = Arrays.asList(params.trim().split(\";\"));\n                }\n                return adapter.etl(task, paramArray);\n            } finally {\n                if (destination != null && oriSwitchStatus) {\n                    syncSwitch.on(destination);\n                } else if (destination == null && oriSwitchStatus) {\n                    syncSwitch.on(task);\n                }\n            }\n        } finally {\n            etlLock.unlock(ETL_LOCK_ZK_NODE + type + \"-\" + lockKey);\n        }\n    }\n\n    /**\n     * ETL curl http://127.0.0.1:8081/etl/hbase/mytest_person2.yml -X POST\n     *\n     * @param type 类型 hbase, es\n     * @param task 任务名对应配置文件名 mytest_person2.yml\n     * @param params etl where条件参数, 为空全部导入\n     */\n    @PostMapping(\"/etl/{type}/{task}\")\n    public EtlResult etl(@PathVariable String type, @PathVariable String task,\n                         @RequestParam(name = \"params\", required = false) String params) {\n        return etl(type, null, task, params);\n    }\n\n    /**\n     * 统计总数 curl http://127.0.0.1:8081/count/rdb/oracle1/mytest_user.yml\n     *\n     * @param type 类型 hbase, es\n     * @param key adapter key\n     * @param task 任务名对应配置文件名 mytest_person2.yml\n     * @return\n     */\n    @GetMapping(\"/count/{type}/{key}/{task}\")\n    public Map<String, Object> count(@PathVariable String type, @PathVariable String key, @PathVariable String task) {\n        if (key == null) {\n            key = FileName2KeyMapping.getKey(type, task);\n        }\n        OuterAdapter adapter = loader.getExtension(type, key);\n        return adapter.count(task);\n    }\n\n    /**\n     * 统计总数 curl http://127.0.0.1:8081/count/hbase/mytest_person2.yml\n     *\n     * @param type 类型 hbase, es\n     * @param task 任务名对应配置文件名 mytest_person2.yml\n     * @return\n     */\n    @GetMapping(\"/count/{type}/{task}\")\n    public Map<String, Object> count(@PathVariable String type, @PathVariable String task) {\n        return count(type, null, task);\n    }\n\n    /**\n     * 返回所有实例 curl http://127.0.0.1:8081/destinations\n     */\n    @GetMapping(\"/destinations\")\n    public List<Map<String, String>> destinations() {\n        List<Map<String, String>> result = new ArrayList<>();\n        Set<String> destinations = adapterCanalConfig.DESTINATIONS;\n        for (String destination : destinations) {\n            Map<String, String> resMap = new LinkedHashMap<>();\n            boolean status = syncSwitch.status(destination);\n            String resStatus;\n            if (status) {\n                resStatus = \"on\";\n            } else {\n                resStatus = \"off\";\n            }\n            resMap.put(\"destination\", destination);\n            resMap.put(\"status\", resStatus);\n            result.add(resMap);\n        }\n        return result;\n    }\n\n    /**\n     * 实例同步开关 curl http://127.0.0.1:8081/syncSwitch/example/off -X PUT\n     *\n     * @param destination 实例名称\n     * @param status 开关状态: off on\n     * @return\n     */\n    @PutMapping(\"/syncSwitch/{destination}/{status}\")\n    public Result etl(@PathVariable String destination, @PathVariable String status) {\n        if (status.equals(\"on\")) {\n            syncSwitch.on(destination);\n            logger.info(\"#Destination: {} sync on\", destination);\n            return Result.createSuccess(\"实例: \" + destination + \" 开启同步成功\");\n        } else if (status.equals(\"off\")) {\n            syncSwitch.off(destination);\n            logger.info(\"#Destination: {} sync off\", destination);\n            return Result.createSuccess(\"实例: \" + destination + \" 关闭同步成功\");\n        } else {\n            Result result = new Result();\n            result.setCode(50000);\n            result.setMessage(\"实例: \" + destination + \" 操作失败\");\n            return result;\n        }\n    }\n\n    /**\n     * 获取实例开关状态 curl http://127.0.0.1:8081/syncSwitch/example\n     *\n     * @param destination 实例名称\n     * @return\n     */\n    @GetMapping(\"/syncSwitch/{destination}\")\n    public Map<String, String> etl(@PathVariable String destination) {\n        boolean status = syncSwitch.status(destination);\n        String resStatus;\n        if (status) {\n            resStatus = \"on\";\n        } else {\n            resStatus = \"off\";\n        }\n        Map<String, String> res = new LinkedHashMap<>();\n        res.put(\"status\", resStatus);\n        return res;\n    }\n}\n"
  },
  {
    "path": "client-adapter/launcher/src/main/resources/META-INF/spring.factories",
    "content": "# Bootstrap Configuration\norg.springframework.cloud.bootstrap.BootstrapConfiguration=\\\n  com.alibaba.otter.canal.adapter.launcher.config.BootstrapConfiguration"
  },
  {
    "path": "client-adapter/launcher/src/main/resources/application.yml",
    "content": "server:\n  port: 8081\nspring:\n  jackson:\n    date-format: yyyy-MM-dd HH:mm:ss\n    time-zone: GMT+8\n    default-property-inclusion: non_null\n\ncanal.conf:\n  mode: tcp #tcp kafka rocketMQ rabbitMQ\n  flatMessage: true\n  zookeeperHosts:\n  syncBatchSize: 1000\n  retries: -1\n  timeout:\n  accessKey:\n  secretKey:\n  consumerProperties:\n    # canal tcp consumer\n    canal.tcp.server.host: 127.0.0.1:11111\n    canal.tcp.zookeeper.hosts:\n    canal.tcp.batch.size: 500\n    canal.tcp.username:\n    canal.tcp.password:\n    # kafka consumer\n    kafka.bootstrap.servers: 127.0.0.1:9092\n    kafka.enable.auto.commit: false\n    kafka.auto.commit.interval.ms: 1000\n    kafka.auto.offset.reset: latest\n    kafka.request.timeout.ms: 40000\n    kafka.session.timeout.ms: 30000\n    kafka.isolation.level: read_committed\n    kafka.max.poll.records: 1000\n    # rocketMQ consumer\n    rocketmq.namespace:\n    rocketmq.namesrv.addr: 127.0.0.1:9876\n    rocketmq.batch.size: 1000\n    rocketmq.enable.message.trace: false\n    rocketmq.customized.trace.topic:\n    rocketmq.access.channel:\n    rocketmq.subscribe.filter:\n    # rabbitMQ consumer\n    rabbitmq.host:\n    rabbitmq.virtual.host:\n    rabbitmq.username:\n    rabbitmq.password:\n    rabbitmq.resource.ownerId:\n\n#  srcDataSources:\n#    defaultDS:\n#      url: jdbc:mysql://127.0.0.1:3306/mytest?useUnicode=true\n#      username: root\n#      password: 121212\n  canalAdapters:\n  - instance: example # canal instance Name or mq topic name\n    groups:\n    - groupId: g1\n      outerAdapters:\n      - name: logger\n#      - name: rdb\n#        key: mysql1\n#        properties:\n#          jdbc.driverClassName: com.mysql.jdbc.Driver\n#          jdbc.url: jdbc:mysql://127.0.0.1:3306/mytest2?useUnicode=true\n#          jdbc.username: root\n#          jdbc.password: 121212\n#          druid.stat.enable: false\n#          druid.stat.slowSqlMillis: 1000\n#      - name: rdb\n#        key: oracle1\n#        properties:\n#          jdbc.driverClassName: oracle.jdbc.OracleDriver\n#          jdbc.url: jdbc:oracle:thin:@localhost:49161:XE\n#          jdbc.username: mytest\n#          jdbc.password: m121212\n#      - name: rdb\n#        key: postgres1\n#        properties:\n#          jdbc.driverClassName: org.postgresql.Driver\n#          jdbc.url: jdbc:postgresql://localhost:5432/postgres\n#          jdbc.username: postgres\n#          jdbc.password: 121212\n#          threads: 1\n#          commitSize: 3000\n#      - name: hbase\n#        properties:\n#          hbase.zookeeper.quorum: 127.0.0.1\n#          hbase.zookeeper.property.clientPort: 2181\n#          zookeeper.znode.parent: /hbase\n#      - name: es\n#        hosts: 127.0.0.1:9300 # 127.0.0.1:9200 for rest mode\n#        properties:\n#          mode: transport # or rest\n#          # security.ca.path: /etc/es8/ca.crt\n#          # security.auth: test:123456 #  only used for rest mode\n#          cluster.name: elasticsearch\n#      - name: kudu\n#        key: kudu\n#        properties:\n#          kudu.master.address: 127.0.0.1 # ',' split multi address\n#      - name: phoenix\n#        key: phoenix\n#        properties:\n#          jdbc.driverClassName: org.apache.phoenix.jdbc.PhoenixDriver\n#          jdbc.url: jdbc:phoenix:127.0.0.1:2181:/hbase/db\n#          jdbc.username:\n#          jdbc.password:\n#      - name: clickhouse\n#        key: clickhouse1\n#        properties:\n#          jdbc.driverClassName: ru.yandex.clickhouse.ClickHouseDriver\n#          jdbc.url: jdbc:clickhouse://127.0.0.1:8123/default\n#          jdbc.username: default\n#          jdbc.password: 123456\n#          batchSize: 3000\n#          scheduleTime: 600   # second unit\n#          threads: 3          # parallel threads\n"
  },
  {
    "path": "client-adapter/launcher/src/main/resources/bootstrap.yml",
    "content": "canal:\n  manager:\n    jdbc:\n      url: jdbc:mysql://127.0.0.1:3306/canal_manager?useUnicode=true&characterEncoding=UTF-8\n      username: canal\n      password: canal\n"
  },
  {
    "path": "client-adapter/launcher/src/main/resources/logback.xml",
    "content": "<configuration scan=\"true\" scanPeriod=\" 5 seconds\">\n\t<jmxConfigurator />\n\t<appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n\t\t<encoder>\n\t\t\t<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{56} - %msg%n\n\t\t\t</pattern>\n\t\t</encoder>\n\t</appender>\n\n\t<appender name=\"CANAL-ROOT\" class=\"ch.qos.logback.classic.sift.SiftingAppender\">\n        <discriminator>\n            <Key>adapter</Key>\n            <DefaultValue>adapter</DefaultValue>\n        </discriminator>\n\t\t<sift>\n\t\t\t<appender name=\"FILE-adapter\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n\t\t\t\t<File>../logs/adapter/adapter.log</File>\n\t\t\t\t<rollingPolicy\n\t\t\t\t\t\tclass=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n\t\t\t\t\t<!-- rollover daily -->\n\t\t\t\t\t<fileNamePattern>../logs/adapter/%d{yyyy-MM-dd}/adapter-%d{yyyy-MM-dd}-%i.log.gz</fileNamePattern>\n\t\t\t\t\t<timeBasedFileNamingAndTriggeringPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP\">\n\t\t\t\t\t\t<!-- or whenever the file size reaches 100MB -->\n\t\t\t\t\t\t<maxFileSize>512MB</maxFileSize>\n\t\t\t\t\t</timeBasedFileNamingAndTriggeringPolicy>\n\t\t\t\t\t<maxHistory>60</maxHistory>\n\t\t\t\t</rollingPolicy>\n\t\t\t\t<encoder>\n\t\t\t\t\t<pattern>\n\t\t\t\t\t\t%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{56} - %msg%n\n\t\t\t\t\t</pattern>\n\t\t\t\t</encoder>\n\t\t\t</appender>\n\t\t</sift>\n\t</appender>\n\n\t<appender name=\"RocketmqClientAppender\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n\t\t<file>../logs/adapter/rocketmq_client.log</file>\n\t\t<rollingPolicy\n\t\t\t\tclass=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n\t\t\t<!-- rollover daily -->\n\t\t\t<fileNamePattern>../logs/adapter/%d{yyyy-MM-dd}/rocketmq_client-%d{yyyy-MM-dd}-%i.log.gz</fileNamePattern>\n\t\t\t<timeBasedFileNamingAndTriggeringPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP\">\n\t\t\t\t<!-- or whenever the file size reaches 100MB -->\n\t\t\t\t<maxFileSize>512MB</maxFileSize>\n\t\t\t</timeBasedFileNamingAndTriggeringPolicy>\n\t\t\t<maxHistory>60</maxHistory>\n\t\t</rollingPolicy>\n\t\t<encoder charset=\"UTF-8\">\n\t\t\t<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{56} - %msg%n</pattern>\n\t\t</encoder>\n\t</appender>\n\n\t<logger name=\"com.alibaba.otter.canal.client.adapter.hbase\" additivity=\"false\">\n\t\t<level value=\"DEBUG\" />\n\t\t<appender-ref ref=\"STDOUT\"/>\n\t\t<appender-ref ref=\"CANAL-ROOT\" />\n\t</logger>\n\t<logger name=\"com.alibaba.otter.canal.client.adapter.es\" additivity=\"false\">\n\t\t<level value=\"DEBUG\" />\n\t\t<appender-ref ref=\"STDOUT\"/>\n\t\t<appender-ref ref=\"CANAL-ROOT\" />\n\t</logger>\n\t<logger name=\"com.alibaba.otter.canal.client.adapter.rdb\" additivity=\"false\">\n\t\t<level value=\"DEBUG\" />\n\t\t<appender-ref ref=\"STDOUT\"/>\n\t\t<appender-ref ref=\"CANAL-ROOT\" />\n\t</logger>\n\t<logger name=\"com.alibaba.otter.canal.client.adapter.logger\" additivity=\"false\">\n\t\t<level value=\"DEBUG\" />\n\t\t<appender-ref ref=\"STDOUT\"/>\n\t\t<appender-ref ref=\"CANAL-ROOT\" />\n\t</logger>\n\t<logger name=\"RocketmqClient\" additivity=\"false\">\n\t\t<level value=\"INFO\" />\n\t\t<appender-ref ref=\"RocketmqClientAppender\" />\n\t</logger>\n\n\t<root level=\"INFO\">\n\t\t<appender-ref ref=\"STDOUT\"/>\n\t\t<appender-ref ref=\"CANAL-ROOT\" />\n\t</root>\n</configuration>\n"
  },
  {
    "path": "client-adapter/logger/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>canal.client-adapter</artifactId>\n        <groupId>com.alibaba.otter</groupId>\n        <version>1.1.9-SNAPSHOT</version>\n        <relativePath>../pom.xml</relativePath>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>com.alibaba.otter</groupId>\n    <artifactId>client-adapter.logger</artifactId>\n    <packaging>jar</packaging>\n    <name>canal client adapter logger example module for otter ${project.version}</name>\n    <dependencies>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>client-adapter.common</artifactId>\n            <version>${project.version}</version>\n            <scope>provided</scope>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-assembly-plugin</artifactId>\n                <version>2.4</version>\n                <configuration>\n                    <descriptorRefs>\n                        <descriptorRef>jar-with-dependencies</descriptorRef>\n                    </descriptorRefs>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>make-assembly</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>single</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "client-adapter/logger/src/main/java/com/alibaba/otter/canal/client/adapter/logger/LoggerAdapterExample.java",
    "content": "package com.alibaba.otter.canal.client.adapter.logger;\n\nimport java.util.List;\nimport java.util.Properties;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.JSONWriter.Feature;\nimport com.alibaba.otter.canal.client.adapter.OuterAdapter;\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\nimport com.alibaba.otter.canal.client.adapter.support.OuterAdapterConfig;\nimport com.alibaba.otter.canal.client.adapter.support.SPI;\n\n/**\n * 外部适配器示例\n *\n * @author machengyuan 2018-8-19 下午11:45:38\n * @version 1.0.0\n */\n@SPI(\"logger\")\n// logger参数对应CanalOuterAdapterConfiguration配置中的name\npublic class LoggerAdapterExample implements OuterAdapter {\n\n    private Logger logger = LoggerFactory.getLogger(this.getClass());\n\n    @Override\n    public void init(OuterAdapterConfig configuration, Properties envProperties) {\n    }\n\n    public void sync(List<Dml> dmls) {\n        for (Dml dml : dmls) {\n            sync(dml);\n        }\n    }\n\n    public void sync(Dml dml) {\n        logger.info(\"DML: {}\", JSON.toJSONString(dml, Feature.WriteNulls));\n    }\n\n    @Override\n    public void destroy() {\n    }\n}\n"
  },
  {
    "path": "client-adapter/logger/src/main/resources/META-INF/canal/com.alibaba.otter.canal.client.adapter.OuterAdapter",
    "content": "logger=com.alibaba.otter.canal.client.adapter.logger.LoggerAdapterExample"
  },
  {
    "path": "client-adapter/phoenix/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>canal.client-adapter</artifactId>\n        <groupId>com.alibaba.otter</groupId>\n        <version>1.1.9-SNAPSHOT</version>\n        <relativePath>../pom.xml</relativePath>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>com.alibaba.otter</groupId>\n    <artifactId>client-adapter.phoenix</artifactId>\n    <packaging>jar</packaging>\n    <name>canal client adapter phoenix module for otter ${project.version}</name>\n\n\n    <dependencies>\n        <dependency>\n            <groupId>org.apache.phoenix</groupId>\n            <artifactId>phoenix-core</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.hbase</groupId>\n            <artifactId>hbase-client</artifactId>\n        </dependency>\n        <!-- 强制指定protobuf版本 -->\n        <dependency>\n            <groupId>com.google.protobuf</groupId>\n            <artifactId>protobuf-java</artifactId>\n            <version>2.5.0</version>\n        </dependency>\n\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>client-adapter.common</artifactId>\n            <version>${project.version}</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>slf4j-api</artifactId>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>commons-lang</groupId>\n            <artifactId>commons-lang</artifactId>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>commons-io</groupId>\n            <artifactId>commons-io</artifactId>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.google.guava</groupId>\n            <artifactId>guava</artifactId>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid</artifactId>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.fastjson2</groupId>\n            <artifactId>fastjson2</artifactId>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <scope>provided</scope>\n        </dependency>\n    </dependencies>\n\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-assembly-plugin</artifactId>\n                <version>2.4</version>\n                <configuration>\n                    <descriptorRefs>\n                        <descriptorRef>jar-with-dependencies</descriptorRef>\n                    </descriptorRefs>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>make-assembly</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>single</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-antrun-plugin</artifactId>\n                <version>1.8</version>\n                <executions>\n                    <execution>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>run</goal>\n                        </goals>\n                        <configuration>\n<!--                            <tasks>-->\n<!--                                <copy todir=\"${project.basedir}/../launcher/target/classes/phoenix\" overwrite=\"true\">-->\n<!--                                    <fileset dir=\"${project.basedir}/target/classes/phoenix\" erroronmissingdir=\"true\">-->\n<!--                                        <include name=\"*.yml\" />-->\n<!--                                    </fileset>-->\n<!--                                </copy>-->\n<!--                            </tasks>-->\n                            <tasks>\n                                <copy todir=\"${project.basedir}/../launcher/target/canal-adapter/conf/phoenix\" overwrite=\"true\">\n                                    <fileset dir=\"${project.basedir}/target/classes/phoenix\" erroronmissingdir=\"true\">\n                                        <include name=\"*.yml\" />\n                                    </fileset>\n                                </copy>\n                                <copy todir=\"${project.basedir}/../launcher/target/canal-adapter/plugin\" overwrite=\"true\">\n                                    <fileset dir=\"${project.basedir}/target/\" erroronmissingdir=\"true\">\n                                        <include name=\"*with-dependencies.jar\" />\n                                    </fileset>\n                                </copy>\n                                <copy todir=\"${project.basedir}/../launcher/target/classes/phoenix\" overwrite=\"true\">\n                                    <fileset dir=\"${project.basedir}/target/classes/phoenix\" erroronmissingdir=\"true\">\n                                        <include name=\"*.yml\" />\n                                    </fileset>\n                                </copy>\n                            </tasks>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "client-adapter/phoenix/src/main/java/com/alibaba/otter/canal/client/adapter/phoenix/PhoenixAdapter.java",
    "content": "package com.alibaba.otter.canal.client.adapter.phoenix;\nimport com.alibaba.otter.canal.client.adapter.phoenix.config.ConfigLoader;\nimport com.alibaba.otter.canal.client.adapter.phoenix.config.MappingConfig;\nimport com.alibaba.otter.canal.client.adapter.phoenix.monitor.PhoenixConfigMonitor;\nimport com.alibaba.otter.canal.client.adapter.phoenix.service.PhoenixEtlService;\nimport com.alibaba.otter.canal.client.adapter.phoenix.service.PhoenixSyncService;\nimport com.alibaba.otter.canal.client.adapter.OuterAdapter;\nimport com.alibaba.otter.canal.client.adapter.phoenix.support.SyncUtil;\nimport com.alibaba.otter.canal.client.adapter.support.*;\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport javax.sql.DataSource;\nimport java.sql.Connection;\nimport java.sql.DriverManager;\nimport java.sql.SQLException;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * @author: lihua\n * @date: 2021/1/5 15:01\n * @Description: Phoenix适配器实现类\n */\n@SPI(\"phoenix\")\npublic class PhoenixAdapter implements OuterAdapter {\n\n    private static Logger logger = LoggerFactory.getLogger(PhoenixAdapter.class);\n\n    private Map<String, MappingConfig> phoenixMapping = new ConcurrentHashMap<>();                // 文件名对应配置\n    private Map<String, Map<String, MappingConfig>> mappingConfigCache = new ConcurrentHashMap<>();                // 库名-表名对应配置\n\n    private static  String DriverClass;\n    private static  String PhoenixUrl;\n    private static  Properties phoenixPro = new Properties();\n\n    private PhoenixSyncService phoenixSyncService;\n\n    private PhoenixConfigMonitor phoenixConfigMonitor;\n\n    private Properties envProperties;\n\n    private OuterAdapterConfig configuration;\n\n    public Map<String, MappingConfig> getPhoenixMapping() {\n        return phoenixMapping;\n    }\n\n    public Map<String, Map<String, MappingConfig>> getMappingConfigCache() {\n        return mappingConfigCache;\n    }\n\n    public PhoenixAdapter() {\n        logger.info(\"PhoenixAdapter create: {} {}\", this, Thread.currentThread().getStackTrace());\n    }\n    /**\n     * 初始化方法\n     *\n     * @param configuration 外部适配器配置信息\n     */\n    @Override\n    public void init(OuterAdapterConfig configuration, Properties envProperties) {\n        this.envProperties = envProperties;\n        this.configuration = configuration;\n        Map<String, MappingConfig> phoenixMappingTmp = ConfigLoader.load(envProperties);\n        // 过滤不匹配的key的配置\n        phoenixMappingTmp.forEach((key, config) -> {\n            addConfig(key, config);\n        });\n\n        if (phoenixMapping.isEmpty()) {\n            throw new RuntimeException(\"No phoenix adapter found for config key: \" + configuration.getKey());\n        } else {\n            logger.info(\"[{}]phoenix config mapping: {}\", this, phoenixMapping.keySet());\n        }\n\n        Map<String, String> properties = configuration.getProperties();\n\n        DriverClass= properties.get(\"jdbc.driverClassName\");\n        PhoenixUrl=properties.get(\"jdbc.url\");\n\n        try {\n            //phoenix内部本身有连接池，不需要使用Druid初始化\n            phoenixPro.setProperty(\"hbase.rpc.timeout\",\"600000\");\n            phoenixPro.setProperty(\"hbase.client.scanner.timeout.period\",\"600000\");\n            phoenixPro.setProperty(\"dfs.client.socket-timeout\",\"600000\");\n            phoenixPro.setProperty(\"phoenix.query.keepAliveMs\",\"600000\");\n            phoenixPro.setProperty(\"phoenix.query.timeoutMs\",\"3600000\");\n            Class.forName(DriverClass);\n        } catch (ClassNotFoundException e) {\n            e.printStackTrace();\n        }\n        String threads = properties.get(\"threads\");\n        phoenixSyncService = new PhoenixSyncService(\n                threads != null ? Integer.valueOf(threads) : null\n        );\n\n        phoenixConfigMonitor = new PhoenixConfigMonitor();\n        phoenixConfigMonitor.init(configuration.getKey(), this, envProperties);\n    }\n\n\n    /**\n     * 获取phoenix连接\n     * @return\n     */\n    public static  Connection  getPhoenixConnection() {\n        try {\n            return DriverManager.getConnection(PhoenixUrl,phoenixPro);\n        } catch (SQLException e) {\n            logger.error(\"getPhoenixConnection Exception\"+e.getMessage());\n        }\n        return  null;\n    }\n\n\n\n    /**\n     * 同步方法\n     *\n     * @param dmls 数据包\n     */\n    @Override\n    public void sync(List<Dml> dmls) {\n        if (dmls == null || dmls.isEmpty()) {\n            return;\n        }\n        try {\n            phoenixSyncService.sync(mappingConfigCache, dmls, envProperties);\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * ETL方法\n     *\n     * @param task   任务名, 对应配置名\n     * @param params etl筛选条件\n     * @return ETL结果\n     */\n    @Override\n    public EtlResult etl(String task, List<String> params) {\n        EtlResult etlResult = new EtlResult();\n        MappingConfig config = phoenixMapping.get(task);\n        if (config != null) {\n            DataSource srcDataSource = DatasourceConfig.DATA_SOURCES.get(config.getDataSourceKey());\n            if (srcDataSource != null) {\n                return PhoenixEtlService.importData(srcDataSource, getPhoenixConnection(), config, params);\n            } else {\n                etlResult.setSucceeded(false);\n                etlResult.setErrorMessage(\"DataSource not found\");\n                return etlResult;\n            }\n        } else {\n            StringBuilder resultMsg = new StringBuilder();\n            boolean resSucc = true;\n            // ds不为空说明传入的是destination\n            for (MappingConfig configTmp : phoenixMapping.values()) {\n                // 取所有的destination为task的配置\n                if (configTmp.getDestination().equals(task)) {\n                    DataSource srcDataSource = DatasourceConfig.DATA_SOURCES.get(configTmp.getDataSourceKey());\n                    if (srcDataSource == null) {\n                        continue;\n                    }\n                    EtlResult etlRes = PhoenixEtlService.importData(srcDataSource,getPhoenixConnection(), configTmp, params);\n                    if (!etlRes.getSucceeded()) {\n                        resSucc = false;\n                        resultMsg.append(etlRes.getErrorMessage()).append(\"\\n\");\n                    } else {\n                        resultMsg.append(etlRes.getResultMessage()).append(\"\\n\");\n                    }\n                }\n            }\n            if (resultMsg.length() > 0) {\n                etlResult.setSucceeded(resSucc);\n                if (resSucc) {\n                    etlResult.setResultMessage(resultMsg.toString());\n                } else {\n                    etlResult.setErrorMessage(resultMsg.toString());\n                }\n                return etlResult;\n            }\n        }\n        etlResult.setSucceeded(false);\n        etlResult.setErrorMessage(\"Task not found\");\n        return etlResult;\n    }\n\n    /**\n     * 获取总数方法\n     *\n     * @param task 任务名, 对应配置名\n     * @return 总数\n     */\n    @Override\n    public Map<String, Object> count(String task) {\n        Map<String, Object> res = new LinkedHashMap<>();\n        MappingConfig config = phoenixMapping.get(task);\n        if (config == null) {\n            logger.info(\"[{}]phoenix config mapping: {}\", this, phoenixMapping.keySet());\n            res.put(\"succeeded\", false);\n            res.put(\"errorMessage\", \"Task[\" + task + \"] not found\");\n            res.put(\"tasks\", phoenixMapping.keySet());\n            return res;\n        }\n        MappingConfig.DbMapping dbMapping = config.getDbMapping();\n        String sql = \"SELECT COUNT(1) AS cnt FROM \" + SyncUtil.getDbTableName(dbMapping);\n        Connection conn = null;\n        try {\n            //conn = dataSource.getConnection();\n            conn = getPhoenixConnection();\n            Util.sqlRS(conn, sql, rs -> {\n                try {\n                    if (rs.next()) {\n                        Long rowCount = rs.getLong(\"cnt\");\n                        res.put(\"count\", rowCount);\n                    }\n                } catch (SQLException e) {\n                    logger.error(e.getMessage(), e);\n                }\n            });\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n        } finally {\n            if (conn != null) {\n                try {\n                    conn.close();\n                } catch (SQLException e) {\n                    logger.error(e.getMessage(), e);\n                }\n            }\n        }\n        res.put(\"targetTable\", SyncUtil.getDbTableName(dbMapping));\n\n        return res;\n    }\n\n    /**\n     * 获取对应canal instance name 或 mq topic\n     *\n     * @param task 任务名, 对应配置名\n     * @return destination\n     */\n    @Override\n    public String getDestination(String task) {\n        MappingConfig config = phoenixMapping.get(task);\n        if (config != null) {\n            return config.getDestination();\n        }\n        return null;\n    }\n\n    /**\n     * 销毁方法\n     */\n    @Override\n    public void destroy() {\n        if (phoenixConfigMonitor != null) {\n            phoenixConfigMonitor.destroy();\n        }\n\n        if (phoenixSyncService != null) {\n            phoenixSyncService.close();\n        }\n    }\n\n    private void addSyncConfigToCache(String configName, MappingConfig mappingConfig) {\n        String key;\n        if (envProperties != null && !\"tcp\".equalsIgnoreCase(envProperties.getProperty(\"canal.conf.mode\"))) {\n            key = StringUtils.trimToEmpty(mappingConfig.getDestination()) + \"-\"\n                    + StringUtils.trimToEmpty(mappingConfig.getGroupId()) + \"_\"\n                    + mappingConfig.getDbMapping().getDatabase() + \"-\" + mappingConfig.getDbMapping().getTable().toLowerCase();\n        } else {\n            key = StringUtils.trimToEmpty(mappingConfig.getDestination()) + \"_\"\n                    + mappingConfig.getDbMapping().getDatabase() + \"-\" + mappingConfig.getDbMapping().getTable().toLowerCase();\n        }\n        Map<String, MappingConfig> configMap = mappingConfigCache.computeIfAbsent(key,\n                k1 -> new ConcurrentHashMap<>());\n        configMap.put(configName, mappingConfig);\n    }\n\n    public boolean addConfig(String fileName, MappingConfig config) {\n        if (match(config)) {\n            phoenixMapping.put(fileName, config);\n            addSyncConfigToCache(fileName, config);\n            FileName2KeyMapping.register(getClass().getAnnotation(SPI.class).value(), fileName,\n                    configuration.getKey());\n            return true;\n        }\n        return false;\n    }\n\n    public void updateConfig(String fileName, MappingConfig config) {\n        if (config.getOuterAdapterKey() != null && !config.getOuterAdapterKey()\n                .equals(configuration.getKey())) {\n            // 理论上不允许改这个 因为本身就是通过这个关联起Adapter和Config的\n            throw new RuntimeException(\"not allow to change outAdapterKey\");\n        }\n        phoenixMapping.put(fileName, config);\n        addSyncConfigToCache(fileName, config);\n    }\n\n    public void deleteConfig(String fileName) {\n        phoenixMapping.remove(fileName);\n        for (Map<String, MappingConfig> configMap : mappingConfigCache.values()) {\n            if (configMap != null) {\n                configMap.remove(fileName);\n            }\n        }\n        FileName2KeyMapping.unregister(getClass().getAnnotation(SPI.class).value(), fileName);\n    }\n\n    private boolean match(MappingConfig config) {\n        boolean sameMatch = config.getOuterAdapterKey() != null && config.getOuterAdapterKey()\n                .equalsIgnoreCase(configuration.getKey());\n        boolean prefixMatch = config.getOuterAdapterKey() == null && configuration.getKey()\n                .startsWith(StringUtils\n                        .join(new String[]{Util.AUTO_GENERATED_PREFIX, config.getDestination(),\n                                config.getGroupId()}, '-'));\n        return sameMatch || prefixMatch;\n    }\n}\n"
  },
  {
    "path": "client-adapter/phoenix/src/main/java/com/alibaba/otter/canal/client/adapter/phoenix/config/ConfigLoader.java",
    "content": "package com.alibaba.otter.canal.client.adapter.phoenix.config;\n\nimport com.alibaba.otter.canal.client.adapter.support.MappingConfigsLoader;\nimport com.alibaba.otter.canal.client.adapter.support.YamlUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Properties;\n\n/**\n * Phoenix表映射配置加载器\n */\npublic class ConfigLoader {\n\n    private static Logger logger = LoggerFactory.getLogger(ConfigLoader.class);\n\n    /**\n     * 加载Phoenix表映射配置\n     *\n     * @return 配置名/配置文件名--对象\n     */\n    public static Map<String, MappingConfig> load(Properties envProperties) {\n        logger.info(\"## Start loading phoenix mapping config ... \");\n\n        Map<String, MappingConfig> result = new LinkedHashMap<>();\n\n        Map<String, String> configContentMap = MappingConfigsLoader.loadConfigs(\"phoenix\");\n        configContentMap.forEach((fileName, content) -> {\n            MappingConfig config = YamlUtils.ymlToObj(null, content, MappingConfig.class, null, envProperties);\n            if (config == null) {\n                return;\n            }\n            try {\n                config.validate();\n            } catch (Exception e) {\n                throw new RuntimeException(\"ERROR Config: \" + fileName + \" \" + e.getMessage(), e);\n            }\n            result.put(fileName, config);\n        });\n\n        logger.info(\"## Phoenix mapping config loaded\");\n        logger.info(\"## Phoenix sync threads: \" + ConfigurationManager.getInteger(\"threads\"));\n        return result;\n    }\n}\n"
  },
  {
    "path": "client-adapter/phoenix/src/main/java/com/alibaba/otter/canal/client/adapter/phoenix/config/ConfigurationManager.java",
    "content": "package com.alibaba.otter.canal.client.adapter.phoenix.config;\n\nimport java.io.InputStream;\nimport java.util.Properties;\n\n/**\n * 配置管理组件\n * @author Administrator\n *\n */\npublic class ConfigurationManager {\n\n\tprivate static Properties prop = new Properties();\n\n\tstatic {\n\t\ttry {\n\t\t\tInputStream in = ConfigurationManager.class\n\t\t\t\t\t.getClassLoader().getResourceAsStream(\"phoenix/phoenix_common.properties\");\n\t\t\tprop.load(in);  \n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();  \n\t\t}\n\t}\n\t\n\t/**\n\t * 获取指定key对应的value\n\t *\n\t * @param key \n\t * @return 返回value是字符串\n\t */\n\tpublic static String getProperty(String key) {\n\t\treturn prop.getProperty(key);\n\t}\n\t\n\t/**\n\t * 获取整数类型的配置项\n\t * @param key StringKye\n\t * @return value\n\t */\n\tpublic static Integer getInteger(String key) {\n\t\tString value = getProperty(key);\n\t\ttry {\n\t\t\treturn Integer.valueOf(value);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn 0;\n\t}\n}\n"
  },
  {
    "path": "client-adapter/phoenix/src/main/java/com/alibaba/otter/canal/client/adapter/phoenix/config/MappingConfig.java",
    "content": "package com.alibaba.otter.canal.client.adapter.phoenix.config;\n\nimport org.apache.commons.lang.StringUtils;\n\nimport java.util.*;\n\n/**\n * Phoenix表映射配置\n */\n@SuppressWarnings(\"unused\")\npublic class MappingConfig {\n\n    private String dataSourceKey;           // 数据源key\n    private String destination;             // canal实例或MQ的topic\n    private String groupId;                 // groupId\n    private String outerAdapterKey;         // 对应适配器的key\n    private boolean concurrent = false;     // 是否并行同步\n    private DbMapping dbMapping;            // db映射配置\n    private boolean debug = false;          // 调试\n\n    public String getDataSourceKey() {\n        return dataSourceKey;\n    }\n\n    public void setDataSourceKey(String dataSourceKey) {\n        this.dataSourceKey = dataSourceKey;\n    }\n\n    public String getGroupId() {\n        return groupId;\n    }\n\n    public void setGroupId(String groupId) {\n        this.groupId = groupId;\n    }\n\n    public String getOuterAdapterKey() {\n        return outerAdapterKey;\n    }\n\n    public void setOuterAdapterKey(String outerAdapterKey) {\n        this.outerAdapterKey = outerAdapterKey;\n    }\n\n    public boolean getConcurrent() {\n        return concurrent;\n    }\n\n    public void setConcurrent(boolean concurrent) {\n        this.concurrent = concurrent;\n    }\n\n    public DbMapping getDbMapping() {\n        return dbMapping;\n    }\n\n    public void setDbMapping(DbMapping dbMapping) {\n        this.dbMapping = dbMapping;\n    }\n\n    public String getDestination() {\n        return destination;\n    }\n\n    public void setDestination(String destination) {\n        this.destination = destination;\n    }\n\n    public boolean isDebug() {\n        return debug;\n    }\n\n    public void setDebug(boolean debug) {\n        this.debug = debug;\n    }\n\n    public void validate() {\n        if (dbMapping.database == null || dbMapping.database.isEmpty()) {\n            throw new NullPointerException(\"dbMapping.database\");\n        }\n        if ((dbMapping.table == null || dbMapping.table.isEmpty())) {\n            throw new NullPointerException(\"dbMapping.table\");\n        }\n        if ((dbMapping.targetTable == null || dbMapping.targetTable.isEmpty())) {\n            throw new NullPointerException(\"dbMapping.targetTable\");\n        }\n    }\n\n    public static class DbMapping {\n\n        private String database;                            // 数据库名或schema名\n        private String table;                               // 表名\n        private Map<String, String> targetPk = new LinkedHashMap<>(); // 目标表主键字段\n        private boolean mapAll = true;                      // 映射所有字段\n\n        private boolean alter = true;                       // 是否允许修改表\n        private boolean drop = false;                       // 是否允许删除字段\n        private boolean limit = false;                      // 是否限制字段长度\n        private boolean skipMissing = false;                // 是否跳过丢失的字段\n        private boolean escapeUpper = true;                 // 字段默认大写加双引号\n\n        private String targetDb;                            // 目标库名\n        private String targetTable;                         // 目标表名\n        private Map<String, String> targetColumns;          // 目标表字段映射\n\n        private List<String> excludeColumns;                // 不映射的字段\n\n        private String etlCondition;                        // etl条件sql\n        private int readBatch = 5000;\n        private int commitBatch = 5000;                     // etl等批量提交大小\n        private Map<String, String> allMapColumns;\n\n        public String escape(String name) {\n            if (escapeUpper) {\n                return \"\\\"\" + name.toUpperCase() + \"\\\"\";\n            } else {\n                return name;\n            }\n        }\n\n        public String getDatabase() {\n            return database;\n        }\n\n        public void setDatabase(String database) {\n            this.database = database;\n        }\n\n        public String getTable() {\n            return table;\n        }\n\n        public void setTable(String table) {\n            this.table = table;\n        }\n\n        public Map<String, String> getTargetPk() {\n            return targetPk;\n        }\n\n        public void setTargetPk(Map<String, String> targetPk) {\n            this.targetPk = targetPk;\n        }\n\n        public Boolean getMapAll() {\n            return mapAll;\n        }\n\n        public void setMapAll(Boolean mapAll) {\n            this.mapAll = mapAll;\n        }\n\n        public boolean isAlter() {\n            return alter;\n        }\n\n        public void setAlter(boolean alter) {\n            this.alter = alter;\n        }\n\n        public boolean isLimit() {\n            return limit;\n        }\n\n        public void setLimit(boolean limit) {\n            this.limit = limit;\n        }\n\n        public boolean isDrop() {\n            return drop;\n        }\n\n        public void setDrop(boolean drop) {\n            this.drop = drop;\n        }\n\n        public boolean isSkipMissing() {\n            return skipMissing;\n        }\n\n        public void setSkipMissing(boolean skipMissing) {\n            this.skipMissing = skipMissing;\n        }\n\n        public boolean isEscapeUpper() {\n            return escapeUpper;\n        }\n\n        public void setEscapeUpper(boolean escapeUpper) {\n            this.escapeUpper = escapeUpper;\n        }\n\n        public String getTargetDb() {\n            return targetDb;\n        }\n\n        public void setTargetDb(String targetDb) {\n            this.targetDb = targetDb;\n        }\n\n        public String getTargetTable() {\n            return targetTable;\n        }\n\n        public void setTargetTable(String targetTable) {\n            this.targetTable = targetTable;\n        }\n\n        public Map<String, String> getTargetColumns() {\n            if (targetColumns != null) {\n                targetColumns.forEach((key, value) -> {\n                    if (StringUtils.isEmpty(value)) {\n                        targetColumns.put(key, key);\n                    }\n                });\n            } else {\n                targetColumns = new HashMap<>();\n            }\n            return targetColumns;\n        }\n\n        public void setTargetColumns(Map<String, String> targetColumns) {\n            this.targetColumns = targetColumns;\n        }\n\n        public void addTargetColumn(String key, String value) {\n            if (targetColumns == null) {\n                targetColumns = new HashMap<>();\n            }\n            targetColumns.put(key, value);\n            if (allMapColumns != null) {\n                allMapColumns.put(key, value);\n            }\n        }\n\n        public void removeTargetColumn(String key) {\n            if (targetColumns != null) {\n                targetColumns.remove(key);\n            }\n            if (allMapColumns != null) {\n                allMapColumns.remove(key);\n            }\n        }\n\n        public List<String> getExcludeColumns() {\n            if (excludeColumns == null) {\n                excludeColumns = new ArrayList<>();\n            }\n            return excludeColumns;\n        }\n\n        public void setExcludeColumns(List<String> excludeColumns) {\n            this.excludeColumns = excludeColumns;\n        }\n\n        public String getEtlCondition() {\n            return etlCondition;\n        }\n\n        public void setEtlCondition(String etlCondition) {\n            this.etlCondition = etlCondition;\n        }\n\n        public int getReadBatch() {\n            return readBatch;\n        }\n\n        public void setReadBatch(int readBatch) {\n            this.readBatch = readBatch;\n        }\n\n        public int getCommitBatch() {\n            return commitBatch;\n        }\n\n        public void setCommitBatch(int commitBatch) {\n            this.commitBatch = commitBatch;\n        }\n\n        public Map<String, String> getAllMapColumns() {\n            return allMapColumns;\n        }\n\n        public void setAllMapColumns(Map<String, String> allMapColumns) {\n            this.allMapColumns = allMapColumns;\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/phoenix/src/main/java/com/alibaba/otter/canal/client/adapter/phoenix/monitor/PhoenixConfigMonitor.java",
    "content": "package com.alibaba.otter.canal.client.adapter.phoenix.monitor;\n\nimport com.alibaba.otter.canal.client.adapter.phoenix.PhoenixAdapter;\nimport com.alibaba.otter.canal.client.adapter.phoenix.config.MappingConfig;\nimport com.alibaba.otter.canal.client.adapter.support.MappingConfigsLoader;\nimport com.alibaba.otter.canal.client.adapter.support.Util;\nimport com.alibaba.otter.canal.client.adapter.support.YamlUtils;\nimport java.io.File;\nimport java.util.Properties;\nimport org.apache.commons.io.filefilter.FileFilterUtils;\nimport org.apache.commons.io.monitor.FileAlterationListenerAdaptor;\nimport org.apache.commons.io.monitor.FileAlterationMonitor;\nimport org.apache.commons.io.monitor.FileAlterationObserver;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * phoenix config monitor\n */\npublic class PhoenixConfigMonitor {\n\n    private static final Logger   logger      = LoggerFactory.getLogger(PhoenixConfigMonitor.class);\n\n    private static final String   adapterName = \"phoenix\";                                          // 相应组件名字\n\n    private String                key;\n\n    private PhoenixAdapter        phoenixAdapter;                                                   // 相应适配器名实现类\n\n    private Properties            envProperties;\n\n    private FileAlterationMonitor fileMonitor;\n\n    public void init(String key, PhoenixAdapter phoenixAdapter, Properties envProperties) {\n        this.key = key;\n        this.phoenixAdapter = phoenixAdapter;\n        this.envProperties = envProperties;\n        File confDir = Util.getConfDirPath(adapterName);\n        try {\n            FileAlterationObserver observer = new FileAlterationObserver(confDir,\n                FileFilterUtils.and(FileFilterUtils.fileFileFilter(), FileFilterUtils.suffixFileFilter(\"yml\")));\n            FileListener listener = new FileListener();\n            observer.addListener(listener);\n            fileMonitor = new FileAlterationMonitor(3000, observer);\n            fileMonitor.start();\n\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n        }\n    }\n\n    public void destroy() {\n        try {\n            fileMonitor.stop();\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n        }\n    }\n\n    private class FileListener extends FileAlterationListenerAdaptor {\n\n        @Override\n        public void onFileCreate(File file) {\n            super.onFileCreate(file);\n            try {\n                // 加载新增的配置文件\n                String configContent = MappingConfigsLoader.loadConfig(adapterName + File.separator + file.getName());\n                MappingConfig config = YamlUtils\n                    .ymlToObj(null, configContent, MappingConfig.class, null, envProperties);\n                if (config == null) {\n                    return;\n                }\n                config.validate();\n                boolean result = phoenixAdapter.addConfig(file.getName(), config);\n                if (result) {\n                    logger.info(\"Add a new phoenix mapping config: {} to canal adapter\", file.getName());\n                }\n            } catch (Exception e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n\n        @Override\n        public void onFileChange(File file) {\n            super.onFileChange(file);\n\n            try {\n                if (phoenixAdapter.getPhoenixMapping().containsKey(file.getName())) {\n                    // 加载配置文件\n                    String configContent = MappingConfigsLoader\n                        .loadConfig(adapterName + File.separator + file.getName());\n                    if (configContent == null) {\n                        onFileDelete(file);\n                        return;\n                    }\n                    MappingConfig config = YamlUtils\n                        .ymlToObj(null, configContent, MappingConfig.class, null, envProperties);\n                    if (config == null) {\n                        return;\n                    }\n                    config.validate();\n                    phoenixAdapter.updateConfig(file.getName(), config);\n                    logger.info(\"Change a phoenix mapping config: {} of canal adapter\", file.getName());\n                }\n            } catch (Exception e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n\n        @Override\n        public void onFileDelete(File file) {\n            super.onFileDelete(file);\n\n            try {\n                if (phoenixAdapter.getPhoenixMapping().containsKey(file.getName())) {\n                    phoenixAdapter.deleteConfig(file.getName());\n                    logger.info(\"Delete a phoenix mapping config: {} of canal adapter\", file.getName());\n                }\n            } catch (Exception e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/phoenix/src/main/java/com/alibaba/otter/canal/client/adapter/phoenix/service/PhoenixEtlService.java",
    "content": "package com.alibaba.otter.canal.client.adapter.phoenix.service;\n\nimport java.sql.*;\nimport java.util.*;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport javax.sql.DataSource;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.client.adapter.phoenix.PhoenixAdapter;\nimport com.alibaba.otter.canal.client.adapter.phoenix.config.MappingConfig;\nimport com.alibaba.otter.canal.client.adapter.phoenix.config.MappingConfig.DbMapping;\nimport com.alibaba.otter.canal.client.adapter.phoenix.support.PhoenixSupportUtil;\nimport com.alibaba.otter.canal.client.adapter.phoenix.support.SyncUtil;\nimport com.alibaba.otter.canal.client.adapter.phoenix.support.TypeUtil;\nimport com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;\nimport com.alibaba.otter.canal.client.adapter.support.EtlResult;\nimport com.alibaba.otter.canal.client.adapter.support.Util;\nimport com.google.common.base.Joiner;\n\n/**\n * Phoenix ETL 操作业务类\n */\npublic class PhoenixEtlService {\n\n    private static final Logger logger = LoggerFactory.getLogger(PhoenixEtlService.class);\n\n    private static String[] splitNotEmpty(String s) {\n        if (s != null && s.trim().length() > 0) {\n            return s.trim().split(\",\");\n        }\n        return new String[]{};\n    }\n\n\n    static boolean syncSchema(Connection targetDSConnection, MappingConfig config) {\n        DataSource srcDataSource = DatasourceConfig.DATA_SOURCES.get(config.getDataSourceKey());\n        if (srcDataSource == null) {\n            return false;\n        }\n\n        try (Connection conn = srcDataSource.getConnection()) {\n            return syncSchema(conn, targetDSConnection, config);\n        } catch (SQLException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    private static boolean syncSchema(DataSource srcDS,Connection targetDSConnection, MappingConfig config) {\n        try (Connection conn = srcDS.getConnection()) {\n            return syncSchema(conn, targetDSConnection, config);\n        } catch (SQLException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static boolean syncSchema(Connection srcDS, Connection targetDS, MappingConfig config) {\n        DbMapping dbMapping = config.getDbMapping();\n        if (dbMapping.getMapAll() && dbMapping.isAlter()) { // 检查字段是否缺失\n            Map<String, Integer> targetColumnType = new LinkedHashMap<>();\n            String targetTable = SyncUtil.getDbTableName(dbMapping);\n            try {\n                Util.sqlRS(targetDS, \"SELECT * FROM \" + targetTable + \" LIMIT 1\", rs -> {\n                    try {\n                        ResultSetMetaData rsd = rs.getMetaData();\n                        int columnCount = rsd.getColumnCount();\n                        for (int i = 1; i <= columnCount; i++) {\n                            targetColumnType.put(rsd.getColumnName(i).toLowerCase(), rsd.getColumnType(i));\n                        }\n                    } catch (Exception e) {\n                        logger.error(dbMapping.getTable() + \" etl failed! ==>\" + e.getMessage(), e);\n                    }\n                });\n            } catch (RuntimeException e) {\n                if (!e.getCause().getClass().getName().endsWith(\"TableNotFoundException\")) {\n                    throw e;\n                }\n            }\n            StringBuilder missing = new StringBuilder();\n            StringBuilder constraint = new StringBuilder();\n            Util.sqlRS(srcDS, \"SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '\" + dbMapping.getDatabase() + \"'  AND TABLE_NAME = '\" + dbMapping.getTable() + \"'\", rs -> {\n                try {\n                    List<String> excludeColumns = config.getDbMapping().getExcludeColumns();\n                    while (rs.next()) {\n                        String name = rs.getString(\"COLUMN_NAME\");\n                        String lower = name.toLowerCase();\n                        String colType = rs.getString(\"COLUMN_TYPE\");\n                        if (targetColumnType.get(lower) == null && !excludeColumns.contains(lower)) {\n                            boolean isPri = rs.getString(\"COLUMN_KEY\").equals(\"PRI\");\n                            String[] args = splitNotEmpty(colType.replaceAll(\"^\\\\w+(?:\\\\(([^)]*)\\\\))?[\\\\s\\\\S]*$\", \"$1\"));\n                            missing.append(dbMapping.escape(name)).append(\" \").append(TypeUtil.getPhoenixType(\n                                    rs.getString(\"DATA_TYPE\").toUpperCase(),\n                                    args,\n                                    colType.contains(\"unsigned\"),\n                                    dbMapping.isLimit()\n                            ));\n                            if (isPri) {\n                                if (args.length > 0 && dbMapping.isLimit() || rs.getString(\"IS_NULLABLE\").equals(\"NO\")) {\n                                    missing.append(\" NOT NULL\");\n                                }\n                                constraint.append(dbMapping.escape(name)).append(',');\n                            }\n                            missing.append(',');\n                        }\n                    }\n                } catch (Exception e) {\n                    logger.error(dbMapping.getDatabase() + \".\" + dbMapping.getTable() + \" schema failed! ==>\" + e.getMessage(), e);\n                    throw new RuntimeException(e);\n                }\n            });\n            if (missing.length() > 0) {\n                String sql;\n                if (targetColumnType.isEmpty()) {\n                    if (constraint.length() > 0) {\n                        constraint.deleteCharAt(constraint.length() - 1);\n                        missing.append(\"CONSTRAINT pk PRIMARY KEY(\").append(constraint.toString()).append(\")\");\n                    } else {\n                        missing.deleteCharAt(missing.length() - 1);\n                    }\n                    sql = \"CREATE TABLE \" + targetTable + \" (\" + missing.toString() + \")\";\n                } else {\n                    missing.deleteCharAt(missing.length() - 1);\n                    sql = \"ALTER TABLE \" + targetTable + \" ADD \" + missing.toString();\n                }\n                logger.info(\"schema missing: {} {}\", targetColumnType, sql);\n                try (PreparedStatement pstmt = targetDS.prepareStatement(sql)) {\n                    pstmt.executeUpdate();\n                } catch (SQLException e) {\n                    logger.error(\"sync schema error: \" + e.getMessage(), e);\n                }\n            } else {\n                logger.debug(\"schema ok: {}\", targetColumnType);\n            }\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * 导入数据\n     */\n    public static EtlResult importData(DataSource srcDS, Connection targetDSConnection, MappingConfig config,\n                                       List<String> params) {\n        EtlResult etlResult = new EtlResult();\n        AtomicLong successCount = new AtomicLong();\n        List<String> errMsg = new ArrayList<>();\n        String hbaseTable = \"\";\n        try {\n            if (config == null) {\n                logger.error(\"Config is null!\");\n                etlResult.setSucceeded(false);\n                etlResult.setErrorMessage(\"Config is null!\");\n                return etlResult;\n            }\n            boolean debug = params != null && params.get(0).equals(\"_debug\");\n            if (debug) {\n                params = params.subList(1, params.size());\n            }\n            syncSchema(srcDS, targetDSConnection, config);\n            DbMapping dbMapping = config.getDbMapping();\n\n            long start = System.currentTimeMillis();\n\n            // 拼接sql\n            StringBuilder sql = new StringBuilder(\n                    \"SELECT * FROM \" + dbMapping.getDatabase() + \".\" + dbMapping.getTable());\n\n            // 拼接条件\n            appendCondition(params, dbMapping, srcDS, sql);\n\n            // 获取总数\n            String countSql = \"SELECT COUNT(1) FROM ( \" + sql + \") _CNT \";\n            long cnt = (Long) Util.sqlRS(srcDS, countSql, rs -> {\n                Long count = null;\n                try {\n                    if (rs.next()) {\n                        count = ((Number) rs.getObject(1)).longValue();\n                    }\n                } catch (Exception e) {\n                    logger.error(e.getMessage(), e);\n                }\n                return count == null ? 0 : count;\n            });\n\n            // 当大于1万条记录时开启多线程\n            if (cnt >= 10000) {\n                int threadCount = 3;\n                long perThreadCnt = cnt / threadCount;\n                ExecutorService executor = Util.newFixedThreadPool(threadCount, 5000L);\n                for (int i = 0; i < threadCount; i++) {\n                    long offset = i * perThreadCnt;\n                    Long size = null;\n                    if (i != threadCount - 1) {\n                        size = perThreadCnt;\n                    }\n                    String sqlFinal;\n                    if (size != null) {\n                        sqlFinal = sql + \" LIMIT \" + offset + \",\" + size;\n                    } else {\n                        sqlFinal = sql + \" LIMIT \" + offset + \",\" + cnt;\n                    }\n                    executor\n                            .execute(() -> executeSqlImport(srcDS, targetDSConnection, sqlFinal, dbMapping, successCount, errMsg, debug));\n                }\n\n                executor.shutdown();\n                //noinspection StatementWithEmptyBody\n                while (!executor.awaitTermination(3, TimeUnit.SECONDS)) ;\n            } else {\n                executeSqlImport(srcDS, targetDSConnection, sql.toString(), dbMapping, successCount, errMsg, debug);\n            }\n\n            logger.info(\n                    dbMapping.getTable() + \" etl completed in: \" + (System.currentTimeMillis() - start) / 1000 + \"s!\");\n\n            etlResult\n                    .setResultMessage(\"导入目标表 \" + SyncUtil.getDbTableName(dbMapping) + \" 数据：\" + successCount.get() + \" 条\");\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n            errMsg.add(hbaseTable + \" etl failed! ==>\" + e.getMessage());\n        }\n\n        if (errMsg.isEmpty()) {\n            etlResult.setSucceeded(true);\n        } else {\n            etlResult.setErrorMessage(Joiner.on(\"\\n\").join(errMsg));\n        }\n        return etlResult;\n    }\n\n    private static void appendCondition(List<String> params, DbMapping dbMapping, DataSource ds,\n                                        StringBuilder sql) {\n        if (params != null && params.size() == 1 && dbMapping.getEtlCondition() == null) {\n            AtomicBoolean stExists = new AtomicBoolean(false);\n            // 验证是否有SYS_TIME字段\n            Util.sqlRS(ds, sql.toString(), rs -> {\n                try {\n                    ResultSetMetaData rsmd = rs.getMetaData();\n                    int cnt = rsmd.getColumnCount();\n                    for (int i = 1; i <= cnt; i++) {\n                        String columnName = rsmd.getColumnName(i);\n                        if (\"SYS_TIME\".equalsIgnoreCase(columnName)) {\n                            stExists.set(true);\n                            break;\n                        }\n                    }\n                } catch (Exception e) {\n                    // ignore\n                }\n                return null;\n            });\n            if (stExists.get()) {\n                sql.append(\" WHERE SYS_TIME >= '\").append(params.get(0)).append(\"' \");\n            }\n        } else if (dbMapping.getEtlCondition() != null && params != null && params.size() > 0) {\n            String etlCondition = dbMapping.getEtlCondition();\n            int size = params.size();\n            for (int i = 0; i < size; i++) {\n                etlCondition = etlCondition.replace(\"{\" + i + \"}\", params.get(i));\n            }\n\n            sql.append(\" \").append(etlCondition);\n        }\n    }\n\n    /**\n     * 执行导入\n     */\n    private static boolean executeSqlImport(DataSource srcDS, Connection targetDSConnection, String sql, DbMapping dbMapping,\n                                            AtomicLong successCount, List<String> errMsg, boolean debug) {\n        try {\n            Map<String, String> columnsMap = new LinkedHashMap<>();\n            Map<String, Integer> columnType = new LinkedHashMap<>();\n\n\n            PhoenixSupportUtil.sqlRS(targetDSConnection, \"SELECT * FROM \" + SyncUtil.getDbTableName(dbMapping) + \" LIMIT 1 \", rs -> {\n                try {\n\n                    ResultSetMetaData rsd = rs.getMetaData();\n                    int columnCount = rsd.getColumnCount();\n                    List<String> columns = new ArrayList<>();\n                    List<String> excludeColumns = dbMapping.getExcludeColumns();\n                    for (int i = 1; i <= columnCount; i++) {\n                        String lower = rsd.getColumnName(i).toLowerCase();\n                        if (!excludeColumns.contains(lower)) {\n                            columnType.put(lower, rsd.getColumnType(i));\n                            columns.add(lower);\n                        }\n                    }\n                    columnsMap.putAll(SyncUtil.getColumnsMap(dbMapping, columns));\n                    return true;\n                } catch (Exception e) {\n                    logger.error(e.getMessage(), e);\n                    return false;\n                }\n            });\n            Util.sqlRS(srcDS, sql, rs -> {\n                int idx = 1;\n\n                try {\n                    boolean completed = false;\n\n                    // if (dbMapping.isMapAll()) {\n                    // columnsMap = dbMapping.getAllColumns();\n                    // } else {\n                    // columnsMap = dbMapping.getTargetColumns();\n                    // }\n\n                    StringBuilder insertSql = new StringBuilder();\n                    insertSql.append(\"UPSERT INTO \").append(SyncUtil.getDbTableName(dbMapping)).append(\" (\");\n                    columnsMap\n                            .forEach((targetColumnName, srcColumnName) -> insertSql.append(dbMapping.escape(targetColumnName)).append(\",\"));\n\n                    int len = insertSql.length();\n                    insertSql.delete(len - 1, len).append(\") VALUES (\");\n                    int mapLen = columnsMap.size();\n                    for (int i = 0; i < mapLen; i++) {\n                        insertSql.append(\"?,\");\n                    }\n                    len = insertSql.length();\n                    insertSql.delete(len - 1, len).append(\")\");\n                    try (\n                         //Connection connTarget = targetDS.getConnection();\n                         Connection connTarget =PhoenixAdapter.getPhoenixConnection();\n                         PreparedStatement pstmt = connTarget.prepareStatement(insertSql.toString())) {\n                        connTarget.setAutoCommit(false);\n\n                        while (rs.next()) {\n                            completed = false;\n\n                            pstmt.clearParameters();\n\n                            // 删除数据\n                            Map<String, Object> values = new LinkedHashMap<>();\n                            StringBuilder deleteSql = new StringBuilder(\n                                    \"DELETE FROM \" + SyncUtil.getDbTableName(dbMapping) + \" WHERE \");\n                            appendCondition(dbMapping, deleteSql, values, rs);\n                            try (PreparedStatement pstmt2 = connTarget.prepareStatement(deleteSql.toString())) {\n                                int k = 1;\n                                for (Object val : values.values()) {\n                                    pstmt2.setObject(k++, val);\n                                }\n                                pstmt2.execute();\n                            }\n\n                            Map<String, Object> insertValues = new HashMap<>();\n                            int i = 1;\n                            for (Map.Entry<String, String> entry : columnsMap.entrySet()) {\n                                String targetColumnName = entry.getKey();\n                                String srcColumnName = entry.getValue();\n                                if (srcColumnName == null) {\n                                    srcColumnName = targetColumnName;\n                                }\n\n                                Integer type = columnType.get(targetColumnName.toLowerCase());\n\n                                try {\n                                    Object value = rs.getObject(srcColumnName);\n                                    insertValues.put(srcColumnName, value);\n                                    if (value != null) {\n                                        SyncUtil.setPStmt(type, pstmt, value, i);\n                                    } else {\n                                        pstmt.setNull(i, type);\n                                    }\n                                } catch (SQLException e) {\n                                    insertValues.put(srcColumnName, null);\n                                    pstmt.setNull(i, type);\n                                }\n                                i++;\n                            }\n                            if (debug) {\n                                logger.info(\"insert sql: {} {} {}\", insertSql, insertValues, pstmt);\n                            }\n\n                            pstmt.execute();\n                            if (logger.isTraceEnabled()) {\n                                logger.trace(\"Insert into target table, sql: {}\", insertSql);\n                            }\n\n                            if (idx % dbMapping.getCommitBatch() == 0) {\n                                connTarget.commit();\n                                completed = true;\n                            }\n                            idx++;\n                            successCount.incrementAndGet();\n                            if (logger.isDebugEnabled()) {\n                                logger.debug(\"successful import count:\" + successCount.get());\n                            }\n                        }\n                        if (!completed) {\n                            connTarget.commit();\n                        }\n                    }\n\n                } catch (Exception e) {\n                    logger.error(dbMapping.getTable() + \" etl failed! ==>\" + e.getMessage(), e);\n                    errMsg.add(dbMapping.getTable() + \" etl failed! ==>\" + e.getMessage());\n                }\n                return idx;\n            });\n            return true;\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n            return false;\n        }\n    }\n\n    /**\n     * 拼接目标表主键where条件\n     */\n    private static void appendCondition(DbMapping dbMapping, StringBuilder sql, Map<String, Object> values,\n                                        ResultSet rs) throws SQLException {\n        // 拼接主键\n        for (Map.Entry<String, String> entry : dbMapping.getTargetPk().entrySet()) {\n            String targetColumnName = entry.getKey();\n            String srcColumnName = entry.getValue();\n            if (srcColumnName == null) {\n                srcColumnName = targetColumnName;\n            }\n            sql.append(dbMapping.escape(targetColumnName)).append(\"=? AND \");\n            values.put(targetColumnName, rs.getObject(srcColumnName));\n        }\n        int len = sql.length();\n        sql.delete(len - 4, len);\n    }\n}\n"
  },
  {
    "path": "client-adapter/phoenix/src/main/java/com/alibaba/otter/canal/client/adapter/phoenix/service/PhoenixSyncService.java",
    "content": "package com.alibaba.otter.canal.client.adapter.phoenix.service;\n\nimport com.alibaba.druid.sql.SQLUtils;\nimport com.alibaba.druid.sql.ast.SQLName;\nimport com.alibaba.druid.sql.ast.SQLStatement;\nimport com.alibaba.druid.sql.ast.statement.*;\nimport com.alibaba.druid.sql.parser.ParserException;\nimport com.alibaba.druid.util.JdbcConstants;\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.JSONWriter.Feature;\nimport com.alibaba.otter.canal.client.adapter.phoenix.config.ConfigurationManager;\nimport com.alibaba.otter.canal.client.adapter.phoenix.config.MappingConfig;\nimport com.alibaba.otter.canal.client.adapter.phoenix.config.MappingConfig.DbMapping;\nimport com.alibaba.otter.canal.client.adapter.phoenix.support.BatchExecutor;\nimport com.alibaba.otter.canal.client.adapter.phoenix.support.SingleDml;\nimport com.alibaba.otter.canal.client.adapter.phoenix.support.SyncUtil;\nimport com.alibaba.otter.canal.client.adapter.phoenix.support.TypeUtil;\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\nimport com.alibaba.otter.canal.client.adapter.support.Util;\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.sql.Connection;\nimport java.sql.ResultSetMetaData;\nimport java.sql.SQLException;\nimport java.util.*;\nimport java.util.concurrent.*;\nimport java.util.function.Function;\n\n/**\n * Phoenix同步操作业务\n */\npublic class PhoenixSyncService {\n\n    private static final Logger logger = LoggerFactory.getLogger(PhoenixSyncService.class);\n\n    // 源库表字段类型缓存: instance.schema.table -> <columnName, jdbcType>\n    private Map<String, Map<String, Integer>> columnsTypeCache;\n\n    //同步线程数\n    //默认开启3个线程同步,此处配置了自定义同步线程数\n    private int threads = ConfigurationManager.getInteger(\"threads\");\n\n    private List<SyncItem>[] dmlsPartition;\n    private BatchExecutor[] batchExecutors;\n    private ExecutorService[] executorThreads;\n\n    public PhoenixSyncService(Integer threads) {\n        this(threads, new ConcurrentHashMap<>());\n    }\n\n\n    @SuppressWarnings(\"unchecked\")\n    private PhoenixSyncService(Integer threads, Map<String, Map<String, Integer>> columnsTypeCache) {\n        this.columnsTypeCache = columnsTypeCache;\n        try {\n            if (threads != null) {\n                this.threads = threads;\n            }\n            this.dmlsPartition = new List[this.threads];\n            this.batchExecutors = new BatchExecutor[this.threads];\n            this.executorThreads = new ExecutorService[this.threads];\n            for (int i = 0; i < this.threads; i++) {\n                dmlsPartition[i] = new ArrayList<>();\n                batchExecutors[i] = new BatchExecutor();\n                //创建单个线程，用来操作一个无界的队列任务，不会使用额外的线程。如果线程崩溃会重新创建一个，直到任务完成。\n                executorThreads[i] = Executors.newSingleThreadExecutor();\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * 批量同步回调\n     *\n     * @param dmls     批量 DML\n     * @param function 回调方法\n     */\n    private void sync(List<Dml> dmls, Function<Dml, Boolean> function) {\n        try {\n            boolean toExecute = false;\n            for (Dml dml : dmls) {\n                if (!toExecute) {\n                    toExecute = function.apply(dml);\n                } else {\n                    function.apply(dml);\n                }\n            }\n            if (toExecute) {\n                List<Future<Boolean>> futures = new ArrayList<>();\n                for (int i = 0; i < threads; i++) {\n                    int j = i;\n                    if (dmlsPartition[j].isEmpty()) {\n                        // bypass\n                        continue;\n                    }\n\n                    futures.add(executorThreads[i].submit(() -> {\n                        try {\n                            dmlsPartition[j].forEach(syncItem -> sync(batchExecutors[j],\n                                    syncItem.config,\n                                    syncItem.singleDml));\n                            //相对于RDB同步 少了  dmlsPartition[j].clear();\n                            //在 try catch中获取异常后再次执行一次batchExecutors[j].commit()\n                            batchExecutors[j].commit();\n                            return true;\n                        } catch (Throwable e) {\n                            batchExecutors[j].rollback();\n                            if (!e.getClass().getName().endsWith(\"ColumnNotFoundException\")\n                                    && !e.getClass().getName().endsWith(\"TableNotFoundException\")) {\n                                throw new RuntimeException(e);\n                            }\n                            logger.info(\"table or column not found: \" + e.getMessage());\n                            boolean synced = false;\n                            for (SyncItem syncItem : dmlsPartition[j]) {\n                                if (PhoenixEtlService.syncSchema(batchExecutors[j].getConn(), syncItem.config)) {\n                                    synced = true;\n                                }\n                            }\n                            if (!synced) {\n                                throw new RuntimeException(e);\n                            }\n                            dmlsPartition[j].forEach(syncItem -> sync(batchExecutors[j],\n                                    syncItem.config,\n                                    syncItem.singleDml));\n                            try {\n                                batchExecutors[j].commit();\n                                return true;\n                            } catch (Throwable e1) {\n                                batchExecutors[j].rollback();\n                                throw new RuntimeException(e1);\n                            }\n                        } finally {\n                            dmlsPartition[j].clear();\n                        }\n                    }));\n                }\n                futures.forEach(future -> {\n                    try {\n                        future.get();\n                    } catch (ExecutionException | InterruptedException e) {\n                        throw new RuntimeException(e);\n                    }\n                });\n            }\n        } finally {\n            for (BatchExecutor batchExecutor : batchExecutors) {\n                if (batchExecutor != null) {\n                    batchExecutor.close();\n                }\n            }\n        }\n    }\n\n    /**\n     * 批量同步 :将批量DML进行解析并放入List<SingleDml> --> dmlsPartition[hash].add(syncItem);\n     * @param mappingConfig 配置集合\n     * @param dmls   批量 DML\n     */\n    public void sync(Map<String, Map<String, MappingConfig>> mappingConfig, List<Dml> dmls, Properties envProperties) {\n        sync(dmls, dml -> {\n            String destination = StringUtils.trimToEmpty(dml.getDestination());\n            String groupId = StringUtils.trimToEmpty(dml.getGroupId());\n            String database = dml.getDatabase();\n            String table = dml.getTable().toLowerCase();\n            Map<String, MappingConfig> configMap;\n            if (envProperties != null && !\"tcp\".equalsIgnoreCase(envProperties.getProperty(\"canal.conf.mode\"))) {\n                //tcp 模式\n                configMap = mappingConfig.get(destination + \"-\" + groupId + \"_\" + database + \"-\" + table);\n            } else {\n                //kafka 模式 或者 RocketMQ模式\n                configMap = mappingConfig.get(destination + \"_\" + database + \"-\" + table);\n            }\n\n            if (configMap == null) {\n                if (logger.isTraceEnabled()) {\n                    logger.trace(\"no config map: destination={},groupId={}, database={}, table={}, keys={}\", destination, groupId, database, table, mappingConfig.keySet());\n                }\n                return false;\n            }\n            if (configMap.values().isEmpty()) {\n                logger.info(\"config map empty: destination={},groupId={}, database={}, table={}, keys={}\", destination, groupId, database, table, mappingConfig.keySet());\n                return false;\n            }\n            if (dml.getIsDdl() != null && dml.getIsDdl() && StringUtils.isNotEmpty(dml.getSql())) {\n                // DDL\n                columnsTypeCache.remove(dml.getDestination() + \".\" + dml.getDatabase() + \".\" + dml.getTable());\n                List<SQLStatement> stmtList;\n                try {\n                    stmtList = SQLUtils.parseStatements(dml.getSql(), JdbcConstants.MYSQL, false);\n                } catch (ParserException e) {\n                    // 可能存在一些SQL是不支持的，比如存储过程\n                    logger.info(\"parse sql error: \" + dml.getSql(), e);\n                    return false;\n                }\n                for (Map.Entry<String, MappingConfig> entry : configMap.entrySet()) {\n                    try {\n                        alter(batchExecutors[0], entry.getValue(), dml, stmtList, entry.getKey());\n                    } catch (SQLException e) {\n                        throw new RuntimeException(e);\n                    }\n                }\n                return false;\n            } else {\n                // DML\n                for (Map.Entry<String, MappingConfig> entry : configMap.entrySet()) {\n                    MappingConfig config = entry.getValue();\n                    if (config.isDebug()) {\n                        logger.info(\"DML: {} {}\", entry.getKey(), JSON.toJSONString(dml, Feature.WriteNulls));\n                    }\n                    if (config.getConcurrent()) {\n                        //并行同步\n                        //将一批DML转成SingleDml\n                        List<SingleDml> singleDmls = SingleDml.dml2SingleDmls(dml);\n                        singleDmls.forEach(singleDml -> {\n                            //取主键hash\n                            int hash = pkHash(config.getDbMapping(), singleDml.getData());\n                            SyncItem syncItem = new SyncItem(config, singleDml);\n                            //相同的主键数据的顺序是可以保证的\n                            dmlsPartition[hash].add(syncItem);\n                        });\n                    } else {\n                        //不并行同步\n                        int hash = 0;\n                        List<SingleDml> singleDmls = SingleDml.dml2SingleDmls(dml);\n                        singleDmls.forEach(singleDml -> {\n                            SyncItem syncItem = new SyncItem(config, singleDml);\n                            //这里线程默认是3个,如果不并行，则会出现2个线程空跑\n                            dmlsPartition[hash].add(syncItem);\n                        });\n                    }\n                }\n                return true;\n            }\n        });\n    }\n\n    /**\n     * 单条 dml 同步\n     *\n     * @param batchExecutor 批量事务执行器\n     * @param config        对应配置对象\n     * @param dml           DML\n     */\n    private void sync(BatchExecutor batchExecutor, MappingConfig config, SingleDml dml) {\n        if (config != null) {\n            try {\n                String type = dml.getType();\n                if (type != null && type.equalsIgnoreCase(\"INSERT\")) {\n                    insert(batchExecutor, config, dml);\n                } else if (type != null && type.equalsIgnoreCase(\"UPDATE\")) {\n                    insert(batchExecutor, config, dml);\n                } else if (type != null && type.equalsIgnoreCase(\"DELETE\")) {\n                    delete(batchExecutor, config, dml);\n                } else if (type != null && type.equalsIgnoreCase(\"TRUNCATE\")) {\n                    truncate(batchExecutor, config);\n                } else if (logger.isInfoEnabled()){\n                    logger.info(\"SingleDml: {}\", JSON.toJSONString(dml, Feature.WriteNulls));\n                }\n            } catch (SQLException e) {\n                logger.error(\"sync error: \" + e.getMessage(), e);\n                throw new RuntimeException(e);\n            }\n        }\n    }\n\n    private void alter(BatchExecutor batchExecutor, MappingConfig config, Dml dml, List<SQLStatement> stmtList, String configFile) throws SQLException {\n        if (config.isDebug()) {\n            logger.info(\"DML: {} {}\", configFile, JSON.toJSONString(dml, Feature.WriteNulls));\n        }\n        DbMapping dbMapping = config.getDbMapping();\n        if (!dbMapping.isAlter()) {\n            logger.info(\"not alterable table: {} {}\", dml.getTable(), configFile);\n            return;\n        }\n\n        Map<String, String> columnsMap = dbMapping.getTargetColumns();\n\n        Map<String, String> columnsMap1 = new HashMap<>();\n        for (Map.Entry<String, String> entry : columnsMap.entrySet()) {\n            columnsMap1.put(entry.getValue(), entry.getKey());\n        }\n\n        String targetTable = SyncUtil.getDbTableName(dbMapping);\n        Map<String, String> defValues = new HashMap<>();\n        for (SQLStatement statement : stmtList) {\n            if (statement instanceof SQLAlterTableStatement) {\n                SQLAlterTableStatement alterTable = (SQLAlterTableStatement) statement;\n                for (SQLAlterTableItem item : alterTable.getItems()) {\n                    if (item instanceof SQLAlterTableDropColumnItem) {\n                        SQLAlterTableDropColumnItem dropColumnItem = (SQLAlterTableDropColumnItem) item;\n                        if (!dbMapping.isDrop()) {\n                            logger.info(\"drop table column disabled: {} {}\", targetTable, dropColumnItem.getColumns());\n                            continue;\n                        }\n                        for (SQLName sqlName : dropColumnItem.getColumns()) {\n                            String name = Util.cleanColumn(sqlName.getSimpleName());\n                            String sql = \"ALTER TABLE \" + targetTable + \" DROP COLUMN IF EXISTS \" +\n                                    dbMapping.escape(columnsMap1.getOrDefault(name, name));\n                            try {\n                                logger.info(\"drop table column: {} {}\", sql, batchExecutor.executeUpdate(sql));\n                                dbMapping.removeTargetColumn(name);\n                            } catch (Exception e) {\n                                logger.warn(\"drop table column error: \" + sql, e);\n                            }\n                        }\n                    } else if (item instanceof SQLAlterTableAddColumn) {\n                        SQLAlterTableAddColumn addColumn = (SQLAlterTableAddColumn) item;\n                        if (!dbMapping.getMapAll()) {\n                            logger.info(\"add table column disabled: {} {}\", targetTable, addColumn.getColumns());\n                            continue;\n                        }\n                        for (SQLColumnDefinition definition : addColumn.getColumns()) {\n                            String name = Util.cleanColumn(definition.getNameAsString());\n                            if (dbMapping.getExcludeColumns().contains(name)) {\n                                continue;\n                            }\n                            String sql = \"ALTER TABLE \" + targetTable +\n                                    \" ADD IF NOT EXISTS \" +\n                                    dbMapping.escape(name) + \" \" + TypeUtil.getPhoenixType(definition, dbMapping.isLimit());\n                            try {\n                                logger.info(\"add table column: {} {}\", sql, batchExecutor.executeUpdate(sql));\n                                dbMapping.addTargetColumn(name, name);\n                                if (definition.getDefaultExpr() != null) {\n                                    String defVal = definition.getDefaultExpr().toString();\n                                    if (!defVal.equalsIgnoreCase(\"NULL\") && !defVal.equalsIgnoreCase(\"NOT NULL\") && name.length() > 0) {\n                                        defValues.put(name, defVal);\n                                    }\n                                }\n                            } catch (Exception e) {\n                                logger.error(\"add table column error: \" + sql, e);\n                                throw e;\n                            }\n                        }\n                    }\n                }\n            }\n        }\n        if (!defValues.isEmpty()) {\n            StringBuilder defSql = new StringBuilder();\n            defSql.append(\"UPSERT INTO \").append(targetTable).append(\"(\");\n            Set<Map.Entry<String, String>> pkSet = dbMapping.getTargetPk().entrySet();\n            Set<Map.Entry<String, String>> defSet = defValues.entrySet();\n            for (Map.Entry<String, String> entry : pkSet) {\n                defSql.append(dbMapping.escape(entry.getKey())).append(\",\");\n            }\n            for (Map.Entry<String, String> entry : defSet) {\n                defSql.append(dbMapping.escape(entry.getKey())).append(\",\");\n            }\n            defSql.deleteCharAt(defSql.length() - 1).append(\") SELECT \");\n            for (Map.Entry<String, String> entry : pkSet) {\n                defSql.append(dbMapping.escape(entry.getKey())).append(\",\");\n            }\n            for (Map.Entry<String, String> entry : defSet) {\n                defSql.append(entry.getValue()).append(\",\");\n            }\n            defSql.deleteCharAt(defSql.length() - 1).append(\" FROM \").append(targetTable);\n            try {\n                logger.info(\"set column default value: {} {}\", defSql, batchExecutor.executeUpdate(defSql.toString()));\n                batchExecutor.commit();\n            } catch (SQLException e) {\n                logger.error(\"set column default value error: {}\", defSql, e);\n                batchExecutor.rollback();\n                throw e;\n            }\n        }\n    }\n\n    /**\n     * 插入操作\n     *\n     * @param config 配置项\n     * @param dml    DML数据\n     */\n    private void insert(BatchExecutor batchExecutor, MappingConfig config, SingleDml dml) throws SQLException {\n        Map<String, Object> data = dml.getData();\n        if (data == null || data.isEmpty()) {\n            return;\n        }\n\n        DbMapping dbMapping = config.getDbMapping();\n        Map<String, String> columnsMap = SyncUtil.getColumnsMap(dbMapping, data);\n\n        StringBuilder insertSql = new StringBuilder();\n        insertSql.append(\"UPSERT INTO \").append(SyncUtil.getDbTableName(dbMapping)).append(\" (\");\n\n        Map<String, Integer> ctype = getTargetColumnType(batchExecutor.getConn(), config);\n\n        int mapLen = columnsMap.size();\n        List<Map<String, ?>> values = new ArrayList<>();\n        for (Map.Entry<String, String> entry : columnsMap.entrySet()) {\n            String targetColumnName = entry.getKey();\n            String srcColumnName = entry.getValue();\n            if (srcColumnName == null) {\n                srcColumnName = Util.cleanColumn(targetColumnName);\n            }\n\n            Integer type = ctype.get(Util.cleanColumn(targetColumnName).toLowerCase());\n            if (type == null) {\n                if (dbMapping.isSkipMissing()) {\n                    logger.warn(\"Target missing field: {}\", targetColumnName);\n                    mapLen -= 1;\n                    continue;\n                } else if (dbMapping.getMapAll() && dbMapping.isAlter() && PhoenixEtlService.syncSchema(batchExecutor.getConn(), config)) {\n                    columnsTypeCache.remove(config.getDestination() + \".\" + dbMapping.getDatabase() + \".\" + dbMapping.getTable());\n                    ctype = getTargetColumnType(batchExecutor.getConn(), config);\n                    type = ctype.get(Util.cleanColumn(targetColumnName).toLowerCase());\n                }\n                if (type == null) {\n                    throw new RuntimeException(\"Target column: \" + targetColumnName + \" not matched\");\n                }\n            }\n            insertSql.append(dbMapping.escape(targetColumnName)).append(\",\");\n            Object value = data.get(srcColumnName);\n            BatchExecutor.setValue(values, type, value);\n        }\n\n        int len = insertSql.length();\n        insertSql.delete(len - 1, len).append(\") VALUES (\");\n        for (int i = 0; i < mapLen; i++) {\n            insertSql.append(\"?,\");\n        }\n        len = insertSql.length();\n        insertSql.delete(len - 1, len).append(\")\");\n\n        Map<String, Object> old = dml.getOld();\n        try {\n            if (old != null && !old.isEmpty()) {\n                boolean keyChanged = false;\n                List<Map<String, ?>> delValues = new ArrayList<>();\n                StringBuilder deleteSql = new StringBuilder();\n                deleteSql.append(\"DELETE FROM \").append(SyncUtil.getDbTableName(dbMapping)).append(\" WHERE \");\n                for (Map.Entry<String, String> entry : dbMapping.getTargetPk().entrySet()) {\n                    String targetColumnName = entry.getKey();\n                    String srcColumnName = entry.getValue();\n                    if (srcColumnName == null) {\n                        srcColumnName = Util.cleanColumn(targetColumnName);\n                    }\n                    Integer type = ctype.get(Util.cleanColumn(targetColumnName).toLowerCase());\n                    if (type != null) {\n                        deleteSql.append(dbMapping.escape(targetColumnName)).append(\"=? AND \");\n                        // 如果有修改主键的情况\n                        if (old.containsKey(srcColumnName)) {\n                            keyChanged = true;\n                            BatchExecutor.setValue(delValues, type, old.get(srcColumnName));\n                        } else {\n                            BatchExecutor.setValue(delValues, type, data.get(srcColumnName));\n                        }\n                    }\n                }\n                if (keyChanged) {\n                    if (config.isDebug()) {\n                        logger.info(\"insert into table: {} {}\", deleteSql, delValues);\n                    }\n                    batchExecutor.execute(deleteSql.toString(), delValues);\n                }\n            }\n            if (config.isDebug()) {\n                logger.info(\"insert into table: {} {}\", insertSql, values);\n            }\n            batchExecutor.execute(insertSql.toString(), values);\n        } catch (SQLException | RuntimeException e) {\n            logger.warn(\"Insert into target table, sql: {} {}\", insertSql, values ,e);\n            throw e;\n        }\n        if (logger.isTraceEnabled()) {\n            logger.trace(\"Insert into target table, sql: {}\", insertSql);\n        }\n    }\n\n    /**\n     * 删除操作 没有改动\n     *\n     * @param config MappingConfig\n     * @param dml    Single DML\n     */\n    private void delete(BatchExecutor batchExecutor, MappingConfig config, SingleDml dml) throws SQLException {\n        Map<String, Object> data = dml.getData();\n        if (data == null || data.isEmpty()) {\n            return;\n        }\n\n        DbMapping dbMapping = config.getDbMapping();\n\n        Map<String, Integer> ctype = getTargetColumnType(batchExecutor.getConn(), config);\n\n        StringBuilder sql = new StringBuilder();\n        sql.append(\"DELETE FROM \").append(SyncUtil.getDbTableName(dbMapping)).append(\" WHERE \");\n\n        List<Map<String, ?>> values = new ArrayList<>();\n        // 拼接主键\n        appendCondition(dbMapping, sql, ctype, values, data);\n        try {\n            batchExecutor.execute(sql.toString(), values);\n            if (logger.isTraceEnabled()) {\n                logger.trace(\"Delete from target table, sql: {}\", sql);\n            }\n        } catch (SQLException e) {\n            logger.warn(\"Delete from target error, sql: {} {}\", sql, values);\n            throw e;\n        }\n    }\n\n    /**\n     * truncate操作   没有改动\n     *\n     * @param config MappingConfig\n     */\n    private void truncate(BatchExecutor batchExecutor, MappingConfig config) throws SQLException {\n        DbMapping dbMapping = config.getDbMapping();\n        StringBuilder sql = new StringBuilder();\n        sql.append(\"TRUNCATE TABLE \").append(SyncUtil.getDbTableName(dbMapping));\n        batchExecutor.execute(sql.toString(), new ArrayList<>());\n        if (logger.isTraceEnabled()) {\n            logger.trace(\"Truncate target table, sql: {}\", sql);\n        }\n    }\n\n    /**\n     * 获取目标字段类型\n     *\n     * @param conn   sql connection\n     * @param config 映射配置\n     * @return 字段sqlType\n     */\n    private Map<String, Integer> getTargetColumnType(Connection conn, MappingConfig config) {\n        DbMapping dbMapping = config.getDbMapping();\n        String cacheKey = config.getDestination() + \".\" + dbMapping.getDatabase() + \".\" + dbMapping.getTable();\n        Map<String, Integer> columnType = columnsTypeCache.get(cacheKey);\n        if (columnType == null) {\n            synchronized (PhoenixSyncService.class) {\n                columnType = columnsTypeCache.get(cacheKey);\n                if (columnType == null) {\n                    columnType = new LinkedHashMap<>();\n                    final Map<String, Integer> columnTypeTmp = columnType;\n                    String sql = \"SELECT * FROM \" + SyncUtil.getDbTableName(dbMapping) + \" WHERE 1=2\";\n                    try {\n                        Util.sqlRS(conn, sql, rs -> {\n                            try {\n                                ResultSetMetaData rsd = rs.getMetaData();\n                                int columnCount = rsd.getColumnCount();\n                                for (int i = 1; i <= columnCount; i++) {\n                                    columnTypeTmp.put(rsd.getColumnName(i).toLowerCase(), rsd.getColumnType(i));\n                                }\n                                columnsTypeCache.put(cacheKey, columnTypeTmp);\n                            } catch (SQLException e) {\n                                logger.error(e.getMessage(), e);\n                            }\n                        });\n                    } catch (RuntimeException e) {\n                        //新增catch 里面做了操作\n                        if (!e.getCause().getClass().getName().endsWith(\"TableNotFoundException\")) {\n                            throw e;\n                        }\n                        if (!PhoenixEtlService.syncSchema(conn, config)) {\n                            throw e;\n                        }\n                        Util.sqlRS(conn, sql, rs -> {\n                            try {\n                                ResultSetMetaData rsd = rs.getMetaData();\n                                int columnCount = rsd.getColumnCount();\n                                for (int i = 1; i <= columnCount; i++) {\n                                    columnTypeTmp.put(rsd.getColumnName(i).toLowerCase(), rsd.getColumnType(i));\n                                }\n                                columnsTypeCache.put(cacheKey, columnTypeTmp);\n                            } catch (SQLException e1) {\n                                logger.error(e1.getMessage(), e1);\n                            }\n                        });\n                    }\n                }\n            }\n        }\n        return columnType;\n    }\n\n    /**\n     * 拼接主键 where条件\n     */\n    private void appendCondition(DbMapping dbMapping, StringBuilder sql, Map<String, Integer> ctype,\n                                 List<Map<String, ?>> values, Map<String, Object> d) {\n        // 拼接主键\n        for (Map.Entry<String, String> entry : dbMapping.getTargetPk().entrySet()) {\n            String targetColumnName = entry.getKey();\n            String srcColumnName = entry.getValue();\n            if (srcColumnName == null) {\n                srcColumnName = Util.cleanColumn(targetColumnName);\n            }\n            sql.append(dbMapping.escape(targetColumnName)).append(\"=? AND \");\n            Integer type = ctype.get(Util.cleanColumn(targetColumnName).toLowerCase());\n            if (type == null) {\n                throw new RuntimeException(\"Target column: \" + targetColumnName + \" not matched\");\n            }\n            BatchExecutor.setValue(values, type, d.get(srcColumnName));\n        }\n        int len = sql.length();\n        sql.delete(len - 4, len);\n    }\n\n    public static class SyncItem {\n\n        private MappingConfig config;\n        private SingleDml singleDml;\n\n        SyncItem(MappingConfig config, SingleDml singleDml) {\n            this.config = config;\n            this.singleDml = singleDml;\n        }\n    }\n\n    /**\n     * 取主键hash\n     */\n    private int pkHash(DbMapping dbMapping, Map<String, Object> d) {\n        int hash = 0;\n        // 取主键\n        for (Map.Entry<String, String> entry : dbMapping.getTargetPk().entrySet()) {\n            String targetColumnName = entry.getKey();\n            String srcColumnName = entry.getValue();\n            if (srcColumnName == null) {\n                srcColumnName = Util.cleanColumn(targetColumnName);\n            }\n            Object value = null;\n            if (d != null) {\n                value = d.get(srcColumnName);\n            }\n            if (value != null) {\n                hash += value.hashCode();\n\n            }\n        }\n        hash = Math.abs(hash) % threads;\n        return Math.abs(hash);\n    }\n\n\n    public void close() {\n        for (int i = 0; i < threads; i++) {\n            executorThreads[i].shutdown();\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/phoenix/src/main/java/com/alibaba/otter/canal/client/adapter/phoenix/support/BatchExecutor.java",
    "content": "package com.alibaba.otter.canal.client.adapter.phoenix.support;\n\nimport com.alibaba.otter.canal.client.adapter.phoenix.PhoenixAdapter;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport javax.sql.DataSource;\nimport java.io.Closeable;\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * sql批量执行器   基本没有变动\n */\npublic class BatchExecutor implements Closeable {\n\n    private static final Logger logger = LoggerFactory.getLogger(BatchExecutor.class);\n\n    private DataSource          dataSource;\n    private Connection          conn;\n    private AtomicInteger       idx    = new AtomicInteger(0);\n\n    public BatchExecutor(DataSource dataSource){\n        this.dataSource = dataSource;\n    }\n    public BatchExecutor(){\n    }\n\n    public Connection getConn() {\n        if (conn == null) {\n            try {\n                conn=PhoenixAdapter.getPhoenixConnection();\n                this.conn.setAutoCommit(false);\n            } catch (SQLException e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n        return conn;\n    }\n\n    public static void setValue(List<Map<String, ?>> values, int type, Object value) {\n        Map<String, Object> valueItem = new HashMap<>();\n        valueItem.put(\"type\", type);\n        valueItem.put(\"value\", value);\n        values.add(valueItem);\n    }\n\n    public int executeUpdate(String sql) throws SQLException {\n        logger.debug(\"execute: {}\", sql);\n        Statement statement = getConn().createStatement();\n        int ret = statement.executeUpdate(sql);\n        statement.close();\n        return ret;\n    }\n\n    public void execute(String sql, List<Map<String, ?>> values) throws SQLException {\n        if (logger.isDebugEnabled()) {\n            logger.debug(\"execute: {} {}\", sql, Arrays.toString(values.toArray()));\n        }\n        PreparedStatement pstmt = getConn().prepareStatement(sql);\n        int len = values.size();\n        for (int i = 0; i < len; i++) {\n            int type = (Integer) values.get(i).get(\"type\");\n            Object value = values.get(i).get(\"value\");\n            SyncUtil.setPStmt(type, pstmt, value, i + 1);\n        }\n\n        pstmt.execute();\n        idx.incrementAndGet();\n        pstmt.close();\n    }\n\n    public void commit() throws SQLException {\n        getConn().commit();\n        if (logger.isTraceEnabled()) {\n            logger.trace(\"Batch executor commit \" + idx.get() + \" rows\");\n        }\n        idx.set(0);\n    }\n\n    public void rollback() throws SQLException {\n        getConn().rollback();\n        if (logger.isTraceEnabled()) {\n            logger.trace(\"Batch executor rollback \" + idx.get() + \" rows\");\n        }\n        idx.set(0);\n    }\n\n    @Override\n    public void close() {\n        if (conn != null) {\n            try {\n                conn.close();\n            } catch (SQLException e) {\n                logger.error(e.getMessage(), e);\n            } finally {\n                conn = null;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/phoenix/src/main/java/com/alibaba/otter/canal/client/adapter/phoenix/support/PhoenixSupportUtil.java",
    "content": "package com.alibaba.otter.canal.client.adapter.phoenix.support;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.sql.Connection;\nimport java.sql.ResultSet;\nimport java.sql.Statement;\nimport java.util.function.Function;\n\n/**\n * @author: lihua\n * @date: 2020/12/30 18:43\n * @Description:\n */\npublic class PhoenixSupportUtil {\n\n\n    public static final  Logger logger = LoggerFactory.getLogger(PhoenixSupportUtil.class);\n    public static Object sqlRS(Connection dsConnection, String sql, Function<ResultSet, Object> fun) {\n\n        try {\n            Connection conn = dsConnection;\n            Throwable var4 = null;\n\n            Object var9;\n            try {\n                Statement stmt = conn.createStatement(1003, 1007);\n                Throwable var6 = null;\n\n                try {\n                    stmt.setFetchSize(-2147483648);\n                    ResultSet rs = stmt.executeQuery(sql);\n                    Throwable var8 = null;\n\n                    try {\n                        var9 = fun.apply(rs);\n                    } catch (Throwable var56) {\n                        var9 = var56;\n                        var8 = var56;\n                        throw var56;\n                    } finally {\n                        if (rs != null) {\n                            if (var8 != null) {\n                                try {\n                                    rs.close();\n                                } catch (Throwable var55) {\n                                    var8.addSuppressed(var55);\n                                }\n                            } else {\n                                rs.close();\n                            }\n                        }\n\n                    }\n                } catch (Throwable var58) {\n                    var6 = var58;\n                    throw var58;\n                } finally {\n                    if (stmt != null) {\n                        if (var6 != null) {\n                            try {\n                                stmt.close();\n                            } catch (Throwable var54) {\n                                var6.addSuppressed(var54);\n                            }\n                        } else {\n                            stmt.close();\n                        }\n                    }\n\n                }\n            } catch (Throwable var60) {\n                var4 = var60;\n                throw var60;\n            } finally {\n                if (conn != null) {\n                    if (var4 != null) {\n                        try {\n                            conn.close();\n                        } catch (Throwable var53) {\n                            var4.addSuppressed(var53);\n                        }\n                    } else {\n                        conn.close();\n                    }\n                }\n\n            }\n\n            return var9;\n        } catch (Exception var62) {\n            logger.error(\"sqlRs has error, sql: {} \", sql);\n            throw new RuntimeException(var62);\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/phoenix/src/main/java/com/alibaba/otter/canal/client/adapter/phoenix/support/SingleDml.java",
    "content": "package com.alibaba.otter.canal.client.adapter.phoenix.support;\n\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * 没有改动 单个DML类\n */\n@SuppressWarnings({\"unused\", \"WeakerAccess\"})\npublic class SingleDml {\n\n    private String              destination;\n    private String              database;\n    private String              table;\n    private String              type;\n    private Map<String, Object> data;\n    private Map<String, Object> old;\n\n    public String getDestination() {\n        return destination;\n    }\n\n    public void setDestination(String destination) {\n        this.destination = destination;\n    }\n\n    public String getDatabase() {\n        return database;\n    }\n\n    public void setDatabase(String database) {\n        this.database = database;\n    }\n\n    public String getTable() {\n        return table;\n    }\n\n    public void setTable(String table) {\n        this.table = table;\n    }\n\n    public String getType() {\n        return type;\n    }\n\n    public void setType(String type) {\n        this.type = type;\n    }\n\n    public Map<String, Object> getData() {\n        return data;\n    }\n\n    public void setData(Map<String, Object> data) {\n        this.data = data;\n    }\n\n    public Map<String, Object> getOld() {\n        return old;\n    }\n\n    public void setOld(Map<String, Object> old) {\n        this.old = old;\n    }\n\n    public static List<SingleDml> dml2SingleDmls(Dml dml) {\n        List<SingleDml> singleDmls = new ArrayList<>();\n        if (dml.getData() != null) {\n            int size = dml.getData().size();\n            for (int i = 0; i < size; i++) {\n                SingleDml singleDml = new SingleDml();\n                singleDml.setDestination(dml.getDestination());\n                singleDml.setDatabase(dml.getDatabase());\n                singleDml.setTable(dml.getTable());\n                singleDml.setType(dml.getType());\n                singleDml.setData(dml.getData().get(i));\n                if (dml.getOld() != null) {\n                    singleDml.setOld(dml.getOld().get(i));\n                }\n                singleDmls.add(singleDml);\n            }\n            //MaxWell 中没有对TRUNCATE的DML操作进行解析\n        } else if (\"TRUNCATE\".equalsIgnoreCase(dml.getType())) {\n            SingleDml singleDml = new SingleDml();\n            singleDml.setDestination(dml.getDestination());\n            singleDml.setDatabase(dml.getDatabase());\n            singleDml.setTable(dml.getTable());\n            singleDml.setType(dml.getType());\n            singleDmls.add(singleDml);\n        }\n        return singleDmls;\n    }\n}\n"
  },
  {
    "path": "client-adapter/phoenix/src/main/java/com/alibaba/otter/canal/client/adapter/phoenix/support/SyncUtil.java",
    "content": "package com.alibaba.otter.canal.client.adapter.phoenix.support;\n\nimport com.alibaba.otter.canal.client.adapter.phoenix.config.MappingConfig;\nimport com.alibaba.otter.canal.client.adapter.support.Util;\nimport org.apache.commons.lang.StringUtils;\n\nimport java.io.Reader;\nimport java.io.StringReader;\nimport java.math.BigDecimal;\nimport java.nio.charset.StandardCharsets;\nimport java.sql.*;\nimport java.util.Collection;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\npublic class SyncUtil {\n\n    public static Map<String, String> getColumnsMap(MappingConfig.DbMapping dbMapping, Map<String, Object> data) {\n        return getColumnsMap(dbMapping, data.keySet());\n    }\n\n    public static Map<String, String> getColumnsMap(MappingConfig.DbMapping dbMapping, Collection<String> columns) {\n        Map<String, String> columnsMap;\n        if (dbMapping.getMapAll()) {\n            if (dbMapping.getAllMapColumns() != null) {\n                return dbMapping.getAllMapColumns();\n            }\n            columnsMap = new LinkedHashMap<>();\n            for (String srcColumn : columns) {\n                boolean flag = true;\n                if (dbMapping.getTargetColumns() != null) {\n                    for (Map.Entry<String, String> entry : dbMapping.getTargetColumns().entrySet()) {\n                        if (srcColumn.equals(entry.getValue())) {\n                            columnsMap.put(entry.getKey(), srcColumn);\n                            flag = false;\n                            break;\n                        }\n                    }\n                }\n                //新增 排除掉getExcludeColumns() 去除的列\n                if (flag && !dbMapping.getExcludeColumns().contains(srcColumn)) {\n                    columnsMap.put(srcColumn, srcColumn);\n                }\n            }\n            dbMapping.setAllMapColumns(columnsMap);\n        } else {\n            columnsMap = dbMapping.getTargetColumns();\n        }\n        return columnsMap;\n    }\n\n    /**\n     * 设置 preparedStatement\n     *\n     * @param type sqlType\n     * @param pstmt 需要设置的preparedStatement\n     * @param value 值\n     * @param i 索引号\n     */\n    public static void setPStmt(int type, PreparedStatement pstmt, Object value, int i) throws SQLException {\n        switch (type) {\n            case Types.BIT:\n            case Types.BOOLEAN:\n                if (value instanceof Boolean) {\n                    pstmt.setBoolean(i, (Boolean) value);\n                } else if (value instanceof String) {\n                    boolean v = !value.equals(\"0\");\n                    pstmt.setBoolean(i, v);\n                } else if (value instanceof Number) {\n                    boolean v = ((Number) value).intValue() != 0;\n                    pstmt.setBoolean(i, v);\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.CHAR:\n            case Types.NCHAR:\n            case Types.VARCHAR:\n            case Types.LONGVARCHAR:\n                if (value instanceof String) {\n                    pstmt.setString(i, (String) value);\n                } else if (value == null) {\n                    pstmt.setNull(i, type);\n                } else {\n                    pstmt.setString(i, value.toString());\n                }\n                break;\n            case Types.TINYINT:\n                if (value instanceof Number) {\n                    pstmt.setByte(i, ((Number) value).byteValue());\n                } else if (value instanceof String) {\n                    pstmt.setByte(i, Byte.parseByte((String) value));\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.SMALLINT:\n                if (value instanceof Number) {\n                    pstmt.setShort(i, ((Number) value).shortValue());\n                } else if (value instanceof String) {\n                    pstmt.setShort(i, Short.parseShort((String) value));\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.INTEGER:\n                if (value instanceof Number) {\n                    pstmt.setInt(i, ((Number) value).intValue());\n                } else if (value instanceof String) {\n                    pstmt.setInt(i, Integer.parseInt((String) value));\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.BIGINT:\n                if (value instanceof Number) {\n                    pstmt.setLong(i, ((Number) value).longValue());\n                } else if (value instanceof String) {\n                    pstmt.setLong(i, Long.parseLong((String) value));\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.DECIMAL:\n            case Types.NUMERIC:\n                if (value instanceof BigDecimal) {\n                    pstmt.setBigDecimal(i, (BigDecimal) value);\n                } else if (value instanceof Byte) {\n                    pstmt.setInt(i, ((Byte) value).intValue());\n                } else if (value instanceof Short) {\n                    pstmt.setInt(i, ((Short) value).intValue());\n                } else if (value instanceof Integer) {\n                    pstmt.setInt(i, (Integer) value);\n                } else if (value instanceof Long) {\n                    pstmt.setLong(i, (Long) value);\n                } else if (value instanceof Float) {\n                    pstmt.setBigDecimal(i, new BigDecimal((float) value));\n                } else if (value instanceof Double) {\n                    pstmt.setBigDecimal(i, new BigDecimal((double) value));\n                } else if (value != null) {\n                    pstmt.setBigDecimal(i, new BigDecimal(value.toString()));\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.REAL:\n                if (value instanceof Number) {\n                    pstmt.setFloat(i, ((Number) value).floatValue());\n                } else if (value instanceof String) {\n                    pstmt.setFloat(i, Float.parseFloat((String) value));\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.FLOAT:\n            case Types.DOUBLE:\n                if (value instanceof Number) {\n                    pstmt.setDouble(i, ((Number) value).doubleValue());\n                } else if (value instanceof String) {\n                    pstmt.setDouble(i, Double.parseDouble((String) value));\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.BINARY:\n            case Types.VARBINARY:\n            case Types.LONGVARBINARY:\n            case Types.BLOB:\n                if (value instanceof Blob) {\n                    pstmt.setBlob(i, (Blob) value);\n                } else if (value instanceof byte[]) {\n                    pstmt.setBytes(i, (byte[]) value);\n                } else if (value instanceof String) {\n                    pstmt.setBytes(i, ((String) value).getBytes(StandardCharsets.ISO_8859_1));\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.CLOB:\n                if (value instanceof Clob) {\n                    pstmt.setClob(i, (Clob) value);\n                } else if (value instanceof byte[]) {\n                    pstmt.setBytes(i, (byte[]) value);\n                } else if (value instanceof String) {\n                    Reader clobReader = new StringReader((String) value);\n                    pstmt.setCharacterStream(i, clobReader);\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.DATE:\n                if (value instanceof Date) {\n                    pstmt.setDate(i, (Date) value);\n                } else if (value instanceof java.util.Date) {\n                    pstmt.setDate(i, new Date(((java.util.Date) value).getTime()));\n                } else if (value instanceof String) {\n                    String v = (String) value;\n                    if (!v.startsWith(\"0000-00-00\")) {\n                        java.util.Date date = Util.parseDate(v);\n                        if (date != null) {\n                            pstmt.setDate(i, new Date(date.getTime()));\n                        } else {\n                            pstmt.setNull(i, type);\n                        }\n                    } else {\n                        pstmt.setObject(i, value);\n                    }\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.TIME:\n                if (value instanceof Time) {\n                    pstmt.setTime(i, (Time) value);\n                } else if (value instanceof java.util.Date) {\n                    pstmt.setTime(i, new Time(((java.util.Date) value).getTime()));\n                } else if (value instanceof String) {\n                    String v = (String) value;\n                    java.util.Date date = Util.parseDate(v);\n                    if (date != null) {\n                        pstmt.setTime(i, new Time(date.getTime()));\n                    } else {\n                        pstmt.setNull(i, type);\n                    }\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.TIMESTAMP:\n                if (value instanceof Timestamp) {\n                    pstmt.setTimestamp(i, (Timestamp) value);\n                } else if (value instanceof java.util.Date) {\n                    pstmt.setTimestamp(i, new Timestamp(((java.util.Date) value).getTime()));\n                } else if (value instanceof String) {\n                    String v = (String) value;\n                    if (!v.startsWith(\"0000-00-00\")) {\n                        java.util.Date date = Util.parseDate(v);\n                        if (date != null) {\n                            pstmt.setTimestamp(i, new Timestamp(date.getTime()));\n                        } else {\n                            pstmt.setNull(i, type);\n                        }\n                    } else {\n                        pstmt.setObject(i, value);\n                    }\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            default:\n                pstmt.setObject(i, value, type);\n        }\n    }\n\n    public static String getDbTableName(MappingConfig.DbMapping dbMapping) {\n        String result = \"\";\n        if (StringUtils.isNotEmpty(dbMapping.getTargetDb())) {\n            if (dbMapping.isEscapeUpper()) {\n                //新增 字段默认大写加双引号\n                result += \"\\\"\" + dbMapping.getTargetDb() + \"\\\".\";\n            } else {\n                result += dbMapping.getTargetDb() + \".\";\n            }\n        }\n\n        if (dbMapping.isEscapeUpper()) {\n            //新增  字段默认大写加双引号\n            result += \"\\\"\" + dbMapping.getTargetTable().replaceAll(\"\\\\.\", \"\\\".\\\"\") + \"\\\"\";\n        } else {\n            result += dbMapping.getTargetTable();\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "client-adapter/phoenix/src/main/java/com/alibaba/otter/canal/client/adapter/phoenix/support/TypeUtil.java",
    "content": "package com.alibaba.otter.canal.client.adapter.phoenix.support;\n\nimport com.alibaba.druid.sql.ast.SQLDataType;\nimport com.alibaba.druid.sql.ast.SQLDataTypeImpl;\nimport com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;\nimport org.apache.commons.lang.StringUtils;\n\n/**\n * Phoenix类型   此类型完全新增\n */\npublic class TypeUtil {\n\n    private static String joinArgs(String type, Object[] args) {\n        if (args.length > 0) {\n            return type + \"(\" + StringUtils.join(args, \",\") + \")\";\n        }\n        return type;\n    }\n\n    /**\n     * 根据SQL的定义返回Phoenix的类型定义\n     * @see \"https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-reference-type-conversions.html\"\n     * @param definition SQL的字段定义\n     * @param limit 是否启用字段长度限制\n     * @return Phoenix字段类型定义\n     */\n    public static String getPhoenixType(SQLColumnDefinition definition, boolean limit) {\n        if (definition == null) return \"VARCHAR\";\n        SQLDataType sqlDataType = definition.getDataType();\n        SQLDataTypeImpl sqlDataType1 = sqlDataType instanceof SQLDataTypeImpl ? (SQLDataTypeImpl)sqlDataType : null;\n        boolean isUnsigned = sqlDataType1 != null && sqlDataType1.isUnsigned();\n\n        return getPhoenixType(sqlDataType.getName().toUpperCase(), sqlDataType.getArguments().toArray(), isUnsigned, limit);\n    }\n\n    //MySQL类型和Phoenix类型一一对应\n    public static String getPhoenixType(String name, Object[] args, boolean isUnsigned, boolean limit) {\n        switch (name) {\n            case \"BIT\":\n                if (limit) {\n                    return joinArgs(\"BINARY\", args);\n                }\n                return \"BINARY\";\n            case \"TINYINT\":\n                if (isUnsigned) {\n                    return \"UNSIGNED_TINYINT\";\n                }\n                return \"TINYINT\";\n            case \"BOOLEAN\":\n            case \"BOOL\":\n                return \"BOOLEAN\";\n            case \"SMALLINT\":\n                if (isUnsigned) {\n                    return \"UNSIGNED_SMALLINT\";\n                }\n                return \"SMALLINT\";\n            case \"MEDIUMINT\":\n                return \"INTEGER\";\n            case \"INT\":\n            case \"INTEGER\":\n                if (isUnsigned) {\n                    return \"UNSIGNED_INT\";\n                }\n                return \"INTEGER\";\n            case \"BIGINT\":\n                if (isUnsigned) {\n                    return \"UNSIGNED_LONG\";\n                }\n                return \"BIGINT\";\n            case \"FLOAT\":\n                if (isUnsigned) {\n                    return \"UNSIGNED_FLOAT\";\n                }\n                return \"FLOAT\";\n            case \"DOUBLE\":\n                if (isUnsigned) {\n                    return \"UNSIGNED_DOUBLE\";\n                }\n                return \"DOUBLE\";\n            case \"DECIMAL\":\n                if (limit) {\n                    return joinArgs(\"DECIMAL\", args);\n                }\n                return \"DECIMAL\";\n            case \"DATE\":\n                if (isUnsigned) {\n                    return \"UNSIGNED_DATE\";\n                }\n                return \"DATE\";\n            case \"DATETIME\":\n            case \"TIMESTAMP\":\n                if (isUnsigned) {\n                    return \"UNSIGNED_TIMESTAMP\";\n                }\n                return \"TIMESTAMP\";\n            case \"TIME\":\n                if (isUnsigned) {\n                    return \"UNSIGNED_TIME\";\n                }\n                return \"TIME\";\n            case \"YEAR\":\n                return \"INTEGER\";\n            case \"CHAR\":\n                if (limit) {\n                    return joinArgs(name, args);\n                }\n                return \"VARCHAR\";\n            case \"VARCHAR\":\n                if (limit) {\n                    return joinArgs(name, args);\n                }\n                return \"VARCHAR\";\n            case \"BINARY\":\n                if (limit) {\n                    return joinArgs(name, args);\n                }\n                return \"VARBINARY\";\n            case \"VARBINARY\":\n                return \"VARBINARY\";\n            case \"TINYBLOB\":\n                return \"VARBINARY\";\n            case \"TINYTEXT\":\n                return \"VARCHAR\";\n            case \"BLOB\":\n                return \"VARBINARY\";\n            case \"TEXT\":\n                return \"VARCHAR\";\n            case \"MEDIUMBLOB\":\n                return \"VARBINARY\";\n            case \"MEDIUMTEXT\":\n                return \"VARCHAR\";\n            case \"LONGBLOB\":\n                return \"VARBINARY\";\n            case \"LONGTEXT\":\n                return \"VARCHAR\";\n            case \"ENUM\":\n            case \"SET\":\n                return \"VARCHAR\";\n        }\n        return \"VARCHAR\";\n    }\n}\n"
  },
  {
    "path": "client-adapter/phoenix/src/main/resources/META-INF/canal/com.alibaba.otter.canal.client.adapter.OuterAdapter",
    "content": "phoenix=com.alibaba.otter.canal.client.adapter.phoenix.PhoenixAdapter"
  },
  {
    "path": "client-adapter/phoenix/src/main/resources/hbase-site.xml",
    "content": "<?xml version=\"1.0\"?>\n<?xml-stylesheet type=\"text/xsl\" href=\"configuration.xsl\"?>\n<!--\n/**\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n-->\n<configuration>\n\n  <!--支持NAMESPACE映射 -->\n   <property>\n          <name>phoenix.schema.isNamespaceMappingEnabled</name>\n          <value>true</value>\n   </property>\n   <property>\n          <name>phoenix.schema.mapSystemTablesToNamespace</name>\n          <value>true</value>\n   </property>\n  <!--支持phoenix的二级索引 -->\n   <property>\n          <name>hbase.regionserver.wal.codec</name>\n          <value>org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec</value>\n   </property>\n   <property>  \n        <name>hbase.table.sanity.checks</name>  \n        <value>false</value> \n   </property> \n  <!--启动压缩文件检查 -->\n   <property>\n     <name>hbase.regionserver.codecs</name>\n     <value>snappy,lzo</value>\n   </property>\n  <!-- rpc 超时时长 -->\n\t<property>\n\t  <name>hbase.rpc.timeout</name>\n\t  <value>1200000</value>\n\t</property>\n\t<property>\n\t  <name>hbase.client.operation.timeout</name>\n\t  <value>600000</value>\n\t</property>\n\t<property>\n\t  <name>hbase.client.scanner.timeout.period</name>\n\t  <value>1200000</value>\n\t</property>\n\t<property>\n\t  <name>hbase.client.scanner.timeout.period</name>\n\t  <value>1200000</value>\n\t</property>\n\t<property>\n\t <name>phoenix.query.timeoutMs</name>\n\t <value>1800000</value>\n\t</property>\n\t<property>\n\t <name>phoenix.query.keepAliveMs</name>\n\t <value>600000</value>\n\t</property>\n\t<property>\n\t  <name>hbase.client.ipc.pool.type</name>\n\t  <value>RoundRobinPool</value>\n\t</property>\n\t<property>\n\t  <name>hbase.client.ipc.pool.size</name>\n\t  <value>10</value>\n\t</property>\n\t<property>\n\t  <name>index.builder.threads.keepalivetime</name>\n\t  <value>1200000</value>\n\t</property>\n\t<property>\n\t  <name>index.write.threads.keepalivetime</name>\n\t  <value>1200000</value>\n\t</property>\n\t<property>\n\t  <name>hbase.htable.threads.keepalivetime</name>\n\t  <value>1200000</value>\n\t</property>\n<!--允许写入自定义WAL编辑，确保索引更新的正确性 -->\n\t<property>\n\t  <name>hbase.regionserver.wal.codec</name>\n\t  <value>org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec</value>\n\t</property>\n\n</configuration>\n"
  },
  {
    "path": "client-adapter/phoenix/src/main/resources/phoenix/phoenix_common.properties",
    "content": "# ͬ߳\nthreads =3"
  },
  {
    "path": "client-adapter/phoenix/src/main/resources/phoenix/phoenixtest_user.yml",
    "content": "dataSourceKey: defaultDS\ndestination: example\ngroupId: g1\nouterAdapterKey: phoenix\nconcurrent: true\ndbMapping:\n  database: mytest\n  table: user\n  targetTable: mytest.user\n  escapeUpper: true  # 字段默认大写，并用双引号引起来\n  targetPk:\n    id: ID\n  mapAll: true  # 映射所有字段(默认true，不包含排除的字段)\n  alter: true   # 允许修改表结构(默认true，mapAll=true时可以新增，drop=true时可以删除字段)\n  drop: false   # 允许删除字段(默认false)\n  skipMissing: false # 是否跳过缺失的字段(默认false，允许新增字段时会自动同步缺失的字段;true时跳过缺失的字段)\n  limit: false  # 是否限与数据长度限制一致(默认false，不限制长度避免修改长度而无法修改)\n  targetColumns:\n    id: ID\n    name: NAME\n  excludeColumns: # 排除字段\n    - password"
  },
  {
    "path": "client-adapter/phoenix/src/test/java/com/alibaba/otter/canal/client/adapter/phoenix/test/PhoenixConnectionTest.java",
    "content": "package com.alibaba.otter.canal.client.adapter.phoenix.test;\n\nimport java.sql.Connection;\nimport java.sql.DriverManager;\nimport java.util.Properties;\n\n/**\n * @author: lihua\n * @date: 2021/1/5 16:58\n * @Description:\n */\npublic class PhoenixConnectionTest {\n\n    public static void main(String[] args) {\n        Properties phoenixPro = new Properties();\n        //phoenix内部本身有连接池，不需要使用Druid初始化\n        phoenixPro.setProperty(\"hbase.rpc.timeout\",\"600000\");\n        phoenixPro.setProperty(\"hbase.client.scanner.timeout.period\",\"600000\");\n        phoenixPro.setProperty(\"dfs.client.socket-timeout\",\"600000\");\n        phoenixPro.setProperty(\"phoenix.query.keepAliveMs\",\"600000\");\n        phoenixPro.setProperty(\"phoenix.query.timeoutMs\",\"3600000\");\n        try {\n            Class.forName(\"org.apache.phoenix.jdbc.PhoenixDriver\");\n            Connection connection = DriverManager.getConnection(\"jdbc:phoenix:zookeeper01,zookeeper02,zookeeper03:2181:/hbase/db\", phoenixPro);\n            System.out.println(connection);\n            connection.close();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n    }\n}\n"
  },
  {
    "path": "client-adapter/phoenix/src/test/java/com/alibaba/otter/canal/client/adapter/phoenix/test/TestConfigLoad.java",
    "content": "package com.alibaba.otter.canal.client.adapter.phoenix.test;\n\nimport com.alibaba.otter.canal.client.adapter.phoenix.config.ConfigLoader;\nimport com.alibaba.otter.canal.client.adapter.phoenix.config.MappingConfig;\nimport com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.util.Map;\n\n/**\n * @author: lihua\n * @date: 2021/1/5 17:07\n * @Description:\n */\npublic class TestConfigLoad {\n    @Before\n    public void before() {\n        // 加载数据源连接池\n        DatasourceConfig.DATA_SOURCES.put(\"defaultDS\", TestConstant.dataSource);\n    }\n\n    @Test\n    public void testLoad() {\n        Map<String, MappingConfig> configMap = ConfigLoader.load(null);\n        Assert.assertFalse(configMap.isEmpty());\n    }\n}\n"
  },
  {
    "path": "client-adapter/phoenix/src/test/java/com/alibaba/otter/canal/client/adapter/phoenix/test/TestConstant.java",
    "content": "package com.alibaba.otter.canal.client.adapter.phoenix.test;\n\nimport com.alibaba.druid.pool.DruidDataSource;\n\nimport java.sql.SQLException;\n\n/**\n * @author: lihua\n * @date: 2021/1/5 17:09\n * @Description:\n */\npublic class TestConstant {\n    public final static String          jdbcUrl      = \"jdbc:mysql://127.0.0.1:3306/canal_adapter?useUnicode=true\";\n    public final static String          jdbcUser     = \"root\";\n    public final static String          jdbcPassword = \"!123456\";\n\n    public final static DruidDataSource dataSource;\n\n    static {\n        dataSource = new DruidDataSource();\n        dataSource.setDriverClassName(\"com.mysql.jdbc.Driver\");\n        dataSource.setUrl(jdbcUrl);\n        dataSource.setUsername(jdbcUser);\n        dataSource.setPassword(jdbcPassword);\n        dataSource.setInitialSize(1);\n        dataSource.setMinIdle(1);\n        dataSource.setMaxActive(1);\n        dataSource.setMaxWait(60000);\n        dataSource.setTimeBetweenEvictionRunsMillis(60000);\n        dataSource.setMinEvictableIdleTimeMillis(300000);\n        dataSource.setPoolPreparedStatements(false);\n        dataSource.setMaxPoolPreparedStatementPerConnectionSize(20);\n        dataSource.setValidationQuery(\"select 1\");\n        try {\n            dataSource.init();\n        } catch (SQLException e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/phoenix/src/test/java/com/alibaba/otter/canal/client/adapter/phoenix/test/sync/Common.java",
    "content": "package com.alibaba.otter.canal.client.adapter.phoenix.test.sync;\n\nimport com.alibaba.otter.canal.client.adapter.phoenix.PhoenixAdapter;\nimport com.alibaba.otter.canal.client.adapter.phoenix.test.TestConstant;\nimport com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;\nimport com.alibaba.otter.canal.client.adapter.support.OuterAdapterConfig;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * @author: lihua\n * @date: 2021/1/5 23:15\n * @Description:\n */\npublic class Common {\n    public static PhoenixAdapter init() {\n        DatasourceConfig.DATA_SOURCES.put(\"defaultDS\", TestConstant.dataSource);\n\n        OuterAdapterConfig outerAdapterConfig = new OuterAdapterConfig();\n        outerAdapterConfig.setName(\"phoenix\");\n        outerAdapterConfig.setKey(\"phoenix\");\n        Map<String, String> properties = new HashMap<>();\n        properties.put(\"jdbc.driverClassName\", \"org.apache.phoenix.jdbc.PhoenixDriver\");\n        properties.put(\"jdbc.url\", \"jdbc:phoenix:zookeeper01,zookeeper02,zookeeper03:2181:/hbase/db\");\n        outerAdapterConfig.setProperties(properties);\n\n        PhoenixAdapter adapter = new PhoenixAdapter();\n        adapter.init(outerAdapterConfig, null);\n        return adapter;\n    }\n\n    public static void main(String[] args) {\n        init();\n    }\n}\n"
  },
  {
    "path": "client-adapter/phoenix/src/test/java/com/alibaba/otter/canal/client/adapter/phoenix/test/sync/PhoenixSyncTest.java",
    "content": "package com.alibaba.otter.canal.client.adapter.phoenix.test.sync;\n\nimport com.alibaba.otter.canal.client.adapter.phoenix.PhoenixAdapter;\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.util.*;\n\n/**\n * @author: lihua\n * @date: 2021/1/5 23:16\n * @Description:\n */\npublic class PhoenixSyncTest {\n\n    private PhoenixAdapter phoenixAdapter;\n\n    @Before\n    public void init() {\n        phoenixAdapter = Common.init();\n    }\n\n    @Test\n    public void testEtl() {\n        List<String> param = new ArrayList<>();\n        phoenixAdapter.etl(\"phoenixtest_user.yml\", param);\n    }\n    @Test\n    public void testCount() {\n        phoenixAdapter.count(\"phoenixtest_user.yml\");\n    }\n    @Test\n    public void test01() {\n        Dml dml = new Dml();\n        dml.setDestination(\"example\");\n        dml.setTs(new Date().getTime());\n        dml.setType(\"INSERT\");\n        dml.setDatabase(\"mytest\");\n        dml.setTable(\"user\");\n        List<Map<String, Object>> dataList = new ArrayList<>();\n        Map<String, Object> data = new LinkedHashMap<>();\n        dataList.add(data);\n        data.put(\"id\", 1);\n        data.put(\"name\", \"sixPulseExcalibur\");\n        data.put(\"password\", \"123456\");\n        dml.setData(dataList);\n\n        phoenixAdapter.sync(Collections.singletonList(dml));\n    }\n\n    @Test\n    public void test02() {\n        Dml dml = new Dml();\n        dml.setDestination(\"example\");\n        dml.setTs(new Date().getTime());\n        dml.setType(\"UPDATE\");\n        dml.setDatabase(\"mytest\");\n        dml.setTable(\"user\");\n        List<Map<String, Object>> dataList = new ArrayList<>();\n        Map<String, Object> data = new LinkedHashMap<>();\n        dataList.add(data);\n        data.put(\"id\", 1);\n        data.put(\"name\", \"sixPulseExcalibur2\");\n        dml.setData(dataList);\n        List<Map<String, Object>> oldList = new ArrayList<>();\n        Map<String, Object> old = new LinkedHashMap<>();\n        oldList.add(old);\n        old.put(\"name\", \"sixPulseExcalibur\");\n        dml.setOld(oldList);\n        phoenixAdapter.sync(Collections.singletonList(dml));\n    }\n}\n"
  },
  {
    "path": "client-adapter/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>com.alibaba.otter</groupId>\n        <artifactId>canal</artifactId>\n        <version>1.1.9-SNAPSHOT</version>\n        <relativePath>../pom.xml</relativePath>\n    </parent>\n    <groupId>com.alibaba.otter</groupId>\n    <artifactId>canal.client-adapter</artifactId>\n    <version>1.1.9-SNAPSHOT</version>\n    <packaging>pom</packaging>\n    <name>canal client adapter module for otter ${project.version}</name>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <maven.test.skip>true</maven.test.skip>\n        <downloadSources>true</downloadSources>\n        <java_source_version>1.8</java_source_version>\n        <java_target_version>1.8</java_target_version>\n        <file_encoding>UTF-8</file_encoding>\n        <log4j_version>2.17.0</log4j_version>\n    </properties>\n\n    <modules>\n        <module>common</module>\n        <module>logger</module>\n        <module>hbase</module>\n        <module>launcher</module>\n        <module>rdb</module>\n        <module>es6x</module>\n        <module>es7x</module>\n        <module>es8x</module>\n        <module>escore</module>\n        <module>kudu</module>\n        <module>phoenix</module>\n        <module>tablestore</module>\n        <module>clickhouse</module>\n    </modules>\n\n    <licenses>\n        <license>\n            <name>Apache License, Version 2.0</name>\n            <url>http://www.apache.org/licenses/LICENSE-2.0</url>\n        </license>\n    </licenses>\n\n    <scm>\n        <url>git@github.com:alibaba/canal.git</url>\n        <connection>scm:git:git@github.com:alibaba/canal.git</connection>\n        <developerConnection>scm:git:git@github.com:alibaba/canal.git</developerConnection>\n    </scm>\n\n    <repositories>\n        <repository>\n            <id>central</id>\n            <url>https://repo1.maven.org/maven2</url>\n            <releases>\n                <enabled>true</enabled>\n            </releases>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </repository>\n        <repository>\n            <id>java.net</id>\n            <url>https://download.java.net/maven/2/</url>\n            <releases>\n                <enabled>true</enabled>\n            </releases>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </repository>\n        <repository>\n            <id>aliyun</id>\n            <url>https://maven.aliyun.com/nexus/content/groups/public/</url>\n            <releases>\n                <enabled>true</enabled>\n            </releases>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </repository>\n        <repository>\n            <id>sonatype</id>\n            <name>sonatype</name>\n            <url>https://oss.sonatype.org/content/repositories/snapshots</url>\n            <releases>\n                <enabled>false</enabled>\n            </releases>\n            <snapshots>\n                <enabled>true</enabled>\n            </snapshots>\n        </repository>\n        <repository>\n            <id>sonatype-release</id>\n            <name>sonatype-release</name>\n            <url>https://oss.sonatype.org/service/local/repositories/releases/content</url>\n            <releases>\n                <enabled>false</enabled>\n            </releases>\n            <snapshots>\n                <enabled>true</enabled>\n            </snapshots>\n        </repository>\n    </repositories>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-context</artifactId>\n                <version>3.0.6</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot</artifactId>\n                <version>2.5.15</version>\n            </dependency>\n            <dependency>\n                <groupId>com.h2database</groupId>\n                <artifactId>h2</artifactId>\n                <version>1.4.192</version>\n            </dependency>\n            <!-- 单独引入rocketmq依赖 -->\n            <dependency>\n                <groupId>org.apache.rocketmq</groupId>\n                <artifactId>rocketmq-client</artifactId>\n            <version>${rocketmq_version}</version>\n            </dependency>\n            <!-- 单独引入kafka依赖 -->\n            <dependency>\n                <groupId>org.apache.kafka</groupId>\n                <artifactId>kafka-clients</artifactId>\n                <version>${kafka_version}</version>\n            </dependency>\n            <!-- rabbitmq -->\n            <dependency>\n                <groupId>com.rabbitmq</groupId>\n                <artifactId>amqp-client</artifactId>\n                <version>${rabbitmq_version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.alibaba.mq-amqp</groupId>\n                <artifactId>mq-amqp-client</artifactId>\n                <version>${mq_amqp_client}</version>\n            </dependency>\n            <!-- jdbc -->\n            <dependency>\n                <groupId>mysql</groupId>\n                <artifactId>mysql-connector-java</artifactId>\n                <version>${mysql_driver_version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.postgresql</groupId>\n                <artifactId>postgresql</artifactId>\n                <version>42.5.1</version>\n            </dependency>\n            <dependency>\n                <groupId>com.oracle.database.jdbc</groupId>\n                <artifactId>ojdbc6</artifactId>\n                <version>11.2.0.4</version>\n            </dependency>\n            <dependency>\n                <groupId>com.microsoft.sqlserver</groupId>\n                <artifactId>mssql-jdbc</artifactId>\n                <version>7.0.0.jre8</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.hbase</groupId>\n                <artifactId>hbase-shaded-client</artifactId>\n                <version>1.1.2</version>\n                <exclusions>\n                    <exclusion>\n                        <groupId>org.slf4j</groupId>\n                        <artifactId>slf4j-log4j12</artifactId>\n                    </exclusion>\n                    <exclusion>\n                        <groupId>jdk.tools</groupId>\n                        <artifactId>jdk.tools</artifactId>\n                    </exclusion>\n                </exclusions>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.phoenix</groupId>\n                <artifactId>phoenix-core</artifactId>\n                <version>4.14.1-HBase-1.4</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.hbase</groupId>\n                <artifactId>hbase-client</artifactId>\n                <version>1.4.8</version>\n            </dependency>\n            <dependency>\n                <groupId>ru.yandex.clickhouse</groupId>\n                <artifactId>clickhouse-jdbc</artifactId>\n                <version>0.3.1</version>\n            </dependency>\n            <dependency>\n                <groupId>com.aliyun.openservices</groupId>\n                <artifactId>tablestore</artifactId>\n                <version>5.10.3</version>\n                <classifier>jar-with-dependencies</classifier>\n                <exclusions>\n                    <exclusion>\n                        <groupId>com.google.protobuf</groupId>\n                        <artifactId>protobuf-java</artifactId>\n                    </exclusion>\n                    <exclusion>\n                        <groupId>org.apache.httpcomponents</groupId>\n                        <artifactId>httpasyncclient</artifactId>\n                    </exclusion>\n                </exclusions>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.kudu</groupId>\n                <artifactId>kudu-client</artifactId>\n                <version>1.6.0</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.curator</groupId>\n                <artifactId>curator-recipes</artifactId>\n                <version>2.10.0</version>\n            </dependency>\n            <!-- 单独指定guava版本，兼容curator-client -->\n            <dependency>\n                <groupId>com.google.guava</groupId>\n                <artifactId>guava</artifactId>\n                <version>18.0</version>\n            </dependency>\n            <dependency>\n                <groupId>joda-time</groupId>\n                <artifactId>joda-time</artifactId>\n                <version>2.9.4</version>\n            </dependency>\n            <dependency>\n                <groupId>org.yaml</groupId>\n                <artifactId>snakeyaml</artifactId>\n                <version>2.0</version>\n            </dependency>\n            <!-- test -->\n            <dependency>\n                <groupId>org.powermock</groupId>\n                <artifactId>powermock-api-mockito</artifactId>\n                <version>1.6.5</version>\n                <scope>test</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.powermock</groupId>\n                <artifactId>powermock-module-junit4</artifactId>\n                <version>1.6.5</version>\n                <scope>test</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.mockito</groupId>\n                <artifactId>mockito-all</artifactId>\n                <version>1.10.19</version>\n                <scope>test</scope>\n            </dependency>\n            <dependency>\n                <groupId>junit</groupId>\n                <artifactId>junit</artifactId>\n                <version>4.8.2</version>\n                <scope>test</scope>\n            </dependency>\n            <dependency>\n                <groupId>com.diffblue</groupId>\n                <artifactId>deeptestutils</artifactId>\n                <version>1.9.0</version>\n                <scope>test</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.7.0</version>\n                <configuration>\n                    <source>${java_source_version}</source>\n                    <target>${java_target_version}</target>\n                    <encoding>${file_encoding}</encoding>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n    <distributionManagement>\n        <snapshotRepository>\n            <id>sonatype-nexus-snapshots</id>\n            <name>Sonatype Nexus Snapshots</name>\n            <url>https://oss.sonatype.org/content/repositories/snapshots/</url>\n        </snapshotRepository>\n        <repository>\n            <id>sonatype-nexus-staging</id>\n            <name>Nexus Release Repository</name>\n            <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>\n        </repository>\n    </distributionManagement>\n</project>\n"
  },
  {
    "path": "client-adapter/rdb/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>canal.client-adapter</artifactId>\n        <groupId>com.alibaba.otter</groupId>\n        <version>1.1.9-SNAPSHOT</version>\n        <relativePath>../pom.xml</relativePath>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>com.alibaba.otter</groupId>\n    <artifactId>client-adapter.rdb</artifactId>\n    <packaging>jar</packaging>\n    <name>canal client adapter rdb module for otter ${project.version}</name>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>client-adapter.common</artifactId>\n            <version>${project.version}</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.postgresql</groupId>\n            <artifactId>postgresql</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.oracle.database.jdbc</groupId>\n            <artifactId>ojdbc6</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.microsoft.sqlserver</groupId>\n            <artifactId>mssql-jdbc</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-assembly-plugin</artifactId>\n                <version>2.4</version>\n                <configuration>\n                    <descriptorRefs>\n                        <descriptorRef>jar-with-dependencies</descriptorRef>\n                    </descriptorRefs>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>make-assembly</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>single</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-antrun-plugin</artifactId>\n                <version>1.8</version>\n                <executions>\n                    <execution>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>run</goal>\n                        </goals>\n                        <configuration>\n                            <tasks>\n                                <copy todir=\"${project.basedir}/../launcher/target/classes/rdb\" overwrite=\"true\">\n                                    <fileset dir=\"${project.basedir}/target/classes/rdb\" erroronmissingdir=\"true\">\n                                        <include name=\"*.yml\" />\n                                    </fileset>\n                                </copy>\n                            </tasks>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "client-adapter/rdb/src/main/java/com/alibaba/otter/canal/client/adapter/rdb/RdbAdapter.java",
    "content": "package com.alibaba.otter.canal.client.adapter.rdb;\n\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.apache.commons.lang.BooleanUtils;\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.druid.filter.stat.StatFilter;\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.alibaba.druid.util.JdbcUtils;\nimport com.alibaba.otter.canal.client.adapter.OuterAdapter;\nimport com.alibaba.otter.canal.client.adapter.rdb.config.ConfigLoader;\nimport com.alibaba.otter.canal.client.adapter.rdb.config.MappingConfig;\nimport com.alibaba.otter.canal.client.adapter.rdb.config.MirrorDbConfig;\nimport com.alibaba.otter.canal.client.adapter.rdb.monitor.RdbConfigMonitor;\nimport com.alibaba.otter.canal.client.adapter.rdb.service.RdbEtlService;\nimport com.alibaba.otter.canal.client.adapter.rdb.service.RdbMirrorDbSyncService;\nimport com.alibaba.otter.canal.client.adapter.rdb.service.RdbSyncService;\nimport com.alibaba.otter.canal.client.adapter.rdb.support.SyncUtil;\nimport com.alibaba.otter.canal.client.adapter.support.*;\n\n/**\n * RDB适配器实现类\n *\n * @author rewerma 2018-11-7 下午06:45:49\n * @version 1.0.0\n */\n@SPI(\"rdb\")\npublic class RdbAdapter implements OuterAdapter {\n\n    private static Logger                           logger              = LoggerFactory.getLogger(RdbAdapter.class);\n\n    private Map<String, MappingConfig>              rdbMapping          = new ConcurrentHashMap<>();                // 文件名对应配置\n    private Map<String, Map<String, MappingConfig>> mappingConfigCache  = new ConcurrentHashMap<>();                // 库名-表名对应配置\n    private Map<String, MirrorDbConfig>             mirrorDbConfigCache = new ConcurrentHashMap<>();                // 镜像库配置\n\n    private DruidDataSource                         dataSource;\n\n    private RdbSyncService                          rdbSyncService;\n    private RdbMirrorDbSyncService                  rdbMirrorDbSyncService;\n\n    private RdbConfigMonitor                        rdbConfigMonitor;\n\n    private Properties                              envProperties;\n\n    private OuterAdapterConfig                      configuration;\n\n    public Map<String, MappingConfig> getRdbMapping() {\n        return rdbMapping;\n    }\n\n    public Map<String, Map<String, MappingConfig>> getMappingConfigCache() {\n        return mappingConfigCache;\n    }\n\n    public Map<String, MirrorDbConfig> getMirrorDbConfigCache() {\n        return mirrorDbConfigCache;\n    }\n\n    /**\n     * 初始化方法\n     *\n     * @param configuration 外部适配器配置信息\n     */\n    @Override\n    public void init(OuterAdapterConfig configuration, Properties envProperties) {\n        this.envProperties = envProperties;\n        this.configuration = configuration;\n      \n        // 从jdbc url获取db类型\n        Map<String, String> properties = configuration.getProperties();\n        String dbType = JdbcUtils.getDbType(properties.get(\"jdbc.url\"), null);\n        // 当.yml文件编码格式存在问题，此处rdb yml文件构建 可能会抛出异常\n        Map<String, MappingConfig> rdbMappingTmp = ConfigLoader.load(envProperties);\n        // 过滤不匹配的key的配置\n        rdbMappingTmp.forEach((key, config) -> {\n            addConfig(key, config);\n        });\n\n        if (rdbMapping.isEmpty()) {\n            throw new RuntimeException(\"No rdb adapter found for config key: \" + configuration.getKey());\n        }\n\n        // 初始化连接池\n        dataSource = new DruidDataSource();\n        dataSource.setDriverClassName(properties.get(\"jdbc.driverClassName\"));\n        dataSource.setUrl(properties.get(\"jdbc.url\"));\n        dataSource.setUsername(properties.get(\"jdbc.username\"));\n        dataSource.setPassword(properties.get(\"jdbc.password\"));\n        dataSource.setInitialSize(1);\n        dataSource.setMinIdle(1);\n        dataSource.setMaxActive(30);\n        dataSource.setMaxWait(60000);\n        dataSource.setTimeBetweenEvictionRunsMillis(60000);\n        dataSource.setMinEvictableIdleTimeMillis(300000);\n        dataSource.setUseUnfairLock(true);\n        dataSource.setDbType(dbType);\n\n        // List<String> array = new ArrayList<>();\n        // array.add(\"set names utf8mb4;\");\n        // dataSource.setConnectionInitSqls(array);\n\n        if (\"true\".equals(properties.getOrDefault(\"druid.stat.enable\", \"true\"))) {\n            StatFilter statFilter = new StatFilter();\n            statFilter.setSlowSqlMillis(Long.parseLong(properties.getOrDefault(\"druid.stat.slowSqlMillis\", \"1000\")));\n            statFilter.setMergeSql(true);\n            statFilter.setLogSlowSql(true);\n            dataSource.setProxyFilters(Collections.singletonList(statFilter));\n        }\n\n        try {\n            dataSource.init();\n        } catch (SQLException e) {\n            logger.error(\"ERROR ## failed to initial datasource: \" + properties.get(\"jdbc.url\"), e);\n        }\n\n        String threads = properties.get(\"threads\");\n        // String commitSize = properties.get(\"commitSize\");\n\n        boolean skipDupException = BooleanUtils.toBoolean(configuration.getProperties()\n            .getOrDefault(\"skipDupException\", \"true\"));\n        rdbSyncService = new RdbSyncService(dataSource,\n            threads != null ? Integer.valueOf(threads) : null,\n            skipDupException);\n\n        rdbMirrorDbSyncService = new RdbMirrorDbSyncService(mirrorDbConfigCache,\n            dataSource,\n            threads != null ? Integer.valueOf(threads) : null,\n            rdbSyncService.getColumnsTypeCache(),\n            skipDupException);\n\n        rdbConfigMonitor = new RdbConfigMonitor();\n        rdbConfigMonitor.init(configuration.getKey(), this, envProperties);\n    }\n\n    /**\n     * 同步方法\n     *\n     * @param dmls 数据包\n     */\n    @Override\n    public void sync(List<Dml> dmls) {\n        if (dmls == null || dmls.isEmpty()) {\n            return;\n        }\n        try {\n            if (!mappingConfigCache.isEmpty()) {\n                rdbSyncService.sync(mappingConfigCache, dmls, envProperties);\n            }\n            rdbMirrorDbSyncService.sync(dmls);\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * ETL方法\n     *\n     * @param task 任务名, 对应配置名\n     * @param params etl筛选条件\n     * @return ETL结果\n     */\n    @Override\n    public EtlResult etl(String task, List<String> params) {\n        EtlResult etlResult = new EtlResult();\n        MappingConfig config = rdbMapping.get(task);\n        RdbEtlService rdbEtlService = new RdbEtlService(dataSource, config);\n        if (config != null) {\n            return rdbEtlService.importData(params);\n        } else {\n            StringBuilder resultMsg = new StringBuilder();\n            boolean resSucc = true;\n            for (MappingConfig configTmp : rdbMapping.values()) {\n                // 取所有的destination为task的配置\n                if (configTmp.getDestination().equals(task)) {\n                    EtlResult etlRes = rdbEtlService.importData(params);\n                    if (!etlRes.getSucceeded()) {\n                        resSucc = false;\n                        resultMsg.append(etlRes.getErrorMessage()).append(\"\\n\");\n                    } else {\n                        resultMsg.append(etlRes.getResultMessage()).append(\"\\n\");\n                    }\n                }\n            }\n            if (resultMsg.length() > 0) {\n                etlResult.setSucceeded(resSucc);\n                if (resSucc) {\n                    etlResult.setResultMessage(resultMsg.toString());\n                } else {\n                    etlResult.setErrorMessage(resultMsg.toString());\n                }\n                return etlResult;\n            }\n        }\n        etlResult.setSucceeded(false);\n        etlResult.setErrorMessage(\"Task not found\");\n        return etlResult;\n    }\n\n    /**\n     * 获取总数方法\n     *\n     * @param task 任务名, 对应配置名\n     * @return 总数\n     */\n    @Override\n    public Map<String, Object> count(String task) {\n        MappingConfig config = rdbMapping.get(task);\n        MappingConfig.DbMapping dbMapping = config.getDbMapping();\n        String sql = \"SELECT COUNT(1) AS cnt FROM \" + SyncUtil.getDbTableName(dbMapping, dataSource.getDbType());\n        Connection conn = null;\n        Map<String, Object> res = new LinkedHashMap<>();\n        try {\n            conn = dataSource.getConnection();\n            Util.sqlRS(conn, sql, rs -> {\n                try {\n                    if (rs.next()) {\n                        Long rowCount = rs.getLong(\"cnt\");\n                        res.put(\"count\", rowCount);\n                    }\n                } catch (SQLException e) {\n                    logger.error(e.getMessage(), e);\n                }\n            });\n        } catch (SQLException e) {\n            logger.error(e.getMessage(), e);\n        } finally {\n            if (conn != null) {\n                try {\n                    conn.close();\n                } catch (SQLException e) {\n                    logger.error(e.getMessage(), e);\n                }\n            }\n        }\n        res.put(\"targetTable\", SyncUtil.getDbTableName(dbMapping, dataSource.getDbType()));\n\n        return res;\n    }\n\n    /**\n     * 获取对应canal instance name 或 mq topic\n     *\n     * @param task 任务名, 对应配置名\n     * @return destination\n     */\n    @Override\n    public String getDestination(String task) {\n        MappingConfig config = rdbMapping.get(task);\n        if (config != null) {\n            return config.getDestination();\n        }\n        return null;\n    }\n\n    /**\n     * 销毁方法\n     */\n    @Override\n    public void destroy() {\n        if (rdbConfigMonitor != null) {\n            rdbConfigMonitor.destroy();\n        }\n\n        if (rdbSyncService != null) {\n            rdbSyncService.close();\n        }\n\n        if (dataSource != null) {\n            dataSource.close();\n        }\n    }\n\n    private void addSyncConfigToCache(String configName, MappingConfig mappingConfig) {\n        if (!mappingConfig.getDbMapping().getMirrorDb()) {\n            String key;\n            if (envProperties != null && !\"tcp\".equalsIgnoreCase(envProperties.getProperty(\"canal.conf.mode\"))) {\n                key = StringUtils.trimToEmpty(mappingConfig.getDestination()) + \"-\"\n                        + StringUtils.trimToEmpty(mappingConfig.getGroupId()) + \"_\"\n                        + mappingConfig.getDbMapping().getDatabase() + \"-\" + mappingConfig.getDbMapping().getTable();\n            } else {\n                key = StringUtils.trimToEmpty(mappingConfig.getDestination()) + \"_\"\n                        + mappingConfig.getDbMapping().getDatabase() + \"-\" + mappingConfig.getDbMapping().getTable();\n            }\n            Map<String, MappingConfig> configMap = mappingConfigCache.computeIfAbsent(key,\n                    k1 -> new ConcurrentHashMap<>());\n            configMap.put(configName, mappingConfig);\n        } else {\n            // mirrorDB\n            String key = StringUtils.trimToEmpty(mappingConfig.getDestination()) + \".\"\n                    + mappingConfig.getDbMapping().getDatabase();\n            mirrorDbConfigCache.put(key, MirrorDbConfig.create(configName, mappingConfig));\n        }\n    }\n\n    public boolean addConfig(String fileName, MappingConfig config) {\n        if (match(config)) {\n            rdbMapping.put(fileName, config);\n            addSyncConfigToCache(fileName, config);\n            FileName2KeyMapping.register(getClass().getAnnotation(SPI.class).value(), fileName,\n                    configuration.getKey());\n            return true;\n        }\n        return false;\n    }\n\n    public void updateConfig(String fileName, MappingConfig config) {\n        if (config.getOuterAdapterKey() != null && !config.getOuterAdapterKey()\n                .equals(configuration.getKey())) {\n            // 理论上不允许改这个 因为本身就是通过这个关联起Adapter和Config的\n            throw new RuntimeException(\"not allow to change outAdapterKey\");\n        }\n        rdbMapping.put(fileName, config);\n        addSyncConfigToCache(fileName, config);\n    }\n\n    public void deleteConfig(String fileName) {\n        rdbMapping.remove(fileName);\n        for (Map<String, MappingConfig> configMap : mappingConfigCache.values()) {\n            if (configMap != null) {\n                configMap.remove(fileName);\n            }\n        }\n        FileName2KeyMapping.unregister(getClass().getAnnotation(SPI.class).value(), fileName);\n    }\n\n    private boolean match(MappingConfig config) {\n        boolean sameMatch = config.getOuterAdapterKey() != null && config.getOuterAdapterKey()\n                .equalsIgnoreCase(configuration.getKey());\n        boolean prefixMatch = config.getOuterAdapterKey() == null && configuration.getKey()\n                .startsWith(StringUtils\n                        .join(new String[]{Util.AUTO_GENERATED_PREFIX, config.getDestination(),\n                                config.getGroupId()}, '-'));\n        return sameMatch || prefixMatch;\n    }\n}\n"
  },
  {
    "path": "client-adapter/rdb/src/main/java/com/alibaba/otter/canal/client/adapter/rdb/config/ConfigLoader.java",
    "content": "package com.alibaba.otter.canal.client.adapter.rdb.config;\r\n\r\nimport com.alibaba.otter.canal.client.adapter.support.YamlUtils;\r\nimport java.util.LinkedHashMap;\r\nimport java.util.Map;\r\nimport java.util.Properties;\r\n\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\n\r\nimport com.alibaba.otter.canal.client.adapter.support.MappingConfigsLoader;\r\n\r\n/**\r\n * RDB表映射配置加载器\r\n *\r\n * @author rewerma 2018-11-07 下午02:41:34\r\n * @version 1.0.0\r\n */\r\npublic class ConfigLoader {\r\n\r\n    private static Logger logger = LoggerFactory.getLogger(ConfigLoader.class);\r\n\r\n    /**\r\n     * 加载RDB表映射配置\r\n     *\r\n     * @return 配置名/配置文件名--对象\r\n     */\r\n    public static Map<String, MappingConfig> load(Properties envProperties) {\r\n        logger.info(\"## Start loading rdb mapping config ... \");\r\n\r\n        Map<String, MappingConfig> result = new LinkedHashMap<>();\r\n\r\n        Map<String, String> configContentMap = MappingConfigsLoader.loadConfigs(\"rdb\");\r\n        configContentMap.forEach((fileName, content) -> {\r\n            MappingConfig config = YamlUtils.ymlToObj(null, content, MappingConfig.class, null, envProperties);\r\n            if (config == null) {\r\n                return;\r\n            }\r\n            try {\r\n                config.validate();\r\n            } catch (Exception e) {\r\n                throw new RuntimeException(\"ERROR Config: \" + fileName + \" \" + e.getMessage(), e);\r\n            }\r\n            result.put(fileName, config);\r\n        });\r\n\r\n        logger.info(\"## Rdb mapping config loaded\");\r\n        return result;\r\n    }\r\n}\r\n"
  },
  {
    "path": "client-adapter/rdb/src/main/java/com/alibaba/otter/canal/client/adapter/rdb/config/MappingConfig.java",
    "content": "package com.alibaba.otter.canal.client.adapter.rdb.config;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.apache.commons.lang.StringUtils;\n\nimport com.alibaba.otter.canal.client.adapter.support.AdapterConfig;\n\n/**\n * RDB表映射配置\n *\n * @author rewerma 2018-11-07 下午02:41:34\n * @version 1.0.0\n */\npublic class MappingConfig implements AdapterConfig {\n\n    private String    dataSourceKey;      // 数据源key\n\n    private String    destination;        // canal实例或MQ的topic\n\n    private String    groupId;            // groupId\n\n    private String    outerAdapterKey;    // 对应适配器的key\n\n    private boolean   concurrent = false; // 是否并行同步\n\n    private DbMapping dbMapping;          // db映射配置\n\n    public String getDataSourceKey() {\n        return dataSourceKey;\n    }\n\n    public void setDataSourceKey(String dataSourceKey) {\n        this.dataSourceKey = dataSourceKey;\n    }\n\n    public String getGroupId() {\n        return groupId;\n    }\n\n    public void setGroupId(String groupId) {\n        this.groupId = groupId;\n    }\n\n    public String getOuterAdapterKey() {\n        return outerAdapterKey;\n    }\n\n    public void setOuterAdapterKey(String outerAdapterKey) {\n        this.outerAdapterKey = outerAdapterKey;\n    }\n\n    public boolean getConcurrent() {\n        return concurrent;\n    }\n\n    public void setConcurrent(boolean concurrent) {\n        this.concurrent = concurrent;\n    }\n\n    public DbMapping getDbMapping() {\n        return dbMapping;\n    }\n\n    public void setDbMapping(DbMapping dbMapping) {\n        this.dbMapping = dbMapping;\n    }\n\n    public String getDestination() {\n        return destination;\n    }\n\n    public void setDestination(String destination) {\n        this.destination = destination;\n    }\n\n    public AdapterMapping getMapping() {\n        return dbMapping;\n    }\n\n    public void validate() {\n        if (dbMapping.database == null || dbMapping.database.isEmpty()) {\n            throw new NullPointerException(\"dbMapping.database\");\n        }\n        if (!dbMapping.getMirrorDb() && (dbMapping.table == null || dbMapping.table.isEmpty())) {\n            throw new NullPointerException(\"dbMapping.table\");\n        }\n        if (!dbMapping.getMirrorDb() && (dbMapping.targetTable == null || dbMapping.targetTable.isEmpty())) {\n            throw new NullPointerException(\"dbMapping.targetTable\");\n        }\n    }\n\n    public static class DbMapping implements AdapterMapping {\n\n        private boolean             mirrorDb        = false;                 // 是否镜像库\n        private String              database;                                // 数据库名或schema名\n        private String              table;                                   // 表名\n        private Map<String, String> targetPk        = new LinkedHashMap<>(); // 目标表主键字段\n        private boolean             mapAll          = false;                 // 映射所有字段\n        private String              targetDb;                                // 目标库名\n        private String              targetTable;                             // 目标表名\n        private Map<String, String> targetColumns;                           // 目标表字段映射\n\n        private boolean             caseInsensitive = false;                 // 目标表不区分大小写，默认是否\n\n        private String              etlCondition;                            // etl条件sql\n\n        private int                 readBatch       = 5000;\n        private int                 commitBatch     = 5000;                  // etl等批量提交大小\n\n        private Map<String, String> allMapColumns;\n\n        public boolean getMirrorDb() {\n            return mirrorDb;\n        }\n\n        public void setMirrorDb(boolean mirrorDb) {\n            this.mirrorDb = mirrorDb;\n        }\n\n        public String getDatabase() {\n            return database;\n        }\n\n        public void setDatabase(String database) {\n            this.database = database;\n        }\n\n        public String getTable() {\n            return table;\n        }\n\n        public void setTable(String table) {\n            this.table = table;\n        }\n\n        public Map<String, String> getTargetPk() {\n            return targetPk;\n        }\n\n        public void setTargetPk(Map<String, String> targetPk) {\n            this.targetPk = targetPk;\n        }\n\n        public Boolean getMapAll() {\n            return mapAll;\n        }\n\n        public void setMapAll(Boolean mapAll) {\n            this.mapAll = mapAll;\n        }\n\n        public String getTargetDb() {\n            return targetDb;\n        }\n\n        public void setTargetDb(String targetDb) {\n            this.targetDb = targetDb;\n        }\n\n        public String getTargetTable() {\n            return targetTable;\n        }\n\n        public void setTargetTable(String targetTable) {\n            this.targetTable = targetTable;\n        }\n\n        public Map<String, String> getTargetColumns() {\n            if (targetColumns != null) {\n                targetColumns.forEach((key, value) -> {\n                    if (StringUtils.isEmpty(value)) {\n                        targetColumns.put(key, key);\n                    }\n                });\n            }\n            return targetColumns;\n        }\n\n        public void setTargetColumns(Map<String, String> targetColumns) {\n            this.targetColumns = targetColumns;\n        }\n\n        public boolean isCaseInsensitive() {\n            return caseInsensitive;\n        }\n\n        public void setCaseInsensitive(boolean caseInsensitive) {\n            this.caseInsensitive = caseInsensitive;\n        }\n\n        public String getEtlCondition() {\n            return etlCondition;\n        }\n\n        public void setEtlCondition(String etlCondition) {\n            this.etlCondition = etlCondition;\n        }\n\n        public int getReadBatch() {\n            return readBatch;\n        }\n\n        public void setReadBatch(int readBatch) {\n            this.readBatch = readBatch;\n        }\n\n        public int getCommitBatch() {\n            return commitBatch;\n        }\n\n        public void setCommitBatch(int commitBatch) {\n            this.commitBatch = commitBatch;\n        }\n\n        public Map<String, String> getAllMapColumns() {\n            return allMapColumns;\n        }\n\n        public void setAllMapColumns(Map<String, String> allMapColumns) {\n            this.allMapColumns = allMapColumns;\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/rdb/src/main/java/com/alibaba/otter/canal/client/adapter/rdb/config/MirrorDbConfig.java",
    "content": "package com.alibaba.otter.canal.client.adapter.rdb.config;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\npublic class MirrorDbConfig {\n\n    private String             fileName;\n    private MappingConfig      mappingConfig;\n    private Map<String, MappingConfig> tableConfig = new ConcurrentHashMap<>();\n\n    public static MirrorDbConfig create(String fileName, MappingConfig mappingConfig) {\n        return new MirrorDbConfig(fileName, mappingConfig);\n    }\n\n    public MirrorDbConfig(String fileName, MappingConfig mappingConfig){\n        this.fileName = fileName;\n        this.mappingConfig = mappingConfig;\n    }\n\n    public String getFileName() {\n        return fileName;\n    }\n\n    public void setFileName(String fileName) {\n        this.fileName = fileName;\n    }\n\n    public MappingConfig getMappingConfig() {\n        return mappingConfig;\n    }\n\n    public void setMappingConfig(MappingConfig mappingConfig) {\n        this.mappingConfig = mappingConfig;\n    }\n\n    public Map<String, MappingConfig> getTableConfig() {\n        return tableConfig;\n    }\n\n    public void setTableConfig(Map<String, MappingConfig> tableConfig) {\n        this.tableConfig = tableConfig;\n    }\n}\n"
  },
  {
    "path": "client-adapter/rdb/src/main/java/com/alibaba/otter/canal/client/adapter/rdb/monitor/RdbConfigMonitor.java",
    "content": "package com.alibaba.otter.canal.client.adapter.rdb.monitor;\n\nimport com.alibaba.otter.canal.client.adapter.rdb.RdbAdapter;\nimport com.alibaba.otter.canal.client.adapter.rdb.config.MappingConfig;\nimport com.alibaba.otter.canal.client.adapter.support.MappingConfigsLoader;\nimport com.alibaba.otter.canal.client.adapter.support.Util;\nimport com.alibaba.otter.canal.client.adapter.support.YamlUtils;\nimport java.io.File;\nimport java.util.Properties;\nimport org.apache.commons.io.filefilter.FileFilterUtils;\nimport org.apache.commons.io.monitor.FileAlterationListenerAdaptor;\nimport org.apache.commons.io.monitor.FileAlterationMonitor;\nimport org.apache.commons.io.monitor.FileAlterationObserver;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class RdbConfigMonitor {\n\n    private static final Logger   logger      = LoggerFactory.getLogger(RdbConfigMonitor.class);\n\n    private static final String   adapterName = \"rdb\";\n\n    private String                key;\n\n    private RdbAdapter            rdbAdapter;\n\n    private Properties            envProperties;\n\n    private FileAlterationMonitor fileMonitor;\n\n    public void init(String key, RdbAdapter rdbAdapter, Properties envProperties) {\n        this.key = key;\n        this.rdbAdapter = rdbAdapter;\n        this.envProperties = envProperties;\n        File confDir = Util.getConfDirPath(adapterName);\n        try {\n            FileAlterationObserver observer = new FileAlterationObserver(confDir,\n                FileFilterUtils.and(FileFilterUtils.fileFileFilter(), FileFilterUtils.suffixFileFilter(\"yml\")));\n            FileListener listener = new FileListener();\n            observer.addListener(listener);\n            fileMonitor = new FileAlterationMonitor(3000, observer);\n            fileMonitor.start();\n\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n        }\n    }\n\n    public void destroy() {\n        try {\n            fileMonitor.stop();\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n        }\n    }\n\n    private class FileListener extends FileAlterationListenerAdaptor {\n\n        @Override\n        public void onFileCreate(File file) {\n            super.onFileCreate(file);\n            try {\n                // 加载新增的配置文件\n                String configContent = MappingConfigsLoader.loadConfig(adapterName + File.separator + file.getName());\n                MappingConfig config = YamlUtils\n                    .ymlToObj(null, configContent, MappingConfig.class, null, envProperties);\n                if (config == null) {\n                    return;\n                }\n                config.validate();\n                boolean result = rdbAdapter.addConfig(file.getName(), config);\n                if (result) {\n                    logger.info(\"Add a new rdb mapping config: {} to canal adapter\", file.getName());\n                }\n            } catch (Exception e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n\n        @Override\n        public void onFileChange(File file) {\n            super.onFileChange(file);\n\n            try {\n                if (rdbAdapter.getRdbMapping().containsKey(file.getName())) {\n                    // 加载配置文件\n                    String configContent = MappingConfigsLoader\n                        .loadConfig(adapterName + File.separator + file.getName());\n                    if (configContent == null) {\n                        onFileDelete(file);\n                        return;\n                    }\n                    MappingConfig config = YamlUtils\n                        .ymlToObj(null, configContent, MappingConfig.class, null, envProperties);\n                    if (config == null) {\n                        return;\n                    }\n                    config.validate();\n                    rdbAdapter.updateConfig(file.getName(), config);\n                    logger.info(\"Change a rdb mapping config: {} of canal adapter\", file.getName());\n                }\n            } catch (Exception e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n\n        @Override\n        public void onFileDelete(File file) {\n            super.onFileDelete(file);\n\n            try {\n                if (rdbAdapter.getRdbMapping().containsKey(file.getName())) {\n                    rdbAdapter.deleteConfig(file.getName());\n\n                    logger.info(\"Delete a rdb mapping config: {} of canal adapter\", file.getName());\n                }\n            } catch (Exception e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/rdb/src/main/java/com/alibaba/otter/canal/client/adapter/rdb/service/RdbEtlService.java",
    "content": "package com.alibaba.otter.canal.client.adapter.rdb.service;\n\nimport java.sql.*;\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport javax.sql.DataSource;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.alibaba.otter.canal.client.adapter.rdb.config.MappingConfig;\nimport com.alibaba.otter.canal.client.adapter.rdb.config.MappingConfig.DbMapping;\nimport com.alibaba.otter.canal.client.adapter.rdb.support.SyncUtil;\nimport com.alibaba.otter.canal.client.adapter.support.*;\n\n/**\n * RDB ETL 操作业务类\n *\n * @author rewerma @ 2018-11-7\n * @version 1.0.0\n */\npublic class RdbEtlService extends AbstractEtlService {\n\n    private DataSource    targetDS;\n    private MappingConfig config;\n\n    public RdbEtlService(DataSource targetDS, MappingConfig config){\n        super(\"RDB\", config);\n        this.targetDS = targetDS;\n        this.config = config;\n    }\n\n    /**\n     * 导入数据\n     */\n    public EtlResult importData(List<String> params) {\n        DbMapping dbMapping = config.getDbMapping();\n        // 获取源数据源，根据数据库类型拼装数据库名和表名\n        DruidDataSource dataSource = DatasourceConfig.DATA_SOURCES.get(config.getDataSourceKey());\n        String sql = \"SELECT * FROM \" + SyncUtil.getSourceDbTableName(dbMapping, dataSource.getDbType());\n        return importData(sql, params);\n    }\n\n    /**\n     * 执行导入\n     */\n    protected boolean executeSqlImport(DataSource srcDS, String sql, List<Object> values,\n                                       AdapterConfig.AdapterMapping mapping, AtomicLong impCount, List<String> errMsg) {\n        try {\n            DbMapping dbMapping = (DbMapping) mapping;\n            Map<String, String> columnsMap = new LinkedHashMap<>();\n            Map<String, Integer> columnType = new LinkedHashMap<>();\n            DruidDataSource dataSource = (DruidDataSource) srcDS;\n            String backtick = SyncUtil.getBacktickByDbType(dataSource.getDbType());\n\n            Util.sqlRS(targetDS,\n                \"SELECT * FROM \" + SyncUtil.getDbTableName(dbMapping, dataSource.getDbType()) + \" LIMIT 1 \",\n                rs -> {\n                try {\n\n                    ResultSetMetaData rsd = rs.getMetaData();\n                    int columnCount = rsd.getColumnCount();\n                    List<String> columns = new ArrayList<>();\n                    for (int i = 1; i <= columnCount; i++) {\n                        columnType.put(rsd.getColumnName(i).toLowerCase(), rsd.getColumnType(i));\n                        columns.add(rsd.getColumnName(i));\n                    }\n\n                    columnsMap.putAll(SyncUtil.getColumnsMap(dbMapping, columns));\n                    return true;\n                } catch (Exception e) {\n                    logger.error(e.getMessage(), e);\n                    return false;\n                }\n            });\n\n            Util.sqlRS(srcDS, sql, values, rs -> {\n                int idx = 1;\n\n                try {\n                    boolean completed = false;\n\n                    StringBuilder insertSql = new StringBuilder();\n                    insertSql.append(\"INSERT INTO \")\n                        .append(SyncUtil.getDbTableName(dbMapping, dataSource.getDbType()))\n                        .append(\" (\");\n                    columnsMap\n                        .forEach((targetColumnName, srcColumnName) -> insertSql.append(backtick).append(targetColumnName).append(backtick).append(\",\"));\n\n                    int len = insertSql.length();\n                    insertSql.delete(len - 1, len).append(\") VALUES (\");\n                    int mapLen = columnsMap.size();\n                    for (int i = 0; i < mapLen; i++) {\n                        insertSql.append(\"?,\");\n                    }\n                    len = insertSql.length();\n                    insertSql.delete(len - 1, len).append(\")\");\n                    logger.info(\"executeSqlImport sql:{}\",insertSql.toString());\n                    try (Connection connTarget = targetDS.getConnection();\n                            PreparedStatement pstmt = connTarget.prepareStatement(insertSql.toString())) {\n                        connTarget.setAutoCommit(false);\n\n                        while (rs.next()) {\n                            completed = false;\n\n                            pstmt.clearParameters();\n\n                            // 删除数据\n                            Map<String, Object> pkVal = new LinkedHashMap<>();\n                            StringBuilder deleteSql = new StringBuilder(\n                                \"DELETE FROM \" + SyncUtil.getDbTableName(dbMapping, dataSource.getDbType()) + \" WHERE \");\n                            appendCondition(dbMapping, deleteSql, pkVal, rs, backtick);\n                            try (PreparedStatement pstmt2 = connTarget.prepareStatement(deleteSql.toString())) {\n                                int k = 1;\n                                for (Object val : pkVal.values()) {\n                                    pstmt2.setObject(k++, val);\n                                }\n                                pstmt2.execute();\n                            }\n\n                            int i = 1;\n                            for (Map.Entry<String, String> entry : columnsMap.entrySet()) {\n                                String targetColumnName = entry.getKey();\n                                String srcColumnName = entry.getValue();\n                                if (srcColumnName == null) {\n                                    srcColumnName = targetColumnName;\n                                }\n\n                                Integer type = columnType.get(targetColumnName.toLowerCase());\n                                Object value = rs.getObject(srcColumnName);\n                                if (value != null) {\n                                    SyncUtil.setPStmt(type, pstmt, value, i);\n                                } else {\n                                    pstmt.setNull(i, type);\n                                }\n\n                                i++;\n                            }\n\n                            pstmt.execute();\n                            if (logger.isTraceEnabled()) {\n                                logger.trace(\"Insert into target table, sql: {}\", insertSql);\n                            }\n\n                            if (idx % dbMapping.getCommitBatch() == 0) {\n                                connTarget.commit();\n                                completed = true;\n                            }\n                            idx++;\n                            impCount.incrementAndGet();\n                            if (logger.isDebugEnabled()) {\n                                logger.debug(\"successful import count:\" + impCount.get());\n                            }\n                        }\n                        if (!completed) {\n                            connTarget.commit();\n                        }\n                    }\n\n                } catch (Exception e) {\n                    logger.error(dbMapping.getTable() + \" etl failed! ==>\" + e.getMessage(), e);\n                    errMsg.add(dbMapping.getTable() + \" etl failed! ==>\" + e.getMessage());\n                }\n                return idx;\n            });\n            return true;\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n            return false;\n        }\n    }\n\n    /**\n     * 拼接目标表主键where条件\n     */\n    private static void appendCondition(DbMapping dbMapping, StringBuilder sql, Map<String, Object> values,\n                                        ResultSet rs, String backtick) throws SQLException {\n        // 拼接主键\n        for (Map.Entry<String, String> entry : dbMapping.getTargetPk().entrySet()) {\n            String targetColumnName = entry.getKey();\n            String srcColumnName = entry.getValue();\n            if (srcColumnName == null) {\n                srcColumnName = targetColumnName;\n            }\n            sql.append(backtick).append(targetColumnName).append(backtick).append(\"=? AND \");\n            values.put(targetColumnName, rs.getObject(srcColumnName));\n        }\n        int len = sql.length();\n        sql.delete(len - 4, len);\n    }\n}\n"
  },
  {
    "path": "client-adapter/rdb/src/main/java/com/alibaba/otter/canal/client/adapter/rdb/service/RdbMirrorDbSyncService.java",
    "content": "package com.alibaba.otter.canal.client.adapter.rdb.service;\n\nimport java.sql.Connection;\nimport java.sql.Statement;\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.JSONWriter.Feature;\nimport com.alibaba.otter.canal.client.adapter.rdb.config.MappingConfig;\nimport com.alibaba.otter.canal.client.adapter.rdb.config.MirrorDbConfig;\nimport com.alibaba.otter.canal.client.adapter.rdb.support.SingleDml;\nimport com.alibaba.otter.canal.client.adapter.rdb.support.SyncUtil;\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\n\n/**\n * RDB镜像库同步操作业务\n *\n * @author rewerma 2018-12-12 下午011:23\n * @version 1.0.0\n */\npublic class RdbMirrorDbSyncService {\n\n    private static final Logger         logger = LoggerFactory.getLogger(RdbMirrorDbSyncService.class);\n\n    private Map<String, MirrorDbConfig> mirrorDbConfigCache;                                           // 镜像库配置\n    private DruidDataSource             dataSource;\n    private RdbSyncService              rdbSyncService;                                                // rdbSyncService代理\n\n    public RdbMirrorDbSyncService(Map<String, MirrorDbConfig> mirrorDbConfigCache, DruidDataSource dataSource,\n                                  Integer threads, Map<String, Map<String, Integer>> columnsTypeCache,\n                                  boolean skipDupException){\n        this.mirrorDbConfigCache = mirrorDbConfigCache;\n        this.dataSource = dataSource;\n        this.rdbSyncService = new RdbSyncService(dataSource, threads, columnsTypeCache, skipDupException);\n    }\n\n    /**\n     * 批量同步方法\n     *\n     * @param dmls 批量 DML，包含DDL\n     */\n    public void sync(List<Dml> dmls) {\n        List<Dml> dmlList = new ArrayList<>();\n        for (Dml dml : dmls) {\n            String destination = StringUtils.trimToEmpty(dml.getDestination());\n            String database = dml.getDatabase();\n            MirrorDbConfig mirrorDbConfig = mirrorDbConfigCache.get(destination + \".\" + database);\n            if (mirrorDbConfig == null) {\n                continue;\n            }\n            if (mirrorDbConfig.getMappingConfig() == null) {\n                continue;\n            }\n            if (dml.getGroupId() != null && StringUtils.isNotEmpty(mirrorDbConfig.getMappingConfig().getGroupId())) {\n                if (!mirrorDbConfig.getMappingConfig().getGroupId().equals(dml.getGroupId())) {\n                    continue; // 如果groupId不匹配则过滤\n                }\n            }\n\n            if (dml.getIsDdl() != null && dml.getIsDdl() && StringUtils.isNotEmpty(dml.getSql())) {\n                // 确保执行DDL前DML已执行完\n                syncDml(dmlList);\n                dmlList.clear();\n\n                // DDL\n                if (logger.isDebugEnabled()) {\n                    logger.debug(\"DDL: {}\", JSON.toJSONString(dml, Feature.WriteNulls));\n                }\n                executeDdl(mirrorDbConfig, dml);\n                rdbSyncService.getColumnsTypeCache().remove(destination + \".\" + database + \".\" + dml.getTable());\n                mirrorDbConfig.getTableConfig().remove(dml.getTable()); // 删除对应库表配置\n            } else {\n                // DML\n                initMappingConfig(dml.getTable(), mirrorDbConfig.getMappingConfig(), mirrorDbConfig, dml);\n                dmlList.add(dml);\n            }\n        }\n        syncDml(dmlList);\n    }\n\n    /**\n     * 批量同步Dml\n     *\n     * @param dmlList Dml列表，不包含DDL\n     */\n    private void syncDml(List<Dml> dmlList) {\n        if (dmlList == null || dmlList.isEmpty()) {\n            return;\n        }\n        rdbSyncService.sync(dmlList, dml -> {\n            MirrorDbConfig mirrorDbConfig = mirrorDbConfigCache.get(dml.getDestination() + \".\" + dml.getDatabase());\n            if (mirrorDbConfig == null) {\n                return false;\n            }\n            String table = dml.getTable();\n            MappingConfig config = mirrorDbConfig.getTableConfig().get(table);\n\n            if (config == null) {\n                return false;\n            }\n            rdbSyncService.appendDmlPartition(config, dml);\n            return true;\n        });\n    }\n\n    /**\n     * 初始化表配置\n     *\n     * @param key 配置key: destination.database.table\n     * @param baseConfigMap db sync config\n     * @param dml DML\n     */\n    private void initMappingConfig(String key, MappingConfig baseConfigMap, MirrorDbConfig mirrorDbConfig, Dml dml) {\n        MappingConfig mappingConfig = mirrorDbConfig.getTableConfig().get(key);\n        if (mappingConfig == null) {\n            // 构造表配置\n            mappingConfig = new MappingConfig();\n            mappingConfig.setDataSourceKey(baseConfigMap.getDataSourceKey());\n            mappingConfig.setDestination(baseConfigMap.getDestination());\n            mappingConfig.setGroupId(baseConfigMap.getGroupId());\n            mappingConfig.setOuterAdapterKey(baseConfigMap.getOuterAdapterKey());\n            mappingConfig.setConcurrent(baseConfigMap.getConcurrent());\n            MappingConfig.DbMapping dbMapping = new MappingConfig.DbMapping();\n            mappingConfig.setDbMapping(dbMapping);\n            dbMapping.setDatabase(dml.getDatabase());\n            dbMapping.setTable(dml.getTable());\n            dbMapping.setTargetDb(dml.getDatabase());\n            dbMapping.setTargetTable(dml.getTable());\n            dbMapping.setMapAll(true);\n            List<String> pkNames = dml.getPkNames();\n            Map<String, String> pkMapping = new LinkedHashMap<>();\n            pkNames.forEach(pkName -> pkMapping.put(pkName, pkName));\n            dbMapping.setTargetPk(pkMapping);\n\n            mirrorDbConfig.getTableConfig().put(key, mappingConfig);\n        }\n    }\n\n    /**\n     * DDL 操作\n     *\n     * @param ddl DDL\n     */\n    private void executeDdl(MirrorDbConfig mirrorDbConfig, Dml ddl) {\n        try (Connection conn = dataSource.getConnection(); Statement statement = conn.createStatement()) {\n            // 替换反引号\n            String sql = ddl.getSql();\n            String backtick = SyncUtil.getBacktickByDbType(dataSource.getDbType());\n            if (!\"`\".equals(backtick)) {\n                sql = sql.replaceAll(\"`\", backtick);\n            }\n            statement.execute(sql);\n            // 移除对应配置\n            mirrorDbConfig.getTableConfig().remove(ddl.getTable());\n            if (logger.isTraceEnabled()) {\n                logger.trace(\"Execute DDL sql: {} for database: {}\", ddl.getSql(), ddl.getDatabase());\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/rdb/src/main/java/com/alibaba/otter/canal/client/adapter/rdb/service/RdbSyncService.java",
    "content": "package com.alibaba.otter.canal.client.adapter.rdb.service;\n\nimport java.sql.Connection;\nimport java.sql.ResultSetMetaData;\nimport java.sql.SQLException;\nimport java.sql.Types;\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.function.Function;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.JSONWriter.Feature;\nimport com.alibaba.otter.canal.client.adapter.rdb.config.MappingConfig;\nimport com.alibaba.otter.canal.client.adapter.rdb.config.MappingConfig.DbMapping;\nimport com.alibaba.otter.canal.client.adapter.rdb.support.BatchExecutor;\nimport com.alibaba.otter.canal.client.adapter.rdb.support.SingleDml;\nimport com.alibaba.otter.canal.client.adapter.rdb.support.SyncUtil;\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\nimport com.alibaba.otter.canal.client.adapter.support.Util;\n\n/**\n * RDB同步操作业务\n *\n * @author rewerma 2018-11-7 下午06:45:49\n * @version 1.0.0\n */\npublic class RdbSyncService {\n\n    private static final Logger               logger  = LoggerFactory.getLogger(RdbSyncService.class);\n\n    private DruidDataSource                   dataSource;\n    // 源库表字段类型缓存: instance.schema.table -> <columnName, jdbcType>\n    private Map<String, Map<String, Integer>> columnsTypeCache;\n\n    private int                               threads = 3;\n    private boolean                           skipDupException;\n\n    private List<SyncItem>[]                  dmlsPartition;\n    private BatchExecutor[]                   batchExecutors;\n    private ExecutorService[]                 executorThreads;\n\n    public List<SyncItem>[] getDmlsPartition() {\n        return dmlsPartition;\n    }\n\n    public Map<String, Map<String, Integer>> getColumnsTypeCache() {\n        return columnsTypeCache;\n    }\n\n    public RdbSyncService(DruidDataSource dataSource, Integer threads, boolean skipDupException){\n        this(dataSource, threads, new ConcurrentHashMap<>(), skipDupException);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public RdbSyncService(DruidDataSource dataSource, Integer threads, Map<String, Map<String, Integer>> columnsTypeCache,\n                          boolean skipDupException){\n        this.dataSource = dataSource;\n        this.columnsTypeCache = columnsTypeCache;\n        this.skipDupException = skipDupException;\n        try {\n            if (threads != null) {\n                this.threads = threads;\n            }\n            this.dmlsPartition = new List[this.threads];\n            this.batchExecutors = new BatchExecutor[this.threads];\n            this.executorThreads = new ExecutorService[this.threads];\n            for (int i = 0; i < this.threads; i++) {\n                dmlsPartition[i] = new ArrayList<>();\n                batchExecutors[i] = new BatchExecutor(dataSource);\n                executorThreads[i] = Executors.newSingleThreadExecutor();\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * 批量同步回调\n     *\n     * @param dmls 批量 DML\n     * @param function 回调方法\n     */\n    public void sync(List<Dml> dmls, Function<Dml, Boolean> function) {\n        try {\n            boolean toExecute = false;\n            for (Dml dml : dmls) {\n                if (!toExecute) {\n                    toExecute = function.apply(dml);\n                } else {\n                    function.apply(dml);\n                }\n            }\n            if (toExecute) {\n                List<Future<Boolean>> futures = new ArrayList<>();\n                for (int i = 0; i < threads; i++) {\n                    int j = i;\n                    if (dmlsPartition[j].isEmpty()) {\n                        // bypass\n                        continue;\n                    }\n\n                    futures.add(executorThreads[i].submit(() -> {\n                        try {\n                            dmlsPartition[j].forEach(syncItem -> sync(batchExecutors[j],\n                                syncItem.config,\n                                syncItem.singleDml));\n                            dmlsPartition[j].clear();\n                            batchExecutors[j].commit();\n                            return true;\n                        } catch (Throwable e) {\n                            dmlsPartition[j].clear();\n                            batchExecutors[j].rollback();\n                            throw new RuntimeException(e);\n                        }\n                    }));\n                }\n\n                futures.forEach(future -> {\n                    try {\n                        future.get();\n                    } catch (ExecutionException | InterruptedException e) {\n                        throw new RuntimeException(e);\n                    }\n                });\n            }\n        } finally {\n            for (BatchExecutor batchExecutor : batchExecutors) {\n                if (batchExecutor != null) {\n                    batchExecutor.close();\n                }\n            }\n        }\n    }\n\n    /**\n     * 批量同步\n     *\n     * @param mappingConfig 配置集合\n     * @param dmls 批量 DML\n     */\n    public void sync(Map<String, Map<String, MappingConfig>> mappingConfig, List<Dml> dmls, Properties envProperties) {\n        sync(dmls, dml -> {\n            if (dml.getIsDdl() != null && dml.getIsDdl() && StringUtils.isNotEmpty(dml.getSql())) {\n                // DDL\n            columnsTypeCache.remove(dml.getDestination() + \".\" + dml.getDatabase() + \".\" + dml.getTable());\n            return false;\n        } else {\n            // DML\n            String destination = StringUtils.trimToEmpty(dml.getDestination());\n            String groupId = StringUtils.trimToEmpty(dml.getGroupId());\n            String database = dml.getDatabase();\n            String table = dml.getTable();\n            Map<String, MappingConfig> configMap;\n            if (envProperties != null && !\"tcp\".equalsIgnoreCase(envProperties.getProperty(\"canal.conf.mode\"))) {\n                configMap = mappingConfig.get(destination + \"-\" + groupId + \"_\" + database + \"-\" + table);\n            } else {\n                configMap = mappingConfig.get(destination + \"_\" + database + \"-\" + table);\n            }\n\n            if (configMap == null) {\n                return false;\n            }\n\n            if (configMap.values().isEmpty()) {\n                return false;\n            }\n\n            for (MappingConfig config : configMap.values()) {\n                appendDmlPartition(config, dml);\n            }\n            return true;\n        }\n    }   );\n    }\n\n    /**\n     * 将Dml加入 {@link #dmlsPartition}\n     *\n     * @param config 表映射配置\n     * @param dml    Dml对象\n     */\n    public void appendDmlPartition(MappingConfig config, Dml dml) {\n        boolean caseInsensitive = config.getDbMapping().isCaseInsensitive();\n        if (config.getConcurrent()) {\n            List<SingleDml> singleDmls = SingleDml.dml2SingleDmls(dml, caseInsensitive);\n            singleDmls.forEach(singleDml -> {\n                int hash = pkHash(config.getDbMapping(), singleDml.getData());\n                SyncItem syncItem = new SyncItem(config, singleDml);\n                dmlsPartition[hash].add(syncItem);\n            });\n        } else {\n            int hash = 0;\n            List<SingleDml> singleDmls = SingleDml.dml2SingleDmls(dml, caseInsensitive);\n            singleDmls.forEach(singleDml -> {\n                SyncItem syncItem = new SyncItem(config, singleDml);\n                dmlsPartition[hash].add(syncItem);\n            });\n        }\n    }\n\n    /**\n     * 单条 dml 同步\n     *\n     * @param batchExecutor 批量事务执行器\n     * @param config 对应配置对象\n     * @param dml DML\n     */\n    public void sync(BatchExecutor batchExecutor, MappingConfig config, SingleDml dml) {\n        if (config != null) {\n            try {\n                String type = dml.getType();\n                if (type != null && type.equalsIgnoreCase(\"INSERT\")) {\n                    insert(batchExecutor, config, dml);\n                } else if (type != null && type.equalsIgnoreCase(\"UPDATE\")) {\n                    update(batchExecutor, config, dml);\n                } else if (type != null && type.equalsIgnoreCase(\"DELETE\")) {\n                    delete(batchExecutor, config, dml);\n                } else if (type != null && type.equalsIgnoreCase(\"TRUNCATE\")) {\n                    truncate(batchExecutor, config);\n                }\n                if (logger.isDebugEnabled()) {\n                    logger.debug(\"DML: {}\", JSON.toJSONString(dml, Feature.WriteNulls));\n                }\n            } catch (SQLException e) {\n                throw new RuntimeException(e);\n            }\n        }\n    }\n\n    /**\n     * 插入操作\n     *\n     * @param config 配置项\n     * @param dml DML数据\n     */\n    private void insert(BatchExecutor batchExecutor, MappingConfig config, SingleDml dml) throws SQLException {\n        Map<String, Object> data = dml.getData();\n        if (data == null || data.isEmpty()) {\n            return;\n        }\n\n        DbMapping dbMapping = config.getDbMapping();\n        String backtick = SyncUtil.getBacktickByDbType(dataSource.getDbType());\n        Map<String, String> columnsMap = SyncUtil.getColumnsMap(dbMapping, data);\n\n        StringBuilder insertSql = new StringBuilder();\n        insertSql.append(\"INSERT INTO \").append(SyncUtil.getDbTableName(dbMapping, dataSource.getDbType())).append(\" (\");\n\n        columnsMap.forEach((targetColumnName, srcColumnName) -> insertSql.append(backtick)\n            .append(targetColumnName)\n            .append(backtick)\n            .append(\",\"));\n        int len = insertSql.length();\n        insertSql.delete(len - 1, len).append(\") VALUES (\");\n        int mapLen = columnsMap.size();\n        for (int i = 0; i < mapLen; i++) {\n            insertSql.append(\"?,\");\n        }\n        len = insertSql.length();\n        insertSql.delete(len - 1, len).append(\")\");\n\n        Map<String, Integer> ctype = getTargetColumnType(batchExecutor.getConn(), config);\n\n        List<Map<String, ?>> values = new ArrayList<>();\n        for (Map.Entry<String, String> entry : columnsMap.entrySet()) {\n            String targetColumnName = entry.getKey();\n            String srcColumnName = entry.getValue();\n            if (srcColumnName == null) {\n                srcColumnName = Util.cleanColumn(targetColumnName);\n            }\n\n            Integer type = ctype.get(Util.cleanColumn(targetColumnName).toLowerCase());\n            if (type == null) {\n                throw new RuntimeException(\"Target column: \" + targetColumnName + \" not matched\");\n            }\n            Object value = data.get(srcColumnName);\n            BatchExecutor.setValue(values, type, value);\n        }\n\n        try {\n            batchExecutor.execute(insertSql.toString(), values);\n        } catch (SQLException e) {\n            if (skipDupException\n                && (e.getMessage().contains(\"Duplicate entry\") || e.getMessage().contains(\"duplicate key\") || e.getMessage().startsWith(\"ORA-00001:\"))) {\n                // ignore\n                // TODO 增加更多关系数据库的主键冲突的错误码\n            } else {\n                throw e;\n            }\n        }\n        if (logger.isTraceEnabled()) {\n            logger.trace(\"Insert into target table, sql: {}\", insertSql);\n        }\n\n    }\n\n    /**\n     * 更新操作\n     *\n     * @param config 配置项\n     * @param dml DML数据\n     */\n    private void update(BatchExecutor batchExecutor, MappingConfig config, SingleDml dml) throws SQLException {\n        Map<String, Object> data = dml.getData();\n        if (data == null || data.isEmpty()) {\n            return;\n        }\n\n        Map<String, Object> old = dml.getOld();\n        if (old == null || old.isEmpty()) {\n            return;\n        }\n\n        DbMapping dbMapping = config.getDbMapping();\n        String backtick = SyncUtil.getBacktickByDbType(dataSource.getDbType());\n        Map<String, String> columnsMap = SyncUtil.getColumnsMap(dbMapping, data);\n\n        Map<String, Integer> ctype = getTargetColumnType(batchExecutor.getConn(), config);\n\n        StringBuilder updateSql = new StringBuilder();\n        updateSql.append(\"UPDATE \").append(SyncUtil.getDbTableName(dbMapping, dataSource.getDbType())).append(\" SET \");\n        List<Map<String, ?>> values = new ArrayList<>();\n        boolean hasMatched = false;\n        for (String srcColumnName : old.keySet()) {\n            List<String> targetColumnNames = new ArrayList<>();\n            columnsMap.forEach((targetColumn, srcColumn) -> {\n                if (srcColumnName.equalsIgnoreCase(srcColumn)) {\n                    targetColumnNames.add(targetColumn);\n                }\n            });\n            if (!targetColumnNames.isEmpty()) {\n                hasMatched = true;\n                for (String targetColumnName : targetColumnNames) {\n                    updateSql.append(backtick).append(targetColumnName).append(backtick).append(\"=?, \");\n                    Integer type = ctype.get(Util.cleanColumn(targetColumnName).toLowerCase());\n                    if (type == null) {\n                        throw new RuntimeException(\"Target column: \" + targetColumnName + \" not matched\");\n                    }\n                    BatchExecutor.setValue(values, type, data.get(srcColumnName));\n                }\n            }\n        }\n        if (!hasMatched) {\n            logger.warn(\"Did not matched any columns to update \");\n            return;\n        }\n        int len = updateSql.length();\n        updateSql.delete(len - 2, len).append(\" WHERE \");\n\n        // 拼接主键\n        appendCondition(dbMapping, updateSql, ctype, values, data, old);\n        batchExecutor.execute(updateSql.toString(), values);\n        if (logger.isTraceEnabled()) {\n            logger.trace(\"Update target table, sql: {}\", updateSql);\n        }\n    }\n\n    /**\n     * 删除操作\n     *\n     * @param config\n     * @param dml\n     */\n    private void delete(BatchExecutor batchExecutor, MappingConfig config, SingleDml dml) throws SQLException {\n        Map<String, Object> data = dml.getData();\n        if (data == null || data.isEmpty()) {\n            return;\n        }\n\n        DbMapping dbMapping = config.getDbMapping();\n        Map<String, Integer> ctype = getTargetColumnType(batchExecutor.getConn(), config);\n\n        StringBuilder sql = new StringBuilder();\n        sql.append(\"DELETE FROM \").append(SyncUtil.getDbTableName(dbMapping, dataSource.getDbType())).append(\" WHERE \");\n\n        List<Map<String, ?>> values = new ArrayList<>();\n        // 拼接主键\n        appendCondition(dbMapping, sql, ctype, values, data);\n        batchExecutor.execute(sql.toString(), values);\n        if (logger.isTraceEnabled()) {\n            logger.trace(\"Delete from target table, sql: {}\", sql);\n        }\n    }\n\n    /**\n     * truncate操作\n     *\n     * @param config\n     */\n    private void truncate(BatchExecutor batchExecutor, MappingConfig config) throws SQLException {\n        DbMapping dbMapping = config.getDbMapping();\n        StringBuilder sql = new StringBuilder();\n        sql.append(\"TRUNCATE TABLE \").append(SyncUtil.getDbTableName(dbMapping, dataSource.getDbType()));\n        batchExecutor.execute(sql.toString(), new ArrayList<>());\n        if (logger.isTraceEnabled()) {\n            logger.trace(\"Truncate target table, sql: {}\", sql);\n        }\n    }\n\n    /**\n     * 获取目标字段类型\n     *\n     * @param conn sql connection\n     * @param config 映射配置\n     * @return 字段sqlType\n     */\n    private Map<String, Integer> getTargetColumnType(Connection conn, MappingConfig config) {\n        DbMapping dbMapping = config.getDbMapping();\n        String cacheKey = config.getDestination() + \".\" + dbMapping.getDatabase() + \".\" + dbMapping.getTable();\n        Map<String, Integer> columnType = columnsTypeCache.get(cacheKey);\n        if (columnType == null) {\n            synchronized (RdbSyncService.class) {\n                columnType = columnsTypeCache.get(cacheKey);\n                if (columnType == null) {\n                    columnType = new LinkedHashMap<>();\n                    final Map<String, Integer> columnTypeTmp = columnType;\n                    String sql = \"SELECT * FROM \" + SyncUtil.getDbTableName(dbMapping, dataSource.getDbType()) + \" WHERE 1=2\";\n                    Util.sqlRS(conn, sql, rs -> {\n                        try {\n                            ResultSetMetaData rsd = rs.getMetaData();\n                            int columnCount = rsd.getColumnCount();\n                            for (int i = 1; i <= columnCount; i++) {\n                                int colType = rsd.getColumnType(i);\n                                // 修复year类型作为date处理时的data truncated问题\n                                if (\"YEAR\".equals(rsd.getColumnTypeName(i))) {\n                                    colType = Types.VARCHAR;\n                                }\n                                columnTypeTmp.put(rsd.getColumnName(i).toLowerCase(), colType);\n                            }\n                            columnsTypeCache.put(cacheKey, columnTypeTmp);\n                        } catch (SQLException e) {\n                            logger.error(e.getMessage(), e);\n                        }\n                    });\n                }\n            }\n        }\n        return columnType;\n    }\n\n    /**\n     * 拼接主键 where条件\n     */\n    private void appendCondition(MappingConfig.DbMapping dbMapping, StringBuilder sql, Map<String, Integer> ctype,\n                                 List<Map<String, ?>> values, Map<String, Object> d) {\n        appendCondition(dbMapping, sql, ctype, values, d, null);\n    }\n\n    private void appendCondition(MappingConfig.DbMapping dbMapping, StringBuilder sql, Map<String, Integer> ctype,\n                                 List<Map<String, ?>> values, Map<String, Object> d, Map<String, Object> o) {\n        String backtick = SyncUtil.getBacktickByDbType(dataSource.getDbType());\n\n        // 拼接主键\n        for (Map.Entry<String, String> entry : dbMapping.getTargetPk().entrySet()) {\n            String targetColumnName = entry.getKey();\n            String srcColumnName = entry.getValue();\n            if (srcColumnName == null) {\n                srcColumnName = Util.cleanColumn(targetColumnName);\n            }\n            sql.append(backtick).append(targetColumnName).append(backtick).append(\"=? AND \");\n            Integer type = ctype.get(Util.cleanColumn(targetColumnName).toLowerCase());\n            if (type == null) {\n                throw new RuntimeException(\"Target column: \" + targetColumnName + \" not matched\");\n            }\n            // 如果有修改主键的情况\n            if (o != null && o.containsKey(srcColumnName)) {\n                BatchExecutor.setValue(values, type, o.get(srcColumnName));\n            } else {\n                BatchExecutor.setValue(values, type, d.get(srcColumnName));\n            }\n        }\n        int len = sql.length();\n        sql.delete(len - 4, len);\n    }\n\n    public static class SyncItem {\n\n        private MappingConfig config;\n        private SingleDml     singleDml;\n\n        public SyncItem(MappingConfig config, SingleDml singleDml){\n            this.config = config;\n            this.singleDml = singleDml;\n        }\n    }\n\n    /**\n     * 取主键hash\n     */\n    public int pkHash(DbMapping dbMapping, Map<String, Object> d) {\n        return pkHash(dbMapping, d, null);\n    }\n\n    public int pkHash(DbMapping dbMapping, Map<String, Object> d, Map<String, Object> o) {\n        int hash = 0;\n        // 取主键\n        for (Map.Entry<String, String> entry : dbMapping.getTargetPk().entrySet()) {\n            String targetColumnName = entry.getKey();\n            String srcColumnName = entry.getValue();\n            if (srcColumnName == null) {\n                srcColumnName = Util.cleanColumn(targetColumnName);\n            }\n            Object value = null;\n            if (o != null && o.containsKey(srcColumnName)) {\n                value = o.get(srcColumnName);\n            } else if (d != null) {\n                value = d.get(srcColumnName);\n            }\n            if (value != null) {\n                hash += value.hashCode();\n            }\n        }\n        hash = Math.abs(hash) % threads;\n        return Math.abs(hash);\n    }\n\n    public void close() {\n        for (int i = 0; i < threads; i++) {\n            executorThreads[i].shutdown();\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/rdb/src/main/java/com/alibaba/otter/canal/client/adapter/rdb/support/BatchExecutor.java",
    "content": "package com.alibaba.otter.canal.client.adapter.rdb.support;\n\nimport java.io.Closeable;\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.SQLException;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport javax.sql.DataSource;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * sql批量执行器\n *\n * @author rewerma 2018-11-7 下午06:45:49\n * @version 1.0.0\n */\npublic class BatchExecutor implements Closeable {\n\n    private static final Logger logger = LoggerFactory.getLogger(BatchExecutor.class);\n\n    private DataSource          dataSource;\n    private Connection          conn;\n    private AtomicInteger       idx    = new AtomicInteger(0);\n\n    public BatchExecutor(DataSource dataSource){\n        this.dataSource = dataSource;\n    }\n\n    public Connection getConn() {\n        if (conn == null) {\n            try {\n                conn = dataSource.getConnection();\n                this.conn.setAutoCommit(false);\n            } catch (SQLException e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n        return conn;\n    }\n\n    public static void setValue(List<Map<String, ?>> values, int type, Object value) {\n        Map<String, Object> valueItem = new HashMap<>();\n        valueItem.put(\"type\", type);\n        valueItem.put(\"value\", value);\n        values.add(valueItem);\n    }\n\n    public void execute(String sql, List<Map<String, ?>> values) throws SQLException {\n        PreparedStatement pstmt = getConn().prepareStatement(sql);\n        int len = values.size();\n        for (int i = 0; i < len; i++) {\n            int type = (Integer) values.get(i).get(\"type\");\n            Object value = values.get(i).get(\"value\");\n            SyncUtil.setPStmt(type, pstmt, value, i + 1);\n        }\n\n        pstmt.execute();\n        idx.incrementAndGet();\n        pstmt.close();\n    }\n\n    public void commit() throws SQLException {\n        getConn().commit();\n        if (logger.isTraceEnabled()) {\n            logger.trace(\"Batch executor commit \" + idx.get() + \" rows\");\n        }\n        idx.set(0);\n    }\n\n    public void rollback() throws SQLException {\n        getConn().rollback();\n        if (logger.isTraceEnabled()) {\n            logger.trace(\"Batch executor rollback \" + idx.get() + \" rows\");\n        }\n        idx.set(0);\n    }\n\n    @Override\n    public void close() {\n        if (conn != null) {\n            try {\n                conn.close();\n            } catch (SQLException e) {\n                logger.error(e.getMessage(), e);\n            } finally {\n                conn = null;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/rdb/src/main/java/com/alibaba/otter/canal/client/adapter/rdb/support/SingleDml.java",
    "content": "package com.alibaba.otter.canal.client.adapter.rdb.support;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.springframework.util.LinkedCaseInsensitiveMap;\n\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\n\npublic class SingleDml {\n\n    private String              destination;\n    private String              database;\n    private String              table;\n    private String              type;\n    private Map<String, Object> data;\n    private Map<String, Object> old;\n\n    public String getDestination() {\n        return destination;\n    }\n\n    public void setDestination(String destination) {\n        this.destination = destination;\n    }\n\n    public String getDatabase() {\n        return database;\n    }\n\n    public void setDatabase(String database) {\n        this.database = database;\n    }\n\n    public String getTable() {\n        return table;\n    }\n\n    public void setTable(String table) {\n        this.table = table;\n    }\n\n    public String getType() {\n        return type;\n    }\n\n    public void setType(String type) {\n        this.type = type;\n    }\n\n    public Map<String, Object> getData() {\n        return data;\n    }\n\n    public void setData(Map<String, Object> data) {\n        this.data = data;\n    }\n\n    public Map<String, Object> getOld() {\n        return old;\n    }\n\n    public void setOld(Map<String, Object> old) {\n        this.old = old;\n    }\n\n    public static List<SingleDml> dml2SingleDmls(Dml dml, boolean caseInsensitive) {\n        List<SingleDml> singleDmls = new ArrayList<>();\n        if (dml.getData() != null) {\n            int size = dml.getData().size();\n            for (int i = 0; i < size; i++) {\n                SingleDml singleDml = new SingleDml();\n                singleDml.setDestination(dml.getDestination());\n                singleDml.setDatabase(dml.getDatabase());\n                singleDml.setTable(dml.getTable());\n                singleDml.setType(dml.getType());\n                Map<String, Object> data = dml.getData().get(i);\n                if (caseInsensitive) {\n                    data = toCaseInsensitiveMap(data);\n                }\n                singleDml.setData(data);\n                if (dml.getOld() != null) {\n                    Map<String, Object> oldData = dml.getOld().get(i);\n                    if (caseInsensitive) {\n                        oldData = toCaseInsensitiveMap(oldData);\n                    }\n                    singleDml.setOld(oldData);\n                }\n                singleDmls.add(singleDml);\n            }\n        } else if (\"TRUNCATE\".equalsIgnoreCase(dml.getType())) {\n            SingleDml singleDml = new SingleDml();\n            singleDml.setDestination(dml.getDestination());\n            singleDml.setDatabase(dml.getDatabase());\n            singleDml.setTable(dml.getTable());\n            singleDml.setType(dml.getType());\n            singleDmls.add(singleDml);\n        }\n        return singleDmls;\n    }\n\n    public static List<SingleDml> dml2SingleDmls(Dml dml) {\n        return dml2SingleDmls(dml, false);\n    }\n\n    private static <V> LinkedCaseInsensitiveMap<V> toCaseInsensitiveMap(Map<String, V> data) {\n        LinkedCaseInsensitiveMap map = new LinkedCaseInsensitiveMap();\n        map.putAll(data);\n        return map;\n    }\n}\n"
  },
  {
    "path": "client-adapter/rdb/src/main/java/com/alibaba/otter/canal/client/adapter/rdb/support/SyncUtil.java",
    "content": "package com.alibaba.otter.canal.client.adapter.rdb.support;\n\nimport java.io.Reader;\nimport java.io.StringReader;\nimport java.math.BigDecimal;\nimport java.nio.charset.StandardCharsets;\nimport java.sql.*;\nimport java.time.LocalDateTime;\nimport java.util.Collection;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.druid.DbType;\nimport com.alibaba.otter.canal.client.adapter.rdb.config.MappingConfig;\nimport com.alibaba.otter.canal.client.adapter.support.Util;\n\npublic class SyncUtil {\n    private static final Logger logger  = LoggerFactory.getLogger(SyncUtil.class);\n\n    public static Map<String, String> getColumnsMap(MappingConfig.DbMapping dbMapping, Map<String, Object> data) {\n        return getColumnsMap(dbMapping, data.keySet());\n    }\n\n    public static Map<String, String> getColumnsMap(MappingConfig.DbMapping dbMapping, Collection<String> columns) {\n        Map<String, String> columnsMap;\n        if (dbMapping.getMapAll()) {\n            if (dbMapping.getAllMapColumns() != null) {\n                return dbMapping.getAllMapColumns();\n            }\n            columnsMap = new LinkedHashMap<>();\n            for (String srcColumn : columns) {\n                boolean flag = true;\n                if (dbMapping.getTargetColumns() != null) {\n                    for (Map.Entry<String, String> entry : dbMapping.getTargetColumns().entrySet()) {\n                        if (srcColumn.equals(entry.getValue())) {\n                            columnsMap.put(entry.getKey(), srcColumn);\n                            flag = false;\n                            break;\n                        }\n                    }\n                }\n                if (flag) {\n                    columnsMap.put(srcColumn, srcColumn);\n                }\n            }\n            dbMapping.setAllMapColumns(columnsMap);\n        } else {\n            columnsMap = dbMapping.getTargetColumns();\n        }\n        return columnsMap;\n    }\n\n    /**\n     * 设置 preparedStatement\n     *\n     * @param type sqlType\n     * @param pstmt 需要设置的preparedStatement\n     * @param value 值\n     * @param i 索引号\n     */\n    public static void setPStmt(int type, PreparedStatement pstmt, Object value, int i) throws SQLException {\n        switch (type) {\n            case Types.BIT:\n            case Types.BOOLEAN:\n                if (value instanceof Boolean) {\n                    pstmt.setBoolean(i, (Boolean) value);\n                } else if (value instanceof String) {\n                    boolean v = !value.equals(\"0\");\n                    pstmt.setBoolean(i, v);\n                } else if (value instanceof Number) {\n                    boolean v = ((Number) value).intValue() != 0;\n                    pstmt.setBoolean(i, v);\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.CHAR:\n            case Types.NCHAR:\n            case Types.VARCHAR:\n            case Types.LONGVARCHAR:\n                if (value instanceof String) {\n                    pstmt.setString(i, (String) value);\n                } else if (value == null) {\n                    pstmt.setNull(i, type);\n                } else {\n                    pstmt.setString(i, value.toString());\n                }\n                break;\n            case Types.TINYINT:\n                // 向上提升一级，处理unsigned情况\n                if (value instanceof Number) {\n                    pstmt.setShort(i, ((Number) value).shortValue());\n                } else if (value instanceof String) {\n                    pstmt.setShort(i, Short.parseShort((String) value));\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.SMALLINT:\n                if (value instanceof Number) {\n                    pstmt.setInt(i, ((Number) value).intValue());\n                } else if (value instanceof String) {\n                    pstmt.setInt(i, Integer.parseInt((String) value));\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.INTEGER:\n                if (value instanceof Number) {\n                    pstmt.setLong(i, ((Number) value).longValue());\n                } else if (value instanceof String) {\n                    pstmt.setLong(i, Long.parseLong((String) value));\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.BIGINT:\n                if (value instanceof Number) {\n                    pstmt.setBigDecimal(i, new BigDecimal(value.toString()));\n                } else if (value instanceof String) {\n                    pstmt.setBigDecimal(i, new BigDecimal(value.toString()));\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.DECIMAL:\n            case Types.NUMERIC:\n                if (value instanceof BigDecimal) {\n                    pstmt.setBigDecimal(i, (BigDecimal) value);\n                } else if (value instanceof Byte) {\n                    pstmt.setInt(i, ((Byte) value).intValue());\n                } else if (value instanceof Short) {\n                    pstmt.setInt(i, ((Short) value).intValue());\n                } else if (value instanceof Integer) {\n                    pstmt.setInt(i, (Integer) value);\n                } else if (value instanceof Long) {\n                    pstmt.setLong(i, (Long) value);\n                } else if (value instanceof Float) {\n                    pstmt.setBigDecimal(i, new BigDecimal((float) value));\n                } else if (value instanceof Double) {\n                    pstmt.setBigDecimal(i, new BigDecimal((double) value));\n                } else if (value != null) {\n                    pstmt.setBigDecimal(i, new BigDecimal(value.toString()));\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.REAL:\n                if (value instanceof Number) {\n                    pstmt.setFloat(i, ((Number) value).floatValue());\n                } else if (value instanceof String) {\n                    pstmt.setFloat(i, Float.parseFloat((String) value));\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.FLOAT:\n            case Types.DOUBLE:\n                if (value instanceof Number) {\n                    pstmt.setDouble(i, ((Number) value).doubleValue());\n                } else if (value instanceof String) {\n                    pstmt.setDouble(i, Double.parseDouble((String) value));\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.BINARY:\n            case Types.VARBINARY:\n            case Types.LONGVARBINARY:\n            case Types.BLOB:\n                if (value instanceof Blob) {\n                    pstmt.setBlob(i, (Blob) value);\n                } else if (value instanceof byte[]) {\n                    pstmt.setBytes(i, (byte[]) value);\n                } else if (value instanceof String) {\n                    pstmt.setBytes(i, ((String) value).getBytes(StandardCharsets.ISO_8859_1));\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.CLOB:\n                if (value instanceof Clob) {\n                    pstmt.setClob(i, (Clob) value);\n                } else if (value instanceof byte[]) {\n                    pstmt.setBytes(i, (byte[]) value);\n                } else if (value instanceof String) {\n                    Reader clobReader = new StringReader((String) value);\n                    pstmt.setCharacterStream(i, clobReader);\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.DATE:\n                if (value instanceof java.sql.Date) {\n                    pstmt.setDate(i, (java.sql.Date) value);\n                } else if (value instanceof java.util.Date) {\n                    pstmt.setDate(i, new java.sql.Date(((java.util.Date) value).getTime()));\n                } else if (value instanceof String) {\n                    String v = (String) value;\n                    if (!v.startsWith(\"0000-00-00\")) {\n                        java.util.Date date = Util.parseDate(v);\n                        if (date != null) {\n                            pstmt.setDate(i, new Date(date.getTime()));\n                        } else {\n                            pstmt.setNull(i, type);\n                        }\n                    } else {\n                        pstmt.setObject(i, value);\n                    }\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.TIME:\n                if (value instanceof java.sql.Time) {\n                    pstmt.setTime(i, (java.sql.Time) value);\n                } else if (value instanceof java.util.Date) {\n                    pstmt.setTime(i, new java.sql.Time(((java.util.Date) value).getTime()));\n                } else if (value instanceof String) {\n                    String v = (String) value;\n                    if(Util.isAccuracyOverSecond(v)) {\n                        //the java.sql.time doesn't support for even millisecond, only setObject works here.\n                        pstmt.setObject(i, v);\n                    }else {\n                        java.util.Date date = Util.parseDate(v);\n                        if (date != null) {\n                            pstmt.setTime(i, new Time(date.getTime()));\n                        } else {\n                            pstmt.setNull(i, type);\n                        }\n                    }\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            case Types.TIMESTAMP:\n                if (value instanceof java.sql.Timestamp) {\n                    pstmt.setTimestamp(i, (java.sql.Timestamp) value);\n                } else if (value instanceof java.util.Date) {\n                    pstmt.setTimestamp(i, new java.sql.Timestamp(((java.util.Date) value).getTime()));\n                } else if (value instanceof String) {\n                    String v = (String) value;\n                    if (!v.startsWith(\"0000-00-00\")) {\n                        if(Util.isAccuracyOverMillisecond(v)){\n                            //convert to ISO-8601 standard format, with up to nanoseconds (9 digits) precision\n                            LocalDateTime isoDatetime = Util.parseISOLocalDateTime(v);\n                            if (isoDatetime != null) {\n                                pstmt.setTimestamp(i, Timestamp.valueOf(isoDatetime));\n                            } else {\n                                //if can't convert, set to null\n                                pstmt.setNull(i, type);\n                            }\n                        }else {\n                            java.util.Date date = Util.parseDate(v);\n                            if (date != null) {\n                                pstmt.setTimestamp(i, new Timestamp(date.getTime()));\n                            } else {\n                                pstmt.setNull(i, type);\n                            }\n                        }\n                    } else {\n                        pstmt.setObject(i, value);\n                    }\n                } else {\n                    pstmt.setNull(i, type);\n                }\n                break;\n            default:\n                pstmt.setObject(i, value, type);\n        }\n    }\n\n    public static String getDbTableName(MappingConfig.DbMapping dbMapping, String dbType) {\n        String result = \"\";\n        String backtick = getBacktickByDbType(dbType);\n        if (StringUtils.isNotEmpty(dbMapping.getTargetDb())) {\n            result += (backtick + dbMapping.getTargetDb() + backtick + \".\");\n        }\n        result += (backtick + dbMapping.getTargetTable() + backtick);\n        return result;\n    }\n\n    public static String getSourceDbTableName(MappingConfig.DbMapping dbMapping, String dbType) {\n        String result = \"\";\n        String backtick = getBacktickByDbType(dbType);\n        if (StringUtils.isNotEmpty(dbMapping.getDatabase())) {\n            result += (backtick + dbMapping.getDatabase() + backtick + \".\");\n        }\n\n        result += (backtick + dbMapping.getTable() + backtick);\n        return result;\n    }\n\n    /**\n     * 根据DbType返回反引号或空字符串\n     *\n     * @param dbTypeName DbType名称\n     * @return 反引号或空字符串\n     */\n    public static String getBacktickByDbType(String dbTypeName) {\n        DbType dbType = DbType.of(dbTypeName);\n        if (dbType == null) {\n            dbType = DbType.other;\n        }\n\n        // 只有当dbType为MySQL/MariaDB或OceanBase时返回反引号\n        switch (dbType) {\n            case mysql:\n            case mariadb:\n            case oceanbase:\n                return \"`\";\n        //  当dbType 为 postgresql时，返回双引号(避免表名为postgresql的关键字时，sql查询报错)\n            case postgresql:\n                return \"\\\"\";\n            default:\n                return \"\";\n        }\n    }\n}\n"
  },
  {
    "path": "client-adapter/rdb/src/main/resources/META-INF/canal/com.alibaba.otter.canal.client.adapter.OuterAdapter",
    "content": "rdb=com.alibaba.otter.canal.client.adapter.rdb.RdbAdapter"
  },
  {
    "path": "client-adapter/rdb/src/main/resources/rdb/mytest_user.yml",
    "content": "dataSourceKey: defaultDS\ndestination: example\ngroupId: g1\nouterAdapterKey: mysql1\nconcurrent: true\ndbMapping:\n  database: mytest\n  table: user\n  targetTable: mytest2.user\n  targetPk:\n    id: id\n#  mapAll: true\n  targetColumns:\n    id:\n    name:\n    role_id:\n    c_time:\n    test1:\n  etlCondition: \"where c_time>={}\"\n  commitBatch: 3000 # 批量提交的大小\n\n\n## Mirror schema synchronize config\n#dataSourceKey: defaultDS\n#destination: example\n#groupId: g1\n#outerAdapterKey: mysql1\n#concurrent: true\n#dbMapping:\n#  mirrorDb: true\n#  database: mytest\n"
  },
  {
    "path": "client-adapter/rdb/src/test/java/com/alibaba/otter/canal/client/adapter/rdb/test/ConfigLoadTest.java",
    "content": "package com.alibaba.otter.canal.client.adapter.rdb.test;\n\nimport java.util.Map;\n\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.client.adapter.rdb.config.ConfigLoader;\nimport com.alibaba.otter.canal.client.adapter.rdb.config.MappingConfig;\nimport com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;\n\npublic class ConfigLoadTest {\n\n    @Before\n    public void before() {\n        // 加载数据源连接池\n        DatasourceConfig.DATA_SOURCES.put(\"defaultDS\", TestConstant.dataSource);\n    }\n\n    @Test\n    public void testLoad() {\n        Map<String, MappingConfig> configMap =  ConfigLoader.load(null);\n\n        Assert.assertFalse(configMap.isEmpty());\n    }\n}\n"
  },
  {
    "path": "client-adapter/rdb/src/test/java/com/alibaba/otter/canal/client/adapter/rdb/test/DBTest.java",
    "content": "package com.alibaba.otter.canal.client.adapter.rdb.test;\n\nimport java.io.BufferedReader;\nimport java.io.Reader;\nimport java.sql.Clob;\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.SQLException;\n\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.druid.pool.DruidDataSource;\n\n@Ignore\npublic class DBTest {\n\n    @Test\n    public void test01() throws SQLException {\n        DruidDataSource dataSource = new DruidDataSource();\n        // dataSource.setDriverClassName(\"oracle.jdbc.OracleDriver\");\n        // dataSource.setUrl(\"jdbc:oracle:thin:@127.0.0.1:49161:XE\");\n        // dataSource.setUsername(\"mytest\");\n        // dataSource.setPassword(\"m121212\");\n\n        dataSource.setDriverClassName(\"com.mysql.jdbc.Driver\");\n        dataSource.setUrl(\"jdbc:mysql://127.0.0.1:3306/mytest?useUnicode=true\");\n        dataSource.setUsername(\"root\");\n        dataSource.setPassword(\"121212\");\n\n        dataSource.setInitialSize(1);\n        dataSource.setMinIdle(1);\n        dataSource.setMaxActive(2);\n        dataSource.setMaxWait(60000);\n        dataSource.setTimeBetweenEvictionRunsMillis(60000);\n        dataSource.setMinEvictableIdleTimeMillis(300000);\n\n        dataSource.init();\n\n        Connection conn = dataSource.getConnection();\n\n        conn.setAutoCommit(false);\n        PreparedStatement pstmt = conn.prepareStatement(\"insert into user (id,name,role_id,c_time,test1,test2) values (?,?,?,?,?,?)\");\n\n        java.util.Date now = new java.util.Date();\n        for (int i = 1; i <= 10000; i++) {\n            pstmt.clearParameters();\n            pstmt.setLong(1, (long) i);\n            pstmt.setString(2, \"test_\" + i);\n            pstmt.setLong(3, (long) i % 4 + 1);\n            pstmt.setDate(4, new java.sql.Date(now.getTime()));\n            pstmt.setString(5, null);\n            pstmt.setBytes(6, null);\n\n            pstmt.execute();\n            if (i % 5000 == 0) {\n                conn.commit();\n            }\n        }\n        conn.commit();\n\n        pstmt.close();\n\n        // Statement stmt = conn.createStatement();\n        // ResultSet rs = stmt.executeQuery(\"select * from user t where 1=2\");\n        //\n        // ResultSetMetaData rsm = rs.getMetaData();\n        // int cnt = rsm.getColumnCount();\n        // for (int i = 1; i <= cnt; i++) {\n        // System.out.println(rsm.getColumnName(i) + \" \" +\n        // rsm.getColumnType(i));\n        // }\n\n        // rs.close();\n        // stmt.close();\n\n        // PreparedStatement pstmt = conn\n        // .prepareStatement(\"insert into tb_user\n        // (id,name,role_id,c_time,test1,test2)\n        // values (?,?,?,?,?,?)\");\n        // pstmt.setBigDecimal(1, new BigDecimal(\"5\"));\n        // pstmt.setString(2, \"test\");\n        // pstmt.setBigDecimal(3, new BigDecimal(\"1\"));\n        // pstmt.setDate(4, new Date(new java.util.Date().getTime()));\n        // byte[] a = { (byte) 1, (byte) 2 };\n        // pstmt.setBytes(5, a);\n        // pstmt.setBytes(6, a);\n        // pstmt.execute();\n        //\n        // pstmt.close();\n\n        conn.close();\n        dataSource.close();\n    }\n\n    @SuppressWarnings(\"unused\")\n    private String clob2Str(Clob clob) {\n        String content = \"\";\n        try (Reader is = clob.getCharacterStream(); BufferedReader buff = new BufferedReader(is)) {\n            String line = buff.readLine();\n            StringBuilder sb = new StringBuilder();\n            while (line != null) {\n                sb.append(line);\n                line = buff.readLine();\n            }\n            content = sb.toString();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return content;\n    }\n}\n"
  },
  {
    "path": "client-adapter/rdb/src/test/java/com/alibaba/otter/canal/client/adapter/rdb/test/SqlParserTest.java",
    "content": "//wpackage com.alibaba.otter.canal.client.adapter.rdb.test;\n//\n//import com.alibaba.druid.sql.ast.SQLName;\n//import com.alibaba.druid.sql.ast.SQLStatement;\n//import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement;\n//import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;\n//import com.alibaba.druid.sql.dialect.mysql.parser.MySqlCreateTableParser;\n//import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;\n//import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor;\n//import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor;\n//import com.alibaba.druid.sql.parser.SQLStatementParser;\n//\n//import java.io.StringWriter;\n//\n//public class SqlParserTest {\n//\n//    public static class TableNameVisitor extends MySqlOutputVisitor {\n//\n//        public TableNameVisitor(Appendable appender){\n//            super(appender);\n//        }\n//\n//        @Override\n//        public boolean visit(SQLExprTableSource x) {\n//            SQLName table = (SQLName) x.getExpr();\n//            String tableName = table.getSimpleName();\n//\n//            // 改写tableName\n//            print0(\"new_\" + tableName.toUpperCase());\n//\n//            return true;\n//        }\n//\n//    }\n//\n//    public static void main(String[] args) {\n//        // String sql = \"select * from `mytest`.`t` where id=1 and name=ming group by\n//        // uid limit 1,200 order by ctime\";\n//\n//        String sql = \"CREATE TABLE `mytest`.`user` (\\n\" + \"  `id` bigint(20) NOT NULL AUTO_INCREMENT,\\n\"\n//                     + \"  `name` varchar(30) NOT NULL,\\n\" + \"  `c_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,\\n\"\n//                     + \"  `role_id` bigint(20) DEFAULT NULL,\\n\" + \"  `test1` text,\\n\" + \"  `test2` blob,\\n\"\n//                     + \"  `key` varchar(30) DEFAULT NULL,\\n\" + \"  PRIMARY KEY (`id`)\\n\"\n//                     + \") ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;\";\n//\n//        // // 新建 MySQL Parser\n//        // SQLStatementParser parser = new MySqlStatementParser(sql);\n//        //\n//        // // 使用Parser解析生成AST，这里SQLStatement就是AST\n//        // SQLStatement sqlStatement = parser.parseStatement();\n//        //\n//        // MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor();\n//        // sqlStatement.accept(visitor);\n//        //\n//        // System.out.println(\"getTables:\" + visitor.getTables());\n//        // System.out.println(\"getParameters:\" + visitor.getParameters());\n//        // System.out.println(\"getOrderByColumns:\" + visitor.getOrderByColumns());\n//        // System.out.println(\"getGroupByColumns:\" + visitor.getGroupByColumns());\n//        // System.out.println(\"---------------------------------------------------------------------------\");\n//        //\n//        // // 使用select访问者进行select的关键信息打印\n//        // // SelectPrintVisitor selectPrintVisitor = new SelectPrintVisitor();\n//        // // sqlStatement.accept(selectPrintVisitor);\n//        //\n//        // System.out.println(\"---------------------------------------------------------------------------\");\n//        // // 最终sql输出\n//        // StringWriter out = new StringWriter();\n//        // TableNameVisitor outputVisitor = new TableNameVisitor(out);\n//        // sqlStatement.accept(outputVisitor);\n//        // System.out.println(out.toString());\n//\n//        MySqlCreateTableParser parser1 = new MySqlCreateTableParser(sql);\n//        SQLCreateTableStatement createTableStatement = parser1.parseCreateTable();\n////        MySqlSchemaStatVisitor visitor1 = new MySqlSchemaStatVisitor();\n////        createTableStatement.accept(visitor1);\n//        // visitor1.getTables().forEach((k, v) -> {\n//        // System.out.println(k.);\n//        // System.out.println(v);\n//        // });\n//        // 最终sql输出\n//        StringWriter out = new StringWriter();\n//        TableNameVisitor outputVisitor = new TableNameVisitor(out);\n//        createTableStatement.accept(outputVisitor);\n//        System.out.println(out.toString());\n//    }\n//}\n"
  },
  {
    "path": "client-adapter/rdb/src/test/java/com/alibaba/otter/canal/client/adapter/rdb/test/TestConstant.java",
    "content": "package com.alibaba.otter.canal.client.adapter.rdb.test;\n\nimport java.sql.SQLException;\n\nimport com.alibaba.druid.pool.DruidDataSource;\n\npublic class TestConstant {\n\n    public final static String    jdbcUrl      = \"jdbc:mysql://127.0.0.1:3306/mytest?useUnicode=true\";\n    public final static String    jdbcUser     = \"root\";\n    public final static String    jdbcPassword = \"121212\";\n\n    public final static DruidDataSource dataSource;\n\n    static {\n        dataSource = new DruidDataSource();\n        dataSource.setDriverClassName(\"com.mysql.jdbc.Driver\");\n        dataSource.setUrl(jdbcUrl);\n        dataSource.setUsername(jdbcUser);\n        dataSource.setPassword(jdbcPassword);\n        dataSource.setInitialSize(1);\n        dataSource.setMinIdle(1);\n        dataSource.setMaxActive(1);\n        dataSource.setMaxWait(60000);\n        dataSource.setTimeBetweenEvictionRunsMillis(60000);\n        dataSource.setMinEvictableIdleTimeMillis(300000);\n        dataSource.setPoolPreparedStatements(false);\n        dataSource.setMaxPoolPreparedStatementPerConnectionSize(20);\n        dataSource.setValidationQuery(\"select 1\");\n        try {\n            dataSource.init();\n        } catch (SQLException e) {\n            e.printStackTrace();\n        }\n    }\n\n}\n"
  },
  {
    "path": "client-adapter/rdb/src/test/java/com/alibaba/otter/canal/client/adapter/rdb/test/sync/Common.java",
    "content": "package com.alibaba.otter.canal.client.adapter.rdb.test.sync;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport com.alibaba.otter.canal.client.adapter.rdb.RdbAdapter;\nimport com.alibaba.otter.canal.client.adapter.rdb.test.TestConstant;\nimport com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;\nimport com.alibaba.otter.canal.client.adapter.support.OuterAdapterConfig;\n\npublic class Common {\n\n    public static RdbAdapter init() {\n        DatasourceConfig.DATA_SOURCES.put(\"defaultDS\", TestConstant.dataSource);\n\n        OuterAdapterConfig outerAdapterConfig = new OuterAdapterConfig();\n        outerAdapterConfig.setName(\"rdb\");\n        outerAdapterConfig.setKey(\"oracle1\");\n        Map<String, String> properties = new HashMap<>();\n        properties.put(\"jdbc.driveClassName\", \"oracle.jdbc.OracleDriver\");\n        properties.put(\"jdbc.url\", \"jdbc:oracle:thin:@127.0.0.1:49161:XE\");\n        properties.put(\"jdbc.username\", \"mytest\");\n        properties.put(\"jdbc.password\", \"m121212\");\n        outerAdapterConfig.setProperties(properties);\n\n        RdbAdapter adapter = new RdbAdapter();\n        adapter.init(outerAdapterConfig, null);\n        return adapter;\n    }\n}\n"
  },
  {
    "path": "client-adapter/rdb/src/test/java/com/alibaba/otter/canal/client/adapter/rdb/test/sync/OracleSyncTest.java",
    "content": "package com.alibaba.otter.canal.client.adapter.rdb.test.sync;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.client.adapter.rdb.RdbAdapter;\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\n@Ignore\npublic class OracleSyncTest {\n\n    private RdbAdapter rdbAdapter;\n\n    @Before\n    public void init() {\n        rdbAdapter = Common.init();\n    }\n\n    @Test\n    public void test01() {\n        Dml dml = new Dml();\n        dml.setDestination(\"example\");\n        dml.setTs(new Date().getTime());\n        dml.setType(\"INSERT\");\n        dml.setDatabase(\"mytest\");\n        dml.setTable(\"user\");\n        List<Map<String, Object>> dataList = new ArrayList<>();\n        Map<String, Object> data = new LinkedHashMap<>();\n        dataList.add(data);\n        data.put(\"id\", 1L);\n        data.put(\"name\", \"Eric\");\n        data.put(\"role_id\", 1L);\n        data.put(\"c_time\", new Date());\n        data.put(\"test1\", \"sdfasdfawe中国asfwef\");\n        dml.setData(dataList);\n\n        rdbAdapter.sync(Collections.singletonList(dml));\n    }\n\n    @Test\n    public void test02() {\n        Dml dml = new Dml();\n        dml.setDestination(\"example\");\n        dml.setTs(new Date().getTime());\n        dml.setType(\"UPDATE\");\n        dml.setDatabase(\"mytest\");\n        dml.setTable(\"user\");\n        List<Map<String, Object>> dataList = new ArrayList<>();\n        Map<String, Object> data = new LinkedHashMap<>();\n        dataList.add(data);\n        data.put(\"id\", 1L);\n        data.put(\"name\", \"Eric2\");\n        dml.setData(dataList);\n        List<Map<String, Object>> oldList = new ArrayList<>();\n        Map<String, Object> old = new LinkedHashMap<>();\n        oldList.add(old);\n        old.put(\"name\", \"Eric\");\n        dml.setOld(oldList);\n\n        rdbAdapter.sync(Collections.singletonList(dml));\n    }\n\n}\n"
  },
  {
    "path": "client-adapter/rdb/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"ERROR\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>"
  },
  {
    "path": "client-adapter/rdb/src/test/resources/logback-test.xml",
    "content": "<configuration scan=\"true\" scanPeriod=\" 5 seconds\">\n\t<jmxConfigurator />\n\t<appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n\t\t<encoder>\n\t\t\t<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{56} - %msg%n\n\t\t\t</pattern>\n\t\t</encoder>\n\t</appender>\n\n\t<root level=\"TRACE\">\n\t\t<appender-ref ref=\"STDOUT\"/>\n\t</root>\n</configuration>"
  },
  {
    "path": "client-adapter/rdb/src/test/resources/rdb/mytest_user.yml",
    "content": "dataSourceKey: defaultDS\ndestination: example\nouterAdapterKey: oracle1\nconcurrent: true\ndbMapping:\n  database: mytest\n  table: user\n  targetTable: mytest.tb_user\n  targetPk:\n    id: id\n  mapAll: true\n#  targetColumns:\n#    id:\n#    name:\n#    role_id:\n#    c_time:\n#    test1:"
  },
  {
    "path": "client-adapter/tablestore/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>canal.client-adapter</artifactId>\n        <groupId>com.alibaba.otter</groupId>\n        <version>1.1.9-SNAPSHOT</version>\n        <relativePath>../pom.xml</relativePath>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>com.alibaba.otter</groupId>\n    <artifactId>client-adapter.tablestore</artifactId>\n    <packaging>jar</packaging>\n    <name>canal client adapter rdb module for otter ${project.version}</name>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>client-adapter.common</artifactId>\n            <version>${project.version}</version>\n            <scope>provided</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.12</version>\n            <scope>test</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>com.aliyun.openservices</groupId>\n            <artifactId>tablestore</artifactId>\n            <classifier>jar-with-dependencies</classifier>\n            <exclusions>\n                <exclusion>\n                    <groupId>com.google.protobuf</groupId>\n                    <artifactId>protobuf-java</artifactId>\n                </exclusion>\n                <exclusion>\n                    <groupId>org.apache.httpcomponents</groupId>\n                    <artifactId>httpasyncclient</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-assembly-plugin</artifactId>\n                <version>2.4</version>\n                <configuration>\n                    <descriptorRefs>\n                        <descriptorRef>jar-with-dependencies</descriptorRef>\n                    </descriptorRefs>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>make-assembly</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>single</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-antrun-plugin</artifactId>\n                <version>1.8</version>\n                <executions>\n                    <execution>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>run</goal>\n                        </goals>\n                        <configuration>\n                            <tasks>\n                                <copy todir=\"${project.basedir}/../launcher/target/classes/tablestore\" overwrite=\"true\">\n                                    <fileset dir=\"${project.basedir}/target/classes/tablestore\" erroronmissingdir=\"true\">\n                                        <include name=\"*.yml\" />\n                                    </fileset>\n                                </copy>\n                            </tasks>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "client-adapter/tablestore/src/main/java/com/alibaba/otter/canal/client/adapter/tablestore/TablestoreAdapter.java",
    "content": "package com.alibaba.otter.canal.client.adapter.tablestore;\n\n\nimport com.alibaba.otter.canal.client.adapter.support.FileName2KeyMapping;\nimport com.alibaba.otter.canal.client.adapter.support.Util;\nimport java.util.*;\nimport java.util.concurrent.*;\nimport java.util.stream.Collectors;\n\nimport com.alibaba.otter.canal.client.adapter.OuterAdapter;\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\nimport com.alibaba.otter.canal.client.adapter.support.EtlResult;\nimport com.alibaba.otter.canal.client.adapter.support.OuterAdapterConfig;\nimport com.alibaba.otter.canal.client.adapter.support.SPI;\nimport com.alibaba.otter.canal.client.adapter.tablestore.common.PropertyConstants;\nimport com.alibaba.otter.canal.client.adapter.tablestore.config.ConfigLoader;\nimport com.alibaba.otter.canal.client.adapter.tablestore.config.MappingConfig;\nimport com.alibaba.otter.canal.client.adapter.tablestore.service.TablestoreEtlService;\nimport com.alibaba.otter.canal.client.adapter.tablestore.service.TablestoreSyncService;\nimport com.alicloud.openservices.tablestore.DefaultTableStoreWriter;\nimport com.alicloud.openservices.tablestore.TableStoreWriter;\nimport com.alicloud.openservices.tablestore.core.auth.DefaultCredentials;\nimport com.alicloud.openservices.tablestore.core.auth.ServiceCredentials;\nimport com.alicloud.openservices.tablestore.writer.WriterConfig;\nimport com.alicloud.openservices.tablestore.writer.WriterResult;\nimport com.alicloud.openservices.tablestore.writer.enums.BatchRequestType;\nimport com.alicloud.openservices.tablestore.writer.enums.DispatchMode;\nimport com.alicloud.openservices.tablestore.writer.enums.WriteMode;\nimport com.alicloud.openservices.tablestore.writer.enums.WriterRetryStrategy;\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.util.CollectionUtils;\n\n\n@SPI(\"tablestore\")\npublic class TablestoreAdapter implements OuterAdapter {\n\n    private static final Logger logger              = LoggerFactory.getLogger(TablestoreAdapter.class);\n\n    private Map<String, MappingConfig>              tablestoreMapping          = new ConcurrentHashMap<>();                // 文件名对应配置\n\n    private Map<String, Map<String, MappingConfig>> mappingConfigCache  = new ConcurrentHashMap<>();\n\n    private Map<String, Map<String, TableStoreWriter>> writerCache  = new ConcurrentHashMap<>();\n\n    private TablestoreSyncService tablestoreSyncService;\n\n    private Properties                              envProperties;\n\n    private OuterAdapterConfig configuration;\n\n\n    @Override\n    public void init(OuterAdapterConfig configuration, Properties envProperties) {\n        this.envProperties = envProperties;\n        this.configuration = configuration;\n        Map<String, MappingConfig> tablestoreMappingTmp = ConfigLoader.load(envProperties);\n        // 过滤不匹配的key的配置\n        tablestoreMappingTmp.forEach((key, config) -> {\n            addConfig(key, config);\n        });\n\n        if (tablestoreMapping.isEmpty()) {\n            throw new RuntimeException(\"No tablestore adapter found for config key: \" + configuration.getKey());\n        }\n\n        tablestoreSyncService = new TablestoreSyncService();\n    }\n\n    /**\n     * 根据配置文件获得tablestorewriter的WriterConfig信息\n     * @param mappingConfig\n     * @return\n     */\n    private WriterConfig getWriterConfig(MappingConfig mappingConfig) {\n        WriterConfig config = new WriterConfig();\n        MappingConfig.DbMapping mapping = mappingConfig.getDbMapping();\n        config.setMaxBatchRowsCount(mapping.getCommitBatch());\n        config.setConcurrency(mappingConfig.getThreads());\n        config.setDispatchMode(DispatchMode.HASH_PRIMARY_KEY);\n        config.setWriteMode(WriteMode.SEQUENTIAL);\n        config.setBatchRequestType(BatchRequestType.BULK_IMPORT);\n        config.setBucketCount(mappingConfig.getThreads());\n        config.setWriterRetryStrategy(WriterRetryStrategy.CERTAIN_ERROR_CODE_NOT_RETRY);\n        config.setAllowDuplicatedRowInBatchRequest(false);\n        return config;\n    }\n\n\n    @Override\n    public void sync(List<Dml> dmls) {\n        if (dmls == null || dmls.isEmpty()) {\n            return;\n        }\n\n        try {\n            Set<TableStoreWriter> writerSet = new HashSet<>();\n            List<Future<WriterResult>> futureList = new ArrayList<>();\n            for (Dml dml : dmls) {\n                String destination = StringUtils.trimToEmpty(dml.getDestination());\n                String groupId = StringUtils.trimToEmpty(dml.getGroupId());\n                String database = dml.getDatabase();\n                String table = dml.getTable();\n                String key;\n                if (envProperties != null && !\"tcp\".equalsIgnoreCase(envProperties.getProperty(\"canal.conf.mode\"))) {\n                    key = destination + \"-\" + groupId + \"_\" + database + \"-\" + table;\n                } else {\n                    key = destination + \"_\" + database + \"-\" + table;\n                }\n                Map<String, MappingConfig> configMap = mappingConfigCache.get(key);\n                if (configMap == null) {\n                    // 可能有dml中涉及到的表并没有出现在配置中，说明此类dml并不需要同步\n                    continue;\n                }\n\n                Map<String, TableStoreWriter> writerMap = writerCache.get(key);\n\n                for (Map.Entry<String, MappingConfig> entry : configMap.entrySet()) {\n                    TableStoreWriter w = writerMap.get(entry.getKey());\n                    // 拿到所有future用于判定失败的记录\n                    Future<WriterResult> futureTemp = tablestoreSyncService.sync(entry.getValue(), dml, w);\n                    if (futureTemp != null) {\n                        writerSet.add(w);\n                        futureList.add(futureTemp);\n                    }\n                }\n            }\n\n            if (writerSet.isEmpty()) {\n                return;\n            }\n\n            writerSet.forEach(e -> e.flush());\n\n            List<WriterResult.RowChangeStatus> totalFailedRows = new ArrayList<>();\n            for (Future<WriterResult> future : futureList) {\n                try {\n                    WriterResult result = future.get();\n                    List<WriterResult.RowChangeStatus> failedRows = result.getFailedRows();\n                    if (!CollectionUtils.isEmpty(failedRows)) {\n                        totalFailedRows.addAll(failedRows);\n                    }\n                } catch (InterruptedException e) {\n                    logger.info(\"InterruptedException\", e);\n                    Thread.currentThread().interrupt();\n                } catch (ExecutionException e) {\n                    throw new RuntimeException(e);\n                }\n            }\n\n            if (!CollectionUtils.isEmpty(totalFailedRows)) {\n                // 认为有失败的请求\n                List<String> msgs = totalFailedRows.stream().map(e -> buildErrorMsgForFailedRowChange(e)).collect(Collectors.toList());\n                throw new RuntimeException(\"Failed rows:\" + org.springframework.util.StringUtils.collectionToDelimitedString(msgs, \",\", \"[\", \"]\"));\n            }\n\n        } catch (Exception e) {\n            throw e;\n        }\n    }\n\n    /**\n     * 组装失败记录的信息\n     * @param rowChangeStatus\n     * @return\n     */\n    public static String buildErrorMsgForFailedRowChange(WriterResult.RowChangeStatus rowChangeStatus) {\n        StringBuilder sb = new StringBuilder(\"{Exception:\");\n        sb.append(rowChangeStatus.getException().getMessage()).append(\",Table:\")\n        .append(rowChangeStatus.getRowChange().getTableName()).append(\",PrimaryKey:\")\n        .append(\"{\").append(rowChangeStatus.getRowChange().getPrimaryKey().toString())\n        .append(\"}}\");\n        return sb.toString();\n    }\n\n\n    @Override\n    public EtlResult etl(String task, List<String> params) {\n        EtlResult etlResult = new EtlResult();\n        MappingConfig config = tablestoreMapping.get(task);\n        if (config == null) {\n            etlResult.setErrorMessage(\"can not find config for \" + task);\n            etlResult.setSucceeded(false);\n            return etlResult;\n        }\n\n        TableStoreWriter writer = null;\n        try {\n            writer = buildEtlWriter(configuration, config);\n\n            TablestoreEtlService rdbEtlService = new TablestoreEtlService(writer, config);\n            rdbEtlService.importData(params);\n\n            etlResult.setSucceeded(true);\n            return etlResult;\n        } catch (Exception e) {\n            logger.error(\"Error while etl for task \" + task, e);\n            etlResult.setSucceeded(false);\n            etlResult.setErrorMessage(e.getMessage());\n            return etlResult;\n        } finally {\n            if (writer != null) {\n                writer.close();\n            }\n        }\n    }\n\n    /**\n     * 构造批量导入的writer\n     * @param configuration\n     * @param mappingConfig\n     * @return\n     */\n    private TableStoreWriter buildEtlWriter(OuterAdapterConfig configuration, MappingConfig mappingConfig) {\n        Map<String, String> properties = configuration.getProperties();\n\n        ServiceCredentials credentials = new DefaultCredentials(\n                properties.get(PropertyConstants.TABLESTORE_ACCESSSECRETID),\n                properties.get(PropertyConstants.TABLESTORE_ACCESSSECRETKEY)\n        );\n\n        WriterConfig config = getWriterConfig(mappingConfig);\n        config.setBucketCount(3);\n        config.setAllowDuplicatedRowInBatchRequest(true);\n        config.setConcurrency(8);\n        config.setWriteMode(WriteMode.PARALLEL);\n\n        TableStoreWriter writer = new DefaultTableStoreWriter(\n                properties.get(PropertyConstants.TABLESTORE_ENDPOINT),\n                credentials,\n                properties.get(PropertyConstants.TABLESTORE_INSTANCENAME),\n                mappingConfig.getDbMapping().getTargetTable(),\n                config,\n                null\n        );\n        return writer;\n    }\n\n\n    @Override\n    public Map<String, Object> count(String task) {\n        throw new RuntimeException(\"count is not supportted in tablestore\");\n    }\n\n\n    @Override\n    public String getDestination(String task) {\n        MappingConfig config = tablestoreMapping.get(task);\n        if (config != null) {\n            return config.getDestination();\n        }\n        return null;\n    }\n\n    @Override\n    public void destroy() {\n        if (tablestoreSyncService != null) {\n            tablestoreSyncService.close();\n        }\n\n        if (writerCache != null) {\n            for (Map<String, TableStoreWriter> tmpMap : writerCache.values()) {\n                if (tmpMap != null) {\n                    for (TableStoreWriter writer : tmpMap.values()) {\n                        writer.close();\n                    }\n                }\n            }\n        }\n    }\n\n    private void addSyncConfigToCache(String configName, MappingConfig mappingConfig) {\n        Map<String, String> properties = configuration.getProperties();\n        String key;\n        if (envProperties != null && !\"tcp\".equalsIgnoreCase(envProperties.getProperty(\"canal.conf.mode\"))) {\n            key = StringUtils.trimToEmpty(mappingConfig.getDestination()) + \"-\"\n                    + StringUtils.trimToEmpty(mappingConfig.getGroupId()) + \"_\"\n                    + mappingConfig.getDbMapping().getDatabase() + \"-\" + mappingConfig.getDbMapping().getTable();\n        } else {\n            key = StringUtils.trimToEmpty(mappingConfig.getDestination()) + \"_\"\n                    + mappingConfig.getDbMapping().getDatabase() + \"-\" + mappingConfig.getDbMapping().getTable();\n        }\n        Map<String, MappingConfig> configMap = mappingConfigCache.computeIfAbsent(key,\n                k1 -> new ConcurrentHashMap<>());\n        configMap.put(configName, mappingConfig);\n\n\n        // 构建对应的 TableStoreWriter\n        ServiceCredentials credentials = new DefaultCredentials(\n                properties.get(PropertyConstants.TABLESTORE_ACCESSSECRETID),\n                properties.get(PropertyConstants.TABLESTORE_ACCESSSECRETKEY)\n        );\n\n\n        WriterConfig config = getWriterConfig(mappingConfig);\n\n        TableStoreWriter writer = new DefaultTableStoreWriter(\n                properties.get(PropertyConstants.TABLESTORE_ENDPOINT),\n                credentials,\n                properties.get(PropertyConstants.TABLESTORE_INSTANCENAME),\n                mappingConfig.getDbMapping().getTargetTable(),\n                config,\n                null\n        );\n\n        Map<String, TableStoreWriter> config2writerMap = writerCache.computeIfAbsent(key,\n                k1 -> new ConcurrentHashMap<>());\n        config2writerMap.put(configName, writer);\n    }\n\n    public boolean addConfig(String fileName, MappingConfig config) {\n        if (match(config)) {\n            tablestoreMapping.put(fileName, config);\n            addSyncConfigToCache(fileName, config);\n            FileName2KeyMapping.register(getClass().getAnnotation(SPI.class).value(), fileName,\n                    configuration.getKey());\n            return true;\n        }\n        return false;\n    }\n\n    public void updateConfig(String fileName, MappingConfig config) {\n        if (config.getOuterAdapterKey() != null && !config.getOuterAdapterKey()\n                .equals(configuration.getKey())) {\n            // 理论上不允许改这个 因为本身就是通过这个关联起Adapter和Config的\n            throw new RuntimeException(\"not allow to change outAdapterKey\");\n        }\n        tablestoreMapping.put(fileName, config);\n        addSyncConfigToCache(fileName, config);\n    }\n\n    public void deleteConfig(String fileName) {\n        tablestoreMapping.remove(fileName);\n        for (Map<String, MappingConfig> configMap : mappingConfigCache.values()) {\n            if (configMap != null) {\n                configMap.remove(fileName);\n            }\n        }\n        FileName2KeyMapping.unregister(getClass().getAnnotation(SPI.class).value(), fileName);\n    }\n\n    private boolean match(MappingConfig config) {\n        boolean sameMatch = config.getOuterAdapterKey() != null && config.getOuterAdapterKey()\n                .equalsIgnoreCase(configuration.getKey());\n        boolean prefixMatch = config.getOuterAdapterKey() == null && configuration.getKey()\n                .startsWith(StringUtils\n                        .join(new String[]{Util.AUTO_GENERATED_PREFIX, config.getDestination(),\n                                config.getGroupId()}, '-'));\n        return sameMatch || prefixMatch;\n    }\n}\n"
  },
  {
    "path": "client-adapter/tablestore/src/main/java/com/alibaba/otter/canal/client/adapter/tablestore/common/PropertyConstants.java",
    "content": "package com.alibaba.otter.canal.client.adapter.tablestore.common;\n\n\npublic class PropertyConstants {\n\n    public static final String TABLESTORE_ACCESSSECRETID = \"tablestore.accessSecretId\";\n\n    public static final String TABLESTORE_ACCESSSECRETKEY = \"tablestore.accessSecretKey\";\n\n    public static final String TABLESTORE_ENDPOINT = \"tablestore.endpoint\";\n\n    public static final String TABLESTORE_INSTANCENAME = \"tablestore.instanceName\";\n\n}\n"
  },
  {
    "path": "client-adapter/tablestore/src/main/java/com/alibaba/otter/canal/client/adapter/tablestore/config/ConfigLoader.java",
    "content": "package com.alibaba.otter.canal.client.adapter.tablestore.config;\n\nimport com.alibaba.otter.canal.client.adapter.support.MappingConfigsLoader;\nimport com.alibaba.otter.canal.client.adapter.support.YamlUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.util.StringUtils;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Properties;\n\n/**\n * RDB表映射配置加载器\n *\n * @author rewerma 2018-11-07 下午02:41:34\n * @version 1.0.0\n */\npublic class ConfigLoader {\n\n    private static Logger logger = LoggerFactory.getLogger(ConfigLoader.class);\n\n    /**\n     * 加载RDB表映射配置\n     *\n     * @return 配置名/配置文件名--对象\n     */\n    public static Map<String, MappingConfig> load(Properties envProperties) {\n        logger.info(\"## Start loading tablestore mapping config ... \");\n\n        Map<String, MappingConfig> result = new LinkedHashMap<>();\n\n        Map<String, String> configContentMap = MappingConfigsLoader.loadConfigs(\"tablestore\");\n        configContentMap.forEach((fileName, content) -> {\n            MappingConfig config = YamlUtils.ymlToObj(null, content, MappingConfig.class, null, envProperties);\n            if (config == null) {\n                return;\n            }\n            try {\n                config.validate();\n            } catch (Exception e) {\n                throw new RuntimeException(\"ERROR Config: \" + fileName + \" \" + e.getMessage(), e);\n            }\n            result.put(fileName, config);\n        });\n\n        logger.info(\n            \"## Tablestore mapping config loaded:\" + StringUtils.collectionToCommaDelimitedString(result.keySet()));\n        return result;\n    }\n}\n"
  },
  {
    "path": "client-adapter/tablestore/src/main/java/com/alibaba/otter/canal/client/adapter/tablestore/config/MappingConfig.java",
    "content": "package com.alibaba.otter.canal.client.adapter.tablestore.config;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.alibaba.otter.canal.client.adapter.support.AdapterConfig;\nimport com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;\nimport com.alibaba.otter.canal.client.adapter.support.Util;\nimport com.alibaba.otter.canal.client.adapter.tablestore.enums.TablestoreFieldType;\nimport com.alibaba.otter.canal.client.adapter.tablestore.support.SyncUtil;\nimport org.apache.commons.lang.StringUtils;\n\nimport java.sql.ResultSetMetaData;\nimport java.util.*;\n\n/**\n * RDB表映射配置\n *\n * @author rewerma 2018-11-07 下午02:41:34\n * @version 1.0.0\n */\npublic class MappingConfig implements AdapterConfig {\n\n    private String    dataSourceKey;      // 数据源key\n\n    private String    destination;        // canal实例或MQ的topic\n\n    private String    groupId;            // groupId\n\n    private String    outerAdapterKey;    // 对应适配器的key\n\n    private DbMapping dbMapping;          // db映射配置\n\n    private Boolean updateChangeColumns = false;\n\n    private Integer threads = 8;\n\n    public String getDataSourceKey() {\n        return dataSourceKey;\n    }\n\n    public void setDataSourceKey(String dataSourceKey) {\n        this.dataSourceKey = dataSourceKey;\n    }\n\n    public String getGroupId() {\n        return groupId;\n    }\n\n    public void setGroupId(String groupId) {\n        this.groupId = groupId;\n    }\n\n    public String getOuterAdapterKey() {\n        return outerAdapterKey;\n    }\n\n    public void setOuterAdapterKey(String outerAdapterKey) {\n        this.outerAdapterKey = outerAdapterKey;\n    }\n\n    public DbMapping getDbMapping() {\n        return dbMapping;\n    }\n\n    public void setDbMapping(DbMapping dbMapping) {\n        this.dbMapping = dbMapping;\n    }\n\n    public String getDestination() {\n        return destination;\n    }\n\n    public void setDestination(String destination) {\n        this.destination = destination;\n    }\n\n    public AdapterMapping getMapping() {\n        return dbMapping;\n    }\n\n    public Boolean getUpdateChangeColumns() {\n        return updateChangeColumns;\n    }\n\n    public void setUpdateChangeColumns(Boolean updateChangeColumns) {\n        this.updateChangeColumns = updateChangeColumns;\n    }\n\n    public Integer getThreads() {\n        return threads;\n    }\n\n    public void setThreads(Integer threads) {\n        this.threads = threads;\n    }\n\n    public void validate() {\n        if (dbMapping.database == null || dbMapping.database.isEmpty()) {\n            throw new NullPointerException(\"dbMapping.database\");\n        }\n        if (dbMapping.table == null || dbMapping.table.isEmpty()) {\n            throw new NullPointerException(\"dbMapping.table\");\n        }\n        if (dbMapping.targetTable == null || dbMapping.targetTable.isEmpty()) {\n            throw new NullPointerException(\"dbMapping.targetTable\");\n        }\n    }\n\n\n\n\n    public static class ColumnItem {\n        private String targetColumn;\n        private String  column;\n        private TablestoreFieldType type;\n\n        public String getColumn() {\n            return column;\n        }\n\n        public void setColumn(String column) {\n            this.column = column;\n        }\n\n        public TablestoreFieldType getType() {\n            return type;\n        }\n\n        public void setType(TablestoreFieldType type) {\n            this.type = type;\n        }\n\n        public String getTargetColumn() {\n            return targetColumn;\n        }\n\n        public void setTargetColumn(String targetColumn) {\n            this.targetColumn = targetColumn;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (o == null || getClass() != o.getClass()) return false;\n            ColumnItem that = (ColumnItem) o;\n            return Objects.equals(column, that.column);\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(column);\n        }\n    }\n\n\n\n    public static class DbMapping implements AdapterMapping {\n\n        private String              database;                                // 数据库名或schema名\n        private String              table;                                   // 表名\n        private LinkedHashMap<String, String> targetPk        = new LinkedHashMap<>(); // 目标表主键字段\n//        private boolean             mapAll          = false;                 // 映射所有字段\n\n        private String              targetTable;                             // 目标表名\n        private Map<String, String> targetColumns;                           // 目标表字段映射\n        private Map<String, String> targetColumnsParsed;\n        private String              etlCondition;                            // etl条件sql\n\n        private int                 readBatch       = 5000;\n        private int                 commitBatch     = 5000;                  // etl等批量提交大小\n\n        private Map<String, ColumnItem> columnItems        = new LinkedHashMap<>(); // 转换后的字段映射列表\n\n        public String getDatabase() {\n            return database;\n        }\n\n        public void setDatabase(String database) {\n            this.database = database;\n        }\n\n        public String getTable() {\n            return table;\n        }\n\n        public void setTable(String table) {\n            this.table = table;\n        }\n\n\n        public LinkedHashMap<String, String> getTargetPk() {\n            return targetPk;\n        }\n\n        public void setTargetPk(LinkedHashMap<String, String> targetPk) {\n            this.targetPk = targetPk;\n        }\n\n        public String getTargetTable() {\n            return targetTable;\n        }\n\n        public void setTargetTable(String targetTable) {\n            this.targetTable = targetTable;\n        }\n\n        public Map<String, String> getTargetColumns() {\n            return targetColumns;\n        }\n\n\n        public void setTargetColumns(Map<String, String> targetColumns) {\n            this.targetColumns = targetColumns;\n\n        }\n\n        public Map<String, String> getTargetColumnsParsed() {\n            return targetColumnsParsed;\n        }\n\n        public String getEtlCondition() {\n            return etlCondition;\n        }\n\n        public void setEtlCondition(String etlCondition) {\n            this.etlCondition = etlCondition;\n        }\n\n        public int getReadBatch() {\n            return readBatch;\n        }\n\n        public void setReadBatch(int readBatch) {\n            this.readBatch = readBatch;\n        }\n\n        public int getCommitBatch() {\n            return commitBatch;\n        }\n\n        public void setCommitBatch(int commitBatch) {\n            this.commitBatch = commitBatch;\n        }\n\n        public Map<String, ColumnItem> getColumnItems() {\n            return columnItems;\n        }\n\n        public void setColumnItems(Map<String, ColumnItem> columnItems) {\n            this.columnItems = columnItems;\n        }\n\n        public void init(MappingConfig config) {\n            String splitBy = \"$\";\n            if (targetColumns != null) {\n                boolean needTypeInference = false;\n                for (Map.Entry<String, String> columnField : targetColumns.entrySet()) {\n                    String field = columnField.getValue();\n                    String type = null;\n                    if (field != null) {\n                        // 解析类型\n                        int i = field.indexOf(splitBy);\n                        if (i > -1) {\n                            type = field.substring(i + 1);\n                            field = field.substring(0, i);\n                        }\n                    }\n                    ColumnItem columnItem = new ColumnItem();\n                    columnItem.setColumn(columnField.getKey());\n                    columnItem.setTargetColumn(StringUtils.isBlank(field) ? columnField.getKey() : field);\n\n                    TablestoreFieldType fieldType = SyncUtil.getTablestoreType(type);\n                    if (fieldType == null) {\n                        needTypeInference = true;\n                    }\n                    columnItem.setType(fieldType);\n                    columnItems.put(columnField.getKey(), columnItem);\n                }\n                if (needTypeInference) {\n                    // 认为有field没有配置映射类型，需要进行类型推断\n                    DruidDataSource sourceDS = DatasourceConfig.DATA_SOURCES.get(config.getDataSourceKey());\n\n                    Util.sqlRS(sourceDS, \"SELECT * FROM \" + SyncUtil.getDbTableName(database, table) + \" LIMIT 1 \", rs -> {\n                        try {\n                            ResultSetMetaData rsd = rs.getMetaData();\n                            int columnCount = rsd.getColumnCount();\n                            List<String> columns = new ArrayList<>();\n                            for (int i = 1; i <= columnCount; i++) {\n                                String columnName = rsd.getColumnName(i);\n                                if (columnItems.containsKey(columnName) && columnItems.get(columnName).getType() == null) {\n                                    int columnType = rsd.getColumnType(i);\n                                    columnItems.get(columnName).setType(SyncUtil.getDefaultTablestoreType(columnType));\n                                }\n                            }\n                            return true;\n                        } catch (Exception e) {\n                            throw new RuntimeException(e);\n                        }\n                    });\n                }\n\n            } else {\n                this.targetColumns = new LinkedHashMap<>();\n            }\n            targetColumnsParsed = new HashMap<>();\n\n            targetColumns.forEach((key, value) -> {\n                if (StringUtils.isEmpty(value)) {\n                    targetColumnsParsed.put(key, key);\n                } else if (value.contains(splitBy) && columnItems.containsKey(key)) {\n                    targetColumnsParsed.put(key, columnItems.get(key).targetColumn);\n                } else {\n                    targetColumnsParsed.put(key, value);\n                }\n            });\n        }\n\n    }\n}\n"
  },
  {
    "path": "client-adapter/tablestore/src/main/java/com/alibaba/otter/canal/client/adapter/tablestore/enums/TablestoreFieldType.java",
    "content": "package com.alibaba.otter.canal.client.adapter.tablestore.enums;\n\npublic enum TablestoreFieldType {\n    INT,\n    DOUBLE,\n    BOOL,\n    STRING,\n    BINARY\n}\n"
  },
  {
    "path": "client-adapter/tablestore/src/main/java/com/alibaba/otter/canal/client/adapter/tablestore/service/TablestoreEtlService.java",
    "content": "package com.alibaba.otter.canal.client.adapter.tablestore.service;\n\n\nimport com.alibaba.otter.canal.client.adapter.support.*;\nimport com.alibaba.otter.canal.client.adapter.tablestore.TablestoreAdapter;\nimport com.alibaba.otter.canal.client.adapter.tablestore.config.MappingConfig;\nimport com.alibaba.otter.canal.client.adapter.tablestore.support.SyncUtil;\nimport com.alicloud.openservices.tablestore.TableStoreWriter;\nimport com.alicloud.openservices.tablestore.model.RowChange;\nimport com.alicloud.openservices.tablestore.writer.WriterResult;\nimport org.springframework.util.CollectionUtils;\n\nimport javax.sql.DataSource;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.stream.Collectors;\n\npublic class TablestoreEtlService extends AbstractEtlService {\n\n    private TableStoreWriter writer;\n    private MappingConfig config;\n    private TablestoreSyncService syncService;\n\n\n    public TablestoreEtlService(TableStoreWriter writer, MappingConfig config){\n        super(\"Tablestore\", config);\n        this.writer = writer;\n        this.config = config;\n        syncService = new TablestoreSyncService();\n    }\n\n\n    public EtlResult importData(List<String> params) {\n        MappingConfig.DbMapping dbMapping = config.getDbMapping();\n        String sql = \"SELECT * FROM \" + SyncUtil.getDbTableName(dbMapping.getDatabase(), dbMapping.getTable());\n        return importData(sql, params);\n    }\n\n    @Override\n    protected boolean executeSqlImport(DataSource srcDS, String sql, List<Object> values,\n                                       AdapterConfig.AdapterMapping mapping, AtomicLong impCount, List<String> errMsg) {\n\n        try {\n            MappingConfig.DbMapping dbMapping = (MappingConfig.DbMapping) mapping;\n            Map<String, String> columnsMap = dbMapping.getTargetColumnsParsed();\n\n            Util.sqlRS(srcDS, sql, values, rs -> {\n                int idx = 0;\n                List<Future<WriterResult>> futureList = new ArrayList<>();\n                while (true) {\n                    try {\n                        if (!rs.next()) break;\n                    } catch (SQLException throwables) {\n                        logger.error(\"Error while get data from srcDs\", throwables);\n                        break;\n                    }\n\n                    Dml dml = getDMLByRs(columnsMap, rs);\n\n                    List<RowChange> rowChanges = syncService.getRowChanges(dml, config);\n                    if (CollectionUtils.isEmpty(rowChanges)) {\n                        return null;\n                    }\n\n\n                    Future<WriterResult> future = writer.addRowChangeWithFuture(rowChanges);\n                    if (future != null) {\n                        futureList.add(future);\n                    }\n\n                }\n                writer.flush();\n                for (Future<WriterResult> future : futureList) {\n                    try {\n                        WriterResult result = future.get();\n                        if (result != null && result.isAllSucceed()) {\n                            impCount.incrementAndGet();\n                            idx++;\n                        } else if (result != null && !result.isAllSucceed()) {\n                            List<WriterResult.RowChangeStatus> totalFailedRows = result.getFailedRows();\n                            List<String> msgs = totalFailedRows.stream().map(e -> TablestoreAdapter.buildErrorMsgForFailedRowChange(e)).collect(Collectors.toList());\n                            logger.error(\"Failed rows when ETL:\" + org.springframework.util.StringUtils.collectionToDelimitedString(msgs, \",\", \"[\", \"]\"));\n                        }\n                    } catch (InterruptedException e) {\n                        logger.info(\"InterruptedException\", e);\n                        errMsg.add(e.getMessage());\n                        Thread.currentThread().interrupt();\n                    } catch (ExecutionException e) {\n                        errMsg.add(e.getMessage());\n                        throw new RuntimeException(e);\n                    }\n                }\n\n                return idx;\n            });\n            return true;\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n            return false;\n        }\n    }\n\n\n\n\n    private Dml getDMLByRs(Map<String, String> columnsMap, ResultSet rs) {\n        try {\n            Dml dml = new Dml();\n            dml.setType(\"INSERT\");\n            Map<String, Object> dataMap = new HashMap<>();\n            List<Map<String, Object>> dataList = new ArrayList<>();\n            dataList.add(dataMap);\n            dml.setData(dataList);\n            for (String key : columnsMap.keySet()) {\n                dataMap.put(key, rs.getObject(key));\n            }\n\n            return dml;\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n\n\n\n}\n"
  },
  {
    "path": "client-adapter/tablestore/src/main/java/com/alibaba/otter/canal/client/adapter/tablestore/service/TablestoreSyncService.java",
    "content": "package com.alibaba.otter.canal.client.adapter.tablestore.service;\n\n\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.Future;\n\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.JSONWriter.Feature;\nimport com.alibaba.otter.canal.client.adapter.tablestore.enums.TablestoreFieldType;\nimport com.alibaba.otter.canal.client.adapter.tablestore.support.SyncUtil;\nimport com.alicloud.openservices.tablestore.TableStoreWriter;\nimport com.alicloud.openservices.tablestore.model.*;\nimport com.alicloud.openservices.tablestore.writer.WriterResult;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport com.alibaba.otter.canal.client.adapter.tablestore.config.MappingConfig;\nimport com.alibaba.otter.canal.client.adapter.support.Dml;\nimport org.springframework.util.CollectionUtils;\n\n\n/**\n * RDB同步操作业务\n *\n * @author rewerma 2018-11-7 下午06:45:49\n * @version 1.0.0\n */\npublic class TablestoreSyncService {\n\n    private static final Logger               logger  = LoggerFactory.getLogger(TablestoreSyncService.class);\n\n    private Map<String, Map<String, Integer>> columnsTypeCache;\n\n\n    public Map<String, Map<String, Integer>> getColumnsTypeCache() {\n        return columnsTypeCache;\n    }\n\n    public TablestoreSyncService(){\n        this(new ConcurrentHashMap<>());\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public TablestoreSyncService(Map<String, Map<String, Integer>> columnsTypeCache){\n        this.columnsTypeCache = columnsTypeCache;\n\n    }\n\n    public Future<WriterResult> sync(MappingConfig mappingConfig,\n                     Dml dml,\n                     TableStoreWriter writer) {\n\n        List<RowChange> rowChanges = getRowChanges(dml, mappingConfig);\n        if (CollectionUtils.isEmpty(rowChanges)) {\n            return null;\n        }\n\n        Future<WriterResult> future = writer.addRowChangeWithFuture(rowChanges);\n\n        if (logger.isDebugEnabled()) {\n            logger.debug(\"DML: {}\", JSON.toJSONString(dml, Feature.WriteNulls));\n        }\n        return future;\n    }\n\n    public List<RowChange> getRowChanges(Dml dml, MappingConfig config) {\n        String type = dml.getType();\n        boolean updateColume = config.getUpdateChangeColumns();\n        if (type != null && type.equalsIgnoreCase(\"INSERT\")) {\n            return getInsertChanges(dml, updateColume, config);\n        } else if (type != null && type.equalsIgnoreCase(\"UPDATE\")) {\n            return getUpdateChanges(dml, updateColume, config);\n        } else if (type != null && type.equalsIgnoreCase(\"DELETE\")) {\n            return getDeleteChanges(dml, updateColume, config);\n        } else {\n            return null;\n        }\n    }\n\n    /**\n     * Update 类型下构造rowChangeList\n     * @param dml\n     * @param isColumnUpdate\n     * @param config\n     * @return\n     */\n    private List<RowChange> getUpdateChanges(Dml dml, boolean isColumnUpdate, MappingConfig config) {\n        List<RowChange> changeList = new ArrayList<>();\n        Map<String, String> columnMap = config.getDbMapping().getTargetColumnsParsed();\n        Map<String, MappingConfig.ColumnItem> typeMap = SyncUtil.getTypeMap(config);\n        MappingConfig.DbMapping dbMapping = config.getDbMapping();\n\n        if (isColumnUpdate) {\n            // 列更新\n            for (int i = 0; i < dml.getData().size(); i++) {\n                Map<String, Object> map = dml.getData().get(i);\n                Map<String, Object> old = dml.getOld().get(i);\n                boolean isPrimaryKeyChange = isPrimaryKeyChange(old, dbMapping.getTargetPk());\n                if (isPrimaryKeyChange) {\n                    // 如果发现主键修改用put delete操作\n                    // 先 delete\n                    RowUpdateChange change = new RowUpdateChange(dbMapping.getTargetTable());\n                    PrimaryKey primaryKey = buildOldPrimaryKey(map, typeMap, columnMap, dbMapping.getTargetPk(), old);\n                    change.setPrimaryKey(primaryKey);\n                    for (Map.Entry<String, Object> entry : map.entrySet()) {\n                        if (dbMapping.getTargetPk().containsKey(entry.getKey())) {\n                            // 这是个主键, 不需要再次处理\n                            continue;\n                        }\n                        if (!dbMapping.getTargetColumns().containsKey(entry.getKey())) {\n                            // 可能是没有配置的字段\n                            continue;\n                        }\n                        // 非主键\n                        String targetColumn = columnMap.get(entry.getKey());\n                        change.deleteColumns(targetColumn);\n                    }\n                    changeList.add(change);\n\n                    // 然后再put\n                    change = new RowUpdateChange(dbMapping.getTargetTable());\n                    primaryKey = buildPrimaryKey(map, typeMap, columnMap, dbMapping.getTargetPk());\n                    change.setPrimaryKey(primaryKey);\n\n                    List<Column> columnList = getColumnsWhenPut(columnMap, dbMapping, map, typeMap);\n                    if (!CollectionUtils.isEmpty(columnList)) {\n                        change.put(columnList);\n                        changeList.add(change);\n                    }\n\n\n                } else {\n                    //否则用update\n                    RowUpdateChange change = new RowUpdateChange(dbMapping.getTargetTable());\n                    PrimaryKey primaryKey = buildPrimaryKey(map, typeMap, columnMap, dbMapping.getTargetPk());\n                    change.setPrimaryKey(primaryKey);\n                    // 部分update 部分delete\n\n                    boolean validData = false;\n                    for (Map.Entry<String, Object> entry : old.entrySet()) {\n                        if (dbMapping.getTargetPk().containsKey(entry.getKey())) {\n                            // 这是个主键, 不需要再次处理\n                            continue;\n                        }\n                        if (!dbMapping.getTargetColumns().containsKey(entry.getKey())) {\n                            // 可能是没有配置的字段\n                            continue;\n                        }\n                        // 非主键\n                        String targetColumn = columnMap.get(entry.getKey());\n                        Object value = map.get(entry.getKey());\n                        validData = true;\n                        if (value == null) {\n                            change.deleteColumns(targetColumn);\n                        } else {\n                            TablestoreFieldType type = typeMap.get(entry.getKey()).getType();\n                            ColumnValue columnValue = SyncUtil.getColumnValue(value, type);\n                            change.put(targetColumn, columnValue);\n                        }\n                    }\n                    if (validData) {\n                        changeList.add(change);\n                    }\n\n                }\n            }\n\n        } else {\n            // 列覆盖\n            for (int i = 0; i < dml.getData().size(); i++) {\n                Map<String, Object> map = dml.getData().get(i);\n\n                RowPutChange change = new RowPutChange(dbMapping.getTargetTable());\n                PrimaryKey primaryKey = buildPrimaryKey(map, typeMap, columnMap, dbMapping.getTargetPk());\n                change.setPrimaryKey(primaryKey);\n\n                List<Column> columnList = getColumnsWhenPut(columnMap, dbMapping, map, typeMap);\n                if (!CollectionUtils.isEmpty(columnList)) {\n                    change.addColumns(columnList);\n                    changeList.add(change);\n                }\n\n                if (dml.getOld() != null) {\n                    // 如果主键发生修改，需要在tablestore中删除对应的原记录\n                    Map<String, Object> old = dml.getOld().get(i);\n                    if (isPrimaryKeyChange(old, dbMapping.getTargetPk())) {\n                        RowDeleteChange delete = new RowDeleteChange(dbMapping.getTargetTable());\n                        PrimaryKey primaryKeyDelete = buildOldPrimaryKey(map, typeMap, columnMap, dbMapping.getTargetPk(), old);\n                        delete.setPrimaryKey(primaryKeyDelete);\n                        changeList.add(delete);\n                    }\n\n                }\n\n            }\n        }\n\n        return changeList;\n    }\n\n    /**\n     * Delete 类型下构造rowChangeList\n     * @param dml\n     * @param isColumnUpdate\n     * @param config\n     * @return\n     */\n    private List<RowChange> getDeleteChanges(Dml dml, boolean isColumnUpdate, MappingConfig config) {\n        List<RowChange> changeList = new ArrayList<>();\n        Map<String, String> columnMap = config.getDbMapping().getTargetColumnsParsed();\n        Map<String, MappingConfig.ColumnItem> typeMap = SyncUtil.getTypeMap(config);\n        MappingConfig.DbMapping dbMapping = config.getDbMapping();\n\n        if (isColumnUpdate) {\n            // 列更新\n            for (Map<String, Object> map : dml.getData()) {\n                RowUpdateChange change = new RowUpdateChange(dbMapping.getTargetTable());\n                PrimaryKey primaryKey = buildPrimaryKey(map, typeMap, columnMap, dbMapping.getTargetPk());\n                change.setPrimaryKey(primaryKey);\n                boolean validData = false;\n                for (Map.Entry<String, Object> entry : map.entrySet()) {\n                    if (dbMapping.getTargetPk().containsKey(entry.getKey())) {\n                        // 这是个主键, 不需要再次处理\n                        continue;\n                    }\n                    if (!dbMapping.getTargetColumns().containsKey(entry.getKey())) {\n                        // 可能是没有配置的字段\n                        continue;\n                    }\n                    // 非主键\n                    validData = true;\n                    String targetColumn = columnMap.get(entry.getKey());\n                    change.deleteColumns(targetColumn);\n                }\n                if (validData) {\n                    changeList.add(change);\n                }\n            }\n\n        } else {\n            // 列覆盖\n            for (Map<String, Object> map : dml.getData()) {\n                RowDeleteChange change = new RowDeleteChange(dbMapping.getTargetTable());\n                PrimaryKey primaryKey = buildPrimaryKey(map, typeMap, columnMap, dbMapping.getTargetPk());\n                change.setPrimaryKey(primaryKey);\n\n                changeList.add(change);\n            }\n        }\n\n        return changeList;\n    }\n\n    /**\n     * Insert 类型下构造rowChangeList\n     * @param dml\n     * @param isColumnUpdate\n     * @param config\n     * @return\n     */\n    private List<RowChange> getInsertChanges(Dml dml, boolean isColumnUpdate, MappingConfig config) {\n        List<RowChange> changeList = new ArrayList<>();\n\n        Map<String, String> columnMap = config.getDbMapping().getTargetColumnsParsed();\n        Map<String, MappingConfig.ColumnItem> typeMap = SyncUtil.getTypeMap(config);\n        MappingConfig.DbMapping dbMapping = config.getDbMapping();\n        if (isColumnUpdate) {\n            // 列更新\n            for (Map<String, Object> map : dml.getData()) {\n                RowUpdateChange change = new RowUpdateChange(dbMapping.getTargetTable());\n                PrimaryKey primaryKey = buildPrimaryKey(map, typeMap, columnMap, dbMapping.getTargetPk());\n                change.setPrimaryKey(primaryKey);\n\n                List<Column> columnList = getColumnsWhenPut(columnMap, dbMapping, map, typeMap);\n                if (!CollectionUtils.isEmpty(columnList)) {\n                    change.put(columnList);\n                    changeList.add(change);\n                }\n            }\n\n        } else {\n            // 列覆盖\n            for (Map<String, Object> map : dml.getData()) {\n                RowPutChange change = new RowPutChange(dbMapping.getTargetTable());\n                PrimaryKey primaryKey = buildPrimaryKey(map, typeMap, columnMap, dbMapping.getTargetPk());\n                change.setPrimaryKey(primaryKey);\n\n                List<Column> columnList = getColumnsWhenPut(columnMap, dbMapping, map, typeMap);\n                if (!CollectionUtils.isEmpty(columnList)) {\n                    change.addColumns(columnList);\n                }\n\n                changeList.add(change);\n            }\n        }\n        return changeList;\n    }\n\n\n    /**\n     * 组装rowChange的主键\n     * @param map 数据map\n     * @param typeMap  类型映射\n     * @param columnMap 字段名称映射\n     * @param targetPk  主键map\n     * @return\n     */\n    private PrimaryKey buildPrimaryKey(Map<String, Object> map, Map<String, MappingConfig.ColumnItem> typeMap, Map<String, String> columnMap, LinkedHashMap<String, String> targetPk) {\n        List primaryKeyList = new ArrayList<>();\n        for (Map.Entry<String, String> entry : targetPk.entrySet()) {\n            // build primary key\n            String targetColumn = columnMap.get(entry.getKey());\n            Object value = map.get(entry.getKey());\n            TablestoreFieldType type = typeMap.get(entry.getKey()).getType();\n            PrimaryKeyValue keyValue = SyncUtil.getPrimaryKeyValue(value, type);\n            PrimaryKeyColumn primaryKeyColumn = new PrimaryKeyColumn(targetColumn, keyValue);\n            primaryKeyList.add(primaryKeyColumn);\n        }\n        return new PrimaryKey(primaryKeyList);\n    }\n\n\n\n    private PrimaryKey buildOldPrimaryKey(Map<String, Object> map,\n                                          Map<String, MappingConfig.ColumnItem> typeMap,\n                                          Map<String, String> columnMap,\n                                          LinkedHashMap<String, String> targetPk,\n                                          Map<String, Object> old) {\n        List primaryKeyList = new ArrayList<>();\n        for (Map.Entry<String, String> entry : targetPk.entrySet()) {\n            // build primary key\n            String targetColumn = columnMap.get(entry.getKey());\n            Object value = old != null && old.containsKey(entry.getKey()) && !old.get(entry.getKey()).equals(map.get(entry.getKey())) ? old.get(entry.getKey()) : map.get(entry.getKey());\n            TablestoreFieldType type = typeMap.get(entry.getKey()).getType();\n            PrimaryKeyValue keyValue = SyncUtil.getPrimaryKeyValue(value, type);\n            PrimaryKeyColumn primaryKeyColumn = new PrimaryKeyColumn(targetColumn, keyValue);\n            primaryKeyList.add(primaryKeyColumn);\n        }\n        return new PrimaryKey(primaryKeyList);\n    }\n\n    /**\n     * 用于获得全量覆盖时的非主键列对应的columnlist\n     * @param columnMap\n     * @param dbMapping\n     * @param map\n     * @param typeMap\n     * @return\n     */\n    private List<Column> getColumnsWhenPut(Map<String, String> columnMap,\n                                           MappingConfig.DbMapping dbMapping,\n                                           Map<String, Object> map,\n                                           Map<String, MappingConfig.ColumnItem> typeMap) {\n        List<Column> columnList = new ArrayList<>();\n        for (Map.Entry<String, Object> entry : map.entrySet()) {\n            if (dbMapping.getTargetPk().containsKey(entry.getKey())) {\n                // 这是个主键, 不需要再次处理\n                continue;\n            }\n            if (!dbMapping.getTargetColumns().containsKey(entry.getKey())) {\n                // 可能是没有配置的字段\n                continue;\n            }\n            // 非主键\n            String targetColumn = columnMap.get(entry.getKey());\n            Object value = entry.getValue();\n            if (value == null) {\n                // insert时空值过滤掉\n                continue;\n            }\n            TablestoreFieldType type = typeMap.get(entry.getKey()).getType();\n            ColumnValue columnValue = SyncUtil.getColumnValue(value, type);\n            columnList.add(new Column(targetColumn, columnValue));\n        }\n        return columnList;\n    }\n\n    /**\n     * 检查是否主键被修改\n     * @param old       old中的数据\n     * @param targetPk  主键map\n     * @return\n     */\n    private boolean isPrimaryKeyChange(Map<String, Object> old, Map<String, String> targetPk) {\n        for (String pkCol : targetPk.keySet()) {\n            if (old.containsKey(pkCol)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public void close() {\n\n    }\n}\n"
  },
  {
    "path": "client-adapter/tablestore/src/main/java/com/alibaba/otter/canal/client/adapter/tablestore/support/SyncUtil.java",
    "content": "package com.alibaba.otter.canal.client.adapter.tablestore.support;\n\n\nimport com.alibaba.otter.canal.client.adapter.tablestore.config.MappingConfig;\nimport com.alibaba.otter.canal.client.adapter.tablestore.enums.TablestoreFieldType;\nimport com.alicloud.openservices.tablestore.model.ColumnValue;\nimport com.alicloud.openservices.tablestore.model.PrimaryKeyValue;\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport java.nio.charset.StandardCharsets;\nimport java.sql.*;\nimport java.util.Map;\n\npublic class SyncUtil {\n    private static final Logger logger  = LoggerFactory.getLogger(SyncUtil.class);\n\n\n    public static PrimaryKeyValue getPrimaryKeyValue(Object value, TablestoreFieldType fieldType) {\n        Object tablestoreValue;\n        switch (fieldType) {\n            case STRING:\n                tablestoreValue = getTablestoreValue(value, fieldType);\n                return PrimaryKeyValue.fromString((String)tablestoreValue);\n            case INT:\n                tablestoreValue = getTablestoreValue(value, fieldType);\n                return PrimaryKeyValue.fromLong((long)tablestoreValue);\n            case BINARY:\n                tablestoreValue = getTablestoreValue(value, fieldType);\n                return PrimaryKeyValue.fromBinary((byte[])tablestoreValue);\n\n            default:\n                return PrimaryKeyValue.fromString(value.toString());\n\n        }\n    }\n\n    private static Object getTablestoreValue(Object value, TablestoreFieldType type) {\n        switch (type) {\n            case STRING:\n                if (value instanceof byte[]) {\n                    return new String(((byte[])value));\n                }\n                return value.toString();\n            case INT:\n                if (value instanceof Number) {\n                    return ((Number) value).longValue();\n                } else if (value instanceof Timestamp) {\n                    return ((Timestamp) value).getTime();\n                } else if (value instanceof String) {\n                    try {\n                        return Long.parseLong((String) value);\n                    } catch (NumberFormatException e) {\n                        logger.error(\"Error while parse long:\" + value.toString(), e);\n                        throw e;\n                    }\n                } else if (value instanceof Date) {\n                    return ((Date) value).getTime();\n                } else if (value instanceof Time) {\n                    return ((Time) value).getTime();\n                } else if (value instanceof java.util.Date) {\n                    return ((java.util.Date) value).getTime();\n                } else if (value instanceof Boolean) {\n                    Boolean ob =  ((Boolean)value);\n                    return ob ? 1L : 0L;\n                }\n                return null;\n            case BINARY:\n                if (value instanceof byte[]) {\n                    return value;\n                } else if (value instanceof Blob) {\n                    Blob item = ((Blob) value);\n                    int length;\n                    try {\n                        length = (int) item.length();\n                        return item.getBytes(1, length);\n                    } catch (SQLException e) {\n                        logger.error(\"Error while convert blob to binary, blob:\" + item.toString(), e);\n                        throw new RuntimeException(e);\n                    }\n                } else if (value instanceof String) {\n                    return ((String) value).getBytes(StandardCharsets.ISO_8859_1);\n                } else if (value instanceof Clob) {\n                    return value.toString().getBytes(StandardCharsets.ISO_8859_1);\n                }\n                return null;\n            case BOOL:\n                if (value instanceof Boolean) {\n                    return value;\n                } else if (value instanceof String) {\n                    return !value.equals(\"0\");\n                } else if (value instanceof Number) {\n                    return ((Number) value).intValue() != 0;\n                }\n                return null;\n            case DOUBLE:\n                if (value instanceof Number) {\n                    return ((Number)value).doubleValue();\n                } else if (value instanceof String) {\n                    try {\n                        return Double.parseDouble((String) value);\n                    } catch (NumberFormatException e) {\n                        logger.error(\"Error while parse double:\" + value.toString(), e);\n                        throw e;\n                    }\n                }\n                return null;\n            default:\n                return value;\n        }\n    }\n\n    /**\n     * 解析配置的字段映射类型\n     * @param type\n     * @return\n     */\n    public static TablestoreFieldType getTablestoreType(String type) {\n        if (type != null) {\n            if (type.equalsIgnoreCase(\"string\")) {\n                return TablestoreFieldType.STRING;\n            } else if (type.equalsIgnoreCase(\"int\") || type.equalsIgnoreCase(\"integer\")) {\n                return TablestoreFieldType.INT;\n            } else if (type.equalsIgnoreCase(\"bool\") || type.equalsIgnoreCase(\"boolean\")) {\n                return TablestoreFieldType.BOOL;\n            } else if (type.equalsIgnoreCase(\"binary\")) {\n                return TablestoreFieldType.BINARY;\n            } else if (type.equalsIgnoreCase(\"double\") || type.equalsIgnoreCase(\"float\") || type.equalsIgnoreCase(\"decimal\")) {\n                return TablestoreFieldType.DOUBLE;\n            } else {\n                return null;\n            }\n        } else {\n            return null;\n        }\n    }\n\n\n    public static ColumnValue getColumnValue(Object value, TablestoreFieldType fieldType) {\n        Object tablestoreValue;\n        switch (fieldType) {\n            case STRING:\n                tablestoreValue = getTablestoreValue(value, fieldType);\n                return ColumnValue.fromString((String)tablestoreValue);\n            case INT:\n                tablestoreValue = getTablestoreValue(value, fieldType);\n                return ColumnValue.fromLong((long)tablestoreValue);\n            case BINARY:\n                tablestoreValue = getTablestoreValue(value, fieldType);\n                return ColumnValue.fromBinary((byte[])tablestoreValue);\n            case DOUBLE:\n                tablestoreValue = getTablestoreValue(value, fieldType);\n                return ColumnValue.fromDouble((double)tablestoreValue);\n            case BOOL:\n                tablestoreValue = getTablestoreValue(value, fieldType);\n                return ColumnValue.fromBoolean((boolean)tablestoreValue);\n            default:\n                return ColumnValue.fromString(value.toString());\n        }\n\n\n    }\n\n    public static Map<String, MappingConfig.ColumnItem> getTypeMap(MappingConfig config) {\n        return config.getDbMapping().getColumnItems();\n    }\n\n    public static TablestoreFieldType getDefaultTablestoreType(int sqlType) {\n        switch (sqlType) {\n            case Types.BIT:\n            case Types.BOOLEAN:\n                return TablestoreFieldType.BOOL;\n            case Types.BINARY:\n            case Types.VARBINARY:\n            case Types.LONGVARBINARY:\n            case Types.BLOB:\n                return TablestoreFieldType.BINARY;\n            case Types.TINYINT:\n            case Types.SMALLINT:\n            case Types.INTEGER:\n            case Types.BIGINT:\n                return TablestoreFieldType.INT;\n            case Types.DECIMAL:\n            case Types.NUMERIC:\n            case Types.REAL:\n            case Types.FLOAT:\n            case Types.DOUBLE:\n                return TablestoreFieldType.DOUBLE;\n            case Types.CHAR:\n            case Types.NCHAR:\n            case Types.VARCHAR:\n            case Types.LONGVARCHAR:\n            case Types.CLOB:\n            case Types.DATE:\n            case Types.TIME:\n            case Types.TIMESTAMP:\n                return TablestoreFieldType.STRING;\n            default:\n                return TablestoreFieldType.STRING;\n        }\n    }\n\n    public static String getDbTableName(String db,String table) {\n        String result = \"\";\n        if (StringUtils.isNotEmpty(db)) {\n            result += (\"`\" + db + \"`.\");\n        }\n        result += (\"`\" + table + \"`\");\n        return result;\n    }\n}\n"
  },
  {
    "path": "client-adapter/tablestore/src/main/resources/META-INF/canal/com.alibaba.otter.canal.client.adapter.OuterAdapter",
    "content": "tablestore=com.alibaba.otter.canal.client.adapter.tablestore.TablestoreAdapter"
  },
  {
    "path": "client-adapter/tablestore/src/main/resources/tablestore/test.yml",
    "content": "dataSourceKey: defaultDS\ndestination: test_ots\ngroupId: g1\nouterAdapterKey: mysql1\nthreads: 1\nupdateChangeColumns: false\ndbMapping:\n  database: test_ots\n  table: test\n  targetTable: canal_target\n  targetPk:\n    oId: oId\n  targetColumns:\n    oId:\n    c_id:\n    p_price:\n    p_count:\n  etlCondition: \n  commitBatch: 1 # 批量提交的大小\n\n\n"
  },
  {
    "path": "codeformat.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<profiles version=\"12\">\n<profile kind=\"CodeFormatterProfile\" name=\"canal-format\" version=\"12\">\n<setting id=\"org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.disabling_tag\" value=\"@formatter:off\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_field\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.use_on_off_tags\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_ellipsis\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_multiple_fields\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer\" value=\"18\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_conditional_expression\" value=\"4\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_binary_operator\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_array_initializer\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_after_package\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.continuation_indentation\" value=\"2\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation\" value=\"84\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_binary_operator\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_package\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.compiler.source\" value=\"1.7\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.format_line_comments\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.join_wrapped_lines\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call\" value=\"84\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_member_type\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.align_type_members_on_columns\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation\" value=\"84\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_unary_operator\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.indent_parameter_description\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.lineSplit\" value=\"120\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indentation.size\" value=\"4\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.enabling_tag\" value=\"@formatter:on\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_assignment\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.compiler.problem.assertIdentifier\" value=\"error\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.tabulation.char\" value=\"space\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_statements_compare_to_body\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_method\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration\" value=\"18\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_method_declaration\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_switch\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.compiler.problem.enumIdentifier\" value=\"error\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_ellipsis\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_block\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_method_declaration\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.compact_else_if\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.indent_root_tags\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_enum_constant\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.tabulation.size\" value=\"4\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration\" value=\"18\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_empty_lines\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_block_in_case\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression\" value=\"84\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.compiler.compliance\" value=\"1.7\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer\" value=\"2\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression\" value=\"84\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_unary_operator\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_binary_expression\" value=\"18\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode\" value=\"enabled\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_label\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant\" value=\"18\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.format_javadoc_comments\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.line_length\" value=\"80\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_between_import_groups\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_semicolon\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.wrap_before_binary_operator\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_statements_compare_to_block\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration\" value=\"18\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.join_lines_in_comments\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_compact_if\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_imports\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.format_html\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration\" value=\"18\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.format_source_code\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration\" value=\"18\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.compiler.codegen.targetPlatform\" value=\"1.7\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_resources_in_try\" value=\"80\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.format_header\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.format_block_comments\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_enum_constants\" value=\"18\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_type_declaration\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_after_imports\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line\" value=\"true\"/>\n</profile>\n</profiles>\n"
  },
  {
    "path": "codetemplates.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><templates><template autoinsert=\"true\" context=\"gettercomment_context\" deleted=\"false\" description=\"Comment for getter method\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.gettercomment\" name=\"gettercomment\">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert=\"true\" context=\"settercomment_context\" deleted=\"false\" description=\"Comment for setter method\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.settercomment\" name=\"settercomment\">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert=\"true\" context=\"constructorcomment_context\" deleted=\"false\" description=\"Comment for created constructors\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.constructorcomment\" name=\"constructorcomment\">/**\n * ${tags}\n */</template><template autoinsert=\"false\" context=\"filecomment_context\" deleted=\"false\" description=\"Comment for created Java files\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.filecomment\" name=\"filecomment\"/><template autoinsert=\"false\" context=\"typecomment_context\" deleted=\"false\" description=\"Comment for created types\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.typecomment\" name=\"typecomment\">/**\n * @author ${user} ${date} ${time}\n * @since 1.0.0\n */</template><template autoinsert=\"true\" context=\"fieldcomment_context\" deleted=\"false\" description=\"Comment for fields\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.fieldcomment\" name=\"fieldcomment\">/**\n * \n */</template><template autoinsert=\"true\" context=\"methodcomment_context\" deleted=\"false\" description=\"Comment for non-overriding methods\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.methodcomment\" name=\"methodcomment\">/**\n * ${tags}\n */</template><template autoinsert=\"false\" context=\"overridecomment_context\" deleted=\"false\" description=\"Comment for overriding methods\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.overridecomment\" name=\"overridecomment\"/><template autoinsert=\"true\" context=\"delegatecomment_context\" deleted=\"false\" description=\"Comment for delegate methods\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.delegatecomment\" name=\"delegatecomment\">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert=\"false\" context=\"newtype_context\" deleted=\"false\" description=\"Newly created files\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.newtype\" name=\"newtype\">${filecomment}\n${package_declaration}\n${typecomment}\n${type_declaration}</template><template autoinsert=\"true\" context=\"classbody_context\" deleted=\"false\" description=\"Code in new class type bodies\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.classbody\" name=\"classbody\">\n</template><template autoinsert=\"true\" context=\"interfacebody_context\" deleted=\"false\" description=\"Code in new interface type bodies\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.interfacebody\" name=\"interfacebody\">\n</template><template autoinsert=\"true\" context=\"enumbody_context\" deleted=\"false\" description=\"Code in new enum type bodies\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.enumbody\" name=\"enumbody\">\n</template><template autoinsert=\"true\" context=\"annotationbody_context\" deleted=\"false\" description=\"Code in new annotation type bodies\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.annotationbody\" name=\"annotationbody\">\n</template><template autoinsert=\"true\" context=\"catchblock_context\" deleted=\"false\" description=\"Code in new catch blocks\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.catchblock\" name=\"catchblock\">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert=\"true\" context=\"methodbody_context\" deleted=\"false\" description=\"Code in created method stubs\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.methodbody\" name=\"methodbody\">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert=\"true\" context=\"constructorbody_context\" deleted=\"false\" description=\"Code in created constructor stubs\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.constructorbody\" name=\"constructorbody\">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert=\"true\" context=\"getterbody_context\" deleted=\"false\" description=\"Code in created getters\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.getterbody\" name=\"getterbody\">return ${field};</template><template autoinsert=\"true\" context=\"setterbody_context\" deleted=\"false\" description=\"Code in created setters\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.setterbody\" name=\"setterbody\">${field} = ${param};</template></templates>\n"
  },
  {
    "path": "common/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>com.alibaba.otter</groupId>\n\t\t<artifactId>canal</artifactId>\n\t\t<version>1.1.9-SNAPSHOT</version>\n\t\t<relativePath>../pom.xml</relativePath>\n\t</parent>\n\t<artifactId>canal.common</artifactId>\n\t<packaging>jar</packaging>\n\t<name>canal common module for otter ${project.version}</name>\n\t<url>http://b2b-doc.alibaba-inc.com/display/opentech/Otter</url>\n\t<dependencies>\n\t\t<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->\n\t\t<dependency>\n\t\t\t<groupId>io.netty</groupId>\n\t\t\t<artifactId>netty-all</artifactId>\n\t\t</dependency>\n\t\t<!-- zk -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.zookeeper</groupId>\n\t\t\t<artifactId>zookeeper</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.101tec</groupId>\n\t\t\t<artifactId>zkclient</artifactId>\n\t\t</dependency>\n\t\t<!-- external -->\n\t\t<dependency>\n\t\t\t<groupId>commons-io</groupId>\n\t\t\t<artifactId>commons-io</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>commons-lang</groupId>\n\t\t\t<artifactId>commons-lang</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>commons-codec</groupId>\n\t\t\t<artifactId>commons-codec</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.fastjson2</groupId>\n\t\t\t<artifactId>fastjson2</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.google.guava</groupId>\n\t\t\t<artifactId>guava</artifactId>\n\t\t</dependency>\n\t\t<!-- log -->\n\t\t<dependency>\n\t\t\t<groupId>ch.qos.logback</groupId>\n\t\t\t<artifactId>logback-core</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>ch.qos.logback</groupId>\n\t\t\t<artifactId>logback-classic</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>jcl-over-slf4j</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-core</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-aop</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-jdbc</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-orm</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.google.code.findbugs</groupId>\n\t\t\t<artifactId>jsr305</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>druid</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-test</artifactId>\n\t\t\t<version>${spring_version}</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<!-- junit -->\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "common/src/main/java/com/alibaba/otter/canal/common/AbstractCanalLifeCycle.java",
    "content": "package com.alibaba.otter.canal.common;\n\n/**\n * 基本实现\n * \n * @author jianghang 2012-7-12 上午10:11:07\n * @version 1.0.0\n */\npublic abstract class AbstractCanalLifeCycle implements CanalLifeCycle {\n\n    protected volatile boolean running = false; // 是否处于运行中\n\n    public boolean isStart() {\n        return running;\n    }\n\n    public void start() {\n        if (running) {\n            throw new CanalException(this.getClass().getName() + \" has startup , don't repeat start\");\n        }\n\n        running = true;\n    }\n\n    public void stop() {\n        if (!running) {\n            throw new CanalException(this.getClass().getName() + \" isn't start , please check\");\n        }\n\n        running = false;\n    }\n\n}\n"
  },
  {
    "path": "common/src/main/java/com/alibaba/otter/canal/common/CanalException.java",
    "content": "package com.alibaba.otter.canal.common;\n\nimport org.apache.commons.lang.exception.NestableRuntimeException;\n\n/**\n * @author jianghang 2012-7-12 上午10:10:31\n * @version 1.0.0\n */\npublic class CanalException extends NestableRuntimeException {\n\n    private static final long serialVersionUID = -654893533794556357L;\n\n    public CanalException(String errorCode){\n        super(errorCode);\n    }\n\n    public CanalException(String errorCode, Throwable cause){\n        super(errorCode, cause);\n    }\n\n    public CanalException(String errorCode, String errorDesc){\n        super(errorCode + \":\" + errorDesc);\n    }\n\n    public CanalException(String errorCode, String errorDesc, Throwable cause){\n        super(errorCode + \":\" + errorDesc, cause);\n    }\n\n    public CanalException(Throwable cause){\n        super(cause);\n    }\n\n    public Throwable fillInStackTrace() {\n        return this;\n    }\n\n}\n"
  },
  {
    "path": "common/src/main/java/com/alibaba/otter/canal/common/CanalLifeCycle.java",
    "content": "package com.alibaba.otter.canal.common;\n\n/**\n * @author jianghang 2012-7-12 上午09:39:33\n * @version 1.0.0\n */\npublic interface CanalLifeCycle {\n\n    void start();\n\n    void stop();\n\n    boolean isStart();\n}\n"
  },
  {
    "path": "common/src/main/java/com/alibaba/otter/canal/common/alarm/CanalAlarmHandler.java",
    "content": "package com.alibaba.otter.canal.common.alarm;\n\nimport com.alibaba.otter.canal.common.CanalLifeCycle;\n\n/**\n * canal报警处理机制\n * \n * @author jianghang 2012-8-22 下午10:08:56\n * @version 1.0.0\n */\npublic interface CanalAlarmHandler extends CanalLifeCycle {\n\n    /**\n     * 发送对应destination的报警\n     * \n     * @param destination\n     * @param msg\n     */\n    void sendAlarm(String destination, String msg);\n}\n"
  },
  {
    "path": "common/src/main/java/com/alibaba/otter/canal/common/alarm/LogAlarmHandler.java",
    "content": "package com.alibaba.otter.canal.common.alarm;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.common.AbstractCanalLifeCycle;\n\n/**\n * 基于log的alarm机制实现\n * \n * @author jianghang 2012-8-22 下午10:12:35\n * @version 1.0.0\n */\npublic class LogAlarmHandler extends AbstractCanalLifeCycle implements CanalAlarmHandler {\n\n    private static final Logger logger = LoggerFactory.getLogger(LogAlarmHandler.class);\n\n    public void sendAlarm(String destination, String msg) {\n        logger.error(\"destination:{}[{}]\", new Object[] { destination, msg });\n    }\n\n}\n"
  },
  {
    "path": "common/src/main/java/com/alibaba/otter/canal/common/utils/AddressUtils.java",
    "content": "package com.alibaba.otter.canal.common.utils;\n\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.net.NetworkInterface;\nimport java.net.ServerSocket;\nimport java.util.Enumeration;\nimport java.util.regex.Pattern;\n\nimport org.apache.commons.lang.ArrayUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class AddressUtils {\n\n    private static final Logger  logger       = LoggerFactory.getLogger(AddressUtils.class);\n    private static final String  LOCALHOST_IP = \"127.0.0.1\";\n    private static final String  EMPTY_IP     = \"0.0.0.0\";\n    private static final Pattern IP_PATTERN   = Pattern.compile(\"[0-9]{1,3}(\\\\.[0-9]{1,3}){3,}\");\n\n    public static boolean isAvailablePort(int port) {\n        try (ServerSocket ss = new ServerSocket(port)) {\n            ss.bind(null);\n            return true;\n        } catch (IOException e) {\n            return false;\n        }\n    }\n\n    private static boolean isValidHostAddress(InetAddress address) {\n        if (address == null || address.isLoopbackAddress()) return false;\n        String name = address.getHostAddress();\n        return (name != null && !EMPTY_IP.equals(name) && !LOCALHOST_IP.equals(name) && IP_PATTERN.matcher(name)\n            .matches());\n    }\n\n    public static String getHostIp() {\n        InetAddress address = getHostAddress();\n        return address == null ? null : address.getHostAddress();\n    }\n\n    public static String getHostName() {\n        InetAddress address = getHostAddress();\n        return address == null ? null : address.getHostName();\n    }\n\n    public static InetAddress getHostAddress() {\n        InetAddress localAddress = null;\n        try {\n            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();\n            if (interfaces != null) {\n                while (interfaces.hasMoreElements()) {\n                    try {\n                        NetworkInterface network = interfaces.nextElement();\n                        Enumeration<InetAddress> addresses = network.getInetAddresses();\n                        if (addresses != null) {\n                            while (addresses.hasMoreElements()) {\n                                try {\n                                    InetAddress address = addresses.nextElement();\n                                    if (isValidHostAddress(address)) {\n                                        return address;\n                                    }\n                                } catch (Throwable e) {\n                                    logger.warn(\"Failed to retriving network card ip address. cause:\" + e.getMessage());\n                                }\n                            }\n                        }\n                    } catch (Throwable e) {\n                        logger.warn(\"Failed to retriving network card ip address. cause:\" + e.getMessage());\n                    }\n                }\n            }\n        } catch (Throwable e) {\n            logger.warn(\"Failed to retriving network card ip address. cause:\" + e.getMessage());\n        }\n        logger.error(\"Could not get local host ip address, will use 127.0.0.1 instead.\");\n        return localAddress;\n    }\n\n    /**\n     * 拆分IP地址和端口号\n     *\n     * @param text ip地址和端口号，ip和端口号以英文冒号(:)分隔;\n     * \n     *     <pre>\n     *             ipv4 127.0.0.1:3306\n     *             ipv6 [::1]:3306\n     *     </pre>\n     *\n     * @return\n     */\n    public static String[] splitIPAndPort(String text) {\n        text = text.replace(\"[\", \"\").replace(\"]\", \"\");\n        int idx = text.lastIndexOf(':');\n        if (idx > 0) {\n            String ip = text.substring(0, idx);\n            String port = text.substring(idx + 1);\n            return new String[] { ip, port };\n        }\n        return ArrayUtils.EMPTY_STRING_ARRAY;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/com/alibaba/otter/canal/common/utils/BooleanMutex.java",
    "content": "package com.alibaba.otter.canal.common.utils;\n\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\nimport java.util.concurrent.locks.AbstractQueuedSynchronizer;\n\n/**\n * 实现一个互斥实现，基于Cocurrent中的AQS实现了自己的sync <br/>\n * 应用场景：系统初始化/授权控制，没权限时阻塞等待。有权限时所有线程都可以快速通过\n * \n * <pre>\n * false : 代表需要被阻塞挂起，等待mutex变为true被唤醒\n * true : 唤醒被阻塞在false状态下的thread\n * \n * BooleanMutex mutex = new BooleanMutex(true);\n * try {\n *     mutex.get(); //当前状态为true, 不会被阻塞\n * } catch (InterruptedException e) {\n *     // do something\n * }\n * \n * mutex.set(false);\n * try {\n *     mutex.get(); //当前状态为false, 会被阻塞直到另一个线程调用mutex.set(true);\n * } catch (InterruptedException e) {\n *     // do something\n * }\n * </pre>\n * \n * @author jianghang 2011-9-23 上午09:58:03\n * @version 1.0.0\n */\npublic class BooleanMutex {\n\n    private final Sync sync;\n\n    public BooleanMutex(){\n        sync = new Sync();\n        set(false);\n    }\n\n    public BooleanMutex(Boolean mutex){\n        sync = new Sync();\n        set(mutex);\n    }\n\n    /**\n     * 阻塞等待Boolean为true\n     * \n     * @throws InterruptedException if the current thread is interrupted\n     */\n    public void get() throws InterruptedException {\n        sync.innerGet();\n    }\n\n    /**\n     * 阻塞等待Boolean为true,允许设置超时时间\n     * \n     * @param timeout\n     * @param unit\n     * @throws InterruptedException\n     * @throws TimeoutException\n     */\n    public void get(long timeout, TimeUnit unit) throws InterruptedException, TimeoutException {\n        sync.innerGet(unit.toNanos(timeout));\n    }\n\n    /**\n     * 重新设置对应的Boolean mutex\n     * \n     * @param mutex\n     */\n    public void set(Boolean mutex) {\n        if (mutex) {\n            sync.innerSetTrue();\n        } else {\n            sync.innerSetFalse();\n        }\n    }\n\n    public boolean state() {\n        return sync.innerState();\n    }\n\n    /**\n     * Synchronization control for BooleanMutex. Uses AQS sync state to\n     * represent run status\n     */\n    private static final class Sync extends AbstractQueuedSynchronizer {\n\n        private static final long serialVersionUID = 2559471934544126329L;\n        /** State value representing that TRUE */\n        private static final int  TRUE             = 1;\n        /** State value representing that FALSE */\n        private static final int  FALSE            = 2;\n\n        private boolean isTrue(int state) {\n            return (state & TRUE) != 0;\n        }\n\n        /**\n         * 实现AQS的接口，获取共享锁的判断\n         */\n        protected int tryAcquireShared(int state) {\n            // 如果为true，直接允许获取锁对象\n            // 如果为false，进入阻塞队列，等待被唤醒\n            return isTrue(getState()) ? 1 : -1;\n        }\n\n        /**\n         * 实现AQS的接口，释放共享锁的判断\n         */\n        protected boolean tryReleaseShared(int ignore) {\n            // 始终返回true，代表可以release\n            return true;\n        }\n\n        boolean innerState() {\n            return isTrue(getState());\n        }\n\n        void innerGet() throws InterruptedException {\n            acquireSharedInterruptibly(0);\n        }\n\n        void innerGet(long nanosTimeout) throws InterruptedException, TimeoutException {\n            if (!tryAcquireSharedNanos(0, nanosTimeout)) throw new TimeoutException();\n        }\n\n        void innerSetTrue() {\n            for (;;) {\n                int s = getState();\n                if (s == TRUE) {\n                    return; // 直接退出\n                }\n                if (compareAndSetState(s, TRUE)) {// cas更新状态，避免并发更新true操作\n                    releaseShared(0);// 释放一下锁对象，唤醒一下阻塞的Thread\n                    return;\n                }\n            }\n        }\n\n        void innerSetFalse() {\n            for (;;) {\n                int s = getState();\n                if (s == FALSE) {\n                    return; // 直接退出\n                }\n                if (compareAndSetState(s, FALSE)) {// cas更新状态，避免并发更新false操作\n                    return;\n                }\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "common/src/main/java/com/alibaba/otter/canal/common/utils/CanalToStringStyle.java",
    "content": "package com.alibaba.otter.canal.common.utils;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\nimport org.apache.commons.lang.builder.ToStringStyle;\n\n/**\n * Otter项目内部使用的ToStringStyle\n * \n * <pre>\n * 默认Style输出格式：\n * Person[name=John Doe,age=33,smoker=false ,time=2010-04-01 00:00:00]\n * </pre>\n * \n * @author jianghang 2010-6-18 上午11:35:27\n */\npublic class CanalToStringStyle extends ToStringStyle {\n\n    private static final long         serialVersionUID = -6568177374288222145L;\n\n    private static final String       DEFAULT_TIME     = \"yyyy-MM-dd HH:mm:ss\";\n    private static final String       DEFAULT_DAY      = \"yyyy-MM-dd\";\n\n    /**\n     * <pre>\n     * 输出格式：\n     * Person[name=John Doe,age=33,smoker=false ,time=2010-04-01 00:00:00]\n     * </pre>\n     */\n    public static final ToStringStyle TIME_STYLE       = new OtterDateStyle(DEFAULT_TIME);\n\n    /**\n     * <pre>\n     * 输出格式：\n     * Person[name=John Doe,age=33,smoker=false ,day=2010-04-01]\n     * </pre>\n     */\n    public static final ToStringStyle DAY_STYLE        = new OtterDateStyle(DEFAULT_DAY);\n\n    /**\n     * <pre>\n     * 输出格式：\n     * Person[name=John Doe,age=33,smoker=false ,time=2010-04-01 00:00:00]\n     * </pre>\n     */\n    public static final ToStringStyle DEFAULT_STYLE    = CanalToStringStyle.TIME_STYLE;\n\n    // =========================== 自定义style =============================\n\n    /**\n     * 支持日期格式化的ToStringStyle\n     * \n     * @author li.jinl\n     */\n    private static class OtterDateStyle extends ToStringStyle {\n\n        private static final long serialVersionUID = 5208917932254652886L;\n\n        // 日期format格式\n        private String            pattern;\n\n        public OtterDateStyle(String pattern){\n            super();\n            this.setUseShortClassName(true);\n            this.setUseIdentityHashCode(false);\n            // 设置日期format格式\n            this.pattern = pattern;\n        }\n\n        protected void appendDetail(StringBuffer buffer, String fieldName, Object value) {\n            // 增加自定义的date对象处理\n            if (value instanceof Date) {\n                value = new SimpleDateFormat(pattern).format(value);\n            }\n            // 后续可以增加其他自定义对象处理\n            buffer.append(value);\n        }\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/com/alibaba/otter/canal/common/utils/CommonUtils.java",
    "content": "package com.alibaba.otter.canal.common.utils;\n\nimport com.alibaba.druid.filter.config.ConfigTools;\n\nimport java.io.File;\n\n/**\n * 通用工具类\n *\n * @author rewerma 2019-01-25 下午05:20:16\n * @version 1.0.0\n */\npublic class CommonUtils {\n\n    /**\n     * 获取conf文件夹所在路径\n     *\n     * @return 路径地址\n     */\n    public static String getConfPath() {\n        String classpath = CommonUtils.class.getResource(\"/\").getPath();\n        String confPath = classpath + \"../conf/\";\n        if (new File(confPath).exists()) {\n            return confPath;\n        } else {\n            return classpath;\n        }\n    }\n\n    /**\n     * 删除文件夹\n     *\n     * @param dirFile 文件夹对象\n     * @return 是否删除成功\n     */\n    public static boolean deleteDir(File dirFile) {\n        if (!dirFile.exists()) {\n            return false;\n        }\n\n        if (dirFile.isFile()) {\n            return dirFile.delete();\n        } else {\n            File[] files = dirFile.listFiles();\n            if (files == null || files.length == 0) {\n                return dirFile.delete();\n            }\n            for (File file : files) {\n                deleteDir(file);\n            }\n        }\n\n        return dirFile.delete();\n    }\n\n    public static String decryptDruidPassword(String publicKeyText, String cipherText) throws Exception {\n        return ConfigTools.decrypt(publicKeyText, cipherText);\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/com/alibaba/otter/canal/common/utils/ExecutorTemplate.java",
    "content": "package com.alibaba.otter.canal.common.utils;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.ThreadPoolExecutor;\n\n/**\n * 多线程执行器模板代码，otter中好多地方都写多线程，比较多的都是重复的逻辑代码，抽象一下做个模板把\n *\n * <pre>\n * 示例代码：\n * ExecutorTemplate template = new ExecutorTemplate(executor);\n * ...\n * try {\n *    for ( ....) {\n *       template.submit(new Runnable() {})\n *    }\n * \n *    List<?> result = template.waitForResult();\n *    // do result\n * } finally {\n *    template.clear();\n * }\n * \n * 注意：该模板工程，不支持多业务并发调用，会出现数据混乱\n * </pre>\n */\npublic class ExecutorTemplate {\n\n    private volatile ThreadPoolExecutor executor = null;\n    private volatile List<Future>       futures  = null;\n\n    public ExecutorTemplate(ThreadPoolExecutor executor){\n        this.futures = Collections.synchronizedList(new ArrayList<>());\n        this.executor = executor;\n    }\n\n    public void submit(Runnable task) {\n        Future future = executor.submit(task, null);\n        futures.add(future);\n        check(future);\n    }\n\n    public void submit(Callable task) {\n        Future future = executor.submit(task);\n        futures.add(future);\n        check(future);\n    }\n\n    private void check(Future future) {\n        if (future.isDone()) {\n            // 立即判断一次，因为使用了CallerRun可能当场跑出结果，针对有异常时快速响应，而不是等跑完所有的才抛异常\n            try {\n                future.get();\n            } catch (Throwable e) {\n                // 取消完之后立马退出\n                cacelAllFutures();\n                throw new RuntimeException(e);\n            }\n        }\n    }\n\n    public synchronized List<?> waitForResult() {\n        List result = new ArrayList();\n        RuntimeException exception = null;\n\n        for (Future future : futures) {\n            try {\n                result.add(future.get());\n            } catch (Throwable e) {\n                exception = new RuntimeException(e);\n                // 如何一个future出现了异常，就退出\n                break;\n            }\n        }\n\n        if (exception != null) {\n            cacelAllFutures();\n            throw exception;\n        } else {\n            return result;\n        }\n    }\n\n    public void cacelAllFutures() {\n        for (Future future : futures) {\n            if (!future.isDone() && !future.isCancelled()) {\n                future.cancel(true);\n            }\n        }\n    }\n\n    public void clear() {\n        futures.clear();\n    }\n\n}\n"
  },
  {
    "path": "common/src/main/java/com/alibaba/otter/canal/common/utils/FileUtils.java",
    "content": "package com.alibaba.otter.canal.common.utils;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.charset.StandardCharsets;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class FileUtils {\n\n    private static final Logger logger = LoggerFactory.getLogger(FileUtils.class);\n\n    public static String readFileFromOffset(String filename, int l, String charset) {\n        return readFileFromOffset(filename, l, charset, 4 * 1024 * 1024);\n    }\n\n    public static String readFileFromOffset(String filename, int l, String charset, int maxSize) {\n        RandomAccessFile rf = null;\n        StringBuilder res = new StringBuilder();\n        try {\n            rf = new RandomAccessFile(filename, \"r\");\n            long fileLength = rf.length();\n            long start = rf.getFilePointer();\n            long readIndex = start + fileLength - 1;\n            long minIndex = readIndex - maxSize;\n            if (minIndex < 0) {\n                minIndex = 0;\n            }\n\n            if (readIndex < 0) {\n                readIndex = 0;\n            }\n            rf.seek(readIndex);\n            int k = 0;\n            int c = -1;\n            String line = null;\n            while (readIndex > start) {\n                if (k == l) {\n                    break;\n                }\n                c = rf.read();\n                String readText = null;\n                if (c == '\\n' || c == '\\r') {\n                    line = rf.readLine();\n                    if (line != null) {\n                        readText = new String(line.getBytes(StandardCharsets.ISO_8859_1), charset);\n                    } else {\n                        if (k != 0) {\n                            res.insert(0, \"\\n\");\n                        }\n                        res.insert(0, \"\");\n                        k++;\n                    }\n                    readIndex--;\n                }\n                readIndex--;\n                if (readIndex < minIndex) {\n                    break;\n                } else {\n                    rf.seek(readIndex);\n                }\n\n                if (readIndex == 0) {\n                    readText = rf.readLine();\n                }\n                if (readText != null) {\n                    if (k != 0) {\n                        res.insert(0, \"\\n\");\n                    }\n                    res.insert(0, readText);\n                    k++;\n                }\n            }\n        } catch (IOException e) {\n            logger.error(e.getMessage(), e);\n        } finally {\n            if (rf != null) {\n                try {\n                    rf.close();\n                } catch (IOException e) {\n                    // ignore\n                }\n                rf = null;\n            }\n        }\n\n        return res.toString();\n    }\n\n    /**\n     * 校验自定义的文件名，是否在允许的基目录范围内，如何合法就返回全路径，否则就直接报错\n     *\n     * @param baseDir\n     * @param destination\n     * @return\n     */\n    public static String validateFileName(String baseDir, String destination) {\n        try {\n            // 验证 destination 是否在允许的基目录范围内\n            String basePath = new File(baseDir).getCanonicalPath();\n            String fullPath = new File(basePath, destination).getCanonicalPath();\n\n            // 检查 fullPath 是否以 basePath 开头\n            if (!fullPath.startsWith(basePath + File.separator)) {\n                throw new IllegalArgumentException(\"Invalid destination path\");\n            }\n\n            return fullPath;\n        } catch (IOException e) {\n            throw new RuntimeException(\"Failed to read file\", e);\n        }\n    }\n\n    public static void main(String[] args) throws IOException {\n        String fullPath = validateFileName(\"/tmp/\", \"1.txt\");\n        System.out.println(fullPath);\n        System.out.println(org.apache.commons.io.FileUtils.readLines(new File(fullPath)));\n\n        fullPath = validateFileName(\"/tmp/\", \"test\");\n        fullPath = validateFileName(fullPath,\"1.txt\");\n        System.out.println(fullPath);\n        System.out.println(org.apache.commons.io.FileUtils.readLines(new File(fullPath)));\n\n\n        fullPath = validateFileName(\"/tmp/\", \"../etc/hosts\");\n        System.out.println(fullPath);\n        System.out.println(org.apache.commons.io.FileUtils.readLines(new File(fullPath)));\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/com/alibaba/otter/canal/common/utils/JsonUtils.java",
    "content": "package com.alibaba.otter.canal.common.utils;\n\nimport java.lang.reflect.Type;\nimport java.net.InetAddress;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport com.alibaba.fastjson2.*;\nimport com.alibaba.fastjson2.filter.Filter;\nimport com.alibaba.fastjson2.filter.PropertyFilter;\nimport com.alibaba.fastjson2.writer.ObjectWriter;\n\n\n/**\n * 字节处理相关工具类\n * \n * @author jianghang\n */\npublic class JsonUtils {\n    static final Filter AUTO_TYPE_FILTER = JSONReader.autoTypeFilter(\n            \"com.alibaba.otter.\",\n            \"com.taobao.tddl.dbsync.\"\n    );\n\n    public static <T> T unmarshalFromByte(byte[] bytes, Class<T> targetClass) {\n        return (T) JSON.parseObject(bytes, targetClass, AUTO_TYPE_FILTER);// 默认为UTF-8\n    }\n\n    public static <T> T unmarshalFromByte(byte[] bytes, TypeReference<T> type) {\n\n        return (T) JSON.parseObject(bytes, type.getType(), AUTO_TYPE_FILTER);\n    }\n\n    public static byte[] marshalToByte(Object obj) {\n        return JSON.toJSONBytes(obj); // 默认为UTF-8\n    }\n\n    public static byte[] marshalToByte(Object obj, JSONWriter.Feature... features) {\n        return JSON.toJSONBytes(obj, features); // 默认为UTF-8\n    }\n\n    public static <T> T unmarshalFromString(String json, Class<T> targetClass) {\n        return (T) JSON.parseObject(json, targetClass, AUTO_TYPE_FILTER);// 默认为UTF-8\n    }\n\n    public static <T> T unmarshalFromString(String json, TypeReference<T> type) {\n        return (T) JSON.parseObject(json, type.getType(), AUTO_TYPE_FILTER);// 默认为UTF-8\n    }\n\n    public static String marshalToString(Object obj) {\n        return JSON.toJSONString(obj); // 默认为UTF-8\n    }\n\n    public static String marshalToString(Object obj, JSONWriter.Feature... features) {\n        return JSON.toJSONString(obj, features); // 默认为UTF-8\n    }\n\n    /**\n     * 可以允许指定一些过滤字段进行生成json对象\n     */\n    public static String marshalToString(Object obj, String... fliterFields) {\n        final List<String> propertyFliters = Arrays.asList(fliterFields);\n\n        return JSON.toJSONString(obj, new PropertyFilter() {\n            @Override\n            public boolean apply(Object object, String name, Object value) {\n                return !propertyFliters.contains(name);\n            }\n        });\n    }\n\n    public static class InetAddressWriter implements ObjectWriter {\n\n        public static InetAddressWriter instance = new InetAddressWriter();\n\n        @Override\n        public void write(JSONWriter jsonWriter, Object object, Object fieldName, Type fieldType, long features) {\n            if (object == null) {\n                jsonWriter.writeNull();\n                return;\n            }\n\n            InetAddress address = (InetAddress) object;\n            // 优先使用name\n            jsonWriter.writeString(address.getHostName());\n        }\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/com/alibaba/otter/canal/common/utils/MQUtil.java",
    "content": "package com.alibaba.otter.canal.common.utils;\n\n\npublic class MQUtil {\n    /**\n     * topic是否是正则表达式\n     *\n     * @param topic\n     * @return true是正则表达式\n     */\n    public static boolean isPatternTopic(String topic) {\n        return !topic.matches(\"^[0-9a-z:/-]+$\");\n    }\n\n    /**\n     * 检查topic有效性\n     *\n     * @param topic\n     * @return\n     */\n    public static boolean checkTopic(String topic) {\n        return topic.matches(\"^[0-9a-z:/.*-]+$\");\n    }\n\n    /**\n     * 检查tag有效性\n     *\n     * @param tag\n     * @return\n     */\n    public static boolean checkTag(String tag) {\n        return tag.matches(\"^[0-9a-zA-Z.*]+$\");\n    }\n\n    /**\n     * 判断tag是否是正则\n     *\n     * @param tag\n     * @return\n     */\n    public static boolean isPatternTag(String tag) {\n        return !tag.matches(\"^[0-9a-zA-Z]+$\");\n    }\n\n    /**\n     * 检查topic有效性\n     *\n     * @param topics\n     */\n    public static void checkTopicWithErr(String... topics) {\n        if (null == topics || 0 == topics.length) {\n            throw new NullPointerException(\"topic cannot null\");\n        }\n\n        if (1 == topics.length) {\n            boolean ok = checkTopic(topics[0]);\n            if (ok) {\n                return;\n            }\n            throw new RuntimeException(\"topic invalid: \" + topics[0]);\n        }\n\n        for (String t : topics) {\n            if (!checkTopic(t)) {\n                throw new IllegalArgumentException(\"topic invalid: \" + t);\n            }\n            if (isPatternTopic(t)) {\n                throw new RuntimeException(\"pattern topic cannot multi: \" + t);\n            }\n        }\n    }\n\n    /**\n     * 检查tag有效性\n     *\n     * @param tags\n     */\n    public static void checkTagWithErr(String... tags) {\n        // 空表示不使用tag\n        if (null == tags || 0 == tags.length) {\n            return;\n        }\n\n//        if (1 == tags.length && (null == tags[0] || 0 == tags[0].trim().length())) {\n//            throw new NullPointerException(\"tag cannot null\");\n//        }\n\n        for (String t : tags) {\n            if (!checkTag(t)) {\n                throw new IllegalArgumentException(\"tag invalid: \" + t);\n            }\n            if (isPatternTag(t)) {\n                throw new RuntimeException(\"pattern tag cannot multi: \" + t);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/com/alibaba/otter/canal/common/utils/NamedThreadFactory.java",
    "content": "package com.alibaba.otter.canal.common.utils;\n\nimport java.lang.Thread.UncaughtExceptionHandler;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * @author zebin.xuzb 2012-9-20 下午3:47:47\n * @version 1.0.0\n */\npublic class NamedThreadFactory implements ThreadFactory {\n\n    private static final Logger           logger                   = LoggerFactory.getLogger(NamedThreadFactory.class);\n    final private static String           DEFAULT_NAME             = \"canal-worker\";\n    final private String                  name;\n    final private boolean                 daemon;\n    final private ThreadGroup             group;\n    final private AtomicInteger           threadNumber             = new AtomicInteger(0);\n    final static UncaughtExceptionHandler uncaughtExceptionHandler = (t, e) -> {\n                                                                        if (e instanceof InterruptedException\n                                                                            || (e.getCause() != null && e.getCause() instanceof InterruptedException)) {\n                                                                            return;\n                                                                        }\n\n                                                                        logger.error(\"from \" + t.getName(), e);\n                                                                    };\n\n    public NamedThreadFactory(){\n        this(DEFAULT_NAME, true);\n    }\n\n    public NamedThreadFactory(String name){\n        this(name, true);\n    }\n\n    public NamedThreadFactory(String name, boolean daemon){\n        this.name = name;\n        this.daemon = daemon;\n        SecurityManager s = System.getSecurityManager();\n        group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();\n    }\n\n    public Thread newThread(Runnable r) {\n        Thread t = new Thread(group, r, name + \"-\" + threadNumber.getAndIncrement(), 0);\n        t.setDaemon(daemon);\n        if (t.getPriority() != Thread.NORM_PRIORITY) {\n            t.setPriority(Thread.NORM_PRIORITY);\n        }\n\n        t.setUncaughtExceptionHandler(uncaughtExceptionHandler);\n        return t;\n    }\n\n}\n"
  },
  {
    "path": "common/src/main/java/com/alibaba/otter/canal/common/utils/PropertiesUtils.java",
    "content": "package com.alibaba.otter.canal.common.utils;\n\n\nimport org.apache.commons.lang.StringUtils;\n\nimport java.util.Properties;\n\npublic class PropertiesUtils {\n    public static String getProperty(Properties properties, String key, String defaultValue) {\n        String value = getProperty(properties, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        } else {\n            return value;\n        }\n    }\n\n    public static String getProperty(Properties properties, String key) {\n        key = StringUtils.trim(key);\n        String value = System.getProperty(key);\n\n        if (value == null) {\n            value = System.getenv(key);\n        }\n\n        if (value == null) {\n            value = properties.getProperty(key);\n        }\n\n        return StringUtils.trim(value);\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/com/alibaba/otter/canal/common/utils/UriUtils.java",
    "content": "package com.alibaba.otter.canal.common.utils;\n\nimport java.io.UnsupportedEncodingException;\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.net.URLDecoder;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Scanner;\n\nimport org.apache.commons.lang.StringUtils;\n\n/**\n * @author zebin.xuzb 2012-11-15 下午3:53:09\n * @since 1.0.0\n */\npublic final class UriUtils {\n\n    private final static String SPLIT            = \"&\";\n    private final static String EQUAL            = \"=\";\n    private final static String DEFAULT_ENCODING = \"ISO_8859_1\";\n\n    private UriUtils(){\n    }\n\n    public static Map<String, String> parseQuery(final String uriString) {\n        URI uri = null;\n        try {\n            uri = new URI(uriString);\n        } catch (URISyntaxException e) {\n            throw new IllegalArgumentException(e);\n        }\n        return parseQuery(uri);\n    }\n\n    public static Map<String, String> parseQuery(final String uriString, final String encoding) {\n        URI uri = null;\n        try {\n            uri = new URI(uriString);\n        } catch (URISyntaxException e) {\n            throw new IllegalArgumentException(e);\n        }\n        return parseQuery(uri, encoding);\n    }\n\n    public static Map<String, String> parseQuery(final URI uri) {\n        return parseQuery(uri, DEFAULT_ENCODING);\n    }\n\n    public static Map<String, String> parseQuery(final URI uri, final String encoding) {\n        if (uri == null || StringUtils.isBlank(uri.getQuery())) {\n            return Collections.EMPTY_MAP;\n        }\n        String query = uri.getRawQuery();\n        HashMap<String, String> params = new HashMap<>();\n        @SuppressWarnings(\"resource\")\n        Scanner scan = new Scanner(query);\n        scan.useDelimiter(SPLIT);\n        while (scan.hasNext()) {\n            String token = scan.next().trim();\n            String[] pair = token.split(EQUAL);\n            String key = decode(pair[0], encoding);\n            String value = null;\n            if (pair.length == 2) {\n                value = decode(pair[1], encoding);\n            }\n            params.put(key, value);\n        }\n        return params;\n    }\n\n    private static String decode(final String content, final String encoding) {\n        try {\n            return URLDecoder.decode(content, encoding != null ? encoding : DEFAULT_ENCODING);\n        } catch (UnsupportedEncodingException e) {\n            throw new IllegalArgumentException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/com/alibaba/otter/canal/common/zookeeper/ByteSerializer.java",
    "content": "package com.alibaba.otter.canal.common.zookeeper;\n\nimport java.io.UnsupportedEncodingException;\n\nimport org.I0Itec.zkclient.exception.ZkMarshallingError;\nimport org.I0Itec.zkclient.serialize.ZkSerializer;\n\n/**\n * 基于string的序列化方式\n * \n * @author jianghang 2012-7-11 下午02:57:09\n * @version 1.0.0\n */\npublic class ByteSerializer implements ZkSerializer {\n\n    public Object deserialize(final byte[] bytes) throws ZkMarshallingError {\n        return bytes;\n    }\n\n    public byte[] serialize(final Object data) throws ZkMarshallingError {\n        try {\n            if (data instanceof byte[]) {\n                return (byte[]) data;\n            } else {\n                return ((String) data).getBytes(\"utf-8\");\n            }\n        } catch (final UnsupportedEncodingException e) {\n            throw new ZkMarshallingError(e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "common/src/main/java/com/alibaba/otter/canal/common/zookeeper/StringSerializer.java",
    "content": "package com.alibaba.otter.canal.common.zookeeper;\n\nimport java.io.UnsupportedEncodingException;\n\nimport org.I0Itec.zkclient.exception.ZkMarshallingError;\nimport org.I0Itec.zkclient.serialize.ZkSerializer;\n\n/**\n * 基于string的序列化方式\n * \n * @author jianghang 2012-7-11 下午02:57:09\n * @version 1.0.0\n */\npublic class StringSerializer implements ZkSerializer {\n\n    public Object deserialize(final byte[] bytes) throws ZkMarshallingError {\n        try {\n            return new String(bytes, \"utf-8\");\n        } catch (final UnsupportedEncodingException e) {\n            throw new ZkMarshallingError(e);\n        }\n    }\n\n    public byte[] serialize(final Object data) throws ZkMarshallingError {\n        try {\n            return ((String) data).getBytes(\"utf-8\");\n        } catch (final UnsupportedEncodingException e) {\n            throw new ZkMarshallingError(e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "common/src/main/java/com/alibaba/otter/canal/common/zookeeper/ZkClientx.java",
    "content": "package com.alibaba.otter.canal.common.zookeeper;\n\nimport java.util.Map;\n\nimport org.I0Itec.zkclient.IZkConnection;\nimport org.I0Itec.zkclient.ZkClient;\nimport org.I0Itec.zkclient.exception.ZkException;\nimport org.I0Itec.zkclient.exception.ZkInterruptedException;\nimport org.I0Itec.zkclient.exception.ZkNoNodeException;\nimport org.I0Itec.zkclient.exception.ZkNodeExistsException;\nimport org.I0Itec.zkclient.serialize.ZkSerializer;\nimport org.apache.zookeeper.CreateMode;\n\nimport com.google.common.collect.MigrateMap;\n\n/**\n * 使用自定义的ZooKeeperx for zk connection\n *\n * @author jianghang 2012-7-10 下午02:31:15\n * @version 1.0.0\n */\npublic class ZkClientx extends ZkClient {\n\n    // 对于zkclient进行一次缓存，避免一个jvm内部使用多个zk connection\n    private static Map<String, ZkClientx> clients = MigrateMap.makeComputingMap(ZkClientx::new);\n\n    public static ZkClientx getZkClient(String servers) {\n        return clients.get(servers);\n    }\n\n    public static void clearClients() {\n        clients.clear();\n    }\n\n    public ZkClientx(String serverstring){\n        this(serverstring, Integer.MAX_VALUE);\n    }\n\n    public ZkClientx(String zkServers, int connectionTimeout){\n        this(new ZooKeeperx(zkServers), connectionTimeout);\n    }\n\n    public ZkClientx(String zkServers, int sessionTimeout, int connectionTimeout){\n        this(new ZooKeeperx(zkServers, sessionTimeout), connectionTimeout);\n    }\n\n    public ZkClientx(String zkServers, int sessionTimeout, int connectionTimeout, ZkSerializer zkSerializer){\n        this(new ZooKeeperx(zkServers, sessionTimeout), connectionTimeout, zkSerializer);\n    }\n\n    private ZkClientx(IZkConnection connection, int connectionTimeout){\n        this(connection, connectionTimeout, new ByteSerializer());\n    }\n\n    private ZkClientx(IZkConnection zkConnection, int connectionTimeout, ZkSerializer zkSerializer){\n        super(zkConnection, connectionTimeout, zkSerializer);\n    }\n\n    /**\n     * Create a persistent Sequential node.\n     *\n     * @param path\n     * @param createParents if true all parent dirs are created as well and no\n     * {@link ZkNodeExistsException} is thrown in case the path already exists\n     * @throws ZkInterruptedException if operation was interrupted, or a\n     * required reconnection got interrupted\n     * @throws IllegalArgumentException if called from anything except the\n     * ZooKeeper event thread\n     * @throws ZkException if any ZooKeeper exception occurred\n     * @throws RuntimeException if any other exception occurs\n     */\n    public String createPersistentSequential(String path, boolean createParents) throws ZkInterruptedException,\n                                                                                IllegalArgumentException, ZkException,\n                                                                                RuntimeException {\n        try {\n            return create(path, null, CreateMode.PERSISTENT_SEQUENTIAL);\n        } catch (ZkNoNodeException e) {\n            if (!createParents) {\n                throw e;\n            }\n            String parentDir = path.substring(0, path.lastIndexOf('/'));\n            createPersistent(parentDir, createParents);\n            return createPersistentSequential(path, createParents);\n        }\n    }\n\n    /**\n     * Create a persistent Sequential node.\n     *\n     * @param path\n     * @param data\n     * @param createParents if true all parent dirs are created as well and no\n     * {@link ZkNodeExistsException} is thrown in case the path already exists\n     * @throws ZkInterruptedException if operation was interrupted, or a\n     * required reconnection got interrupted\n     * @throws IllegalArgumentException if called from anything except the\n     * ZooKeeper event thread\n     * @throws ZkException if any ZooKeeper exception occurred\n     * @throws RuntimeException if any other exception occurs\n     */\n    public String createPersistentSequential(String path, Object data, boolean createParents)\n                                                                                             throws ZkInterruptedException,\n                                                                                             IllegalArgumentException,\n                                                                                             ZkException,\n                                                                                             RuntimeException {\n        try {\n            return create(path, data, CreateMode.PERSISTENT_SEQUENTIAL);\n        } catch (ZkNoNodeException e) {\n            if (!createParents) {\n                throw e;\n            }\n            String parentDir = path.substring(0, path.lastIndexOf('/'));\n            createPersistent(parentDir, createParents);\n            return createPersistentSequential(path, data, createParents);\n        }\n    }\n\n    /**\n     * Create a persistent Sequential node.\n     *\n     * @param path\n     * @param data\n     * @param createParents if true all parent dirs are created as well and no\n     * {@link ZkNodeExistsException} is thrown in case the path already exists\n     * @throws ZkInterruptedException if operation was interrupted, or a\n     * required reconnection got interrupted\n     * @throws IllegalArgumentException if called from anything except the\n     * ZooKeeper event thread\n     * @throws ZkException if any ZooKeeper exception occurred\n     * @throws RuntimeException if any other exception occurs\n     */\n    public void createPersistent(String path, Object data, boolean createParents) throws ZkInterruptedException,\n                                                                                 IllegalArgumentException, ZkException,\n                                                                                 RuntimeException {\n        try {\n            create(path, data, CreateMode.PERSISTENT);\n        } catch (ZkNodeExistsException e) {\n            if (!createParents) {\n                throw e;\n            }\n        } catch (ZkNoNodeException e) {\n            if (!createParents) {\n                throw e;\n            }\n            String parentDir = path.substring(0, path.lastIndexOf('/'));\n            createPersistent(parentDir, createParents);\n            createPersistent(path, data, createParents);\n        }\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/com/alibaba/otter/canal/common/zookeeper/ZooKeeperx.java",
    "content": "package com.alibaba.otter.canal.common.zookeeper;\n\nimport java.io.IOException;\nimport java.lang.reflect.Field;\nimport java.net.InetSocketAddress;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\n\nimport org.I0Itec.zkclient.ZkConnection;\nimport org.I0Itec.zkclient.exception.ZkException;\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.zookeeper.ClientCnxn;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.client.ConnectStringParser;\nimport org.apache.zookeeper.client.HostProvider;\nimport org.apache.zookeeper.client.StaticHostProvider;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * 封装了ZooKeeper，使其支持节点的优先顺序，比如美国机房的节点会优先加载美国对应的zk集群列表，都失败后才会选择加载杭州的zk集群列表 *\n * \n * @author jianghang 2012-7-10 下午02:31:42\n * @version 1.0.0\n */\npublic class ZooKeeperx extends ZkConnection {\n\n    private static final String SERVER_COMMA            = \";\";\n    private static final Logger logger                  = LoggerFactory.getLogger(ZooKeeperx.class);\n    private static final Field  clientCnxnField         = ReflectionUtils.findField(ZooKeeper.class, \"cnxn\");\n    private static final Field  hostProviderField       = ReflectionUtils.findField(ClientCnxn.class, \"hostProvider\");\n    private static final Field  serverAddressesField    = ReflectionUtils.findField(StaticHostProvider.class,\n                                                            \"serverAddresses\");\n    private static final Field  zookeeperLockField      = ReflectionUtils.findField(ZkConnection.class,\n                                                            \"_zookeeperLock\");\n    private static final Field  zookeeperFiled          = ReflectionUtils.findField(ZkConnection.class, \"_zk\");\n    private static final int    DEFAULT_SESSION_TIMEOUT = 90000;\n\n    private final List<String>  _serversList;\n    private final int           _sessionTimeOut;\n\n    public ZooKeeperx(String zkServers){\n        this(zkServers, DEFAULT_SESSION_TIMEOUT);\n    }\n\n    public ZooKeeperx(String zkServers, int sessionTimeOut){\n        super(zkServers, sessionTimeOut);\n        _serversList = Arrays.asList(StringUtils.split(this.getServers(), SERVER_COMMA));\n        _sessionTimeOut = sessionTimeOut;\n    }\n\n    @Override\n    public void connect(Watcher watcher) {\n        ReflectionUtils.makeAccessible(zookeeperLockField);\n        ReflectionUtils.makeAccessible(zookeeperFiled);\n        Lock _zookeeperLock = (ReentrantLock) ReflectionUtils.getField(zookeeperLockField, this);\n        ZooKeeper _zk = (ZooKeeper) ReflectionUtils.getField(zookeeperFiled, this);\n\n        _zookeeperLock.lock();\n        try {\n            if (_zk != null) {\n                throw new IllegalStateException(\"zk client has already been started\");\n            }\n            String zkServers = _serversList.get(0);\n\n            try {\n                logger.debug(\"Creating new ZookKeeper instance to connect to \" + zkServers + \".\");\n                _zk = new ZooKeeper(zkServers, _sessionTimeOut, watcher);\n                configMutliCluster(_zk);\n                ReflectionUtils.setField(zookeeperFiled, this, _zk);\n            } catch (IOException e) {\n                throw new ZkException(\"Unable to connect to \" + zkServers, e);\n            }\n        } finally {\n            _zookeeperLock.unlock();\n        }\n    }\n\n    // ===============================\n\n    public void configMutliCluster(ZooKeeper zk) {\n        if (_serversList.size() == 1) {\n            return;\n        }\n        String cluster1 = _serversList.get(0);\n        try {\n            if (_serversList.size() > 1) {\n                // 强制的声明accessible\n                ReflectionUtils.makeAccessible(clientCnxnField);\n                ReflectionUtils.makeAccessible(hostProviderField);\n                ReflectionUtils.makeAccessible(serverAddressesField);\n\n                // 添加第二组集群列表\n                for (int i = 1; i < _serversList.size(); i++) {\n                    String cluster = _serversList.get(i);\n                    // 强制获取zk中的地址信息\n                    ClientCnxn cnxn = (ClientCnxn) ReflectionUtils.getField(clientCnxnField, zk);\n                    HostProvider hostProvider = (HostProvider) ReflectionUtils.getField(hostProviderField, cnxn);\n                    List<InetSocketAddress> serverAddrs = (List<InetSocketAddress>) ReflectionUtils.getField(serverAddressesField,\n                        hostProvider);\n                    // 添加第二组集群列表\n                    serverAddrs.addAll(new ConnectStringParser(cluster).getServerAddresses());\n                }\n            }\n        } catch (Exception e) {\n            try {\n                if (zk != null) {\n                    zk.close();\n                }\n            } catch (InterruptedException ie) {\n                // ignore interrupt\n            }\n            throw new ZkException(\"zookeeper_create_error, serveraddrs=\" + cluster1, e);\n        }\n\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/com/alibaba/otter/canal/common/zookeeper/ZookeeperPathUtils.java",
    "content": "package com.alibaba.otter.canal.common.zookeeper;\r\n\r\nimport java.text.MessageFormat;\r\n\r\nimport org.apache.commons.lang.StringUtils;\r\n\r\n/**\r\n * 存储结构：\r\n * \r\n * <pre>\r\n * /otter\r\n *    canal\r\n *      cluster\r\n *      destinations\r\n *        dest1\r\n *          running (EPHEMERAL) \r\n *          cluster\r\n *          client1\r\n *            running (EPHEMERAL)\r\n *            cluster\r\n *            filter\r\n *            cursor\r\n *            mark\r\n *              1\r\n *              2\r\n *              3\r\n * </pre>\r\n * \r\n * @author zebin.xuzb @ 2012-6-21\r\n * @version 1.0.0\r\n */\r\npublic class ZookeeperPathUtils {\r\n\r\n    public static final String ZOOKEEPER_SEPARATOR                          = \"/\";\r\n\r\n    public static final String OTTER_ROOT_NODE                              = ZOOKEEPER_SEPARATOR + \"otter\";\r\n\r\n    public static final String CANAL_ROOT_NODE                              = OTTER_ROOT_NODE + ZOOKEEPER_SEPARATOR\r\n                                                                              + \"canal\";\r\n\r\n    public static final String DESTINATION_ROOT_NODE                        = CANAL_ROOT_NODE + ZOOKEEPER_SEPARATOR\r\n                                                                              + \"destinations\";\r\n\r\n    public static final String FILTER_NODE                                  = \"filter\";\r\n\r\n    public static final String BATCH_MARK_NODE                              = \"mark\";\r\n\r\n    public static final String PARSE_NODE                                   = \"parse\";\r\n\r\n    public static final String CURSOR_NODE                                  = \"cursor\";\r\n\r\n    public static final String RUNNING_NODE                                 = \"running\";\r\n\r\n    public static final String CLUSTER_NODE                                 = \"cluster\";\r\n\r\n    public static final String DESTINATION_NODE                             = DESTINATION_ROOT_NODE\r\n                                                                              + ZOOKEEPER_SEPARATOR + \"{0}\";\r\n\r\n    public static final String DESTINATION_PARSE_NODE                       = DESTINATION_NODE + ZOOKEEPER_SEPARATOR\r\n                                                                              + PARSE_NODE;\r\n\r\n    public static final String DESTINATION_CLIENTID_NODE                    = DESTINATION_NODE + ZOOKEEPER_SEPARATOR\r\n                                                                              + \"{1}\";\r\n\r\n    public static final String DESTINATION_CURSOR_NODE                      = DESTINATION_CLIENTID_NODE\r\n                                                                              + ZOOKEEPER_SEPARATOR + CURSOR_NODE;\r\n\r\n    public static final String DESTINATION_CLIENTID_FILTER_NODE             = DESTINATION_CLIENTID_NODE\r\n                                                                              + ZOOKEEPER_SEPARATOR + FILTER_NODE;\r\n\r\n    public static final String DESTINATION_CLIENTID_BATCH_MARK_NODE         = DESTINATION_CLIENTID_NODE\r\n                                                                              + ZOOKEEPER_SEPARATOR + BATCH_MARK_NODE;\r\n\r\n    public static final String DESTINATION_CLIENTID_BATCH_MARK_WITH_ID_PATH = DESTINATION_CLIENTID_BATCH_MARK_NODE\r\n                                                                              + ZOOKEEPER_SEPARATOR + \"{2}\";\r\n\r\n    /**\r\n     * 服务端当前正在提供服务的running节点\r\n     */\r\n    public static final String DESTINATION_RUNNING_NODE                     = DESTINATION_NODE + ZOOKEEPER_SEPARATOR\r\n                                                                              + RUNNING_NODE;\r\n\r\n    /**\r\n     * 客户端当前正在工作的running节点\r\n     */\r\n    public static final String DESTINATION_CLIENTID_RUNNING_NODE            = DESTINATION_CLIENTID_NODE\r\n                                                                              + ZOOKEEPER_SEPARATOR + RUNNING_NODE;\r\n\r\n    /**\r\n     * 整个canal server的集群列表\r\n     */\r\n    public static final String CANAL_CLUSTER_ROOT_NODE                      = CANAL_ROOT_NODE + ZOOKEEPER_SEPARATOR\r\n                                                                              + CLUSTER_NODE;\r\n\r\n    public static final String CANAL_CLUSTER_NODE                           = CANAL_CLUSTER_ROOT_NODE\r\n                                                                              + ZOOKEEPER_SEPARATOR + \"{0}\";\r\n\r\n    /**\r\n     * 针对某个destination的工作的集群列表\r\n     */\r\n    public static final String DESTINATION_CLUSTER_ROOT                     = DESTINATION_NODE + ZOOKEEPER_SEPARATOR\r\n                                                                              + CLUSTER_NODE;\r\n    public static final String DESTINATION_CLUSTER_NODE                     = DESTINATION_CLUSTER_ROOT\r\n                                                                              + ZOOKEEPER_SEPARATOR + \"{1}\";\r\n\r\n    public static String getDestinationPath(String destinationName) {\r\n        return MessageFormat.format(DESTINATION_NODE, destinationName);\r\n    }\r\n\r\n    public static String getClientIdNodePath(String destinationName, short clientId) {\r\n        return MessageFormat.format(DESTINATION_CLIENTID_NODE, destinationName, String.valueOf(clientId));\r\n    }\r\n\r\n    public static String getFilterPath(String destinationName, short clientId) {\r\n        return MessageFormat.format(DESTINATION_CLIENTID_FILTER_NODE, destinationName, String.valueOf(clientId));\r\n    }\r\n\r\n    public static String getBatchMarkPath(String destinationName, short clientId) {\r\n        return MessageFormat.format(DESTINATION_CLIENTID_BATCH_MARK_NODE, destinationName, String.valueOf(clientId));\r\n    }\r\n\r\n    public static String getBatchMarkWithIdPath(String destinationName, short clientId, Long batchId) {\r\n        return MessageFormat.format(DESTINATION_CLIENTID_BATCH_MARK_WITH_ID_PATH,\r\n            destinationName,\r\n            String.valueOf(clientId),\r\n            getBatchMarkNode(batchId));\r\n    }\r\n\r\n    public static String getCursorPath(String destination, short clientId) {\r\n        return MessageFormat.format(DESTINATION_CURSOR_NODE, destination, String.valueOf(clientId));\r\n    }\r\n\r\n    public static String getCanalClusterNode(String node) {\r\n        return MessageFormat.format(CANAL_CLUSTER_NODE, node);\r\n    }\r\n\r\n    /**\r\n     * 服务端当前正在提供服务的running节点\r\n     */\r\n    public static String getDestinationServerRunning(String destination) {\r\n        return MessageFormat.format(DESTINATION_RUNNING_NODE, destination);\r\n    }\r\n\r\n    /**\r\n     * 客户端当前正在工作的running节点\r\n     */\r\n    public static String getDestinationClientRunning(String destination, short clientId) {\r\n        return MessageFormat.format(DESTINATION_CLIENTID_RUNNING_NODE, destination, String.valueOf(clientId));\r\n    }\r\n\r\n    public static String getDestinationClusterNode(String destination, String node) {\r\n        return MessageFormat.format(DESTINATION_CLUSTER_NODE, destination, node);\r\n    }\r\n\r\n    public static String getDestinationClusterRoot(String destination) {\r\n        return MessageFormat.format(DESTINATION_CLUSTER_ROOT, destination);\r\n    }\r\n\r\n    public static String getParsePath(String destination) {\r\n        return MessageFormat.format(DESTINATION_PARSE_NODE, destination);\r\n    }\r\n\r\n    /**\r\n     * 将batchNode转换为Long\r\n     */\r\n    public static short getClientId(String clientNode) {\r\n        return Short.valueOf(clientNode);\r\n    }\r\n\r\n    /**\r\n     * 将batchNode转换为Long\r\n     */\r\n    public static long getBatchMarkId(String batchMarkNode) {\r\n        return Long.valueOf(batchMarkNode);\r\n    }\r\n\r\n    /**\r\n     * 将batchId转化为zookeeper中的node名称\r\n     */\r\n    public static String getBatchMarkNode(Long batchId) {\r\n        return StringUtils.leftPad(String.valueOf(batchId.intValue()), 10, '0');\r\n    }\r\n}\r\n"
  },
  {
    "path": "common/src/main/java/com/alibaba/otter/canal/common/zookeeper/running/ServerRunningData.java",
    "content": "package com.alibaba.otter.canal.common.zookeeper.running;\n\nimport java.io.Serializable;\n\nimport org.apache.commons.lang.builder.ToStringBuilder;\n\nimport com.alibaba.otter.canal.common.utils.CanalToStringStyle;\n\n/**\n * 服务端running状态信息\n * \n * @author jianghang 2012-11-22 下午03:11:30\n * @version 1.0.0\n */\npublic class ServerRunningData implements Serializable {\n\n    private static final long serialVersionUID = 92260481691855281L;\n\n    @Deprecated\n    private Long              cid;\n    private String            address;\n    private boolean           active           = true;\n\n    public ServerRunningData(){\n    }\n\n    public ServerRunningData(String address){\n        this.address = address;\n    }\n\n    public Long getCid() {\n        return cid;\n    }\n\n    public void setCid(Long cid) {\n        this.cid = cid;\n    }\n\n    public String getAddress() {\n        return address;\n    }\n\n    public void setAddress(String address) {\n        this.address = address;\n    }\n\n    public boolean isActive() {\n        return active;\n    }\n\n    public void setActive(boolean active) {\n        this.active = active;\n    }\n\n    public String toString() {\n        return ToStringBuilder.reflectionToString(this, CanalToStringStyle.DEFAULT_STYLE);\n    }\n\n}\n"
  },
  {
    "path": "common/src/main/java/com/alibaba/otter/canal/common/zookeeper/running/ServerRunningListener.java",
    "content": "package com.alibaba.otter.canal.common.zookeeper.running;\n\n/**\n * 触发一下mainstem发生切换\n * \n * @author jianghang 2012-9-11 下午02:26:03\n * @version 1.0.0\n */\npublic interface ServerRunningListener {\n\n    /**\n     * 启动时回调做点事情\n     */\n    public void processStart();\n\n    /**\n     * 关闭时回调做点事情\n     */\n    public void processStop();\n\n    /**\n     * 触发现在轮到自己做为active，需要载入上一个active的上下文数据\n     */\n    public void processActiveEnter();\n\n    /**\n     * 触发一下当前active模式失败\n     */\n    public void processActiveExit();\n\n}\n"
  },
  {
    "path": "common/src/main/java/com/alibaba/otter/canal/common/zookeeper/running/ServerRunningMonitor.java",
    "content": "package com.alibaba.otter.canal.common.zookeeper.running;\n\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\n\nimport org.I0Itec.zkclient.IZkDataListener;\nimport org.I0Itec.zkclient.exception.ZkException;\nimport org.I0Itec.zkclient.exception.ZkInterruptedException;\nimport org.I0Itec.zkclient.exception.ZkNoNodeException;\nimport org.I0Itec.zkclient.exception.ZkNodeExistsException;\nimport org.apache.zookeeper.CreateMode;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.slf4j.MDC;\n\nimport com.alibaba.otter.canal.common.AbstractCanalLifeCycle;\nimport com.alibaba.otter.canal.common.utils.BooleanMutex;\nimport com.alibaba.otter.canal.common.utils.JsonUtils;\nimport com.alibaba.otter.canal.common.zookeeper.ZkClientx;\nimport com.alibaba.otter.canal.common.zookeeper.ZookeeperPathUtils;\n\n/**\n * 针对server的running节点控制\n * \n * @author jianghang 2012-11-22 下午02:59:42\n * @version 1.0.0\n */\npublic class ServerRunningMonitor extends AbstractCanalLifeCycle {\n\n    private static final Logger        logger       = LoggerFactory.getLogger(ServerRunningMonitor.class);\n    private ZkClientx                  zkClient;\n    private String                     destination;\n    private IZkDataListener            dataListener;\n    private BooleanMutex               mutex        = new BooleanMutex(false);\n    private volatile boolean           release      = false;\n    // 当前服务节点状态信息\n    private ServerRunningData          serverData;\n    // 当前实际运行的节点状态信息\n    private volatile ServerRunningData activeData;\n    private ScheduledExecutorService   delayExecutor;\n    private int                        delayTime    = 5;\n    private ServerRunningListener      listener;\n\n    public ServerRunningMonitor(ServerRunningData serverData){\n        this();\n        this.serverData = serverData;\n    }\n\n    public ServerRunningMonitor(){\n        // 创建父节点\n        dataListener = new IZkDataListener() {\n\n            public void handleDataChange(String dataPath, Object data) throws Exception {\n                MDC.put(\"destination\", destination);\n                ServerRunningData runningData = JsonUtils.unmarshalFromByte((byte[]) data, ServerRunningData.class);\n                if (!isMine(runningData.getAddress())) {\n                    mutex.set(false);\n                }\n\n                if (!runningData.isActive() && isMine(runningData.getAddress())) { // 说明出现了主动释放的操作，并且本机之前是active\n                    releaseRunning();// 彻底释放mainstem\n                }\n\n                activeData = (ServerRunningData) runningData;\n            }\n\n            public void handleDataDeleted(String dataPath) throws Exception {\n                MDC.put(\"destination\", destination);\n                mutex.set(false);\n                if (!release && activeData != null && isMine(activeData.getAddress())) {\n                    // 如果上一次active的状态就是本机，则即时触发一下active抢占\n                    initRunning();\n                } else {\n                    // 否则就是等待delayTime，避免因网络瞬端或者zk异常，导致出现频繁的切换操作\n                    delayExecutor.schedule(() -> initRunning(), delayTime, TimeUnit.SECONDS);\n                }\n            }\n\n        };\n\n    }\n\n    public void init() {\n        processStart();\n    }\n\n    public synchronized void start() {\n        super.start();\n        try {\n            processStart();\n            if (zkClient != null) {\n                delayExecutor = Executors.newScheduledThreadPool(1);\n                // 如果需要尽可能释放instance资源，不需要监听running节点，不然即使stop了这台机器，另一台机器立马会start\n                String path = ZookeeperPathUtils.getDestinationServerRunning(destination);\n                zkClient.subscribeDataChanges(path, dataListener);\n\n                initRunning();\n            } else {\n                processActiveEnter();// 没有zk，直接启动\n            }\n        } catch (Exception e) {\n            logger.error(\"start failed\", e);\n            // 没有正常启动，重置一下状态，避免干扰下一次start\n            stop();\n        }\n\n    }\n\n    public boolean release() {\n        if (zkClient != null) {\n            releaseRunning(); // 尝试一下release\n            return true;\n        } else {\n            processActiveExit(); // 没有zk，直接退出\n            return false;\n        }\n    }\n\n    public synchronized void stop() {\n        super.stop();\n\n        if (zkClient != null) {\n            String path = ZookeeperPathUtils.getDestinationServerRunning(destination);\n            zkClient.unsubscribeDataChanges(path, dataListener);\n            if (delayExecutor != null) {\n                delayExecutor.shutdown();\n                delayExecutor = null;\n            }\n\n            releaseRunning(); // 尝试一下release\n        } else {\n            processActiveExit(); // 没有zk，直接启动\n        }\n        processStop();\n    }\n\n    private void initRunning() {\n        if (!isStart()) {\n            return;\n        }\n\n        String path = ZookeeperPathUtils.getDestinationServerRunning(destination);\n        // 序列化\n        byte[] bytes = JsonUtils.marshalToByte(serverData);\n        try {\n            mutex.set(false);\n            zkClient.create(path, bytes, CreateMode.EPHEMERAL);\n            activeData = serverData;\n            processActiveEnter();// 触发一下事件\n            mutex.set(true);\n            release = false;\n        } catch (ZkNodeExistsException e) {\n            bytes = zkClient.readData(path, true);\n            if (bytes == null) {// 如果不存在节点，立即尝试一次\n                initRunning();\n            } else {\n                activeData = JsonUtils.unmarshalFromByte(bytes, ServerRunningData.class);\n            }\n        } catch (ZkNoNodeException e) {\n            zkClient.createPersistent(ZookeeperPathUtils.getDestinationPath(destination), true); // 尝试创建父节点\n            initRunning();\n        }\n    }\n\n    /**\n     * 阻塞等待自己成为active，如果自己成为active，立马返回\n     * \n     * @throws InterruptedException\n     */\n    public void waitForActive() throws InterruptedException {\n        initRunning();\n        mutex.get();\n    }\n\n    /**\n     * 检查当前的状态\n     */\n    public boolean check() {\n        String path = ZookeeperPathUtils.getDestinationServerRunning(destination);\n        try {\n            byte[] bytes = zkClient.readData(path);\n            ServerRunningData eventData = JsonUtils.unmarshalFromByte(bytes, ServerRunningData.class);\n            activeData = eventData;// 更新下为最新值\n            // 检查下nid是否为自己\n            boolean result = isMine(activeData.getAddress());\n            if (!result) {\n                logger.warn(\"canal is running in node[{}] , but not in node[{}]\",\n                    activeData.getAddress(),\n                    serverData.getAddress());\n            }\n            return result;\n        } catch (ZkNoNodeException e) {\n            logger.warn(\"canal is not run any in node\");\n            return false;\n        } catch (ZkInterruptedException e) {\n            logger.warn(\"canal check is interrupt\");\n            Thread.interrupted();// 清除interrupt标记\n            return check();\n        } catch (ZkException e) {\n            logger.warn(\"canal check is failed\");\n            return false;\n        }\n    }\n\n    private boolean releaseRunning() {\n        if (check()) {\n            release = true;\n            String path = ZookeeperPathUtils.getDestinationServerRunning(destination);\n            zkClient.delete(path);\n            mutex.set(false);\n            processActiveExit();\n            return true;\n        }\n\n        return false;\n    }\n\n    // ====================== helper method ======================\n\n    private boolean isMine(String address) {\n        return address.equals(serverData.getAddress());\n    }\n\n    private void processStart() {\n        if (listener != null) {\n            try {\n                listener.processStart();\n            } catch (Exception e) {\n                logger.error(\"processStart failed\", e);\n            }\n        }\n    }\n\n    private void processStop() {\n        if (listener != null) {\n            try {\n                listener.processStop();\n            } catch (Exception e) {\n                logger.error(\"processStop failed\", e);\n            }\n        }\n    }\n\n    private void processActiveEnter() {\n        if (listener != null) {\n            listener.processActiveEnter();\n        }\n    }\n\n    private void processActiveExit() {\n        if (listener != null) {\n            try {\n                listener.processActiveExit();\n            } catch (Exception e) {\n                logger.error(\"processActiveExit failed\", e);\n            }\n        }\n    }\n\n    public void setListener(ServerRunningListener listener) {\n        this.listener = listener;\n    }\n\n    // ===================== setter / getter =======================\n\n    public void setDelayTime(int delayTime) {\n        this.delayTime = delayTime;\n    }\n\n    public void setServerData(ServerRunningData serverData) {\n        this.serverData = serverData;\n    }\n\n    public void setDestination(String destination) {\n        this.destination = destination;\n    }\n\n    public void setZkClient(ZkClientx zkClient) {\n        this.zkClient = zkClient;\n    }\n\n}\n"
  },
  {
    "path": "common/src/main/java/com/alibaba/otter/canal/common/zookeeper/running/ServerRunningMonitors.java",
    "content": "package com.alibaba.otter.canal.common.zookeeper.running;\n\nimport java.util.Map;\n\n/**\n * {@linkplain ServerRunningMonitor}管理容器，使用static进行数据全局共享\n * \n * @author jianghang 2012-12-3 下午09:32:06\n * @version 1.0.0\n */\npublic class ServerRunningMonitors {\n\n    private static ServerRunningData serverData;\n    private static Map               runningMonitors; // <String,\n                                                      // ServerRunningMonitor>\n\n    public static ServerRunningData getServerData() {\n        return serverData;\n    }\n\n    public static Map<String, ServerRunningMonitor> getRunningMonitors() {\n        return runningMonitors;\n    }\n\n    public static ServerRunningMonitor getRunningMonitor(String destination) {\n        return (ServerRunningMonitor) runningMonitors.get(destination);\n    }\n\n    public static void setServerData(ServerRunningData serverData) {\n        ServerRunningMonitors.serverData = serverData;\n    }\n\n    public static void setRunningMonitors(Map runningMonitors) {\n        ServerRunningMonitors.runningMonitors = runningMonitors;\n    }\n\n}\n"
  },
  {
    "path": "common/src/main/java/com/google/common/collect/MigrateMap.java",
    "content": "package com.google.common.collect;\n\nimport java.util.Collection;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.ExecutionException;\n\nimport com.google.common.base.Function;\nimport com.google.common.cache.CacheBuilder;\nimport com.google.common.cache.CacheLoader;\nimport com.google.common.cache.LoadingCache;\n\npublic class MigrateMap {\n\n    public static <K, V> ConcurrentMap<K, V> makeComputingMap(CacheBuilder<Object, Object> builder,\n                                                              Function<? super K, ? extends V> computingFunction) {\n        final Function<? super K, ? extends V> function = computingFunction;\n        LoadingCache<K, V> computingCache = builder.build(new CacheLoader<K, V>() {\n\n            @Override\n            public V load(K key) throws Exception {\n                return function.apply(key);\n            }\n        });\n\n        return new MigrateConcurrentMap<>(computingCache);\n    }\n\n    public static <K, V> ConcurrentMap<K, V> makeComputingMap(Function<? super K, ? extends V> computingFunction) {\n        return makeComputingMap(CacheBuilder.newBuilder(), computingFunction);\n    }\n\n    final static class MigrateConcurrentMap<K, V> implements ConcurrentMap<K, V> {\n\n        private final LoadingCache<K, V>  computingCache;\n\n        private final ConcurrentMap<K, V> cacheView;\n\n        MigrateConcurrentMap(LoadingCache<K, V> computingCache){\n            this.computingCache = computingCache;\n            this.cacheView = computingCache.asMap();\n        }\n\n        @Override\n        public int size() {\n            return cacheView.size();\n        }\n\n        @Override\n        public boolean isEmpty() {\n            return cacheView.isEmpty();\n        }\n\n        @Override\n        public boolean containsKey(Object key) {\n            return cacheView.containsKey(key);\n        }\n\n        @Override\n        public boolean containsValue(Object value) {\n            return cacheView.containsValue(value);\n        }\n\n        @Override\n        public V get(Object key) {\n            try {\n                return computingCache.get((K) key);\n            } catch (ExecutionException e) {\n                throw new RuntimeException(e);\n            }\n        }\n\n        @Override\n        public V put(K key, V value) {\n            return cacheView.put(key, value);\n        }\n\n        @Override\n        public V remove(Object key) {\n            return cacheView.remove(key);\n        }\n\n        @Override\n        public void putAll(Map<? extends K, ? extends V> m) {\n            cacheView.putAll(m);\n        }\n\n        @Override\n        public void clear() {\n            cacheView.clear();\n        }\n\n        @Override\n        public Set<K> keySet() {\n            return cacheView.keySet();\n        }\n\n        @Override\n        public Collection<V> values() {\n            return cacheView.values();\n        }\n\n        @Override\n        public Set<Entry<K, V>> entrySet() {\n            return cacheView.entrySet();\n        }\n\n        @Override\n        public V putIfAbsent(K key, V value) {\n            return cacheView.putIfAbsent(key, value);\n        }\n\n        @Override\n        public boolean remove(Object key, Object value) {\n            return cacheView.remove(key, value);\n        }\n\n        @Override\n        public boolean replace(K key, V oldValue, V newValue) {\n            return cacheView.replace(key, oldValue, newValue);\n        }\n\n        @Override\n        public V replace(K key, V value) {\n            return cacheView.replace(key, value);\n        }\n\n        @Override\n        public String toString() {\n            return cacheView.toString();\n        }\n    }\n}\n"
  },
  {
    "path": "common/src/test/java/com/alibaba/otter/canal/common/AbstractZkTest.java",
    "content": "package com.alibaba.otter.canal.common;\n\nimport org.junit.Assert;\n\npublic class AbstractZkTest {\n\n    protected String destination = \"ljhtest1\";\n    protected String cluster1    = \"127.0.0.1:2188\";\n    protected String cluster2    = \"127.0.0.1:2188,127.0.0.1:2188\";\n\n    public void sleep(long time) {\n        try {\n            Thread.sleep(time);\n        } catch (InterruptedException e) {\n            Assert.fail(e.getMessage());\n        }\n    }\n}\n"
  },
  {
    "path": "common/src/test/java/com/alibaba/otter/canal/common/JsonUtilsTest.java",
    "content": "package com.alibaba.otter.canal.common;\n\nimport com.alibaba.otter.canal.common.utils.JsonUtils;\nimport org.junit.Test;\n\nimport java.net.InetAddress;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class JsonUtilsTest {\n    @Test\n    public void marshalToString() throws Exception {\n        InetAddress address = InetAddress.getByName(\"localhost\");\n\n        String json = JsonUtils.marshalToString(address);\n        assertEquals(\"\\\"localhost\\\"\", json);\n\n        InetAddress address1 = JsonUtils.unmarshalFromString(json, InetAddress.class);\n        assertEquals(address, address1);\n    }\n}\n"
  },
  {
    "path": "common/src/test/java/com/alibaba/otter/canal/common/ServerRunningTest.java",
    "content": "package com.alibaba.otter.canal.common;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport org.apache.commons.lang.math.RandomUtils;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.common.zookeeper.ZkClientx;\nimport com.alibaba.otter.canal.common.zookeeper.ZookeeperPathUtils;\nimport com.alibaba.otter.canal.common.zookeeper.running.ServerRunningData;\nimport com.alibaba.otter.canal.common.zookeeper.running.ServerRunningListener;\nimport com.alibaba.otter.canal.common.zookeeper.running.ServerRunningMonitor;\n\n@Ignore\npublic class ServerRunningTest extends AbstractZkTest {\n\n    private ZkClientx zkclientx = new ZkClientx(cluster1 + \";\" + cluster2);\n\n    @Before\n    public void setUp() {\n        String path = ZookeeperPathUtils.getDestinationPath(destination);\n        zkclientx.deleteRecursive(path);\n\n        zkclientx.createPersistent(ZookeeperPathUtils.getDestinationPath(destination), true);\n    }\n\n    @After\n    public void tearDown() {\n        String path = ZookeeperPathUtils.getDestinationPath(destination);\n        zkclientx.deleteRecursive(path);\n    }\n\n    @Test\n    public void testOneServer() {\n        final CountDownLatch countLatch = new CountDownLatch(2);\n        ServerRunningMonitor runningMonitor = buildServerRunning(countLatch, \"127.0.0.1\", 2088);\n        runningMonitor.start();\n        sleep(2000L);\n        runningMonitor.stop();\n        sleep(2000L);\n\n        if (countLatch.getCount() != 0) {\n            Assert.fail();\n        }\n    }\n\n    @Test\n    public void testMultiServer() {\n        final CountDownLatch countLatch = new CountDownLatch(30);\n        final ServerRunningMonitor runningMonitor1 = buildServerRunning(countLatch, \"127.0.0.1\", 2088);\n        final ServerRunningMonitor runningMonitor2 = buildServerRunning(countLatch, \"127.0.0.1\", 2089);\n        final ServerRunningMonitor runningMonitor3 = buildServerRunning(countLatch, \"127.0.0.1\", 2090);\n        final ExecutorService executor = Executors.newFixedThreadPool(3);\n        executor.submit(() -> {\n            for (int i = 0; i < 10; i++) {\n                if (!runningMonitor1.isStart()) {\n                    runningMonitor1.start();\n                }\n                sleep(2000L + RandomUtils.nextInt(500));\n                if (runningMonitor1.check()) {\n                    runningMonitor1.stop();\n                }\n                sleep(2000L + RandomUtils.nextInt(500));\n            }\n        });\n\n        executor.submit(() -> {\n            for (int i = 0; i < 10; i++) {\n                if (!runningMonitor2.isStart()) {\n                    runningMonitor2.start();\n                }\n                sleep(2000L + RandomUtils.nextInt(500));\n                if (runningMonitor2.check()) {\n                    runningMonitor2.stop();\n                }\n                sleep(2000L + RandomUtils.nextInt(500));\n            }\n        });\n\n        executor.submit(() -> {\n            for (int i = 0; i < 10; i++) {\n                if (!runningMonitor3.isStart()) {\n                    runningMonitor3.start();\n                }\n                sleep(2000L + RandomUtils.nextInt(500));\n                if (runningMonitor3.check()) {\n                    runningMonitor3.stop();\n                }\n                sleep(2000L + RandomUtils.nextInt(500));\n            }\n        });\n\n        sleep(30000L);\n    }\n\n    private ServerRunningMonitor buildServerRunning(final CountDownLatch countLatch, final String ip, final int port) {\n        ServerRunningData serverData = new ServerRunningData(ip + \":\" + port);\n        ServerRunningMonitor runningMonitor = new ServerRunningMonitor(serverData);\n        runningMonitor.setDestination(destination);\n        runningMonitor.setListener(new ServerRunningListener() {\n\n            public void processActiveEnter() {\n                System.out.println(String.format(\"ip:%s:%s has start\", ip, port));\n                countLatch.countDown();\n            }\n\n            public void processActiveExit() {\n                System.out.println(String.format(\"ip:%s:%s has stop\", ip, port));\n                countLatch.countDown();\n            }\n\n            public void processStart() {\n                System.out.println(String.format(\"ip:%s:%s processStart\", ip, port));\n            }\n\n            public void processStop() {\n                System.out.println(String.format(\"ip:%s:%s processStop\", ip, port));\n            }\n\n        });\n\n        runningMonitor.setZkClient(zkclientx);\n        runningMonitor.setDelayTime(1);\n        return runningMonitor;\n    }\n}\n"
  },
  {
    "path": "common/src/test/java/com/alibaba/otter/canal/common/utils/BooleanMutexTest.java",
    "content": "package com.alibaba.otter.canal.common.utils;\n\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.util.concurrent.*;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport static org.junit.Assert.*;\n\npublic class BooleanMutexTest {\n\n    public static final int CONCURRENCY = 10;\n    private ExecutorService executorService;\n\n    @Before\n    public void setUp() {\n        executorService = Executors.newFixedThreadPool(CONCURRENCY);\n    }\n\n    @After\n    public void tearDown() {\n        if (executorService != null) {\n            executorService.shutdownNow();\n        }\n    }\n\n    @Test(timeout = 3000L)\n    public void testBooleanMutexGet() throws Exception {\n\n        BooleanMutex mutex = new BooleanMutex();\n\n        AtomicLong atomicLong = new AtomicLong(0);\n\n        Phaser phaser = new Phaser(CONCURRENCY + 1);\n\n        for (int i = 0; i < CONCURRENCY; i++) {\n            executorService.submit(() -> {\n                try {\n                    // arrive phase1 and wait until phase1 finish\n                    int phase1 = phaser.arrive();\n                    phaser.awaitAdvanceInterruptibly(phase1);\n\n                    mutex.get();\n                    atomicLong.addAndGet(1);\n\n                    // arrive phase2\n                    phaser.arrive();\n                } catch (InterruptedException e) {\n                    throw new IllegalStateException(e);\n                }\n            });\n        }\n\n        assertEquals(0, atomicLong.get());\n\n        // arrive phase1 and wait until phase1 finish\n        int phase1 = phaser.arrive();\n        phaser.awaitAdvanceInterruptibly(phase1);\n        assertEquals(0, atomicLong.get());\n\n        mutex.set(true);\n\n        // arrive phase2 and wait until phase2 finish\n        int phase2 = phaser.arrive();\n        phaser.awaitAdvanceInterruptibly(phase2);\n        assertEquals(CONCURRENCY, atomicLong.get());\n    }\n\n\n    @Test(timeout = 30000L, expected = TimeoutException.class)\n    public void testBooleanMutexBlock() throws Exception {\n\n        BooleanMutex mutex = new BooleanMutex();\n\n        AtomicLong atomicLong = new AtomicLong(0);\n\n        Phaser phaser = new Phaser(CONCURRENCY + 1);\n\n        for (int i = 0; i < CONCURRENCY; i++) {\n            executorService.submit(() -> {\n                try {\n                    // arrive phase1 and wait until phase1 finish\n                    int phase1 = phaser.arrive();\n                    phaser.awaitAdvanceInterruptibly(phase1);\n\n                    mutex.get();\n                    atomicLong.addAndGet(1);\n\n                    // arrive phase2\n                    phaser.arrive();\n                } catch (InterruptedException e) {\n                    throw new IllegalStateException(e);\n                }\n            });\n        }\n\n        assertEquals(0, atomicLong.get());\n\n        // arrive phase1 and wait until phase1 finish\n        int phase1 = phaser.arrive();\n        phaser.awaitAdvanceInterruptibly(phase1);\n        assertEquals(0, atomicLong.get());\n\n        // mutex is still false\n        mutex.set(false);\n\n\n        // arrive phase2 and wait until phase2 finish\n        int phase2 = phaser.arrive();\n        // will throw interrupted exception when timeout because mutex is still false\n        phaser.awaitAdvanceInterruptibly(phase2, 2, TimeUnit.SECONDS);\n\n        fail(\"unreachable code\");\n    }\n}"
  },
  {
    "path": "common/src/test/java/logback.xml",
    "content": "<configuration scan=\"true\" scanPeriod=\" 5 seconds\">\n\n\t<jmxConfigurator />\n\t<appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n\t\t<encoder>\n\t\t\t<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{56} - %msg%n\n\t\t\t</pattern>\n\t\t</encoder>\n\t</appender>\n\t\n\t<root level=\"WARN\">\n\t\t<appender-ref ref=\"STDOUT\"/>\n\t</root>\n</configuration>"
  },
  {
    "path": "connector/core/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>canal.connector</artifactId>\n        <groupId>com.alibaba.otter</groupId>\n        <version>1.1.9-SNAPSHOT</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>com.alibaba.otter</groupId>\n    <artifactId>connector.core</artifactId>\n    <packaging>jar</packaging>\n    <name>canal connector core module for otter ${project.version}</name>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>canal.protocol</artifactId>\n            <version>${project.version}</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.googlecode.aviator</groupId>\n            <artifactId>aviator</artifactId>\n            <version>2.2.1</version>\n        </dependency>\n        <dependency>\n            <groupId>oro</groupId>\n            <artifactId>oro</artifactId>\n            <version>2.0.8</version>\n        </dependency>\n        <dependency>\n            <groupId>joda-time</groupId>\n            <artifactId>joda-time</artifactId>\n            <version>2.9.4</version>\n        </dependency>\n    </dependencies>\n\n</project>"
  },
  {
    "path": "connector/core/src/main/java/com/alibaba/otter/canal/connector/core/config/CanalConstants.java",
    "content": "package com.alibaba.otter.canal.connector.core.config;\n\n/**\n * MQ配置常量\n *\n * @author rewerma 2020-01-27\n * @version 1.0.0\n */\npublic class CanalConstants {\n\n    public static final String ROOT                           = \"canal\";\n\n    public static final String CANAL_FILTER_TRANSACTION_ENTRY = ROOT + \".\" + \"instance.filter.transaction.entry\";\n\n    public static final String CANAL_MQ_ACCESS_CHANNEL        = ROOT + \".\" + \"mq.accessChannel\";\n    public static final String CANAL_MQ_CANAL_BATCH_SIZE      = ROOT + \".\" + \"mq.canalBatchSize\";\n    public static final String CANAL_MQ_CANAL_GET_TIMEOUT     = ROOT + \".\" + \"mq.canalGetTimeout\";\n    public static final String CANAL_MQ_FLAT_MESSAGE          = ROOT + \".\" + \"mq.flatMessage\";\n\n    public static final String CANAL_MQ_DATABASE_HASH         = ROOT + \".\" + \"mq.database.hash\";\n    public static final String CANAL_MQ_BUILD_THREAD_SIZE     = ROOT + \".\" + \"mq.build.thread.size\";\n    public static final String CANAL_MQ_SEND_THREAD_SIZE      = ROOT + \".\" + \"mq.send.thread.size\";\n\n    public static final String CANAL_ALIYUN_ACCESS_KEY        = ROOT + \".\" + \"aliyun.accessKey\";\n    public static final String CANAL_ALIYUN_SECRET_KEY        = ROOT + \".\" + \"aliyun.secretKey\";\n    public static final String CANAL_ALIYUN_UID               = ROOT + \".\" + \"aliyun.uid\";\n\n}\n"
  },
  {
    "path": "connector/core/src/main/java/com/alibaba/otter/canal/connector/core/config/MQProperties.java",
    "content": "package com.alibaba.otter.canal.connector.core.config;\n\n/**\n * MQ配置类\n *\n * @author rewerma 2020-01-27\n * @version 1.0.0\n */\npublic class MQProperties {\n\n    private boolean flatMessage             = true;\n    private boolean databaseHash            = true;\n    private boolean filterTransactionEntry  = true;\n    private Integer parallelBuildThreadSize = 8;\n    private Integer parallelSendThreadSize  = 30;\n    private Integer fetchTimeout            = 100;\n    private Integer batchSize               = 50;\n    private String  accessChannel           = \"local\";\n\n    private String  aliyunAccessKey         = \"\";\n    private String  aliyunSecretKey         = \"\";\n    private int     aliyunUid               = 0;\n\n    public boolean isFlatMessage() {\n        return flatMessage;\n    }\n\n    public void setFlatMessage(boolean flatMessage) {\n        this.flatMessage = flatMessage;\n    }\n\n    public boolean isDatabaseHash() {\n        return databaseHash;\n    }\n\n    public void setDatabaseHash(boolean databaseHash) {\n        this.databaseHash = databaseHash;\n    }\n\n    public boolean isFilterTransactionEntry() {\n        return filterTransactionEntry;\n    }\n\n    public void setFilterTransactionEntry(boolean filterTransactionEntry) {\n        this.filterTransactionEntry = filterTransactionEntry;\n    }\n\n    public Integer getParallelBuildThreadSize() {\n        return parallelBuildThreadSize;\n    }\n\n    public void setParallelBuildThreadSize(Integer parallelBuildThreadSize) {\n        this.parallelBuildThreadSize = parallelBuildThreadSize;\n    }\n\n    public Integer getParallelSendThreadSize() {\n        return parallelSendThreadSize;\n    }\n\n    public void setParallelSendThreadSize(Integer parallelSendThreadSize) {\n        this.parallelSendThreadSize = parallelSendThreadSize;\n    }\n\n    public Integer getFetchTimeout() {\n        return fetchTimeout;\n    }\n\n    public void setFetchTimeout(Integer fetchTimeout) {\n        this.fetchTimeout = fetchTimeout;\n    }\n\n    public Integer getBatchSize() {\n        return batchSize;\n    }\n\n    public void setBatchSize(Integer batchSize) {\n        this.batchSize = batchSize;\n    }\n\n    public String getAccessChannel() {\n        return accessChannel;\n    }\n\n    public void setAccessChannel(String accessChannel) {\n        this.accessChannel = accessChannel;\n    }\n\n    public String getAliyunAccessKey() {\n        return aliyunAccessKey;\n    }\n\n    public void setAliyunAccessKey(String aliyunAccessKey) {\n        this.aliyunAccessKey = aliyunAccessKey;\n    }\n\n    public String getAliyunSecretKey() {\n        return aliyunSecretKey;\n    }\n\n    public void setAliyunSecretKey(String aliyunSecretKey) {\n        this.aliyunSecretKey = aliyunSecretKey;\n    }\n\n    public int getAliyunUid() {\n        return aliyunUid;\n    }\n\n    public void setAliyunUid(int aliyunUid) {\n        this.aliyunUid = aliyunUid;\n    }\n}\n"
  },
  {
    "path": "connector/core/src/main/java/com/alibaba/otter/canal/connector/core/consumer/CommonMessage.java",
    "content": "package com.alibaba.otter.canal.connector.core.consumer;\n\nimport java.io.Serializable;\nimport java.util.List;\nimport java.util.Map;\n\npublic class CommonMessage implements Serializable {\n\n    private static final long         serialVersionUID = 2611556444074013268L;\n\n    private String                    database;                               // 数据库或schema\n    private String                    table;                                  // 表名\n    private List<String>              pkNames;\n    private Boolean                   isDdl;\n    // 类型:INSERT/UPDATE/DELETE\n    private String                    type;\n    // binlog executeTime, 执行耗时\n    private Long                      es;\n    // dml build timeStamp, 同步时间\n    private Long                      ts;\n    // 执行的sql,dml sql为空\n    private String                    sql;\n    // 数据列表\n    private List<Map<String, Object>> data;\n    // 旧数据列表,用于update,size和data的size一一对应\n    private List<Map<String, Object>> old;\n\n    public String getDatabase() {\n        return database;\n    }\n\n    public void setDatabase(String database) {\n        this.database = database;\n    }\n\n    public String getTable() {\n        return table;\n    }\n\n    public void setTable(String table) {\n        this.table = table;\n    }\n\n    public List<String> getPkNames() {\n        return pkNames;\n    }\n\n    public void setPkNames(List<String> pkNames) {\n        this.pkNames = pkNames;\n    }\n\n    public Boolean getIsDdl() {\n        return isDdl;\n    }\n\n    public void setIsDdl(Boolean isDdl) {\n        this.isDdl = isDdl;\n    }\n\n    public String getType() {\n        return type;\n    }\n\n    public void setType(String type) {\n        this.type = type;\n    }\n\n    public Long getTs() {\n        return ts;\n    }\n\n    public void setTs(Long ts) {\n        this.ts = ts;\n    }\n\n    public String getSql() {\n        return sql;\n    }\n\n    public void setSql(String sql) {\n        this.sql = sql;\n    }\n\n    public List<Map<String, Object>> getData() {\n        return data;\n    }\n\n    public void setData(List<Map<String, Object>> data) {\n        this.data = data;\n    }\n\n    public List<Map<String, Object>> getOld() {\n        return old;\n    }\n\n    public void setOld(List<Map<String, Object>> old) {\n        this.old = old;\n    }\n\n    public Long getEs() {\n        return es;\n    }\n\n    public void setEs(Long es) {\n        this.es = es;\n    }\n\n    public void clear() {\n        database = null;\n        table = null;\n        type = null;\n        ts = null;\n        es = null;\n        data = null;\n        old = null;\n        sql = null;\n    }\n\n    @Override\n    public String toString() {\n        return \"CommonMessage{\" + \"database='\" + database + '\\'' + \", table='\" + table + '\\'' + \", pkNames=\" + pkNames\n               + \", isDdl=\" + isDdl + \", type='\" + type + '\\'' + \", es=\" + es + \", ts=\" + ts + \", sql='\" + sql + '\\''\n               + \", data=\" + data + \", old=\" + old + '}';\n    }\n}\n"
  },
  {
    "path": "connector/core/src/main/java/com/alibaba/otter/canal/connector/core/filter/AviaterRegexFilter.java",
    "content": "package com.alibaba.otter.canal.connector.core.filter;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.lang.StringUtils;\n\nimport com.googlecode.aviator.AviatorEvaluator;\nimport com.googlecode.aviator.Expression;\n\n/**\n * 基于aviater进行tableName正则匹配的过滤算法\n *\n * @author jianghang 2012-7-20 下午06:01:34\n */\npublic class AviaterRegexFilter {\n\n    private static final String             SPLIT             = \",\";\n    private static final String             PATTERN_SPLIT     = \"|\";\n    private static final String             FILTER_EXPRESSION = \"regex(pattern,target)\";\n    private static final RegexFunction      regexFunction     = new RegexFunction();\n    private final Expression                exp               = AviatorEvaluator.compile(FILTER_EXPRESSION, true);\n    static {\n        AviatorEvaluator.addFunction(regexFunction);\n    }\n\n    private static final Comparator<String> COMPARATOR        = new StringComparator();\n\n    final private String                    pattern;\n    final private boolean                   defaultEmptyValue;\n\n    public AviaterRegexFilter(String pattern){\n        this(pattern, true);\n    }\n\n    public AviaterRegexFilter(String pattern, boolean defaultEmptyValue){\n        this.defaultEmptyValue = defaultEmptyValue;\n        List<String> list = null;\n        if (StringUtils.isEmpty(pattern)) {\n            list = new ArrayList<>();\n        } else {\n            String[] ss = StringUtils.split(pattern, SPLIT);\n            list = Arrays.asList(ss);\n        }\n\n        // 对pattern按照从长到短的排序\n        // 因为 foo|foot 匹配 foot 会出错，原因是 foot 匹配了 foo 之后，会返回 foo，但是 foo 的长度和 foot\n        // 的长度不一样\n        list.sort(COMPARATOR);\n        // 对pattern进行头尾完全匹配\n        list = completionPattern(list);\n        this.pattern = StringUtils.join(list, PATTERN_SPLIT);\n    }\n\n    public boolean filter(String filtered) {\n        if (StringUtils.isEmpty(pattern)) {\n            return defaultEmptyValue;\n        }\n\n        if (StringUtils.isEmpty(filtered)) {\n            return defaultEmptyValue;\n        }\n\n        Map<String, Object> env = new HashMap<>();\n        env.put(\"pattern\", pattern);\n        env.put(\"target\", filtered.toLowerCase());\n        return (Boolean) exp.execute(env);\n    }\n\n    /**\n     * 修复正则表达式匹配的问题，因为使用了 oro 的 matches，会出现：\n     *\n     * <pre>\n     * foo|foot 匹配 foot 出错，原因是 foot 匹配了 foo 之后，会返回 foo，但是 foo 的长度和 foot 的长度不一样\n     * </pre>\n     *\n     * 因此此类对正则表达式进行了从长到短的排序\n     *\n     * @author zebin.xuzb 2012-10-22 下午2:02:26\n     * @version 1.0.0\n     */\n    private static class StringComparator implements Comparator<String> {\n\n        @Override\n        public int compare(String str1, String str2) {\n            return Integer.compare(str2.length(), str1.length());\n        }\n    }\n\n    /**\n     * 修复正则表达式匹配的问题，即使按照长度递减排序，还是会出现以下问题：\n     *\n     * <pre>\n     * foooo|f.*t 匹配 fooooot 出错，原因是 fooooot 匹配了 foooo 之后，会将 fooo 和数据进行匹配，但是 foooo 的长度和 fooooot 的长度不一样\n     * </pre>\n     *\n     * 因此此类对正则表达式进行头尾完全匹配\n     *\n     * @author simon\n     * @version 1.0.0\n     */\n\n    private List<String> completionPattern(List<String> patterns) {\n        List<String> result = new ArrayList<>();\n        for (String pattern : patterns) {\n            StringBuilder stringBuilder = new StringBuilder();\n            stringBuilder.append(\"^\");\n            stringBuilder.append(pattern);\n            stringBuilder.append(\"$\");\n            result.add(stringBuilder.toString());\n        }\n        return result;\n    }\n\n    @Override\n    public String toString() {\n        return pattern;\n    }\n\n}\n"
  },
  {
    "path": "connector/core/src/main/java/com/alibaba/otter/canal/connector/core/filter/PatternUtils.java",
    "content": "package com.alibaba.otter.canal.connector.core.filter;\n\nimport java.util.Map;\n\nimport org.apache.oro.text.regex.MalformedPatternException;\nimport org.apache.oro.text.regex.Pattern;\nimport org.apache.oro.text.regex.PatternCompiler;\nimport org.apache.oro.text.regex.Perl5Compiler;\n\nimport com.google.common.cache.CacheBuilder;\nimport com.google.common.collect.MigrateMap;\n\npublic class PatternUtils {\n\n    private static Map<String, Pattern> patterns = MigrateMap.makeComputingMap(CacheBuilder.newBuilder().softValues(),\n                                                     pattern -> {\n                                                         try {\n                                                             PatternCompiler pc = new Perl5Compiler();\n                                                             return pc.compile(pattern,\n                                                                 Perl5Compiler.CASE_INSENSITIVE_MASK\n                                                                         | Perl5Compiler.READ_ONLY_MASK\n                                                                         | Perl5Compiler.SINGLELINE_MASK);\n                                                         } catch (MalformedPatternException e) {\n                                                             throw new RuntimeException(e);\n                                                         }\n                                                     });\n\n    public static Pattern getPattern(String pattern) {\n        return patterns.get(pattern);\n    }\n\n    public static void clear() {\n        patterns.clear();\n    }\n}\n"
  },
  {
    "path": "connector/core/src/main/java/com/alibaba/otter/canal/connector/core/filter/RegexFunction.java",
    "content": "package com.alibaba.otter.canal.connector.core.filter;\n\nimport java.util.Map;\n\nimport org.apache.oro.text.regex.Perl5Matcher;\n\nimport com.googlecode.aviator.runtime.function.AbstractFunction;\nimport com.googlecode.aviator.runtime.function.FunctionUtils;\nimport com.googlecode.aviator.runtime.type.AviatorBoolean;\nimport com.googlecode.aviator.runtime.type.AviatorObject;\n\n/**\n * 提供aviator regex的代码扩展\n *\n * @author jianghang 2012-7-23 上午10:29:23\n */\npublic class RegexFunction extends AbstractFunction {\n\n    public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {\n        String pattern = FunctionUtils.getStringValue(arg1, env);\n        String text = FunctionUtils.getStringValue(arg2, env);\n        Perl5Matcher matcher = new Perl5Matcher();\n        boolean isMatch = matcher.matches(text, PatternUtils.getPattern(pattern));\n        return AviatorBoolean.valueOf(isMatch);\n    }\n\n    public String getName() {\n        return \"regex\";\n    }\n\n}\n"
  },
  {
    "path": "connector/core/src/main/java/com/alibaba/otter/canal/connector/core/producer/AbstractMQProducer.java",
    "content": "package com.alibaba.otter.canal.connector.core.producer;\n\nimport com.alibaba.otter.canal.common.utils.NamedThreadFactory;\nimport com.alibaba.otter.canal.common.utils.PropertiesUtils;\nimport com.alibaba.otter.canal.connector.core.config.CanalConstants;\nimport com.alibaba.otter.canal.connector.core.config.MQProperties;\nimport com.alibaba.otter.canal.connector.core.spi.CanalMQProducer;\nimport org.apache.commons.lang.StringUtils;\n\nimport java.util.Properties;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * MQ producer 抽象类\n *\n * @author rewerma 2020-01-27\n * @version 1.0.0\n */\npublic abstract class AbstractMQProducer implements CanalMQProducer {\n\n    protected MQProperties mqProperties;\n\n    protected ThreadPoolExecutor sendExecutor;\n    protected ThreadPoolExecutor buildExecutor;\n\n    @Override\n    public void init(Properties properties) {\n        // parse canal mq properties\n        loadCanalMqProperties(properties);\n\n        int parallelBuildThreadSize = mqProperties.getParallelBuildThreadSize();\n        buildExecutor = new ThreadPoolExecutor(parallelBuildThreadSize,\n                parallelBuildThreadSize,\n                0,\n                TimeUnit.SECONDS,\n                new ArrayBlockingQueue<>(parallelBuildThreadSize * 2),\n                new NamedThreadFactory(\"MQ-Parallel-Builder\"),\n                new ThreadPoolExecutor.CallerRunsPolicy());\n\n        int parallelSendThreadSize = mqProperties.getParallelSendThreadSize();\n        sendExecutor = new ThreadPoolExecutor(parallelSendThreadSize,\n                parallelSendThreadSize,\n                0,\n                TimeUnit.SECONDS,\n                new ArrayBlockingQueue<>(parallelSendThreadSize * 2),\n                new NamedThreadFactory(\"MQ-Parallel-Sender\"),\n                new ThreadPoolExecutor.CallerRunsPolicy());\n    }\n\n    @Override\n    public MQProperties getMqProperties() {\n        return this.mqProperties;\n    }\n\n    @Override\n    public void stop() {\n        if (buildExecutor != null) {\n            buildExecutor.shutdownNow();\n        }\n\n        if (sendExecutor != null) {\n            sendExecutor.shutdownNow();\n        }\n    }\n\n    /**\n     * 初始化配置\n     * <p>\n     * canal.mq.flat.message = true <br/>\n     * canal.mq.database.hash = true <br/>\n     * canal.mq.filter.transaction.entry = true <br/>\n     * canal.mq.parallel.build.thread.size = 8 <br/>\n     * canal.mq.parallel.send.thread.size = 8 <br/>\n     * canal.mq.batch.size = 50 <br/>\n     * canal.mq.timeout = 100 <br/>\n     * canal.mq.access.channel = local <br/>\n     * </p>\n     *\n     * @param properties 总配置对象\n     */\n    private void loadCanalMqProperties(Properties properties) {\n        String flatMessage = PropertiesUtils.getProperty(properties, CanalConstants.CANAL_MQ_FLAT_MESSAGE);\n        if (!StringUtils.isEmpty(flatMessage)) {\n            mqProperties.setFlatMessage(Boolean.parseBoolean(flatMessage));\n        }\n\n        String databaseHash = PropertiesUtils.getProperty(properties, CanalConstants.CANAL_MQ_DATABASE_HASH);\n        if (!StringUtils.isEmpty(databaseHash)) {\n            mqProperties.setDatabaseHash(Boolean.parseBoolean(databaseHash));\n        }\n        String filterTranEntry = PropertiesUtils.getProperty(properties, CanalConstants.CANAL_FILTER_TRANSACTION_ENTRY);\n        if (!StringUtils.isEmpty(filterTranEntry)) {\n            mqProperties.setFilterTransactionEntry(Boolean.parseBoolean(filterTranEntry));\n        }\n        String parallelBuildThreadSize = PropertiesUtils.getProperty(properties, CanalConstants.CANAL_MQ_BUILD_THREAD_SIZE);\n        if (!StringUtils.isEmpty(parallelBuildThreadSize)) {\n            mqProperties.setParallelBuildThreadSize(Integer.parseInt(parallelBuildThreadSize));\n        }\n        String parallelSendThreadSize = PropertiesUtils.getProperty(properties, CanalConstants.CANAL_MQ_SEND_THREAD_SIZE);\n        if (!StringUtils.isEmpty(parallelSendThreadSize)) {\n            mqProperties.setParallelSendThreadSize(Integer.parseInt(parallelSendThreadSize));\n        }\n        String batchSize = PropertiesUtils.getProperty(properties, CanalConstants.CANAL_MQ_CANAL_BATCH_SIZE);\n        if (!StringUtils.isEmpty(batchSize)) {\n            mqProperties.setBatchSize(Integer.parseInt(batchSize));\n        }\n        String timeOut = PropertiesUtils.getProperty(properties, CanalConstants.CANAL_MQ_CANAL_GET_TIMEOUT);\n        if (!StringUtils.isEmpty(timeOut)) {\n            mqProperties.setFetchTimeout(Integer.parseInt(timeOut));\n        }\n        String accessChannel = PropertiesUtils.getProperty(properties, CanalConstants.CANAL_MQ_ACCESS_CHANNEL);\n        if (!StringUtils.isEmpty(accessChannel)) {\n            mqProperties.setAccessChannel(accessChannel);\n        }\n        String aliyunAccessKey = PropertiesUtils.getProperty(properties, CanalConstants.CANAL_ALIYUN_ACCESS_KEY);\n        if (!StringUtils.isEmpty(aliyunAccessKey)) {\n            mqProperties.setAliyunAccessKey(aliyunAccessKey);\n        }\n        String aliyunSecretKey = PropertiesUtils.getProperty(properties, CanalConstants.CANAL_ALIYUN_SECRET_KEY);\n        if (!StringUtils.isEmpty(aliyunSecretKey)) {\n            mqProperties.setAliyunSecretKey(aliyunSecretKey);\n        }\n        String aliyunUid = PropertiesUtils.getProperty(properties, CanalConstants.CANAL_ALIYUN_UID);\n        if (!StringUtils.isEmpty(aliyunUid)) {\n            mqProperties.setAliyunUid(Integer.parseInt(aliyunUid));\n        }\n    }\n\n    /**\n     * 兼容下<=1.1.4的mq配置项\n     */\n    protected void doMoreCompatibleConvert(String oldKey, String newKey, Properties properties) {\n        String value = PropertiesUtils.getProperty(properties, oldKey);\n        if (StringUtils.isNotEmpty(value)) {\n            properties.setProperty(newKey, value);\n        }\n    }\n}\n"
  },
  {
    "path": "connector/core/src/main/java/com/alibaba/otter/canal/connector/core/producer/MQDestination.java",
    "content": "package com.alibaba.otter.canal.connector.core.producer;\n\n/**\n * MQ producer destination\n *\n * @author rewerma 2020-01-27\n * @version 1.0.0\n */\npublic class MQDestination {\n\n    private String  canalDestination;\n    private String  topic;\n    private Integer partition;\n    private Integer partitionsNum;\n    private String  partitionHash;\n    private String  dynamicTopic;\n    private String  dynamicTopicPartitionNum;\n    private Boolean enableDynamicQueuePartition;\n\n    public String getCanalDestination() {\n        return canalDestination;\n    }\n\n    public void setCanalDestination(String canalDestination) {\n        this.canalDestination = canalDestination;\n    }\n\n    public String getTopic() {\n        return topic;\n    }\n\n    public void setTopic(String topic) {\n        this.topic = topic;\n    }\n\n    public Integer getPartition() {\n        return partition;\n    }\n\n    public void setPartition(Integer partition) {\n        this.partition = partition;\n    }\n\n    public Integer getPartitionsNum() {\n        return partitionsNum;\n    }\n\n    public void setPartitionsNum(Integer partitionsNum) {\n        this.partitionsNum = partitionsNum;\n    }\n\n    public String getPartitionHash() {\n        return partitionHash;\n    }\n\n    public void setPartitionHash(String partitionHash) {\n        this.partitionHash = partitionHash;\n    }\n\n    public String getDynamicTopic() {\n        return dynamicTopic;\n    }\n\n    public void setDynamicTopic(String dynamicTopic) {\n        this.dynamicTopic = dynamicTopic;\n    }\n\n    public String getDynamicTopicPartitionNum() {\n        return dynamicTopicPartitionNum;\n    }\n\n    public void setDynamicTopicPartitionNum(String dynamicTopicPartitionNum) {\n        this.dynamicTopicPartitionNum = dynamicTopicPartitionNum;\n    }\n\n    public Boolean getEnableDynamicQueuePartition() {\n        return enableDynamicQueuePartition;\n    }\n\n    public void setEnableDynamicQueuePartition(Boolean enableDynamicQueuePartition) {\n        this.enableDynamicQueuePartition = enableDynamicQueuePartition;\n    }\n}\n"
  },
  {
    "path": "connector/core/src/main/java/com/alibaba/otter/canal/connector/core/producer/MQMessageUtils.java",
    "content": "package com.alibaba.otter.canal.connector.core.producer;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ThreadPoolExecutor;\n\nimport org.apache.commons.lang.StringUtils;\n\nimport com.alibaba.otter.canal.common.utils.ExecutorTemplate;\nimport com.alibaba.otter.canal.connector.core.filter.AviaterRegexFilter;\nimport com.alibaba.otter.canal.protocol.CanalEntry;\nimport com.alibaba.otter.canal.protocol.CanalEntry.Entry;\nimport com.alibaba.otter.canal.protocol.CanalEntry.RowChange;\nimport com.alibaba.otter.canal.protocol.FlatMessage;\nimport com.alibaba.otter.canal.protocol.Message;\nimport com.google.common.cache.CacheBuilder;\nimport com.google.common.collect.Lists;\nimport com.google.common.collect.MigrateMap;\nimport com.google.protobuf.ByteString;\nimport com.google.protobuf.InvalidProtocolBufferException;\n\n/**\n * process MQ Message utils\n *\n * @author agapple 2019年9月29日 下午12:36:26\n * @since 5.0.0\n */\npublic class MQMessageUtils {\n\n    private static Map<String, List<PartitionData>>    partitionDatas    = MigrateMap.makeComputingMap(CacheBuilder.newBuilder()\n                                                                             .softValues(),\n                                                                             pkHashConfigs -> {\n                                                                                 List<PartitionData> datas = new ArrayList<>();\n\n                                                                                 String[] pkHashConfigArray = StringUtils.split(StringUtils.replace(pkHashConfigs,\n                                                                                     \",\",\n                                                                                     \";\"),\n                                                                                     \";\");\n                                                                                 // schema.table:id^name\n                                                                                 for (String pkHashConfig : pkHashConfigArray) {\n                                                                                     PartitionData data = new PartitionData();\n                                                                                     int i = pkHashConfig.lastIndexOf(\":\");\n                                                                                     if (i > 0) {\n                                                                                         String pkStr = pkHashConfig.substring(i + 1);\n                                                                                         if (pkStr.equalsIgnoreCase(\"$pk$\")) {\n                                                                                             data.hashMode.autoPkHash = true;\n                                                                                         } else {\n                                                                                             data.hashMode.pkNames = Lists.newArrayList(StringUtils.split(pkStr,\n                                                                                                 '^'));\n                                                                                         }\n\n                                                                                         pkHashConfig = pkHashConfig.substring(0,\n                                                                                             i);\n                                                                                     } else {\n                                                                                         data.hashMode.tableHash = true;\n                                                                                     }\n\n                                                                                     if (!isWildCard(pkHashConfig)) {\n                                                                                         data.simpleName = pkHashConfig;\n                                                                                     } else {\n                                                                                         data.regexFilter = new AviaterRegexFilter(pkHashConfig);\n                                                                                     }\n                                                                                     datas.add(data);\n                                                                                 }\n\n                                                                                 return datas;\n                                                                             });\n\n    private static Map<String, List<DynamicTopicData>> dynamicTopicDatas = MigrateMap.makeComputingMap(CacheBuilder.newBuilder()\n                                                                             .softValues(),\n                                                                              pkHashConfigs -> {\n                                                                                List<DynamicTopicData> datas = new ArrayList<>();\n                                                                                String[] dynamicTopicArray = StringUtils.split(StringUtils.replace(pkHashConfigs,\n                                                                                    \",\",\n                                                                                    \";\"),\n                                                                                    \";\");\n                                                                                // schema.table\n                                                                                for (String dynamicTopic : dynamicTopicArray) {\n                                                                                    DynamicTopicData data = new DynamicTopicData();\n\n                                                                                    if (!isWildCard(dynamicTopic)) {\n                                                                                        data.simpleName = dynamicTopic;\n                                                                                    } else {\n                                                                                        if (dynamicTopic.contains(\"\\\\.\")) {\n                                                                                            data.tableRegexFilter = new AviaterRegexFilter(dynamicTopic);\n                                                                                        } else {\n                                                                                            data.schemaRegexFilter = new AviaterRegexFilter(dynamicTopic);\n                                                                                        }\n                                                                                    }\n                                                                                    datas.add(data);\n                                                                                }\n\n                                                                                return datas;\n                                                                            });\n\n    private static Map<String, List<TopicPartitionData>> topicPartitionDatas = MigrateMap.makeComputingMap(CacheBuilder.newBuilder()\n                                                                                .softValues(),\n                                                                                tPConfigs -> {\n                                                                                    List<TopicPartitionData> datas = new ArrayList<>();\n                                                                                    String[] tPArray = StringUtils.split(StringUtils.replace(tPConfigs,\n                                                                                            \",\",\n                                                                                            \";\"),\n                                                                                            \";\");\n                                                                                    for (String tPConfig : tPArray) {\n                                                                                        TopicPartitionData data = new TopicPartitionData();\n                                                                                        int i = tPConfig.lastIndexOf(\":\");\n                                                                                        if (i > 0) {\n                                                                                            String tStr = tPConfig.substring(0, i);\n                                                                                            String pStr = tPConfig.substring(i + 1);\n                                                                                            if (!isWildCard(tStr)) {\n                                                                                                data.simpleName = tStr;\n                                                                                            } else {\n                                                                                                data.regexFilter = new AviaterRegexFilter(tStr);\n                                                                                            }\n                                                                                            if (!StringUtils.isEmpty(pStr) && StringUtils.isNumeric(pStr)) {\n                                                                                                data.partitionNum = Integer.valueOf(pStr);\n                                                                                            }\n                                                                                            datas.add(data);\n                                                                                        }\n                                                                                    }\n\n                                                                                    return datas;\n                                                                                });\n\n    /**\n     * 按 schema 或者 schema+table 将 message 分配到对应topic\n     *\n     * @param message 原message\n     * @param defaultTopic 默认topic\n     * @param dynamicTopicConfigs 动态topic规则\n     * @return 分隔后的message map\n     */\n    public static Map<String, Message> messageTopics(Message message, String defaultTopic, String dynamicTopicConfigs) {\n        List<CanalEntry.Entry> entries;\n        if (message.isRaw()) {\n            List<ByteString> rawEntries = message.getRawEntries();\n            entries = new ArrayList<>(rawEntries.size());\n            for (ByteString byteString : rawEntries) {\n                CanalEntry.Entry entry;\n                try {\n                    entry = CanalEntry.Entry.parseFrom(byteString);\n                } catch (InvalidProtocolBufferException e) {\n                    throw new RuntimeException(e);\n                }\n                entries.add(entry);\n            }\n        } else {\n            entries = message.getEntries();\n        }\n        Map<String, Message> messages = new HashMap<>();\n        for (CanalEntry.Entry entry : entries) {\n            // 如果有topic路由,则忽略begin/end事件\n            if (entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONBEGIN\n                || entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONEND) {\n                continue;\n            }\n\n            String schemaName = entry.getHeader().getSchemaName();\n            String tableName = entry.getHeader().getTableName();\n\n            if (StringUtils.isEmpty(schemaName) || StringUtils.isEmpty(tableName)) {\n                put2MapMessage(messages, message.getId(), defaultTopic, entry);\n            } else {\n                Set<String> topics = matchTopics(schemaName + \".\" + tableName, dynamicTopicConfigs);\n                if (topics != null) {\n                    for (String topic : topics) {\n                        put2MapMessage(messages, message.getId(), topic, entry);\n                    }\n                } else {\n                    topics = matchTopics(schemaName, dynamicTopicConfigs);\n                    if (topics != null) {\n                        for (String topic : topics) {\n                            put2MapMessage(messages, message.getId(), topic, entry);\n                        }\n                    } else {\n                        put2MapMessage(messages, message.getId(), defaultTopic, entry);\n                    }\n                }\n            }\n        }\n        return messages;\n    }\n\n    /**\n     * 多线程构造message的rowChanged对象，比如为partition/flastMessage转化等处理 </br>\n     * 因为protobuf对象的序列化和反序列化是cpu密集型，串行执行会有代价\n     */\n    public static EntryRowData[] buildMessageData(Message message, ThreadPoolExecutor executor) {\n        ExecutorTemplate template = new ExecutorTemplate(executor);\n        if (message.isRaw()) {\n            List<ByteString> rawEntries = message.getRawEntries();\n            final EntryRowData[] datas = new EntryRowData[rawEntries.size()];\n            int i = 0;\n            for (ByteString byteString : rawEntries) {\n                final int index = i;\n                template.submit(() -> {\n                    try {\n                        Entry entry = Entry.parseFrom(byteString);\n                        RowChange rowChange = RowChange.parseFrom(entry.getStoreValue());\n                        datas[index] = new EntryRowData();\n                        datas[index].entry = entry;\n                        datas[index].rowChange = rowChange;\n                    } catch (InvalidProtocolBufferException e) {\n                        throw new RuntimeException(e);\n                    }\n                });\n\n                i++;\n            }\n\n            template.waitForResult();\n            return datas;\n        } else {\n            final EntryRowData[] datas = new EntryRowData[message.getEntries().size()];\n            int i = 0;\n            for (Entry entry : message.getEntries()) {\n                final int index = i;\n                template.submit(() -> {\n                    try {\n                        RowChange rowChange = RowChange.parseFrom(entry.getStoreValue());\n                        datas[index] = new EntryRowData();\n                        datas[index].entry = entry;\n                        datas[index].rowChange = rowChange;\n                    } catch (InvalidProtocolBufferException e) {\n                        throw new RuntimeException(e);\n                    }\n                });\n\n                i++;\n            }\n\n            template.waitForResult();\n            return datas;\n        }\n    }\n\n    /**\n     * 将 message 分区\n     *\n     * @param partitionsNum 分区数\n     * @param pkHashConfigs 分区库表主键正则表达式\n     * @param databaseHash 是否取消根据database进行hash\n     * @return 分区message数组\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static Message[] messagePartition(EntryRowData[] datas, long id, Integer partitionsNum,\n                                             String pkHashConfigs, boolean databaseHash) {\n        if (partitionsNum == null) {\n            partitionsNum = 1;\n        }\n        Message[] partitionMessages = new Message[partitionsNum];\n        List<Entry>[] partitionEntries = new List[partitionsNum];\n        for (int i = 0; i < partitionsNum; i++) {\n            // 注意一下并发\n            partitionEntries[i] = Collections.synchronizedList(new ArrayList<>());\n        }\n\n        for (EntryRowData data : datas) {\n            CanalEntry.Entry entry = data.entry;\n            CanalEntry.RowChange rowChange = data.rowChange;\n            // 如果有分区路由,则忽略begin/end事件\n            if (entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONBEGIN\n                || entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONEND) {\n                continue;\n            }\n\n            if (rowChange.getIsDdl()) {\n                partitionEntries[0].add(entry);\n            } else {\n                if (rowChange.getRowDatasList() != null && !rowChange.getRowDatasList().isEmpty()) {\n                    String database = entry.getHeader().getSchemaName();\n                    String table = entry.getHeader().getTableName();\n                    HashMode hashMode = getPartitionHashColumns(database + \".\" + table, pkHashConfigs);\n                    if (hashMode == null) {\n                        // 如果都没有匹配，发送到第一个分区\n                        partitionEntries[0].add(entry);\n                    } else if (hashMode.tableHash) {\n                        int hashCode = table.hashCode();\n                        int pkHash = Math.abs(hashCode) % partitionsNum;\n                        pkHash = Math.abs(pkHash);\n                        // tableHash not need split entry message\n                        partitionEntries[pkHash].add(entry);\n                    } else {\n                        // build new entry\n                        Entry.Builder builder = Entry.newBuilder(entry);\n                        RowChange.Builder rowChangeBuilder = RowChange.newBuilder(rowChange);\n\n                        for (CanalEntry.RowData rowData : rowChange.getRowDatasList()) {\n                            int hashCode = 0;\n                            if (databaseHash) {\n                                hashCode = database.hashCode();\n                            }\n                            CanalEntry.EventType eventType = rowChange.getEventType();\n                            List<CanalEntry.Column> columns = null;\n                            if (eventType == CanalEntry.EventType.DELETE) {\n                                columns = rowData.getBeforeColumnsList();\n                            } else {\n                                columns = rowData.getAfterColumnsList();\n                            }\n\n                            if (hashMode.autoPkHash) {\n                                // isEmpty use default pkNames\n                                for (CanalEntry.Column column : columns) {\n                                    if (column.getIsKey()) {\n                                        hashCode = hashCode ^ column.getValue().hashCode();\n                                    }\n                                }\n                            } else {\n                                for (CanalEntry.Column column : columns) {\n                                    if (checkPkNamesHasContain(hashMode.pkNames, column.getName())) {\n                                        hashCode = hashCode ^ column.getValue().hashCode();\n                                    }\n                                }\n                            }\n\n                            int pkHash = Math.abs(hashCode) % partitionsNum;\n                            pkHash = Math.abs(pkHash);\n                            // clear rowDatas\n                            rowChangeBuilder.clearRowDatas();\n                            rowChangeBuilder.addRowDatas(rowData);\n                            builder.clearStoreValue();\n                            builder.setStoreValue(rowChangeBuilder.build().toByteString());\n                            partitionEntries[pkHash].add(builder.build());\n                        }\n                    }\n                } else {\n                    // 针对stmt/mixed binlog格式的query事件\n                    partitionEntries[0].add(entry);\n                }\n            }\n        }\n\n        for (int i = 0; i < partitionsNum; i++) {\n            List<Entry> entriesTmp = partitionEntries[i];\n            if (!entriesTmp.isEmpty()) {\n                partitionMessages[i] = new Message(id, entriesTmp);\n            }\n        }\n\n        return partitionMessages;\n    }\n\n    /**\n     * 将Message转换为FlatMessage\n     *\n     * @return FlatMessage列表\n     * @author agapple 2018年12月11日 下午1:28:32\n     */\n    public static List<FlatMessage> messageConverter(EntryRowData[] datas, long id) {\n        List<FlatMessage> flatMessages = new ArrayList<>();\n        for (EntryRowData entryRowData : datas) {\n            CanalEntry.Entry entry = entryRowData.entry;\n            CanalEntry.RowChange rowChange = entryRowData.rowChange;\n            // 如果有分区路由,则忽略begin/end事件\n            if (entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONBEGIN\n                || entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONEND) {\n                continue;\n            }\n\n            // build flatMessage\n            CanalEntry.EventType eventType = rowChange.getEventType();\n            FlatMessage flatMessage = new FlatMessage(id);\n            flatMessages.add(flatMessage);\n            flatMessage.setDatabase(entry.getHeader().getSchemaName());\n            flatMessage.setTable(entry.getHeader().getTableName());\n            flatMessage.setIsDdl(rowChange.getIsDdl());\n            flatMessage.setType(eventType.toString());\n            flatMessage.setEs(entry.getHeader().getExecuteTime());\n            flatMessage.setTs(System.currentTimeMillis());\n            flatMessage.setSql(rowChange.getSql());\n            flatMessage.setGtid(entry.getHeader().getGtid());\n\n            if (!rowChange.getIsDdl()) {\n                Map<String, Integer> sqlType = new LinkedHashMap<>();\n                Map<String, String> mysqlType = new LinkedHashMap<>();\n                List<Map<String, String>> data = new ArrayList<>();\n                List<Map<String, String>> old = new ArrayList<>();\n\n                Set<String> updateSet = new HashSet<>();\n                boolean hasInitPkNames = false;\n                for (CanalEntry.RowData rowData : rowChange.getRowDatasList()) {\n                    if (eventType != CanalEntry.EventType.INSERT && eventType != CanalEntry.EventType.UPDATE\n                        && eventType != CanalEntry.EventType.DELETE) {\n                        continue;\n                    }\n\n                    Map<String, String> row = new LinkedHashMap<>();\n                    List<CanalEntry.Column> columns;\n\n                    if (eventType == CanalEntry.EventType.DELETE) {\n                        columns = rowData.getBeforeColumnsList();\n                    } else {\n                        columns = rowData.getAfterColumnsList();\n                    }\n\n                    for (CanalEntry.Column column : columns) {\n                        if (!hasInitPkNames && column.getIsKey()) {\n                            flatMessage.addPkName(column.getName());\n                        }\n                        sqlType.put(column.getName(), column.getSqlType());\n                        mysqlType.put(column.getName(), column.getMysqlType());\n                        if (column.getIsNull()) {\n                            row.put(column.getName(), null);\n                        } else {\n                            row.put(column.getName(), column.getValue());\n                        }\n                        // 获取update为true的字段\n                        if (column.getUpdated()) {\n                            updateSet.add(column.getName());\n                        }\n                    }\n\n                    hasInitPkNames = true;\n                    if (!row.isEmpty()) {\n                        data.add(row);\n                    }\n\n                    if (eventType == CanalEntry.EventType.UPDATE) {\n                        Map<String, String> rowOld = new LinkedHashMap<>();\n                        for (CanalEntry.Column column : rowData.getBeforeColumnsList()) {\n                            if (updateSet.contains(column.getName())) {\n                                if (column.getIsNull()) {\n                                    rowOld.put(column.getName(), null);\n                                } else {\n                                    rowOld.put(column.getName(), column.getValue());\n                                }\n                            }\n                        }\n                        // update操作将记录修改前的值\n                        old.add(rowOld);\n                    }\n                }\n                if (!sqlType.isEmpty()) {\n                    flatMessage.setSqlType(sqlType);\n                }\n                if (!mysqlType.isEmpty()) {\n                    flatMessage.setMysqlType(mysqlType);\n                }\n                if (!data.isEmpty()) {\n                    flatMessage.setData(data);\n                }\n                if (!old.isEmpty()) {\n                    flatMessage.setOld(old);\n                }\n            }\n        }\n        return flatMessages;\n    }\n\n    /**\n     * 将FlatMessage按指定的字段值hash拆分\n     *\n     * @param flatMessage flatMessage\n     * @param partitionsNum 分区数量\n     * @param pkHashConfigs hash映射\n     * @param databaseHash 是否取消根据database进行hash\n     * @return 拆分后的flatMessage数组\n     */\n    public static FlatMessage[] messagePartition(FlatMessage flatMessage, Integer partitionsNum, String pkHashConfigs,\n                                                 boolean databaseHash) {\n        if (partitionsNum == null) {\n            partitionsNum = 1;\n        }\n        FlatMessage[] partitionMessages = new FlatMessage[partitionsNum];\n\n        if (flatMessage.getIsDdl()) {\n            partitionMessages[0] = flatMessage;\n        } else {\n            if (flatMessage.getData() != null && !flatMessage.getData().isEmpty()) {\n                String database = flatMessage.getDatabase();\n                String table = flatMessage.getTable();\n                HashMode hashMode = getPartitionHashColumns(database + \".\" + table, pkHashConfigs);\n                if (hashMode == null) {\n                    // 如果都没有匹配，发送到第一个分区\n                    partitionMessages[0] = flatMessage;\n                } else if (hashMode.tableHash) {\n                    int hashCode = table.hashCode();\n                    int pkHash = Math.abs(hashCode) % partitionsNum;\n                    // math.abs可能返回负值，这里再取反，把出现负值的数据还是写到固定的分区，仍然可以保证消费顺序\n                    pkHash = Math.abs(pkHash);\n                    partitionMessages[pkHash] = flatMessage;\n                } else {\n                    List<String> pkNames = hashMode.pkNames;\n                    if (hashMode.autoPkHash) {\n                        pkNames = flatMessage.getPkNames();\n                    }\n\n                    int idx = 0;\n                    for (Map<String, String> row : flatMessage.getData()) {\n                        int hashCode = 0;\n                        if (databaseHash) {\n                            hashCode = database.hashCode();\n                        }\n                        if (pkNames != null) {\n                            for (String pkName : pkNames) {\n                                String value = row.get(pkName);\n                                if (value == null) {\n                                    value = \"\";\n                                }\n                                hashCode = hashCode ^ value.hashCode();\n                            }\n                        }\n\n                        int pkHash = Math.abs(hashCode) % partitionsNum;\n                        // math.abs可能返回负值，这里再取反，把出现负值的数据还是写到固定的分区，仍然可以保证消费顺序\n                        pkHash = Math.abs(pkHash);\n\n                        FlatMessage flatMessageTmp = partitionMessages[pkHash];\n                        if (flatMessageTmp == null) {\n                            flatMessageTmp = new FlatMessage(flatMessage.getId());\n                            partitionMessages[pkHash] = flatMessageTmp;\n                            flatMessageTmp.setDatabase(flatMessage.getDatabase());\n                            flatMessageTmp.setTable(flatMessage.getTable());\n                            flatMessageTmp.setIsDdl(flatMessage.getIsDdl());\n                            flatMessageTmp.setType(flatMessage.getType());\n                            flatMessageTmp.setSql(flatMessage.getSql());\n                            flatMessageTmp.setSqlType(flatMessage.getSqlType());\n                            flatMessageTmp.setMysqlType(flatMessage.getMysqlType());\n                            flatMessageTmp.setEs(flatMessage.getEs());\n                            flatMessageTmp.setTs(flatMessage.getTs());\n                            flatMessageTmp.setPkNames(flatMessage.getPkNames());\n                            flatMessageTmp.setGtid(flatMessage.getGtid());\n                        }\n                        List<Map<String, String>> data = flatMessageTmp.getData();\n                        if (data == null) {\n                            data = new ArrayList<>();\n                            flatMessageTmp.setData(data);\n                        }\n                        data.add(row);\n                        if (flatMessage.getOld() != null && !flatMessage.getOld().isEmpty()) {\n                            List<Map<String, String>> old = flatMessageTmp.getOld();\n                            if (old == null) {\n                                old = new ArrayList<>();\n                                flatMessageTmp.setOld(old);\n                            }\n                            old.add(flatMessage.getOld().get(idx));\n                        }\n                        idx++;\n                    }\n                }\n            } else {\n                // 针对stmt/mixed binlog格式的query事件\n                partitionMessages[0] = flatMessage;\n            }\n        }\n        return partitionMessages;\n    }\n\n    /**\n     * match return List , not match return null\n     */\n    public static HashMode getPartitionHashColumns(String name, String pkHashConfigs) {\n        if (StringUtils.isEmpty(pkHashConfigs)) {\n            return null;\n        }\n\n        List<PartitionData> datas = partitionDatas.get(pkHashConfigs);\n        for (PartitionData data : datas) {\n            if (data.simpleName != null) {\n                if (data.simpleName.equalsIgnoreCase(name)) {\n                    return data.hashMode;\n                }\n            } else {\n                if (data.regexFilter.filter(name)) {\n                    return data.hashMode;\n                }\n            }\n        }\n\n        return null;\n    }\n\n    private static Set<String> matchTopics(String name, String dynamicTopicConfigs) {\n        String[] router = StringUtils.split(StringUtils.replace(dynamicTopicConfigs, \",\", \";\"), \";\");\n        Set<String> topics = new HashSet<>();\n        for (String item : router) {\n            int i = item.indexOf(\":\");\n            if (i > -1) {\n                String topic = item.substring(0, i).trim();\n                String topicConfigs = item.substring(i + 1).trim();\n                if (matchDynamicTopic(name, topicConfigs)) {\n                    topics.add(topic);\n                    // 匹配了一个就退出\n                    break;\n                }\n            } else if (matchDynamicTopic(name, item)) {\n                // 匹配了一个就退出\n                topics.add(name.toLowerCase());\n                break;\n            }\n        }\n        return topics.isEmpty() ? null : topics;\n    }\n\n    public static boolean matchDynamicTopic(String name, String dynamicTopicConfigs) {\n        if (StringUtils.isEmpty(dynamicTopicConfigs)) {\n            return false;\n        }\n\n        boolean res = false;\n        List<DynamicTopicData> datas = dynamicTopicDatas.get(dynamicTopicConfigs);\n        for (DynamicTopicData data : datas) {\n            if (data.simpleName != null) {\n                if (data.simpleName.equalsIgnoreCase(name)) {\n                    res = true;\n                    break;\n                }\n            } else if (name.contains(\".\")) {\n                if (data.tableRegexFilter != null && data.tableRegexFilter.filter(name)) {\n                    res = true;\n                    break;\n                }\n            } else {\n                if (data.schemaRegexFilter != null && data.schemaRegexFilter.filter(name)) {\n                    res = true;\n                    break;\n                }\n            }\n        }\n        return res;\n    }\n\n    public static boolean checkPkNamesHasContain(List<String> pkNames, String name) {\n        for (String pkName : pkNames) {\n            if (pkName.equalsIgnoreCase(name)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    public static Integer parseDynamicTopicPartition(String name, String tPConfigs) {\n        if (!StringUtils.isEmpty(tPConfigs)) {\n            List<TopicPartitionData> datas = topicPartitionDatas.get(tPConfigs);\n            for (TopicPartitionData data : datas) {\n                if (data.simpleName != null) {\n                    if (data.simpleName.equalsIgnoreCase(name)) {\n                        return data.partitionNum;\n                    }\n                } else {\n                    if (data.regexFilter.filter(name)) {\n                        return data.partitionNum;\n                    }\n                }\n            }\n        }\n        return null;\n    }\n\n    private static boolean isWildCard(String value) {\n        // not contaiins '.' ?\n        return StringUtils.containsAny(value, new char[] { '*', '?', '+', '|', '(', ')', '{', '}', '[', ']', '\\\\', '$',\n                '^' });\n    }\n\n    private static void put2MapMessage(Map<String, Message> messageMap, Long messageId, String topicName,\n                                       CanalEntry.Entry entry) {\n        Message message = messageMap.get(topicName);\n        if (message == null) {\n            message = new Message(messageId, new ArrayList<>());\n            messageMap.put(topicName, message);\n        }\n        message.getEntries().add(entry);\n    }\n\n    public static class PartitionData {\n        /**\n         * 当{schemaName.tableName}没有正则时，就匹配{schemaName.tableName}\n         */\n        public String             simpleName;\n        /**\n         * 当{schemaName.tableName}有正则时，匹配正则\n         */\n        public AviaterRegexFilter regexFilter;\n        /**\n         * hash模式\n         */\n        public HashMode           hashMode = new HashMode();\n    }\n\n    public static class HashMode {\n        /**\n         * 当{schemaName.tableName}:$pk$时，使用自动主键hash\n         */\n        public boolean      autoPkHash = false;\n        /**\n         * 当表达式仅为{schemaName.tableName}，没有:时，仅使用table hash\n         */\n        public boolean      tableHash  = false;\n\n        /**\n         * 当表达式为{schemaName.tableName}:id^name^age时，pkNames为：id, name, age三个\n         */\n        public List<String> pkNames    = new ArrayList<>();\n    }\n\n    public static class DynamicTopicData {\n\n        public String             simpleName;\n        public AviaterRegexFilter schemaRegexFilter;\n        public AviaterRegexFilter tableRegexFilter;\n    }\n\n    public static class TopicPartitionData {\n\n        public String             simpleName;\n        public AviaterRegexFilter regexFilter;\n        public Integer            partitionNum;\n    }\n\n    public static class EntryRowData {\n\n        public Entry     entry;\n        public RowChange rowChange;\n    }\n}\n"
  },
  {
    "path": "connector/core/src/main/java/com/alibaba/otter/canal/connector/core/spi/CanalMQProducer.java",
    "content": "package com.alibaba.otter.canal.connector.core.spi;\n\nimport java.util.Properties;\n\nimport com.alibaba.otter.canal.connector.core.config.MQProperties;\nimport com.alibaba.otter.canal.connector.core.producer.MQDestination;\nimport com.alibaba.otter.canal.connector.core.util.Callback;\nimport com.alibaba.otter.canal.protocol.Message;\n\n/**\n * MQ producer SPI 接口\n *\n * @author rewerma 2020-01-27\n * @version 1.0.0\n */\n@SPI(\"kafka\")\npublic interface CanalMQProducer {\n\n    /**\n     * Init producer.\n     */\n    void init(Properties properties);\n\n    /**\n     * Get base mq properties\n     * \n     * @return MQProperties\n     */\n    MQProperties getMqProperties();\n\n    /**\n     * Send canal message to related topic\n     *\n     * @param canalDestination canal mq destination\n     * @param message canal message\n     */\n    void send(MQDestination canalDestination, Message message, Callback callback);\n\n    /**\n     * Stop MQ producer service\n     */\n    void stop();\n}\n"
  },
  {
    "path": "connector/core/src/main/java/com/alibaba/otter/canal/connector/core/spi/CanalMsgConsumer.java",
    "content": "package com.alibaba.otter.canal.connector.core.spi;\n\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.concurrent.TimeUnit;\n\nimport com.alibaba.otter.canal.connector.core.consumer.CommonMessage;\n\n/**\n * Canal/MQ consumer SPI 接口\n *\n * @author rewerma @ 2020-02-01\n * @version 1.0.0\n */\n@SPI(\"kafka\")\npublic interface CanalMsgConsumer {\n\n    /**\n     * 初始化\n     * \n     * @param properties consumer properties\n     * @param topic topic/destination\n     * @param groupId mq group id\n     */\n    void init(Properties properties, String topic, String groupId);\n\n    /**\n     * 连接Canal/MQ\n     */\n    void connect();\n\n    /**\n     * 批量拉取数据\n     * \n     * @param timeout 超时时间\n     * @param unit 时间单位\n     * @return Message列表\n     */\n    List<CommonMessage> getMessage(Long timeout, TimeUnit unit);\n\n    /**\n     * 提交\n     */\n    void ack();\n\n    /**\n     * 回滚\n     */\n    void rollback();\n\n    /**\n     * 断开连接\n     */\n    void disconnect();\n}\n"
  },
  {
    "path": "connector/core/src/main/java/com/alibaba/otter/canal/connector/core/spi/ExtensionLoader.java",
    "content": "package com.alibaba.otter.canal.connector.core.spi;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.InputStreamReader;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.Arrays;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.regex.Pattern;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * SPI 类加载器\n *\n * @author rewerma 2018-8-19 下午11:30:49\n * @version 1.0.0\n */\npublic class ExtensionLoader<T> {\n\n    private static final Logger                                      logger                     = LoggerFactory.getLogger(ExtensionLoader.class);\n\n    private static final String                                      SERVICES_DIRECTORY         = \"META-INF/services/\";\n\n    private static final String                                      CANAL_DIRECTORY            = \"META-INF/canal/\";\n\n    private static final String                                      DEFAULT_CLASSLOADER_POLICY = \"internal\";\n\n    private static final Pattern                                     NAME_SEPARATOR             = Pattern.compile(\"\\\\s*[,]+\\\\s*\");\n\n    private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS          = new ConcurrentHashMap<>();\n\n    private static final ConcurrentMap<Class<?>, Object>             EXTENSION_INSTANCES        = new ConcurrentHashMap<>();\n\n    private static final ConcurrentMap<String, Object>               EXTENSION_KEY_INSTANCE     = new ConcurrentHashMap<>();\n\n    private final Class<?>                                           type;\n\n    private final String                                             classLoaderPolicy;\n\n    private final ConcurrentMap<Class<?>, String>                    cachedNames                = new ConcurrentHashMap<>();\n\n    private final Holder<Map<String, Class<?>>>                      cachedClasses              = new Holder<>();\n\n    private final ConcurrentMap<String, Holder<Object>>              cachedInstances            = new ConcurrentHashMap<>();\n\n    private String                                                   cachedDefaultName;\n\n    private ConcurrentHashMap<String, IllegalStateException>         exceptions                 = new ConcurrentHashMap<>();\n\n    private static <T> boolean withExtensionAnnotation(Class<T> type) {\n        return type.isAnnotationPresent(SPI.class);\n    }\n\n    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {\n        return getExtensionLoader(type, DEFAULT_CLASSLOADER_POLICY);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type, String classLoaderPolicy) {\n        if (type == null) throw new IllegalArgumentException(\"Extension type == null\");\n        if (!type.isInterface()) {\n            throw new IllegalArgumentException(\"Extension type(\" + type + \") is not interface!\");\n        }\n        if (!withExtensionAnnotation(type)) {\n            throw new IllegalArgumentException(\"Extension type(\" + type + \") is not extension, because WITHOUT @\"\n                                               + SPI.class.getSimpleName() + \" Annotation!\");\n        }\n\n        ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);\n        if (loader == null) {\n            EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type, classLoaderPolicy));\n            loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);\n        }\n        return loader;\n    }\n\n    public ExtensionLoader(Class<?> type){\n        this.type = type;\n        this.classLoaderPolicy = DEFAULT_CLASSLOADER_POLICY;\n    }\n\n    public ExtensionLoader(Class<?> type, String classLoaderPolicy){\n        this.type = type;\n        this.classLoaderPolicy = classLoaderPolicy;\n    }\n\n    /**\n     * 返回指定名字的扩展\n     *\n     * @param name\n     * @return\n     */\n    @SuppressWarnings(\"unchecked\")\n    public T getExtension(String name, String spiDir, String standbyDir) {\n        if (name == null || name.length() == 0) throw new IllegalArgumentException(\"Extension name == null\");\n        if (\"true\".equals(name)) {\n            return getDefaultExtension(spiDir, standbyDir);\n        }\n        Holder<Object> holder = cachedInstances.get(name);\n        if (holder == null) {\n            cachedInstances.putIfAbsent(name, new Holder<>());\n            holder = cachedInstances.get(name);\n        }\n        Object instance = holder.get();\n        if (instance == null) {\n            synchronized (holder) {\n                instance = holder.get();\n                if (instance == null) {\n                    instance = createExtension(name, spiDir, standbyDir);\n                    holder.set(instance);\n                }\n            }\n        }\n        return (T) instance;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public T getExtension(String name, String key, String spiDir, String standbyDir) {\n        if (name == null || name.length() == 0) throw new IllegalArgumentException(\"Extension name == null\");\n        if (\"true\".equals(name)) {\n            return getDefaultExtension(spiDir, standbyDir);\n        }\n        String extKey = name + \"-\" + StringUtils.trimToEmpty(key);\n        Holder<Object> holder = cachedInstances.get(extKey);\n        if (holder == null) {\n            cachedInstances.putIfAbsent(extKey, new Holder<>());\n            holder = cachedInstances.get(extKey);\n        }\n        Object instance = holder.get();\n        if (instance == null) {\n            synchronized (holder) {\n                instance = holder.get();\n                if (instance == null) {\n                    instance = createExtension(name, key, spiDir, standbyDir);\n                    holder.set(instance);\n                }\n            }\n        }\n        return (T) instance;\n    }\n\n    /**\n     * 返回缺省的扩展，如果没有设置则返回<code>null</code>\n     */\n    public T getDefaultExtension(String spiDir, String standbyDir) {\n        getExtensionClasses(spiDir, standbyDir);\n        if (null == cachedDefaultName || cachedDefaultName.length() == 0 || \"true\".equals(cachedDefaultName)) {\n            return null;\n        }\n        return getExtension(cachedDefaultName, spiDir, standbyDir);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public T createExtension(String name, String spiDir, String standbyDir) {\n        Class<?> clazz = getExtensionClasses(spiDir, standbyDir).get(name);\n        if (clazz == null) {\n            throw new IllegalStateException(\"Extension instance(name: \" + name + \", class: \" + type\n                                            + \")  could not be instantiated: class could not be found\");\n        }\n        try {\n            T instance = (T) EXTENSION_INSTANCES.get(clazz);\n            if (instance == null) {\n                EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance());\n                instance = (T) EXTENSION_INSTANCES.get(clazz);\n            }\n            return instance;\n        } catch (Throwable t) {\n            throw new IllegalStateException(\"Extension instance(name: \" + name + \", class: \" + type\n                                            + \")  could not be instantiated: \" + t.getMessage(), t);\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private T createExtension(String name, String key, String spiDir, String standbyDir) {\n        Class<?> clazz = getExtensionClasses(spiDir, standbyDir).get(name);\n        if (clazz == null) {\n            throw new IllegalStateException(\"Extension instance(name: \" + name + \", class: \" + type\n                                            + \")  could not be instantiated: class could not be found\");\n        }\n        try {\n            T instance = (T) EXTENSION_KEY_INSTANCE.get(name + \"-\" + key);\n            if (instance == null) {\n                EXTENSION_KEY_INSTANCE.putIfAbsent(name + \"-\" + key, clazz.newInstance());\n                instance = (T) EXTENSION_KEY_INSTANCE.get(name + \"-\" + key);\n            }\n            return instance;\n        } catch (Throwable t) {\n            throw new IllegalStateException(\"Extension instance(name: \" + name + \", class: \" + type\n                                            + \")  could not be instantiated: \" + t.getMessage(), t);\n        }\n    }\n\n    private Map<String, Class<?>> getExtensionClasses(String spiDir, String standbyDir) {\n        Map<String, Class<?>> classes = cachedClasses.get();\n        if (classes == null) {\n            synchronized (cachedClasses) {\n                classes = cachedClasses.get();\n                if (classes == null) {\n                    classes = loadExtensionClasses(spiDir, standbyDir);\n                    cachedClasses.set(classes);\n                }\n            }\n        }\n\n        return classes;\n    }\n\n    private String getJarDirectoryPath() {\n        URL url = Thread.currentThread().getContextClassLoader().getResource(\"\");\n        String dirtyPath;\n        if (url != null) {\n            dirtyPath = url.toString();\n        } else {\n            File file = new File(\"\");\n            dirtyPath = file.getAbsolutePath();\n        }\n        String jarPath = dirtyPath.replaceAll(\"^.*file:/\", \"\"); // removes\n                                                                // file:/ and\n                                                                // everything\n                                                                // before it\n        jarPath = jarPath.replaceAll(\"jar!.*\", \"jar\"); // removes everything\n                                                       // after .jar, if .jar\n                                                       // exists in dirtyPath\n        jarPath = jarPath.replaceAll(\"%20\", \" \"); // necessary if path has\n                                                  // spaces within\n        if (!jarPath.endsWith(\".jar\")) { // this is needed if you plan to run\n                                         // the app using Spring Tools Suit play\n                                         // button.\n            jarPath = jarPath.replaceAll(\"/classes/.*\", \"/classes/\");\n        }\n        Path path = Paths.get(jarPath).getParent(); // Paths - from java 8\n        if (path != null) {\n            return path.toString();\n        }\n        return null;\n    }\n\n    private Map<String, Class<?>> loadExtensionClasses(String spiDir, String standbyDir) {\n        final SPI defaultAnnotation = type.getAnnotation(SPI.class);\n        if (defaultAnnotation != null) {\n            String value = defaultAnnotation.value();\n            if ((value = value.trim()).length() > 0) {\n                String[] names = NAME_SEPARATOR.split(value);\n                if (names.length > 1) {\n                    throw new IllegalStateException(\"more than 1 default extension name on extension \" + type.getName()\n                                                    + \": \" + Arrays.toString(names));\n                }\n                if (names.length == 1) cachedDefaultName = names[0];\n            }\n        }\n\n        Map<String, Class<?>> extensionClasses = new HashMap<>();\n\n        if (spiDir != null && standbyDir != null) {\n            // 1. plugin folder，customized extension classLoader\n            // （jar_dir/plugin）\n            String dir = File.separator + this.getJarDirectoryPath() + spiDir; // +\n                                                                               // \"plugin\";\n\n            File externalLibDir = new File(dir);\n            if (!externalLibDir.exists()) {\n                externalLibDir = new File(File.separator + this.getJarDirectoryPath() + standbyDir);\n            }\n            logger.info(\"extension classpath dir: \" + externalLibDir.getAbsolutePath());\n            if (externalLibDir.exists()) {\n                File[] files = externalLibDir.listFiles((dir1, name) -> name.endsWith(\".jar\"));\n                if (files != null) {\n                    for (File f : files) {\n                        URL url;\n                        try {\n                            url = f.toURI().toURL();\n                        } catch (MalformedURLException e) {\n                            throw new RuntimeException(\"load extension jar failed!\", e);\n                        }\n\n                        ClassLoader parent = Thread.currentThread().getContextClassLoader();\n                        URLClassLoader localClassLoader;\n                        if (classLoaderPolicy == null || \"\".equals(classLoaderPolicy)\n                            || DEFAULT_CLASSLOADER_POLICY.equalsIgnoreCase(classLoaderPolicy)) {\n                            localClassLoader = new URLClassExtensionLoader(new URL[] { url });\n                        } else {\n                            localClassLoader = new URLClassLoader(new URL[] { url }, parent);\n                        }\n\n                        loadFile(extensionClasses, CANAL_DIRECTORY, localClassLoader);\n                        loadFile(extensionClasses, SERVICES_DIRECTORY, localClassLoader);\n                    }\n                }\n            }\n        }\n\n        // 2. load inner extension class with default classLoader\n        ClassLoader classLoader = findClassLoader();\n        loadFile(extensionClasses, CANAL_DIRECTORY, classLoader);\n        loadFile(extensionClasses, SERVICES_DIRECTORY, classLoader);\n\n        return extensionClasses;\n    }\n\n    private void loadFile(Map<String, Class<?>> extensionClasses, String dir, ClassLoader classLoader) {\n        String fileName = dir + type.getName();\n        try {\n            Enumeration<URL> urls;\n            if (classLoader != null) {\n                urls = classLoader.getResources(fileName);\n            } else {\n                urls = ClassLoader.getSystemResources(fileName);\n            }\n            if (urls != null) {\n                while (urls.hasMoreElements()) {\n                    URL url = urls.nextElement();\n                    try {\n                        BufferedReader reader = null;\n                        try {\n                            reader = new BufferedReader(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8));\n                            String line = null;\n                            while ((line = reader.readLine()) != null) {\n                                final int ci = line.indexOf('#');\n                                if (ci >= 0) line = line.substring(0, ci);\n                                line = line.trim();\n                                if (line.length() > 0) {\n                                    try {\n                                        String name = null;\n                                        int i = line.indexOf('=');\n                                        if (i > 0) {\n                                            name = line.substring(0, i).trim();\n                                            line = line.substring(i + 1).trim();\n                                        }\n                                        if (line.length() > 0) {\n                                            Class<?> clazz = classLoader.loadClass(line);\n                                            // Class<?> clazz =\n                                            // Class.forName(line, true,\n                                            // classLoader);\n                                            if (!type.isAssignableFrom(clazz)) {\n                                                throw new IllegalStateException(\"Error when load extension class(interface: \"\n                                                                                + type\n                                                                                + \", class line: \"\n                                                                                + clazz.getName()\n                                                                                + \"), class \"\n                                                                                + clazz.getName()\n                                                                                + \"is not subtype of interface.\");\n                                            } else {\n                                                try {\n                                                    clazz.getConstructor(type);\n                                                } catch (NoSuchMethodException e) {\n                                                    clazz.getConstructor();\n                                                    String[] names = NAME_SEPARATOR.split(name);\n                                                    if (names != null && names.length > 0) {\n                                                        for (String n : names) {\n                                                            if (!cachedNames.containsKey(clazz)) {\n                                                                cachedNames.put(clazz, n);\n                                                            }\n                                                            Class<?> c = extensionClasses.get(n);\n                                                            if (c == null) {\n                                                                extensionClasses.put(n, clazz);\n                                                            } else if (c != clazz) {\n                                                                cachedNames.remove(clazz);\n                                                                throw new IllegalStateException(\"Duplicate extension \"\n                                                                                                + type.getName()\n                                                                                                + \" name \" + n + \" on \"\n                                                                                                + c.getName() + \" and \"\n                                                                                                + clazz.getName());\n                                                            }\n                                                        }\n                                                    }\n                                                }\n                                            }\n                                        }\n                                    } catch (Throwable t) {\n                                        IllegalStateException e = new IllegalStateException(\"Failed to load extension class(interface: \"\n                                                                                            + type\n                                                                                            + \", class line: \"\n                                                                                            + line\n                                                                                            + \") in \"\n                                                                                            + url\n                                                                                            + \", cause: \"\n                                                                                            + t.getMessage(),\n                                            t);\n                                        exceptions.put(line, e);\n                                    }\n                                }\n                            } // end of while read lines\n                        } finally {\n                            if (reader != null) {\n                                reader.close();\n                            }\n                        }\n                    } catch (Throwable t) {\n                        logger.error(\"Exception when load extension class(interface: \" + type + \", class file: \" + url\n                                     + \") in \" + url, t);\n                    }\n                } // end of while urls\n            }\n        } catch (Throwable t) {\n            logger.error(\"Exception when load extension class(interface: \" + type + \", description file: \" + fileName\n                         + \").\", t);\n        }\n    }\n\n    private static ClassLoader findClassLoader() {\n        return ExtensionLoader.class.getClassLoader();\n    }\n\n    @Override\n    public String toString() {\n        return this.getClass().getName() + \"[\" + type.getName() + \"]\";\n    }\n\n    private static class Holder<T> {\n\n        private volatile T value;\n\n        private void set(T value) {\n            this.value = value;\n        }\n\n        private T get() {\n            return value;\n        }\n\n    }\n}\n"
  },
  {
    "path": "connector/core/src/main/java/com/alibaba/otter/canal/connector/core/spi/ProxyCanalMQProducer.java",
    "content": "package com.alibaba.otter.canal.connector.core.spi;\n\nimport com.alibaba.otter.canal.connector.core.config.MQProperties;\nimport com.alibaba.otter.canal.connector.core.producer.MQDestination;\nimport com.alibaba.otter.canal.connector.core.util.Callback;\nimport com.alibaba.otter.canal.protocol.Message;\nimport java.util.Properties;\n\npublic class ProxyCanalMQProducer implements CanalMQProducer {\n\n    private CanalMQProducer canalMQProducer;\n\n    public ProxyCanalMQProducer(CanalMQProducer canalMQProducer) {\n        this.canalMQProducer = canalMQProducer;\n    }\n\n    private ClassLoader changeCL() {\n        ClassLoader cl = Thread.currentThread().getContextClassLoader();\n        Thread.currentThread().setContextClassLoader(canalMQProducer.getClass().getClassLoader());\n        return cl;\n    }\n\n    private void revertCL(ClassLoader cl) {\n        Thread.currentThread().setContextClassLoader(cl);\n    }\n\n    @Override\n    public void init(Properties properties) {\n        ClassLoader cl = changeCL();\n        try {\n            canalMQProducer.init(properties);\n        } finally {\n            revertCL(cl);\n        }\n    }\n\n    @Override\n    public MQProperties getMqProperties() {\n        ClassLoader cl = changeCL();\n        try {\n            return canalMQProducer.getMqProperties();\n        } finally {\n            revertCL(cl);\n        }\n    }\n\n    @Override\n    public void send(MQDestination canalDestination, Message message, Callback callback) {\n        ClassLoader cl = changeCL();\n        try {\n            canalMQProducer.send(canalDestination, message, callback);\n        } finally {\n            revertCL(cl);\n        }\n    }\n\n    @Override\n    public void stop() {\n        ClassLoader cl = changeCL();\n        try {\n            canalMQProducer.stop();\n        } finally {\n            revertCL(cl);\n        }\n    }\n}\n"
  },
  {
    "path": "connector/core/src/main/java/com/alibaba/otter/canal/connector/core/spi/ProxyCanalMsgConsumer.java",
    "content": "package com.alibaba.otter.canal.connector.core.spi;\n\nimport com.alibaba.otter.canal.connector.core.consumer.CommonMessage;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.concurrent.TimeUnit;\n\npublic class ProxyCanalMsgConsumer implements CanalMsgConsumer {\n\n    private CanalMsgConsumer canalMsgConsumer;\n\n    public ProxyCanalMsgConsumer(CanalMsgConsumer canalMsgConsumer) {\n        this.canalMsgConsumer = canalMsgConsumer;\n    }\n\n    private ClassLoader changeCL() {\n        ClassLoader cl = Thread.currentThread().getContextClassLoader();\n        Thread.currentThread().setContextClassLoader(canalMsgConsumer.getClass().getClassLoader());\n        return cl;\n    }\n\n    private void revertCL(ClassLoader cl) {\n        Thread.currentThread().setContextClassLoader(cl);\n    }\n\n\n    @Override\n    public void init(Properties properties, String topic, String groupId) {\n        ClassLoader cl = changeCL();\n        try {\n            canalMsgConsumer.init(properties, topic, groupId);\n        } finally {\n            revertCL(cl);\n        }\n    }\n\n    @Override\n    public void connect() {\n        ClassLoader cl = changeCL();\n        try {\n            canalMsgConsumer.connect();\n        } finally {\n            revertCL(cl);\n        }\n    }\n\n    @Override\n    public List<CommonMessage> getMessage(Long timeout, TimeUnit unit) {\n        ClassLoader cl = changeCL();\n        try {\n            return canalMsgConsumer.getMessage(timeout, unit);\n        } finally {\n            revertCL(cl);\n        }\n    }\n\n    @Override\n    public void ack() {\n        ClassLoader cl = changeCL();\n        try {\n            canalMsgConsumer.ack();\n        } finally {\n            revertCL(cl);\n        }\n    }\n\n    @Override\n    public void rollback() {\n        ClassLoader cl = changeCL();\n        try {\n            canalMsgConsumer.rollback();\n        } finally {\n            revertCL(cl);\n        }\n    }\n\n    @Override\n    public void disconnect() {\n        ClassLoader cl = changeCL();\n        try {\n            canalMsgConsumer.disconnect();\n        } finally {\n            revertCL(cl);\n        }\n    }\n}\n"
  },
  {
    "path": "connector/core/src/main/java/com/alibaba/otter/canal/connector/core/spi/SPI.java",
    "content": "package com.alibaba.otter.canal.connector.core.spi;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * SPI装载器注解\n *\n * @author rewerma @ 2018-10-20\n * @version 1.0.0\n */\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE })\npublic @interface SPI {\n\n    // Default SPI name\n    String value() default \"\";\n}\n"
  },
  {
    "path": "connector/core/src/main/java/com/alibaba/otter/canal/connector/core/spi/URLClassExtensionLoader.java",
    "content": "package com.alibaba.otter.canal.connector.core.spi;\n\nimport java.io.IOException;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.util.Enumeration;\nimport java.util.NoSuchElementException;\n\npublic class URLClassExtensionLoader extends URLClassLoader {\n\n    public URLClassExtensionLoader(URL[] urls){\n        super(urls);\n    }\n\n    @Override\n    public Class<?> loadClass(String name) throws ClassNotFoundException {\n        Class<?> c = findLoadedClass(name);\n        if (c != null) {\n            return c;\n        }\n\n        if (name.startsWith(\"java.\") || name.startsWith(\"org.slf4j.\") || name.startsWith(\"org.apache.logging\")\n            || name.startsWith(\"org.apache.zookeeper.\") || name.startsWith(\"org.I0Itec.zkclient.\")\n            || name.startsWith(\"org.apache.commons.logging.\")) {\n            // || name.startsWith(\"org.apache.hadoop.\"))\n            // {\n            c = super.loadClass(name);\n        }\n        if (c != null) return c;\n\n        try {\n            // 先加载jar内的class，可避免jar冲突\n            c = findClass(name);\n        } catch (ClassNotFoundException e) {\n            c = null;\n        }\n        if (c != null) {\n            return c;\n        }\n\n        return super.loadClass(name);\n    }\n\n    @Override\n    public Enumeration<URL> getResources(String name) throws IOException {\n        @SuppressWarnings(\"unchecked\")\n        Enumeration<URL>[] tmp = (Enumeration<URL>[]) new Enumeration<?>[2];\n\n        tmp[0] = findResources(name); // local class\n        // path first\n        // tmp[1] = super.getResources(name);\n\n        return new CompoundEnumeration<>(tmp);\n    }\n\n    private static class CompoundEnumeration<E> implements Enumeration<E> {\n\n        private Enumeration<E>[] enums;\n        private int              index = 0;\n\n        public CompoundEnumeration(Enumeration<E>[] enums){\n            this.enums = enums;\n        }\n\n        private boolean next() {\n            while (this.index < this.enums.length) {\n                if (this.enums[this.index] != null && this.enums[this.index].hasMoreElements()) {\n                    return true;\n                }\n\n                ++this.index;\n            }\n\n            return false;\n        }\n\n        public boolean hasMoreElements() {\n            return this.next();\n        }\n\n        public E nextElement() {\n            if (!this.next()) {\n                throw new NoSuchElementException();\n            } else {\n                return this.enums[this.index].nextElement();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "connector/core/src/main/java/com/alibaba/otter/canal/connector/core/util/Callback.java",
    "content": "package com.alibaba.otter.canal.connector.core.util;\n\n/**\n * MQ 回调类\n *\n * @author rewerma 2020-01-27\n * @version 1.0.0\n */\npublic interface Callback {\n\n    void commit();\n\n    void rollback();\n}\n"
  },
  {
    "path": "connector/core/src/main/java/com/alibaba/otter/canal/connector/core/util/CanalMessageSerializerUtil.java",
    "content": "package com.alibaba.otter.canal.connector.core.util;\n\nimport java.util.List;\n\nimport org.springframework.util.CollectionUtils;\n\nimport com.alibaba.otter.canal.protocol.CanalEntry;\nimport com.alibaba.otter.canal.protocol.CanalPacket;\nimport com.alibaba.otter.canal.protocol.CanalPacket.PacketType;\nimport com.alibaba.otter.canal.protocol.Message;\nimport com.alibaba.otter.canal.protocol.exception.CanalClientException;\nimport com.google.protobuf.ByteString;\nimport com.google.protobuf.CodedOutputStream;\nimport com.google.protobuf.WireFormat;\n\n/**\n * Canal message 序列化工具类\n *\n * @author rewerma 2020-01-27\n * @version 1.0.0\n */\npublic class CanalMessageSerializerUtil {\n\n    @SuppressWarnings(\"deprecation\")\n    public static byte[] serializer(Message data, boolean filterTransactionEntry) {\n        try {\n            if (data != null) {\n                if (data.getId() != -1) {\n                    if (data.isRaw() && !CollectionUtils.isEmpty(data.getRawEntries())) {\n                        // for performance\n                        List<ByteString> rowEntries = data.getRawEntries();\n                        // message size\n                        int messageSize = 0;\n                        messageSize += CodedOutputStream.computeInt64Size(1, data.getId());\n\n                        int dataSize = 0;\n                        for (ByteString rowEntry : rowEntries) {\n                            dataSize += CodedOutputStream.computeBytesSizeNoTag(rowEntry);\n                        }\n                        messageSize += dataSize;\n                        messageSize += 1 * rowEntries.size();\n                        // packet size\n                        int size = 0;\n                        size += CodedOutputStream.computeEnumSize(3, PacketType.MESSAGES.getNumber());\n                        size += CodedOutputStream.computeTagSize(5)\n                                + CodedOutputStream.computeRawVarint32Size(messageSize) + messageSize;\n                        // build data\n                        byte[] body = new byte[size];\n                        CodedOutputStream output = CodedOutputStream.newInstance(body);\n                        output.writeEnum(3, PacketType.MESSAGES.getNumber());\n\n                        output.writeTag(5, WireFormat.WIRETYPE_LENGTH_DELIMITED);\n                        output.writeRawVarint32(messageSize);\n                        // message\n                        output.writeInt64(1, data.getId());\n                        for (ByteString rowEntry : rowEntries) {\n                            output.writeBytes(2, rowEntry);\n                        }\n                        output.checkNoSpaceLeft();\n                        return body;\n                    } else if (!CollectionUtils.isEmpty(data.getEntries())) {\n                        // mq模式只会走到非rawEntry模式\n                        CanalPacket.Messages.Builder messageBuilder = CanalPacket.Messages.newBuilder();\n                        for (CanalEntry.Entry entry : data.getEntries()) {\n                            if (filterTransactionEntry\n                                && (entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONBEGIN || entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONEND)) {\n                                continue;\n                            }\n\n                            messageBuilder.addMessages(entry.toByteString());\n                        }\n\n                        CanalPacket.Packet.Builder packetBuilder = CanalPacket.Packet.newBuilder();\n                        packetBuilder.setType(PacketType.MESSAGES);\n                        packetBuilder.setVersion(1);\n                        packetBuilder.setBody(messageBuilder.build().toByteString());\n                        return packetBuilder.build().toByteArray();\n                    }\n                }\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(\"Error when serializing message to byte[] by \" + e.getMessage() , e);\n        }\n        return null;\n    }\n\n    public static Message deserializer(byte[] data) {\n        return deserializer(data, false);\n    }\n\n    public static Message deserializer(byte[] data, boolean lazyParseEntry) {\n        try {\n            if (data == null) {\n                return null;\n            } else {\n                CanalPacket.Packet p = CanalPacket.Packet.parseFrom(data);\n                switch (p.getType()) {\n                    case MESSAGES: {\n                        if (!p.getCompression().equals(CanalPacket.Compression.NONE)\n                            && !p.getCompression().equals(CanalPacket.Compression.COMPRESSIONCOMPATIBLEPROTO2)) {\n                            throw new CanalClientException(\"compression is not supported in this connector\");\n                        }\n\n                        CanalPacket.Messages messages = CanalPacket.Messages.parseFrom(p.getBody());\n                        Message result = new Message(messages.getBatchId());\n                        if (lazyParseEntry) {\n                            // byteString\n                            result.setRawEntries(messages.getMessagesList());\n                            result.setRaw(true);\n                        } else {\n                            for (ByteString byteString : messages.getMessagesList()) {\n                                result.addEntry(CanalEntry.Entry.parseFrom(byteString));\n                            }\n                            result.setRaw(false);\n                        }\n                        return result;\n                    }\n                    case ACK: {\n                        CanalPacket.Ack ack = CanalPacket.Ack.parseFrom(p.getBody());\n                        throw new CanalClientException(\"something goes wrong with reason: \" + ack.getErrorMessage());\n                    }\n                    default: {\n                        throw new CanalClientException(\"unexpected packet type: \" + p.getType());\n                    }\n                }\n            }\n        } catch (Exception e) {\n            throw new CanalClientException(\"deserializer failed by \" + e.getMessage(), e);\n        }\n    }\n}\n"
  },
  {
    "path": "connector/core/src/main/java/com/alibaba/otter/canal/connector/core/util/DateUtil.java",
    "content": "package com.alibaba.otter.canal.connector.core.util;\n\nimport java.util.Date;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.joda.time.DateTime;\nimport org.joda.time.DateTimeZone;\n\npublic class DateUtil {\n\n    private static DateTimeZone dateTimeZone;\n\n    static {\n        dateTimeZone = DateTimeZone.forID(TimeZone.LOCATION_TIME_ZONE);\n    }\n\n    /**\n     * 通用日期时间字符解析\n     *\n     * @param datetimeStr 日期时间字符串\n     * @return Date\n     */\n    public static Date parseDate(String datetimeStr) {\n        if (StringUtils.isEmpty(datetimeStr)) {\n            return null;\n        }\n        datetimeStr = datetimeStr.trim().replace('/', '-');\n        if (datetimeStr.contains(\"-\")) {\n            if (datetimeStr.contains(\":\")) {\n                datetimeStr = datetimeStr.replace(\" \", \"T\");\n            }\n        } else if (datetimeStr.contains(\":\")) {\n            datetimeStr = \"T\" + datetimeStr;\n        } else {\n            if (datetimeStr.length() == 8) {\n                String year = datetimeStr.substring(0, 4);\n                String month = datetimeStr.substring(4, 6);\n                String day = datetimeStr.substring(6, 8);\n                datetimeStr = year + \"-\" + month + \"-\" + day;\n            }\n        }\n\n        DateTime dateTime = new DateTime(datetimeStr, dateTimeZone);\n\n        return dateTime.toDate();\n    }\n}\n"
  },
  {
    "path": "connector/core/src/main/java/com/alibaba/otter/canal/connector/core/util/JdbcTypeUtil.java",
    "content": "package com.alibaba.otter.canal.connector.core.util;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.sql.Date;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.sql.Time;\nimport java.sql.Timestamp;\nimport java.sql.Types;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * 类型转换工具类\n *\n * @author rewerma 2018-8-19 下午06:14:23\n * @version 1.0.0\n */\npublic class JdbcTypeUtil {\n\n    private static Logger logger = LoggerFactory.getLogger(JdbcTypeUtil.class);\n\n    public static Object getRSData(ResultSet rs, String columnName, int jdbcType) throws SQLException {\n        if (jdbcType == Types.BIT || jdbcType == Types.BOOLEAN) {\n            return rs.getByte(columnName);\n        } else {\n            return rs.getObject(columnName);\n        }\n    }\n\n    public static Class<?> jdbcType2javaType(int jdbcType) {\n        switch (jdbcType) {\n            case Types.BIT:\n            case Types.BOOLEAN:\n                // return Boolean.class;\n            case Types.TINYINT:\n                return Byte.TYPE;\n            case Types.SMALLINT:\n                return Short.class;\n            case Types.INTEGER:\n                return Integer.class;\n            case Types.BIGINT:\n                return Long.class;\n            case Types.DECIMAL:\n            case Types.NUMERIC:\n                return BigDecimal.class;\n            case Types.REAL:\n                return Float.class;\n            case Types.FLOAT:\n            case Types.DOUBLE:\n                return Double.class;\n            case Types.CHAR:\n            case Types.VARCHAR:\n            case Types.LONGVARCHAR:\n                return String.class;\n            case Types.BINARY:\n            case Types.VARBINARY:\n            case Types.LONGVARBINARY:\n            case Types.BLOB:\n                return byte[].class;\n            case Types.DATE:\n                return Date.class;\n            case Types.TIME:\n                return Time.class;\n            case Types.TIMESTAMP:\n                return Timestamp.class;\n            default:\n                return String.class;\n        }\n    }\n\n    private static boolean isText(String columnType) {\n        return \"LONGTEXT\".equalsIgnoreCase(columnType) || \"MEDIUMTEXT\".equalsIgnoreCase(columnType)\n               || \"TEXT\".equalsIgnoreCase(columnType) || \"TINYTEXT\".equalsIgnoreCase(columnType);\n    }\n\n    public static Object typeConvert(String tableName, String columnName, String value, int sqlType, String mysqlType) {\n        if (value == null\n            || (value.equals(\"\") && !(isText(mysqlType) || sqlType == Types.CHAR || sqlType == Types.VARCHAR || sqlType == Types.LONGVARCHAR))) {\n            return null;\n        }\n\n        try {\n            Object res;\n            switch (sqlType) {\n                case Types.INTEGER:\n                    res = Integer.parseInt(value);\n                    break;\n                case Types.SMALLINT:\n                    res = Short.parseShort(value);\n                    break;\n                case Types.BIT:\n                case Types.TINYINT:\n                    res = Byte.parseByte(value);\n                    break;\n                case Types.BIGINT:\n                    if (mysqlType != null && mysqlType.startsWith(\"bigint\") && mysqlType.endsWith(\"unsigned\")) {\n                        res = new BigInteger(value);\n                    } else {\n                        res = Long.parseLong(value);\n                    }\n                    break;\n                // case Types.BIT:\n                case Types.BOOLEAN:\n                    res = !\"0\".equals(value);\n                    break;\n                case Types.DOUBLE:\n                case Types.FLOAT:\n                    res = Double.parseDouble(value);\n                    break;\n                case Types.REAL:\n                    res = Float.parseFloat(value);\n                    break;\n                case Types.DECIMAL:\n                case Types.NUMERIC:\n                    res = new BigDecimal(value);\n                    break;\n                case Types.BINARY:\n                case Types.VARBINARY:\n                case Types.LONGVARBINARY:\n                case Types.BLOB:\n                    res = value.getBytes(\"ISO-8859-1\");\n                    break;\n                case Types.DATE:\n                    if (!value.startsWith(\"0000-00-00\")) {\n                        java.util.Date date = DateUtil.parseDate(value);\n                        if (date != null) {\n                            res = new Date(date.getTime());\n                        } else {\n                            res = null;\n                        }\n                    } else {\n                        res = null;\n                    }\n                    break;\n                case Types.TIME: {\n                    java.util.Date date = DateUtil.parseDate(value);\n                    if (date != null) {\n                        res = new Time(date.getTime());\n                    } else {\n                        res = null;\n                    }\n                    break;\n                }\n                case Types.TIMESTAMP:\n                    if (!value.startsWith(\"0000-00-00\")) {\n                        java.util.Date date = DateUtil.parseDate(value);\n                        if (date != null) {\n                            res = new Timestamp(date.getTime());\n                        } else {\n                            res = null;\n                        }\n                    } else {\n                        res = null;\n                    }\n                    break;\n                case Types.CLOB:\n                default:\n                    res = value;\n                    break;\n            }\n            return res;\n        } catch (Exception e) {\n            logger.error(\"table: {} column: {}, failed convert type {} to {}\", tableName, columnName, value, sqlType);\n            return value;\n        }\n    }\n}\n"
  },
  {
    "path": "connector/core/src/main/java/com/alibaba/otter/canal/connector/core/util/MessageUtil.java",
    "content": "package com.alibaba.otter.canal.connector.core.util;\n\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport com.alibaba.otter.canal.connector.core.consumer.CommonMessage;\nimport com.alibaba.otter.canal.protocol.CanalEntry;\nimport com.alibaba.otter.canal.protocol.Message;\n\n/**\n * Message对象解析工具类\n *\n * @author rewerma 2018-8-19 下午06:14:23\n * @version 1.0.0\n */\npublic class MessageUtil {\n\n    public static List<CommonMessage> convert(Message message) {\n        if (message == null) {\n            return null;\n        }\n        List<CanalEntry.Entry> entries = message.getEntries();\n        List<CommonMessage> msgs = new ArrayList<>(entries.size());\n        for (CanalEntry.Entry entry : entries) {\n            if (entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONBEGIN\n                || entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONEND) {\n                continue;\n            }\n\n            CanalEntry.RowChange rowChange;\n            try {\n                rowChange = CanalEntry.RowChange.parseFrom(entry.getStoreValue());\n            } catch (Exception e) {\n                throw new RuntimeException(\"ERROR ## parser of eromanga-event has an error , data:\" + entry.toString(),\n                    e);\n            }\n\n            CanalEntry.EventType eventType = rowChange.getEventType();\n\n            final CommonMessage msg = new CommonMessage();\n            msg.setIsDdl(rowChange.getIsDdl());\n            msg.setDatabase(entry.getHeader().getSchemaName());\n            msg.setTable(entry.getHeader().getTableName());\n            msg.setType(eventType.toString());\n            msg.setEs(entry.getHeader().getExecuteTime());\n            msg.setIsDdl(rowChange.getIsDdl());\n            msg.setTs(System.currentTimeMillis());\n            msg.setSql(rowChange.getSql());\n            msgs.add(msg);\n            List<Map<String, Object>> data = new ArrayList<>();\n            List<Map<String, Object>> old = new ArrayList<>();\n\n            if (!rowChange.getIsDdl()) {\n                Set<String> updateSet = new HashSet<>();\n                msg.setPkNames(new ArrayList<>());\n                int i = 0;\n                for (CanalEntry.RowData rowData : rowChange.getRowDatasList()) {\n                    if (eventType != CanalEntry.EventType.INSERT && eventType != CanalEntry.EventType.UPDATE\n                        && eventType != CanalEntry.EventType.DELETE) {\n                        continue;\n                    }\n\n                    Map<String, Object> row = new LinkedHashMap<>();\n                    List<CanalEntry.Column> columns;\n\n                    if (eventType == CanalEntry.EventType.DELETE) {\n                        columns = rowData.getBeforeColumnsList();\n                    } else {\n                        columns = rowData.getAfterColumnsList();\n                    }\n\n                    for (CanalEntry.Column column : columns) {\n                        if (i == 0) {\n                            if (column.getIsKey()) {\n                                msg.getPkNames().add(column.getName());\n                            }\n                        }\n                        if (column.getIsNull()) {\n                            row.put(column.getName(), null);\n                        } else {\n                            row.put(column.getName(),\n                                JdbcTypeUtil.typeConvert(msg.getTable(),\n                                    column.getName(),\n                                    column.getValue(),\n                                    column.getSqlType(),\n                                    column.getMysqlType()));\n                        }\n                        // 获取update为true的字段\n                        if (column.getUpdated()) {\n                            updateSet.add(column.getName());\n                        }\n                    }\n                    if (!row.isEmpty()) {\n                        data.add(row);\n                    }\n\n                    if (eventType == CanalEntry.EventType.UPDATE) {\n                        Map<String, Object> rowOld = new LinkedHashMap<>();\n                        for (CanalEntry.Column column : rowData.getBeforeColumnsList()) {\n                            if (updateSet.contains(column.getName())) {\n                                if (column.getIsNull()) {\n                                    rowOld.put(column.getName(), null);\n                                } else {\n                                    rowOld.put(column.getName(), JdbcTypeUtil.typeConvert(msg.getTable(),\n                                        column.getName(),\n                                        column.getValue(),\n                                        column.getSqlType(),\n                                        column.getMysqlType()));\n                                }\n                            }\n                        }\n                        // update操作将记录修改前的值\n                        if (!rowOld.isEmpty()) {\n                            old.add(rowOld);\n                        }\n                    }\n\n                    i++;\n                }\n                if (!data.isEmpty()) {\n                    msg.setData(data);\n                }\n                if (!old.isEmpty()) {\n                    msg.setOld(old);\n                }\n            }\n        }\n\n        return msgs;\n    }\n}\n"
  },
  {
    "path": "connector/core/src/main/java/com/alibaba/otter/canal/connector/core/util/TimeZone.java",
    "content": "package com.alibaba.otter.canal.connector.core.util;\n\npublic class TimeZone {\n\n    public final static String LOCATION_TIME_ZONE; // 当前时区\n\n    static {\n        java.util.TimeZone localTimeZone = java.util.TimeZone.getDefault();\n        int rawOffset = localTimeZone.getRawOffset();\n        String symbol = \"+\";\n        if (rawOffset < 0) {\n            symbol = \"-\";\n        }\n        rawOffset = Math.abs(rawOffset);\n        int offsetHour = rawOffset / 3600000;\n        int offsetMinute = rawOffset % 3600000 / 60000;\n        String hour = String.format(\"%1$02d\", offsetHour);\n        String minute = String.format(\"%1$02d\", offsetMinute);\n        LOCATION_TIME_ZONE = symbol + hour + \":\" + minute;\n        java.util.TimeZone.setDefault(java.util.TimeZone.getTimeZone(\"GMT\" + LOCATION_TIME_ZONE));\n    }\n}\n"
  },
  {
    "path": "connector/kafka-connector/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>canal.connector</artifactId>\n        <groupId>com.alibaba.otter</groupId>\n        <version>1.1.9-SNAPSHOT</version>\n        <relativePath>../pom.xml</relativePath>\n    </parent>\n\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>com.alibaba.otter</groupId>\n    <artifactId>connector.kafka</artifactId>\n    <packaging>jar</packaging>\n    <name>canal connector kafka module for otter ${project.version}</name>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>canal.protocol</artifactId>\n            <version>${project.version}</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>connector.core</artifactId>\n            <version>${project.version}</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.kafka</groupId>\n            <artifactId>kafka-clients</artifactId>\n            <version>${kafka_version}</version>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-assembly-plugin</artifactId>\n                <version>2.4</version>\n                <configuration>\n                    <descriptorRefs>\n                        <descriptorRef>jar-with-dependencies</descriptorRef>\n                    </descriptorRefs>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>make-assembly</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>single</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-antrun-plugin</artifactId>\n                <version>1.8</version>\n                <executions>\n                    <execution>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>run</goal>\n                        </goals>\n                        <configuration>\n                            <tasks>\n                                <copy todir=\"${project.basedir}/../../deployer/target/canal/plugin\" overwrite=\"true\">\n                                    <fileset dir=\"${project.basedir}/target\" erroronmissingdir=\"true\">\n                                        <include name=\"connector.kafka-${project.version}-jar-with-dependencies.jar\" />\n                                    </fileset>\n                                </copy>\n                                <copy todir=\"${project.basedir}/../../client-adapter/launcher/target/canal-adapter/plugin\" overwrite=\"true\">\n                                    <fileset dir=\"${project.basedir}/target\" erroronmissingdir=\"true\">\n                                        <include name=\"connector.kafka-${project.version}-jar-with-dependencies.jar\" />\n                                    </fileset>\n                                </copy>\n                            </tasks>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "connector/kafka-connector/src/main/java/com/alibaba/otter/canal/connector/kafka/config/KafkaConstants.java",
    "content": "package com.alibaba.otter.canal.connector.kafka.config;\n\n/**\n * Kafka 配置常量类\n *\n * @author rewerma 2020-01-27\n * @version 1.0.0\n */\npublic class KafkaConstants {\n\n    public static final String ROOT                              = \"kafka\";\n\n    public static final String CANAL_MQ_KAFKA_KERBEROS_ENABLE    = ROOT + \".\" + \"kerberos.enable\";\n    public static final String CANAL_MQ_KAFKA_KERBEROS_KRB5_FILE = ROOT + \".\" + \"kerberos.krb5.file\";\n    public static final String CANAL_MQ_KAFKA_KERBEROS_JAAS_FILE = ROOT + \".\" + \"kerberos.jaas.file\";\n}\n"
  },
  {
    "path": "connector/kafka-connector/src/main/java/com/alibaba/otter/canal/connector/kafka/config/KafkaProducerConfig.java",
    "content": "package com.alibaba.otter.canal.connector.kafka.config;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport com.alibaba.otter.canal.connector.core.config.MQProperties;\n\n/**\n * Kafka producer 配置类\n *\n * @author rewerma 2020-01-27\n * @version 1.0.0\n */\npublic class KafkaProducerConfig extends MQProperties {\n\n    private Map<String, Object> kafkaProperties = new LinkedHashMap<>();\n\n    private boolean             kerberosEnabled = false;\n    private String              krb5File;\n    private String              jaasFile;\n\n    public Map<String, Object> getKafkaProperties() {\n        return kafkaProperties;\n    }\n\n    public void setKafkaProperties(Map<String, Object> kafkaProperties) {\n        this.kafkaProperties = kafkaProperties;\n    }\n\n    public boolean isKerberosEnabled() {\n        return kerberosEnabled;\n    }\n\n    public void setKerberosEnabled(boolean kerberosEnabled) {\n        this.kerberosEnabled = kerberosEnabled;\n    }\n\n    public String getKrb5File() {\n        return krb5File;\n    }\n\n    public void setKrb5File(String krb5File) {\n        this.krb5File = krb5File;\n    }\n\n    public String getJaasFile() {\n        return jaasFile;\n    }\n\n    public void setJaasFile(String jaasFile) {\n        this.jaasFile = jaasFile;\n    }\n}\n"
  },
  {
    "path": "connector/kafka-connector/src/main/java/com/alibaba/otter/canal/connector/kafka/consumer/CanalKafkaConsumer.java",
    "content": "package com.alibaba.otter.canal.connector.kafka.consumer;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.UUID;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.TimeUnit;\n\nimport com.alibaba.otter.canal.common.utils.PropertiesUtils;\nimport org.apache.kafka.clients.consumer.ConsumerRecord;\nimport org.apache.kafka.clients.consumer.ConsumerRecords;\nimport org.apache.kafka.clients.consumer.KafkaConsumer;\nimport org.apache.kafka.common.TopicPartition;\nimport org.apache.kafka.common.serialization.StringDeserializer;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.otter.canal.connector.core.config.CanalConstants;\nimport com.alibaba.otter.canal.connector.core.consumer.CommonMessage;\nimport com.alibaba.otter.canal.connector.core.spi.CanalMsgConsumer;\nimport com.alibaba.otter.canal.connector.core.spi.SPI;\nimport com.alibaba.otter.canal.connector.core.util.MessageUtil;\nimport com.alibaba.otter.canal.protocol.Message;\n\n/**\n * Kafka consumer SPI 实现\n *\n * @author rewerma @ 2020-02-01\n * @version 1.0.0\n */\n@SPI(\"kafka\")\npublic class CanalKafkaConsumer implements CanalMsgConsumer {\n\n    private static final String      PREFIX_KAFKA_CONFIG = \"kafka.\";\n\n    private KafkaConsumer<String, ?> kafkaConsumer;\n    private boolean                  flatMessage         = true;\n    private String                   topic;\n\n    private Map<Integer, Long>       currentOffsets      = new ConcurrentHashMap<>();\n    private Properties               kafkaProperties     = new Properties();\n\n    @Override\n    public void init(Properties properties, String topic, String groupId) {\n        this.topic = topic;\n\n        Boolean flatMessage = (Boolean) properties.get(CanalConstants.CANAL_MQ_FLAT_MESSAGE);\n        if (flatMessage != null) {\n            this.flatMessage = flatMessage;\n        }\n        for (Map.Entry<Object, Object> entry : properties.entrySet()) {\n            String k = (String) entry.getKey();\n            Object v = entry.getValue();\n            if (k.startsWith(PREFIX_KAFKA_CONFIG) && v != null) {\n                // check env config\n                v = PropertiesUtils.getProperty(properties, k);\n                kafkaProperties.put(k.substring(PREFIX_KAFKA_CONFIG.length()), v);\n            }\n        }\n        kafkaProperties.put(\"group.id\", groupId);\n        kafkaProperties.put(\"key.deserializer\", StringDeserializer.class);\n        kafkaProperties.put(\"client.id\", UUID.randomUUID().toString().substring(0, 6));\n    }\n\n    @Override\n    public void connect() {\n        if (this.flatMessage) {\n            kafkaProperties.put(\"value.deserializer\", StringDeserializer.class);\n            this.kafkaConsumer = new KafkaConsumer<String, String>(kafkaProperties);\n        } else {\n            kafkaProperties.put(\"value.deserializer\", KafkaMessageDeserializer.class);\n            this.kafkaConsumer = new KafkaConsumer<String, Message>(kafkaProperties);\n        }\n        kafkaConsumer.subscribe(Collections.singletonList(topic));\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public List<CommonMessage> getMessage(Long timeout, TimeUnit unit) {\n        if (!flatMessage) {\n            ConsumerRecords<String, Message> records = (ConsumerRecords<String, Message>) kafkaConsumer.poll(unit.toMillis(timeout));\n            if (!records.isEmpty()) {\n                currentOffsets.clear();\n                List<CommonMessage> messages = new ArrayList<>();\n                for (ConsumerRecord<String, Message> record : records) {\n                    if (currentOffsets.get(record.partition()) == null) {\n                        currentOffsets.put(record.partition(), record.offset());\n                    }\n                    messages.addAll(MessageUtil.convert(record.value()));\n                }\n                return messages;\n            }\n        } else {\n            ConsumerRecords<String, String> records = (ConsumerRecords<String, String>) kafkaConsumer.poll(unit.toMillis(timeout));\n\n            if (!records.isEmpty()) {\n                List<CommonMessage> messages = new ArrayList<>();\n                currentOffsets.clear();\n                for (ConsumerRecord<String, String> record : records) {\n                    if (currentOffsets.get(record.partition()) == null) {\n                        currentOffsets.put(record.partition(), record.offset());\n                    }\n                    String flatMessageJson = record.value();\n                    CommonMessage flatMessages = JSON.parseObject(flatMessageJson, CommonMessage.class);\n                    messages.add(flatMessages);\n                }\n                return messages;\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public void rollback() {\n        // 回滚所有分区\n        if (kafkaConsumer != null) {\n            for (Map.Entry<Integer, Long> entry : currentOffsets.entrySet()) {\n                kafkaConsumer.seek(new TopicPartition(topic, entry.getKey()), currentOffsets.get(entry.getKey()));\n                kafkaConsumer.commitSync();\n            }\n        }\n    }\n\n    @Override\n    public void ack() {\n        if (kafkaConsumer != null) {\n            kafkaConsumer.commitSync();\n        }\n    }\n\n    @Override\n    public void disconnect() {\n        if (kafkaConsumer != null) {\n            kafkaConsumer.unsubscribe();\n        }\n        if (kafkaConsumer != null) {\n            kafkaConsumer.close();\n            kafkaConsumer = null;\n        }\n    }\n}\n"
  },
  {
    "path": "connector/kafka-connector/src/main/java/com/alibaba/otter/canal/connector/kafka/consumer/KafkaMessageDeserializer.java",
    "content": "package com.alibaba.otter.canal.connector.kafka.consumer;\n\nimport java.util.Map;\n\nimport org.apache.kafka.common.serialization.Deserializer;\n\nimport com.alibaba.otter.canal.connector.core.util.CanalMessageSerializerUtil;\nimport com.alibaba.otter.canal.protocol.Message;\n\n/**\n * Kafka Message类的反序列化\n *\n * @author rewerma @ 2018-6-12\n * @version 1.0.0\n */\npublic class KafkaMessageDeserializer implements Deserializer<Message> {\n\n    @Override\n    public void configure(Map<String, ?> configs, boolean isKey) {\n    }\n\n    @Override\n    public Message deserialize(String topic1, byte[] data) {\n        return CanalMessageSerializerUtil.deserializer(data);\n    }\n\n    @Override\n    public void close() {\n        // nothing to do\n    }\n}\n"
  },
  {
    "path": "connector/kafka-connector/src/main/java/com/alibaba/otter/canal/connector/kafka/producer/CanalKafkaProducer.java",
    "content": "package com.alibaba.otter.canal.connector.kafka.producer;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Future;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.kafka.clients.producer.KafkaProducer;\nimport org.apache.kafka.clients.producer.Producer;\nimport org.apache.kafka.clients.producer.ProducerRecord;\nimport org.apache.kafka.common.serialization.StringSerializer;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.JSONWriter;\nimport com.alibaba.otter.canal.common.utils.ExecutorTemplate;\nimport com.alibaba.otter.canal.common.utils.PropertiesUtils;\nimport com.alibaba.otter.canal.connector.core.producer.AbstractMQProducer;\nimport com.alibaba.otter.canal.connector.core.producer.MQDestination;\nimport com.alibaba.otter.canal.connector.core.producer.MQMessageUtils;\nimport com.alibaba.otter.canal.connector.core.producer.MQMessageUtils.EntryRowData;\nimport com.alibaba.otter.canal.connector.core.spi.CanalMQProducer;\nimport com.alibaba.otter.canal.connector.core.spi.SPI;\nimport com.alibaba.otter.canal.connector.core.util.Callback;\nimport com.alibaba.otter.canal.connector.core.util.CanalMessageSerializerUtil;\nimport com.alibaba.otter.canal.connector.kafka.config.KafkaConstants;\nimport com.alibaba.otter.canal.connector.kafka.config.KafkaProducerConfig;\nimport com.alibaba.otter.canal.protocol.FlatMessage;\nimport com.alibaba.otter.canal.protocol.Message;\n\n/**\n * kafka producer SPI 实现\n *\n * @author rewerma 2018-6-11 下午05:30:49\n * @version 1.0.0\n */\n@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n@SPI(\"kafka\")\npublic class CanalKafkaProducer extends AbstractMQProducer implements CanalMQProducer {\n\n    private static final Logger      logger              = LoggerFactory.getLogger(CanalKafkaProducer.class);\n\n    private static final String      PREFIX_KAFKA_CONFIG = \"kafka.\";\n\n    private Producer<String, byte[]> producer;\n\n    @Override\n    public void init(Properties properties) {\n        KafkaProducerConfig kafkaProducerConfig = new KafkaProducerConfig();\n        this.mqProperties = kafkaProducerConfig;\n        super.init(properties);\n        // load properties\n        this.loadKafkaProperties(properties);\n\n        Properties kafkaProperties = new Properties();\n        kafkaProperties.putAll(kafkaProducerConfig.getKafkaProperties());\n        kafkaProperties.put(\"max.in.flight.requests.per.connection\", 1);\n        kafkaProperties.put(\"key.serializer\", StringSerializer.class);\n        if (kafkaProducerConfig.isKerberosEnabled()) {\n            File krb5File = new File(kafkaProducerConfig.getKrb5File());\n            File jaasFile = new File(kafkaProducerConfig.getJaasFile());\n            if (krb5File.exists() && jaasFile.exists()) {\n                // 配置kerberos认证，需要使用绝对路径\n                System.setProperty(\"java.security.krb5.conf\", krb5File.getAbsolutePath());\n                System.setProperty(\"java.security.auth.login.config\", jaasFile.getAbsolutePath());\n                System.setProperty(\"javax.security.auth.useSubjectCredsOnly\", \"false\");\n                kafkaProperties.put(\"security.protocol\", \"SASL_PLAINTEXT\");\n                kafkaProperties.put(\"sasl.kerberos.service.name\", \"kafka\");\n            } else {\n                String errorMsg = \"ERROR # The kafka kerberos configuration file does not exist! please check it\";\n                logger.error(errorMsg);\n                throw new RuntimeException(errorMsg);\n            }\n        }\n        kafkaProperties.put(\"value.serializer\", KafkaMessageSerializer.class);\n        producer = new KafkaProducer<>(kafkaProperties);\n    }\n\n    private void loadKafkaProperties(Properties properties) {\n        KafkaProducerConfig kafkaProducerConfig = (KafkaProducerConfig) this.mqProperties;\n        Map<String, Object> kafkaProperties = kafkaProducerConfig.getKafkaProperties();\n        // 兼容下<=1.1.4的mq配置\n        doMoreCompatibleConvert(\"canal.mq.servers\", \"kafka.bootstrap.servers\", properties);\n        doMoreCompatibleConvert(\"canal.mq.acks\", \"kafka.acks\", properties);\n        doMoreCompatibleConvert(\"canal.mq.compressionType\", \"kafka.compression.type\", properties);\n        doMoreCompatibleConvert(\"canal.mq.retries\", \"kafka.retries\", properties);\n        doMoreCompatibleConvert(\"canal.mq.batchSize\", \"kafka.batch.size\", properties);\n        doMoreCompatibleConvert(\"canal.mq.lingerMs\", \"kafka.linger.ms\", properties);\n        doMoreCompatibleConvert(\"canal.mq.maxRequestSize\", \"kafka.max.request.size\", properties);\n        doMoreCompatibleConvert(\"canal.mq.bufferMemory\", \"kafka.buffer.memory\", properties);\n        doMoreCompatibleConvert(\"canal.mq.kafka.kerberos.enable\", \"kafka.kerberos.enable\", properties);\n        doMoreCompatibleConvert(\"canal.mq.kafka.kerberos.krb5.file\", \"kafka.kerberos.krb5.file\", properties);\n        doMoreCompatibleConvert(\"canal.mq.kafka.kerberos.jaas.file\", \"kafka.kerberos.jaas.file\", properties);\n\n        for (Map.Entry<Object, Object> entry : properties.entrySet()) {\n            String key = (String) entry.getKey();\n            Object value = entry.getValue();\n            if (key.startsWith(PREFIX_KAFKA_CONFIG) && value != null) {\n                // check env config\n                value = PropertiesUtils.getProperty(properties, key);\n                key = key.substring(PREFIX_KAFKA_CONFIG.length());\n                kafkaProperties.put(key, value);\n            }\n        }\n        String kerberosEnabled = PropertiesUtils.getProperty(properties, KafkaConstants.CANAL_MQ_KAFKA_KERBEROS_ENABLE);\n        if (!StringUtils.isEmpty(kerberosEnabled)) {\n            kafkaProducerConfig.setKerberosEnabled(Boolean.parseBoolean(kerberosEnabled));\n        }\n        String krb5File = PropertiesUtils.getProperty(properties, KafkaConstants.CANAL_MQ_KAFKA_KERBEROS_KRB5_FILE);\n        if (!StringUtils.isEmpty(krb5File)) {\n            kafkaProducerConfig.setKrb5File(krb5File);\n        }\n        String jaasFile = PropertiesUtils.getProperty(properties, KafkaConstants.CANAL_MQ_KAFKA_KERBEROS_JAAS_FILE);\n        if (!StringUtils.isEmpty(jaasFile)) {\n            kafkaProducerConfig.setJaasFile(jaasFile);\n        }\n    }\n\n    @Override\n    public void stop() {\n        try {\n            logger.info(\"## stop the kafka producer\");\n            if (producer != null) {\n                producer.close();\n            }\n            super.stop();\n        } catch (Throwable e) {\n            logger.warn(\"##something goes wrong when stopping kafka producer:\", e);\n        } finally {\n            logger.info(\"## kafka producer is down.\");\n        }\n    }\n\n    @Override\n    public void send(MQDestination mqDestination, Message message, Callback callback) {\n        ExecutorTemplate template = new ExecutorTemplate(sendExecutor);\n\n        try {\n            List result;\n            if (!StringUtils.isEmpty(mqDestination.getDynamicTopic())) {\n                // 动态topic路由计算,只是基于schema/table,不涉及proto数据反序列化\n                Map<String, Message> messageMap = MQMessageUtils.messageTopics(message,\n                    mqDestination.getTopic(),\n                    mqDestination.getDynamicTopic());\n\n                // 针对不同的topic,引入多线程提升效率\n                for (Map.Entry<String, Message> entry : messageMap.entrySet()) {\n                    final String topicName = entry.getKey().replace('.', '_');\n                    final Message messageSub = entry.getValue();\n                    template.submit((Callable) () -> {\n                        try {\n                            return send(mqDestination, topicName, messageSub, mqProperties.isFlatMessage());\n                        } catch (Exception e) {\n                            throw new RuntimeException(e);\n                        }\n                    });\n                }\n\n                result = template.waitForResult();\n            } else {\n                result = new ArrayList();\n                List<Future> futures = send(mqDestination,\n                    mqDestination.getTopic(),\n                    message,\n                    mqProperties.isFlatMessage());\n                result.add(futures);\n            }\n\n            // 一个批次的所有topic和分区的队列，都采用异步的模式进行多线程批量发送\n            // 最后在集结点进行flush等待，确保所有数据都写出成功\n            // 注意：kafka的异步模式如果要保证顺序性，需要设置max.in.flight.requests.per.connection=1，确保在网络异常重试时有排他性\n            producer.flush();\n            // flush操作也有可能是发送失败,这里需要异步关注一下发送结果,针对有异常的直接出发rollback\n            for (Object obj : result) {\n                List<Future> futures = (List<Future>) obj;\n                for (Future future : futures) {\n                    try {\n                        future.get();\n                    } catch (InterruptedException | ExecutionException e) {\n                        throw new RuntimeException(e);\n                    }\n                }\n            }\n\n            callback.commit();\n        } catch (Throwable e) {\n            logger.error(e.getMessage(), e);\n            callback.rollback();\n        } finally {\n            template.clear();\n        }\n    }\n\n    private List<Future> send(MQDestination mqDestination, String topicName, Message message, boolean flat) {\n        List<ProducerRecord<String, byte[]>> records = new ArrayList<>();\n        // 获取当前topic的分区数\n        Integer partitionNum = MQMessageUtils.parseDynamicTopicPartition(topicName, mqDestination.getDynamicTopicPartitionNum());\n        if (partitionNum == null) {\n            partitionNum = mqDestination.getPartitionsNum();\n        }\n        if (!flat) {\n            if (mqDestination.getPartitionHash() != null && !mqDestination.getPartitionHash().isEmpty()) {\n                // 并发构造\n                EntryRowData[] datas = MQMessageUtils.buildMessageData(message, buildExecutor);\n                // 串行分区\n                Message[] messages = MQMessageUtils.messagePartition(datas,\n                    message.getId(),\n                    partitionNum,\n                    mqDestination.getPartitionHash(),\n                    this.mqProperties.isDatabaseHash());\n                int length = messages.length;\n                for (int i = 0; i < length; i++) {\n                    Message messagePartition = messages[i];\n                    if (messagePartition != null) {\n                        records.add(new ProducerRecord<>(topicName,\n                            i,\n                            null,\n                            CanalMessageSerializerUtil.serializer(messagePartition,\n                                mqProperties.isFilterTransactionEntry())));\n                    }\n                }\n            } else {\n                final int partition = mqDestination.getPartition() != null ? mqDestination.getPartition() : 0;\n                records.add(new ProducerRecord<>(topicName,\n                    partition,\n                    null,\n                    CanalMessageSerializerUtil.serializer(message, mqProperties.isFilterTransactionEntry())));\n            }\n        } else {\n            // 发送扁平数据json\n            // 并发构造\n            EntryRowData[] datas = MQMessageUtils.buildMessageData(message, buildExecutor);\n            // 串行分区\n            List<FlatMessage> flatMessages = MQMessageUtils.messageConverter(datas, message.getId());\n            for (FlatMessage flatMessage : flatMessages) {\n                if (mqDestination.getPartitionHash() != null && !mqDestination.getPartitionHash().isEmpty()) {\n                    FlatMessage[] partitionFlatMessage = MQMessageUtils.messagePartition(flatMessage,\n                        partitionNum,\n                        mqDestination.getPartitionHash(),\n                        this.mqProperties.isDatabaseHash());\n                    int length = partitionFlatMessage.length;\n                    for (int i = 0; i < length; i++) {\n                        FlatMessage flatMessagePart = partitionFlatMessage[i];\n                        if (flatMessagePart != null) {\n                            records.add(new ProducerRecord<>(topicName, i, null, JSON.toJSONBytes(flatMessagePart,\n                                JSONWriter.Feature.WriteNulls,\n                                JSONWriter.Feature.LargeObject)));\n                        }\n                    }\n                } else {\n                    final int partition = mqDestination.getPartition() != null ? mqDestination.getPartition() : 0;\n                    records.add(new ProducerRecord<>(topicName, partition, null, JSON.toJSONBytes(flatMessage,\n                        JSONWriter.Feature.WriteNulls,\n                        JSONWriter.Feature.LargeObject)));\n                }\n            }\n        }\n\n        return produce(records);\n    }\n\n    private List<Future> produce(List<ProducerRecord<String, byte[]>> records) {\n        List<Future> futures = new ArrayList<>();\n        // 异步发送，因为在partition hash的时候已经按照每个分区合并了消息，走到这一步不需要考虑单个分区内的顺序问题\n        for (ProducerRecord record : records) {\n            futures.add(producer.send(record));\n        }\n\n        return futures;\n    }\n\n}\n"
  },
  {
    "path": "connector/kafka-connector/src/main/java/com/alibaba/otter/canal/connector/kafka/producer/KafkaMessageSerializer.java",
    "content": "package com.alibaba.otter.canal.connector.kafka.producer;\n\nimport java.util.Map;\n\nimport org.apache.kafka.common.serialization.Serializer;\n\n/**\n * Kafka Message类的序列化\n *\n * @author rewerma 2018-6-11 下午05:30:49\n * @version 1.0.0\n */\npublic class KafkaMessageSerializer implements Serializer<byte[]> {\n\n    @Override\n    public void configure(Map<String, ?> configs, boolean isKey) {\n    }\n\n    @Override\n    public byte[] serialize(String topic, byte[] data) {\n        return data;\n    }\n\n    @Override\n    public void close() {\n        // nothing to do\n    }\n}\n"
  },
  {
    "path": "connector/kafka-connector/src/main/resources/META-INF/canal/com.alibaba.otter.canal.connector.core.spi.CanalMQProducer",
    "content": "kafka=com.alibaba.otter.canal.connector.kafka.producer.CanalKafkaProducer"
  },
  {
    "path": "connector/kafka-connector/src/main/resources/META-INF/canal/com.alibaba.otter.canal.connector.core.spi.CanalMsgConsumer",
    "content": "kafka=com.alibaba.otter.canal.connector.kafka.consumer.CanalKafkaConsumer"
  },
  {
    "path": "connector/kafka-connector/src/test/java/com/alibaba/otter/canal/connector/kafka/test/CanalKafkaProducerTest.java",
    "content": "package com.alibaba.otter.canal.connector.kafka.test;\n\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.util.Properties;\n\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.connector.core.spi.CanalMQProducer;\nimport com.alibaba.otter.canal.connector.core.spi.ExtensionLoader;\n\n@Ignore\npublic class CanalKafkaProducerTest {\n\n    @Test\n    public void testLoadKafkaProducer() throws IOException {\n        Properties pro = new Properties();\n        FileInputStream in = new FileInputStream(\"../../deployer/src/main/resources/canal.properties\");\n        pro.load(in);\n\n        ExtensionLoader<CanalMQProducer> loader = ExtensionLoader.getExtensionLoader(CanalMQProducer.class);\n        CanalMQProducer canalMQProducer = loader.getExtension(\"kafka\",\n            \"/../../deployer/target/canal/plugin\",\n            \"/../../deployer/target/canal/plugin\");\n        canalMQProducer.init(pro);\n\n        in.close();\n    }\n}\n"
  },
  {
    "path": "connector/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>com.alibaba.otter</groupId>\n        <artifactId>canal</artifactId>\n        <version>1.1.9-SNAPSHOT</version>\n        <relativePath>../pom.xml</relativePath>\n    </parent>\n\n    <groupId>com.alibaba.otter</groupId>\n    <artifactId>canal.connector</artifactId>\n    <version>1.1.9-SNAPSHOT</version>\n    <packaging>pom</packaging>\n    <name>canal connector module for otter ${project.version}</name>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <maven.test.skip>true</maven.test.skip>\n        <downloadSources>true</downloadSources>\n        <java_source_version>1.8</java_source_version>\n        <java_target_version>1.8</java_target_version>\n        <file_encoding>UTF-8</file_encoding>\n    </properties>\n\n    <licenses>\n        <license>\n            <name>Apache License, Version 2.0</name>\n            <url>http://www.apache.org/licenses/LICENSE-2.0</url>\n        </license>\n    </licenses>\n\n    <scm>\n        <url>git@github.com:alibaba/canal.git</url>\n        <connection>scm:git:git@github.com:alibaba/canal.git</connection>\n        <developerConnection>scm:git:git@github.com:alibaba/canal.git</developerConnection>\n    </scm>\n\n    <repositories>\n        <repository>\n            <id>central</id>\n            <url>https://repo1.maven.org/maven2</url>\n            <releases>\n                <enabled>true</enabled>\n            </releases>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </repository>\n        <repository>\n            <id>java.net</id>\n            <url>https://download.java.net/maven/2/</url>\n            <releases>\n                <enabled>true</enabled>\n            </releases>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </repository>\n        <repository>\n            <id>aliyun</id>\n            <url>https://maven.aliyun.com/nexus/content/groups/public/</url>\n            <releases>\n                <enabled>true</enabled>\n            </releases>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </repository>\n        <repository>\n            <id>sonatype</id>\n            <name>sonatype</name>\n            <url>https://oss.sonatype.org/content/repositories/snapshots</url>\n            <releases>\n                <enabled>false</enabled>\n            </releases>\n            <snapshots>\n                <enabled>true</enabled>\n            </snapshots>\n        </repository>\n        <repository>\n            <id>sonatype-release</id>\n            <name>sonatype-release</name>\n            <url>https://oss.sonatype.org/service/local/repositories/releases/content</url>\n            <releases>\n                <enabled>false</enabled>\n            </releases>\n            <snapshots>\n                <enabled>true</enabled>\n            </snapshots>\n        </repository>\n    </repositories>\n\n    <modules>\n        <module>core</module>\n        <module>kafka-connector</module>\n        <module>rocketmq-connector</module>\n        <module>rabbitmq-connector</module>\n        <module>pulsarmq-connector</module>\n        <module>tcp-connector</module>\n    </modules>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.7.0</version>\n                <configuration>\n                    <source>${java_source_version}</source>\n                    <target>${java_target_version}</target>\n                    <encoding>${file_encoding}</encoding>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n    <distributionManagement>\n        <snapshotRepository>\n            <id>sonatype-nexus-snapshots</id>\n            <name>Sonatype Nexus Snapshots</name>\n            <url>https://oss.sonatype.org/content/repositories/snapshots/</url>\n        </snapshotRepository>\n        <repository>\n            <id>sonatype-nexus-staging</id>\n            <name>Nexus Release Repository</name>\n            <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>\n        </repository>\n    </distributionManagement>\n</project>\n"
  },
  {
    "path": "connector/pulsarmq-connector/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>canal.connector</artifactId>\n        <groupId>com.alibaba.otter</groupId>\n        <version>1.1.9-SNAPSHOT</version>\n        <relativePath>../pom.xml</relativePath>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>com.alibaba.otter</groupId>\n    <artifactId>connector.pulsarmq</artifactId>\n    <packaging>jar</packaging>\n    <name>canal connector pulsarmq module for otter ${project.version}</name>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>canal.protocol</artifactId>\n            <version>${project.version}</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>connector.core</artifactId>\n            <version>${project.version}</version>\n            <scope>provided</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>org.apache.pulsar</groupId>\n            <artifactId>pulsar-client</artifactId>\n            <version>${pulsar_version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.pulsar</groupId>\n            <artifactId>pulsar-client-admin</artifactId>\n            <version>${pulsar_version}</version>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-assembly-plugin</artifactId>\n                <version>2.4</version>\n                <configuration>\n                    <descriptorRefs>\n                        <descriptorRef>jar-with-dependencies</descriptorRef>\n                    </descriptorRefs>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>make-assembly</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>single</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-antrun-plugin</artifactId>\n                <version>1.8</version>\n                <executions>\n                    <execution>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>run</goal>\n                        </goals>\n                        <configuration>\n                            <tasks>\n                                <copy todir=\"${project.basedir}/../../deployer/target/canal/plugin\" overwrite=\"true\">\n                                    <fileset dir=\"${project.basedir}/target\" erroronmissingdir=\"true\">\n                                        <include name=\"connector.pulsarmq-${project.version}-jar-with-dependencies.jar\" />\n                                    </fileset>\n                                </copy>\n                                <copy todir=\"${project.basedir}/../../client-adapter/launcher/target/canal-adapter/plugin\" overwrite=\"true\">\n                                    <fileset dir=\"${project.basedir}/target\" erroronmissingdir=\"true\">\n                                        <include name=\"connector.pulsarmq-${project.version}-jar-with-dependencies.jar\" />\n                                    </fileset>\n                                </copy>\n                            </tasks>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "connector/pulsarmq-connector/src/main/java/com/alibaba/otter/canal/connector/pulsarmq/config/PulsarMQConstants.java",
    "content": "package com.alibaba.otter.canal.connector.pulsarmq.config;\n\n/**\n * PulsarMQ配置\n *\n * @author chad\n * @date 2021/9/15 11:13\n * @since 1 by chad at 2021/9/15 新增配置文件\n */\npublic class PulsarMQConstants {\n\n    public static final String ROOT                               = \"pulsarmq\";\n    /**\n     * pulsar服务连接地址\n     */\n    public static final String PULSARMQ_SERVER_URL                = ROOT + \".\" + \"serverUrl\";\n    /**\n     * pulsar服务角色token，需要有对应token的生产者权限\n     */\n    public static final String PULSARMQ_ROLE_TOKEN                = ROOT + \".\" + \"roleToken\";\n    /**\n     * topic前缀\n     */\n    public static final String PULSARMQ_TOPIC_TENANT_PREFIX       = ROOT + \".\" + \"topicTenantPrefix\";\n\n    /**** 消费者 *****/\n    /**\n     * 获取批量消息超时等待时间\n     */\n    public static final String PULSARMQ_GET_BATCH_TIMEOUT_SECONDS = ROOT + \".\" + \"getBatchTimeoutSeconds\";\n    /**\n     * 批量处理超时时间\n     */\n    public static final String PULSARMQ_BATCH_PROCESS_TIMEOUT     = ROOT + \".\" + \"batchProcessTimeout\";\n    /**\n     * 消费都订阅名称，将以该名称为消费者身份标识，同一个subscriptName，认为是同一个消费实例\n     */\n    public static final String PULSARMQ_SUBSCRIPT_NAME            = ROOT + \".\" + \"subscriptName\";\n    /**\n     * 重试间隔秒数\n     */\n    public static final String PULSARMQ_REDELIVERY_DELAY_SECONDS  = ROOT + \".\" + \"redeliveryDelaySeconds\";\n    /**\n     * ACK超时秒数\n     */\n    public static final String PULSARMQ_ACK_TIMEOUT_SECONDS       = ROOT + \".\" + \"ackTimeoutSeconds\";\n    /**\n     * 是否开启消费重试\n     */\n    public static final String PULSARMQ_IS_RETRY                  = ROOT + \".\" + \"isRetry\";\n    /**\n     * 自动生成的 retry dlq队列名称后缀是否大写\n     */\n    public static final String PULSARMQ_IS_RETRY_DLQ_UPPERCASE    = ROOT + \".\" + \"isRetryDLQUpperCase\";\n    /**\n     * 最大重试次数\n     */\n    public static final String PULSARMQ_MAX_REDELIVERY_COUNT      = ROOT + \".\" + \"maxRedeliveryCount\";\n    /**\n     * Pulsar admin服务器地址\n     */\n    public static final String PULSARMQ_ADMIN_SERVER_URL          = ROOT + \".\" + \"adminServerUrl\";\n\n    /**\n     * Pulsar 监听器名字\n     */\n    public static final String PULSARMQ_LISTENER_NAME             = ROOT + \".\" + \"listenerName\";\n\n    /**\n     * Pulsar 开启chunking\n     */\n    public static final String PULSARMQ_ENABLE_CHUNKING           = ROOT + \".\" + \"enableChunking\";\n\n    /**\n     * Pulsar 压缩算法\n     */\n    public static final String PULSARMQ_COMPRESSION_TYPE          = ROOT + \".\" + \"compressionType\";\n}\n"
  },
  {
    "path": "connector/pulsarmq-connector/src/main/java/com/alibaba/otter/canal/connector/pulsarmq/config/PulsarMQProducerConfig.java",
    "content": "package com.alibaba.otter.canal.connector.pulsarmq.config;\n\nimport com.alibaba.otter.canal.connector.core.config.MQProperties;\n\n/**\n * Pulsar生产者配置\n * \n * @author chad\n * @date 2021/9/15 11:23\n * @since 1 by chad at 2021/9/15 新增\n */\npublic class PulsarMQProducerConfig extends MQProperties {\n\n    /**\n     * pulsar服务连接地址\n     * <p>\n     * broker: pulsar://localhost:6650<br/>\n     * httpUrl: http://localhost:8080\n     * </p>\n     */\n    private String  serverUrl;\n    /**\n     * pulsar topic前缀\n     * <p>\n     * 正常的pulsar topic全路径为：persistent://{tenant}/{namespace}/{TOPIC}，\n     * 而为了方便，在配置文件中仅需要配置 {TOPIC} 段即可，persistent://{tenant}/{namespace}由此参数控制。\n     * 在发送消息时会自动拼接上\n     * </p>\n     */\n    private String  topicTenantPrefix;\n    /**\n     * 生产者角色权限，请确保该角色有canal使用的所有topic生产者权限（最低要求）\n     */\n    private String  roleToken;\n    /**\n     * admin服务器地址\n     */\n    private String  adminServerUrl;\n\n    /**\n     * listener name\n     */\n    private String  listenerName;\n\n    /**\n     * enableChunking\n     */\n    private boolean enableChunking;\n\n    /**\n     * compressionType\n     */\n    private String  compressionType;\n\n    public String getServerUrl() {\n        return serverUrl;\n    }\n\n    public void setServerUrl(String serverUrl) {\n        this.serverUrl = serverUrl;\n    }\n\n    public String getRoleToken() {\n        return roleToken;\n    }\n\n    public void setRoleToken(String roleToken) {\n        this.roleToken = roleToken;\n    }\n\n    public String getTopicTenantPrefix() {\n        return topicTenantPrefix;\n    }\n\n    public void setTopicTenantPrefix(String topicTenantPrefix) {\n        this.topicTenantPrefix = topicTenantPrefix;\n    }\n\n    public String getAdminServerUrl() {\n        return adminServerUrl;\n    }\n\n    public void setAdminServerUrl(String adminServerUrl) {\n        this.adminServerUrl = adminServerUrl;\n    }\n\n    public String getListenerName() {\n        return listenerName;\n    }\n\n    public void setListenerName(String listenerName) {\n        this.listenerName = listenerName;\n    }\n\n    public void setEnableChunking(boolean enableChunking) {\n        this.enableChunking = enableChunking;\n    }\n\n    public boolean getEnableChunking() {\n        return this.enableChunking;\n    }\n\n    public void setCompressionType(String compressionType) {\n        this.compressionType = compressionType;\n    }\n\n    public String getCompressionType() {\n        return this.compressionType;\n    }\n}\n"
  },
  {
    "path": "connector/pulsarmq-connector/src/main/java/com/alibaba/otter/canal/connector/pulsarmq/consumer/CanalPulsarMQConsumer.java",
    "content": "package com.alibaba.otter.canal.connector.pulsarmq.consumer;\n\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.pulsar.client.api.*;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.otter.canal.common.utils.MQUtil;\nimport com.alibaba.otter.canal.connector.core.config.CanalConstants;\nimport com.alibaba.otter.canal.connector.core.consumer.CommonMessage;\nimport com.alibaba.otter.canal.connector.core.spi.CanalMsgConsumer;\nimport com.alibaba.otter.canal.connector.core.spi.SPI;\nimport com.alibaba.otter.canal.connector.core.util.CanalMessageSerializerUtil;\nimport com.alibaba.otter.canal.connector.core.util.MessageUtil;\nimport com.alibaba.otter.canal.connector.pulsarmq.config.PulsarMQConstants;\nimport com.alibaba.otter.canal.protocol.Message;\nimport com.alibaba.otter.canal.protocol.exception.CanalClientException;\nimport com.google.common.collect.Lists;\n\n/**\n * Pulsar consumer SPI 实现\n *\n * @author rewerma @ 2020-02-01\n * @version 1.0.0\n */\n@SPI(\"pulsarmq\")\npublic class CanalPulsarMQConsumer implements CanalMsgConsumer {\n\n    /**\n     * 连接pulsar客户端\n     */\n    private PulsarClient              pulsarClient;\n    private Consumer<byte[]>          pulsarMQConsumer;\n    /**\n     * 是否为扁平消息\n     */\n    private boolean                   flatMessage            = false;\n    /**\n     * 主题名称\n     */\n    private String                    topic;\n    /**\n     * 单线程控制\n     */\n    private volatile Messages<byte[]> lastGetBatchMessage;\n    /**\n     * 环境连接URL\n     */\n    private String                    serviceUrl;\n    /**\n     * 角色认证token\n     */\n    private String                    roleToken;\n\n    /**\n     * listener name\n     */\n    private String                    listenerName;\n\n    /**\n     * 订阅客户端名称\n     */\n    private String                    subscriptName;\n    /**\n     * 每次批量获取数据的最大条目数，默认30\n     */\n    private int                       batchSize              = 30;\n    /**\n     * 与{@code batchSize}一起决定批量获取的数据大小 当：\n     * <p>\n     * 1. {@code batchSize} 条消息未消费时<br/>\n     * 2. 距上一次批量消费时间达到{@code batchTimeoutSeconds}秒时\n     * </p>\n     * 任一条件满足，即执行批量消费\n     */\n    private int                       getBatchTimeoutSeconds = 30;\n    /**\n     * 批量处理消息时，一次批量处理的超时时间\n     * <p>\n     * 该时间应该根据{@code batchSize}和{@code batchTimeoutSeconds}合理设置\n     * </p>\n     */\n    private long                      batchProcessTimeout    = 60 * 1000;\n    /**\n     * 消费失败后的重试秒数，默认60秒\n     */\n    private int                       redeliveryDelaySeconds = 60;\n    /**\n     * 当客户端接收到消息，30秒还没有返回ack给服务端时，ack超时，会重新消费该消息\n     */\n    private int                       ackTimeoutSeconds      = 30;\n    /**\n     * 是否开启消息失败重试功能，默认开启\n     */\n    private boolean                   isRetry                = true;\n    /**\n     * <p>\n     * true重试(-RETRY)和死信队列(-DLQ)后缀为大写，有些地方创建的为小写，需确保正确\n     * </p>\n     */\n    private boolean                   isRetryDLQUpperCase    = false;\n    /**\n     * 最大重试次数\n     */\n    private int                       maxRedeliveryCount     = 128;\n\n    @Override\n    public void init(Properties properties, String topic, String groupId) {\n        this.topic = topic;\n        String flatMessageStr = properties.getProperty(CanalConstants.CANAL_MQ_FLAT_MESSAGE);\n        if (StringUtils.isNotEmpty(flatMessageStr)) {\n            this.flatMessage = Boolean.parseBoolean(flatMessageStr);\n        }\n        this.serviceUrl = properties.getProperty(PulsarMQConstants.PULSARMQ_SERVER_URL);\n        this.roleToken = properties.getProperty(PulsarMQConstants.PULSARMQ_ROLE_TOKEN);\n        this.listenerName = properties.getProperty(PulsarMQConstants.PULSARMQ_LISTENER_NAME);\n        this.subscriptName = properties.getProperty(PulsarMQConstants.PULSARMQ_SUBSCRIPT_NAME);\n        // 采用groupId作为subscriptName，避免所有的都是同一个订阅者名称\n        if (StringUtils.isEmpty(this.subscriptName)) {\n            this.subscriptName = groupId;\n        }\n\n        if (StringUtils.isEmpty(this.subscriptName)) {\n            throw new RuntimeException(\"Pulsar Consumer subscriptName required\");\n        }\n        String batchSizeStr = properties.getProperty(CanalConstants.CANAL_MQ_CANAL_BATCH_SIZE);\n        if (StringUtils.isNotEmpty(batchSizeStr)) {\n            this.batchSize = Integer.parseInt(batchSizeStr);\n        }\n        String getBatchTimeoutSecondsStr = properties.getProperty(PulsarMQConstants.PULSARMQ_GET_BATCH_TIMEOUT_SECONDS);\n        if (StringUtils.isNotEmpty(getBatchTimeoutSecondsStr)) {\n            this.getBatchTimeoutSeconds = Integer.parseInt(getBatchTimeoutSecondsStr);\n        }\n        String batchProcessTimeoutStr = properties.getProperty(PulsarMQConstants.PULSARMQ_BATCH_PROCESS_TIMEOUT);\n        if (StringUtils.isNotEmpty(batchProcessTimeoutStr)) {\n            this.batchProcessTimeout = Integer.parseInt(batchProcessTimeoutStr);\n        }\n        String redeliveryDelaySecondsStr = properties.getProperty(PulsarMQConstants.PULSARMQ_REDELIVERY_DELAY_SECONDS);\n        if (StringUtils.isNotEmpty(redeliveryDelaySecondsStr)) {\n            this.redeliveryDelaySeconds = Integer.parseInt(redeliveryDelaySecondsStr);\n        }\n        String ackTimeoutSecondsStr = properties.getProperty(PulsarMQConstants.PULSARMQ_ACK_TIMEOUT_SECONDS);\n        if (StringUtils.isNotEmpty(ackTimeoutSecondsStr)) {\n            this.ackTimeoutSeconds = Integer.parseInt(ackTimeoutSecondsStr);\n        }\n        String isRetryStr = properties.getProperty(PulsarMQConstants.PULSARMQ_IS_RETRY);\n        if (StringUtils.isNotEmpty(isRetryStr)) {\n            this.isRetry = Boolean.parseBoolean(isRetryStr);\n        }\n        String isRetryDLQUpperCaseStr = properties.getProperty(PulsarMQConstants.PULSARMQ_IS_RETRY_DLQ_UPPERCASE);\n        if (StringUtils.isNotEmpty(isRetryDLQUpperCaseStr)) {\n            this.isRetryDLQUpperCase = Boolean.parseBoolean(isRetryDLQUpperCaseStr);\n        }\n        String maxRedeliveryCountStr = properties.getProperty(PulsarMQConstants.PULSARMQ_MAX_REDELIVERY_COUNT);\n        if (StringUtils.isNotEmpty(maxRedeliveryCountStr)) {\n            this.maxRedeliveryCount = Integer.parseInt(maxRedeliveryCountStr);\n        }\n    }\n\n    @Override\n    public void connect() {\n        if (isConsumerActive()) {\n            return;\n        }\n        // 连接创建客户端\n        try {\n            // AuthenticationDataProvider\n            ClientBuilder builder = PulsarClient.builder().serviceUrl(serviceUrl);\n            if (StringUtils.isNotEmpty(roleToken)) {\n                builder.authentication(AuthenticationFactory.token(roleToken));\n            }\n            if (StringUtils.isNotEmpty(listenerName)) {\n                builder.authentication(AuthenticationFactory.token(listenerName));\n            }\n            pulsarClient = builder.build();\n        } catch (PulsarClientException e) {\n            throw new RuntimeException(e);\n        }\n        ConsumerBuilder<byte[]> builder = pulsarClient.newConsumer();\n        if (MQUtil.isPatternTopic(this.topic)) {\n            // 正则只支持一个\n            builder.topicsPattern(this.topic);\n        } else {// 多个topic\n            builder.topic(this.topic);\n        }\n        // 为保证消息的有序性，仅支持单消费实例模式\n        // 灾备模式，一个分区只能有一个消费者，如果当前消费者不可用，自动切换到其他消费者\n        builder.subscriptionType(SubscriptionType.Failover);\n\n        builder\n            // 调用consumer.negativeAcknowledge(message) （即nack）来表示消费失败的消息\n            // 在指定的时间进行重新消费，默认是1分钟。\n            .negativeAckRedeliveryDelay(this.redeliveryDelaySeconds, TimeUnit.SECONDS)\n            .subscriptionName(this.subscriptName);\n        if (this.isRetry) {\n            DeadLetterPolicy.DeadLetterPolicyBuilder dlqBuilder = DeadLetterPolicy.builder()\n                // 最大重试次数\n                .maxRedeliverCount(this.maxRedeliveryCount);\n            // 指定重试队列，不是多个或通配符topic才能判断重试队列\n            if (!MQUtil.isPatternTag(this.topic)) {\n                String retryTopic = this.topic + (this.isRetryDLQUpperCase ? \"-RETRY\" : \"-retry\");\n                dlqBuilder.retryLetterTopic(retryTopic);\n                String dlqTopic = this.topic + (this.isRetryDLQUpperCase ? \"-DLQ\" : \"-dlq\");\n                dlqBuilder.deadLetterTopic(dlqTopic);\n            }\n\n            // 默认关闭，如果需要重试则开启\n            builder.enableRetry(true).deadLetterPolicy(dlqBuilder.build());\n        }\n\n        // ack超时\n        builder.ackTimeout(this.ackTimeoutSeconds, TimeUnit.SECONDS);\n\n        // pulsar批量获取消息设置\n        builder.batchReceivePolicy(new BatchReceivePolicy.Builder().maxNumMessages(this.batchSize)\n            .timeout(this.getBatchTimeoutSeconds, TimeUnit.SECONDS)\n            .build());\n\n        try {\n            this.pulsarMQConsumer = builder.subscribe();\n        } catch (PulsarClientException e) {\n            throw new CanalClientException(\"Subscript pulsar consumer error\", e);\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public List<CommonMessage> getMessage(Long timeout, TimeUnit unit) {\n        List<CommonMessage> messageList = Lists.newArrayList();\n        try {\n            Messages<byte[]> messages = pulsarMQConsumer.batchReceive();\n            if (null == messages || messages.size() == 0) {\n                return messageList;\n            }\n            // 保存当前消费记录，用于ack和rollback\n            this.lastGetBatchMessage = messages;\n            for (org.apache.pulsar.client.api.Message<byte[]> msg : messages) {\n                byte[] data = msg.getData();\n                if (!this.flatMessage) {\n                    Message message = CanalMessageSerializerUtil.deserializer(data);\n                    List<CommonMessage> list = MessageUtil.convert(message);\n                    messageList.addAll(list);\n                } else {\n                    CommonMessage commonMessage = JSON.parseObject(data, CommonMessage.class);\n                    messageList.add(commonMessage);\n                }\n            }\n        } catch (PulsarClientException e) {\n            throw new CanalClientException(\"Receive pulsar batch message error\", e);\n        }\n\n        return messageList;\n    }\n\n    @Override\n    public void rollback() {\n        try {\n            if (isConsumerActive() && hasLastMessages()) {\n                // 回滚所有消息\n                this.pulsarMQConsumer.negativeAcknowledge(this.lastGetBatchMessage);\n            }\n        } finally {\n            this.lastGetBatchMessage = null;\n        }\n    }\n\n    @Override\n    public void ack() {\n        try {\n            if (isConsumerActive() && hasLastMessages()) {\n                // 确认所有消息\n                this.pulsarMQConsumer.acknowledge(this.lastGetBatchMessage);\n            }\n        } catch (PulsarClientException e) {\n            if (isConsumerActive() && hasLastMessages()) {\n                this.pulsarMQConsumer.negativeAcknowledge(this.lastGetBatchMessage);\n            }\n        } finally {\n            this.lastGetBatchMessage = null;\n        }\n    }\n\n    @Override\n    public void disconnect() {\n        if (null == this.pulsarMQConsumer || !this.pulsarMQConsumer.isConnected()) {\n            return;\n        }\n        try {\n            // 会导致暂停期间数据丢失\n            // this.pulsarMQConsumer.unsubscribe();\n            this.pulsarClient.close();\n        } catch (PulsarClientException e) {\n            throw new CanalClientException(\"Disconnect pulsar consumer error\", e);\n        }\n    }\n\n    /**\n     * 是否消费可用\n     *\n     * @return true消费者可用\n     */\n    private boolean isConsumerActive() {\n        return null != this.pulsarMQConsumer && this.pulsarMQConsumer.isConnected();\n    }\n\n    /**\n     * 是否有未确认消息\n     *\n     * @return true有正在消费的待确认消息\n     */\n    private boolean hasLastMessages() {\n        return null != this.lastGetBatchMessage && this.lastGetBatchMessage.size() > 0;\n    }\n}\n"
  },
  {
    "path": "connector/pulsarmq-connector/src/main/java/com/alibaba/otter/canal/connector/pulsarmq/producer/CanalPulsarMQProducer.java",
    "content": "package com.alibaba.otter.canal.connector.pulsarmq.producer;\n\nimport java.util.*;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.pulsar.client.admin.PulsarAdmin;\nimport org.apache.pulsar.client.admin.PulsarAdminException;\nimport org.apache.pulsar.client.api.*;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.JSONWriter;\nimport com.alibaba.fastjson2.JSONWriter.Feature;\nimport com.alibaba.otter.canal.common.utils.ExecutorTemplate;\nimport com.alibaba.otter.canal.common.utils.NamedThreadFactory;\nimport com.alibaba.otter.canal.common.utils.PropertiesUtils;\nimport com.alibaba.otter.canal.connector.core.producer.AbstractMQProducer;\nimport com.alibaba.otter.canal.connector.core.producer.MQDestination;\nimport com.alibaba.otter.canal.connector.core.producer.MQMessageUtils;\nimport com.alibaba.otter.canal.connector.core.spi.CanalMQProducer;\nimport com.alibaba.otter.canal.connector.core.spi.SPI;\nimport com.alibaba.otter.canal.connector.core.util.Callback;\nimport com.alibaba.otter.canal.connector.core.util.CanalMessageSerializerUtil;\nimport com.alibaba.otter.canal.connector.pulsarmq.config.PulsarMQConstants;\nimport com.alibaba.otter.canal.connector.pulsarmq.config.PulsarMQProducerConfig;\nimport com.alibaba.otter.canal.protocol.CanalEntry;\nimport com.alibaba.otter.canal.protocol.FlatMessage;\n\n/**\n * PulsarMQ Producer SPI 实现\n *\n * @author chad 2021/9/2\n * @version 1.0.0\n */\n@SPI(\"pulsarmq\")\npublic class CanalPulsarMQProducer extends AbstractMQProducer implements CanalMQProducer {\n\n    /**\n     * 消息体分区属性名称\n     */\n    public static final String                         MSG_PROPERTY_PARTITION_NAME = \"partitionNum\";\n    private static final Logger                        logger                      = LoggerFactory\n        .getLogger(CanalPulsarMQProducer.class);\n    private static final Map<String, Producer<byte[]>> PRODUCERS                   = new HashMap<>();\n    protected ThreadPoolExecutor                       sendPartitionExecutor;\n    /**\n     * pulsar客户端，管理连接\n     */\n    protected PulsarClient                             client;\n    /**\n     * Pulsar admin 客户端\n     */\n    protected PulsarAdmin                              pulsarAdmin;\n\n    @Override\n    public void init(Properties properties) {\n        // 加载配置\n        PulsarMQProducerConfig pulsarMQProducerConfig = new PulsarMQProducerConfig();\n        this.mqProperties = pulsarMQProducerConfig;\n        super.init(properties);\n        loadPulsarMQProperties(properties);\n\n        // 初始化连接客户端\n        try {\n            ClientBuilder builder = PulsarClient.builder()\n                // 填写pulsar的连接地址\n                .serviceUrl(pulsarMQProducerConfig.getServerUrl());\n            if (StringUtils.isNotEmpty(pulsarMQProducerConfig.getRoleToken())) {\n                // 角色权限认证的token\n                builder.authentication(AuthenticationFactory.token(pulsarMQProducerConfig.getRoleToken()));\n            }\n            if (StringUtils.isNotEmpty(pulsarMQProducerConfig.getListenerName())) {\n                // listener name\n                builder.listenerName(pulsarMQProducerConfig.getListenerName());\n            }\n\n            client = builder.build();\n        } catch (PulsarClientException e) {\n            throw new RuntimeException(e);\n        }\n\n        // 初始化Pulsar admin\n        if (StringUtils.isNotEmpty(pulsarMQProducerConfig.getAdminServerUrl())) {\n            try {\n                pulsarAdmin = PulsarAdmin.builder().serviceHttpUrl(pulsarMQProducerConfig.getAdminServerUrl()).build();\n            } catch (PulsarClientException e) {\n                throw new RuntimeException(e);\n            }\n        }\n\n        // 加载所有生产者 --> topic可能有正则或表名，无法确认所有topic，在使用时再加载\n        int parallelPartitionSendThreadSize = mqProperties.getParallelSendThreadSize();\n        sendPartitionExecutor = new ThreadPoolExecutor(parallelPartitionSendThreadSize,\n            parallelPartitionSendThreadSize,\n            0,\n            TimeUnit.SECONDS,\n            new ArrayBlockingQueue<>(parallelPartitionSendThreadSize * 2),\n            new NamedThreadFactory(\"MQ-Parallel-Sender-Partition\"),\n            new ThreadPoolExecutor.CallerRunsPolicy());\n    }\n\n    /**\n     * 加载配置\n     *\n     * @param properties\n     * @return void\n     * @date 2021/9/15 11:22\n     * @author chad\n     * @since 1 by chad at 2021/9/15 新增\n     */\n    private void loadPulsarMQProperties(Properties properties) {\n        PulsarMQProducerConfig tmpProperties = (PulsarMQProducerConfig) this.mqProperties;\n        String serverUrl = PropertiesUtils.getProperty(properties, PulsarMQConstants.PULSARMQ_SERVER_URL);\n        if (!StringUtils.isEmpty(serverUrl)) {\n            tmpProperties.setServerUrl(serverUrl);\n        }\n\n        String roleToken = PropertiesUtils.getProperty(properties, PulsarMQConstants.PULSARMQ_ROLE_TOKEN);\n        if (!StringUtils.isEmpty(roleToken)) {\n            tmpProperties.setRoleToken(roleToken);\n        }\n        String topicTenantPrefix = PropertiesUtils.getProperty(properties,\n            PulsarMQConstants.PULSARMQ_TOPIC_TENANT_PREFIX);\n        if (!StringUtils.isEmpty(topicTenantPrefix)) {\n            tmpProperties.setTopicTenantPrefix(topicTenantPrefix);\n        }\n        String adminServerUrl = PropertiesUtils.getProperty(properties, PulsarMQConstants.PULSARMQ_ADMIN_SERVER_URL);\n        if (!StringUtils.isEmpty(adminServerUrl)) {\n            tmpProperties.setAdminServerUrl(adminServerUrl);\n        }\n        String listenerName = PropertiesUtils.getProperty(properties, PulsarMQConstants.PULSARMQ_LISTENER_NAME);\n        if (!StringUtils.isEmpty(listenerName)) {\n            tmpProperties.setListenerName(listenerName);\n        }\n\n        String enableChunkingStr = PropertiesUtils.getProperty(properties, PulsarMQConstants.PULSARMQ_ENABLE_CHUNKING);\n        if (!StringUtils.isEmpty(enableChunkingStr)) {\n            tmpProperties.setEnableChunking(Boolean.parseBoolean(enableChunkingStr));\n        }\n\n        String compressionType = PropertiesUtils.getProperty(properties, PulsarMQConstants.PULSARMQ_COMPRESSION_TYPE);\n        if (!StringUtils.isEmpty(compressionType)) {\n            tmpProperties.setCompressionType(compressionType);\n        }\n\n        if (logger.isDebugEnabled()) {\n            logger.debug(\"Load pulsar properties ==> {}\", JSON.toJSON(this.mqProperties));\n        }\n    }\n\n    /**\n     * 发送消息，处理的任务：\n     * <p>\n     * 1. 动态 Topic，根据schema.table或schema来匹配topic配置，将改变发送到指定的一个或多个具体的Topic<br/>\n     * 2. 使用线程池发送多个消息，单个消息不使用线程池\n     * </p>\n     *\n     * @param destination 消息目标信息\n     * @param message 消息\n     * @param callback 消息发送结果回调\n     * @return void\n     * @date 2021/9/2 22:01\n     * @author chad\n     * @since 1.0.0 by chad at 2021/9/2: 新增\n     */\n    @Override\n    public void send(MQDestination destination, com.alibaba.otter.canal.protocol.Message message, Callback callback) {\n\n        ExecutorTemplate template = new ExecutorTemplate(sendExecutor);\n        try {\n            if (!StringUtils.isEmpty(destination.getDynamicTopic())) {\n                // 动态topic\n                Map<String, com.alibaba.otter.canal.protocol.Message> messageMap = MQMessageUtils\n                    .messageTopics(message, destination.getTopic(), destination.getDynamicTopic());\n\n                for (Map.Entry<String, com.alibaba.otter.canal.protocol.Message> entry : messageMap.entrySet()) {\n                    String topicName = entry.getKey().replace('.', '_');\n                    com.alibaba.otter.canal.protocol.Message messageSub = entry.getValue();\n                    template.submit(() -> {\n                        try {\n                            send(destination, topicName, messageSub);\n                        } catch (Exception e) {\n                            throw new RuntimeException(e);\n                        }\n                    });\n                }\n\n                template.waitForResult();\n            } else {\n                send(destination, destination.getTopic(), message);\n            }\n\n            callback.commit();\n        } catch (Throwable e) {\n            logger.error(e.getMessage(), e);\n            callback.rollback();\n        } finally {\n            template.clear();\n        }\n    }\n\n    /**\n     * 发送单条消息到指定topic。区分是否发送扁平消息\n     *\n     * @param destination\n     * @param topicName\n     * @param message\n     * @return void\n     * @date 2021/9/2 22:05\n     * @author chad\n     * @since 1.0.0 by chad at 2021/9/2: 新增\n     */\n    public void send(final MQDestination destination, String topicName,\n                     com.alibaba.otter.canal.protocol.Message message) {\n\n        // 获取当前topic的分区数\n        Integer partitionNum = MQMessageUtils.parseDynamicTopicPartition(topicName,\n            destination.getDynamicTopicPartitionNum());\n        if (partitionNum == null) {\n            partitionNum = destination.getPartitionsNum();\n        }\n        // 创建多分区topic\n        if (pulsarAdmin != null && partitionNum != null && partitionNum > 0 && PRODUCERS.get(topicName) == null) {\n            createMultipleTopic(topicName, partitionNum);\n        }\n\n        ExecutorTemplate template = new ExecutorTemplate(sendPartitionExecutor);\n        // 并发构造\n        MQMessageUtils.EntryRowData[] datas = MQMessageUtils.buildMessageData(message, buildExecutor);\n        if (!mqProperties.isFlatMessage()) {\n            // 动态计算目标分区\n            if (destination.getPartitionHash() != null && !destination.getPartitionHash().isEmpty()) {\n                for (MQMessageUtils.EntryRowData r : datas) {\n                    CanalEntry.Entry entry = r.entry;\n                    if (null == entry) {\n                        continue;\n                    }\n                    // 串行分区\n                    com.alibaba.otter.canal.protocol.Message[] messages = MQMessageUtils.messagePartition(datas,\n                        message.getId(),\n                        partitionNum,\n                        destination.getPartitionHash(),\n                        mqProperties.isDatabaseHash());\n                    // 发送\n                    int len = messages.length;\n                    for (int i = 0; i < len; i++) {\n                        final int partition = i;\n                        com.alibaba.otter.canal.protocol.Message m = messages[i];\n                        template.submit(() -> {\n                            sendMessage(topicName, partition, m);\n                        });\n                    }\n                }\n            } else {\n                // 默认分区\n                final int partition = destination.getPartition() != null ? destination.getPartition() : 0;\n                sendMessage(topicName, partition, message);\n            }\n        } else {\n            // 串行分区\n            List<FlatMessage> flatMessages = MQMessageUtils.messageConverter(datas, message.getId());\n\n            // 初始化分区合并队列\n            if (destination.getPartitionHash() != null && !destination.getPartitionHash().isEmpty()) {\n                List<List<FlatMessage>> partitionFlatMessages = new ArrayList<>();\n                int len = partitionNum;\n                for (int i = 0; i < len; i++) {\n                    partitionFlatMessages.add(new ArrayList<>());\n                }\n\n                for (FlatMessage flatMessage : flatMessages) {\n                    FlatMessage[] partitionFlatMessage = MQMessageUtils.messagePartition(flatMessage,\n                        partitionNum,\n                        destination.getPartitionHash(),\n                        mqProperties.isDatabaseHash());\n                    int length = partitionFlatMessage.length;\n                    for (int i = 0; i < length; i++) {\n                        // 增加null判断,issue #3267\n                        if (partitionFlatMessage[i] != null) {\n                            partitionFlatMessages.get(i).add(partitionFlatMessage[i]);\n                        }\n                    }\n                }\n\n                for (int i = 0; i < len; i++) {\n                    final List<FlatMessage> flatMessagePart = partitionFlatMessages.get(i);\n                    if (flatMessagePart != null && flatMessagePart.size() > 0) {\n                        final int partition = i;\n                        template.submit(() -> {\n                            // 批量发送\n                            sendMessage(topicName, partition, flatMessagePart);\n                        });\n                    }\n                }\n\n                // 批量等所有分区的结果\n                template.waitForResult();\n            } else {\n                // 默认分区\n                final int partition = destination.getPartition() != null ? destination.getPartition() : 0;\n                sendMessage(topicName, partition, flatMessages);\n            }\n        }\n    }\n\n    /**\n     * 发送原始消息，需要做分区处理\n     *\n     * @param topic topic\n     * @param partitionNum 目标分区\n     * @param msg 原始消息内容\n     * @return void\n     * @date 2021/9/10 17:55\n     * @author chad\n     * @since 1 by chad at 2021/9/10 新增\n     */\n    private void sendMessage(String topic, int partitionNum, com.alibaba.otter.canal.protocol.Message msg) {\n        Producer<byte[]> producer = getProducer(topic);\n        byte[] msgBytes = CanalMessageSerializerUtil.serializer(msg, mqProperties.isFilterTransactionEntry());\n        try {\n            MessageId msgResultId = producer.newMessage()\n                .property(MSG_PROPERTY_PARTITION_NAME, String.valueOf(partitionNum))\n                .value(msgBytes)\n                .send();\n            // todo 判断发送结果\n            if (logger.isDebugEnabled()) {\n                logger.debug(\"Send Message to topic:{} Result: {}\", topic, msgResultId);\n            }\n        } catch (Throwable e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * 发送扁平消息\n     *\n     * @param topic topic主题\n     * @param flatMessages 扁平消息\n     * @return void\n     * @date 2021/9/10 18:22\n     * @author chad\n     * @since 1 by chad at 2021/9/10 新增\n     */\n    private void sendMessage(String topic, int partition, List<FlatMessage> flatMessages) {\n        Producer<byte[]> producer = getProducer(topic);\n        for (FlatMessage f : flatMessages) {\n            try {\n                MessageId msgResultId = producer.newMessage()\n                    .property(MSG_PROPERTY_PARTITION_NAME, String.valueOf(partition))\n                    .value(JSON.toJSONBytes(f, Feature.WriteNulls, JSONWriter.Feature.LargeObject))\n                    .send()\n                //\n                ;\n                if (logger.isDebugEnabled()) {\n                    logger.debug(\"Send Messages to topic:{} Result: {}\", topic, msgResultId);\n                }\n            } catch (Throwable e) {\n                throw new RuntimeException(e);\n            }\n        }\n    }\n\n    /**\n     * 创建多分区topic\n     * \n     * @param topic\n     * @param partitionNum\n     */\n    private void createMultipleTopic(String topic, Integer partitionNum) {\n        // 拼接topic前缀\n        PulsarMQProducerConfig pulsarMQProperties = (PulsarMQProducerConfig) this.mqProperties;\n        String prefix = pulsarMQProperties.getTopicTenantPrefix();\n        String fullTopic = topic;\n        if (!StringUtils.isEmpty(prefix)) {\n            if (!prefix.endsWith(\"/\")) {\n                fullTopic = \"/\" + fullTopic;\n            }\n            fullTopic = pulsarMQProperties.getTopicTenantPrefix() + fullTopic;\n        }\n\n        // 创建分区topic\n        try {\n            pulsarAdmin.topics().createPartitionedTopic(fullTopic, partitionNum);\n        } catch (PulsarAdminException e) {\n            // TODO 无论是否报错，都继续后续的操作，此处不进行阻塞\n        }\n    }\n\n    /**\n     * 获取topic\n     * \n     * @param topic\n     * @return\n     */\n    private Producer<byte[]> getProducer(String topic) {\n        Producer producer = PRODUCERS.get(topic);\n        if (null == producer || !producer.isConnected()) {\n            try {\n                synchronized (PRODUCERS) {\n                    producer = PRODUCERS.get(topic);\n                    if (null != producer && producer.isConnected()) {\n                        return producer;\n                    }\n\n                    // 拼接topic前缀\n                    PulsarMQProducerConfig pulsarMQProperties = (PulsarMQProducerConfig) this.mqProperties;\n                    String prefix = pulsarMQProperties.getTopicTenantPrefix();\n                    String fullTopic = topic;\n                    if (!StringUtils.isEmpty(prefix)) {\n                        if (!prefix.endsWith(\"/\")) {\n                            fullTopic = \"/\" + fullTopic;\n                        }\n                        fullTopic = pulsarMQProperties.getTopicTenantPrefix() + fullTopic;\n                    }\n\n                    // 创建指定topic的生产者\n                    ProducerBuilder producerBuilder = client.newProducer();\n                    if (pulsarMQProperties.getEnableChunking()) {\n                        producerBuilder.enableChunking(true);\n                        producerBuilder.enableBatching(false);\n                    }\n\n                    if (!StringUtils.isEmpty(pulsarMQProperties.getCompressionType())) {\n                        switch (pulsarMQProperties.getCompressionType().toLowerCase()) {\n                            case \"lz4\":\n                                producerBuilder.compressionType(CompressionType.LZ4);\n                                break;\n                            case \"zlib\":\n                                producerBuilder.compressionType(CompressionType.ZLIB);\n                                break;\n                            case \"zstd\":\n                                producerBuilder.compressionType(CompressionType.ZSTD);\n                                break;\n                            case \"snappy\":\n                                producerBuilder.compressionType(CompressionType.SNAPPY);\n                                break;\n                        }\n                    }\n\n                    producer = producerBuilder.topic(fullTopic)\n                        // 指定路由器\n                        .messageRouter(new MessageRouterImpl(topic))\n                        .create();\n\n                    // 放入缓存\n                    PRODUCERS.put(topic, producer);\n                }\n            } catch (PulsarClientException e) {\n                logger.error(\"create producer failed for topic: \" + topic, e);\n                throw new RuntimeException(e);\n            }\n        }\n\n        return producer;\n    }\n\n    @Override\n    public void stop() {\n        logger.info(\"## Stop PulsarMQ producer##\");\n\n        for (Producer p : PRODUCERS.values()) {\n            try {\n                if (null != p && p.isConnected()) {\n                    p.close();\n                }\n            } catch (PulsarClientException e) {\n                logger.warn(\"close producer name: {}, topic: {}, error: {}\",\n                    p.getProducerName(),\n                    p.getTopic(),\n                    e.getMessage());\n            }\n        }\n\n        super.stop();\n    }\n\n    /**\n     * Pulsar自定义路由策略\n     *\n     * @author chad\n     * @version 1\n     * @since 1 by chad at 2021/9/10 新增\n     * @since 2 by chad at 2021/9/17 修改为msg自带目标分区\n     */\n    private static class MessageRouterImpl implements MessageRouter {\n\n        private String topicLocal;\n\n        public MessageRouterImpl(String topicLocal){\n            this.topicLocal = topicLocal;\n        }\n\n        @Override\n        public int choosePartition(Message<?> msg, TopicMetadata metadata) {\n            String partitionStr = msg.getProperty(MSG_PROPERTY_PARTITION_NAME);\n            int partition = 0;\n            if (!StringUtils.isEmpty(partitionStr)) {\n                try {\n                    partition = Integer.parseInt(partitionStr);\n                } catch (NumberFormatException e) {\n                    logger\n                        .warn(\"Parse msg {} property failed for value: {}\", MSG_PROPERTY_PARTITION_NAME, partitionStr);\n                }\n            }\n            // topic创建时设置的分区数\n            Integer partitionNum = metadata.numPartitions();\n            // 如果 partition 超出 partitionNum，取余数\n            if (null != partitionNum && partition >= partitionNum) {\n                partition = partition % partitionNum;\n            }\n            return partition;\n        }\n    }\n}\n"
  },
  {
    "path": "connector/pulsarmq-connector/src/main/resources/META-INF/canal/com.alibaba.otter.canal.connector.core.spi.CanalMQProducer",
    "content": "pulsarmq=com.alibaba.otter.canal.connector.pulsarmq.producer.CanalPulsarMQProducer"
  },
  {
    "path": "connector/pulsarmq-connector/src/main/resources/META-INF/canal/com.alibaba.otter.canal.connector.core.spi.CanalMsgConsumer",
    "content": "pulsarmq=com.alibaba.otter.canal.connector.pulsarmq.consumer.CanalPulsarMQConsumer"
  },
  {
    "path": "connector/pulsarmq-connector/src/test/java/com/alibaba/otter/canal/connector/pulsarmq/consumer/CanalPulsarMQConsumerTest.java",
    "content": "package com.alibaba.otter.canal.connector.pulsarmq.consumer;\n\nimport java.time.LocalTime;\nimport java.time.format.DateTimeFormatter;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.concurrent.TimeUnit;\n\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.otter.canal.connector.core.config.CanalConstants;\nimport com.alibaba.otter.canal.connector.core.consumer.CommonMessage;\nimport com.alibaba.otter.canal.connector.pulsarmq.config.PulsarMQConstants;\n\n/**\n * @author chad\n * @date 2021/9/17 22:32\n * @since\n */\npublic class CanalPulsarMQConsumerTest {\n\n    private Properties            properties;\n\n    private CanalPulsarMQConsumer consumer;\n\n    @Before\n    public void before() {\n        properties = new Properties();\n        properties.setProperty(CanalConstants.CANAL_MQ_FLAT_MESSAGE, String.valueOf(true));\n        properties.setProperty(CanalConstants.CANAL_MQ_CANAL_BATCH_SIZE, String.valueOf(30));\n        properties.setProperty(PulsarMQConstants.PULSARMQ_GET_BATCH_TIMEOUT_SECONDS, String.valueOf(5));\n        properties.setProperty(PulsarMQConstants.PULSARMQ_BATCH_PROCESS_TIMEOUT, String.valueOf(30));\n        properties.setProperty(PulsarMQConstants.PULSARMQ_SERVER_URL, \"pulsar://192.168.1.200:6650\");\n        properties.setProperty(PulsarMQConstants.PULSARMQ_ROLE_TOKEN, \"123456\");\n        properties.setProperty(PulsarMQConstants.PULSARMQ_SUBSCRIPT_NAME, \"test-for-canal-pulsar-consumer\");\n        properties.setProperty(PulsarMQConstants.PULSARMQ_REDELIVERY_DELAY_SECONDS, String.valueOf(30));\n        properties.setProperty(PulsarMQConstants.PULSARMQ_ACK_TIMEOUT_SECONDS, String.valueOf(30));\n        properties.setProperty(PulsarMQConstants.PULSARMQ_IS_RETRY, String.valueOf(true));\n        properties.setProperty(PulsarMQConstants.PULSARMQ_IS_RETRY_DLQ_UPPERCASE, String.valueOf(true));\n        properties.setProperty(PulsarMQConstants.PULSARMQ_MAX_REDELIVERY_COUNT, String.valueOf(16));\n\n        consumer = new CanalPulsarMQConsumer();\n        consumer.init(this.properties, \"persistent://public/canal/test-topics-partition\", \"groupid\");\n    }\n\n    @After\n    public void after() {\n        consumer.disconnect();\n    }\n\n    @Test\n    public void getMessage() {\n        consumer.connect();\n\n        while (true) {\n            List<CommonMessage> list = consumer.getMessage(-1L, TimeUnit.SECONDS);\n            String time = LocalTime.now().format(DateTimeFormatter.ofPattern(\"HH:mm:ss\"));\n            if (null == list || list.isEmpty()) {\n                System.out.println(time + \" Receive empty\");\n                continue;\n            }\n            for (CommonMessage m : list) {\n                System.out.println(time + \" Receive ==> \" + JSON.toJSONString(m));\n            }\n\n            consumer.ack();\n        }\n    }\n}\n"
  },
  {
    "path": "connector/rabbitmq-connector/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>canal.connector</artifactId>\n        <groupId>com.alibaba.otter</groupId>\n        <version>1.1.9-SNAPSHOT</version>\n        <relativePath>../pom.xml</relativePath>\n    </parent>\n\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>com.alibaba.otter</groupId>\n    <artifactId>connector.rabbitmq</artifactId>\n    <packaging>jar</packaging>\n    <name>canal connector rabbitmq module for otter ${project.version}</name>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>canal.protocol</artifactId>\n            <version>${project.version}</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>connector.core</artifactId>\n            <version>${project.version}</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.rabbitmq</groupId>\n            <artifactId>amqp-client</artifactId>\n            <version>${rabbitmq_version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.mq-amqp</groupId>\n            <artifactId>mq-amqp-client</artifactId>\n            <version>${mq_amqp_client}</version>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-assembly-plugin</artifactId>\n                <version>2.4</version>\n                <configuration>\n                    <descriptorRefs>\n                        <descriptorRef>jar-with-dependencies</descriptorRef>\n                    </descriptorRefs>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>make-assembly</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>single</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-antrun-plugin</artifactId>\n                <version>1.8</version>\n                <executions>\n                    <execution>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>run</goal>\n                        </goals>\n                        <configuration>\n                            <tasks>\n                                <copy todir=\"${project.basedir}/../../deployer/target/canal/plugin\" overwrite=\"true\">\n                                    <fileset dir=\"${project.basedir}/target\" erroronmissingdir=\"true\">\n                                        <include name=\"connector.rabbitmq-${project.version}-jar-with-dependencies.jar\" />\n                                    </fileset>\n                                </copy>\n                                <copy todir=\"${project.basedir}/../../client-adapter/launcher/target/canal-adapter/plugin\" overwrite=\"true\">\n                                    <fileset dir=\"${project.basedir}/target\" erroronmissingdir=\"true\">\n                                        <include name=\"connector.rabbitmq-${project.version}-jar-with-dependencies.jar\" />\n                                    </fileset>\n                                </copy>\n                            </tasks>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "connector/rabbitmq-connector/src/main/java/com/alibaba/otter/canal/connector/rabbitmq/config/RabbitMQConstants.java",
    "content": "package com.alibaba.otter.canal.connector.rabbitmq.config;\n\n/**\n * RabbitMQ 配置常量类\n *\n * @author rewerma 2020-01-27\n * @version 1.0.0\n */\npublic class RabbitMQConstants {\n\n    public static final String ROOT                      = \"rabbitmq\";\n\n    public static final String RABBITMQ_HOST             = ROOT + \".\" + \"host\";\n    public static final String RABBITMQ_EXCHANGE         = ROOT + \".\" + \"exchange\";\n    public static final String RABBITMQ_VIRTUAL_HOST     = ROOT + \".\" + \"virtual.host\";\n    public static final String RABBITMQ_USERNAME         = ROOT + \".\" + \"username\";\n    public static final String RABBITMQ_PASSWORD         = ROOT + \".\" + \"password\";\n    public static final String RABBITMQ_QUEUE            = ROOT + \".\" + \"queue\";\n    public static final String RABBITMQ_ROUTING_KEY      = ROOT + \".\" + \"routingKey\";\n    public static final String RABBITMQ_DELIVERY_MODE    = ROOT + \".\" + \"deliveryMode\";\n\n    public static final String RABBITMQ_RESOURCE_OWNERID = ROOT + \".\" + \"rabbitmq.resource.ownerId\";\n}\n"
  },
  {
    "path": "connector/rabbitmq-connector/src/main/java/com/alibaba/otter/canal/connector/rabbitmq/config/RabbitMQProducerConfig.java",
    "content": "package com.alibaba.otter.canal.connector.rabbitmq.config;\n\nimport com.alibaba.otter.canal.connector.core.config.MQProperties;\n\n/**\n * RabbitMQ 配置类\n *\n * @author rewerma 2020-01-27\n * @version 1.0.0\n */\npublic class RabbitMQProducerConfig extends MQProperties {\n\n    private String host;\n    private String virtualHost;\n    private String exchange;\n    private String username;\n    private String password;\n    private String queue;\n    private String routingKey;\n    private String deliveryMode;\n\n    public String getHost() {\n        return host;\n    }\n\n    public void setHost(String host) {\n        this.host = host;\n    }\n\n    public String getVirtualHost() {\n        return virtualHost;\n    }\n\n    public void setVirtualHost(String virtualHost) {\n        this.virtualHost = virtualHost;\n    }\n\n    public String getExchange() {\n        return exchange;\n    }\n\n    public void setExchange(String exchange) {\n        this.exchange = exchange;\n    }\n\n    public String getUsername() {\n        return username;\n    }\n\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    public String getQueue() {\n        return queue;\n    }\n\n    public void setQueue(String queue) {\n        this.queue = queue;\n    }\n\n    public String getRoutingKey() {\n        return routingKey;\n    }\n\n    public void setRoutingKey(String routingKey) {\n        this.routingKey = routingKey;\n    }\n\n    public String getDeliveryMode() {\n        return deliveryMode;\n    }\n\n    public void setDeliveryMode(String deliveryMode) {\n        this.deliveryMode = deliveryMode;\n    }\n}\n"
  },
  {
    "path": "connector/rabbitmq-connector/src/main/java/com/alibaba/otter/canal/connector/rabbitmq/consumer/CanalRabbitMQConsumer.java",
    "content": "package com.alibaba.otter.canal.connector.rabbitmq.consumer;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\n\nimport com.alibaba.otter.canal.common.utils.AddressUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.otter.canal.common.utils.PropertiesUtils;\nimport com.alibaba.otter.canal.connector.core.config.CanalConstants;\nimport com.alibaba.otter.canal.connector.core.consumer.CommonMessage;\nimport com.alibaba.otter.canal.connector.core.spi.CanalMsgConsumer;\nimport com.alibaba.otter.canal.connector.core.spi.SPI;\nimport com.alibaba.otter.canal.connector.core.util.CanalMessageSerializerUtil;\nimport com.alibaba.otter.canal.connector.core.util.MessageUtil;\nimport com.alibaba.otter.canal.connector.rabbitmq.config.RabbitMQConstants;\nimport com.alibaba.otter.canal.connector.rabbitmq.producer.AliyunCredentialsProvider;\nimport com.alibaba.otter.canal.protocol.Message;\nimport com.alibaba.otter.canal.protocol.exception.CanalClientException;\nimport com.rabbitmq.client.*;\n\n/**\n * RabbitMQ consumer SPI 实现\n *\n * @author rewerma 2020-02-01\n * @version 1.0.0\n */\n@SPI(\"rabbitmq\")\npublic class CanalRabbitMQConsumer implements CanalMsgConsumer {\n\n    private static final Logger                                logger              = LoggerFactory\n        .getLogger(CanalRabbitMQConsumer.class);\n\n    // 链接地址\n    private String                                             nameServer;\n    // 主机名\n    private String                                             vhost;\n    private String                                             queueName;\n\n    // 一些鉴权信息\n    private String                                             accessKey;\n    private String                                             secretKey;\n    private Long                                               resourceOwnerId;\n    private String                                             username;\n    private String                                             password;\n\n    private boolean                                            flatMessage;\n\n    private Connection                                         connect;\n    private Channel                                            channel;\n\n    private long                                               batchProcessTimeout = 60 * 1000;\n    private BlockingQueue<ConsumerBatchMessage<CommonMessage>> messageBlockingQueue;\n    private volatile ConsumerBatchMessage<CommonMessage>       lastGetBatchMessage = null;\n\n    @Override\n    public void init(Properties properties, String topic, String groupId) {\n        this.nameServer = PropertiesUtils.getProperty(properties, \"rabbitmq.host\");\n        this.vhost = PropertiesUtils.getProperty(properties, \"rabbitmq.virtual.host\");\n        this.queueName = topic;\n        this.accessKey = PropertiesUtils.getProperty(properties, CanalConstants.CANAL_ALIYUN_ACCESS_KEY);\n        this.secretKey = PropertiesUtils.getProperty(properties, CanalConstants.CANAL_ALIYUN_SECRET_KEY);\n        this.username = PropertiesUtils.getProperty(properties, RabbitMQConstants.RABBITMQ_USERNAME);\n        this.password = PropertiesUtils.getProperty(properties, RabbitMQConstants.RABBITMQ_PASSWORD);\n        Long resourceOwnerIdPro = (Long) properties.get(RabbitMQConstants.RABBITMQ_RESOURCE_OWNERID);\n        if (resourceOwnerIdPro != null) {\n            this.resourceOwnerId = resourceOwnerIdPro;\n        }\n        this.flatMessage = (Boolean) properties.get(CanalConstants.CANAL_MQ_FLAT_MESSAGE);\n        this.messageBlockingQueue = new LinkedBlockingQueue<>(1024);\n    }\n\n    @Override\n    public void connect() {\n        ConnectionFactory factory = new ConnectionFactory();\n        if (accessKey.length() > 0 && secretKey.length() > 0) {\n            factory.setCredentialsProvider(new AliyunCredentialsProvider(accessKey, secretKey, resourceOwnerId));\n        } else {\n            factory.setUsername(username);\n            factory.setPassword(password);\n        }\n        // 解析出端口 modified by 16075140\n        if (nameServer != null && nameServer.contains(\":\")) {\n            String[] serverHostAndPort = AddressUtils.splitIPAndPort(nameServer);\n            factory.setHost(serverHostAndPort[0]);\n            factory.setPort(Integer.parseInt(serverHostAndPort[1]));\n        } else {\n            factory.setHost(nameServer);\n        }\n\n        factory.setAutomaticRecoveryEnabled(true);\n        factory.setNetworkRecoveryInterval(5000);\n        factory.setVirtualHost(vhost);\n        try {\n            connect = factory.newConnection();\n            channel = connect.createChannel();\n        } catch (IOException | TimeoutException e) {\n            throw new CanalClientException(\"Start RabbitMQ producer error\", e);\n        }\n\n        // 不存在连接 则重新连接\n        if (connect == null) {\n            this.connect();\n        }\n\n        Consumer consumer = new DefaultConsumer(channel) {\n\n            @Override\n            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,\n                                       byte[] body) throws IOException {\n\n                if (body != null) {\n                    channel.basicAck(envelope.getDeliveryTag(), process(body));\n                }\n            }\n        };\n        try {\n            channel.basicConsume(queueName, false, consumer);\n        } catch (IOException e) {\n            throw new CanalClientException(\"error\", e);\n        }\n    }\n\n    private boolean process(byte[] messageData) {\n        if (logger.isDebugEnabled()) {\n            logger.debug(\"Get Message: {}\", new String(messageData));\n        }\n        List<CommonMessage> messageList = new ArrayList<>();\n        if (!flatMessage) {\n            Message message = CanalMessageSerializerUtil.deserializer(messageData);\n            messageList.addAll(MessageUtil.convert(message));\n        } else {\n            CommonMessage commonMessage = JSON.parseObject(messageData, CommonMessage.class);\n            messageList.add(commonMessage);\n        }\n        ConsumerBatchMessage<CommonMessage> batchMessage = new ConsumerBatchMessage<>(messageList);\n        try {\n            messageBlockingQueue.put(batchMessage);\n        } catch (InterruptedException e) {\n            logger.error(\"Put message to queue error\", e);\n            throw new RuntimeException(e);\n        }\n        boolean isCompleted;\n        try {\n            isCompleted = batchMessage.waitFinish(batchProcessTimeout);\n        } catch (InterruptedException e) {\n            logger.error(\"Interrupted when waiting messages to be finished.\", e);\n            throw new RuntimeException(e);\n        }\n        boolean isSuccess = batchMessage.isSuccess();\n        return isCompleted && isSuccess;\n    }\n\n    @Override\n    public List<CommonMessage> getMessage(Long timeout, TimeUnit unit) {\n        try {\n            if (this.lastGetBatchMessage != null) {\n                throw new CanalClientException(\"mq get/ack not support concurrent & async ack\");\n            }\n\n            ConsumerBatchMessage<CommonMessage> batchMessage = messageBlockingQueue.poll(timeout, unit);\n            if (batchMessage != null) {\n                this.lastGetBatchMessage = batchMessage;\n                return batchMessage.getData();\n            }\n        } catch (InterruptedException ex) {\n            logger.warn(\"Get message timeout\", ex);\n            throw new CanalClientException(\"Failed to fetch the data after: \" + timeout);\n        }\n        return null;\n    }\n\n    @Override\n    public void rollback() {\n        try {\n            if (this.lastGetBatchMessage != null) {\n                this.lastGetBatchMessage.fail();\n            }\n        } finally {\n            this.lastGetBatchMessage = null;\n        }\n    }\n\n    @Override\n    public void ack() {\n        try {\n            if (this.lastGetBatchMessage != null) {\n                this.lastGetBatchMessage.ack();\n            }\n        } catch (Throwable e) {\n            if (this.lastGetBatchMessage != null) {\n                this.lastGetBatchMessage.fail();\n            }\n        } finally {\n            this.lastGetBatchMessage = null;\n        }\n    }\n\n    @Override\n    public void disconnect() {\n        if (channel != null) {\n            try {\n                channel.close();\n            } catch (IOException | TimeoutException e) {\n                throw new CanalClientException(\"stop channel error\", e);\n            }\n        }\n\n        if (connect != null) {\n            try {\n                connect.close();\n            } catch (IOException e) {\n                throw new CanalClientException(\"stop connect error\", e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "connector/rabbitmq-connector/src/main/java/com/alibaba/otter/canal/connector/rabbitmq/consumer/ConsumerBatchMessage.java",
    "content": "package com.alibaba.otter.canal.connector.rabbitmq.consumer;\n\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\npublic class ConsumerBatchMessage<T> {\n\n    private final List<T>  data;\n    private CountDownLatch latch;\n    private boolean        hasFailure = false;\n\n    public ConsumerBatchMessage(List<T> data){\n        this.data = data;\n        latch = new CountDownLatch(1);\n    }\n\n    public boolean waitFinish(long timeout) throws InterruptedException {\n        return latch.await(timeout, TimeUnit.MILLISECONDS);\n    }\n\n    public boolean isSuccess() {\n        return !hasFailure;\n    }\n\n    public List<T> getData() {\n        return data;\n    }\n\n    /**\n     * Countdown if the sub message is successful.\n     */\n    public void ack() {\n        latch.countDown();\n    }\n\n    /**\n     * Countdown and fail-fast if the sub message is failed.\n     */\n    public void fail() {\n        hasFailure = true;\n        // fail fast\n        long count = latch.getCount();\n        for (int i = 0; i < count; i++) {\n            latch.countDown();\n        }\n    }\n}\n"
  },
  {
    "path": "connector/rabbitmq-connector/src/main/java/com/alibaba/otter/canal/connector/rabbitmq/producer/AliyunCredentialsProvider.java",
    "content": "package com.alibaba.otter.canal.connector.rabbitmq.producer;\n\nimport java.security.InvalidKeyException;\nimport java.security.NoSuchAlgorithmException;\n\nimport com.alibaba.mq.amqp.utils.UserUtils;\nimport com.rabbitmq.client.impl.CredentialsProvider;\n\n/**\n * aliyun amqp协议 账号类 暂不支持STS授权情况\n *\n * @version 1.0.0\n */\npublic class AliyunCredentialsProvider implements CredentialsProvider {\n\n    /**\n     * Access Key ID\n     */\n    private final String AliyunAccessKey;\n\n    /**\n     * Access Key Secret\n     */\n    private final String AliyunAccessSecret;\n\n    /**\n     * 资源主账号ID\n     */\n    private final long   resourceOwnerId;\n\n    public AliyunCredentialsProvider(final String accessKey, final String accessSecret, final long resourceOwnerId){\n        this.AliyunAccessKey = accessKey;\n        this.AliyunAccessSecret = accessSecret;\n        this.resourceOwnerId = resourceOwnerId;\n    }\n\n    @Override\n    public String getUsername() {\n        return UserUtils.getUserName(AliyunAccessKey, resourceOwnerId);\n    }\n\n    @Override\n    public String getPassword() {\n        try {\n            return UserUtils.getPassord(AliyunAccessSecret);\n        } catch (InvalidKeyException | NoSuchAlgorithmException ignored) {\n        }\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "connector/rabbitmq-connector/src/main/java/com/alibaba/otter/canal/connector/rabbitmq/producer/CanalRabbitMQProducer.java",
    "content": "package com.alibaba.otter.canal.connector.rabbitmq.producer;\n\nimport java.io.IOException;\nimport java.net.URISyntaxException;\nimport java.security.KeyManagementException;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.concurrent.TimeoutException;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.JSONWriter;\nimport com.alibaba.otter.canal.common.CanalException;\nimport com.alibaba.otter.canal.common.utils.AddressUtils;\nimport com.alibaba.otter.canal.common.utils.ExecutorTemplate;\nimport com.alibaba.otter.canal.common.utils.PropertiesUtils;\nimport com.alibaba.otter.canal.connector.core.producer.AbstractMQProducer;\nimport com.alibaba.otter.canal.connector.core.producer.MQDestination;\nimport com.alibaba.otter.canal.connector.core.producer.MQMessageUtils;\nimport com.alibaba.otter.canal.connector.core.spi.CanalMQProducer;\nimport com.alibaba.otter.canal.connector.core.spi.SPI;\nimport com.alibaba.otter.canal.connector.core.util.Callback;\nimport com.alibaba.otter.canal.connector.core.util.CanalMessageSerializerUtil;\nimport com.alibaba.otter.canal.connector.rabbitmq.config.RabbitMQConstants;\nimport com.alibaba.otter.canal.connector.rabbitmq.config.RabbitMQProducerConfig;\nimport com.alibaba.otter.canal.protocol.FlatMessage;\nimport com.alibaba.otter.canal.protocol.Message;\nimport com.rabbitmq.client.*;\n\n/**\n * RabbitMQ Producer SPI 实现\n *\n * @author rewerma 2020-01-27\n * @version 1.0.0\n */\n@SPI(\"rabbitmq\")\npublic class CanalRabbitMQProducer extends AbstractMQProducer implements CanalMQProducer {\n\n    private static final Logger logger = LoggerFactory.getLogger(CanalRabbitMQProducer.class);\n\n    private Connection          connect;\n    private Channel             channel;\n\n    @Override\n    public void init(Properties properties) {\n        RabbitMQProducerConfig rabbitMQProperties = new RabbitMQProducerConfig();\n        this.mqProperties = rabbitMQProperties;\n        super.init(properties);\n        loadRabbitMQProperties(properties);\n\n        ConnectionFactory factory = new ConnectionFactory();\n        String servers = rabbitMQProperties.getHost();\n        if (servers.startsWith(\"amqp\")) {\n            try {\n                factory.setUri(servers);\n            } catch (URISyntaxException | NoSuchAlgorithmException | KeyManagementException ex) {\n                throw new CanalException(\"failed to parse host\", ex);\n            }\n        } else if (servers.contains(\":\")) {\n            String[] serverHostAndPort = AddressUtils.splitIPAndPort(servers);\n            factory.setHost(serverHostAndPort[0]);\n            factory.setPort(Integer.parseInt(serverHostAndPort[1]));\n        } else {\n            factory.setHost(servers);\n        }\n\n        if (mqProperties.getAliyunAccessKey().length() > 0 && mqProperties.getAliyunSecretKey().length() > 0\n            && mqProperties.getAliyunUid() > 0) {\n            factory.setCredentialsProvider(new AliyunCredentialsProvider(mqProperties.getAliyunAccessKey(),\n                mqProperties.getAliyunSecretKey(),\n                mqProperties.getAliyunUid()));\n        } else {\n            factory.setUsername(rabbitMQProperties.getUsername());\n            factory.setPassword(rabbitMQProperties.getPassword());\n        }\n        factory.setVirtualHost(rabbitMQProperties.getVirtualHost());\n        try {\n            connect = factory.newConnection();\n            channel = connect.createChannel();\n            String queue = rabbitMQProperties.getQueue();\n            String exchange = rabbitMQProperties.getExchange();\n            String deliveryMode = rabbitMQProperties.getDeliveryMode();\n            String routingKey = rabbitMQProperties.getRoutingKey();\n            if (!StringUtils.isEmpty(queue)) {\n                channel.queueDeclare(queue, true, false, false, null);\n            }\n            if (!StringUtils.isEmpty(queue) && !StringUtils.isEmpty(exchange) && !StringUtils.isEmpty(deliveryMode)\n                && !StringUtils.isEmpty(routingKey)) {\n                channel.exchangeDeclare(exchange, deliveryMode, true, false, false, null);\n                channel.queueBind(queue, exchange, routingKey);\n            }\n        } catch (IOException | TimeoutException ex) {\n            throw new CanalException(\"Start RabbitMQ producer error\", ex);\n        }\n    }\n\n    private void loadRabbitMQProperties(Properties properties) {\n        RabbitMQProducerConfig rabbitMQProperties = (RabbitMQProducerConfig) this.mqProperties;\n        // 兼容下<=1.1.4的mq配置\n        doMoreCompatibleConvert(\"canal.mq.servers\", \"rabbitmq.host\", properties);\n\n        String host = PropertiesUtils.getProperty(properties, RabbitMQConstants.RABBITMQ_HOST);\n        if (!StringUtils.isEmpty(host)) {\n            rabbitMQProperties.setHost(host);\n        }\n        String vhost = PropertiesUtils.getProperty(properties, RabbitMQConstants.RABBITMQ_VIRTUAL_HOST);\n        if (!StringUtils.isEmpty(vhost)) {\n            rabbitMQProperties.setVirtualHost(vhost);\n        }\n        String exchange = PropertiesUtils.getProperty(properties, RabbitMQConstants.RABBITMQ_EXCHANGE);\n        if (!StringUtils.isEmpty(exchange)) {\n            rabbitMQProperties.setExchange(exchange);\n        }\n        String username = PropertiesUtils.getProperty(properties, RabbitMQConstants.RABBITMQ_USERNAME);\n        if (!StringUtils.isEmpty(username)) {\n            rabbitMQProperties.setUsername(username);\n        }\n        String password = PropertiesUtils.getProperty(properties, RabbitMQConstants.RABBITMQ_PASSWORD);\n        if (!StringUtils.isEmpty(password)) {\n            rabbitMQProperties.setPassword(password);\n        }\n        String queue = PropertiesUtils.getProperty(properties, RabbitMQConstants.RABBITMQ_QUEUE);\n        if (!StringUtils.isEmpty(queue)) {\n            rabbitMQProperties.setQueue(queue);\n        }\n        String routingKey = PropertiesUtils.getProperty(properties, RabbitMQConstants.RABBITMQ_ROUTING_KEY);\n        if (!StringUtils.isEmpty(routingKey)) {\n            rabbitMQProperties.setRoutingKey(routingKey);\n        }\n        String deliveryMode = PropertiesUtils.getProperty(properties, RabbitMQConstants.RABBITMQ_DELIVERY_MODE);\n        if (!StringUtils.isEmpty(deliveryMode)) {\n            rabbitMQProperties.setDeliveryMode(deliveryMode);\n        }\n    }\n\n    @Override\n    public void send(final MQDestination destination, Message message, Callback callback) {\n        ExecutorTemplate template = new ExecutorTemplate(sendExecutor);\n        try {\n            if (!StringUtils.isEmpty(destination.getDynamicTopic())) {\n                // 动态topic\n                Map<String, Message> messageMap = MQMessageUtils\n                    .messageTopics(message, destination.getTopic(), destination.getDynamicTopic());\n\n                for (Map.Entry<String, com.alibaba.otter.canal.protocol.Message> entry : messageMap.entrySet()) {\n                    final String topicName = entry.getKey().replace('.', '_');\n                    final com.alibaba.otter.canal.protocol.Message messageSub = entry.getValue();\n\n                    template.submit(() -> send(destination, topicName, messageSub));\n                }\n\n                template.waitForResult();\n            } else {\n                send(destination, destination.getTopic(), message);\n            }\n            callback.commit();\n        } catch (Throwable e) {\n            logger.error(e.getMessage(), e);\n            callback.rollback();\n        } finally {\n            template.clear();\n        }\n    }\n\n    private void send(MQDestination canalDestination, String topicName, Message messageSub) {\n        if (!mqProperties.isFlatMessage()) {\n            byte[] message = CanalMessageSerializerUtil.serializer(messageSub, mqProperties.isFilterTransactionEntry());\n            if (logger.isDebugEnabled()) {\n                logger.debug(\"send message:{} to destination:{}\", message, canalDestination.getCanalDestination());\n            }\n            sendMessage(topicName, message);\n        } else {\n            // 并发构造\n            MQMessageUtils.EntryRowData[] datas = MQMessageUtils.buildMessageData(messageSub, buildExecutor);\n            // 串行分区\n            List<FlatMessage> flatMessages = MQMessageUtils.messageConverter(datas, messageSub.getId());\n            for (FlatMessage flatMessage : flatMessages) {\n                byte[] message = JSON\n                    .toJSONBytes(flatMessage, JSONWriter.Feature.WriteNulls, JSONWriter.Feature.LargeObject);\n                if (logger.isDebugEnabled()) {\n                    logger.debug(\"send message:{} to destination:{}\", message, canalDestination.getCanalDestination());\n                }\n                sendMessage(topicName, message);\n            }\n        }\n\n    }\n\n    private void sendMessage(String queueName, byte[] message) {\n        // tips: 目前逻辑中暂不处理对exchange处理，请在Console后台绑定 才可使用routekey\n        try {\n            RabbitMQProducerConfig rabbitMQProperties = (RabbitMQProducerConfig) this.mqProperties;\n            channel.basicPublish(rabbitMQProperties.getExchange(),\n                queueName,\n                MessageProperties.PERSISTENT_TEXT_PLAIN,\n                message);\n        } catch (Throwable e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    @Override\n    public void stop() {\n        logger.info(\"## Stop RabbitMQ producer##\");\n        try {\n            this.channel.close();\n            this.connect.close();\n            super.stop();\n        } catch (AlreadyClosedException ex) {\n            logger.error(\"Connection is already closed\", ex);\n        } catch (IOException | TimeoutException ex) {\n            throw new CanalException(\"Stop RabbitMQ producer error\", ex);\n        }\n\n        super.stop();\n    }\n}\n"
  },
  {
    "path": "connector/rabbitmq-connector/src/main/resources/META-INF/canal/com.alibaba.otter.canal.connector.core.spi.CanalMQProducer",
    "content": "rabbitmq=com.alibaba.otter.canal.connector.rabbitmq.producer.CanalRabbitMQProducer"
  },
  {
    "path": "connector/rabbitmq-connector/src/main/resources/META-INF/canal/com.alibaba.otter.canal.connector.core.spi.CanalMsgConsumer",
    "content": "rabbitmq=com.alibaba.otter.canal.connector.rabbitmq.consumer.CanalRabbitMQConsumer"
  },
  {
    "path": "connector/rocketmq-connector/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>canal.connector</artifactId>\n        <groupId>com.alibaba.otter</groupId>\n        <version>1.1.9-SNAPSHOT</version>\n        <relativePath>../pom.xml</relativePath>\n    </parent>\n\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>com.alibaba.otter</groupId>\n    <artifactId>connector.rocketmq</artifactId>\n    <packaging>jar</packaging>\n    <name>canal connector rocketMQ module for otter ${project.version}</name>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>canal.protocol</artifactId>\n            <version>${project.version}</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>connector.core</artifactId>\n            <version>${project.version}</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.rocketmq</groupId>\n            <artifactId>rocketmq-client</artifactId>\n            <version>${rocketmq_version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.rocketmq</groupId>\n            <artifactId>rocketmq-acl</artifactId>\n            <version>${rocketmq_version}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-assembly-plugin</artifactId>\n                <version>2.4</version>\n                <configuration>\n                    <descriptorRefs>\n                        <descriptorRef>jar-with-dependencies</descriptorRef>\n                    </descriptorRefs>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>make-assembly</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>single</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-antrun-plugin</artifactId>\n                <version>1.8</version>\n                <executions>\n                    <execution>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>run</goal>\n                        </goals>\n                        <configuration>\n                            <tasks>\n                                <copy todir=\"${project.basedir}/../../deployer/target/canal/plugin\" overwrite=\"true\">\n                                    <fileset dir=\"${project.basedir}/target\" erroronmissingdir=\"true\">\n                                        <include name=\"connector.rocketmq-${project.version}-jar-with-dependencies.jar\" />\n                                    </fileset>\n                                </copy>\n                                <copy todir=\"${project.basedir}/../../client-adapter/launcher/target/canal-adapter/plugin\" overwrite=\"true\">\n                                    <fileset dir=\"${project.basedir}/target\" erroronmissingdir=\"true\">\n                                        <include name=\"connector.rocketmq-${project.version}-jar-with-dependencies.jar\" />\n                                    </fileset>\n                                </copy>\n                            </tasks>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "connector/rocketmq-connector/src/main/java/com/alibaba/otter/canal/connector/rocketmq/config/RocketMQConstants.java",
    "content": "package com.alibaba.otter.canal.connector.rocketmq.config;\n\n/**\n * RocketMQ 配置常量类\n *\n * @author rewerma 2020-01-27\n * @version 1.0.0\n */\npublic class RocketMQConstants {\n\n    public static final String ROOT                                  = \"rocketmq\";\n\n    public static final String ROCKETMQ_PRODUCER_GROUP               = ROOT + \".\" + \"producer.group\";\n    public static final String ROCKETMQ_ENABLE_MESSAGE_TRACE         = ROOT + \".\" + \"enable.message.trace\";\n    public static final String ROCKETMQ_CUSTOMIZED_TRACE_TOPIC       = ROOT + \".\" + \"customized.trace.topic\";\n    public static final String ROCKETMQ_NAMESPACE                    = ROOT + \".\" + \"namespace\";\n    public static final String ROCKETMQ_NAMESRV_ADDR                 = ROOT + \".\" + \"namesrv.addr\";\n    public static final String ROCKETMQ_RETRY_TIMES_WHEN_SEND_FAILED = ROOT + \".\" + \"retry.times.when.send.failed\";\n    public static final String ROCKETMQ_VIP_CHANNEL_ENABLED          = ROOT + \".\" + \"vip.channel.enabled\";\n    public static final String ROCKETMQ_TAG                          = ROOT + \".\" + \"tag\";\n\n    public static final String ROCKETMQ_ACCESS_CHANNEL               = ROOT + \".\" + \"access.channel\";\n    public static final String ROCKETMQ_BATCH_SIZE                   = ROOT + \".\" + \"batch.size\";\n    public static final String ROCKETMQ_SUBSCRIBE_FILTER             = ROOT + \".\" + \"subscribe.filter\";\n\n}\n"
  },
  {
    "path": "connector/rocketmq-connector/src/main/java/com/alibaba/otter/canal/connector/rocketmq/config/RocketMQProducerConfig.java",
    "content": "package com.alibaba.otter.canal.connector.rocketmq.config;\n\nimport com.alibaba.otter.canal.connector.core.config.MQProperties;\n\n/**\n * RocketMQ 配置类\n *\n * @author rewerma 2020-01-27\n * @version 1.0.0\n */\npublic class RocketMQProducerConfig extends MQProperties {\n\n    private String  producerGroup;\n    private boolean enableMessageTrace       = false;\n    private String  customizedTraceTopic;\n    private String  namespace;\n    private String  namesrvAddr;\n    private int     retryTimesWhenSendFailed = 0;\n    private boolean vipChannelEnabled        = false;\n    private String  tag;\n\n    public String getProducerGroup() {\n        return producerGroup;\n    }\n\n    public void setProducerGroup(String producerGroup) {\n        this.producerGroup = producerGroup;\n    }\n\n    public boolean isEnableMessageTrace() {\n        return enableMessageTrace;\n    }\n\n    public void setEnableMessageTrace(boolean enableMessageTrace) {\n        this.enableMessageTrace = enableMessageTrace;\n    }\n\n    public String getCustomizedTraceTopic() {\n        return customizedTraceTopic;\n    }\n\n    public void setCustomizedTraceTopic(String customizedTraceTopic) {\n        this.customizedTraceTopic = customizedTraceTopic;\n    }\n\n    public String getNamespace() {\n        return namespace;\n    }\n\n    public void setNamespace(String namespace) {\n        this.namespace = namespace;\n    }\n\n    public String getNamesrvAddr() {\n        return namesrvAddr;\n    }\n\n    public void setNamesrvAddr(String namesrvAddr) {\n        this.namesrvAddr = namesrvAddr;\n    }\n\n    public int getRetryTimesWhenSendFailed() {\n        return retryTimesWhenSendFailed;\n    }\n\n    public void setRetryTimesWhenSendFailed(int retryTimesWhenSendFailed) {\n        this.retryTimesWhenSendFailed = retryTimesWhenSendFailed;\n    }\n\n    public boolean isVipChannelEnabled() {\n        return vipChannelEnabled;\n    }\n\n    public void setVipChannelEnabled(boolean vipChannelEnabled) {\n        this.vipChannelEnabled = vipChannelEnabled;\n    }\n\n    public String getTag() {\n        return tag;\n    }\n\n    public void setTag(String tag) {\n        this.tag = tag;\n    }\n}\n"
  },
  {
    "path": "connector/rocketmq-connector/src/main/java/com/alibaba/otter/canal/connector/rocketmq/consumer/CanalRocketMQConsumer.java",
    "content": "package com.alibaba.otter.canal.connector.rocketmq.consumer;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.rocketmq.acl.common.AclClientRPCHook;\nimport org.apache.rocketmq.acl.common.SessionCredentials;\nimport org.apache.rocketmq.client.AccessChannel;\nimport org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;\nimport org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyStatus;\nimport org.apache.rocketmq.client.consumer.listener.MessageListenerOrderly;\nimport org.apache.rocketmq.client.consumer.rebalance.AllocateMessageQueueAveragely;\nimport org.apache.rocketmq.client.exception.MQClientException;\nimport org.apache.rocketmq.common.message.MessageExt;\nimport org.apache.rocketmq.remoting.RPCHook;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.otter.canal.connector.core.config.CanalConstants;\nimport com.alibaba.otter.canal.connector.core.consumer.CommonMessage;\nimport com.alibaba.otter.canal.connector.core.spi.CanalMsgConsumer;\nimport com.alibaba.otter.canal.connector.core.spi.SPI;\nimport com.alibaba.otter.canal.connector.core.util.CanalMessageSerializerUtil;\nimport com.alibaba.otter.canal.connector.core.util.MessageUtil;\nimport com.alibaba.otter.canal.connector.rocketmq.config.RocketMQConstants;\nimport com.alibaba.otter.canal.protocol.Message;\nimport com.alibaba.otter.canal.protocol.exception.CanalClientException;\n\n/**\n * RocketMQ consumer SPI 实现\n *\n * @author rewerma 2020-02-01\n * @version 1.0.0\n */\n@SPI(\"rocketmq\")\npublic class CanalRocketMQConsumer implements CanalMsgConsumer {\n\n    private static final Logger                                logger               = LoggerFactory.getLogger(CanalRocketMQConsumer.class);\n    private static final String                                CLOUD_ACCESS_CHANNEL = \"cloud\";\n\n    private String                                             nameServer;\n    private String                                             topic;\n    private String                                             groupName;\n    private DefaultMQPushConsumer                              rocketMQConsumer;\n    private BlockingQueue<ConsumerBatchMessage<CommonMessage>> messageBlockingQueue;\n    private int                                                batchSize            = -1;\n    private long                                               batchProcessTimeout  = 60 * 1000;\n    private boolean                                            flatMessage;\n    private volatile ConsumerBatchMessage<CommonMessage>       lastGetBatchMessage  = null;\n    private String                                             accessKey;\n    private String                                             secretKey;\n    private String                                             customizedTraceTopic;\n    private boolean                                            enableMessageTrace   = false;\n    private String                                             accessChannel;\n    private String                                             namespace;\n    private String                                             filter               = \"*\";\n\n    @Override\n    public void init(Properties properties, String topic, String groupName) {\n        this.topic = topic;\n        this.groupName = groupName;\n        this.flatMessage = (Boolean) properties.get(CanalConstants.CANAL_MQ_FLAT_MESSAGE);\n        this.messageBlockingQueue = new LinkedBlockingQueue<>(1024);\n        this.accessKey = properties.getProperty(CanalConstants.CANAL_ALIYUN_ACCESS_KEY);\n        this.secretKey = properties.getProperty(CanalConstants.CANAL_ALIYUN_SECRET_KEY);\n        String enableMessageTrace = properties.getProperty(RocketMQConstants.ROCKETMQ_ENABLE_MESSAGE_TRACE);\n        if (StringUtils.isNotEmpty(enableMessageTrace)) {\n            this.enableMessageTrace = Boolean.parseBoolean(enableMessageTrace);\n        }\n        this.customizedTraceTopic = properties.getProperty(RocketMQConstants.ROCKETMQ_CUSTOMIZED_TRACE_TOPIC);\n        this.accessChannel = properties.getProperty(RocketMQConstants.ROCKETMQ_ACCESS_CHANNEL);\n        this.namespace = properties.getProperty(RocketMQConstants.ROCKETMQ_NAMESPACE);\n        this.nameServer = properties.getProperty(RocketMQConstants.ROCKETMQ_NAMESRV_ADDR);\n        String batchSize = properties.getProperty(RocketMQConstants.ROCKETMQ_BATCH_SIZE);\n        if (StringUtils.isNotEmpty(batchSize)) {\n            this.batchSize = Integer.parseInt(batchSize);\n        }\n        String subscribeFilter = properties.getProperty(RocketMQConstants.ROCKETMQ_SUBSCRIBE_FILTER);\n        if (StringUtils.isNotEmpty(subscribeFilter)) {\n            this.filter = subscribeFilter;\n        }\n    }\n\n    @Override\n    public void connect() {\n        RPCHook rpcHook = null;\n        if (null != accessKey && accessKey.length() > 0 && null != secretKey && secretKey.length() > 0) {\n            SessionCredentials sessionCredentials = new SessionCredentials();\n            sessionCredentials.setAccessKey(accessKey);\n            sessionCredentials.setSecretKey(secretKey);\n            rpcHook = new AclClientRPCHook(sessionCredentials);\n        }\n\n        rocketMQConsumer = new DefaultMQPushConsumer(groupName,\n            rpcHook,\n            new AllocateMessageQueueAveragely(),\n            enableMessageTrace,\n            customizedTraceTopic);\n        rocketMQConsumer.setVipChannelEnabled(false);\n        if (CLOUD_ACCESS_CHANNEL.equals(this.accessChannel)) {\n            rocketMQConsumer.setAccessChannel(AccessChannel.CLOUD);\n        }\n\n        if (!StringUtils.isEmpty(this.namespace)) {\n            rocketMQConsumer.setNamespace(this.namespace);\n        }\n\n        if (!StringUtils.isBlank(nameServer)) {\n            rocketMQConsumer.setNamesrvAddr(nameServer);\n        }\n        if (batchSize != -1) {\n            rocketMQConsumer.setConsumeMessageBatchMaxSize(batchSize);\n        }\n\n        try {\n            if (rocketMQConsumer == null) {\n                this.connect();\n            }\n            rocketMQConsumer.subscribe(this.topic, this.filter);\n            rocketMQConsumer.registerMessageListener((MessageListenerOrderly) (messageExts, context) -> {\n                context.setAutoCommit(true);\n                boolean isSuccess = process(messageExts);\n                if (isSuccess) {\n                    return ConsumeOrderlyStatus.SUCCESS;\n                } else {\n                    return ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT;\n                }\n            });\n            rocketMQConsumer.start();\n        } catch (MQClientException ex) {\n            logger.error(\"Start RocketMQ consumer error\", ex);\n        }\n    }\n\n    private boolean process(List<MessageExt> messageExts) {\n        if (logger.isDebugEnabled()) {\n            logger.debug(\"Get Message: {}\", messageExts);\n        }\n        List<CommonMessage> messageList = new ArrayList<>();\n        for (MessageExt messageExt : messageExts) {\n            byte[] data = messageExt.getBody();\n            if (data != null) {\n                try {\n                    if (!flatMessage) {\n                        Message message = CanalMessageSerializerUtil.deserializer(data);\n                        messageList.addAll(MessageUtil.convert(message));\n                    } else {\n                        CommonMessage commonMessage = JSON.parseObject(data, CommonMessage.class);\n                        messageList.add(commonMessage);\n                    }\n                } catch (Exception ex) {\n                    logger.error(\"Add message error\", ex);\n                    throw new CanalClientException(ex);\n                }\n            } else {\n                logger.warn(\"Received message data is null\");\n            }\n        }\n        ConsumerBatchMessage<CommonMessage> batchMessage = new ConsumerBatchMessage<>(messageList);\n        try {\n            messageBlockingQueue.put(batchMessage);\n        } catch (InterruptedException e) {\n            logger.error(\"Put message to queue error\", e);\n            throw new RuntimeException(e);\n        }\n        boolean isCompleted;\n        try {\n            isCompleted = batchMessage.waitFinish(batchProcessTimeout);\n        } catch (InterruptedException e) {\n            logger.error(\"Interrupted when waiting messages to be finished.\", e);\n            throw new RuntimeException(e);\n        }\n        boolean isSuccess = batchMessage.isSuccess();\n        return isCompleted && isSuccess;\n    }\n\n    @Override\n    public List<CommonMessage> getMessage(Long timeout, TimeUnit unit) {\n        try {\n            if (this.lastGetBatchMessage != null) {\n                throw new CanalClientException(\"mq get/ack not support concurrent & async ack\");\n            }\n\n            ConsumerBatchMessage<CommonMessage> batchMessage = messageBlockingQueue.poll(timeout, unit);\n            if (batchMessage != null) {\n                this.lastGetBatchMessage = batchMessage;\n                return batchMessage.getData();\n            }\n        } catch (InterruptedException ex) {\n            logger.warn(\"Get message timeout\", ex);\n            throw new CanalClientException(\"Failed to fetch the data after: \" + timeout);\n        }\n        return null;\n    }\n\n    @Override\n    public void rollback() {\n        try {\n            if (this.lastGetBatchMessage != null) {\n                this.lastGetBatchMessage.fail();\n            }\n        } finally {\n            this.lastGetBatchMessage = null;\n        }\n    }\n\n    @Override\n    public void ack() {\n        try {\n            if (this.lastGetBatchMessage != null) {\n                this.lastGetBatchMessage.ack();\n            }\n        } catch (Throwable e) {\n            if (this.lastGetBatchMessage != null) {\n                this.lastGetBatchMessage.fail();\n            }\n        } finally {\n            this.lastGetBatchMessage = null;\n        }\n    }\n\n    @Override\n    public void disconnect() {\n        rocketMQConsumer.unsubscribe(topic);\n        rocketMQConsumer.shutdown();\n    }\n}\n"
  },
  {
    "path": "connector/rocketmq-connector/src/main/java/com/alibaba/otter/canal/connector/rocketmq/consumer/ConsumerBatchMessage.java",
    "content": "package com.alibaba.otter.canal.connector.rocketmq.consumer;\n\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\npublic class ConsumerBatchMessage<T> {\n\n    private final List<T>  data;\n    private CountDownLatch latch;\n    private boolean        hasFailure = false;\n\n    public ConsumerBatchMessage(List<T> data){\n        this.data = data;\n        latch = new CountDownLatch(1);\n    }\n\n    public boolean waitFinish(long timeout) throws InterruptedException {\n        return latch.await(timeout, TimeUnit.MILLISECONDS);\n    }\n\n    public boolean isSuccess() {\n        return !hasFailure;\n    }\n\n    public List<T> getData() {\n        return data;\n    }\n\n    /**\n     * Countdown if the sub message is successful.\n     */\n    public void ack() {\n        latch.countDown();\n    }\n\n    /**\n     * Countdown and fail-fast if the sub message is failed.\n     */\n    public void fail() {\n        hasFailure = true;\n        // fail fast\n        long count = latch.getCount();\n        for (int i = 0; i < count; i++) {\n            latch.countDown();\n        }\n    }\n}\n"
  },
  {
    "path": "connector/rocketmq-connector/src/main/java/com/alibaba/otter/canal/connector/rocketmq/producer/CanalRocketMQProducer.java",
    "content": "package com.alibaba.otter.canal.connector.rocketmq.producer;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.stream.Collectors;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.rocketmq.acl.common.AclClientRPCHook;\nimport org.apache.rocketmq.acl.common.SessionCredentials;\nimport org.apache.rocketmq.client.AccessChannel;\nimport org.apache.rocketmq.client.exception.MQClientException;\nimport org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl;\nimport org.apache.rocketmq.client.impl.producer.TopicPublishInfo;\nimport org.apache.rocketmq.client.producer.DefaultMQProducer;\nimport org.apache.rocketmq.client.producer.SendResult;\nimport org.apache.rocketmq.common.message.Message;\nimport org.apache.rocketmq.common.message.MessageQueue;\nimport org.apache.rocketmq.remoting.RPCHook;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.JSONWriter;\nimport com.alibaba.otter.canal.common.CanalException;\nimport com.alibaba.otter.canal.common.utils.ExecutorTemplate;\nimport com.alibaba.otter.canal.common.utils.NamedThreadFactory;\nimport com.alibaba.otter.canal.common.utils.PropertiesUtils;\nimport com.alibaba.otter.canal.connector.core.producer.AbstractMQProducer;\nimport com.alibaba.otter.canal.connector.core.producer.MQDestination;\nimport com.alibaba.otter.canal.connector.core.producer.MQMessageUtils;\nimport com.alibaba.otter.canal.connector.core.spi.CanalMQProducer;\nimport com.alibaba.otter.canal.connector.core.spi.SPI;\nimport com.alibaba.otter.canal.connector.core.util.Callback;\nimport com.alibaba.otter.canal.connector.core.util.CanalMessageSerializerUtil;\nimport com.alibaba.otter.canal.connector.rocketmq.config.RocketMQConstants;\nimport com.alibaba.otter.canal.connector.rocketmq.config.RocketMQProducerConfig;\nimport com.alibaba.otter.canal.protocol.FlatMessage;\n\n/**\n * RocketMQ Producer SPI 实现\n *\n * @author rewerma 2020-01-27\n * @version 1.0.0\n */\n@SPI(\"rocketmq\")\npublic class CanalRocketMQProducer extends AbstractMQProducer implements CanalMQProducer {\n\n    private static final Logger  logger               = LoggerFactory.getLogger(CanalRocketMQProducer.class);\n\n    private DefaultMQProducer    defaultMQProducer;\n    private static final String  CLOUD_ACCESS_CHANNEL = \"cloud\";\n    private static final String  NAMESPACE_SEPARATOR  = \"%\";\n    protected ThreadPoolExecutor sendPartitionExecutor;\n\n    @Override\n    public void init(Properties properties) {\n        RocketMQProducerConfig rocketMQProperties = new RocketMQProducerConfig();\n        this.mqProperties = rocketMQProperties;\n        super.init(properties);\n        loadRocketMQProperties(properties);\n\n        RPCHook rpcHook = null;\n        if (mqProperties.getAliyunAccessKey().length() > 0 && mqProperties.getAliyunSecretKey().length() > 0) {\n            SessionCredentials sessionCredentials = new SessionCredentials();\n            sessionCredentials.setAccessKey(mqProperties.getAliyunAccessKey());\n            sessionCredentials.setSecretKey(mqProperties.getAliyunSecretKey());\n            rpcHook = new AclClientRPCHook(sessionCredentials);\n        }\n\n        defaultMQProducer = new DefaultMQProducer(rocketMQProperties.getProducerGroup(),\n            rpcHook,\n            rocketMQProperties.isEnableMessageTrace(),\n            rocketMQProperties.getCustomizedTraceTopic());\n        if (CLOUD_ACCESS_CHANNEL.equals(rocketMQProperties.getAccessChannel())) {\n            defaultMQProducer.setAccessChannel(AccessChannel.CLOUD);\n        }\n        if (!StringUtils.isEmpty(rocketMQProperties.getNamespace())) {\n            defaultMQProducer.setNamespace(rocketMQProperties.getNamespace());\n        }\n        defaultMQProducer.setNamesrvAddr(rocketMQProperties.getNamesrvAddr());\n        defaultMQProducer.setRetryTimesWhenSendFailed(rocketMQProperties.getRetryTimesWhenSendFailed());\n        defaultMQProducer.setVipChannelEnabled(rocketMQProperties.isVipChannelEnabled());\n        logger.info(\"##Start RocketMQ producer##\");\n        try {\n            defaultMQProducer.start();\n        } catch (MQClientException ex) {\n            throw new CanalException(\"Start RocketMQ producer error\", ex);\n        }\n\n        int parallelPartitionSendThreadSize = mqProperties.getParallelSendThreadSize();\n        sendPartitionExecutor = new ThreadPoolExecutor(parallelPartitionSendThreadSize,\n            parallelPartitionSendThreadSize,\n            0,\n            TimeUnit.SECONDS,\n            new ArrayBlockingQueue<>(parallelPartitionSendThreadSize * 2),\n            new NamedThreadFactory(\"MQ-Parallel-Sender-Partition\"),\n            new ThreadPoolExecutor.CallerRunsPolicy());\n    }\n\n    private void loadRocketMQProperties(Properties properties) {\n        RocketMQProducerConfig rocketMQProperties = (RocketMQProducerConfig) this.mqProperties;\n        // 兼容下<=1.1.4的mq配置\n        doMoreCompatibleConvert(\"canal.mq.servers\", \"rocketmq.namesrv.addr\", properties);\n        doMoreCompatibleConvert(\"canal.mq.producerGroup\", \"rocketmq.producer.group\", properties);\n        doMoreCompatibleConvert(\"canal.mq.namespace\", \"rocketmq.namespace\", properties);\n        doMoreCompatibleConvert(\"canal.mq.retries\", \"rocketmq.retry.times.when.send.failed\", properties);\n\n        String producerGroup = PropertiesUtils.getProperty(properties, RocketMQConstants.ROCKETMQ_PRODUCER_GROUP);\n        if (!StringUtils.isEmpty(producerGroup)) {\n            rocketMQProperties.setProducerGroup(producerGroup);\n        }\n        String enableMessageTrace = PropertiesUtils.getProperty(properties,\n            RocketMQConstants.ROCKETMQ_ENABLE_MESSAGE_TRACE);\n        if (!StringUtils.isEmpty(enableMessageTrace)) {\n            rocketMQProperties.setEnableMessageTrace(Boolean.parseBoolean(enableMessageTrace));\n        }\n        String customizedTraceTopic = PropertiesUtils.getProperty(properties,\n            RocketMQConstants.ROCKETMQ_CUSTOMIZED_TRACE_TOPIC);\n        if (!StringUtils.isEmpty(customizedTraceTopic)) {\n            rocketMQProperties.setCustomizedTraceTopic(customizedTraceTopic);\n        }\n        String namespace = PropertiesUtils.getProperty(properties, RocketMQConstants.ROCKETMQ_NAMESPACE);\n        if (!StringUtils.isEmpty(namespace)) {\n            rocketMQProperties.setNamespace(namespace);\n        }\n        String namesrvAddr = PropertiesUtils.getProperty(properties, RocketMQConstants.ROCKETMQ_NAMESRV_ADDR);\n        if (!StringUtils.isEmpty(namesrvAddr)) {\n            rocketMQProperties.setNamesrvAddr(namesrvAddr);\n        }\n        String retry = PropertiesUtils.getProperty(properties, RocketMQConstants.ROCKETMQ_RETRY_TIMES_WHEN_SEND_FAILED);\n        if (!StringUtils.isEmpty(retry)) {\n            rocketMQProperties.setRetryTimesWhenSendFailed(Integer.parseInt(retry));\n        }\n        String vipChannelEnabled = PropertiesUtils.getProperty(properties,\n            RocketMQConstants.ROCKETMQ_VIP_CHANNEL_ENABLED);\n        if (!StringUtils.isEmpty(vipChannelEnabled)) {\n            rocketMQProperties.setVipChannelEnabled(Boolean.parseBoolean(vipChannelEnabled));\n        }\n        String tag = PropertiesUtils.getProperty(properties, RocketMQConstants.ROCKETMQ_TAG);\n        if (!StringUtils.isEmpty(tag)) {\n            rocketMQProperties.setTag(tag);\n        }\n    }\n\n    @Override\n    public void send(MQDestination destination, com.alibaba.otter.canal.protocol.Message message, Callback callback) {\n        ExecutorTemplate template = new ExecutorTemplate(sendExecutor);\n        try {\n            if (!StringUtils.isEmpty(destination.getDynamicTopic())) {\n                // 动态topic\n                Map<String, com.alibaba.otter.canal.protocol.Message> messageMap = MQMessageUtils\n                    .messageTopics(message, destination.getTopic(), destination.getDynamicTopic());\n\n                for (Map.Entry<String, com.alibaba.otter.canal.protocol.Message> entry : messageMap.entrySet()) {\n                    String topicName = entry.getKey().replace('.', '_');\n                    com.alibaba.otter.canal.protocol.Message messageSub = entry.getValue();\n                    template.submit(() -> {\n                        try {\n                            send(destination, topicName, messageSub);\n                        } catch (Exception e) {\n                            throw new RuntimeException(e);\n                        }\n                    });\n                }\n\n                template.waitForResult();\n            } else {\n                send(destination, destination.getTopic(), message);\n            }\n\n            callback.commit();\n        } catch (Throwable e) {\n            logger.error(e.getMessage(), e);\n            callback.rollback();\n        } finally {\n            template.clear();\n        }\n    }\n\n    public void send(final MQDestination destination, String topicName,\n                     com.alibaba.otter.canal.protocol.Message message) {\n        // 获取当前topic的分区数\n        Integer partitionNum = MQMessageUtils.parseDynamicTopicPartition(topicName,\n            destination.getDynamicTopicPartitionNum());\n\n        // 获取topic的队列数为分区数\n        if (partitionNum == null) {\n            partitionNum = getTopicDynamicQueuesSize(destination.getEnableDynamicQueuePartition(), topicName);\n        }\n\n        if (partitionNum == null) {\n            partitionNum = destination.getPartitionsNum();\n        }\n        if (!mqProperties.isFlatMessage()) {\n            if (destination.getPartitionHash() != null && !destination.getPartitionHash().isEmpty()) {\n                // 并发构造\n                MQMessageUtils.EntryRowData[] datas = MQMessageUtils.buildMessageData(message, buildExecutor);\n                // 串行分区\n                com.alibaba.otter.canal.protocol.Message[] messages = MQMessageUtils.messagePartition(datas,\n                    message.getId(),\n                    partitionNum,\n                    destination.getPartitionHash(),\n                    mqProperties.isDatabaseHash());\n                int length = messages.length;\n\n                ExecutorTemplate template = new ExecutorTemplate(sendPartitionExecutor);\n                for (int i = 0; i < length; i++) {\n                    com.alibaba.otter.canal.protocol.Message dataPartition = messages[i];\n                    if (dataPartition != null) {\n                        final int index = i;\n                        template.submit(() -> {\n                            Message data = new Message(topicName,\n                                ((RocketMQProducerConfig) this.mqProperties).getTag(),\n                                CanalMessageSerializerUtil.serializer(dataPartition,\n                                    mqProperties.isFilterTransactionEntry()));\n                            sendMessage(data, index);\n                        });\n                    }\n                }\n                // 等所有分片发送完毕\n                template.waitForResult();\n            } else {\n                final int partition = destination.getPartition() != null ? destination.getPartition() : 0;\n                Message data = new Message(topicName,\n                    ((RocketMQProducerConfig) this.mqProperties).getTag(),\n                    CanalMessageSerializerUtil.serializer(message, mqProperties.isFilterTransactionEntry()));\n                sendMessage(data, partition);\n            }\n        } else {\n            // 并发构造\n            MQMessageUtils.EntryRowData[] datas = MQMessageUtils.buildMessageData(message, buildExecutor);\n            // 串行分区\n            List<FlatMessage> flatMessages = MQMessageUtils.messageConverter(datas, message.getId());\n            // 初始化分区合并队列\n            if (destination.getPartitionHash() != null && !destination.getPartitionHash().isEmpty()) {\n                List<List<FlatMessage>> partitionFlatMessages = new ArrayList<>();\n                for (int i = 0; i < partitionNum; i++) {\n                    partitionFlatMessages.add(new ArrayList<>());\n                }\n\n                for (FlatMessage flatMessage : flatMessages) {\n                    FlatMessage[] partitionFlatMessage = MQMessageUtils.messagePartition(flatMessage,\n                        partitionNum,\n                        destination.getPartitionHash(),\n                        mqProperties.isDatabaseHash());\n                    int length = partitionFlatMessage.length;\n                    for (int i = 0; i < length; i++) {\n                        // 增加null判断,issue #3267\n                        if (partitionFlatMessage[i] != null) {\n                            partitionFlatMessages.get(i).add(partitionFlatMessage[i]);\n                        }\n                    }\n                }\n\n                ExecutorTemplate template = new ExecutorTemplate(sendPartitionExecutor);\n                for (int i = 0; i < partitionFlatMessages.size(); i++) {\n                    final List<FlatMessage> flatMessagePart = partitionFlatMessages.get(i);\n                    if (flatMessagePart != null && flatMessagePart.size() > 0) {\n                        final int index = i;\n                        template.submit(() -> {\n                            List<Message> messages = flatMessagePart.stream()\n                                .map(flatMessage -> new Message(topicName,\n                                    ((RocketMQProducerConfig) this.mqProperties).getTag(),\n                                    JSON.toJSONBytes(flatMessage,\n                                        JSONWriter.Feature.WriteNulls,\n                                        JSONWriter.Feature.LargeObject)))\n                                .collect(Collectors.toList());\n                            // 批量发送\n                            sendMessage(messages, index);\n                        });\n                    }\n                }\n\n                // 批量等所有分区的结果\n                template.waitForResult();\n            } else {\n                final int partition = destination.getPartition() != null ? destination.getPartition() : 0;\n                List<Message> messages = flatMessages.stream()\n                    .map(flatMessage -> new Message(topicName,\n                        ((RocketMQProducerConfig) this.mqProperties).getTag(),\n                        JSON.toJSONBytes(flatMessage, JSONWriter.Feature.WriteNulls, JSONWriter.Feature.LargeObject)))\n                    .collect(Collectors.toList());\n                // 批量发送\n                sendMessage(messages, partition);\n            }\n        }\n    }\n\n    private void sendMessage(Message message, int partition) {\n        try {\n            SendResult sendResult = this.defaultMQProducer.send(message, (mqs, msg, arg) -> {\n                if (partition >= mqs.size()) {\n                    return mqs.get(partition % mqs.size());\n                } else {\n                    return mqs.get(partition);\n                }\n            }, null);\n\n            if (logger.isDebugEnabled()) {\n                logger.debug(\"Send Message Result: {}\", sendResult);\n            }\n        } catch (Throwable e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    private void sendMessage(List<Message> messages, int partition) {\n        if (messages.isEmpty()) {\n            return;\n        }\n\n        // 获取一下messageQueue\n        DefaultMQProducerImpl innerProducer = this.defaultMQProducer.getDefaultMQProducerImpl();\n        String topic = messages.get(0).getTopic();\n        if (StringUtils.isNotBlank(this.defaultMQProducer.getNamespace())) {\n            topic = this.defaultMQProducer.getNamespace() + NAMESPACE_SEPARATOR + topic;\n        }\n        TopicPublishInfo topicInfo = innerProducer.getTopicPublishInfoTable().get(topic);\n        if (topicInfo == null) {\n            for (Message message : messages) {\n                sendMessage(message, partition);\n            }\n        } else {\n            // 批量发送\n            List<MessageQueue> queues = topicInfo.getMessageQueueList();\n            int size = queues.size();\n            if (size <= 0) {\n                // 可能是第一次创建\n                for (Message message : messages) {\n                    sendMessage(message, partition);\n                }\n            } else {\n                MessageQueue queue;\n                if (partition >= size) {\n                    queue = queues.get(partition % size);\n                } else {\n                    queue = queues.get(partition);\n                }\n\n                try {\n                    // 阿里云RocketMQ暂不支持批量发送消息，当canal.mq.flatMessage = true时，会发送失败\n                    SendResult sendResult = this.defaultMQProducer.send(messages, queue);\n                    if (logger.isDebugEnabled()) {\n                        logger.debug(\"Send Message Result: {}\", sendResult);\n                    }\n                } catch (Throwable e) {\n                    throw new RuntimeException(e);\n                }\n            }\n        }\n    }\n\n    @Override\n    public void stop() {\n        logger.info(\"## Stop RocketMQ producer##\");\n        this.defaultMQProducer.shutdown();\n        if (sendPartitionExecutor != null) {\n            sendPartitionExecutor.shutdownNow();\n        }\n\n        super.stop();\n    }\n\n    private Integer getTopicDynamicQueuesSize(Boolean enable, String topicName) {\n        if (enable != null && enable) {\n            topicName = this.defaultMQProducer.withNamespace(topicName);\n            DefaultMQProducerImpl innerProducer = this.defaultMQProducer.getDefaultMQProducerImpl();\n            TopicPublishInfo topicInfo = innerProducer.getTopicPublishInfoTable().get(topicName);\n            if (topicInfo == null) {\n                innerProducer.getMqClientFactory().updateTopicRouteInfoFromNameServer(topicName);\n            }\n            topicInfo = innerProducer.getTopicPublishInfoTable().get(topicName);\n            if (topicInfo == null) {\n                return null;\n            } else {\n                return topicInfo.getMessageQueueList().size();\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "connector/rocketmq-connector/src/main/resources/META-INF/canal/com.alibaba.otter.canal.connector.core.spi.CanalMQProducer",
    "content": "rocketmq=com.alibaba.otter.canal.connector.rocketmq.producer.CanalRocketMQProducer"
  },
  {
    "path": "connector/rocketmq-connector/src/main/resources/META-INF/canal/com.alibaba.otter.canal.connector.core.spi.CanalMsgConsumer",
    "content": "rocketmq=com.alibaba.otter.canal.connector.rocketmq.consumer.CanalRocketMQConsumer"
  },
  {
    "path": "connector/tcp-connector/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>canal.connector</artifactId>\n        <groupId>com.alibaba.otter</groupId>\n        <version>1.1.9-SNAPSHOT</version>\n        <relativePath>../pom.xml</relativePath>\n    </parent>\n\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>com.alibaba.otter</groupId>\n    <artifactId>connector.tcp</artifactId>\n    <packaging>jar</packaging>\n    <name>canal connector tcp module for otter ${project.version}</name>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>connector.core</artifactId>\n            <version>${project.version}</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>canal.protocol</artifactId>\n            <version>${project.version}</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>canal.client</artifactId>\n            <version>${project.version}</version>\n            <exclusions>\n                <exclusion>\n                    <groupId>com.google.protobuf</groupId>\n                    <artifactId>protobuf-java</artifactId>\n                </exclusion>\n                <exclusion>\n                    <groupId>org.springframework</groupId>\n                    <artifactId>spring-orm</artifactId>\n                </exclusion>\n                <exclusion>\n                    <groupId>org.springframework</groupId>\n                    <artifactId>spring-jdbc</artifactId>\n                </exclusion>\n                <exclusion>\n                    <groupId>org.springframework</groupId>\n                    <artifactId>spring-aop</artifactId>\n                </exclusion>\n                <exclusion>\n                    <groupId>org.springframework</groupId>\n                    <artifactId>spring-core</artifactId>\n                </exclusion>\n                <exclusion>\n                    <groupId>org.springframework</groupId>\n                    <artifactId>spring-context</artifactId>\n                </exclusion>\n                <exclusion>\n                    <groupId>org.apache.rocketmq</groupId>\n                    <artifactId>rocketmq-client</artifactId>\n                </exclusion>\n                <exclusion>\n                    <groupId>com.aliyun.openservices</groupId>\n                    <artifactId>aliware-apache-rocketmq-cloud</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-assembly-plugin</artifactId>\n                <version>2.4</version>\n                <configuration>\n                    <descriptorRefs>\n                        <descriptorRef>jar-with-dependencies</descriptorRef>\n                    </descriptorRefs>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>make-assembly</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>single</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-antrun-plugin</artifactId>\n                <version>1.8</version>\n                <executions>\n                    <execution>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>run</goal>\n                        </goals>\n                        <configuration>\n                            <tasks>\n                                <copy todir=\"${project.basedir}/../../client-adapter/launcher/target/canal-adapter/plugin\" overwrite=\"true\">\n                                    <fileset dir=\"${project.basedir}/target\" erroronmissingdir=\"true\">\n                                        <include name=\"connector.tcp-${project.version}-jar-with-dependencies.jar\" />\n                                    </fileset>\n                                </copy>\n                            </tasks>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>"
  },
  {
    "path": "connector/tcp-connector/src/main/java/com/alibaba/otter/canal/connector/tcp/config/TCPConstants.java",
    "content": "package com.alibaba.otter.canal.connector.tcp.config;\n\npublic class TCPConstants {\n\n    public static final String ROOT                 = \"canal\";\n\n    public static final String CANAL_TCP_HOST       = ROOT + \".\" + \"tcp.server.host\";\n    public static final String CANAL_TCP_ZK_HOSTS   = ROOT + \".\" + \"tcp.zookeeper.hosts\";\n    public static final String CANAL_TCP_USERNAME   = ROOT + \".\" + \"tcp.username\";\n    public static final String CANAL_TCP_PASSWORD   = ROOT + \".\" + \"tcp.password\";\n    public static final String CANAL_TCP_BATCH_SIZE = ROOT + \".\" + \"tcp.batch.size\";\n}\n"
  },
  {
    "path": "connector/tcp-connector/src/main/java/com/alibaba/otter/canal/connector/tcp/consumer/CanalTCPConsumer.java",
    "content": "package com.alibaba.otter.canal.connector.tcp.consumer;\n\nimport java.net.InetSocketAddress;\nimport java.net.SocketAddress;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.concurrent.TimeUnit;\n\nimport com.alibaba.otter.canal.common.utils.AddressUtils;\nimport org.apache.commons.lang.StringUtils;\n\nimport com.alibaba.otter.canal.client.CanalConnector;\nimport com.alibaba.otter.canal.client.impl.ClusterCanalConnector;\nimport com.alibaba.otter.canal.client.impl.ClusterNodeAccessStrategy;\nimport com.alibaba.otter.canal.client.impl.SimpleCanalConnector;\nimport com.alibaba.otter.canal.common.zookeeper.ZkClientx;\nimport com.alibaba.otter.canal.connector.core.consumer.CommonMessage;\nimport com.alibaba.otter.canal.connector.core.spi.CanalMsgConsumer;\nimport com.alibaba.otter.canal.connector.core.spi.SPI;\nimport com.alibaba.otter.canal.connector.core.util.MessageUtil;\nimport com.alibaba.otter.canal.connector.tcp.config.TCPConstants;\nimport com.alibaba.otter.canal.protocol.Message;\n\n/**\n * TCP 消费者连接器, 一个destination对应一个SPI实例\n *\n * @author rewerma 2020-01-30\n * @author XuDaojie\n * @version 1.1.5\n * @since 1.1.5\n */\n@SPI(\"tcp\")\npublic class CanalTCPConsumer implements CanalMsgConsumer {\n\n    private Long           currentBatchId = null;\n    private CanalConnector canalConnector;\n    private int            batchSize      = 500;\n\n    @Override\n    public void init(Properties properties, String destination, String groupId) {\n        // load config\n        String host = properties.getProperty(TCPConstants.CANAL_TCP_HOST);\n        String username = properties.getProperty(TCPConstants.CANAL_TCP_USERNAME);\n        String password = properties.getProperty(TCPConstants.CANAL_TCP_PASSWORD);\n        String zkHosts = properties.getProperty(TCPConstants.CANAL_TCP_ZK_HOSTS);\n        String batchSizePro = properties.getProperty(TCPConstants.CANAL_TCP_BATCH_SIZE);\n        if (batchSizePro != null) {\n            batchSize = Integer.parseInt(batchSizePro);\n        }\n        if (StringUtils.isNotBlank(host)) {\n            String[] ipPort =  AddressUtils.splitIPAndPort(host);\n            SocketAddress sa = new InetSocketAddress(ipPort[0], Integer.parseInt(ipPort[1]));\n            this.canalConnector = new SimpleCanalConnector(sa, username, password, destination);\n        } else {\n            this.canalConnector = new ClusterCanalConnector(username,\n                password,\n                destination,\n                new ClusterNodeAccessStrategy(destination, ZkClientx.getZkClient(zkHosts)));\n        }\n    }\n\n    @Override\n    public void connect() {\n        canalConnector.connect();\n        canalConnector.subscribe();\n    }\n\n    @Override\n    public List<CommonMessage> getMessage(Long timeout, TimeUnit unit) {\n        try {\n            Message message = canalConnector.getWithoutAck(batchSize, timeout, unit);\n            long batchId = message.getId();\n            currentBatchId = batchId;\n            int size = message.getEntries().size();\n            if (batchId == -1 || size == 0) {\n                return null;\n            } else {\n                return MessageUtil.convert(message);\n            }\n        } catch (Throwable e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    @Override\n    public void rollback() {\n        if (currentBatchId != null && currentBatchId != -1) {\n            canalConnector.rollback(currentBatchId);\n            currentBatchId = null;\n        }\n    }\n\n    @Override\n    public void ack() {\n        if (currentBatchId != null) {\n            canalConnector.ack(currentBatchId);\n            currentBatchId = null;\n        }\n    }\n\n    @Override\n    public void disconnect() {\n        // tcp模式下，因为是单tcp消费，避免adapter异常断开时直接unsubscribe\n        // unsubscribe发送给canal-server会导致清理cursor位点,如果此时canal-server出现重启,就会丢失binlog数据\n        // canalConnector.unsubscribe();\n        canalConnector.disconnect();\n    }\n}\n"
  },
  {
    "path": "connector/tcp-connector/src/main/resources/META-INF/canal/com.alibaba.otter.canal.connector.core.spi.CanalMsgConsumer",
    "content": "tcp=com.alibaba.otter.canal.connector.tcp.consumer.CanalTCPConsumer"
  },
  {
    "path": "dbsync/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>com.alibaba.otter</groupId>\n\t\t<artifactId>canal</artifactId>\n\t\t<version>1.1.9-SNAPSHOT</version>\n\t\t<relativePath>../pom.xml</relativePath>\n\t</parent>\n\t<groupId>com.alibaba.otter</groupId>\n\t<artifactId>canal.parse.dbsync</artifactId>\n\t<packaging>jar</packaging>\n\t<name>canal dbsync module for otter ${project.version}</name>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.parse.driver</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<!-- log -->\n\t\t<dependency>\n\t\t\t<groupId>ch.qos.logback</groupId>\n\t\t\t<artifactId>logback-core</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>ch.qos.logback</groupId>\n\t\t\t<artifactId>logback-classic</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>jcl-over-slf4j</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.commons</groupId>\n\t\t\t<artifactId>commons-compress</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.github.luben</groupId>\n\t\t\t<artifactId>zstd-jni</artifactId>\n\t\t</dependency>\n\t\t<!-- test dependency -->\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n        <dependency>\n            <groupId>org.powermock</groupId>\n            <artifactId>powermock-api-mockito</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.powermock</groupId>\n            <artifactId>powermock-module-junit4</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.mockito</groupId>\n            <artifactId>mockito-all</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.diffblue</groupId>\n            <artifactId>deeptestutils</artifactId>\n            <scope>test</scope>\n        </dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/CharsetConversion.java",
    "content": "package com.taobao.tddl.dbsync.binlog;\r\n\r\nimport java.nio.charset.Charset;\r\n\r\nimport org.apache.commons.logging.Log;\r\nimport org.apache.commons.logging.LogFactory;\r\n\r\n/**\r\n * An utility class implements MySQL/Java charsets conversion. you can see\r\n * com.mysql.jdbc.CharsetMapping.\r\n * \r\n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\r\n */\r\npublic final class CharsetConversion {\r\n\r\n    static final Log logger = LogFactory.getLog(CharsetConversion.class);\r\n\r\n    static final class Entry {\r\n\r\n        protected final int    charsetId;\r\n        protected final String mysqlCharset;\r\n        protected final String mysqlCollation;\r\n        protected final String javaCharset;\r\n        protected final Charset charset;\r\n\r\n        Entry(final int id, String mysqlCharset, // NL\r\n              String mysqlCollation, String javaCharset){\r\n            this.charsetId = id;\r\n            this.mysqlCharset = mysqlCharset;\r\n            this.mysqlCollation = mysqlCollation;\r\n            this.javaCharset = javaCharset;\r\n            this.charset = Charset.isSupported(javaCharset) ? Charset.forName(javaCharset) : null;\r\n        }\r\n    }\r\n\r\n    // Character set data used in lookups. The array will be sparse.\r\n    static final Entry[] entries = new Entry[2048];\r\n\r\n    static Entry getEntry(final int id) {\r\n        if (id >= 0 && id < entries.length) {\r\n            return entries[id];\r\n        } else {\r\n            throw new IllegalArgumentException(\"Invalid charset id: \" + id);\r\n        }\r\n    }\r\n\r\n    // Loads character set information.\r\n    static void putEntry(final int charsetId, String mysqlCharset, String mysqlCollation, String javaCharset) {\r\n        entries[charsetId] = new Entry(charsetId, mysqlCharset, // NL\r\n            mysqlCollation,\r\n            javaCharset);\r\n    }\r\n\r\n    // Loads character set information.\r\n    @Deprecated\r\n    static void putEntry(final int charsetId, String mysqlCharset, String mysqlCollation) {\r\n        entries[charsetId] = new Entry(charsetId, mysqlCharset, // NL\r\n            mysqlCollation, /* Unknown java charset */\r\n            null);\r\n    }\r\n\r\n    // Load character set data statically.\r\n    static {\r\n        putEntry(1, \"big5\", \"big5_chinese_ci\", \"Big5\");\r\n        putEntry(2, \"latin2\", \"latin2_czech_cs\", \"ISO8859_2\");\r\n        putEntry(3, \"dec8\", \"dec8_swedish_ci\", \"ISO8859_1\");\r\n        putEntry(4, \"cp850\", \"cp850_general_ci\", \"Cp850\");\r\n        putEntry(5, \"latin1\", \"latin1_german1_ci\", \"ISO8859_1\");\r\n        putEntry(6, \"hp8\", \"hp8_english_ci\", \"ISO8859_1\");\r\n        putEntry(7, \"koi8r\", \"koi8r_general_ci\", \"KOI8_R\");\r\n        putEntry(8, \"latin1\", \"latin1_swedish_ci\", \"ISO8859_1\");\r\n        putEntry(9, \"latin2\", \"latin2_general_ci\", \"ISO8859_2\");\r\n        putEntry(10, \"swe7\", \"swe7_swedish_ci\", \"ISO8859_1\");\r\n        putEntry(11, \"ascii\", \"ascii_general_ci\", \"US-ASCII\");\r\n        putEntry(12, \"ujis\", \"ujis_japanese_ci\", \"EUC_JP\");\r\n        putEntry(13, \"sjis\", \"sjis_japanese_ci\", \"SJIS\");\r\n        putEntry(14, \"cp1251\", \"cp1251_bulgarian_ci\", \"Cp1251\");\r\n        putEntry(15, \"latin1\", \"latin1_danish_ci\", \"ISO8859_1\");\r\n        putEntry(16, \"hebrew\", \"hebrew_general_ci\", \"ISO8859_8\");\r\n        putEntry(17, \"filename\", \"filename\", \"ISO8859_1\");\r\n        putEntry(18, \"tis620\", \"tis620_thai_ci\", \"TIS620\");\r\n        putEntry(19, \"euckr\", \"euckr_korean_ci\", \"EUC_KR\");\r\n        putEntry(20, \"latin7\", \"latin7_estonian_cs\", \"ISO8859_7\");\r\n        putEntry(21, \"latin2\", \"latin2_hungarian_ci\", \"ISO8859_2\");\r\n        putEntry(22, \"koi8u\", \"koi8u_general_ci\", \"KOI8_U\");\r\n        putEntry(23, \"cp1251\", \"cp1251_ukrainian_ci\", \"Cp1251\");\r\n        putEntry(24, \"gb2312\", \"gb2312_chinese_ci\", \"EUC_CN\");\r\n        putEntry(25, \"greek\", \"greek_general_ci\", \"ISO8859_7\");\r\n        putEntry(26, \"cp1250\", \"cp1250_general_ci\", \"Cp1250\");\r\n        putEntry(27, \"latin2\", \"latin2_croatian_ci\", \"ISO8859_2\");\r\n        putEntry(28, \"gbk\", \"gbk_chinese_ci\", \"GBK\");\r\n        putEntry(29, \"cp1257\", \"cp1257_lithuanian_ci\", \"Cp1257\");\r\n        putEntry(30, \"latin5\", \"latin5_turkish_ci\", \"ISO8859_5\");\r\n        putEntry(31, \"latin1\", \"latin1_german2_ci\", \"ISO8859_1\");\r\n        putEntry(32, \"armscii8\", \"armscii8_general_ci\", \"ISO8859_1\");\r\n        putEntry(33, \"utf8\", \"utf8_general_ci\", \"UTF-8\");\r\n        putEntry(34, \"cp1250\", \"cp1250_czech_cs\", \"Cp1250\");\r\n        putEntry(35, \"ucs2\", \"ucs2_general_ci\", \"UnicodeBig\");\r\n        putEntry(36, \"cp866\", \"cp866_general_ci\", \"Cp866\");\r\n        putEntry(37, \"keybcs2\", \"keybcs2_general_ci\", \"Cp852\");\r\n        putEntry(38, \"macce\", \"macce_general_ci\", \"MacCentralEurope\");\r\n        putEntry(39, \"macroman\", \"macroman_general_ci\", \"MacRoman\");\r\n        putEntry(40, \"cp852\", \"cp852_general_ci\", \"Cp852\");\r\n        putEntry(41, \"latin7\", \"latin7_general_ci\", \"ISO8859_7\");\r\n        putEntry(42, \"latin7\", \"latin7_general_cs\", \"ISO8859_7\");\r\n        putEntry(43, \"macce\", \"macce_bin\", \"MacCentralEurope\");\r\n        putEntry(44, \"cp1250\", \"cp1250_croatian_ci\", \"Cp1250\");\r\n        putEntry(45, \"utf8mb4\", \"utf8mb4_general_ci\", \"UTF-8\");\r\n        putEntry(46, \"utf8mb4\", \"utf8mb4_bin\", \"UTF-8\");\r\n        putEntry(47, \"latin1\", \"latin1_bin\", \"ISO8859_1\");\r\n        putEntry(48, \"latin1\", \"latin1_general_ci\", \"ISO8859_1\");\r\n        putEntry(49, \"latin1\", \"latin1_general_cs\", \"ISO8859_1\");\r\n        putEntry(50, \"cp1251\", \"cp1251_bin\", \"Cp1251\");\r\n        putEntry(51, \"cp1251\", \"cp1251_general_ci\", \"Cp1251\");\r\n        putEntry(52, \"cp1251\", \"cp1251_general_cs\", \"Cp1251\");\r\n        putEntry(53, \"macroman\", \"macroman_bin\", \"MacRoman\");\r\n        putEntry(54, \"utf16\", \"utf16_general_ci\", \"UTF-16\");\r\n        putEntry(55, \"utf16\", \"utf16_bin\", \"UTF-16\");\r\n        putEntry(57, \"cp1256\", \"cp1256_general_ci\", \"Cp1256\");\r\n        putEntry(58, \"cp1257\", \"cp1257_bin\", \"Cp1257\");\r\n        putEntry(59, \"cp1257\", \"cp1257_general_ci\", \"Cp1257\");\r\n        putEntry(60, \"utf32\", \"utf32_general_ci\", \"UTF-32\");\r\n        putEntry(61, \"utf32\", \"utf32_bin\", \"UTF-32\");\r\n        putEntry(63, \"binary\", \"binary\", \"US-ASCII\");\r\n        putEntry(64, \"armscii8\", \"armscii8_bin\", \"ISO8859_2\");\r\n        putEntry(65, \"ascii\", \"ascii_bin\", \"US-ASCII\");\r\n        putEntry(66, \"cp1250\", \"cp1250_bin\", \"Cp1250\");\r\n        putEntry(67, \"cp1256\", \"cp1256_bin\", \"Cp1256\");\r\n        putEntry(68, \"cp866\", \"cp866_bin\", \"Cp866\");\r\n        putEntry(69, \"dec8\", \"dec8_bin\", \"US-ASCII\");\r\n        putEntry(70, \"greek\", \"greek_bin\", \"ISO8859_7\");\r\n        putEntry(71, \"hebrew\", \"hebrew_bin\", \"ISO8859_8\");\r\n        putEntry(72, \"hp8\", \"hp8_bin\", \"US-ASCII\");\r\n        putEntry(73, \"keybcs2\", \"keybcs2_bin\", \"Cp852\");\r\n        putEntry(74, \"koi8r\", \"koi8r_bin\", \"KOI8_R\");\r\n        putEntry(75, \"koi8u\", \"koi8u_bin\", \"KOI8_U\");\r\n        putEntry(77, \"latin2\", \"latin2_bin\", \"ISO8859_2\");\r\n        putEntry(78, \"latin5\", \"latin5_bin\", \"ISO8859_5\");\r\n        putEntry(79, \"latin7\", \"latin7_bin\", \"ISO8859_7\");\r\n        putEntry(80, \"cp850\", \"cp850_bin\", \"Cp850\");\r\n        putEntry(81, \"cp852\", \"cp852_bin\", \"Cp852\");\r\n        putEntry(82, \"swe7\", \"swe7_bin\", \"ISO8859_1\");\r\n        putEntry(83, \"utf8\", \"utf8_bin\", \"UTF-8\");\r\n        putEntry(84, \"big5\", \"big5_bin\", \"Big5\");\r\n        putEntry(85, \"euckr\", \"euckr_bin\", \"EUC_KR\");\r\n        putEntry(86, \"gb2312\", \"gb2312_bin\", \"EUC_CN\");\r\n        putEntry(87, \"gbk\", \"gbk_bin\", \"GBK\");\r\n        putEntry(88, \"sjis\", \"sjis_bin\", \"SJIS\");\r\n        putEntry(89, \"tis620\", \"tis620_bin\", \"TIS620\");\r\n        putEntry(90, \"ucs2\", \"ucs2_bin\", \"UnicodeBig\");\r\n        putEntry(91, \"ujis\", \"ujis_bin\", \"EUC_JP\");\r\n        putEntry(92, \"geostd8\", \"geostd8_general_ci\", \"US-ASCII\");\r\n        putEntry(93, \"geostd8\", \"geostd8_bin\", \"US-ASCII\");\r\n        putEntry(94, \"latin1\", \"latin1_spanish_ci\", \"ISO8859_1\");\r\n        putEntry(95, \"cp932\", \"cp932_japanese_ci\", \"Shift_JIS\");\r\n        putEntry(96, \"cp932\", \"cp932_bin\", \"Shift_JIS\");\r\n        putEntry(97, \"eucjpms\", \"eucjpms_japanese_ci\", \"EUC_JP\");\r\n        putEntry(98, \"eucjpms\", \"eucjpms_bin\", \"EUC_JP\");\r\n        putEntry(99, \"cp1250\", \"cp1250_polish_ci\", \"Cp1250\");\r\n\r\n        putEntry(101, \"utf16\", \"utf16_unicode_ci\", \"UTF-16\");\r\n        putEntry(102, \"utf16\", \"utf16_icelandic_ci\", \"UTF-16\");\r\n        putEntry(103, \"utf16\", \"utf16_latvian_ci\", \"UTF-16\");\r\n        putEntry(104, \"utf16\", \"utf16_romanian_ci\", \"UTF-16\");\r\n        putEntry(105, \"utf16\", \"utf16_slovenian_ci\", \"UTF-16\");\r\n        putEntry(106, \"utf16\", \"utf16_polish_ci\", \"UTF-16\");\r\n        putEntry(107, \"utf16\", \"utf16_estonian_ci\", \"UTF-16\");\r\n        putEntry(108, \"utf16\", \"utf16_spanish_ci\", \"UTF-16\");\r\n        putEntry(109, \"utf16\", \"utf16_swedish_ci\", \"UTF-16\");\r\n        putEntry(110, \"utf16\", \"utf16_turkish_ci\", \"UTF-16\");\r\n        putEntry(111, \"utf16\", \"utf16_czech_ci\", \"UTF-16\");\r\n        putEntry(112, \"utf16\", \"utf16_danish_ci\", \"UTF-16\");\r\n        putEntry(113, \"utf16\", \"utf16_lithuanian_ci\", \"UTF-16\");\r\n        putEntry(114, \"utf16\", \"utf16_slovak_ci\", \"UTF-16\");\r\n        putEntry(115, \"utf16\", \"utf16_spanish2_ci\", \"UTF-16\");\r\n        putEntry(116, \"utf16\", \"utf16_roman_ci\", \"UTF-16\");\r\n        putEntry(117, \"utf16\", \"utf16_persian_ci\", \"UTF-16\");\r\n        putEntry(118, \"utf16\", \"utf16_esperanto_ci\", \"UTF-16\");\r\n        putEntry(119, \"utf16\", \"utf16_hungarian_ci\", \"UTF-16\");\r\n        putEntry(120, \"utf16\", \"utf16_sinhala_ci\", \"UTF-16\");\r\n\r\n        putEntry(128, \"ucs2\", \"ucs2_unicode_ci\", \"UnicodeBig\");\r\n        putEntry(129, \"ucs2\", \"ucs2_icelandic_ci\", \"UnicodeBig\");\r\n        putEntry(130, \"ucs2\", \"ucs2_latvian_ci\", \"UnicodeBig\");\r\n        putEntry(131, \"ucs2\", \"ucs2_romanian_ci\", \"UnicodeBig\");\r\n        putEntry(132, \"ucs2\", \"ucs2_slovenian_ci\", \"UnicodeBig\");\r\n        putEntry(133, \"ucs2\", \"ucs2_polish_ci\", \"UnicodeBig\");\r\n        putEntry(134, \"ucs2\", \"ucs2_estonian_ci\", \"UnicodeBig\");\r\n        putEntry(135, \"ucs2\", \"ucs2_spanish_ci\", \"UnicodeBig\");\r\n        putEntry(136, \"ucs2\", \"ucs2_swedish_ci\", \"UnicodeBig\");\r\n        putEntry(137, \"ucs2\", \"ucs2_turkish_ci\", \"UnicodeBig\");\r\n        putEntry(138, \"ucs2\", \"ucs2_czech_ci\", \"UnicodeBig\");\r\n        putEntry(139, \"ucs2\", \"ucs2_danish_ci\", \"UnicodeBig\");\r\n        putEntry(140, \"ucs2\", \"ucs2_lithuanian_ci\", \"UnicodeBig\");\r\n        putEntry(141, \"ucs2\", \"ucs2_slovak_ci\", \"UnicodeBig\");\r\n        putEntry(142, \"ucs2\", \"ucs2_spanish2_ci\", \"UnicodeBig\");\r\n        putEntry(143, \"ucs2\", \"ucs2_roman_ci\", \"UnicodeBig\");\r\n        putEntry(144, \"ucs2\", \"ucs2_persian_ci\", \"UnicodeBig\");\r\n        putEntry(145, \"ucs2\", \"ucs2_esperanto_ci\", \"UnicodeBig\");\r\n        putEntry(146, \"ucs2\", \"ucs2_hungarian_ci\", \"UnicodeBig\");\r\n        putEntry(147, \"ucs2\", \"ucs2_sinhala_ci\", \"UnicodeBig\");\r\n\r\n        putEntry(160, \"utf32\", \"utf32_unicode_ci\", \"UTF-32\");\r\n        putEntry(161, \"utf32\", \"utf32_icelandic_ci\", \"UTF-32\");\r\n        putEntry(162, \"utf32\", \"utf32_latvian_ci\", \"UTF-32\");\r\n        putEntry(163, \"utf32\", \"utf32_romanian_ci\", \"UTF-32\");\r\n        putEntry(164, \"utf32\", \"utf32_slovenian_ci\", \"UTF-32\");\r\n        putEntry(165, \"utf32\", \"utf32_polish_ci\", \"UTF-32\");\r\n        putEntry(166, \"utf32\", \"utf32_estonian_ci\", \"UTF-32\");\r\n        putEntry(167, \"utf32\", \"utf32_spanish_ci\", \"UTF-32\");\r\n        putEntry(168, \"utf32\", \"utf32_swedish_ci\", \"UTF-32\");\r\n        putEntry(169, \"utf32\", \"utf32_turkish_ci\", \"UTF-32\");\r\n        putEntry(170, \"utf32\", \"utf32_czech_ci\", \"UTF-32\");\r\n        putEntry(171, \"utf32\", \"utf32_danish_ci\", \"UTF-32\");\r\n        putEntry(172, \"utf32\", \"utf32_lithuanian_ci\", \"UTF-32\");\r\n        putEntry(173, \"utf32\", \"utf32_slovak_ci\", \"UTF-32\");\r\n        putEntry(174, \"utf32\", \"utf32_spanish2_ci\", \"UTF-32\");\r\n        putEntry(175, \"utf32\", \"utf32_roman_ci\", \"UTF-32\");\r\n        putEntry(176, \"utf32\", \"utf32_persian_ci\", \"UTF-32\");\r\n        putEntry(177, \"utf32\", \"utf32_esperanto_ci\", \"UTF-32\");\r\n        putEntry(178, \"utf32\", \"utf32_hungarian_ci\", \"UTF-32\");\r\n        putEntry(179, \"utf32\", \"utf32_sinhala_ci\", \"UTF-32\");\r\n\r\n        putEntry(192, \"utf8\", \"utf8_unicode_ci\", \"UTF-8\");\r\n        putEntry(193, \"utf8\", \"utf8_icelandic_ci\", \"UTF-8\");\r\n        putEntry(194, \"utf8\", \"utf8_latvian_ci\", \"UTF-8\");\r\n        putEntry(195, \"utf8\", \"utf8_romanian_ci\", \"UTF-8\");\r\n        putEntry(196, \"utf8\", \"utf8_slovenian_ci\", \"UTF-8\");\r\n        putEntry(197, \"utf8\", \"utf8_polish_ci\", \"UTF-8\");\r\n        putEntry(198, \"utf8\", \"utf8_estonian_ci\", \"UTF-8\");\r\n        putEntry(199, \"utf8\", \"utf8_spanish_ci\", \"UTF-8\");\r\n        putEntry(200, \"utf8\", \"utf8_swedish_ci\", \"UTF-8\");\r\n        putEntry(201, \"utf8\", \"utf8_turkish_ci\", \"UTF-8\");\r\n        putEntry(202, \"utf8\", \"utf8_czech_ci\", \"UTF-8\");\r\n        putEntry(203, \"utf8\", \"utf8_danish_ci\", \"UTF-8\");\r\n        putEntry(204, \"utf8\", \"utf8_lithuanian_ci\", \"UTF-8\");\r\n        putEntry(205, \"utf8\", \"utf8_slovak_ci\", \"UTF-8\");\r\n        putEntry(206, \"utf8\", \"utf8_spanish2_ci\", \"UTF-8\");\r\n        putEntry(207, \"utf8\", \"utf8_roman_ci\", \"UTF-8\");\r\n        putEntry(208, \"utf8\", \"utf8_persian_ci\", \"UTF-8\");\r\n        putEntry(209, \"utf8\", \"utf8_esperanto_ci\", \"UTF-8\");\r\n        putEntry(210, \"utf8\", \"utf8_hungarian_ci\", \"UTF-8\");\r\n        putEntry(211, \"utf8\", \"utf8_sinhala_ci\", \"UTF-8\");\r\n\r\n        putEntry(224, \"utf8mb4\", \"utf8mb4_unicode_ci\", \"UTF-8\");\r\n        putEntry(225, \"utf8mb4\", \"utf8mb4_icelandic_ci\", \"UTF-8\");\r\n        putEntry(226, \"utf8mb4\", \"utf8mb4_latvian_ci\", \"UTF-8\");\r\n        putEntry(227, \"utf8mb4\", \"utf8mb4_romanian_ci\", \"UTF-8\");\r\n        putEntry(228, \"utf8mb4\", \"utf8mb4_slovenian_ci\", \"UTF-8\");\r\n        putEntry(229, \"utf8mb4\", \"utf8mb4_polish_ci\", \"UTF-8\");\r\n        putEntry(230, \"utf8mb4\", \"utf8mb4_estonian_ci\", \"UTF-8\");\r\n        putEntry(231, \"utf8mb4\", \"utf8mb4_spanish_ci\", \"UTF-8\");\r\n        putEntry(232, \"utf8mb4\", \"utf8mb4_swedish_ci\", \"UTF-8\");\r\n        putEntry(233, \"utf8mb4\", \"utf8mb4_turkish_ci\", \"UTF-8\");\r\n        putEntry(234, \"utf8mb4\", \"utf8mb4_czech_ci\", \"UTF-8\");\r\n        putEntry(235, \"utf8mb4\", \"utf8mb4_danish_ci\", \"UTF-8\");\r\n        putEntry(236, \"utf8mb4\", \"utf8mb4_lithuanian_ci\", \"UTF-8\");\r\n        putEntry(237, \"utf8mb4\", \"utf8mb4_slovak_ci\", \"UTF-8\");\r\n        putEntry(238, \"utf8mb4\", \"utf8mb4_spanish2_ci\", \"UTF-8\");\r\n        putEntry(239, \"utf8mb4\", \"utf8mb4_roman_ci\", \"UTF-8\");\r\n        putEntry(240, \"utf8mb4\", \"utf8mb4_persian_ci\", \"UTF-8\");\r\n        putEntry(241, \"utf8mb4\", \"utf8mb4_esperanto_ci\", \"UTF-8\");\r\n        putEntry(242, \"utf8mb4\", \"utf8mb4_hungarian_ci\", \"UTF-8\");\r\n        putEntry(243, \"utf8mb4\", \"utf8mb4_sinhala_ci\", \"UTF-8\");\r\n        putEntry(244, \"utf8mb4\", \"utf8mb4_german2_ci\", \"UTF-8\");\r\n        putEntry(245, \"utf8mb4\", \"utf8mb4_croatian_ci\", \"UTF-8\");\r\n        putEntry(246, \"utf8mb4\", \"utf8mb4_unicode_520_ci\", \"UTF-8\");\r\n        putEntry(247, \"utf8mb4\", \"utf8mb4_vietnamese_ci\", \"UTF-8\");\r\n        putEntry(248, \"gb18030\", \"gb18030_chinese_ci\", \"GB18030\");\r\n        putEntry(249, \"gb18030\", \"gb18030_bin\", \"GB18030\");\r\n        putEntry(250, \"gb18030\", \"gb18030_unicode_520_ci\", \"GB18030\");\r\n\r\n        putEntry(254, \"utf8\", \"utf8_general_cs\", \"UTF-8\");\r\n        putEntry(255, \"utf8mb4\", \"utf8mb4_0900_ai_ci\", \"UTF-8\");\r\n        putEntry(256, \"utf8mb4\", \"utf8mb4_de_pb_0900_ai_ci\", \"UTF-8\");\r\n        putEntry(257, \"utf8mb4\", \"utf8mb4_is_0900_ai_ci\", \"UTF-8\");\r\n        putEntry(258, \"utf8mb4\", \"utf8mb4_lv_0900_ai_ci\", \"UTF-8\");\r\n        putEntry(259, \"utf8mb4\", \"utf8mb4_ro_0900_ai_ci\", \"UTF-8\");\r\n        putEntry(260, \"utf8mb4\", \"utf8mb4_sl_0900_ai_ci\", \"UTF-8\");\r\n        putEntry(261, \"utf8mb4\", \"utf8mb4_pl_0900_ai_ci\", \"UTF-8\");\r\n        putEntry(262, \"utf8mb4\", \"utf8mb4_et_0900_ai_ci\", \"UTF-8\");\r\n        putEntry(263, \"utf8mb4\", \"utf8mb4_es_0900_ai_ci\", \"UTF-8\");\r\n        putEntry(264, \"utf8mb4\", \"utf8mb4_sv_0900_ai_ci\", \"UTF-8\");\r\n        putEntry(265, \"utf8mb4\", \"utf8mb4_tr_0900_ai_ci\", \"UTF-8\");\r\n        putEntry(266, \"utf8mb4\", \"utf8mb4_cs_0900_ai_ci\", \"UTF-8\");\r\n        putEntry(267, \"utf8mb4\", \"utf8mb4_da_0900_ai_ci\", \"UTF-8\");\r\n        putEntry(268, \"utf8mb4\", \"utf8mb4_lt_0900_ai_ci\", \"UTF-8\");\r\n        putEntry(269, \"utf8mb4\", \"utf8mb4_sk_0900_ai_ci\", \"UTF-8\");\r\n        putEntry(270, \"utf8mb4\", \"utf8mb4_es_trad_0900_ai_ci\", \"UTF-8\");\r\n        putEntry(271, \"utf8mb4\", \"utf8mb4_la_0900_ai_ci\", \"UTF-8\");\r\n\r\n        putEntry(273, \"utf8mb4\", \"utf8mb4_eo_0900_ai_ci\", \"UTF-8\");\r\n        putEntry(274, \"utf8mb4\", \"utf8mb4_hu_0900_ai_ci\", \"UTF-8\");\r\n        putEntry(275, \"utf8mb4\", \"utf8mb4_hr_0900_ai_ci\", \"UTF-8\");\r\n\r\n        putEntry(277, \"utf8mb4\", \"utf8mb4_vi_0900_ai_ci\", \"UTF-8\");\r\n        putEntry(278, \"utf8mb4\", \"utf8mb4_0900_as_cs\", \"UTF-8\");\r\n        putEntry(279, \"utf8mb4\", \"utf8mb4_de_pb_0900_as_cs\", \"UTF-8\");\r\n        putEntry(280, \"utf8mb4\", \"utf8mb4_is_0900_as_cs\", \"UTF-8\");\r\n        putEntry(281, \"utf8mb4\", \"utf8mb4_lv_0900_as_cs\", \"UTF-8\");\r\n        putEntry(282, \"utf8mb4\", \"utf8mb4_ro_0900_as_cs\", \"UTF-8\");\r\n        putEntry(283, \"utf8mb4\", \"utf8mb4_sl_0900_as_cs\", \"UTF-8\");\r\n        putEntry(284, \"utf8mb4\", \"utf8mb4_pl_0900_as_cs\", \"UTF-8\");\r\n        putEntry(285, \"utf8mb4\", \"utf8mb4_et_0900_as_cs\", \"UTF-8\");\r\n        putEntry(286, \"utf8mb4\", \"utf8mb4_es_0900_as_cs\", \"UTF-8\");\r\n        putEntry(287, \"utf8mb4\", \"utf8mb4_sv_0900_as_cs\", \"UTF-8\");\r\n        putEntry(288, \"utf8mb4\", \"utf8mb4_tr_0900_as_cs\", \"UTF-8\");\r\n        putEntry(289, \"utf8mb4\", \"utf8mb4_cs_0900_as_cs\", \"UTF-8\");\r\n        putEntry(290, \"utf8mb4\", \"utf8mb4_da_0900_as_cs\", \"UTF-8\");\r\n        putEntry(291, \"utf8mb4\", \"utf8mb4_lt_0900_as_cs\", \"UTF-8\");\r\n        putEntry(292, \"utf8mb4\", \"utf8mb4_sk_0900_as_cs\", \"UTF-8\");\r\n        putEntry(293, \"utf8mb4\", \"utf8mb4_es_trad_0900_as_cs\", \"UTF-8\");\r\n        putEntry(294, \"utf8mb4\", \"utf8mb4_la_0900_as_cs\", \"UTF-8\");\r\n\r\n        putEntry(296, \"utf8mb4\", \"utf8mb4_eo_0900_as_cs\", \"UTF-8\");\r\n        putEntry(297, \"utf8mb4\", \"utf8mb4_hu_0900_as_cs\", \"UTF-8\");\r\n        putEntry(298, \"utf8mb4\", \"utf8mb4_hr_0900_as_cs\", \"UTF-8\");\r\n\r\n        putEntry(300, \"utf8mb4\", \"utf8mb4_vi_0900_as_cs\", \"UTF-8\");\r\n        putEntry(303, \"utf8mb4\", \"utf8mb4_ja_0900_as_cs\", \"UTF-8\");\r\n        putEntry(304, \"utf8mb4\", \"utf8mb4_ja_0900_as_cs_ks\", \"UTF-8\");\r\n        putEntry(305, \"utf8mb4\", \"utf8mb4_0900_as_ci\", \"UTF-8\");\r\n        putEntry(306, \"utf8mb4\", \"utf8mb4_ru_0900_ai_ci\", \"UTF-8\");\r\n        putEntry(307, \"utf8mb4\", \"utf8mb4_ru_0900_as_cs\", \"UTF-8\");\r\n\r\n        putEntry(326, \"utf8mb4\", \"utf8mb4_test_ci\", \"UTF-8\");\r\n        putEntry(327, \"utf16\", \"utf16_test_ci\", \"UTF-16\");\r\n        putEntry(328, \"utf8mb4\", \"utf8mb4_test_400_ci\", \"UTF-8\");\r\n\r\n        putEntry(336, \"utf8\", \"utf8_bengali_standard_ci\", \"UTF-8\");\r\n        putEntry(337, \"utf8\", \"utf8_bengali_standard_ci\", \"UTF-8\");\r\n        putEntry(352, \"utf8\", \"utf8_phone_ci\", \"UTF-8\");\r\n        putEntry(353, \"utf8\", \"utf8_test_ci\", \"UTF-8\");\r\n        putEntry(354, \"utf8\", \"utf8_5624_1\", \"UTF-8\");\r\n        putEntry(355, \"utf8\", \"utf8_5624_2\", \"UTF-8\");\r\n        putEntry(356, \"utf8\", \"utf8_5624_3\", \"UTF-8\");\r\n        putEntry(357, \"utf8\", \"utf8_5624_4\", \"UTF-8\");\r\n        putEntry(358, \"ucs2\", \"ucs2_test_ci\", \"UnicodeBig\");\r\n        putEntry(359, \"ucs2\", \"ucs2_vn_ci\", \"UnicodeBig\");\r\n        putEntry(360, \"ucs2\", \"ucs2_5624_1\", \"UnicodeBig\");\r\n\r\n        putEntry(368, \"utf8\", \"utf8_5624_5\", \"UTF-8\");\r\n        putEntry(391, \"utf32\", \"utf32_test_ci\", \"UTF-32\");\r\n        putEntry(2047, \"utf8\", \"utf8_maxuserid_ci\", \"UTF-8\");\r\n    }\r\n\r\n    /**\r\n     * Return defined charset name for mysql.\r\n     */\r\n    public static String getCharset(final int id) {\r\n        Entry entry = getEntry(id);\r\n\r\n        if (entry != null) {\r\n            return entry.mysqlCharset;\r\n        } else {\r\n            logger.warn(\"Unexpect mysql charset: \" + id);\r\n            return null;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Return defined collaction name for mysql.\r\n     */\r\n    public static String getCollation(final int id) {\r\n        Entry entry = getEntry(id);\r\n\r\n        if (entry != null) {\r\n            return entry.mysqlCollation;\r\n        } else {\r\n            logger.warn(\"Unexpect mysql charset: \" + id);\r\n            return null;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Return converted charset name for java.\r\n     */\r\n    public static String getJavaCharset(final int id) {\r\n        Entry entry = getEntry(id);\r\n\r\n        if (entry != null) {\r\n            if (entry.javaCharset != null) {\r\n                return entry.javaCharset;\r\n            } else {\r\n                logger.warn(\"Unknown java charset for: id = \" + id + \", name = \" + entry.mysqlCharset + \", coll = \"\r\n                            + entry.mysqlCollation);\r\n                return null;\r\n            }\r\n        } else {\r\n            logger.warn(\"Unexpect mysql charset: \" + id);\r\n            return null;\r\n        }\r\n    }\r\n\r\n    public static Charset getNioCharset(final int id) {\r\n        Entry entry = getEntry(id);\r\n\r\n        if (entry != null) {\r\n            if (entry.charset != null) {\r\n                return entry.charset;\r\n            } else {\r\n                logger.warn(\"Unknown java charset for: id = \" + id + \", name = \" + entry.mysqlCharset + \", coll = \"\r\n                            + entry.mysqlCollation);\r\n                return null;\r\n            }\r\n        } else {\r\n            logger.warn(\"Unexpect mysql charset: \" + id);\r\n            return null;\r\n        }\r\n    }\r\n\r\n    public static void main(String[] args) {\r\n        for (int i = 0; i < entries.length; i++) {\r\n            Entry entry = entries[i];\r\n\r\n            System.out.print(i);\r\n            System.out.print(',');\r\n            System.out.print(' ');\r\n            if (entry != null) {\r\n                System.out.print(entry.mysqlCharset);\r\n                System.out.print(',');\r\n                System.out.print(' ');\r\n                System.out.print(entry.javaCharset);\r\n                if (entry.javaCharset != null) {\r\n                    System.out.print(',');\r\n                    System.out.print(' ');\r\n                    System.out.print(Charset.forName(entry.javaCharset).name());\r\n                }\r\n            } else {\r\n                System.out.print(\"null\");\r\n            }\r\n            System.out.println();\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/DirectLogFetcher.java",
    "content": "package com.taobao.tddl.dbsync.binlog;\r\n\r\nimport java.io.IOException;\r\nimport java.io.InputStream;\r\nimport java.io.InterruptedIOException;\r\nimport java.io.OutputStream;\r\nimport java.lang.reflect.Field;\r\nimport java.lang.reflect.InvocationTargetException;\r\nimport java.lang.reflect.Method;\r\nimport java.net.SocketTimeoutException;\r\nimport java.sql.Connection;\r\nimport java.sql.SQLException;\r\n\r\nimport org.apache.commons.logging.Log;\r\nimport org.apache.commons.logging.LogFactory;\r\n\r\n/**\r\n * TODO: Document It!!\r\n * \r\n * <pre>\r\n * DirectLogFetcher fetcher = new DirectLogFetcher();\r\n * fetcher.open(conn, file, 0, 13);\r\n * \r\n * while (fetcher.fetch()) {\r\n *     LogEvent event;\r\n *     do {\r\n *         event = decoder.decode(fetcher, context);\r\n * \r\n *         // process log event.\r\n *     } while (event != null);\r\n * }\r\n * // connection closed.\r\n * </pre>\r\n * \r\n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\r\n * @version 1.0\r\n */\r\npublic final class DirectLogFetcher extends LogFetcher {\r\n\r\n    protected static final Log logger                          = LogFactory.getLog(DirectLogFetcher.class);\r\n\r\n    /** Command to dump binlog */\r\n    public static final byte   COM_BINLOG_DUMP                 = 18;\r\n\r\n    /** Packet header sizes */\r\n    public static final int    NET_HEADER_SIZE                 = 4;\r\n    public static final int    SQLSTATE_LENGTH                 = 5;\r\n\r\n    /** Packet offsets */\r\n    public static final int    PACKET_LEN_OFFSET               = 0;\r\n    public static final int    PACKET_SEQ_OFFSET               = 3;\r\n\r\n    /** Maximum packet length */\r\n    public static final int    MAX_PACKET_LENGTH               = (256 * 256 * 256 - 1);\r\n\r\n    /** BINLOG_DUMP options */\r\n    public static final int    BINLOG_DUMP_NON_BLOCK           = 1;\r\n    public static final int    BINLOG_SEND_ANNOTATE_ROWS_EVENT = 2;\r\n\r\n    private Connection         conn;\r\n    private OutputStream       mysqlOutput;\r\n    private InputStream        mysqlInput;\r\n\r\n    public DirectLogFetcher(){\r\n        super(DEFAULT_INITIAL_CAPACITY, DEFAULT_GROWTH_FACTOR);\r\n    }\r\n\r\n    public DirectLogFetcher(final int initialCapacity){\r\n        super(initialCapacity, DEFAULT_GROWTH_FACTOR);\r\n    }\r\n\r\n    public DirectLogFetcher(final int initialCapacity, final float growthFactor){\r\n        super(initialCapacity, growthFactor);\r\n    }\r\n\r\n    private static final Object unwrapConnection(Object conn, Class<?> connClazz) throws IOException {\r\n        while (!connClazz.isInstance(conn)) {\r\n            try {\r\n                Class<?> connProxy = Class.forName(\"org.springframework.jdbc.datasource.ConnectionProxy\");\r\n                if (connProxy.isInstance(conn)) {\r\n                    conn = invokeMethod(conn, connProxy, \"getTargetConnection\");\r\n                    continue;\r\n                }\r\n            } catch (ClassNotFoundException e) {\r\n                // org.springframework.jdbc.datasource.ConnectionProxy not\r\n                // found.\r\n            }\r\n\r\n            try {\r\n                Class<?> connProxy = Class.forName(\"org.apache.commons.dbcp.DelegatingConnection\");\r\n                if (connProxy.isInstance(conn)) {\r\n                    conn = getDeclaredField(conn, connProxy, \"_conn\");\r\n                    continue;\r\n                }\r\n            } catch (ClassNotFoundException e) {\r\n                // org.apache.commons.dbcp.DelegatingConnection not found.\r\n            }\r\n\r\n            try {\r\n                if (conn instanceof java.sql.Wrapper) {\r\n                    Class<?> connIface = Class.forName(\"com.mysql.jdbc.Connection\");\r\n                    conn = ((java.sql.Wrapper) conn).unwrap(connIface);\r\n                    continue;\r\n                }\r\n            } catch (ClassNotFoundException e) {\r\n                // com.mysql.jdbc.Connection not found.\r\n            } catch (SQLException e) {\r\n                logger.warn(\"Unwrap \" + conn.getClass().getName() + \" to \" + connClazz.getName() + \" failed: \"\r\n                            + e.getMessage(),\r\n                    e);\r\n            }\r\n\r\n            return null;\r\n        }\r\n        return conn;\r\n    }\r\n\r\n    private static final Object invokeMethod(Object obj, Class<?> objClazz, String name) {\r\n        try {\r\n            Method method = objClazz.getMethod(name, (Class<?>[]) null);\r\n            return method.invoke(obj, (Object[]) null);\r\n        } catch (NoSuchMethodException e) {\r\n            throw new IllegalArgumentException(\"No such method: \\'\" + name + \"\\' @ \" + objClazz.getName(), e);\r\n        } catch (IllegalAccessException e) {\r\n            throw new IllegalArgumentException(\"Cannot invoke method: \\'\" + name + \"\\' @ \" + objClazz.getName(), e);\r\n        } catch (InvocationTargetException e) {\r\n            throw new IllegalArgumentException(\"Invoke method failed: \\'\" + name + \"\\' @ \" + objClazz.getName(),\r\n                e.getTargetException());\r\n        }\r\n    }\r\n\r\n    private static final Object getDeclaredField(Object obj, Class<?> objClazz, String name) {\r\n        try {\r\n            Field field = objClazz.getDeclaredField(name);\r\n            field.setAccessible(true);\r\n            return field.get(obj);\r\n        } catch (NoSuchFieldException e) {\r\n            throw new IllegalArgumentException(\"No such field: \\'\" + name + \"\\' @ \" + objClazz.getName(), e);\r\n        } catch (IllegalAccessException e) {\r\n            throw new IllegalArgumentException(\"Cannot get field: \\'\" + name + \"\\' @ \" + objClazz.getName(), e);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Connect MySQL master to fetch binlog.\r\n     */\r\n    public void open(Connection conn, String fileName, final int serverId) throws IOException {\r\n        open(conn, fileName, BIN_LOG_HEADER_SIZE, serverId, false);\r\n    }\r\n\r\n    /**\r\n     * Connect MySQL master to fetch binlog.\r\n     */\r\n    public void open(Connection conn, String fileName, final int serverId, boolean nonBlocking) throws IOException {\r\n        open(conn, fileName, BIN_LOG_HEADER_SIZE, serverId, nonBlocking);\r\n    }\r\n\r\n    /**\r\n     * Connect MySQL master to fetch binlog.\r\n     */\r\n    public void open(Connection conn, String fileName, final long filePosition, final int serverId) throws IOException {\r\n        open(conn, fileName, filePosition, serverId, false);\r\n    }\r\n\r\n    /**\r\n     * Connect MySQL master to fetch binlog.\r\n     */\r\n    public void open(Connection conn, String fileName, long filePosition, final int serverId, boolean nonBlocking)\r\n                                                                                                                  throws IOException {\r\n        try {\r\n            this.conn = conn;\r\n            Class<?> connClazz = Class.forName(\"com.mysql.jdbc.ConnectionImpl\");\r\n            Object unwrapConn = unwrapConnection(conn, connClazz);\r\n            if (unwrapConn == null) {\r\n                throw new IOException(\"Unable to unwrap \" + conn.getClass().getName()\r\n                                      + \" to com.mysql.jdbc.ConnectionImpl\");\r\n            }\r\n\r\n            // Get underlying IO streams for network communications.\r\n            Object connIo = getDeclaredField(unwrapConn, connClazz, \"io\");\r\n            if (connIo == null) {\r\n                throw new IOException(\"Get null field:\" + conn.getClass().getName() + \"#io\");\r\n            }\r\n            mysqlOutput = (OutputStream) getDeclaredField(connIo, connIo.getClass(), \"mysqlOutput\");\r\n            mysqlInput = (InputStream) getDeclaredField(connIo, connIo.getClass(), \"mysqlInput\");\r\n\r\n            if (filePosition == 0) filePosition = BIN_LOG_HEADER_SIZE;\r\n            sendBinlogDump(fileName, filePosition, serverId, nonBlocking);\r\n            position = 0;\r\n        } catch (IOException e) {\r\n            close(); /* Do cleanup */\r\n            logger.error(\"Error on COM_BINLOG_DUMP: file = \" + fileName + \", position = \" + filePosition);\r\n            throw e;\r\n        } catch (ClassNotFoundException e) {\r\n            close(); /* Do cleanup */\r\n            throw new IOException(\"Unable to load com.mysql.jdbc.ConnectionImpl\", e);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Put a byte in the buffer.\r\n     * \r\n     * @param b the byte to put in the buffer\r\n     */\r\n    protected final void putByte(byte b) {\r\n        ensureCapacity(position + 1);\r\n\r\n        buffer[position++] = b;\r\n    }\r\n\r\n    /**\r\n     * Put 16-bit integer in the buffer.\r\n     * \r\n     * @param i16 the integer to put in the buffer\r\n     */\r\n    protected final void putInt16(int i16) {\r\n        ensureCapacity(position + 2);\r\n\r\n        byte[] buf = buffer;\r\n        buf[position++] = (byte) (i16 & 0xff);\r\n        buf[position++] = (byte) (i16 >>> 8);\r\n    }\r\n\r\n    /**\r\n     * Put 32-bit integer in the buffer.\r\n     * \r\n     * @param i32 the integer to put in the buffer\r\n     */\r\n    protected final void putInt32(long i32) {\r\n        ensureCapacity(position + 4);\r\n\r\n        byte[] buf = buffer;\r\n        buf[position++] = (byte) (i32 & 0xff);\r\n        buf[position++] = (byte) (i32 >>> 8);\r\n        buf[position++] = (byte) (i32 >>> 16);\r\n        buf[position++] = (byte) (i32 >>> 24);\r\n    }\r\n\r\n    /**\r\n     * Put a string in the buffer.\r\n     * \r\n     * @param s the value to put in the buffer\r\n     */\r\n    protected final void putString(String s) {\r\n        ensureCapacity(position + (s.length() * 2) + 1);\r\n\r\n        System.arraycopy(s.getBytes(), 0, buffer, position, s.length());\r\n        position += s.length();\r\n        buffer[position++] = 0;\r\n    }\r\n\r\n    protected final void sendBinlogDump(String fileName, final long filePosition, final int serverId,\r\n                                        boolean nonBlocking) throws IOException {\r\n        position = NET_HEADER_SIZE;\r\n\r\n        putByte(COM_BINLOG_DUMP);\r\n        putInt32(filePosition);\r\n        int binlog_flags = nonBlocking ? BINLOG_DUMP_NON_BLOCK : 0;\r\n        binlog_flags |= BINLOG_SEND_ANNOTATE_ROWS_EVENT;\r\n        putInt16(binlog_flags); // binlog_flags\r\n        putInt32(serverId); // slave's server-id\r\n        putString(fileName);\r\n\r\n        final byte[] buf = buffer;\r\n        final int len = position - NET_HEADER_SIZE;\r\n        buf[0] = (byte) (len & 0xff);\r\n        buf[1] = (byte) (len >>> 8);\r\n        buf[2] = (byte) (len >>> 16);\r\n\r\n        mysqlOutput.write(buffer, 0, position);\r\n        mysqlOutput.flush();\r\n    }\r\n\r\n    /**\r\n     * {@inheritDoc}\r\n     * \r\n     * @see com.taobao.tddl.dbsync.binlog.LogFetcher#fetch()\r\n     */\r\n    public boolean fetch() throws IOException {\r\n        try {\r\n            // Fetching packet header from input.\r\n            if (!fetch0(0, NET_HEADER_SIZE)) {\r\n                logger.warn(\"Reached end of input stream while fetching header\");\r\n                return false;\r\n            }\r\n\r\n            // Fetching the first packet(may a multi-packet).\r\n            int netlen = getUint24(PACKET_LEN_OFFSET);\r\n            int netnum = getUint8(PACKET_SEQ_OFFSET);\r\n            if (!fetch0(NET_HEADER_SIZE, netlen)) {\r\n                logger.warn(\"Reached end of input stream: packet #\" + netnum + \", len = \" + netlen);\r\n                return false;\r\n            }\r\n\r\n            // Detecting error code.\r\n            final int mark = getUint8(NET_HEADER_SIZE);\r\n            if (mark != 0) {\r\n                if (mark == 255) // error from master\r\n                {\r\n                    // Indicates an error, for example trying to fetch from\r\n                    // wrong\r\n                    // binlog position.\r\n                    position = NET_HEADER_SIZE + 1;\r\n                    final int errno = getInt16();\r\n                    String sqlstate = forward(1).getFixString(SQLSTATE_LENGTH);\r\n                    String errmsg = getFixString(limit - position);\r\n                    throw new IOException(\"Received error packet:\" + \" errno = \" + errno + \", sqlstate = \" + sqlstate\r\n                                          + \" errmsg = \" + errmsg);\r\n                } else if (mark == 254) {\r\n                    // Indicates end of stream. It's not clear when this would\r\n                    // be sent.\r\n                    logger.warn(\"Received EOF packet from server, apparent\" + \" master disconnected.\");\r\n                    return false;\r\n                } else {\r\n                    // Should not happen.\r\n                    throw new IOException(\"Unexpected response \" + mark + \" while fetching binlog: packet #\" + netnum\r\n                                          + \", len = \" + netlen);\r\n                }\r\n            }\r\n\r\n            // The first packet is a multi-packet, concatenate the packets.\r\n            while (netlen == MAX_PACKET_LENGTH) {\r\n                if (!fetch0(0, NET_HEADER_SIZE)) {\r\n                    logger.warn(\"Reached end of input stream while fetching header\");\r\n                    return false;\r\n                }\r\n\r\n                netlen = getUint24(PACKET_LEN_OFFSET);\r\n                netnum = getUint8(PACKET_SEQ_OFFSET);\r\n                if (!fetch0(limit, netlen)) {\r\n                    logger.warn(\"Reached end of input stream: packet #\" + netnum + \", len = \" + netlen);\r\n                    return false;\r\n                }\r\n            }\r\n\r\n            // Preparing buffer variables to decoding.\r\n            origin = NET_HEADER_SIZE + 1;\r\n            position = origin;\r\n            limit -= origin;\r\n            return true;\r\n        } catch (SocketTimeoutException e) {\r\n            close(); /* Do cleanup */\r\n            logger.error(\"Socket timeout expired, closing connection\", e);\r\n            throw e;\r\n        } catch (InterruptedIOException e) {\r\n            close(); /* Do cleanup */\r\n            logger.warn(\"I/O interrupted while reading from client socket\", e);\r\n            throw e;\r\n        } catch (IOException e) {\r\n            close(); /* Do cleanup */\r\n            logger.error(\"I/O error while reading from client socket\", e);\r\n            throw e;\r\n        }\r\n    }\r\n\r\n    private final boolean fetch0(final int off, final int len) throws IOException {\r\n        ensureCapacity(off + len);\r\n\r\n        for (int count, n = 0; n < len; n += count) {\r\n            if (0 > (count = mysqlInput.read(buffer, off + n, len - n))) {\r\n                // Reached end of input stream\r\n                return false;\r\n            }\r\n        }\r\n\r\n        if (limit < off + len) limit = off + len;\r\n        return true;\r\n    }\r\n\r\n    /**\r\n     * {@inheritDoc}\r\n     * \r\n     * @see com.taobao.tddl.dbsync.binlog.LogFetcher#close()\r\n     */\r\n    public void close() throws IOException {\r\n        try {\r\n            if (conn != null) conn.close();\r\n\r\n            conn = null;\r\n            mysqlInput = null;\r\n            mysqlOutput = null;\r\n        } catch (SQLException e) {\r\n            logger.warn(\"Unable to close connection\", e);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/FileLogFetcher.java",
    "content": "package com.taobao.tddl.dbsync.binlog;\r\n\r\nimport java.io.File;\r\nimport java.io.FileInputStream;\r\nimport java.io.FileNotFoundException;\r\nimport java.io.IOException;\r\nimport java.util.Arrays;\r\n\r\nimport com.taobao.tddl.dbsync.binlog.event.FormatDescriptionLogEvent;\r\n\r\n/**\r\n * TODO: Document It!!\r\n * \r\n * <pre>\r\n * FileLogFetcher fetcher = new FileLogFetcher();\r\n * fetcher.open(file, 0);\r\n * \r\n * while (fetcher.fetch()) {\r\n *     LogEvent event;\r\n *     do {\r\n *         event = decoder.decode(fetcher, context);\r\n * \r\n *         // process log event.\r\n *     } while (event != null);\r\n * }\r\n * // file ending reached.\r\n * </pre>\r\n * \r\n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\r\n * @version 1.0\r\n */\r\npublic final class FileLogFetcher extends LogFetcher {\r\n\r\n    public static final byte[] BINLOG_MAGIC = { -2, 0x62, 0x69, 0x6e };\r\n\r\n    private FileInputStream    fin;\r\n\r\n    public FileLogFetcher(){\r\n        super(DEFAULT_INITIAL_CAPACITY, DEFAULT_GROWTH_FACTOR);\r\n    }\r\n\r\n    public FileLogFetcher(final int initialCapacity){\r\n        super(initialCapacity, DEFAULT_GROWTH_FACTOR);\r\n    }\r\n\r\n    public FileLogFetcher(final int initialCapacity, final float growthFactor){\r\n        super(initialCapacity, growthFactor);\r\n    }\r\n\r\n    /**\r\n     * Open binlog file in local disk to fetch.\r\n     */\r\n    public void open(File file) throws FileNotFoundException, IOException {\r\n        open(file, 0L);\r\n    }\r\n\r\n    /**\r\n     * Open binlog file in local disk to fetch.\r\n     */\r\n    public void open(String filePath) throws FileNotFoundException, IOException {\r\n        open(new File(filePath), 0L);\r\n    }\r\n\r\n    /**\r\n     * Open binlog file in local disk to fetch.\r\n     */\r\n    public void open(String filePath, final long filePosition) throws FileNotFoundException, IOException {\r\n        open(new File(filePath), filePosition);\r\n    }\r\n\r\n    /**\r\n     * Open binlog file in local disk to fetch.\r\n     */\r\n    public void open(File file, final long filePosition) throws FileNotFoundException, IOException {\r\n        fin = new FileInputStream(file);\r\n\r\n        ensureCapacity(BIN_LOG_HEADER_SIZE);\r\n        if (BIN_LOG_HEADER_SIZE != fin.read(buffer, 0, BIN_LOG_HEADER_SIZE)) {\r\n            throw new IOException(\"No binlog file header\");\r\n        }\r\n\r\n        if (buffer[0] != BINLOG_MAGIC[0] || buffer[1] != BINLOG_MAGIC[1] || buffer[2] != BINLOG_MAGIC[2]\r\n            || buffer[3] != BINLOG_MAGIC[3]) {\r\n            throw new IOException(\"Error binlog file header: \"\r\n                                  + Arrays.toString(Arrays.copyOf(buffer, BIN_LOG_HEADER_SIZE)));\r\n        }\r\n\r\n        limit = 0;\r\n        origin = 0;\r\n        position = 0;\r\n\r\n        if (filePosition > BIN_LOG_HEADER_SIZE) {\r\n            final int maxFormatDescriptionEventLen = FormatDescriptionLogEvent.LOG_EVENT_MINIMAL_HEADER_LEN\r\n                                                     + FormatDescriptionLogEvent.ST_COMMON_HEADER_LEN_OFFSET\r\n                                                     + LogEvent.ENUM_END_EVENT + LogEvent.BINLOG_CHECKSUM_ALG_DESC_LEN\r\n                                                     + LogEvent.CHECKSUM_CRC32_SIGNATURE_LEN;\r\n\r\n            ensureCapacity(maxFormatDescriptionEventLen);\r\n            limit = fin.read(buffer, 0, maxFormatDescriptionEventLen);\r\n            limit = (int) getUint32(LogEvent.EVENT_LEN_OFFSET);\r\n            fin.getChannel().position(filePosition);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * {@inheritDoc}\r\n     * \r\n     * @see com.taobao.tddl.dbsync.binlog.LogFetcher#fetch()\r\n     */\r\n    public boolean fetch() throws IOException {\r\n        if (limit == 0) {\r\n            final int len = fin.read(buffer, 0, buffer.length);\r\n            if (len >= 0) {\r\n                limit += len;\r\n                position = 0;\r\n                origin = 0;\r\n\r\n                /* More binlog to fetch */\r\n                return true;\r\n            }\r\n        } else if (origin == 0) {\r\n            if (limit > buffer.length / 2) {\r\n                ensureCapacity(buffer.length + limit);\r\n            }\r\n            final int len = fin.read(buffer, limit, buffer.length - limit);\r\n            if (len >= 0) {\r\n                limit += len;\r\n\r\n                /* More binlog to fetch */\r\n                return true;\r\n            }\r\n        } else if (limit > 0) {\r\n            if (limit >= FormatDescriptionLogEvent.LOG_EVENT_HEADER_LEN) {\r\n                int lenPosition = position + 4 + 1 + 4;\r\n                long eventLen = ((long) (0xff & buffer[lenPosition++])) | ((long) (0xff & buffer[lenPosition++]) << 8)\r\n                                | ((long) (0xff & buffer[lenPosition++]) << 16)\r\n                                | ((long) (0xff & buffer[lenPosition++]) << 24);\r\n\r\n                if (limit >= eventLen) {\r\n                    return true;\r\n                } else {\r\n                    ensureCapacity((int) eventLen);\r\n                }\r\n            }\r\n\r\n            System.arraycopy(buffer, origin, buffer, 0, limit);\r\n            position -= origin;\r\n            origin = 0;\r\n            final int len = fin.read(buffer, limit, buffer.length - limit);\r\n            if (len >= 0) {\r\n                limit += len;\r\n\r\n                /* More binlog to fetch */\r\n                return true;\r\n            }\r\n        } else {\r\n            /* Should not happen. */\r\n            throw new IllegalArgumentException(\"Unexcepted limit: \" + limit);\r\n        }\r\n\r\n        /* Reach binlog file end */\r\n        return false;\r\n    }\r\n\r\n    /**\r\n     * {@inheritDoc}\r\n     * \r\n     * @see com.taobao.tddl.dbsync.binlog.LogFetcher#close()\r\n     */\r\n    public void close() throws IOException {\r\n        if (fin != null) {\r\n            fin.close();\r\n        }\r\n\r\n        fin = null;\r\n    }\r\n}\r\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/JsonConversion.java",
    "content": "package com.taobao.tddl.dbsync.binlog;\n\nimport static com.taobao.tddl.dbsync.binlog.event.RowsLogBuffer.*;\n\nimport java.nio.charset.Charset;\n\n/**\n * 处理下MySQL json二进制转化为可读的字符串\n * \n * @author agapple 2016年6月30日 上午11:26:17\n * @since 1.0.22\n */\npublic class JsonConversion {\n\n    // JSON TYPE\n    public static final int  JSONB_TYPE_SMALL_OBJECT = 0x0;\n    public static final int  JSONB_TYPE_LARGE_OBJECT = 0x1;\n    public static final int  JSONB_TYPE_SMALL_ARRAY  = 0x2;\n    public static final int  JSONB_TYPE_LARGE_ARRAY  = 0x3;\n    public static final int  JSONB_TYPE_LITERAL      = 0x4;\n    public static final int  JSONB_TYPE_INT16        = 0x5;\n    public static final int  JSONB_TYPE_UINT16       = 0x6;\n    public static final int  JSONB_TYPE_INT32        = 0x7;\n    public static final int  JSONB_TYPE_UINT32       = 0x8;\n    public static final int  JSONB_TYPE_INT64        = 0x9;\n    public static final int  JSONB_TYPE_UINT64       = 0xA;\n    public static final int  JSONB_TYPE_DOUBLE       = 0xB;\n    public static final int  JSONB_TYPE_STRING       = 0xC;\n    public static final int  JSONB_TYPE_OPAQUE       = 0xF;\n    public static final char JSONB_NULL_LITERAL      = '\\0';\n    public static final char JSONB_TRUE_LITERAL      = '\\1';\n    public static final char JSONB_FALSE_LITERAL     = '\\2';\n\n    /*\n     * The size of offset or size fields in the small and the large storage format\n     * for JSON objects and JSON arrays.\n     */\n    public static final int  SMALL_OFFSET_SIZE       = 2;\n    public static final int  LARGE_OFFSET_SIZE       = 4;\n\n    /*\n     * The size of key entries for objects when using the small storage format or\n     * the large storage format. In the small format it is 4 bytes (2 bytes for key\n     * length and 2 bytes for key offset). In the large format it is 6 (2 bytes for\n     * length, 4 bytes for offset).\n     */\n    public static final int  KEY_ENTRY_SIZE_SMALL    = (2 + SMALL_OFFSET_SIZE);\n    public static final int  KEY_ENTRY_SIZE_LARGE    = (2 + LARGE_OFFSET_SIZE);\n\n    /*\n     * The size of value entries for objects or arrays. When using the small storage\n     * format, the entry size is 3 (1 byte for type, 2 bytes for offset). When using\n     * the large storage format, it is 5 (1 byte for type, 4 bytes for offset).\n     */\n    public static final int  VALUE_ENTRY_SIZE_SMALL  = (1 + SMALL_OFFSET_SIZE);\n    public static final int  VALUE_ENTRY_SIZE_LARGE  = (1 + LARGE_OFFSET_SIZE);\n\n    public static Json_Value parse_value(int type, LogBuffer buffer, long len, String charsetName) {\n        return parse_value(type, buffer, len, Charset.forName(charsetName));\n    }\n\n    public static Json_Value parse_value(int type, LogBuffer buffer, long len, Charset charset) {\n        buffer = buffer.duplicate(buffer.position(), (int) len);\n        switch (type) {\n            case JSONB_TYPE_SMALL_OBJECT:\n                return parse_array_or_object(Json_enum_type.OBJECT, buffer, len, false, charset);\n            case JSONB_TYPE_LARGE_OBJECT:\n                return parse_array_or_object(Json_enum_type.OBJECT, buffer, len, true, charset);\n            case JSONB_TYPE_SMALL_ARRAY:\n                return parse_array_or_object(Json_enum_type.ARRAY, buffer, len, false, charset);\n            case JSONB_TYPE_LARGE_ARRAY:\n                return parse_array_or_object(Json_enum_type.ARRAY, buffer, len, true, charset);\n            default:\n                return parse_scalar(type, buffer, len, charset);\n        }\n    }\n\n    private static Json_Value parse_array_or_object(Json_enum_type type, LogBuffer buffer, long len, boolean large,\n                                                    Charset charset) {\n        long offset_size = large ? LARGE_OFFSET_SIZE : SMALL_OFFSET_SIZE;\n        if (len < 2 * offset_size) {\n            throw new IllegalArgumentException(\"illegal json data\");\n        }\n        long element_count = read_offset_or_size(buffer, large);\n        long bytes = read_offset_or_size(buffer, large);\n\n        if (bytes > len) {\n            throw new IllegalArgumentException(\"illegal json data\");\n        }\n        long header_size = 2 * offset_size;\n        if (type == Json_enum_type.OBJECT) {\n            header_size += element_count * (large ? KEY_ENTRY_SIZE_LARGE : KEY_ENTRY_SIZE_SMALL);\n        }\n\n        header_size += element_count * (large ? VALUE_ENTRY_SIZE_LARGE : VALUE_ENTRY_SIZE_SMALL);\n        if (header_size > bytes) {\n            throw new IllegalArgumentException(\"illegal json data\");\n        }\n        return new Json_Value(type, buffer.rewind(), element_count, bytes, large);\n    }\n\n    private static long read_offset_or_size(LogBuffer buffer, boolean large) {\n        return large ? buffer.getUint32() : buffer.getUint16();\n    }\n\n    private static Json_Value parse_scalar(int type, LogBuffer buffer, long len, Charset charset) {\n        switch (type) {\n            case JSONB_TYPE_LITERAL:\n                /* purecov: inspected */\n                int data = buffer.getUint8();\n                switch (data) {\n                    case JSONB_NULL_LITERAL:\n                        return new Json_Value(Json_enum_type.LITERAL_NULL);\n                    case JSONB_TRUE_LITERAL:\n                        return new Json_Value(Json_enum_type.LITERAL_TRUE);\n                    case JSONB_FALSE_LITERAL:\n                        return new Json_Value(Json_enum_type.LITERAL_FALSE);\n                    default:\n                        throw new IllegalArgumentException(\"illegal json data\");\n                }\n            case JSONB_TYPE_INT16:\n                return new Json_Value(Json_enum_type.INT, buffer.getInt16());\n            case JSONB_TYPE_INT32:\n                return new Json_Value(Json_enum_type.INT, buffer.getInt32());\n            case JSONB_TYPE_INT64:\n                return new Json_Value(Json_enum_type.INT, buffer.getLong64());\n            case JSONB_TYPE_UINT16:\n                return new Json_Value(Json_enum_type.UINT, buffer.getUint16());\n            case JSONB_TYPE_UINT32:\n                return new Json_Value(Json_enum_type.UINT, buffer.getUint32());\n            case JSONB_TYPE_UINT64:\n                return new Json_Value(Json_enum_type.UINT, buffer.getUlong64());\n            case JSONB_TYPE_DOUBLE:\n                return new Json_Value(Json_enum_type.DOUBLE, Double.valueOf(buffer.getDouble64()));\n            case JSONB_TYPE_STRING:\n                int max_bytes = (int) Math.min(len, 5);\n                long tlen = 0;\n                long str_len = 0;\n                long n = 0;\n                byte[] datas = buffer.getData(max_bytes);\n                for (int i = 0; i < max_bytes; i++) {\n                    // Get the next 7 bits of the length.\n                    tlen |= (datas[i] & 0x7f) << (7 * i);\n                    if ((datas[i] & 0x80) == 0) {\n                        // The length shouldn't exceed 32 bits.\n                        if (tlen > 4294967296L) {\n                            throw new IllegalArgumentException(\"illegal json data\");\n                        }\n\n                        // This was the last byte. Return successfully.\n                        n = i + 1;\n                        str_len = tlen;\n                        break;\n                    }\n                }\n\n                if (len < n + str_len) {\n                    throw new IllegalArgumentException(\"illegal json data\");\n                }\n                return new Json_Value(Json_enum_type.STRING,\n                    buffer.rewind().forward((int) n).getFixLengthString((int) str_len, charset));\n            case JSONB_TYPE_OPAQUE:\n                /*\n                 * There should always be at least one byte, which tells the field type of the\n                 * opaque value.\n                 */\n                // The type is encoded as a uint8 that maps to an\n                // enum_field_types.\n                int type_byte = buffer.getUint8();\n                int position = buffer.position();\n                // Then there's the length of the value.\n                int q_max_bytes = (int) Math.min(len - 1, 5);\n                long q_tlen = 0;\n                long q_str_len = 0;\n                long q_n = 0;\n                byte[] q_datas = buffer.getData(q_max_bytes);\n                for (int i = 0; i < q_max_bytes; i++) {\n                    // Get the next 7 bits of the length.\n                    q_tlen |= (q_datas[i] & 0x7f) << (7 * i);\n                    if ((q_datas[i] & 0x80) == 0) {\n                        // The length shouldn't exceed 32 bits.\n                        if (q_tlen > 4294967296L) {\n                            throw new IllegalArgumentException(\"illegal json data\");\n                        }\n\n                        // This was the last byte. Return successfully.\n                        q_n = i + 1;\n                        q_str_len = q_tlen;\n                        break;\n                    }\n                }\n\n                if (q_str_len == 0 || len < q_n + q_str_len) {\n                    throw new IllegalArgumentException(\"illegal json data\");\n                }\n                return new Json_Value(type_byte, buffer.position(position).forward((int) q_n), q_str_len);\n            default:\n                throw new IllegalArgumentException(\"illegal json data\");\n        }\n    }\n\n    public static class Json_Value {\n\n        Json_enum_type m_type;\n        int            m_field_type;\n        LogBuffer      m_data;\n        long           m_element_count;\n        long           m_length;\n        String         m_string_value;\n        Number         m_int_value;\n        double         m_double_value;\n        boolean        m_large;\n\n        public Json_Value(Json_enum_type t){\n            this.m_type = t;\n        }\n\n        public Json_Value(Json_enum_type t, Number val){\n            this.m_type = t;\n            if (t == Json_enum_type.DOUBLE) {\n                this.m_double_value = val.doubleValue();\n            } else {\n                this.m_int_value = val;\n            }\n        }\n\n        public Json_Value(Json_enum_type t, String value){\n            this.m_type = t;\n            this.m_string_value = value;\n        }\n\n        public Json_Value(int field_type, LogBuffer data, long bytes){\n            this.m_type = Json_enum_type.OPAQUE; // 不确定类型\n            this.m_field_type = field_type;\n            this.m_data = data;\n            this.m_length = bytes;\n        }\n\n        public Json_Value(Json_enum_type t, LogBuffer data, long element_count, long bytes, boolean large){\n            this.m_type = t;\n            this.m_data = data;\n            this.m_element_count = element_count;\n            this.m_length = bytes;\n            this.m_large = large;\n        }\n\n        public String key(int i, Charset charset) {\n            m_data.rewind();\n            int offset_size = m_large ? LARGE_OFFSET_SIZE : SMALL_OFFSET_SIZE;\n            int key_entry_size = m_large ? KEY_ENTRY_SIZE_LARGE : KEY_ENTRY_SIZE_SMALL;\n            int entry_offset = 2 * offset_size + key_entry_size * i;\n            // The offset of the key is the first part of the key\n            // entry.\n            m_data.forward(entry_offset);\n            long key_offset = read_offset_or_size(m_data, m_large);\n            // The length of the key is the second part of the\n            // entry, always two\n            // bytes.\n            long key_length = m_data.getUint16();\n            return m_data.rewind().forward((int) key_offset).getFixLengthString((int) key_length, charset);\n        }\n\n        public Json_Value element(int i, Charset charset) {\n            m_data.rewind();\n            int offset_size = m_large ? LARGE_OFFSET_SIZE : SMALL_OFFSET_SIZE;\n            int key_entry_size = m_large ? KEY_ENTRY_SIZE_LARGE : KEY_ENTRY_SIZE_SMALL;\n            int value_entry_size = m_large ? VALUE_ENTRY_SIZE_LARGE : VALUE_ENTRY_SIZE_SMALL;\n            int first_entry_offset = 2 * offset_size;\n            if (m_type == Json_enum_type.OBJECT) {\n                first_entry_offset += m_element_count * key_entry_size;\n            }\n            int entry_offset = first_entry_offset + value_entry_size * i;\n            int type = m_data.forward(entry_offset).getUint8();\n            if (type == JSONB_TYPE_INT16 || type == JSONB_TYPE_UINT16 || type == JSONB_TYPE_LITERAL\n                || (m_large && (type == JSONB_TYPE_INT32 || type == JSONB_TYPE_UINT32))) {\n                return parse_scalar(type, m_data, value_entry_size - 1, charset);\n            }\n            int value_offset = (int) read_offset_or_size(m_data, m_large);\n            return parse_value(type, m_data.rewind().forward(value_offset), (int) m_length - value_offset, charset);\n        }\n\n        public StringBuilder toJsonString(StringBuilder buf, Charset charset) {\n            switch (m_type) {\n                case OBJECT:\n                    buf.append(\"{\");\n                    for (int i = 0; i < m_element_count; ++i) {\n                        if (i > 0) {\n                            buf.append(\", \");\n                        }\n                        buf.append('\"').append(escapse(key(i, charset))).append('\"');\n                        buf.append(\": \");\n                        element(i, charset).toJsonString(buf, charset);\n                    }\n                    buf.append(\"}\");\n                    break;\n                case ARRAY:\n                    buf.append(\"[\");\n                    for (int i = 0; i < m_element_count; ++i) {\n                        if (i > 0) {\n                            buf.append(\", \");\n                        }\n                        element(i, charset).toJsonString(buf, charset);\n                    }\n                    buf.append(\"]\");\n                    break;\n                case DOUBLE:\n                    buf.append(Double.valueOf(m_double_value).toString());\n                    break;\n                case INT:\n                    buf.append(m_int_value.toString());\n                    break;\n                case UINT:\n                    buf.append(m_int_value.toString());\n                    break;\n                case LITERAL_FALSE:\n                    buf.append(\"false\");\n                    break;\n                case LITERAL_TRUE:\n                    buf.append(\"true\");\n                    break;\n                case LITERAL_NULL:\n                    buf.append(\"null\");\n                    break;\n                case OPAQUE:\n                    String text = null;\n                    if (m_field_type == LogEvent.MYSQL_TYPE_NEWDECIMAL) {\n                        int precision = m_data.getInt8();\n                        int scale = m_data.getInt8();\n                        text = m_data.getDecimal(precision, scale).toPlainString();\n                        buf.append(text);\n                    } else if (m_field_type == LogEvent.MYSQL_TYPE_TIME) {\n                        long packed_value = m_data.getLong64();\n                        if (packed_value == 0) {\n                            text = \"00:00:00\";\n                        } else {\n                            long ultime = Math.abs(packed_value);\n                            long intpart = ultime >> 24;\n                            int frac = (int) (ultime % (1L << 24));\n                            // text = String.format(\"%s%02d:%02d:%02d\",\n                            // packed_value >= 0 ? \"\" : \"-\",\n                            // (int) ((intpart >> 12) % (1 << 10)),\n                            // (int) ((intpart >> 6) % (1 << 6)),\n                            // (int) (intpart % (1 << 6)));\n                            // text = text + \".\" + usecondsToStr(frac, 6);\n                            StringBuilder builder = new StringBuilder(17);\n                            if (packed_value < 0) {\n                                builder.append('-');\n                            }\n\n                            int d = (int) ((intpart >> 12) % (1 << 10));\n                            if (d > 100) {\n                                builder.append(String.valueOf(d));\n                            } else {\n                                appendNumber2(builder, d);\n                            }\n                            builder.append(':');\n                            appendNumber2(builder, (int) ((intpart >> 6) % (1 << 6)));\n                            builder.append(':');\n                            appendNumber2(builder, (int) (intpart % (1 << 6)));\n\n                            builder.append('.').append(usecondsToStr(frac, 6));\n                            text = builder.toString();\n                        }\n                        buf.append('\"').append(text).append('\"');\n                    } else if (m_field_type == LogEvent.MYSQL_TYPE_DATE || m_field_type == LogEvent.MYSQL_TYPE_DATETIME\n                               || m_field_type == LogEvent.MYSQL_TYPE_TIMESTAMP) {\n                                   long packed_value = m_data.getLong64();\n                                   if (packed_value == 0) {\n                                       text = \"0000-00-00 00:00:00\";\n                                   } else {\n                                       // 构造TimeStamp只处理到秒\n                                       long ultime = Math.abs(packed_value);\n                                       long intpart = ultime >> 24;\n                                       int frac = (int) (ultime % (1L << 24));\n                                       long ymd = intpart >> 17;\n                                       long ym = ymd >> 5;\n                                       long hms = intpart % (1 << 17);\n                                       // text =\n                                       // String.format(\"%04d-%02d-%02d %02d:%02d:%02d\",\n                                       // (int) (ym / 13),\n                                       // (int) (ym % 13),\n                                       // (int) (ymd % (1 << 5)),\n                                       // (int) (hms >> 12),\n                                       // (int) ((hms >> 6) % (1 << 6)),\n                                       // (int) (hms % (1 << 6)));\n                                       StringBuilder builder = new StringBuilder(26);\n                                       appendNumber4(builder, (int) (ym / 13));\n                                       builder.append('-');\n                                       appendNumber2(builder, (int) (ym % 13));\n                                       builder.append('-');\n                                       appendNumber2(builder, (int) (ymd % (1 << 5)));\n                                       builder.append(' ');\n                                       appendNumber2(builder, (int) (hms >> 12));\n                                       builder.append(':');\n                                       appendNumber2(builder, (int) ((hms >> 6) % (1 << 6)));\n                                       builder.append(':');\n                                       appendNumber2(builder, (int) (hms % (1 << 6)));\n                                       builder.append('.').append(usecondsToStr(frac, 6));\n                                       text = builder.toString();\n                                   }\n                                   buf.append('\"').append(text).append('\"');\n                               } else {\n                                   text = m_data.getFixLengthString((int) m_length, charset);\n                                   buf.append('\"').append(escapse(text)).append('\"');\n                               }\n\n                    break;\n                case STRING:\n                    buf.append('\"').append(escapse(m_string_value)).append('\"');\n                    break;\n                case ERROR:\n                    throw new IllegalArgumentException(\"illegal json data\");\n            }\n\n            return buf;\n        }\n    }\n\n    private static StringBuilder escapse(String data) {\n        StringBuilder sb = new StringBuilder(data.length());\n        int endIndex = data.length();\n        for (int i = 0; i < endIndex; ++i) {\n            char c = data.charAt(i);\n            if (c == '\"') {\n                sb.append(\"\\\\\\\"\");\n            } else if (c == '\\n') {\n                sb.append(\"\\\\n\");\n            } else if (c == '\\r') {\n                sb.append(\"\\\\r\");\n            } else if (c == '\\\\') {\n                sb.append(\"\\\\\\\\\");\n            } else if (c == '\\t') {\n                sb.append(\"\\\\t\");\n            } else if (c < 16) {\n                sb.append(\"\\\\u000\");\n                sb.append(Integer.toHexString(c));\n            } else if (c < 32) {\n                sb.append(\"\\\\u00\");\n                sb.append(Integer.toHexString(c));\n            } else if (c >= 0x7f && c <= 0xA0) {\n                sb.append(\"\\\\u00\");\n                sb.append(Integer.toHexString(c));\n            } else {\n                sb.append(c);\n            }\n        }\n        return sb;\n    }\n\n    public static enum Json_enum_type {\n                                       OBJECT, ARRAY, STRING, INT, UINT, DOUBLE, LITERAL_NULL, LITERAL_TRUE,\n                                       LITERAL_FALSE, OPAQUE, ERROR\n    }\n\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/JsonDiffConversion.java",
    "content": "package com.taobao.tddl.dbsync.binlog;\n\nimport java.nio.charset.Charset;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Objects;\n\nimport com.taobao.tddl.dbsync.binlog.JsonConversion.Json_Value;\nimport com.taobao.tddl.dbsync.binlog.JsonConversion.Json_enum_type;\n\n/**\n * 处理mysql8.0 parital json diff解析\n *\n * @author agapple 2018年11月4日 下午3:53:46\n * @since 1.1.2\n */\npublic class JsonDiffConversion {\n\n    /**\n     * The JSON value in the given path is replaced with a new value. It has the\n     * same effect as `JSON_REPLACE(col, path, value)`.\n     */\n    public static final int DIFF_OPERATION_REPLACE    = 0;\n    /**\n     * Add a new element at the given path. If the path specifies an array\n     * element, it has the same effect as `JSON_ARRAY_INSERT(col, path, value)`.\n     * If the path specifies an object member, it has the same effect as\n     * `JSON_INSERT(col, path, value)`.\n     */\n    public static final int DIFF_OPERATION_INSERT     = 1;\n    /**\n     * The JSON value at the given path is removed from an array or object. It\n     * has the same effect as `JSON_REMOVE(col, path)`.\n     */\n    public static final int DIFF_OPERATION_REMOVE     = 2;\n\n    public static final int JSON_DIFF_OPERATION_COUNT = 3;\n\n    public static StringBuilder print_json_diff(LogBuffer buffer, long len, String columnName, int columnIndex,\n                                                String charsetName) {\n        return print_json_diff(buffer, len, columnName, columnIndex, Charset.forName(charsetName));\n    }\n\n    public static StringBuilder print_json_diff(LogBuffer buffer, long len, String columnName, int columnIndex,\n                                                Charset charset) {\n        int position = buffer.position();\n        List<String> operation_names = new ArrayList<>();\n        while (buffer.hasRemaining()) {\n            int operation_int = buffer.getUint8();\n            if (operation_int >= JSON_DIFF_OPERATION_COUNT) {\n                throw new IllegalArgumentException(\"reading operation type (invalid operation code)\");\n            }\n\n            // skip path\n            long path_length = buffer.getPackedLong();\n            if (path_length > len) {\n                throw new IllegalArgumentException(\"skipping path\");\n            }\n\n            // compute operation name\n            byte[] lastP = buffer.getData(buffer.position() + (int) path_length - 1, 1);\n            String operation_name = json_diff_operation_name(operation_int, lastP[0]);\n            operation_names.add(operation_name);\n\n            buffer.forward((int) path_length);\n            // skip value\n            if (operation_int != DIFF_OPERATION_REMOVE) {\n                long value_length = buffer.getPackedLong();\n                if (value_length > len) {\n                    throw new IllegalArgumentException(\"skipping path\");\n                }\n\n                buffer.forward((int) value_length);\n            }\n\n            // see https://github.com/alibaba/canal/pull/5018\n            if (buffer.position() - position >= len) {\n                break;\n            }\n        }\n\n        if (buffer.position() - position != len) {\n            throw new IllegalArgumentException(\"reading json diff\");\n        }\n\n        // Print function names in reverse order.\n        StringBuilder builder = new StringBuilder();\n        for (int i = operation_names.size() - 1; i >= 0; i--) {\n            if (i == 0 || !Objects.equals(operation_names.get(i - 1), operation_names.get(i))) {\n                builder.append(operation_names.get(i)).append(\"(\");\n            }\n        }\n\n        // Print column id\n        if (columnName != null) {\n            builder.append(columnName);\n        } else {\n            builder.append(\"@\").append(columnIndex);\n        }\n\n        // In case this vector is empty (a no-op), make an early return\n        // after printing only the column name\n        if (operation_names.isEmpty()) {\n            return builder;\n        }\n\n        // Print comma between column name and next function argument\n        builder.append(\", \");\n        // Print paths and values.\n        buffer.position(position);\n        int diff_i = 0;\n        while (buffer.hasRemaining()) {\n            // Read operation\n            int operation_int = buffer.getUint8();\n\n            // Read path length\n            long path_length = buffer.getPackedLong();\n            // Print path\n            builder.append('\\'').append(buffer.getFixString((int) path_length)).append('\\'');\n\n            if (operation_int != DIFF_OPERATION_REMOVE) {\n                // Print comma between path and value\n                builder.append(\", \");\n                // Read value length\n                long value_length = buffer.getPackedLong();\n\n                Json_Value jsonValue = JsonConversion.parse_value(buffer.getUint8(),\n                    buffer,\n                    value_length - 1,\n                    charset);\n                buffer.forward((int) value_length - 1);\n                // Read value\n                if (jsonValue.m_type == Json_enum_type.ERROR) {\n                    throw new IllegalArgumentException(\"parsing json value\");\n                }\n                StringBuilder jsonBuilder = new StringBuilder();\n                jsonValue.toJsonString(jsonBuilder, charset);\n                builder.append(jsonBuilder);\n            }\n\n            // see https://github.com/alibaba/canal/pull/5018\n            if (buffer.position() - position >= len) {\n                builder.append(\")\");\n                break;\n            }\n\n            // Print closing parenthesis\n            if (!buffer.hasRemaining() || !Objects.equals(operation_names.get(diff_i + 1), operation_names.get(diff_i))) {\n                builder.append(\")\");\n            }\n\n            if (buffer.hasRemaining()) {\n                builder.append(\", \");\n            }\n            diff_i++;\n        }\n\n        if (buffer.position() - position != len) {\n            throw new IllegalArgumentException(\"reading json diff\");\n        }\n\n        return builder;\n    }\n\n    private static String json_diff_operation_name(int operationType, int last_path_char) {\n        switch (operationType) {\n            case DIFF_OPERATION_REPLACE:\n                return \"JSON_REPLACE\";\n            case DIFF_OPERATION_INSERT:\n                if (last_path_char == ']') {\n                    return \"JSON_ARRAY_INSERT\";\n                } else {\n                    return \"JSON_INSERT\";\n                }\n            case DIFF_OPERATION_REMOVE:\n                return \"JSON_REMOVE\";\n        }\n        throw new IllegalArgumentException(\"illeagal operationType : \" + operationType);\n    }\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/LogBuffer.java",
    "content": "package com.taobao.tddl.dbsync.binlog;\r\n\r\nimport java.io.ByteArrayInputStream;\r\nimport java.io.IOException;\r\nimport java.io.OutputStream;\r\nimport java.math.BigDecimal;\r\nimport java.math.BigInteger;\r\nimport java.nio.charset.Charset;\r\nimport java.nio.charset.StandardCharsets;\r\nimport java.util.Arrays;\r\nimport java.util.BitSet;\r\n\r\nimport org.apache.commons.compress.compressors.deflate.DeflateCompressorInputStream;\r\nimport org.apache.commons.io.IOUtils;\r\n\r\n/**\r\n * TODO: Document Me!!\r\n * \r\n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\r\n * @version 1.0\r\n */\r\npublic class LogBuffer {\r\n\r\n    static final BigDecimal DECIMAL_ZERO_1_SCALE = BigDecimal.valueOf(0, 1);\r\n    static final BigDecimal DECIMAL_ONE_1_SCALE = BigDecimal.valueOf(10, 1);\r\n    protected byte[] buffer;\r\n\r\n    protected int    origin, limit;\r\n    protected int    position;\r\n    protected int    semival;\r\n\r\n    protected LogBuffer(){\r\n    }\r\n\r\n    public LogBuffer(byte[] buffer, final int origin, final int limit){\r\n        if (origin + limit > buffer.length) {\r\n            throw new IllegalArgumentException(\"capacity excceed: \" + (origin + limit));\r\n        }\r\n\r\n        this.buffer = buffer;\r\n        this.origin = origin;\r\n        this.position = origin;\r\n        this.limit = limit;\r\n    }\r\n\r\n    /**\r\n     * Return n bytes in this buffer.\r\n     */\r\n    public final LogBuffer duplicate(final int pos, final int len) {\r\n        if (pos + len > limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (pos + len));\r\n        }\r\n\r\n        // XXX: Do momery copy avoid buffer modified.\r\n        final int off = origin + pos;\r\n        byte[] buf = Arrays.copyOfRange(buffer, off, off + len);\r\n        return new LogBuffer(buf, 0, len);\r\n    }\r\n\r\n    /**\r\n     * Return next n bytes in this buffer.\r\n     */\r\n    public final LogBuffer duplicate(final int len) {\r\n        if (position + len > origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position + len - origin));\r\n        }\r\n\r\n        // XXX: Do momery copy avoid buffer modified.\r\n        final int end = position + len;\r\n        byte[] buf = Arrays.copyOfRange(buffer, position, end);\r\n        LogBuffer dupBuffer = new LogBuffer(buf, 0, len);\r\n        position = end;\r\n        return dupBuffer;\r\n    }\r\n\r\n    /**\r\n     * Return next n bytes in this buffer.\r\n     */\r\n    public final LogBuffer duplicate() {\r\n        // XXX: Do momery copy avoid buffer modified.\r\n        byte[] buf = Arrays.copyOfRange(buffer, origin, origin + limit);\r\n        return new LogBuffer(buf, 0, limit);\r\n    }\r\n\r\n    /**\r\n     * Returns this buffer's capacity. </p>\r\n     * \r\n     * @return The capacity of this buffer\r\n     */\r\n    public final int capacity() {\r\n        return buffer.length;\r\n    }\r\n\r\n    /**\r\n     * Returns this buffer's position. </p>\r\n     * \r\n     * @return The position of this buffer\r\n     */\r\n    public final int position() {\r\n        return position - origin;\r\n    }\r\n\r\n    /**\r\n     * Sets this buffer's position. If the mark is defined and larger than the\r\n     * new position then it is discarded. </p>\r\n     * \r\n     * @param newPosition The new position value; must be non-negative and no\r\n     * larger than the current limit\r\n     * @return This buffer\r\n     * @throws IllegalArgumentException If the preconditions on\r\n     * <tt>newPosition</tt> do not hold\r\n     */\r\n    public final LogBuffer position(final int newPosition) {\r\n        if (newPosition > limit || newPosition < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + newPosition);\r\n        }\r\n\r\n        this.position = origin + newPosition;\r\n        return this;\r\n    }\r\n\r\n    /**\r\n     * Forwards this buffer's position.\r\n     * \r\n     * @param len The forward distance\r\n     * @return This buffer\r\n     */\r\n    public final LogBuffer forward(final int len) {\r\n        if (position + len > origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position + len - origin));\r\n        }\r\n\r\n        this.position += len;\r\n        return this;\r\n    }\r\n\r\n    /**\r\n     * Consume this buffer, moving origin and position.\r\n     * \r\n     * @param len The consume distance\r\n     * @return This buffer\r\n     */\r\n    public final LogBuffer consume(final int len) {\r\n        if (limit > len) {\r\n            limit -= len;\r\n            origin += len;\r\n            position = origin;\r\n            return this;\r\n        } else if (limit == len) {\r\n            limit = 0;\r\n            origin = 0;\r\n            position = 0;\r\n            return this;\r\n        } else {\r\n            /* Should not happen. */\r\n            throw new IllegalArgumentException(\"limit excceed: \" + len);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Rewinds this buffer. The position is set to zero.\r\n     * \r\n     * @return This buffer\r\n     */\r\n    public final LogBuffer rewind() {\r\n        position = origin;\r\n        return this;\r\n    }\r\n\r\n    /**\r\n     * Returns this buffer's limit. </p>\r\n     * \r\n     * @return The limit of this buffer\r\n     */\r\n    public final int limit() {\r\n        return limit;\r\n    }\r\n\r\n    /**\r\n     * Sets this buffer's limit. If the position is larger than the new limit\r\n     * then it is set to the new limit. If the mark is defined and larger than\r\n     * the new limit then it is discarded. </p>\r\n     * \r\n     * @param newLimit The new limit value; must be non-negative and no larger\r\n     * than this buffer's capacity\r\n     * @return This buffer\r\n     * @throws IllegalArgumentException If the preconditions on\r\n     * <tt>newLimit</tt> do not hold\r\n     */\r\n    public final LogBuffer limit(int newLimit) {\r\n        if (origin + newLimit > buffer.length || newLimit < 0) {\r\n            throw new IllegalArgumentException(\"capacity excceed: \" + (origin + newLimit));\r\n        }\r\n\r\n        limit = newLimit;\r\n        return this;\r\n    }\r\n\r\n    /**\r\n     * Returns the number of elements between the current position and the\r\n     * limit. </p>\r\n     * \r\n     * @return The number of elements remaining in this buffer\r\n     */\r\n    public final int remaining() {\r\n        return limit + origin - position;\r\n    }\r\n\r\n    /**\r\n     * Tells whether there are any elements between the current position and the\r\n     * limit. </p>\r\n     * \r\n     * @return <tt>true</tt> if, and only if, there is at least one element\r\n     * remaining in this buffer\r\n     */\r\n    public final boolean hasRemaining() {\r\n        return position < limit + origin;\r\n    }\r\n\r\n    /**\r\n     * Return 8-bit signed int from buffer.\r\n     */\r\n    public final int getInt8(final int pos) {\r\n        if (pos >= limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + pos);\r\n        }\r\n\r\n        return buffer[origin + pos];\r\n    }\r\n\r\n    /**\r\n     * Return next 8-bit signed int from buffer.\r\n     */\r\n    public final int getInt8() {\r\n        if (position >= origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position - origin));\r\n        }\r\n\r\n        return buffer[position++];\r\n    }\r\n\r\n    /**\r\n     * Return 8-bit unsigned int from buffer.\r\n     */\r\n    public final int getUint8(final int pos) {\r\n        if (pos >= limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + pos);\r\n        }\r\n\r\n        return 0xff & buffer[origin + pos];\r\n    }\r\n\r\n    /**\r\n     * Return next 8-bit unsigned int from buffer.\r\n     */\r\n    public final int getUint8() {\r\n        if (position >= origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position - origin));\r\n        }\r\n\r\n        return 0xff & buffer[position++];\r\n    }\r\n\r\n    /**\r\n     * Return 16-bit signed int from buffer. (little-endian)\r\n     * \r\n     * @see mysql-5.1.60/include/my_global.h - sint2korr\r\n     */\r\n    public final int getInt16(final int pos) {\r\n        final int position = origin + pos;\r\n\r\n        if (pos + 1 >= limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (pos < 0 ? pos : (pos + 1)));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return (0xff & buf[position]) | ((buf[position + 1]) << 8);\r\n    }\r\n\r\n    /**\r\n     * Return next 16-bit signed int from buffer. (little-endian)\r\n     * \r\n     * @see mysql-5.1.60/include/my_global.h - sint2korr\r\n     */\r\n    public final int getInt16() {\r\n        if (position + 1 >= origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position - origin + 1));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return (0xff & buf[position++]) | ((buf[position++]) << 8);\r\n    }\r\n\r\n    /**\r\n     * Return 16-bit unsigned int from buffer. (little-endian)\r\n     * \r\n     * @see mysql-5.1.60/include/my_global.h - uint2korr\r\n     */\r\n    public final int getUint16(final int pos) {\r\n        final int position = origin + pos;\r\n\r\n        if (pos + 1 >= limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (pos < 0 ? pos : (pos + 1)));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return (0xff & buf[position]) | ((0xff & buf[position + 1]) << 8);\r\n    }\r\n\r\n    /**\r\n     * Return next 16-bit unsigned int from buffer. (little-endian)\r\n     * \r\n     * @see mysql-5.1.60/include/my_global.h - uint2korr\r\n     */\r\n    public final int getUint16() {\r\n        if (position + 1 >= origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position - origin + 1));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return (0xff & buf[position++]) | ((0xff & buf[position++]) << 8);\r\n    }\r\n\r\n    /**\r\n     * Return 16-bit signed int from buffer. (big-endian)\r\n     * \r\n     * @see mysql-5.6.10/include/myisampack.h - mi_sint2korr\r\n     */\r\n    public final int getBeInt16(final int pos) {\r\n        final int position = origin + pos;\r\n        if (pos + 1 >= limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (pos < 0 ? pos : (pos + 1)));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return (0xff & buf[position + 1]) | ((buf[position]) << 8);\r\n    }\r\n\r\n    /**\r\n     * Return next 16-bit signed int from buffer. (big-endian)\r\n     * \r\n     * @see mysql-5.1.60/include/my_global.h - mi_sint2korr\r\n     */\r\n    public final int getBeInt16() {\r\n        if (position + 1 >= origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position - origin + 1));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return (buf[position++] << 8) | (0xff & buf[position++]);\r\n    }\r\n\r\n    /**\r\n     * Return 16-bit unsigned int from buffer. (big-endian)\r\n     * \r\n     * @see mysql-5.6.10/include/myisampack.h - mi_usint2korr\r\n     */\r\n    public final int getBeUint16(final int pos) {\r\n        final int position = origin + pos;\r\n        if (pos + 1 >= limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (pos < 0 ? pos : (pos + 1)));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return (0xff & buf[position + 1]) | ((0xff & buf[position]) << 8);\r\n    }\r\n\r\n    /**\r\n     * Return next 16-bit unsigned int from buffer. (big-endian)\r\n     * \r\n     * @see mysql-5.6.10/include/myisampack.h - mi_usint2korr\r\n     */\r\n    public final int getBeUint16() {\r\n        if (position + 1 >= origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position - origin + 1));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return ((0xff & buf[position++]) << 8) | (0xff & buf[position++]);\r\n    }\r\n\r\n    /**\r\n     * Return 24-bit signed int from buffer. (little-endian)\r\n     * \r\n     * @see mysql-5.1.60/include/my_global.h - sint3korr\r\n     */\r\n    public final int getInt24(final int pos) {\r\n        final int position = origin + pos;\r\n\r\n        if (pos + 2 >= limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (pos < 0 ? pos : (pos + 2)));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return (0xff & buf[position]) | ((0xff & buf[position + 1]) << 8) | ((buf[position + 2]) << 16);\r\n    }\r\n\r\n    /**\r\n     * Return next 24-bit signed int from buffer. (little-endian)\r\n     * \r\n     * @see mysql-5.1.60/include/my_global.h - sint3korr\r\n     */\r\n    public final int getInt24() {\r\n        if (position + 2 >= origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position - origin + 2));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return (0xff & buf[position++]) | ((0xff & buf[position++]) << 8) | ((buf[position++]) << 16);\r\n    }\r\n\r\n    /**\r\n     * Return 24-bit signed int from buffer. (big-endian)\r\n     * \r\n     * @see mysql-5.6.10/include/myisampack.h - mi_usint3korr\r\n     */\r\n    public final int getBeInt24(final int pos) {\r\n        final int position = origin + pos;\r\n\r\n        if (pos + 2 >= limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (pos < 0 ? pos : (pos + 2)));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return (0xff & buf[position + 2]) | ((0xff & buf[position + 1]) << 8) | ((buf[position]) << 16);\r\n    }\r\n\r\n    /**\r\n     * Return next 24-bit signed int from buffer. (big-endian)\r\n     * \r\n     * @see mysql-5.6.10/include/myisampack.h - mi_usint3korr\r\n     */\r\n    public final int getBeInt24() {\r\n        if (position + 2 >= origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position - origin + 2));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return ((buf[position++]) << 16) | ((0xff & buf[position++]) << 8) | (0xff & buf[position++]);\r\n    }\r\n\r\n    /**\r\n     * Return 24-bit unsigned int from buffer. (little-endian)\r\n     * \r\n     * @see mysql-5.1.60/include/my_global.h - uint3korr\r\n     */\r\n    public final int getUint24(final int pos) {\r\n        final int position = origin + pos;\r\n\r\n        if (pos + 2 >= limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (pos < 0 ? pos : (pos + 2)));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return (0xff & buf[position]) | ((0xff & buf[position + 1]) << 8) | ((0xff & buf[position + 2]) << 16);\r\n    }\r\n\r\n    /**\r\n     * Return next 24-bit unsigned int from buffer. (little-endian)\r\n     * \r\n     * @see mysql-5.1.60/include/my_global.h - uint3korr\r\n     */\r\n    public final int getUint24() {\r\n        if (position + 2 >= origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position - origin + 2));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return (0xff & buf[position++]) | ((0xff & buf[position++]) << 8) | ((0xff & buf[position++]) << 16);\r\n    }\r\n\r\n    /**\r\n     * Return 24-bit unsigned int from buffer. (big-endian)\r\n     * \r\n     * @see mysql-5.6.10/include/myisampack.h - mi_usint3korr\r\n     */\r\n    public final int getBeUint24(final int pos) {\r\n        final int position = origin + pos;\r\n\r\n        if (pos + 2 >= limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (pos < 0 ? pos : (pos + 2)));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return (0xff & buf[position + 2]) | ((0xff & buf[position + 1]) << 8) | ((0xff & buf[position]) << 16);\r\n    }\r\n\r\n    /**\r\n     * Return next 24-bit unsigned int from buffer. (big-endian)\r\n     * \r\n     * @see mysql-5.6.10/include/myisampack.h - mi_usint3korr\r\n     */\r\n    public final int getBeUint24() {\r\n        if (position + 2 >= origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position - origin + 2));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return ((0xff & buf[position++]) << 16) | ((0xff & buf[position++]) << 8) | (0xff & buf[position++]);\r\n    }\r\n\r\n    /**\r\n     * Return 32-bit signed int from buffer. (little-endian)\r\n     * \r\n     * @see mysql-5.1.60/include/my_global.h - sint4korr\r\n     */\r\n    public final int getInt32(final int pos) {\r\n        final int position = origin + pos;\r\n\r\n        if (pos + 3 >= limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (pos < 0 ? pos : (pos + 3)));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return (0xff & buf[position]) | ((0xff & buf[position + 1]) << 8) | ((0xff & buf[position + 2]) << 16)\r\n               | ((buf[position + 3]) << 24);\r\n    }\r\n\r\n    /**\r\n     * Return 32-bit signed int from buffer. (big-endian)\r\n     * \r\n     * @see mysql-5.6.10/include/myisampack.h - mi_sint4korr\r\n     */\r\n    public final int getBeInt32(final int pos) {\r\n        final int position = origin + pos;\r\n\r\n        if (pos + 3 >= limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (pos < 0 ? pos : (pos + 3)));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return (0xff & buf[position + 3]) | ((0xff & buf[position + 2]) << 8) | ((0xff & buf[position + 1]) << 16)\r\n               | ((buf[position]) << 24);\r\n    }\r\n\r\n    /**\r\n     * Return next 32-bit signed int from buffer. (little-endian)\r\n     * \r\n     * @see mysql-5.1.60/include/my_global.h - sint4korr\r\n     */\r\n    public final int getInt32() {\r\n        if (position + 3 >= origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position - origin + 3));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return (0xff & buf[position++]) | ((0xff & buf[position++]) << 8) | ((0xff & buf[position++]) << 16)\r\n               | ((buf[position++]) << 24);\r\n    }\r\n\r\n    /**\r\n     * Return next 32-bit signed int from buffer. (big-endian)\r\n     * \r\n     * @see mysql-5.6.10/include/myisampack.h - mi_sint4korr\r\n     */\r\n    public final int getBeInt32() {\r\n        if (position + 3 >= origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position - origin + 3));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return ((buf[position++]) << 24) | ((0xff & buf[position++]) << 16) | ((0xff & buf[position++]) << 8)\r\n               | (0xff & buf[position++]);\r\n    }\r\n\r\n    /**\r\n     * Return 32-bit unsigned int from buffer. (little-endian)\r\n     * \r\n     * @see mysql-5.1.60/include/my_global.h - uint4korr\r\n     */\r\n    public final long getUint32(final int pos) {\r\n        final int position = origin + pos;\r\n\r\n        if (pos + 3 >= limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (pos < 0 ? pos : (pos + 3)));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return ((long) (0xff & buf[position])) | ((long) (0xff & buf[position + 1]) << 8)\r\n               | ((long) (0xff & buf[position + 2]) << 16) | ((long) (0xff & buf[position + 3]) << 24);\r\n    }\r\n\r\n    /**\r\n     * Return 32-bit unsigned int from buffer. (big-endian)\r\n     * \r\n     * @see mysql-5.6.10/include/myisampack.h - mi_usint4korr\r\n     */\r\n    public final long getBeUint32(final int pos) {\r\n        final int position = origin + pos;\r\n\r\n        if (pos + 3 >= limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (pos < 0 ? pos : (pos + 3)));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return ((long) (0xff & buf[position + 3])) | ((long) (0xff & buf[position + 2]) << 8)\r\n               | ((long) (0xff & buf[position + 1]) << 16) | ((long) (0xff & buf[position]) << 24);\r\n    }\r\n\r\n    /**\r\n     * Return next 32-bit unsigned int from buffer. (little-endian)\r\n     * \r\n     * @see mysql-5.1.60/include/my_global.h - uint4korr\r\n     */\r\n    public final long getUint32() {\r\n        if (position + 3 >= origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position - origin + 3));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return ((long) (0xff & buf[position++])) | ((long) (0xff & buf[position++]) << 8)\r\n               | ((long) (0xff & buf[position++]) << 16) | ((long) (0xff & buf[position++]) << 24);\r\n    }\r\n\r\n    /**\r\n     * Return next 32-bit unsigned int from buffer. (big-endian)\r\n     * \r\n     * @see mysql-5.6.10/include/myisampack.h - mi_uint4korr\r\n     */\r\n    public final long getBeUint32() {\r\n        if (position + 3 >= origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position - origin + 3));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return ((long) (0xff & buf[position++]) << 24) | ((long) (0xff & buf[position++]) << 16)\r\n               | ((long) (0xff & buf[position++]) << 8) | ((long) (0xff & buf[position++]));\r\n    }\r\n\r\n    /**\r\n     * Return 40-bit unsigned int from buffer. (little-endian)\r\n     */\r\n    public final long getUlong40(final int pos) {\r\n        final int position = origin + pos;\r\n\r\n        if (pos + 4 >= limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (pos < 0 ? pos : (pos + 4)));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return ((long) (0xff & buf[position])) | ((long) (0xff & buf[position + 1]) << 8)\r\n               | ((long) (0xff & buf[position + 2]) << 16) | ((long) (0xff & buf[position + 3]) << 24)\r\n               | ((long) (0xff & buf[position + 4]) << 32);\r\n    }\r\n\r\n    /**\r\n     * Return next 40-bit unsigned int from buffer. (little-endian)\r\n     */\r\n    public final long getUlong40() {\r\n        if (position + 4 >= origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position - origin + 4));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return ((long) (0xff & buf[position++])) | ((long) (0xff & buf[position++]) << 8)\r\n               | ((long) (0xff & buf[position++]) << 16) | ((long) (0xff & buf[position++]) << 24)\r\n               | ((long) (0xff & buf[position++]) << 32);\r\n    }\r\n\r\n    /**\r\n     * Return 40-bit unsigned int from buffer. (big-endian)\r\n     * \r\n     * @see mysql-5.6.10/include/myisampack.h - mi_uint5korr\r\n     */\r\n    public final long getBeUlong40(final int pos) {\r\n        final int position = origin + pos;\r\n\r\n        if (pos + 4 >= limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (pos < 0 ? pos : (pos + 4)));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return ((long) (0xff & buf[position + 4])) | ((long) (0xff & buf[position + 3]) << 8)\r\n               | ((long) (0xff & buf[position + 2]) << 16) | ((long) (0xff & buf[position + 1]) << 24)\r\n               | ((long) (0xff & buf[position]) << 32);\r\n    }\r\n\r\n    /**\r\n     * Return next 40-bit unsigned int from buffer. (big-endian)\r\n     * \r\n     * @see mysql-5.6.10/include/myisampack.h - mi_uint5korr\r\n     */\r\n    public final long getBeUlong40() {\r\n        if (position + 4 >= origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position - origin + 4));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return ((long) (0xff & buf[position++]) << 32) | ((long) (0xff & buf[position++]) << 24)\r\n               | ((long) (0xff & buf[position++]) << 16) | ((long) (0xff & buf[position++]) << 8)\r\n               | ((long) (0xff & buf[position++]));\r\n    }\r\n\r\n    /**\r\n     * Return 48-bit signed long from buffer. (little-endian)\r\n     * \r\n     * @see mysql-5.1.60/include/my_global.h - sint6korr\r\n     */\r\n    public final long getLong48(final int pos) {\r\n        final int position = origin + pos;\r\n\r\n        if (pos + 5 >= limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (pos < 0 ? pos : (pos + 5)));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return ((long) (0xff & buf[position])) | ((long) (0xff & buf[position + 1]) << 8)\r\n               | ((long) (0xff & buf[position + 2]) << 16) | ((long) (0xff & buf[position + 3]) << 24)\r\n               | ((long) (0xff & buf[position + 4]) << 32) | ((long) (buf[position + 5]) << 40);\r\n    }\r\n\r\n    /**\r\n     * Return 48-bit signed long from buffer. (big-endian)\r\n     * \r\n     * @see mysql-5.6.10/include/myisampack.h - mi_sint6korr\r\n     */\r\n    public final long getBeLong48(final int pos) {\r\n        final int position = origin + pos;\r\n\r\n        if (pos + 5 >= limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (pos < 0 ? pos : (pos + 5)));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return ((long) (0xff & buf[position + 5])) | ((long) (0xff & buf[position + 4]) << 8)\r\n               | ((long) (0xff & buf[position + 3]) << 16) | ((long) (0xff & buf[position + 2]) << 24)\r\n               | ((long) (0xff & buf[position + 1]) << 32) | ((long) (buf[position]) << 40);\r\n    }\r\n\r\n    /**\r\n     * Return next 48-bit signed long from buffer. (little-endian)\r\n     * \r\n     * @see mysql-5.1.60/include/my_global.h - sint6korr\r\n     */\r\n    public final long getLong48() {\r\n        if (position + 5 >= origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position - origin + 5));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return ((long) (0xff & buf[position++])) | ((long) (0xff & buf[position++]) << 8)\r\n               | ((long) (0xff & buf[position++]) << 16) | ((long) (0xff & buf[position++]) << 24)\r\n               | ((long) (0xff & buf[position++]) << 32) | ((long) (buf[position++]) << 40);\r\n    }\r\n\r\n    /**\r\n     * Return next 48-bit signed long from buffer. (Big-endian)\r\n     * \r\n     * @see mysql-5.6.10/include/myisampack.h - mi_sint6korr\r\n     */\r\n    public final long getBeLong48() {\r\n        if (position + 5 >= origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position - origin + 5));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return ((long) (buf[position++]) << 40) | ((long) (0xff & buf[position++]) << 32)\r\n               | ((long) (0xff & buf[position++]) << 24) | ((long) (0xff & buf[position++]) << 16)\r\n               | ((long) (0xff & buf[position++]) << 8) | ((long) (0xff & buf[position++]));\r\n    }\r\n\r\n    /**\r\n     * Return 48-bit unsigned long from buffer. (little-endian)\r\n     * \r\n     * @see mysql-5.1.60/include/my_global.h - uint6korr\r\n     */\r\n    public final long getUlong48(final int pos) {\r\n        final int position = origin + pos;\r\n\r\n        if (pos + 5 >= limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (pos < 0 ? pos : (pos + 5)));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return ((long) (0xff & buf[position])) | ((long) (0xff & buf[position + 1]) << 8)\r\n               | ((long) (0xff & buf[position + 2]) << 16) | ((long) (0xff & buf[position + 3]) << 24)\r\n               | ((long) (0xff & buf[position + 4]) << 32) | ((long) (0xff & buf[position + 5]) << 40);\r\n    }\r\n\r\n    /**\r\n     * Return 48-bit unsigned long from buffer. (big-endian)\r\n     * \r\n     * @see mysql-5.6.10/include/myisampack.h - mi_uint6korr\r\n     */\r\n    public final long getBeUlong48(final int pos) {\r\n        final int position = origin + pos;\r\n\r\n        if (pos + 5 >= limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (pos < 0 ? pos : (pos + 5)));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return ((long) (0xff & buf[position + 5])) | ((long) (0xff & buf[position + 4]) << 8)\r\n               | ((long) (0xff & buf[position + 3]) << 16) | ((long) (0xff & buf[position + 2]) << 24)\r\n               | ((long) (0xff & buf[position + 1]) << 32) | ((long) (0xff & buf[position]) << 40);\r\n    }\r\n\r\n    /**\r\n     * Return next 48-bit unsigned long from buffer. (little-endian)\r\n     * \r\n     * @see mysql-5.1.60/include/my_global.h - uint6korr\r\n     */\r\n    public final long getUlong48() {\r\n        if (position + 5 >= origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position - origin + 5));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return ((long) (0xff & buf[position++])) | ((long) (0xff & buf[position++]) << 8)\r\n               | ((long) (0xff & buf[position++]) << 16) | ((long) (0xff & buf[position++]) << 24)\r\n               | ((long) (0xff & buf[position++]) << 32) | ((long) (0xff & buf[position++]) << 40);\r\n    }\r\n\r\n    /**\r\n     * Return next 48-bit unsigned long from buffer. (big-endian)\r\n     * \r\n     * @see mysql-5.6.10/include/myisampack.h - mi_uint6korr\r\n     */\r\n    public final long getBeUlong48() {\r\n        if (position + 5 >= origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position - origin + 5));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return ((long) (0xff & buf[position++]) << 40) | ((long) (0xff & buf[position++]) << 32)\r\n               | ((long) (0xff & buf[position++]) << 24) | ((long) (0xff & buf[position++]) << 16)\r\n               | ((long) (0xff & buf[position++]) << 8) | ((long) (0xff & buf[position++]));\r\n    }\r\n\r\n    /**\r\n     * Return 56-bit unsigned int from buffer. (little-endian)\r\n     */\r\n    public final long getUlong56(final int pos) {\r\n        final int position = origin + pos;\r\n\r\n        if (pos + 6 >= limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (pos < 0 ? pos : (pos + 6)));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return ((long) (0xff & buf[position])) | ((long) (0xff & buf[position + 1]) << 8)\r\n               | ((long) (0xff & buf[position + 2]) << 16) | ((long) (0xff & buf[position + 3]) << 24)\r\n               | ((long) (0xff & buf[position + 4]) << 32) | ((long) (0xff & buf[position + 5]) << 40)\r\n               | ((long) (0xff & buf[position + 6]) << 48);\r\n    }\r\n\r\n    /**\r\n     * Return next 56-bit unsigned int from buffer. (little-endian)\r\n     */\r\n    public final long getUlong56() {\r\n        if (position + 6 >= origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position - origin + 6));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return ((long) (0xff & buf[position++])) | ((long) (0xff & buf[position++]) << 8)\r\n               | ((long) (0xff & buf[position++]) << 16) | ((long) (0xff & buf[position++]) << 24)\r\n               | ((long) (0xff & buf[position++]) << 32) | ((long) (0xff & buf[position++]) << 40)\r\n               | ((long) (0xff & buf[position++]) << 48);\r\n    }\r\n\r\n    /**\r\n     * Return 56-bit unsigned int from buffer. (big-endian)\r\n     */\r\n    public final long getBeUlong56(final int pos) {\r\n        final int position = origin + pos;\r\n\r\n        if (pos + 6 >= limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (pos < 0 ? pos : (pos + 6)));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return ((long) (0xff & buf[position + 6])) | ((long) (0xff & buf[position + 5]) << 8)\r\n               | ((long) (0xff & buf[position + 4]) << 16) | ((long) (0xff & buf[position + 3]) << 24)\r\n               | ((long) (0xff & buf[position + 2]) << 32) | ((long) (0xff & buf[position + 1]) << 40)\r\n               | ((long) (0xff & buf[position]) << 48);\r\n    }\r\n\r\n    /**\r\n     * Return next 56-bit unsigned int from buffer. (big-endian)\r\n     */\r\n    public final long getBeUlong56() {\r\n        if (position + 6 >= origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position - origin + 6));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return ((long) (0xff & buf[position++]) << 48) | ((long) (0xff & buf[position++]) << 40)\r\n               | ((long) (0xff & buf[position++]) << 32) | ((long) (0xff & buf[position++]) << 24)\r\n               | ((long) (0xff & buf[position++]) << 16) | ((long) (0xff & buf[position++]) << 8)\r\n               | ((long) (0xff & buf[position++]));\r\n    }\r\n\r\n    /**\r\n     * Return 64-bit signed long from buffer. (little-endian)\r\n     * \r\n     * @see mysql-5.1.60/include/my_global.h - sint8korr\r\n     */\r\n    public final long getLong64(final int pos) {\r\n        final int position = origin + pos;\r\n\r\n        if (pos + 7 >= limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (pos < 0 ? pos : (pos + 7)));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return ((long) (0xff & buf[position])) | ((long) (0xff & buf[position + 1]) << 8)\r\n               | ((long) (0xff & buf[position + 2]) << 16) | ((long) (0xff & buf[position + 3]) << 24)\r\n               | ((long) (0xff & buf[position + 4]) << 32) | ((long) (0xff & buf[position + 5]) << 40)\r\n               | ((long) (0xff & buf[position + 6]) << 48) | ((long) (buf[position + 7]) << 56);\r\n    }\r\n\r\n    /**\r\n     * Return 64-bit signed long from buffer. (big-endian)\r\n     * \r\n     * @see mysql-5.6.10/include/myisampack.h - mi_sint8korr\r\n     */\r\n    public final long getBeLong64(final int pos) {\r\n        final int position = origin + pos;\r\n\r\n        if (pos + 7 >= limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (pos < 0 ? pos : (pos + 7)));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return ((long) (0xff & buf[position + 7])) | ((long) (0xff & buf[position + 6]) << 8)\r\n               | ((long) (0xff & buf[position + 5]) << 16) | ((long) (0xff & buf[position + 4]) << 24)\r\n               | ((long) (0xff & buf[position + 3]) << 32) | ((long) (0xff & buf[position + 2]) << 40)\r\n               | ((long) (0xff & buf[position + 1]) << 48) | ((long) (buf[position]) << 56);\r\n    }\r\n\r\n    /**\r\n     * Return next 64-bit signed long from buffer. (little-endian)\r\n     * \r\n     * @see mysql-5.1.60/include/my_global.h - sint8korr\r\n     */\r\n    public final long getLong64() {\r\n        if (position + 7 >= origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position - origin + 7));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return ((long) (0xff & buf[position++])) | ((long) (0xff & buf[position++]) << 8)\r\n               | ((long) (0xff & buf[position++]) << 16) | ((long) (0xff & buf[position++]) << 24)\r\n               | ((long) (0xff & buf[position++]) << 32) | ((long) (0xff & buf[position++]) << 40)\r\n               | ((long) (0xff & buf[position++]) << 48) | ((long) (buf[position++]) << 56);\r\n    }\r\n\r\n    /**\r\n     * Return next 64-bit signed long from buffer. (big-endian)\r\n     * \r\n     * @see mysql-5.6.10/include/myisampack.h - mi_sint8korr\r\n     */\r\n    public final long getBeLong64() {\r\n        if (position + 7 >= origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position - origin + 7));\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        return ((long) (buf[position++]) << 56) | ((long) (0xff & buf[position++]) << 48)\r\n               | ((long) (0xff & buf[position++]) << 40) | ((long) (0xff & buf[position++]) << 32)\r\n               | ((long) (0xff & buf[position++]) << 24) | ((long) (0xff & buf[position++]) << 16)\r\n               | ((long) (0xff & buf[position++]) << 8) | ((long) (0xff & buf[position++]));\r\n    }\r\n\r\n    /* The max ulonglong - 0x ff ff ff ff ff ff ff ff */\r\n    public static final BigInteger BIGINT_MAX_VALUE = new BigInteger(\"18446744073709551615\");\r\n\r\n    /**\r\n     * Return 64-bit unsigned long from buffer. (little-endian)\r\n     * \r\n     * @see mysql-5.1.60/include/my_global.h - uint8korr\r\n     */\r\n    public final BigInteger getUlong64(final int pos) {\r\n        final long long64 = getLong64(pos);\r\n\r\n        return (long64 >= 0) ? BigInteger.valueOf(long64) : BIGINT_MAX_VALUE.add(BigInteger.valueOf(1 + long64));\r\n    }\r\n\r\n    /**\r\n     * Return 64-bit unsigned long from buffer. (big-endian)\r\n     * \r\n     * @see mysql-5.6.10/include/myisampack.h - mi_uint8korr\r\n     */\r\n    public final BigInteger getBeUlong64(final int pos) {\r\n        final long long64 = getBeLong64(pos);\r\n\r\n        return (long64 >= 0) ? BigInteger.valueOf(long64) : BIGINT_MAX_VALUE.add(BigInteger.valueOf(1 + long64));\r\n    }\r\n\r\n    /**\r\n     * Return next 64-bit unsigned long from buffer. (little-endian)\r\n     * \r\n     * @see mysql-5.1.60/include/my_global.h - uint8korr\r\n     */\r\n    public final BigInteger getUlong64() {\r\n        final long long64 = getLong64();\r\n\r\n        return (long64 >= 0) ? BigInteger.valueOf(long64) : BIGINT_MAX_VALUE.add(BigInteger.valueOf(1 + long64));\r\n    }\r\n\r\n    /**\r\n     * Return next 64-bit unsigned long from buffer. (big-endian)\r\n     * \r\n     * @see mysql-5.6.10/include/myisampack.h - mi_uint8korr\r\n     */\r\n    public final BigInteger getBeUlong64() {\r\n        final long long64 = getBeLong64();\r\n\r\n        return (long64 >= 0) ? BigInteger.valueOf(long64) : BIGINT_MAX_VALUE.add(BigInteger.valueOf(1 + long64));\r\n    }\r\n\r\n    /**\r\n     * Return 32-bit float from buffer. (little-endian)\r\n     * \r\n     * @see mysql-5.1.60/include/my_global.h - float4get\r\n     */\r\n    public final float getFloat32(final int pos) {\r\n        return Float.intBitsToFloat(getInt32(pos));\r\n    }\r\n\r\n    /**\r\n     * Return next 32-bit float from buffer. (little-endian)\r\n     * \r\n     * @see mysql-5.1.60/include/my_global.h - float4get\r\n     */\r\n    public final float getFloat32() {\r\n        return Float.intBitsToFloat(getInt32());\r\n    }\r\n\r\n    /**\r\n     * Return 64-bit double from buffer. (little-endian)\r\n     * \r\n     * @see mysql-5.1.60/include/my_global.h - float8get\r\n     */\r\n    public final double getDouble64(final int pos) {\r\n        return Double.longBitsToDouble(getLong64(pos));\r\n    }\r\n\r\n    /**\r\n     * Return next 64-bit double from buffer. (little-endian)\r\n     * \r\n     * @see mysql-5.1.60/include/my_global.h - float8get\r\n     */\r\n    public final double getDouble64() {\r\n        return Double.longBitsToDouble(getLong64());\r\n    }\r\n\r\n    public static final long NULL_LENGTH = ((long) ~0);\r\n\r\n    /**\r\n     * Return packed number from buffer. (little-endian) A Packed Integer has\r\n     * the capacity of storing up to 8-byte integers, while small integers still\r\n     * can use 1, 3, or 4 bytes. The value of the first byte determines how to\r\n     * read the number, according to the following table.\r\n     * <ul>\r\n     * <li>0-250 The first byte is the number (in the range 0-250). No\r\n     * additional bytes are used.</li>\r\n     * <li>252 Two more bytes are used. The number is in the range 251-0xffff.</li>\r\n     * <li>253 Three more bytes are used. The number is in the range\r\n     * 0xffff-0xffffff.</li>\r\n     * <li>254 Eight more bytes are used. The number is in the range\r\n     * 0xffffff-0xffffffffffffffff.</li>\r\n     * </ul>\r\n     * That representation allows a first byte value of 251 to represent the SQL\r\n     * NULL value.\r\n     */\r\n    public final long getPackedLong(final int pos) {\r\n        final int lead = getUint8(pos);\r\n        if (lead < 251) return lead;\r\n\r\n        switch (lead) {\r\n            case 251:\r\n                return NULL_LENGTH;\r\n            case 252:\r\n                return getUint16(pos + 1);\r\n            case 253:\r\n                return getUint24(pos + 1);\r\n            default: /* Must be 254 when here */\r\n                return getUint32(pos + 1);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Return next packed number from buffer. (little-endian)\r\n     * \r\n     * @see LogBuffer#getPackedLong(int)\r\n     */\r\n    public final long getPackedLong() {\r\n        final int lead = getUint8();\r\n        if (lead < 251) return lead;\r\n\r\n        switch (lead) {\r\n            case 251:\r\n                return NULL_LENGTH;\r\n            case 252:\r\n                return getUint16();\r\n            case 253:\r\n                return getUint24();\r\n            default: /* Must be 254 when here */\r\n                final long value = getUint32();\r\n                position += 4; /* ignore other */\r\n                return value;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Return fix length string from buffer.\r\n     */\r\n    public final String getFixString(final int pos, final int len) {\r\n        return getFixString(pos, len, StandardCharsets.ISO_8859_1);\r\n    }\r\n\r\n    /**\r\n     * Return next fix length string from buffer.\r\n     */\r\n    public final String getFixString(final int len) {\r\n        return getFixString(len, StandardCharsets.ISO_8859_1);\r\n    }\r\n\r\n    /**\r\n     * Return fix length string from buffer.\r\n     */\r\n    public final String getFixString(final int pos, final int len, Charset charset) {\r\n        if (pos + len > limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (pos < 0 ? pos : (pos + len)));\r\n        }\r\n\r\n        final int from = origin + pos;\r\n        final int end = from + len;\r\n        byte[] buf = buffer;\r\n        int found = from;\r\n        for (; (found < end) && buf[found] != '\\0'; found++)\r\n            /* empty loop */;\r\n\r\n        return new String(buf, from, found - from, charset);\r\n    }\r\n\r\n    /**\r\n     * Return next fix length string from buffer.\r\n     */\r\n    public final String getFixString(final int len, Charset charset) {\r\n        if (position + len > origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position + len - origin));\r\n        }\r\n\r\n        final int from = position;\r\n        final int end = from + len;\r\n        byte[] buf = buffer;\r\n        int found = from;\r\n        for (; (found < end) && buf[found] != '\\0'; found++)\r\n            /* empty loop */;\r\n\r\n        String string = new String(buf, from, found - from, charset);\r\n        position += len;\r\n        return string;\r\n    }\r\n\r\n    /**\r\n     * Return next fix length string from buffer.\r\n     * see json_binary.cc read_variable_length\r\n     */\r\n    public final String getFixLengthString(final int len, Charset charset) {\r\n        if (position + len > origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position + len - origin));\r\n        }\r\n\r\n        final int from = position;\r\n        byte[] buf = buffer;\r\n\r\n        String string = new String(buf, from, len, charset);\r\n        position += len;\r\n        return string;\r\n    }\r\n\r\n    public final String getFixName(final int len, Charset charset) {\r\n        if (position + len > origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position + len - origin));\r\n        }\r\n\r\n        final int from = position;\r\n        final int end = from + len;\r\n        byte[] buf = buffer;\r\n        int found = from;\r\n        for (; (found < end) && buf[found] != '\\0'; found++)\r\n            /* empty loop */;\r\n\r\n        int length = found - from;\r\n        String string = null;\r\n        if (length <= 16) {\r\n            string = NameCache.name(buf, from, length, charset);\r\n        }\r\n        if (string == null) {\r\n            string = new String(buf, from, length, charset);\r\n        }\r\n        position += len;\r\n        return string;\r\n    }\r\n\r\n    public final String getFixName(final int len) {\r\n        if (position + len > origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position + len - origin));\r\n        }\r\n\r\n        final int from = position;\r\n        final int end = from + len;\r\n        byte[] buf = buffer;\r\n        int found = from;\r\n        for (; (found < end) && buf[found] != '\\0'; found++)\r\n            /* empty loop */;\r\n\r\n        int length = found - from;\r\n        String string = null;\r\n        if (length <= 16) {\r\n            string = NameCache.name(buf, from, length, StandardCharsets.ISO_8859_1);\r\n        }\r\n        if (string == null) {\r\n            string = new String(buf, from, length, StandardCharsets.ISO_8859_1);\r\n        }\r\n        position += len;\r\n        return string;\r\n    }\r\n\r\n    /**\r\n     * Return fix-length string from buffer without null-terminate checking.\r\n     * Fix bug #17 {@link https://github.com/AlibabaTech/canal/issues/17 }\r\n     */\r\n    public final String getFullString(final int pos, final int len, Charset charset) {\r\n        if (pos + len > limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (pos < 0 ? pos : (pos + len)));\r\n        }\r\n\r\n        return new String(buffer, origin + pos, len, charset);\r\n    }\r\n\r\n    /**\r\n     * Return next fix-length string from buffer without null-terminate\r\n     * checking.\r\n     * Fix bug #17 {@link https://github.com/AlibabaTech/canal/issues/17 }\r\n     */\r\n    public final String getFullString(final int len, Charset charset) {\r\n        if (position + len > origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position + len - origin));\r\n        }\r\n\r\n        String string = new String(buffer, position, len, charset);\r\n        position += len;\r\n        return string;\r\n    }\r\n\r\n\r\n    /**\r\n     * Return dynamic length string from buffer.\r\n     */\r\n    public final String getString(final int pos) {\r\n        if (pos >= limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + pos);\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        final int len = (0xff & buf[origin + pos]);\r\n        if (pos + len + 1 > limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (pos + len + 1));\r\n        }\r\n\r\n        return new String(buf, origin + pos + 1, len, StandardCharsets.ISO_8859_1);\r\n    }\r\n\r\n    /**\r\n     * Return next dynamic length string from buffer.\r\n     */\r\n    public final String getString() {\r\n        if (position >= origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + position);\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        final int len = (0xff & buf[position]);\r\n        if (position + len + 1 > origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \"\r\n                                               + (position + len + 1 - origin));\r\n        }\r\n\r\n        String string = new String(buf, position + 1, len, StandardCharsets.ISO_8859_1);\r\n        position += len + 1;\r\n        return string;\r\n    }\r\n\r\n    public final String getName() {\r\n        if (position >= origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + position);\r\n        }\r\n\r\n        byte[] buf = buffer;\r\n        final int len = (0xff & buf[position]);\r\n        if (position + len + 1 > origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position + len + 1 - origin));\r\n        }\r\n\r\n        String string = NameCache.name(buf, position + 1, len, StandardCharsets.ISO_8859_1);\r\n        if (string == null) {\r\n            string = new String(buf, position + 1, len, StandardCharsets.ISO_8859_1);\r\n        }\r\n        position += len + 1;\r\n        return string;\r\n    }\r\n\r\n    /**\r\n     * Return 16-bit signed int from buffer. (big-endian)\r\n     * \r\n     * @see mysql-5.1.60/include/myisampack.h - mi_sint2korr\r\n     */\r\n    private static final int getInt16BE(byte[] buffer, final int pos) {\r\n        return ((buffer[pos]) << 8) | (0xff & buffer[pos + 1]);\r\n    }\r\n\r\n    /**\r\n     * Return 24-bit signed int from buffer. (big-endian)\r\n     * \r\n     * @see mysql-5.1.60/include/myisampack.h - mi_sint3korr\r\n     */\r\n    private static final int getInt24BE(byte[] buffer, final int pos) {\r\n        return (buffer[pos] << 16) | ((0xff & buffer[pos + 1]) << 8) | (0xff & buffer[pos + 2]);\r\n    }\r\n\r\n    /**\r\n     * Return 32-bit signed int from buffer. (big-endian)\r\n     * \r\n     * @see mysql-5.1.60/include/myisampack.h - mi_sint4korr\r\n     */\r\n    private static final int getInt32BE(byte[] buffer, final int pos) {\r\n        return (buffer[pos] << 24) | ((0xff & buffer[pos + 1]) << 16) | ((0xff & buffer[pos + 2]) << 8)\r\n               | (0xff & buffer[pos + 3]);\r\n    }\r\n\r\n    /* decimal representation */\r\n    public static final int DIG_PER_DEC1  = 9;\r\n    public static final int DIG_BASE      = 1000000000;\r\n    public static final int DIG_MAX       = DIG_BASE - 1;\r\n    public static final int dig2bytes[]   = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 4 };\r\n    public static final int powers10[]    = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };\r\n\r\n    public static final int DIG_PER_INT32 = 9;\r\n    public static final int SIZE_OF_INT32 = 4;\r\n\r\n    /**\r\n     * Return big decimal from buffer.\r\n     * \r\n     * @see mysql-5.1.60/strings/decimal.c - bin2decimal()\r\n     */\r\n    public final BigDecimal getDecimal(final int pos, final int precision, final int scale) {\r\n        final int intg = precision - scale;\r\n        final int frac = scale;\r\n        final int intg0 = intg / DIG_PER_INT32;\r\n        final int frac0 = frac / DIG_PER_INT32;\r\n        final int intg0x = intg - intg0 * DIG_PER_INT32;\r\n        final int frac0x = frac - frac0 * DIG_PER_INT32;\r\n\r\n        final int binSize = intg0 * SIZE_OF_INT32 + dig2bytes[intg0x] + frac0 * SIZE_OF_INT32 + dig2bytes[frac0x];\r\n        if (pos + binSize > limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (pos < 0 ? pos : (pos + binSize)));\r\n        }\r\n        return getDecimal0(origin + pos, intg, frac, // NL\r\n            intg0,\r\n            frac0,\r\n            intg0x,\r\n            frac0x);\r\n    }\r\n\r\n    /**\r\n     * Return next big decimal from buffer.\r\n     * \r\n     * @see mysql-5.1.60/strings/decimal.c - bin2decimal()\r\n     */\r\n    public final BigDecimal getDecimal(final int precision, final int scale) {\r\n        final int intg = precision - scale;\r\n        final int frac = scale;\r\n        final int intg0 = intg / DIG_PER_INT32;\r\n        final int frac0 = frac / DIG_PER_INT32;\r\n        final int intg0x = intg - intg0 * DIG_PER_INT32;\r\n        final int frac0x = frac - frac0 * DIG_PER_INT32;\r\n\r\n        final int binSize = intg0 * SIZE_OF_INT32 + dig2bytes[intg0x] + frac0 * SIZE_OF_INT32 + dig2bytes[frac0x];\r\n        if (position + binSize > origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position + binSize - origin));\r\n        }\r\n\r\n        BigDecimal decimal = getDecimal0(position, intg, frac, // NL\r\n            intg0,\r\n            frac0,\r\n            intg0x,\r\n            frac0x);\r\n        position += binSize;\r\n        return decimal;\r\n    }\r\n\r\n    /**\r\n     * Return big decimal from buffer.\r\n     * \r\n     * <pre>\r\n     * Decimal representation in binlog seems to be as follows:\r\n     * \r\n     * 1st bit - sign such that set == +, unset == -\r\n     * every 4 bytes represent 9 digits in big-endian order, so that\r\n     * if you print the values of these quads as big-endian integers one after\r\n     * another, you get the whole number string representation in decimal. What\r\n     * remains is to put a sign and a decimal dot.\r\n     * \r\n     * 80 00 00 05 1b 38 b0 60 00 means:\r\n     * \r\n     *   0x80 - positive \r\n     *   0x00000005 - 5\r\n     *   0x1b38b060 - 456700000\r\n     *   0x00       - 0\r\n     * \r\n     * 54567000000 / 10^{10} = 5.4567\r\n     * </pre>\r\n     * \r\n     * @see mysql-5.1.60/strings/decimal.c - bin2decimal()\r\n     * @see mysql-5.1.60/strings/decimal.c - decimal2string()\r\n     */\r\n    private final BigDecimal getDecimal0(final int begin, final int intg, final int frac, final int intg0,\r\n                                         final int frac0, final int intg0x, final int frac0x) {\r\n        final int mask = ((buffer[begin] & 0x80) == 0x80) ? 0 : -1;\r\n        int from = begin;\r\n\r\n        /* max string length */\r\n        final int len = ((mask != 0) ? 1 : 0) + ((intg != 0) ? intg : 1) // NL\r\n                        + ((frac != 0) ? 1 : 0) + frac;\r\n        char[] buf = new char[len];\r\n        int pos = 0;\r\n\r\n        if (mask != 0) /* decimal sign */\r\n        buf[pos++] = ('-');\r\n\r\n        final byte[] d_copy = buffer;\r\n        d_copy[begin] ^= 0x80; /* clear sign */\r\n        int mark = pos;\r\n\r\n        if (intg0x != 0) {\r\n            final int i = dig2bytes[intg0x];\r\n            int x = 0;\r\n            switch (i) {\r\n                case 1:\r\n                    x = d_copy[from] /* one byte */;\r\n                    break;\r\n                case 2:\r\n                    x = getInt16BE(d_copy, from);\r\n                    break;\r\n                case 3:\r\n                    x = getInt24BE(d_copy, from);\r\n                    break;\r\n                case 4:\r\n                    x = getInt32BE(d_copy, from);\r\n                    break;\r\n            }\r\n            from += i;\r\n            x ^= mask;\r\n            if (x < 0 || x >= powers10[intg0x + 1]) {\r\n                throw new IllegalArgumentException(\"bad format, x exceed: \" + x + \", \" + powers10[intg0x + 1]);\r\n            }\r\n            if (x != 0 /* !digit || x != 0 */) {\r\n                for (int j = intg0x; j > 0; j--) {\r\n                    final int divisor = powers10[j - 1];\r\n                    final int y = x / divisor;\r\n                    if (mark < pos || y != 0) {\r\n                        buf[pos++] = ((char) ('0' + y));\r\n                    }\r\n                    x -= y * divisor;\r\n                }\r\n            }\r\n        }\r\n\r\n        for (final int stop = from + intg0 * SIZE_OF_INT32; from < stop; from += SIZE_OF_INT32) {\r\n            int x = getInt32BE(d_copy, from);\r\n            x ^= mask;\r\n            if (x < 0 || x > DIG_MAX) {\r\n                throw new IllegalArgumentException(\"bad format, x exceed: \" + x + \", \" + DIG_MAX);\r\n            }\r\n            if (x != 0) {\r\n                if (mark < pos) {\r\n                    for (int i = DIG_PER_DEC1; i > 0; i--) {\r\n                        final int divisor = powers10[i - 1];\r\n                        final int y = x / divisor;\r\n                        buf[pos++] = ((char) ('0' + y));\r\n                        x -= y * divisor;\r\n                    }\r\n                } else {\r\n                    for (int i = DIG_PER_DEC1; i > 0; i--) {\r\n                        final int divisor = powers10[i - 1];\r\n                        final int y = x / divisor;\r\n                        if (mark < pos || y != 0) {\r\n                            buf[pos++] = ((char) ('0' + y));\r\n                        }\r\n                        x -= y * divisor;\r\n                    }\r\n                }\r\n            } else if (mark < pos) {\r\n                for (int i = DIG_PER_DEC1; i > 0; i--)\r\n                    buf[pos++] = ('0');\r\n            }\r\n        }\r\n\r\n        if (mark == pos)\r\n        /* fix 0.0 problem, only '.' may cause BigDecimal parsing exception. */\r\n        buf[pos++] = ('0');\r\n\r\n        if (frac > 0) {\r\n            buf[pos++] = ('.');\r\n            mark = pos;\r\n\r\n            for (final int stop = from + frac0 * SIZE_OF_INT32; from < stop; from += SIZE_OF_INT32) {\r\n                int x = getInt32BE(d_copy, from);\r\n                x ^= mask;\r\n                if (x < 0 || x > DIG_MAX) {\r\n                    throw new IllegalArgumentException(\"bad format, x exceed: \" + x + \", \" + DIG_MAX);\r\n                }\r\n                if (x != 0) {\r\n                    for (int i = DIG_PER_DEC1; i > 0; i--) {\r\n                        final int divisor = powers10[i - 1];\r\n                        final int y = x / divisor;\r\n                        buf[pos++] = ((char) ('0' + y));\r\n                        x -= y * divisor;\r\n                    }\r\n                } else {\r\n                    for (int i = DIG_PER_DEC1; i > 0; i--)\r\n                        buf[pos++] = ('0');\r\n                }\r\n            }\r\n\r\n            if (frac0x != 0) {\r\n                final int i = dig2bytes[frac0x];\r\n                int x = 0;\r\n                switch (i) {\r\n                    case 1:\r\n                        x = d_copy[from] /* one byte */;\r\n                        break;\r\n                    case 2:\r\n                        x = getInt16BE(d_copy, from);\r\n                        break;\r\n                    case 3:\r\n                        x = getInt24BE(d_copy, from);\r\n                        break;\r\n                    case 4:\r\n                        x = getInt32BE(d_copy, from);\r\n                        break;\r\n                }\r\n                x ^= mask;\r\n                if (x != 0) {\r\n                    final int dig = DIG_PER_DEC1 - frac0x;\r\n                    x *= powers10[dig];\r\n                    if (x < 0 || x > DIG_MAX) {\r\n                        throw new IllegalArgumentException(\"bad format, x exceed: \" + x + \", \" + DIG_MAX);\r\n                    }\r\n                    for (int j = DIG_PER_DEC1; j > dig; j--) {\r\n                        final int divisor = powers10[j - 1];\r\n                        final int y = x / divisor;\r\n                        buf[pos++] = ((char) ('0' + y));\r\n                        x -= y * divisor;\r\n                    }\r\n                }\r\n            }\r\n\r\n            if (mark == pos)\r\n            /* make number more friendly */\r\n            buf[pos++] = ('0');\r\n        }\r\n\r\n        d_copy[begin] ^= 0x80; /* restore sign */\r\n        // String decimal = String.valueOf(buf, 0, pos);\r\n        // return new BigDecimal(decimal);\r\n        return new BigDecimal(buf, 0, pos);\r\n    }\r\n\r\n    /**\r\n     * Fill MY_BITMAP structure from buffer.\r\n     * \r\n     * @param len The length of MY_BITMAP in bits.\r\n     */\r\n    public final void fillBitmap(BitSet bitmap, final int pos, final int len) {\r\n        if (pos + ((len + 7) / 8) > limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (pos + (len + 7) / 8));\r\n        }\r\n\r\n        fillBitmap0(bitmap, origin + pos, len);\r\n    }\r\n\r\n    /**\r\n     * Fill next MY_BITMAP structure from buffer.\r\n     * \r\n     * @param len The length of MY_BITMAP in bits.\r\n     */\r\n    public final void fillBitmap(BitSet bitmap, final int len) {\r\n        if (position + ((len + 7) / 8) > origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position + ((len + 7) / 8) - origin));\r\n        }\r\n\r\n        position = fillBitmap0(bitmap, position, len);\r\n    }\r\n\r\n    /**\r\n     * Fill MY_BITMAP structure from buffer.\r\n     * \r\n     * @param len The length of MY_BITMAP in bits.\r\n     */\r\n    private final int fillBitmap0(BitSet bitmap, int pos, final int len) {\r\n        final byte[] buf = buffer;\r\n\r\n        for (int bit = 0; bit < len; bit += 8) {\r\n            int flag = ((int) buf[pos++]) & 0xff;\r\n            if (flag == 0) {\r\n                continue;\r\n            }\r\n            if ((flag & 0x01) != 0) bitmap.set(bit);\r\n            if ((flag & 0x02) != 0) bitmap.set(bit + 1);\r\n            if ((flag & 0x04) != 0) bitmap.set(bit + 2);\r\n            if ((flag & 0x08) != 0) bitmap.set(bit + 3);\r\n            if ((flag & 0x10) != 0) bitmap.set(bit + 4);\r\n            if ((flag & 0x20) != 0) bitmap.set(bit + 5);\r\n            if ((flag & 0x40) != 0) bitmap.set(bit + 6);\r\n            if ((flag & 0x80) != 0) bitmap.set(bit + 7);\r\n        }\r\n        return pos;\r\n    }\r\n\r\n    /**\r\n     * Return MY_BITMAP structure from buffer.\r\n     * \r\n     * @param len The length of MY_BITMAP in bits.\r\n     */\r\n    public final BitSet getBitmap(final int pos, final int len) {\r\n        BitSet bitmap = new BitSet(len);\r\n        fillBitmap(bitmap, pos, len);\r\n        return bitmap;\r\n    }\r\n\r\n    /**\r\n     * Return next MY_BITMAP structure from buffer.\r\n     * \r\n     * @param len The length of MY_BITMAP in bits.\r\n     */\r\n    public final BitSet getBitmap(final int len) {\r\n        BitSet bitmap = new BitSet(len);\r\n        fillBitmap(bitmap, len);\r\n        return bitmap;\r\n    }\r\n\r\n    /**\r\n     * Fill n bytes into output stream.\r\n     */\r\n    public final void fillOutput(OutputStream out, final int pos, final int len) throws IOException {\r\n        if (pos + len > limit || pos < 0) throw new IllegalArgumentException(\"limit excceed: \" + (pos + len));\r\n\r\n        out.write(buffer, origin + pos, len);\r\n    }\r\n\r\n    /**\r\n     * Fill next n bytes into output stream.\r\n     */\r\n    public final void fillOutput(OutputStream out, final int len) throws IOException {\r\n        if (position + len > origin + limit) throw new IllegalArgumentException(\"limit excceed: \"\r\n                                                                                + (position + len - origin));\r\n\r\n        out.write(buffer, position, len);\r\n        position += len;\r\n    }\r\n\r\n    /**\r\n     * Fill n bytes in this buffer.\r\n     */\r\n    public final void fillBytes(final int pos, byte[] dest, final int destPos, final int len) {\r\n        if (pos + len > limit || pos < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (pos + len));\r\n        }\r\n\r\n        System.arraycopy(buffer, origin + pos, dest, destPos, len);\r\n    }\r\n\r\n    /**\r\n     * Fill next n bytes in this buffer.\r\n     */\r\n    public final void fillBytes(byte[] dest, final int destPos, final int len) {\r\n        if (position + len > origin + limit) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position + len - origin));\r\n        }\r\n\r\n        System.arraycopy(buffer, position, dest, destPos, len);\r\n        position += len;\r\n    }\r\n\r\n    /**\r\n     * Return n-byte data from buffer.\r\n     */\r\n    public final byte[] getData(final int pos, final int len) {\r\n        byte[] buf = new byte[len];\r\n        fillBytes(pos, buf, 0, len);\r\n        return buf;\r\n    }\r\n\r\n    /**\r\n     * Return next n-byte data from buffer.\r\n     */\r\n    public final byte[] getData(final int len) {\r\n        byte[] buf = new byte[len];\r\n        fillBytes(buf, 0, len);\r\n        return buf;\r\n    }\r\n\r\n    /**\r\n     * Return all remaining data from buffer.\r\n     */\r\n    public final byte[] getData() {\r\n        return getData(0, limit);\r\n    }\r\n\r\n    /**\r\n     * mariadb compress log event Get the length of uncompress content.\r\n     * \r\n     * @return 0 means error.\r\n     */\r\n    public final long getUncompressLong(int lenPad) {\r\n        long len = 0;\r\n        switch (lenPad) {\r\n            case 1:\r\n                len = getInt8();\r\n                break;\r\n            case 2:\r\n                len = getBeUint16();\r\n                break;\r\n            case 3:\r\n                len = getBeUint24();\r\n                break;\r\n            case 4:\r\n                len = getBeUint32();\r\n                break;\r\n            default:\r\n                len = 0;\r\n                break;\r\n        }\r\n\r\n        return len;\r\n    }\r\n\r\n    /**\r\n     * uncompress mariadb log event\r\n     * \r\n     * @return\r\n     */\r\n    public LogBuffer uncompressBuf() {\r\n        int lenPad = getInt8();\r\n        long len = getUncompressLong(lenPad & 0x07);\r\n        int alg = (lenPad & 0x70) >> 4;\r\n        LogBuffer buffer = null;\r\n        try {\r\n            switch (alg) {\r\n                case 0:\r\n                    buffer = uncompressZlib(limit - position);\r\n                    break;\r\n                default:\r\n                    // bad algorithm\r\n                    return this;\r\n            }\r\n        } catch (Exception e) {\r\n            throw new IllegalArgumentException(\"uncompress failed \", e);\r\n        }\r\n\r\n        if (buffer.limit() != len) {\r\n            throw new IllegalArgumentException(\r\n                \"uncompress lenght not match, expected : \" + len + \" , but actual : \" + buffer.limit());\r\n        }\r\n        return buffer;\r\n    }\r\n\r\n    private LogBuffer uncompressZlib(int len) throws Exception {\r\n        if (position + len > limit || position < 0) {\r\n            throw new IllegalArgumentException(\"limit excceed: \" + (position + len));\r\n        }\r\n\r\n        try (DeflateCompressorInputStream in = new DeflateCompressorInputStream(\r\n            new ByteArrayInputStream(buffer, position, position + len))) {\r\n            byte[] decodeBytes = IOUtils.toByteArray(in);\r\n            return new LogBuffer(decodeBytes, 0, decodeBytes.length);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Return full hexdump from position.\r\n     */\r\n    public final String hexdump(final int pos) {\r\n        if ((limit - pos) > 0) {\r\n            final int begin = origin + pos;\r\n            final int end = origin + limit;\r\n\r\n            byte[] buf = buffer;\r\n            StringBuilder dump = new StringBuilder();\r\n            dump.append(Integer.toHexString(buf[begin] >> 4));\r\n            dump.append(Integer.toHexString(buf[begin] & 0xf));\r\n            for (int i = begin + 1; i < end; i++) {\r\n                dump.append(\"_\");\r\n                dump.append(Integer.toHexString(buf[i] >> 4));\r\n                dump.append(Integer.toHexString(buf[i] & 0xf));\r\n            }\r\n\r\n            return dump.toString();\r\n        }\r\n        return \"\";\r\n    }\r\n\r\n    /**\r\n     * Return hexdump from position, for len bytes.\r\n     */\r\n    public final String hexdump(final int pos, final int len) {\r\n        if ((limit - pos) > 0) {\r\n            final int begin = origin + pos;\r\n            final int end = Math.min(begin + len, origin + limit);\r\n\r\n            byte[] buf = buffer;\r\n            StringBuilder dump = new StringBuilder();\r\n            dump.append(Integer.toHexString(buf[begin] >> 4));\r\n            dump.append(Integer.toHexString(buf[begin] & 0xf));\r\n            for (int i = begin + 1; i < end; i++) {\r\n                dump.append(\"_\");\r\n                dump.append(Integer.toHexString(buf[i] >> 4));\r\n                dump.append(Integer.toHexString(buf[i] & 0xf));\r\n            }\r\n\r\n            return dump.toString();\r\n        }\r\n        return \"\";\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/LogContext.java",
    "content": "package com.taobao.tddl.dbsync.binlog;\r\n\r\nimport java.util.HashMap;\r\nimport java.util.Map;\r\n\r\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.GTIDSet;\r\nimport com.taobao.tddl.dbsync.binlog.event.FormatDescriptionLogEvent;\r\nimport com.taobao.tddl.dbsync.binlog.event.TableMapLogEvent;\r\n\r\n/**\r\n * TODO: Document Me!! NOTE: Log context will NOT write multi-threaded.\r\n * \r\n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\r\n * @version 1.0\r\n */\r\npublic final class LogContext {\r\n\r\n    private final Map<Long, TableMapLogEvent> mapOfTable = new HashMap<>();\r\n\r\n    private FormatDescriptionLogEvent         formatDescription;\r\n\r\n    private LogPosition                       logPosition;\r\n\r\n    private GTIDSet                           gtidSet;\r\n\r\n    private LogEvent                          gtidLogEvent; // save current gtid log event\r\n\r\n    private boolean                           iterateDecode = false;\r\n\r\n    private boolean                           compatiablePercona = false;\r\n\r\n    public LogContext(){\r\n        this.formatDescription = FormatDescriptionLogEvent.FORMAT_DESCRIPTION_EVENT_5_x;\r\n    }\r\n\r\n    public LogContext(FormatDescriptionLogEvent descriptionEvent){\r\n        this.formatDescription = descriptionEvent;\r\n    }\r\n\r\n    public final LogPosition getLogPosition() {\r\n        return logPosition;\r\n    }\r\n\r\n    public final void setLogPosition(LogPosition logPosition) {\r\n        this.logPosition = logPosition;\r\n    }\r\n\r\n    public final FormatDescriptionLogEvent getFormatDescription() {\r\n        return formatDescription;\r\n    }\r\n\r\n    public final void setFormatDescription(FormatDescriptionLogEvent formatDescription) {\r\n        this.formatDescription = formatDescription;\r\n    }\r\n\r\n    public final void putTable(TableMapLogEvent mapEvent) {\r\n        mapOfTable.put(Long.valueOf(mapEvent.getTableId()), mapEvent);\r\n    }\r\n\r\n    public final TableMapLogEvent getTable(final long tableId) {\r\n        return mapOfTable.get(Long.valueOf(tableId));\r\n    }\r\n\r\n    public final void clearAllTables() {\r\n        mapOfTable.clear();\r\n    }\r\n\r\n    public void reset() {\r\n        formatDescription = FormatDescriptionLogEvent.FORMAT_DESCRIPTION_EVENT_5_x;\r\n        mapOfTable.clear();\r\n    }\r\n\r\n    public GTIDSet getGtidSet() {\r\n        return gtidSet;\r\n    }\r\n\r\n    public void setGtidSet(GTIDSet gtidSet) {\r\n        this.gtidSet = gtidSet;\r\n    }\r\n\r\n    public LogEvent getGtidLogEvent() {\r\n        return gtidLogEvent;\r\n    }\r\n\r\n    public void setGtidLogEvent(LogEvent gtidLogEvent) {\r\n        this.gtidLogEvent = gtidLogEvent;\r\n    }\r\n\r\n    public boolean isIterateDecode() {\r\n        return iterateDecode;\r\n    }\r\n\r\n    public void setIterateDecode(boolean iterateDecode) {\r\n        this.iterateDecode = iterateDecode;\r\n    }\r\n\r\n    public boolean isCompatiablePercona() {\r\n        return compatiablePercona;\r\n    }\r\n\r\n    public void setCompatiablePercona(boolean compatiablePercona) {\r\n        this.compatiablePercona = compatiablePercona;\r\n    }\r\n}\r\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/LogDecoder.java",
    "content": "package com.taobao.tddl.dbsync.binlog;\r\n\r\nimport java.io.ByteArrayInputStream;\r\nimport java.io.IOException;\r\nimport java.util.BitSet;\r\nimport java.util.List;\r\n\r\nimport org.apache.commons.compress.compressors.zstandard.ZstdCompressorInputStream;\r\nimport org.apache.commons.compress.utils.Lists;\r\nimport org.apache.commons.io.IOUtils;\r\nimport org.apache.commons.logging.Log;\r\nimport org.apache.commons.logging.LogFactory;\r\n\r\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.GTIDSet;\r\nimport com.taobao.tddl.dbsync.binlog.event.*;\r\nimport com.taobao.tddl.dbsync.binlog.event.mariadb.*;\r\n\r\n/**\r\n * Implements a binary-log decoder.\r\n *\r\n * <pre>\r\n * LogDecoder decoder = new LogDecoder();\r\n * decoder.handle(...);\r\n * \r\n * LogEvent event;\r\n * do\r\n * {\r\n *     event = decoder.decode(buffer, context);\r\n * \r\n *     // process log event.\r\n * }\r\n * while (event != null);\r\n * // no more events in buffer.\r\n * </pre>\r\n *\r\n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\r\n * @version 1.0\r\n */\r\npublic final class LogDecoder {\r\n\r\n    protected static final Log logger    = LogFactory.getLog(LogDecoder.class);\r\n\r\n    protected final BitSet     handleSet = new BitSet(LogEvent.ENUM_END_EVENT);\r\n\r\n    public LogDecoder(){\r\n    }\r\n\r\n    public LogDecoder(final int fromIndex, final int toIndex){\r\n        handleSet.set(fromIndex, toIndex);\r\n    }\r\n\r\n    public final void handle(final int fromIndex, final int toIndex) {\r\n        handleSet.set(fromIndex, toIndex);\r\n    }\r\n\r\n    public final void handle(final int flagIndex) {\r\n        handleSet.set(flagIndex);\r\n    }\r\n\r\n    private LogBuffer compressIterateBuffer;\r\n\r\n    /**\r\n     * Decoding an event from binary-log buffer.\r\n     *\r\n     * @return <code>UknownLogEvent</code> if event type is unknown or skipped,\r\n     * <code>null</code> if buffer is not including a full event.\r\n     */\r\n    public LogEvent decode(LogBuffer buffer, LogContext context) throws IOException {\r\n        final int limit = buffer.limit();\r\n        if (limit >= FormatDescriptionLogEvent.LOG_EVENT_HEADER_LEN) {\r\n            LogHeader header = new LogHeader(buffer, context.getFormatDescription());\r\n\r\n            final int len = header.getEventLen();\r\n            if (limit >= len) {\r\n                LogEvent event;\r\n\r\n                /* Checking binary-log's header */\r\n                if (handleSet.get(header.getType())) {\r\n                    buffer.limit(len);\r\n                    try {\r\n                        /* Decoding binary-log to event */\r\n                        event = decode(buffer, header, context);\r\n                    } catch (IOException e) {\r\n                        if (logger.isWarnEnabled()) {\r\n                            logger.warn(\"Decoding \" + LogEvent.getTypeName(header.getType()) + \" failed from: \"\r\n                                        + context.getLogPosition(), e);\r\n                        }\r\n                        throw e;\r\n                    } finally {\r\n                        buffer.limit(limit); /* Restore limit */\r\n                    }\r\n                } else {\r\n                    /* Ignore unsupported binary-log. */\r\n                    event = new UnknownLogEvent(header);\r\n                }\r\n\r\n                if (event != null) {\r\n                    // set logFileName\r\n                    event.getHeader().setLogFileName(context.getLogPosition().getFileName());\r\n                    event.setSemival(buffer.semival);\r\n                }\r\n\r\n                /* consume this binary-log. */\r\n                buffer.consume(len);\r\n                return event;\r\n            }\r\n        }\r\n\r\n        /* Rewind buffer's position to 0. */\r\n        buffer.rewind();\r\n        return null;\r\n    }\r\n\r\n    /**\r\n     * * process compress binlog payload\r\n     * \r\n     * @param event\r\n     * @param context\r\n     * @return\r\n     * @throws IOException\r\n     */\r\n    public List<LogEvent> processIterateDecode(LogEvent event, LogContext context) throws IOException {\r\n        List<LogEvent> events = Lists.newArrayList();\r\n        if (event.getHeader().getType() == LogEvent.TRANSACTION_PAYLOAD_EVENT) {\r\n            // iterate for compresss payload\r\n            TransactionPayloadLogEvent compressEvent = ((TransactionPayloadLogEvent) event);\r\n            LogBuffer iterateBuffer = null;\r\n            if (compressEvent.isCompressByZstd()) {\r\n                try (ZstdCompressorInputStream in = new ZstdCompressorInputStream(\r\n                    new ByteArrayInputStream(compressEvent.getPayload()))) {\r\n                    byte[] decodeBytes = IOUtils.toByteArray(in);\r\n                    iterateBuffer = new LogBuffer(decodeBytes, 0, decodeBytes.length);\r\n                }\r\n            } else if (compressEvent.isCompressByNone()) {\r\n                iterateBuffer = new LogBuffer(compressEvent.getPayload(), 0, compressEvent.getPayload().length);\r\n            } else {\r\n                throw new IllegalArgumentException(\"unknow compress type for \" + event.getHeader().getLogFileName()\r\n                                                   + \":\" + event.getHeader().getLogPos());\r\n            }\r\n\r\n            try {\r\n                context.setIterateDecode(true);\r\n                while (iterateBuffer.hasRemaining()) {// iterate\r\n                    LogEvent deEvent = decode(iterateBuffer, context);\r\n                    if (deEvent == null) {\r\n                        break;\r\n                    }\r\n\r\n                    // compress event logPos = 0\r\n                    deEvent.getHeader().setLogFileName(event.getHeader().getLogFileName());\r\n                    deEvent.getHeader().setLogPos(event.getHeader().getLogPos());\r\n                    // 需要重置payload每个event的eventLen , ack位点更新依赖logPos - eventLen,\r\n                    // 原因:每个payload都是uncompress的eventLen,无法对应物理binlog的eventLen\r\n                    // 隐患:memory计算空间大小时会出现放大的情况,影响getBatch的数量\r\n                    deEvent.getHeader().setEventLen(event.getHeader().getEventLen());\r\n                    events.add(deEvent);\r\n                }\r\n            } finally {\r\n                context.setIterateDecode(false);\r\n            }\r\n        }\r\n        return events;\r\n    }\r\n\r\n    /**\r\n     * Deserialize an event from buffer.\r\n     *\r\n     * @return <code>UknownLogEvent</code> if event type is unknown or skipped.\r\n     */\r\n    public static LogEvent decode(LogBuffer buffer, LogHeader header, LogContext context) throws IOException {\r\n        FormatDescriptionLogEvent descriptionEvent = context.getFormatDescription();\r\n        LogPosition logPosition = context.getLogPosition();\r\n\r\n        int checksumAlg = LogEvent.BINLOG_CHECKSUM_ALG_UNDEF;\r\n        if (header.getType() != LogEvent.FORMAT_DESCRIPTION_EVENT) {\r\n            checksumAlg = descriptionEvent.header.getChecksumAlg();\r\n        } else {\r\n            // 如果是format事件自己，也需要处理checksum\r\n            checksumAlg = header.getChecksumAlg();\r\n        }\r\n\r\n        if (checksumAlg != LogEvent.BINLOG_CHECKSUM_ALG_OFF && checksumAlg != LogEvent.BINLOG_CHECKSUM_ALG_UNDEF) {\r\n            if (context.isIterateDecode()) {\r\n                // transaction compress payload在主事件已经处理了checksum,遍历解析event忽略checksum处理\r\n            } else {\r\n                // remove checksum bytes\r\n                buffer.limit(header.getEventLen() - LogEvent.BINLOG_CHECKSUM_LEN);\r\n            }\r\n        }\r\n        GTIDSet gtidSet = context.getGtidSet();\r\n        LogEvent gtidLogEvent = context.getGtidLogEvent();\r\n        switch (header.getType()) {\r\n            case LogEvent.QUERY_EVENT: {\r\n                QueryLogEvent event = new QueryLogEvent(header,\r\n                    buffer,\r\n                    descriptionEvent,\r\n                    context.isCompatiablePercona());\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                header.putGtid(context.getGtidSet(), gtidLogEvent);\r\n                return event;\r\n            }\r\n            case LogEvent.XID_EVENT: {\r\n                XidLogEvent event = new XidLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                header.putGtid(context.getGtidSet(), gtidLogEvent);\r\n                return event;\r\n            }\r\n            case LogEvent.TABLE_MAP_EVENT: {\r\n                TableMapLogEvent mapEvent = new TableMapLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                context.putTable(mapEvent);\r\n                return mapEvent;\r\n            }\r\n            case LogEvent.WRITE_ROWS_EVENT_V1:\r\n            case LogEvent.WRITE_ROWS_EVENT: {\r\n                RowsLogEvent event = new WriteRowsLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                event.fillTable(context);\r\n                header.putGtid(context.getGtidSet(), gtidLogEvent);\r\n                return event;\r\n            }\r\n            case LogEvent.UPDATE_ROWS_EVENT_V1:\r\n            case LogEvent.UPDATE_ROWS_EVENT: {\r\n                RowsLogEvent event = new UpdateRowsLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                event.fillTable(context);\r\n                header.putGtid(context.getGtidSet(), gtidLogEvent);\r\n                return event;\r\n            }\r\n            case LogEvent.DELETE_ROWS_EVENT_V1:\r\n            case LogEvent.DELETE_ROWS_EVENT: {\r\n                RowsLogEvent event = new DeleteRowsLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                event.fillTable(context);\r\n                header.putGtid(context.getGtidSet(), gtidLogEvent);\r\n                return event;\r\n            }\r\n            case LogEvent.ROTATE_EVENT: {\r\n                RotateLogEvent event = new RotateLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition = new LogPosition(event.getFilename(), event.getPosition());\r\n                context.setLogPosition(logPosition);\r\n                return event;\r\n            }\r\n            case LogEvent.LOAD_EVENT:\r\n            case LogEvent.NEW_LOAD_EVENT: {\r\n                LoadLogEvent event = new LoadLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                return event;\r\n            }\r\n            case LogEvent.SLAVE_EVENT: /* can never happen (unused event) */\r\n            {\r\n                if (logger.isWarnEnabled()) {\r\n                    logger.warn(\"Skipping unsupported SLAVE_EVENT from: \" + context.getLogPosition());\r\n                }\r\n                break;\r\n            }\r\n            case LogEvent.CREATE_FILE_EVENT: {\r\n                CreateFileLogEvent event = new CreateFileLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                return event;\r\n            }\r\n            case LogEvent.APPEND_BLOCK_EVENT: {\r\n                AppendBlockLogEvent event = new AppendBlockLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                return event;\r\n            }\r\n            case LogEvent.DELETE_FILE_EVENT: {\r\n                DeleteFileLogEvent event = new DeleteFileLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                return event;\r\n            }\r\n            case LogEvent.EXEC_LOAD_EVENT: {\r\n                ExecuteLoadLogEvent event = new ExecuteLoadLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                return event;\r\n            }\r\n            case LogEvent.START_EVENT_V3: {\r\n                /* This is sent only by MySQL <=4.x */\r\n                StartLogEventV3 event = new StartLogEventV3(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                return event;\r\n            }\r\n            case LogEvent.STOP_EVENT: {\r\n                StopLogEvent event = new StopLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                return event;\r\n            }\r\n            case LogEvent.INTVAR_EVENT: {\r\n                IntvarLogEvent event = new IntvarLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                return event;\r\n            }\r\n            case LogEvent.RAND_EVENT: {\r\n                RandLogEvent event = new RandLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                header.putGtid(context.getGtidSet(), gtidLogEvent);\r\n                return event;\r\n            }\r\n            case LogEvent.USER_VAR_EVENT: {\r\n                UserVarLogEvent event = new UserVarLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                header.putGtid(context.getGtidSet(), gtidLogEvent);\r\n                return event;\r\n            }\r\n            case LogEvent.FORMAT_DESCRIPTION_EVENT: {\r\n                descriptionEvent = new FormatDescriptionLogEvent(header, buffer, descriptionEvent);\r\n                context.setFormatDescription(descriptionEvent);\r\n                return descriptionEvent;\r\n            }\r\n            case LogEvent.PRE_GA_WRITE_ROWS_EVENT: {\r\n                if (logger.isWarnEnabled()) {\r\n                    logger.warn(\"Skipping unsupported PRE_GA_WRITE_ROWS_EVENT from: \" + context.getLogPosition());\r\n                }\r\n                // ev = new Write_rows_log_event_old(buf, event_len,\r\n                // description_event);\r\n                break;\r\n            }\r\n            case LogEvent.PRE_GA_UPDATE_ROWS_EVENT: {\r\n                if (logger.isWarnEnabled()) {\r\n                    logger.warn(\"Skipping unsupported PRE_GA_UPDATE_ROWS_EVENT from: \" + context.getLogPosition());\r\n                }\r\n                // ev = new Update_rows_log_event_old(buf, event_len,\r\n                // description_event);\r\n                break;\r\n            }\r\n            case LogEvent.PRE_GA_DELETE_ROWS_EVENT: {\r\n                if (logger.isWarnEnabled()) {\r\n                    logger.warn(\"Skipping unsupported PRE_GA_DELETE_ROWS_EVENT from: \" + context.getLogPosition());\r\n                }\r\n                // ev = new Delete_rows_log_event_old(buf, event_len,\r\n                // description_event);\r\n                break;\r\n            }\r\n            case LogEvent.BEGIN_LOAD_QUERY_EVENT: {\r\n                BeginLoadQueryLogEvent event = new BeginLoadQueryLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                return event;\r\n            }\r\n            case LogEvent.EXECUTE_LOAD_QUERY_EVENT: {\r\n                ExecuteLoadQueryLogEvent event = new ExecuteLoadQueryLogEvent(header,\r\n                    buffer,\r\n                    descriptionEvent,\r\n                    context.isCompatiablePercona());\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                return event;\r\n            }\r\n            case LogEvent.INCIDENT_EVENT: {\r\n                IncidentLogEvent event = new IncidentLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                return event;\r\n            }\r\n            case LogEvent.HEARTBEAT_LOG_EVENT: {\r\n                HeartbeatLogEvent event = new HeartbeatLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                return event;\r\n            }\r\n            case LogEvent.IGNORABLE_LOG_EVENT: {\r\n                IgnorableLogEvent event = new IgnorableLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                return event;\r\n            }\r\n            case LogEvent.ROWS_QUERY_LOG_EVENT: {\r\n                RowsQueryLogEvent event = new RowsQueryLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                header.putGtid(context.getGtidSet(), gtidLogEvent);\r\n                return event;\r\n            }\r\n            case LogEvent.PARTIAL_UPDATE_ROWS_EVENT: {\r\n                RowsLogEvent event = new UpdateRowsLogEvent(header, buffer, descriptionEvent, true);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                event.fillTable(context);\r\n                header.putGtid(context.getGtidSet(), gtidLogEvent);\r\n                return event;\r\n            }\r\n            case LogEvent.GTID_LOG_EVENT:\r\n            case LogEvent.ANONYMOUS_GTID_LOG_EVENT: {\r\n                GtidLogEvent event = new GtidLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                if (gtidSet != null) {\r\n                    gtidSet.update(event.getGtidStr());\r\n                    // update latest gtid\r\n                    header.putGtid(gtidSet, event);\r\n                }\r\n                // update current gtid event to context\r\n                context.setGtidLogEvent(event);\r\n                return event;\r\n            }\r\n            case LogEvent.PREVIOUS_GTIDS_LOG_EVENT: {\r\n                PreviousGtidsLogEvent event = new PreviousGtidsLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                return event;\r\n            }\r\n            case LogEvent.TRANSACTION_CONTEXT_EVENT: {\r\n                TransactionContextLogEvent event = new TransactionContextLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                return event;\r\n            }\r\n            case LogEvent.TRANSACTION_PAYLOAD_EVENT: {\r\n                TransactionPayloadLogEvent event = new TransactionPayloadLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                return event;\r\n            }\r\n            case LogEvent.VIEW_CHANGE_EVENT: {\r\n                ViewChangeEvent event = new ViewChangeEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                return event;\r\n            }\r\n            case LogEvent.XA_PREPARE_LOG_EVENT: {\r\n                XaPrepareLogEvent event = new XaPrepareLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                return event;\r\n            }\r\n            case LogEvent.ANNOTATE_ROWS_EVENT: {\r\n                AnnotateRowsEvent event = new AnnotateRowsEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                header.putGtid(context.getGtidSet(), gtidLogEvent);\r\n                return event;\r\n            }\r\n            case LogEvent.BINLOG_CHECKPOINT_EVENT: {\r\n                BinlogCheckPointLogEvent event = new BinlogCheckPointLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                logPosition.fileName = event.getFilename();\r\n                return event;\r\n            }\r\n            case LogEvent.GTID_EVENT: {\r\n                MariaGtidLogEvent event = new MariaGtidLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                if (gtidSet != null) {\r\n                    gtidSet.update(event.getGtidStr());\r\n                    // update latest gtid\r\n                    header.putGtid(gtidSet, event);\r\n                }\r\n                // update current gtid event to context\r\n                context.setGtidLogEvent(event);\r\n                return event;\r\n            }\r\n            case LogEvent.GTID_LIST_EVENT: {\r\n                MariaGtidListLogEvent event = new MariaGtidListLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                if (gtidSet != null) {\r\n                    gtidSet.update(event.getGtidStr());\r\n                    // update latest gtid\r\n                    header.putGtid(gtidSet, event);\r\n                }\r\n                // update current gtid event to context\r\n                context.setGtidLogEvent(event);\r\n                return event;\r\n            }\r\n            case LogEvent.START_ENCRYPTION_EVENT: {\r\n                StartEncryptionLogEvent event = new StartEncryptionLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                return event;\r\n            }\r\n            case LogEvent.HEARTBEAT_LOG_EVENT_V2: {\r\n                HeartbeatV2LogEvent event = new HeartbeatV2LogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                return event;\r\n            }\r\n            case LogEvent.QUERY_COMPRESSED_EVENT: {\r\n                QueryCompressedLogEvent event = new QueryCompressedLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                return event;\r\n            }\r\n            case LogEvent.WRITE_ROWS_COMPRESSED_EVENT_V1:\r\n            case LogEvent.WRITE_ROWS_COMPRESSED_EVENT: {\r\n                WriteRowsCompressLogEvent event = new WriteRowsCompressLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                event.fillTable(context);\r\n                header.putGtid(context.getGtidSet(), gtidLogEvent);\r\n                return event;\r\n            }\r\n            case LogEvent.UPDATE_ROWS_COMPRESSED_EVENT_V1:\r\n            case LogEvent.UPDATE_ROWS_COMPRESSED_EVENT: {\r\n                UpdateRowsCompressLogEvent event = new UpdateRowsCompressLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                event.fillTable(context);\r\n                header.putGtid(context.getGtidSet(), gtidLogEvent);\r\n                return event;\r\n            }\r\n            case LogEvent.DELETE_ROWS_COMPRESSED_EVENT_V1:\r\n            case LogEvent.DELETE_ROWS_COMPRESSED_EVENT: {\r\n                DeleteRowsCompressLogEvent event = new DeleteRowsCompressLogEvent(header, buffer, descriptionEvent);\r\n                /* updating position in context */\r\n                logPosition.position = header.getLogPos();\r\n                event.fillTable(context);\r\n                header.putGtid(context.getGtidSet(), gtidLogEvent);\r\n                return event;\r\n            }\r\n            default:\r\n                /*\r\n                 * Create an object of Ignorable_log_event for unrecognized\r\n                 * sub-class. So that SLAVE SQL THREAD will only update the\r\n                 * position and continue.\r\n                 */\r\n                if ((buffer.getUint16(LogEvent.FLAGS_OFFSET) & LogEvent.LOG_EVENT_IGNORABLE_F) > 0) {\r\n                    IgnorableLogEvent event = new IgnorableLogEvent(header, buffer, descriptionEvent);\r\n                    /* updating position in context */\r\n                    logPosition.position = header.getLogPos();\r\n                    return event;\r\n                } else {\r\n                    if (logger.isWarnEnabled()) {\r\n                        logger.warn(\"Skipping unrecognized binlog event \" + LogEvent.getTypeName(header.getType())\r\n                                    + \" from: \" + context.getLogPosition());\r\n                    }\r\n                }\r\n        }\r\n\r\n        /* updating position in context */\r\n        logPosition.position = header.getLogPos();\r\n        /* Unknown or unsupported log event */\r\n        return new UnknownLogEvent(header);\r\n    }\r\n}\r\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/LogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog;\r\n\r\nimport org.apache.commons.logging.Log;\r\nimport org.apache.commons.logging.LogFactory;\r\n\r\nimport com.taobao.tddl.dbsync.binlog.event.LogHeader;\r\n\r\n/**\r\n * Binary log event definitions. This includes generic code common to all types\r\n * of log events, as well as specific code for each type of log event. - All\r\n * numbers, whether they are 16-, 24-, 32-, or 64-bit numbers, are stored in\r\n * little endian, i.e., the least significant byte first, unless otherwise\r\n * specified. representation of unsigned integers, called Packed Integer. A\r\n * Packed Integer has the capacity of storing up to 8-byte integers, while small\r\n * integers still can use 1, 3, or 4 bytes. The value of the first byte\r\n * determines how to read the number, according to the following table:\r\n * <table>\r\n * <caption>Format of Packed Integer</caption>\r\n * <tr>\r\n * <th>First byte</th>\r\n * <th>Format</th>\r\n * </tr>\r\n * <tr>\r\n * <td>0-250</td>\r\n * <td>The first byte is the number (in the range 0-250), and no more bytes are\r\n * used.</td>\r\n * </tr>\r\n * <tr>\r\n * <td>252</td>\r\n * <td>Two more bytes are used. The number is in the range 251-0xffff.</td>\r\n * </tr>\r\n * <tr>\r\n * <td>253</td>\r\n * <td>Three more bytes are used. The number is in the range 0xffff-0xffffff.</td>\r\n * </tr>\r\n * <tr>\r\n * <td>254</td>\r\n * <td>Eight more bytes are used. The number is in the range\r\n * 0xffffff-0xffffffffffffffff.</td>\r\n * </tr>\r\n * </table>\r\n * - Strings are stored in various formats. The format of each string is\r\n * documented separately.\r\n * \r\n * @see mysql-5.1.60/sql/log_event.h\r\n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\r\n * @version 1.0\r\n */\r\npublic abstract class LogEvent {\r\n\r\n    /*\r\n     * 3 is MySQL 4.x; 4 is MySQL 5.0.0. Compared to version 3, version 4 has: -\r\n     * a different Start_log_event, which includes info about the binary log\r\n     * (sizes of headers); this info is included for better compatibility if the\r\n     * master's MySQL version is different from the slave's. - all events have a\r\n     * unique ID (the triplet (server_id, timestamp at server start, other) to\r\n     * be sure an event is not executed more than once in a multimaster setup,\r\n     * example: M1 / \\ v v M2 M3 \\ / v v S if a query is run on M1, it will\r\n     * arrive twice on S, so we need that S remembers the last unique ID it has\r\n     * processed, to compare and know if the event should be skipped or not.\r\n     * Example of ID: we already have the server id (4 bytes), plus:\r\n     * timestamp_when_the_master_started (4 bytes), a counter (a sequence number\r\n     * which increments every time we write an event to the binlog) (3 bytes).\r\n     * Q: how do we handle when the counter is overflowed and restarts from 0 ?\r\n     * - Query and Load (Create or Execute) events may have a more precise\r\n     * timestamp (with microseconds), number of matched/affected/warnings rows\r\n     * and fields of session variables: SQL_MODE, FOREIGN_KEY_CHECKS,\r\n     * UNIQUE_CHECKS, SQL_AUTO_IS_NULL, the collations and charsets, the\r\n     * PASSWORD() version (old/new/...).\r\n     */\r\n    public static final int    BINLOG_VERSION                           = 4;\r\n\r\n    /* Default 5.0 server version */\r\n    public static final String SERVER_VERSION                           = \"5.0\";\r\n\r\n    /**\r\n     * Event header offsets; these point to places inside the fixed header.\r\n     */\r\n    public static final int    EVENT_TYPE_OFFSET                        = 4;\r\n    public static final int    SERVER_ID_OFFSET                         = 5;\r\n    public static final int    EVENT_LEN_OFFSET                         = 9;\r\n    public static final int    LOG_POS_OFFSET                           = 13;\r\n    public static final int    FLAGS_OFFSET                             = 17;\r\n\r\n    /* event-specific post-header sizes */\r\n    // where 3.23, 4.x and 5.0 agree\r\n    public static final int    QUERY_HEADER_MINIMAL_LEN                 = (4 + 4 + 1 + 2);\r\n    // where 5.0 differs: 2 for len of N-bytes vars.\r\n    public static final int    QUERY_HEADER_LEN                         = (QUERY_HEADER_MINIMAL_LEN + 2);\r\n\r\n    /* Enumeration type for the different types of log events. */\r\n    public static final int    UNKNOWN_EVENT                            = 0;\r\n    public static final int    START_EVENT_V3                           = 1;\r\n    public static final int    QUERY_EVENT                              = 2;\r\n    public static final int    STOP_EVENT                               = 3;\r\n    public static final int    ROTATE_EVENT                             = 4;\r\n    public static final int    INTVAR_EVENT                             = 5;\r\n    public static final int    LOAD_EVENT                               = 6;\r\n    public static final int    SLAVE_EVENT                              = 7;\r\n    public static final int    CREATE_FILE_EVENT                        = 8;\r\n    public static final int    APPEND_BLOCK_EVENT                       = 9;\r\n    public static final int    EXEC_LOAD_EVENT                          = 10;\r\n    public static final int    DELETE_FILE_EVENT                        = 11;\r\n\r\n    /**\r\n     * NEW_LOAD_EVENT is like LOAD_EVENT except that it has a longer sql_ex,\r\n     * allowing multibyte TERMINATED BY etc; both types share the same class\r\n     * (Load_log_event)\r\n     */\r\n    public static final int    NEW_LOAD_EVENT                           = 12;\r\n    public static final int    RAND_EVENT                               = 13;\r\n    public static final int    USER_VAR_EVENT                           = 14;\r\n    public static final int    FORMAT_DESCRIPTION_EVENT                 = 15;\r\n    public static final int    XID_EVENT                                = 16;\r\n    public static final int    BEGIN_LOAD_QUERY_EVENT                   = 17;\r\n    public static final int    EXECUTE_LOAD_QUERY_EVENT                 = 18;\r\n\r\n    public static final int    TABLE_MAP_EVENT                          = 19;\r\n\r\n    /**\r\n     * These event numbers were used for 5.1.0 to 5.1.15 and are therefore\r\n     * obsolete.\r\n     */\r\n    public static final int    PRE_GA_WRITE_ROWS_EVENT                  = 20;\r\n    public static final int    PRE_GA_UPDATE_ROWS_EVENT                 = 21;\r\n    public static final int    PRE_GA_DELETE_ROWS_EVENT                 = 22;\r\n\r\n    /**\r\n     * These event numbers are used from 5.1.16 and forward\r\n     */\r\n    public static final int    WRITE_ROWS_EVENT_V1                      = 23;\r\n    public static final int    UPDATE_ROWS_EVENT_V1                     = 24;\r\n    public static final int    DELETE_ROWS_EVENT_V1                     = 25;\r\n\r\n    /**\r\n     * Something out of the ordinary happened on the master\r\n     */\r\n    public static final int    INCIDENT_EVENT                           = 26;\r\n\r\n    /**\r\n     * Heartbeat event to be send by master at its idle time to ensure master's\r\n     * online status to slave\r\n     */\r\n    public static final int    HEARTBEAT_LOG_EVENT                      = 27;\r\n\r\n    /**\r\n     * In some situations, it is necessary to send over ignorable data to the\r\n     * slave: data that a slave can handle in case there is code for handling\r\n     * it, but which can be ignored if it is not recognized.\r\n     */\r\n    public static final int    IGNORABLE_LOG_EVENT                      = 28;\r\n    public static final int    ROWS_QUERY_LOG_EVENT                     = 29;\r\n\r\n    /** Version 2 of the Row events */\r\n    public static final int    WRITE_ROWS_EVENT                         = 30;\r\n    public static final int    UPDATE_ROWS_EVENT                        = 31;\r\n    public static final int    DELETE_ROWS_EVENT                        = 32;\r\n\r\n    public static final int    GTID_LOG_EVENT                           = 33;\r\n    public static final int    ANONYMOUS_GTID_LOG_EVENT                 = 34;\r\n\r\n    public static final int    PREVIOUS_GTIDS_LOG_EVENT                 = 35;\r\n\r\n    /* MySQL 5.7 events */\r\n    public static final int    TRANSACTION_CONTEXT_EVENT                = 36;\r\n\r\n    public static final int    VIEW_CHANGE_EVENT                        = 37;\r\n\r\n    /* Prepared XA transaction terminal event similar to Xid */\r\n    public static final int    XA_PREPARE_LOG_EVENT                     = 38;\r\n\r\n    /**\r\n     * Extension of UPDATE_ROWS_EVENT, allowing partial values according to\r\n     * binlog_row_value_options.\r\n     */\r\n    public static final int    PARTIAL_UPDATE_ROWS_EVENT                = 39;\r\n\r\n    /* mysql 8.0.20 */\r\n    public static final int    TRANSACTION_PAYLOAD_EVENT                = 40;\r\n\r\n    /* mysql 8.0.26 */\r\n    public static final int    HEARTBEAT_LOG_EVENT_V2                   = 41;\r\n\r\n    public static final int    MYSQL_ENUM_END_EVENT                     = 42;\r\n\r\n    // mariaDb 5.5.34\r\n    /* New MySQL/Sun events are to be added right above this comment */\r\n    public static final int    MYSQL_EVENTS_END                         = 49;\r\n\r\n    // PolarDB-X 2.5.0\r\n    // CONSENSUS EVENTS START\r\n    public static final int    CONSENSUS_LOG_EVENT                      = 101;\r\n    public static final int    PREVIOUS_CONSENSUS_INDEX_LOG_EVENT       = 102;\r\n    public static final int    CONSENSUS_CLUSTER_INFO_EVENT             = 103;\r\n    public static final int    CONSENSUS_EMPTY_EVENT                    = 104;\r\n    public static final int    GCN_LOG_EVENT                            = 105;\r\n    // CONSENSUS EVENTS END\r\n\r\n    public static final int    MARIA_EVENTS_BEGIN                       = 160;\r\n    /* New Maria event numbers start from here */\r\n    public static final int    ANNOTATE_ROWS_EVENT                      = 160;\r\n    /*\r\n     * Binlog checkpoint event. Used for XA crash recovery on the master, not\r\n     * used in replication. A binlog checkpoint event specifies a binlog file\r\n     * such that XA crash recovery can start from that file - and it is\r\n     * guaranteed to find all XIDs that are prepared in storage engines but not\r\n     * yet committed.\r\n     */\r\n    public static final int    BINLOG_CHECKPOINT_EVENT                  = 161;\r\n    /*\r\n     * Gtid event. For global transaction ID, used to start a new event group,\r\n     * instead of the old BEGIN query event, and also to mark stand-alone\r\n     * events.\r\n     */\r\n    public static final int    GTID_EVENT                               = 162;\r\n    /*\r\n     * Gtid list event. Logged at the start of every binlog, to record the\r\n     * current replication state. This consists of the last GTID seen for each\r\n     * replication domain.\r\n     */\r\n    public static final int    GTID_LIST_EVENT                          = 163;\r\n\r\n    public static final int    START_ENCRYPTION_EVENT                   = 164;\r\n\r\n    // mariadb 10.10.1\r\n    /*\r\n     * Compressed binlog event. Note that the order between WRITE/UPDATE/DELETE\r\n     * events is significant; this is so that we can convert from the compressed to\r\n     * the uncompressed event type with (type-WRITE_ROWS_COMPRESSED_EVENT +\r\n     * WRITE_ROWS_EVENT) and similar for _V1.\r\n     */\r\n    public static final int    QUERY_COMPRESSED_EVENT                   = 165;\r\n    public static final int    WRITE_ROWS_COMPRESSED_EVENT_V1           = 166;\r\n    public static final int    UPDATE_ROWS_COMPRESSED_EVENT_V1          = 167;\r\n    public static final int    DELETE_ROWS_COMPRESSED_EVENT_V1          = 168;\r\n    public static final int    WRITE_ROWS_COMPRESSED_EVENT              = 169;\r\n    public static final int    UPDATE_ROWS_COMPRESSED_EVENT             = 170;\r\n    public static final int    DELETE_ROWS_COMPRESSED_EVENT             = 171;\r\n\r\n    /** end marker */\r\n    public static final int    ENUM_END_EVENT                           = 172;\r\n\r\n    /**\r\n     * 1 byte length, 1 byte format Length is total length in bytes, including 2\r\n     * byte header Length values 0 and 1 are currently invalid and reserved.\r\n     */\r\n    public static final int    EXTRA_ROW_INFO_LEN_OFFSET                = 0;\r\n    public static final int    EXTRA_ROW_INFO_FORMAT_OFFSET             = 1;\r\n    public static final int    EXTRA_ROW_INFO_HDR_BYTES                 = 2;\r\n    public static final int    EXTRA_ROW_INFO_MAX_PAYLOAD               = (255 - EXTRA_ROW_INFO_HDR_BYTES);\r\n\r\n    // Events are without checksum though its generator\r\n    public static final int    BINLOG_CHECKSUM_ALG_OFF                  = 0;\r\n    // is checksum-capable New Master (NM).\r\n    // CRC32 of zlib algorithm.\r\n    public static final int    BINLOG_CHECKSUM_ALG_CRC32                = 1;\r\n    // the cut line: valid alg range is [1, 0x7f].\r\n    public static final int    BINLOG_CHECKSUM_ALG_ENUM_END             = 2;\r\n    // special value to tag undetermined yet checksum\r\n    public static final int    BINLOG_CHECKSUM_ALG_UNDEF                = 255;\r\n    // or events from checksum-unaware servers\r\n\r\n    public static final int    CHECKSUM_CRC32_SIGNATURE_LEN             = 4;\r\n    public static final int    BINLOG_CHECKSUM_ALG_DESC_LEN             = 1;\r\n    /**\r\n     * defined statically while there is just one alg implemented\r\n     */\r\n    public static final int    BINLOG_CHECKSUM_LEN                      = CHECKSUM_CRC32_SIGNATURE_LEN;\r\n\r\n    /* MySQL or old MariaDB slave with no announced capability. */\r\n    public static final int    MARIA_SLAVE_CAPABILITY_UNKNOWN           = 0;\r\n\r\n    /* MariaDB >= 5.3, which understands ANNOTATE_ROWS_EVENT. */\r\n    public static final int    MARIA_SLAVE_CAPABILITY_ANNOTATE          = 1;\r\n    /*\r\n     * MariaDB >= 5.5. This version has the capability to tolerate events\r\n     * omitted from the binlog stream without breaking replication (MySQL slaves\r\n     * fail because they mis-compute the offsets into the master's binlog).\r\n     */\r\n    public static final int    MARIA_SLAVE_CAPABILITY_TOLERATE_HOLES    = 2;\r\n    /* MariaDB >= 10.0, which knows about binlog_checkpoint_log_event. */\r\n    public static final int    MARIA_SLAVE_CAPABILITY_BINLOG_CHECKPOINT = 3;\r\n    /* MariaDB >= 10.0.1, which knows about global transaction id events. */\r\n    public static final int    MARIA_SLAVE_CAPABILITY_GTID              = 4;\r\n\r\n    /* Our capability. */\r\n    public static final int    MARIA_SLAVE_CAPABILITY_MINE              = MARIA_SLAVE_CAPABILITY_GTID;\r\n\r\n    /**\r\n     * For an event, 'e', carrying a type code, that a slave, 's', does not\r\n     * recognize, 's' will check 'e' for LOG_EVENT_IGNORABLE_F, and if the flag\r\n     * is set, then 'e' is ignored. Otherwise, 's' acknowledges that it has\r\n     * found an unknown event in the relay log.\r\n     */\r\n    public static final int    LOG_EVENT_IGNORABLE_F                    = 0x80;\r\n\r\n    /** enum_field_types */\r\n    public static final int    MYSQL_TYPE_DECIMAL                       = 0;\r\n    public static final int    MYSQL_TYPE_TINY                          = 1;\r\n    public static final int    MYSQL_TYPE_SHORT                         = 2;\r\n    public static final int    MYSQL_TYPE_LONG                          = 3;\r\n    public static final int    MYSQL_TYPE_FLOAT                         = 4;\r\n    public static final int    MYSQL_TYPE_DOUBLE                        = 5;\r\n    public static final int    MYSQL_TYPE_NULL                          = 6;\r\n    public static final int    MYSQL_TYPE_TIMESTAMP                     = 7;\r\n    public static final int    MYSQL_TYPE_LONGLONG                      = 8;\r\n    public static final int    MYSQL_TYPE_INT24                         = 9;\r\n    public static final int    MYSQL_TYPE_DATE                          = 10;\r\n    public static final int    MYSQL_TYPE_TIME                          = 11;\r\n    public static final int    MYSQL_TYPE_DATETIME                      = 12;\r\n    public static final int    MYSQL_TYPE_YEAR                          = 13;\r\n    public static final int    MYSQL_TYPE_NEWDATE                       = 14;\r\n    public static final int    MYSQL_TYPE_VARCHAR                       = 15;\r\n    public static final int    MYSQL_TYPE_BIT                           = 16;\r\n    public static final int    MYSQL_TYPE_TIMESTAMP2                    = 17;\r\n    public static final int    MYSQL_TYPE_DATETIME2                     = 18;\r\n    public static final int    MYSQL_TYPE_TIME2                         = 19;\r\n    public static final int    MYSQL_TYPE_TYPED_ARRAY                   = 20;\r\n    public static final int    MYSQL_TYPE_INVALID                       = 243;\r\n    public static final int    MYSQL_TYPE_BOOL                          = 244;\r\n    public static final int    MYSQL_TYPE_JSON                          = 245;\r\n    public static final int    MYSQL_TYPE_NEWDECIMAL                    = 246;\r\n    public static final int    MYSQL_TYPE_ENUM                          = 247;\r\n    public static final int    MYSQL_TYPE_SET                           = 248;\r\n    public static final int    MYSQL_TYPE_TINY_BLOB                     = 249;\r\n    public static final int    MYSQL_TYPE_MEDIUM_BLOB                   = 250;\r\n    public static final int    MYSQL_TYPE_LONG_BLOB                     = 251;\r\n    public static final int    MYSQL_TYPE_BLOB                          = 252;\r\n    public static final int    MYSQL_TYPE_VAR_STRING                    = 253;\r\n    public static final int    MYSQL_TYPE_STRING                        = 254;\r\n    public static final int    MYSQL_TYPE_GEOMETRY                      = 255;\r\n\r\n    public static String getTypeName(final int type) {\r\n        switch (type) {\r\n            case START_EVENT_V3:\r\n                return \"Start_v3\";\r\n            case STOP_EVENT:\r\n                return \"Stop\";\r\n            case QUERY_EVENT:\r\n                return \"Query\";\r\n            case ROTATE_EVENT:\r\n                return \"Rotate\";\r\n            case INTVAR_EVENT:\r\n                return \"Intvar\";\r\n            case LOAD_EVENT:\r\n                return \"Load\";\r\n            case NEW_LOAD_EVENT:\r\n                return \"New_load\";\r\n            case SLAVE_EVENT:\r\n                return \"Slave\";\r\n            case CREATE_FILE_EVENT:\r\n                return \"Create_file\";\r\n            case APPEND_BLOCK_EVENT:\r\n                return \"Append_block\";\r\n            case DELETE_FILE_EVENT:\r\n                return \"Delete_file\";\r\n            case EXEC_LOAD_EVENT:\r\n                return \"Exec_load\";\r\n            case RAND_EVENT:\r\n                return \"RAND\";\r\n            case XID_EVENT:\r\n                return \"Xid\";\r\n            case USER_VAR_EVENT:\r\n                return \"User var\";\r\n            case FORMAT_DESCRIPTION_EVENT:\r\n                return \"Format_desc\";\r\n            case TABLE_MAP_EVENT:\r\n                return \"Table_map\";\r\n            case PRE_GA_WRITE_ROWS_EVENT:\r\n                return \"Write_rows_event_old\";\r\n            case PRE_GA_UPDATE_ROWS_EVENT:\r\n                return \"Update_rows_event_old\";\r\n            case PRE_GA_DELETE_ROWS_EVENT:\r\n                return \"Delete_rows_event_old\";\r\n            case WRITE_ROWS_EVENT_V1:\r\n                return \"Write_rows_v1\";\r\n            case UPDATE_ROWS_EVENT_V1:\r\n                return \"Update_rows_v1\";\r\n            case DELETE_ROWS_EVENT_V1:\r\n                return \"Delete_rows_v1\";\r\n            case BEGIN_LOAD_QUERY_EVENT:\r\n                return \"Begin_load_query\";\r\n            case EXECUTE_LOAD_QUERY_EVENT:\r\n                return \"Execute_load_query\";\r\n            case INCIDENT_EVENT:\r\n                return \"Incident\";\r\n            case HEARTBEAT_LOG_EVENT:\r\n            case HEARTBEAT_LOG_EVENT_V2:\r\n                return \"Heartbeat\";\r\n            case IGNORABLE_LOG_EVENT:\r\n                return \"Ignorable\";\r\n            case ROWS_QUERY_LOG_EVENT:\r\n                return \"Rows_query\";\r\n            case WRITE_ROWS_EVENT:\r\n                return \"Write_rows\";\r\n            case UPDATE_ROWS_EVENT:\r\n                return \"Update_rows\";\r\n            case DELETE_ROWS_EVENT:\r\n                return \"Delete_rows\";\r\n            case GTID_LOG_EVENT:\r\n                return \"Gtid\";\r\n            case ANONYMOUS_GTID_LOG_EVENT:\r\n                return \"Anonymous_Gtid\";\r\n            case PREVIOUS_GTIDS_LOG_EVENT:\r\n                return \"Previous_gtids\";\r\n            case PARTIAL_UPDATE_ROWS_EVENT:\r\n                return \"Update_rows_partial\";\r\n            case TRANSACTION_CONTEXT_EVENT :\r\n                return \"Transaction_context\";\r\n            case VIEW_CHANGE_EVENT :\r\n                return \"view_change\";\r\n            case XA_PREPARE_LOG_EVENT :\r\n                return \"Xa_prepare\";\r\n            case TRANSACTION_PAYLOAD_EVENT :\r\n                return \"transaction_payload\";\r\n            case CONSENSUS_LOG_EVENT:\r\n                return \"Consensus_log\";\r\n            case PREVIOUS_CONSENSUS_INDEX_LOG_EVENT:\r\n                return \"Previous_consensus_index\";\r\n            case CONSENSUS_CLUSTER_INFO_EVENT:\r\n                return \"Consensus_cluster_info\";\r\n            case CONSENSUS_EMPTY_EVENT:\r\n                return \"Consensus_empty\";\r\n            case GCN_LOG_EVENT:\r\n                return \"Gcn_log\";\r\n            default:\r\n                return \"Unknown type:\" + type;\r\n        }\r\n    }\r\n\r\n    protected static final Log logger = LogFactory.getLog(LogEvent.class);\r\n\r\n    protected final LogHeader  header;\r\n\r\n    /**\r\n     * mysql半同步semi标识\r\n     * \r\n     * <pre>\r\n     * 0不需要semi ack 给mysql\r\n     * 1需要semi ack给mysql\r\n     * </pre>\r\n     */\r\n    protected int              semival;\r\n\r\n    public int getSemival() {\r\n        return semival;\r\n    }\r\n\r\n    public void setSemival(int semival) {\r\n        this.semival = semival;\r\n    }\r\n\r\n    protected LogEvent(LogHeader header){\r\n        this.header = header;\r\n    }\r\n\r\n    /**\r\n     * Return event header.\r\n     */\r\n    public final LogHeader getHeader() {\r\n        return header;\r\n    }\r\n\r\n    /**\r\n     * The total size of this event, in bytes. In other words, this is the sum\r\n     * of the sizes of Common-Header, Post-Header, and Body.\r\n     */\r\n    public final int getEventLen() {\r\n        return header.getEventLen();\r\n    }\r\n\r\n    /**\r\n     * Server ID of the server that created the event.\r\n     */\r\n    public final long getServerId() {\r\n        return header.getServerId();\r\n    }\r\n\r\n    /**\r\n     * The position of the next event in the master binary log, in bytes from\r\n     * the beginning of the file. In a binlog that is not a relay log, this is\r\n     * just the position of the next event, in bytes from the beginning of the\r\n     * file. In a relay log, this is the position of the next event in the\r\n     * master's binlog.\r\n     */\r\n    public final long getLogPos() {\r\n        return header.getLogPos();\r\n    }\r\n\r\n    /**\r\n     * The time when the query started, in seconds since 1970.\r\n     */\r\n    public final long getWhen() {\r\n        return header.getWhen();\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/LogFetcher.java",
    "content": "package com.taobao.tddl.dbsync.binlog;\r\n\r\nimport java.io.Closeable;\r\nimport java.io.IOException;\r\nimport java.util.Arrays;\r\n\r\n/**\r\n * Declaration a binary-log fetcher. It extends from <code>LogBuffer</code>.\r\n * \r\n * <pre>\r\n * LogFetcher fetcher = new SomeLogFetcher();\r\n * ...\r\n * \r\n * while (fetcher.fetch())\r\n * {\r\n *     LogEvent event;\r\n *     do\r\n *     {\r\n *         event = decoder.decode(fetcher, context);\r\n * \r\n *         // process log event.\r\n *     }\r\n *     while (event != null);\r\n * }\r\n * // no more binlog.\r\n * fetcher.close();\r\n * </pre>\r\n * \r\n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\r\n * @version 1.0\r\n */\r\npublic abstract class LogFetcher extends LogBuffer implements Closeable {\r\n\r\n    /** Default initial capacity. */\r\n    public static final int   DEFAULT_INITIAL_CAPACITY = 8192;\r\n\r\n    /** Default growth factor. */\r\n    public static final float DEFAULT_GROWTH_FACTOR    = 2.0f;\r\n\r\n    /** Binlog file header size */\r\n    public static final int   BIN_LOG_HEADER_SIZE      = 4;\r\n\r\n    protected final float     factor;\r\n\r\n    public LogFetcher(){\r\n        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_GROWTH_FACTOR);\r\n    }\r\n\r\n    public LogFetcher(final int initialCapacity){\r\n        this(initialCapacity, DEFAULT_GROWTH_FACTOR);\r\n    }\r\n\r\n    public LogFetcher(final int initialCapacity, final float growthFactor){\r\n        this.buffer = new byte[initialCapacity];\r\n        this.factor = growthFactor;\r\n    }\r\n\r\n    /**\r\n     * Increases the capacity of this <tt>LogFetcher</tt> instance, if\r\n     * necessary, to ensure that it can hold at least the number of elements\r\n     * specified by the minimum capacity argument.\r\n     * \r\n     * @param minCapacity the desired minimum capacity\r\n     */\r\n    protected final void ensureCapacity(final int minCapacity) {\r\n        final int oldCapacity = buffer.length;\r\n\r\n        if (minCapacity > oldCapacity) {\r\n            int newCapacity = (int) (oldCapacity * factor);\r\n            if (newCapacity < minCapacity) newCapacity = minCapacity;\r\n\r\n            buffer = Arrays.copyOf(buffer, newCapacity);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Fetches the next frame of binary-log, and fill it in buffer.\r\n     */\r\n    public abstract boolean fetch() throws IOException;\r\n\r\n    /**\r\n     * {@inheritDoc}\r\n     * \r\n     * @see java.io.Closeable#close()\r\n     */\r\n    public abstract void close() throws IOException;\r\n}\r\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/LogPosition.java",
    "content": "package com.taobao.tddl.dbsync.binlog;\r\n\r\n/**\r\n * Implements binlog position.\r\n * \r\n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\r\n * @version 1.0\r\n */\r\npublic class LogPosition implements Cloneable, Comparable<LogPosition> {\r\n\r\n    /* binlog file's name */\r\n    protected String fileName;\r\n\r\n    /* position in file */\r\n    protected long   position;\r\n\r\n    /**\r\n     * Binlog position init.\r\n     * \r\n     * @param fileName file name for binlog files: mysql-bin.000001\r\n     */\r\n    public LogPosition(String fileName){\r\n        this.fileName = fileName;\r\n        this.position = 0L;\r\n    }\r\n\r\n    /**\r\n     * Binlog position init.\r\n     * \r\n     * @param fileName file name for binlog files: mysql-bin.000001\r\n     */\r\n    public LogPosition(String fileName, final long position){\r\n        this.fileName = fileName;\r\n        this.position = position;\r\n    }\r\n\r\n    /**\r\n     * Binlog position copy init.\r\n     */\r\n    public LogPosition(LogPosition source){\r\n        this.fileName = source.fileName;\r\n        this.position = source.position;\r\n    }\r\n\r\n    public final String getFileName() {\r\n        return fileName;\r\n    }\r\n\r\n    public final long getPosition() {\r\n        return position;\r\n    }\r\n\r\n    /* Clone binlog position without CloneNotSupportedException */\r\n    public LogPosition clone() {\r\n        try {\r\n            return (LogPosition) super.clone();\r\n        } catch (CloneNotSupportedException e) {\r\n            // Never happend\r\n            return null;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Compares with the specified fileName and position.\r\n     */\r\n    public final int compareTo(String fileName, final long position) {\r\n        final int val = this.fileName.compareTo(fileName);\r\n\r\n        if (val == 0) {\r\n            return (int) (this.position - position);\r\n        }\r\n        return val;\r\n    }\r\n\r\n    /**\r\n     * {@inheritDoc}\r\n     * \r\n     * @see java.lang.Comparable#compareTo(java.lang.Object)\r\n     */\r\n    public int compareTo(LogPosition o) {\r\n        final int val = fileName.compareTo(o.fileName);\r\n\r\n        if (val == 0) {\r\n            return (int) (position - o.position);\r\n        }\r\n        return val;\r\n    }\r\n\r\n    /**\r\n     * {@inheritDoc}\r\n     * \r\n     * @see java.lang.Object#equals(java.lang.Object)\r\n     */\r\n    public boolean equals(Object obj) {\r\n        if (obj instanceof LogPosition) {\r\n            LogPosition pos = ((LogPosition) obj);\r\n            return fileName.equals(pos.fileName) && (this.position == pos.position);\r\n        }\r\n        return false;\r\n    }\r\n\r\n    /**\r\n     * {@inheritDoc}\r\n     * \r\n     * @see java.lang.Object#toString()\r\n     */\r\n    public String toString() {\r\n        return fileName + ':' + position;\r\n    }\r\n}\r\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/NameCache.java",
    "content": "package com.taobao.tddl.dbsync.binlog;\r\rimport java.nio.charset.Charset;\r\r/**\r * string cache\r * @since  1.1.7\r */\rpublic class NameCache {\r\r    static final NameCacheEntry[]  NAME_CACHE  = new NameCacheEntry[8192];\r    static final NameCacheEntry2[] NAME_CACHE2 = new NameCacheEntry2[8192];\r\r    static final class NameCacheEntry {\r\r        final String name;\r        final long   value;\r\r        public NameCacheEntry(String name, long value){\r            this.name = name;\r            this.value = value;\r        }\r    }\r\r    static final class NameCacheEntry2 {\r\r        final String name;\r        final long   value0;\r        final long   value1;\r\r        public NameCacheEntry2(String name, long value0, long value1){\r            this.name = name;\r            this.value0 = value0;\r            this.value1 = value1;\r        }\r    }\r\r    static String name(byte[] buf, int from, int length, Charset charset) {\r        long nameValue0 = -1, nameValue1 = -1;\r        switch (length) {\r            case 1:\r                nameValue0 = buf[from];\r                break;\r            case 2:\r                nameValue0 = (buf[from + 1] << 8) + (buf[from] & 0xFF);\r                break;\r            case 3:\r                nameValue0 = (buf[from + 2] << 16) + ((buf[from + 1] & 0xFF) << 8) + (buf[from] & 0xFF);\r                break;\r            case 4:\r                nameValue0 = (buf[from + 3] << 24) + ((buf[from + 2] & 0xFF) << 16) + ((buf[from + 1] & 0xFF) << 8)\r                             + (buf[from] & 0xFF);\r                break;\r            case 5:\r                nameValue0 = (((long) buf[from + 4]) << 32) + ((buf[from + 3] & 0xFFL) << 24)\r                             + ((buf[from + 2] & 0xFFL) << 16) + ((buf[from + 1] & 0xFFL) << 8) + (buf[from] & 0xFFL);\r                break;\r            case 6:\r                nameValue0 = (((long) buf[from + 5]) << 40) + ((buf[from + 4] & 0xFFL) << 32)\r                             + ((buf[from + 3] & 0xFFL) << 24) + ((buf[from + 2] & 0xFFL) << 16)\r                             + ((buf[from + 1] & 0xFFL) << 8) + (buf[from] & 0xFFL);\r                break;\r            case 7:\r                nameValue0 = (((long) buf[from + 6]) << 48) + ((buf[from + 5] & 0xFFL) << 40)\r                             + ((buf[from + 4] & 0xFFL) << 32) + ((buf[from + 3] & 0xFFL) << 24)\r                             + ((buf[from + 2] & 0xFFL) << 16) + ((buf[from + 1] & 0xFFL) << 8) + (buf[from] & 0xFFL);\r                break;\r            case 8:\r                nameValue0 = (((long) buf[from + 7]) << 56) + ((buf[from + 6] & 0xFFL) << 48)\r                             + ((buf[from + 5] & 0xFFL) << 40) + ((buf[from + 4] & 0xFFL) << 32)\r                             + ((buf[from + 3] & 0xFFL) << 24) + ((buf[from + 2] & 0xFFL) << 16)\r                             + ((buf[from + 1] & 0xFFL) << 8) + (buf[from] & 0xFFL);\r                break;\r            case 9:\r                nameValue0 = buf[from];\r                nameValue1 = (((long) buf[from + 8]) << 56) + ((buf[from + 7] & 0xFFL) << 48)\r                             + ((buf[from + 6] & 0xFFL) << 40) + ((buf[from + 5] & 0xFFL) << 32)\r                             + ((buf[from + 4] & 0xFFL) << 24) + ((buf[from + 3] & 0xFFL) << 16)\r                             + ((buf[from + 2] & 0xFFL) << 8) + (buf[from + 1] & 0xFFL);\r                break;\r            case 10:\r                nameValue0 = (buf[from + 1] << 8) + (buf[from]);\r                nameValue1 = (((long) buf[from + 9]) << 56) + ((buf[from + 8] & 0xFFL) << 48)\r                             + ((buf[from + 7] & 0xFFL) << 40) + ((buf[from + 6] & 0xFFL) << 32)\r                             + ((buf[from + 5] & 0xFFL) << 24) + ((buf[from + 4] & 0xFFL) << 16)\r                             + ((buf[from + 3] & 0xFFL) << 8) + (buf[from + 2] & 0xFFL);\r                break;\r            case 11:\r                nameValue0 = (buf[from + 2] << 16) + (buf[from + 1] << 8) + (buf[from]);\r                nameValue1 = (((long) buf[from + 10]) << 56) + ((buf[from + 9] & 0xFFL) << 48)\r                             + ((buf[from + 8] & 0xFFL) << 40) + ((buf[from + 7] & 0xFFL) << 32)\r                             + ((buf[from + 6] & 0xFFL) << 24) + ((buf[from + 5] & 0xFFL) << 16)\r                             + ((buf[from + 4] & 0xFFL) << 8) + (buf[from + 3] & 0xFFL);\r                break;\r            case 12:\r                nameValue0 = (buf[from + 3] << 24) + (buf[from + 2] << 16) + (buf[from + 1] << 8) + (buf[from]);\r                nameValue1 = (((long) buf[from + 11]) << 56) + ((buf[from + 10] & 0xFFL) << 48)\r                             + ((buf[from + 9] & 0xFFL) << 40) + ((buf[from + 8] & 0xFFL) << 32)\r                             + ((buf[from + 7] & 0xFFL) << 24) + ((buf[from + 6] & 0xFFL) << 16)\r                             + ((buf[from + 5] & 0xFFL) << 8) + (buf[from + 4] & 0xFFL);\r                break;\r            case 13:\r                nameValue0 = (((long) buf[from + 4]) << 32) + (((long) buf[from + 3]) << 24)\r                             + (((long) buf[from + 2]) << 16) + (((long) buf[from + 1]) << 8) + ((long) buf[from]);\r                nameValue1 = (((long) buf[from + 12]) << 56) + ((buf[from + 11] & 0xFFL) << 48)\r                             + ((buf[from + 10] & 0xFFL) << 40) + ((buf[from + 9] & 0xFFL) << 32)\r                             + ((buf[from + 8] & 0xFFL) << 24) + ((buf[from + 7] & 0xFFL) << 16)\r                             + ((buf[from + 6] & 0xFFL) << 8) + (buf[from + 5] & 0xFFL);\r                break;\r            case 14:\r                nameValue0 = (((long) buf[from + 5]) << 40) + ((buf[from + 4] & 0xFFL) << 32)\r                             + ((buf[from + 3] & 0xFFL) << 24) + ((buf[from + 2] & 0xFFL) << 16)\r                             + ((buf[from + 1] & 0xFFL) << 8) + (buf[from] & 0xFFL);\r                nameValue1 = (((long) buf[from + 13]) << 56) + ((buf[from + 12] & 0xFFL) << 48)\r                             + ((buf[from + 11] & 0xFFL) << 40) + ((buf[from + 10] & 0xFFL) << 32)\r                             + ((buf[from + 9] & 0xFFL) << 24) + ((buf[from + 8] & 0xFFL) << 16)\r                             + ((buf[from + 7] & 0xFFL) << 8) + (buf[from + 6] & 0xFFL);\r                break;\r            case 15:\r                nameValue0 = (((long) buf[from + 6]) << 48) + ((buf[from + 5] & 0xFFL) << 40)\r                             + ((buf[from + 4] & 0xFFL) << 32) + ((buf[from + 3] & 0xFFL) << 24)\r                             + ((buf[from + 2] & 0xFFL) << 16) + ((buf[from + 1] & 0xFFL) << 8) + (buf[from] & 0xFFL);\r                nameValue1 = (((long) buf[from + 14]) << 56) + ((buf[from + 13] & 0xFFL) << 48)\r                             + ((buf[from + 12] & 0xFFL) << 40) + ((buf[from + 11] & 0xFFL) << 32)\r                             + ((buf[from + 10] & 0xFFL) << 24) + ((buf[from + 9] & 0xFFL) << 16)\r                             + ((buf[from + 8] & 0xFFL) << 8) + (buf[from + 7] & 0xFFL);\r                break;\r            case 16:\r                nameValue0 = (((long) buf[from + 7]) << 56) + ((buf[from + 6] & 0xFFL) << 48)\r                             + ((buf[from + 5] & 0xFFL) << 40) + ((buf[from + 4] & 0xFFL) << 32)\r                             + ((buf[from + 3] & 0xFFL) << 24) + ((buf[from + 2] & 0xFFL) << 16)\r                             + ((buf[from + 1] & 0xFFL) << 8) + (buf[from] & 0xFFL);\r                nameValue1 = (((long) buf[from + 15]) << 56) + ((buf[from + 14] & 0xFFL) << 48)\r                             + ((buf[from + 13] & 0xFFL) << 40) + ((buf[from + 12] & 0xFFL) << 32)\r                             + ((buf[from + 11] & 0xFFL) << 24) + ((buf[from + 10] & 0xFFL) << 16)\r                             + ((buf[from + 9] & 0xFFL) << 8) + (buf[from + 8] & 0xFFL);\r                break;\r            default:\r                break;\r        }\r\r        if (nameValue0 != -1) {\r            if (nameValue1 != -1) {\r                int indexMask = ((int) nameValue1) & (NameCache.NAME_CACHE2.length - 1);\r                NameCache.NameCacheEntry2 entry = NameCache.NAME_CACHE2[indexMask];\r                if (entry == null) {\r                    String name = new String(buf, from, length, charset);\r                    NameCache.NAME_CACHE2[indexMask] = new NameCacheEntry2(name, nameValue0, nameValue1);\r                    return name;\r                } else if (entry.value0 == nameValue0 && entry.value1 == nameValue1) {\r                    return entry.name;\r                }\r            } else {\r                int indexMask = ((int) nameValue0) & (NAME_CACHE.length - 1);\r                NameCacheEntry entry = NAME_CACHE[indexMask];\r                if (entry == null) {\r                    String name = new String(buf, from, length, charset);\r                    NAME_CACHE[indexMask] = new NameCacheEntry(name, nameValue0);\r                    return name;\r                } else if (entry.value == nameValue0) {\r                    return entry.name;\r                }\r            }\r        }\r\r        return null;\r    }\r}\r"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/AppendBlockLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\n\n/**\n * Append_block_log_event.\n * \n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\n * @version 1.0\n */\npublic class AppendBlockLogEvent extends LogEvent {\n\n    private final LogBuffer blockBuf;\n    private final int       blockLen;\n\n    private final long      fileId;\n\n    /* AB = \"Append Block\" */\n    public static final int AB_FILE_ID_OFFSET = 0;\n\n    public AppendBlockLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\n        super(header);\n\n        final int commonHeaderLen = descriptionEvent.commonHeaderLen;\n        final int postHeaderLen = descriptionEvent.postHeaderLen[header.type - 1];\n        final int totalHeaderLen = commonHeaderLen + postHeaderLen;\n\n        buffer.position(commonHeaderLen + AB_FILE_ID_OFFSET);\n        fileId = buffer.getUint32();\n\n        buffer.position(postHeaderLen);\n        blockLen = buffer.limit() - totalHeaderLen;\n        blockBuf = buffer.duplicate(blockLen);\n    }\n\n    public final long getFileId() {\n        return fileId;\n    }\n\n    public final LogBuffer getBuffer() {\n        return blockBuf;\n    }\n\n    public final byte[] getData() {\n        return blockBuf.getData();\n    }\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/BeginLoadQueryLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\n\n/**\n * Event for the first block of file to be loaded, its only difference from\n * Append_block event is that this event creates or truncates existing file\n * before writing data.\n * \n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\n * @version 1.0\n */\npublic final class BeginLoadQueryLogEvent extends AppendBlockLogEvent {\n\n    public BeginLoadQueryLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\n        super(header, buffer, descriptionEvent);\n    }\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/CreateFileLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\r\n\r\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\r\n\r\n/**\r\n * Create_file_log_event.\r\n * \r\n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\r\n * @version 1.0\r\n */\r\npublic final class CreateFileLogEvent extends LoadLogEvent {\r\n\r\n    protected LogBuffer     blockBuf;\r\n    protected int           blockLen;\r\n    protected long          fileId;\r\n\r\n    protected boolean       initedFromOld;\r\n\r\n    /* CF = \"Create File\" */\r\n    public static final int CF_FILE_ID_OFFSET = 0;\r\n    public static final int CF_DATA_OFFSET    = FormatDescriptionLogEvent.CREATE_FILE_HEADER_LEN;\r\n\r\n    public CreateFileLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\r\n        super(header, buffer, descriptionEvent);\r\n\r\n        final int headerLen = descriptionEvent.commonHeaderLen;\r\n        final int loadHeaderLen = descriptionEvent.postHeaderLen[LOAD_EVENT - 1];\r\n        final int createFileHeaderLen = descriptionEvent.postHeaderLen[CREATE_FILE_EVENT - 1];\r\n\r\n        copyLogEvent(buffer,\r\n            ((header.type == LOAD_EVENT) ? (loadHeaderLen + headerLen) : (headerLen + loadHeaderLen + createFileHeaderLen)),\r\n            descriptionEvent);\r\n\r\n        if (descriptionEvent.binlogVersion != 1) {\r\n            fileId = buffer.getUint32(headerLen + loadHeaderLen + CF_FILE_ID_OFFSET);\r\n            /*\r\n             * Note that it's ok to use get_data_size() below, because it is\r\n             * computed with values we have already read from this event\r\n             * (because we called copy_log_event()); we are not using slave's\r\n             * format info to decode master's format, we are really using\r\n             * master's format info. Anyway, both formats should be identical\r\n             * (except the common_header_len) as these Load events are not\r\n             * changed between 4.0 and 5.0 (as logging of LOAD DATA INFILE does\r\n             * not use Load_log_event in 5.0).\r\n             */\r\n            blockLen = buffer.limit() - buffer.position();\r\n            blockBuf = buffer.duplicate(blockLen);\r\n        } else {\r\n            initedFromOld = true;\r\n        }\r\n    }\r\n\r\n    public final long getFileId() {\r\n        return fileId;\r\n    }\r\n\r\n    public final LogBuffer getBuffer() {\r\n        return blockBuf;\r\n    }\r\n\r\n    public final byte[] getData() {\r\n        return blockBuf.getData();\r\n    }\r\n}\r\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/DeleteFileLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\n\n/**\n * Delete_file_log_event.\n * \n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\n * @version 1.0\n */\npublic final class DeleteFileLogEvent extends LogEvent {\n\n    private final long      fileId;\n\n    /* DF = \"Delete File\" */\n    public static final int DF_FILE_ID_OFFSET = 0;\n\n    public DeleteFileLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\n        super(header);\n\n        final int commonHeaderLen = descriptionEvent.commonHeaderLen;\n        buffer.position(commonHeaderLen + DF_FILE_ID_OFFSET);\n        fileId = buffer.getUint32(); // DF_FILE_ID_OFFSET\n    }\n\n    public final long getFileId() {\n        return fileId;\n    }\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/DeleteRowsLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\n\n/**\n * Log row deletions. The event contain several delete rows for a table. Note\n * that each event contains only rows for one table.\n * \n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\n * @version 1.0\n */\npublic class DeleteRowsLogEvent extends RowsLogEvent {\n\n    public DeleteRowsLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\n        super(header, buffer, descriptionEvent, false, false);\n    }\n\n    public DeleteRowsLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent,\n                              boolean compress){\n        super(header, buffer, descriptionEvent, false, compress);\n    }\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/ExecuteLoadLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\r\n\r\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\r\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\r\n\r\n/**\r\n * Execute_load_log_event.\r\n * \r\n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\r\n * @version 1.0\r\n */\r\npublic final class ExecuteLoadLogEvent extends LogEvent {\r\n\r\n    private final long      fileId;\r\n\r\n    /* EL = \"Execute Load\" */\r\n    public static final int EL_FILE_ID_OFFSET = 0;\r\n\r\n    public ExecuteLoadLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\r\n        super(header);\r\n\r\n        final int commonHeaderLen = descriptionEvent.commonHeaderLen;\r\n        buffer.position(commonHeaderLen + EL_FILE_ID_OFFSET);\r\n        fileId = buffer.getUint32(); // EL_FILE_ID_OFFSET\r\n    }\r\n\r\n    public final long getFileId() {\r\n        return fileId;\r\n    }\r\n}\r\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/ExecuteLoadQueryLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport java.io.IOException;\n\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\n\n/**\n * Event responsible for LOAD DATA execution, it similar to Query_log_event but\n * before executing the query it substitutes original filename in LOAD DATA\n * query with name of temporary file.\n * <ul>\n * <li>4 bytes. The ID of the file to load.</li>\n * <li>4 bytes. The start position within the statement for filename\n * substitution.</li>\n * <li>4 bytes. The end position within the statement for filename substitution.\n * </li>\n * <li>1 byte. How to handle duplicates: LOAD_DUP_ERROR = 0, LOAD_DUP_IGNORE =\n * 1, LOAD_DUP_REPLACE = 2</li>\n * </ul>\n * \n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\n * @version 1.0\n */\npublic final class ExecuteLoadQueryLogEvent extends QueryLogEvent {\n\n    /** file_id of temporary file */\n    private long            fileId;\n\n    /** pointer to the part of the query that should be substituted */\n    private int             fnPosStart;\n\n    /** pointer to the end of this part of query */\n    private int             fnPosEnd;\n\n    /*\n     * Elements of this enum describe how LOAD DATA handles duplicates.\n     */\n    public static final int LOAD_DUP_ERROR          = 0;\n    public static final int LOAD_DUP_IGNORE         = LOAD_DUP_ERROR + 1;\n    public static final int LOAD_DUP_REPLACE        = LOAD_DUP_IGNORE + 1;\n\n    /**\n     * We have to store type of duplicate handling explicitly, because for LOAD\n     * DATA it also depends on LOCAL option. And this part of query will be\n     * rewritten during replication so this information may be lost...\n     */\n    private int             dupHandling;\n\n    /* ELQ = \"Execute Load Query\" */\n    public static final int ELQ_FILE_ID_OFFSET      = QUERY_HEADER_LEN;\n    public static final int ELQ_FN_POS_START_OFFSET = ELQ_FILE_ID_OFFSET + 4;\n    public static final int ELQ_FN_POS_END_OFFSET   = ELQ_FILE_ID_OFFSET + 8;\n    public static final int ELQ_DUP_HANDLING_OFFSET = ELQ_FILE_ID_OFFSET + 12;\n\n    public ExecuteLoadQueryLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent,\n                                    boolean compatiablePercona) throws IOException{\n        super(header, buffer, descriptionEvent, compatiablePercona);\n\n        buffer.position(descriptionEvent.commonHeaderLen + ELQ_FILE_ID_OFFSET);\n\n        fileId = buffer.getUint32(); // ELQ_FILE_ID_OFFSET\n        fnPosStart = (int) buffer.getUint32(); // ELQ_FN_POS_START_OFFSET\n        fnPosEnd = (int) buffer.getUint32(); // ELQ_FN_POS_END_OFFSET\n        dupHandling = buffer.getInt8(); // ELQ_DUP_HANDLING_OFFSET\n\n        final int len = query.length();\n        if (fnPosStart > len || fnPosEnd > len || dupHandling > LOAD_DUP_REPLACE) {\n            throw new IOException(String.format(\"Invalid ExecuteLoadQueryLogEvent: fn_pos_start=%d, \"\n                                                + \"fn_pos_end=%d, dup_handling=%d\", fnPosStart, fnPosEnd, dupHandling));\n        }\n    }\n\n    public final int getFilenamePosStart() {\n        return fnPosStart;\n    }\n\n    public final int getFilenamePosEnd() {\n        return fnPosEnd;\n    }\n\n    public final String getFilename() {\n        if (query != null) return query.substring(fnPosStart, fnPosEnd).trim();\n\n        return null;\n    }\n\n    public final long getFileId() {\n        return fileId;\n    }\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/FormatDescriptionLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport java.io.IOException;\n\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\n\n/**\n * For binlog version 4. This event is saved by threads which read it, as they\n * need it for future use (to decode the ordinary events).\n * \n * @see mysql-5.1.60/sql/log_event.cc - Format_description_log_event\n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\n * @version 1.0\n */\npublic final class FormatDescriptionLogEvent extends StartLogEventV3 {\n\n    /**\n     * The number of types we handle in Format_description_log_event\n     * (UNKNOWN_EVENT is not to be handled, it does not exist in binlogs, it\n     * does not have a format).\n     */\n    public static final int   LOG_EVENT_TYPES                     = (ENUM_END_EVENT - 1);\n\n    public static final int   ST_COMMON_HEADER_LEN_OFFSET         = (ST_SERVER_VER_OFFSET + ST_SERVER_VER_LEN + 4);\n\n    public static final int   OLD_HEADER_LEN                      = 13;\n    public static final int   LOG_EVENT_HEADER_LEN                = 19;\n    public static final int   LOG_EVENT_MINIMAL_HEADER_LEN        = 19;\n\n    /* event-specific post-header sizes */\n    public static final int   STOP_HEADER_LEN                     = 0;\n    public static final int   LOAD_HEADER_LEN                     = (4 + 4 + 4 + 1 + 1 + 4);\n    public static final int   SLAVE_HEADER_LEN                    = 0;\n    public static final int   START_V3_HEADER_LEN                 = (2 + ST_SERVER_VER_LEN + 4);\n    public static final int   ROTATE_HEADER_LEN                   = 8;                                                       // this\n    // is\n    // FROZEN\n    // (the\n    // Rotate\n    // post-header\n    // is\n    // frozen)\n    public static final int   INTVAR_HEADER_LEN                   = 0;\n    public static final int   CREATE_FILE_HEADER_LEN              = 4;\n    public static final int   APPEND_BLOCK_HEADER_LEN             = 4;\n    public static final int   EXEC_LOAD_HEADER_LEN                = 4;\n    public static final int   DELETE_FILE_HEADER_LEN              = 4;\n    public static final int   NEW_LOAD_HEADER_LEN                 = LOAD_HEADER_LEN;\n    public static final int   RAND_HEADER_LEN                     = 0;\n    public static final int   USER_VAR_HEADER_LEN                 = 0;\n    public static final int   FORMAT_DESCRIPTION_HEADER_LEN       = (START_V3_HEADER_LEN + 1 + LOG_EVENT_TYPES);\n    public static final int   XID_HEADER_LEN                      = 0;\n    public static final int   BEGIN_LOAD_QUERY_HEADER_LEN         = APPEND_BLOCK_HEADER_LEN;\n    public static final int   ROWS_HEADER_LEN_V1                  = 8;\n    public static final int   TABLE_MAP_HEADER_LEN                = 8;\n    public static final int   EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN = (4 + 4 + 4 + 1);\n    public static final int   EXECUTE_LOAD_QUERY_HEADER_LEN       = (QUERY_HEADER_LEN + EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN);\n    public static final int   INCIDENT_HEADER_LEN                 = 2;\n    public static final int   HEARTBEAT_HEADER_LEN                = 0;\n    public static final int   IGNORABLE_HEADER_LEN                = 0;\n    public static final int   ROWS_HEADER_LEN_V2                  = 10;\n    public static final int   TRANSACTION_CONTEXT_HEADER_LEN      = 18;\n    public static final int   VIEW_CHANGE_HEADER_LEN              = 52;\n    public static final int   XA_PREPARE_HEADER_LEN               = 0;\n    public static final int   TRANSACTION_PAYLOAD_HEADER_LEN      = 0;\n\n    public static final int   ANNOTATE_ROWS_HEADER_LEN            = 0;\n    public static final int   BINLOG_CHECKPOINT_HEADER_LEN        = 4;\n    public static final int   GTID_HEADER_LEN                     = 19;\n    public static final int   GTID_LIST_HEADER_LEN                = 4;\n    public static final int   START_ENCRYPTION_HEADER_LEN         = 0;\n\n    public static final int   POST_HEADER_LENGTH                  = 11;\n\n    public static final int   BINLOG_CHECKSUM_ALG_DESC_LEN        = 1;\n    public static final int[] checksumVersionSplit                = { 5, 6, 1 };\n    public static final long  checksumVersionProduct              = (checksumVersionSplit[0] * 256 + checksumVersionSplit[1])\n                                                                    * 256 + checksumVersionSplit[2];\n    /**\n     * The size of the fixed header which _all_ events have (for binlogs written\n     * by this version, this is equal to LOG_EVENT_HEADER_LEN), except\n     * FORMAT_DESCRIPTION_EVENT and ROTATE_EVENT (those have a header of size\n     * LOG_EVENT_MINIMAL_HEADER_LEN).\n     */\n    protected final int       commonHeaderLen;\n    protected int             numberOfEventTypes;\n\n    /** The list of post-headers' lengthes */\n    protected final short[]   postHeaderLen;\n    protected int[]           serverVersionSplit                  = new int[3];\n\n    public FormatDescriptionLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent)\n                                                                                                                    throws IOException{\n        /* Start_log_event_v3 */\n        super(header, buffer, descriptionEvent);\n\n        buffer.position(LOG_EVENT_MINIMAL_HEADER_LEN + ST_COMMON_HEADER_LEN_OFFSET);\n        commonHeaderLen = buffer.getUint8();\n        if (commonHeaderLen < OLD_HEADER_LEN) /* sanity check */\n        {\n            throw new IOException(\"Format Description event header length is too short\");\n        }\n\n        numberOfEventTypes = buffer.limit() - (LOG_EVENT_MINIMAL_HEADER_LEN + ST_COMMON_HEADER_LEN_OFFSET + 1);\n\n        // buffer.position(LOG_EVENT_MINIMAL_HEADER_LEN\n        // + ST_COMMON_HEADER_LEN_OFFSET + 1);\n        postHeaderLen = new short[numberOfEventTypes];\n        for (int i = 0; i < numberOfEventTypes; i++) {\n            postHeaderLen[i] = (short) buffer.getUint8();\n        }\n\n        calcServerVersionSplit();\n        long calc = getVersionProduct();\n        if (calc >= checksumVersionProduct) {\n            /*\n             * the last bytes are the checksum alg desc and value (or value's room)\n             */\n            numberOfEventTypes -= BINLOG_CHECKSUM_ALG_DESC_LEN;\n        }\n\n        if (logger.isInfoEnabled()) {\n            logger.info(\"common_header_len= \" + commonHeaderLen + \", number_of_event_types= \" + numberOfEventTypes);\n        }\n    }\n\n    /** MySQL 5.0 format descriptions. */\n    public static final FormatDescriptionLogEvent FORMAT_DESCRIPTION_EVENT_5_x   = new FormatDescriptionLogEvent(4);\n\n    /** MySQL 4.0.x (x>=2) format descriptions. */\n    public static final FormatDescriptionLogEvent FORMAT_DESCRIPTION_EVENT_4_0_x = new FormatDescriptionLogEvent(3);\n\n    /** MySQL 3.23 format descriptions. */\n    public static final FormatDescriptionLogEvent FORMAT_DESCRIPTION_EVENT_3_23  = new FormatDescriptionLogEvent(1);\n\n    public static FormatDescriptionLogEvent getFormatDescription(final int binlogVersion) throws IOException {\n        /* identify binlog format */\n        switch (binlogVersion) {\n            case 4: /* MySQL 5.0 */\n                return FORMAT_DESCRIPTION_EVENT_5_x;\n            case 3:\n                return FORMAT_DESCRIPTION_EVENT_4_0_x;\n            case 1:\n                return FORMAT_DESCRIPTION_EVENT_3_23;\n            default:\n                throw new IOException(\"Unknown binlog version: \" + binlogVersion);\n        }\n    }\n\n    public FormatDescriptionLogEvent(final int binlogVersion, int binlogChecksum){\n        this(binlogVersion);\n        this.header.checksumAlg = binlogChecksum;\n    }\n\n    public FormatDescriptionLogEvent(final int binlogVersion){\n        this.binlogVersion = binlogVersion;\n\n        postHeaderLen = new short[ENUM_END_EVENT];\n        /* identify binlog format */\n        switch (binlogVersion) {\n            case 4: /* MySQL 5.0 */\n                serverVersion = SERVER_VERSION;\n                commonHeaderLen = LOG_EVENT_HEADER_LEN;\n                numberOfEventTypes = LOG_EVENT_TYPES;\n\n                /*\n                 * Note: all event types must explicitly fill in their lengths\n                 * here.\n                 */\n                postHeaderLen[START_EVENT_V3 - 1] = START_V3_HEADER_LEN;\n                postHeaderLen[QUERY_EVENT - 1] = QUERY_HEADER_LEN;\n                postHeaderLen[STOP_EVENT - 1] = STOP_HEADER_LEN;\n                postHeaderLen[ROTATE_EVENT - 1] = ROTATE_HEADER_LEN;\n                postHeaderLen[INTVAR_EVENT - 1] = INTVAR_HEADER_LEN;\n                postHeaderLen[LOAD_EVENT - 1] = LOAD_HEADER_LEN;\n                postHeaderLen[SLAVE_EVENT - 1] = SLAVE_HEADER_LEN;\n                postHeaderLen[CREATE_FILE_EVENT - 1] = CREATE_FILE_HEADER_LEN;\n                postHeaderLen[APPEND_BLOCK_EVENT - 1] = APPEND_BLOCK_HEADER_LEN;\n                postHeaderLen[EXEC_LOAD_EVENT - 1] = EXEC_LOAD_HEADER_LEN;\n                postHeaderLen[DELETE_FILE_EVENT - 1] = DELETE_FILE_HEADER_LEN;\n                postHeaderLen[NEW_LOAD_EVENT - 1] = NEW_LOAD_HEADER_LEN;\n                postHeaderLen[RAND_EVENT - 1] = RAND_HEADER_LEN;\n                postHeaderLen[USER_VAR_EVENT - 1] = USER_VAR_HEADER_LEN;\n                postHeaderLen[FORMAT_DESCRIPTION_EVENT - 1] = FORMAT_DESCRIPTION_HEADER_LEN;\n                postHeaderLen[XID_EVENT - 1] = XID_HEADER_LEN;\n                postHeaderLen[BEGIN_LOAD_QUERY_EVENT - 1] = BEGIN_LOAD_QUERY_HEADER_LEN;\n                postHeaderLen[EXECUTE_LOAD_QUERY_EVENT - 1] = EXECUTE_LOAD_QUERY_HEADER_LEN;\n                postHeaderLen[TABLE_MAP_EVENT - 1] = TABLE_MAP_HEADER_LEN;\n                postHeaderLen[WRITE_ROWS_EVENT_V1 - 1] = ROWS_HEADER_LEN_V1;\n                postHeaderLen[UPDATE_ROWS_EVENT_V1 - 1] = ROWS_HEADER_LEN_V1;\n                postHeaderLen[DELETE_ROWS_EVENT_V1 - 1] = ROWS_HEADER_LEN_V1;\n                /*\n                 * We here have the possibility to simulate a master of before\n                 * we changed the table map id to be stored in 6 bytes: when it\n                 * was stored in 4 bytes (=> post_header_len was 6). This is\n                 * used to test backward compatibility. This code can be removed\n                 * after a few months (today is Dec 21st 2005), when we know\n                 * that the 4-byte masters are not deployed anymore (check with\n                 * Tomas Ulin first!), and the accompanying test\n                 * (rpl_row_4_bytes) too.\n                 */\n                postHeaderLen[HEARTBEAT_LOG_EVENT - 1] = 0;\n                postHeaderLen[IGNORABLE_LOG_EVENT - 1] = IGNORABLE_HEADER_LEN;\n                postHeaderLen[ROWS_QUERY_LOG_EVENT - 1] = IGNORABLE_HEADER_LEN;\n                postHeaderLen[WRITE_ROWS_EVENT - 1] = ROWS_HEADER_LEN_V2;\n                postHeaderLen[UPDATE_ROWS_EVENT - 1] = ROWS_HEADER_LEN_V2;\n                postHeaderLen[DELETE_ROWS_EVENT - 1] = ROWS_HEADER_LEN_V2;\n                postHeaderLen[GTID_LOG_EVENT - 1] = POST_HEADER_LENGTH;\n                postHeaderLen[ANONYMOUS_GTID_LOG_EVENT - 1] = POST_HEADER_LENGTH;\n                postHeaderLen[PREVIOUS_GTIDS_LOG_EVENT - 1] = IGNORABLE_HEADER_LEN;\n\n                postHeaderLen[TRANSACTION_CONTEXT_EVENT - 1] = TRANSACTION_CONTEXT_HEADER_LEN;\n                postHeaderLen[VIEW_CHANGE_EVENT - 1] = VIEW_CHANGE_HEADER_LEN;\n                postHeaderLen[XA_PREPARE_LOG_EVENT - 1] = XA_PREPARE_HEADER_LEN;\n                postHeaderLen[PARTIAL_UPDATE_ROWS_EVENT - 1] = ROWS_HEADER_LEN_V2;\n                postHeaderLen[TRANSACTION_PAYLOAD_EVENT - 1] = TRANSACTION_PAYLOAD_HEADER_LEN;\n\n                // mariadb 10\n                postHeaderLen[ANNOTATE_ROWS_EVENT - 1] = ANNOTATE_ROWS_HEADER_LEN;\n                postHeaderLen[BINLOG_CHECKPOINT_EVENT - 1] = BINLOG_CHECKPOINT_HEADER_LEN;\n                postHeaderLen[GTID_EVENT - 1] = GTID_HEADER_LEN;\n                postHeaderLen[GTID_LIST_EVENT - 1] = GTID_LIST_HEADER_LEN;\n                postHeaderLen[START_ENCRYPTION_EVENT - 1] = START_ENCRYPTION_HEADER_LEN;\n\n                // mariadb compress\n                postHeaderLen[QUERY_COMPRESSED_EVENT - 1] = QUERY_COMPRESSED_EVENT;\n                postHeaderLen[WRITE_ROWS_COMPRESSED_EVENT - 1] = ROWS_HEADER_LEN_V2;\n                postHeaderLen[UPDATE_ROWS_COMPRESSED_EVENT - 1] = ROWS_HEADER_LEN_V2;\n                postHeaderLen[DELETE_ROWS_COMPRESSED_EVENT - 1] = ROWS_HEADER_LEN_V2;\n                postHeaderLen[WRITE_ROWS_COMPRESSED_EVENT_V1 - 1] = ROWS_HEADER_LEN_V1;\n                postHeaderLen[UPDATE_ROWS_COMPRESSED_EVENT_V1 - 1] = ROWS_HEADER_LEN_V1;\n                postHeaderLen[DELETE_ROWS_COMPRESSED_EVENT_V1 - 1] = ROWS_HEADER_LEN_V1;\n                break;\n\n            case 3: /* 4.0.x x>=2 */\n                /*\n                 * We build an artificial (i.e. not sent by the master) event,\n                 * which describes what those old master versions send.\n                 */\n                serverVersion = \"4.0\";\n                commonHeaderLen = LOG_EVENT_MINIMAL_HEADER_LEN;\n\n                /*\n                 * The first new event in binlog version 4 is Format_desc. So\n                 * any event type after that does not exist in older versions.\n                 * We use the events known by version 3, even if version 1 had\n                 * only a subset of them (this is not a problem: it uses a few\n                 * bytes for nothing but unifies code; it does not make the\n                 * slave detect less corruptions).\n                 */\n                numberOfEventTypes = FORMAT_DESCRIPTION_EVENT - 1;\n\n                postHeaderLen[START_EVENT_V3 - 1] = START_V3_HEADER_LEN;\n                postHeaderLen[QUERY_EVENT - 1] = QUERY_HEADER_MINIMAL_LEN;\n                postHeaderLen[ROTATE_EVENT - 1] = ROTATE_HEADER_LEN;\n                postHeaderLen[LOAD_EVENT - 1] = LOAD_HEADER_LEN;\n                postHeaderLen[CREATE_FILE_EVENT - 1] = CREATE_FILE_HEADER_LEN;\n                postHeaderLen[APPEND_BLOCK_EVENT - 1] = APPEND_BLOCK_HEADER_LEN;\n                postHeaderLen[EXEC_LOAD_EVENT - 1] = EXEC_LOAD_HEADER_LEN;\n                postHeaderLen[DELETE_FILE_EVENT - 1] = DELETE_FILE_HEADER_LEN;\n                postHeaderLen[NEW_LOAD_EVENT - 1] = postHeaderLen[LOAD_EVENT - 1];\n                break;\n\n            case 1: /* 3.23 */\n                /*\n                 * We build an artificial (i.e. not sent by the master) event,\n                 * which describes what those old master versions send.\n                 */\n                serverVersion = \"3.23\";\n                commonHeaderLen = OLD_HEADER_LEN;\n\n                /*\n                 * The first new event in binlog version 4 is Format_desc. So\n                 * any event type after that does not exist in older versions.\n                 * We use the events known by version 3, even if version 1 had\n                 * only a subset of them (this is not a problem: it uses a few\n                 * bytes for nothing but unifies code; it does not make the\n                 * slave detect less corruptions).\n                 */\n                numberOfEventTypes = FORMAT_DESCRIPTION_EVENT - 1;\n\n                postHeaderLen[START_EVENT_V3 - 1] = START_V3_HEADER_LEN;\n                postHeaderLen[QUERY_EVENT - 1] = QUERY_HEADER_MINIMAL_LEN;\n                postHeaderLen[LOAD_EVENT - 1] = LOAD_HEADER_LEN;\n                postHeaderLen[CREATE_FILE_EVENT - 1] = CREATE_FILE_HEADER_LEN;\n                postHeaderLen[APPEND_BLOCK_EVENT - 1] = APPEND_BLOCK_HEADER_LEN;\n                postHeaderLen[EXEC_LOAD_EVENT - 1] = EXEC_LOAD_HEADER_LEN;\n                postHeaderLen[DELETE_FILE_EVENT - 1] = DELETE_FILE_HEADER_LEN;\n                postHeaderLen[NEW_LOAD_EVENT - 1] = postHeaderLen[LOAD_EVENT - 1];\n                break;\n\n            default:\n                numberOfEventTypes = 0;\n                commonHeaderLen = 0;\n        }\n    }\n\n    public void calcServerVersionSplit() {\n        doServerVersionSplit(serverVersion, serverVersionSplit);\n    }\n\n    public long getVersionProduct() {\n        return versionProduct(serverVersionSplit);\n    }\n\n    public boolean isVersionBeforeChecksum() {\n        return getVersionProduct() < checksumVersionProduct;\n    }\n\n    public static void doServerVersionSplit(String serverVersion, int[] versionSplit) {\n        String[] split = serverVersion.split(\"\\\\.\");\n        if (split.length < 3) {\n            versionSplit[0] = 0;\n            versionSplit[1] = 0;\n            versionSplit[2] = 0;\n        } else {\n            int j = 0;\n            for (int i = 0; i <= 2; i++) {\n                String str = split[i];\n                for (j = 0; j < str.length(); j++) {\n                    if (Character.isDigit(str.charAt(j)) == false) {\n                        break;\n                    }\n                }\n                if (j > 0) {\n                    versionSplit[i] = Integer.valueOf(str.substring(0, j), 10);\n                } else {\n                    versionSplit[0] = 0;\n                    versionSplit[1] = 0;\n                    versionSplit[2] = 0;\n                }\n            }\n        }\n    }\n\n    public static long versionProduct(int[] versionSplit) {\n        return ((versionSplit[0] * 256 + versionSplit[1]) * 256 + versionSplit[2]);\n    }\n\n    public final int getCommonHeaderLen() {\n        return commonHeaderLen;\n    }\n\n    public final short[] getPostHeaderLen() {\n        return postHeaderLen;\n    }\n\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/GtidLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport java.nio.ByteBuffer;\nimport java.util.UUID;\n\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\n\n/**\n * @author jianghang 2013-4-8 上午12:36:29\n * @version 1.0.3\n * @since mysql 5.6 / mariadb10\n */\npublic class GtidLogEvent extends LogEvent {\n\n    // / Length of the commit_flag in event encoding\n    public static final int ENCODED_FLAG_LENGTH         = 1;\n    // / Length of SID in event encoding\n    public static final int ENCODED_SID_LENGTH          = 16;\n    public static final int LOGICAL_TIMESTAMP_TYPE_CODE = 2;\n    public static final UUID UUID_ZERO                   = new UUID(0, 0);\n\n    private boolean         commitFlag;\n    private UUID            sid;\n    private long            gno;\n    private long            lastCommitted;\n    private long            sequenceNumber;\n\n    public GtidLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\n        super(header);\n\n        final int commonHeaderLen = descriptionEvent.commonHeaderLen;\n        // final int postHeaderLen = descriptionEvent.postHeaderLen[header.type\n        // - 1];\n\n        buffer.position(commonHeaderLen);\n        commitFlag = (buffer.getUint8() != 0); // ENCODED_FLAG_LENGTH\n\n        long high = buffer.getBeLong64();\n        long low = buffer.getBeLong64();\n        if (high == 0 && low == 0) {\n            sid = UUID_ZERO;\n        } else {\n            sid = new UUID(high, low);\n        }\n\n        gno = buffer.getLong64();\n\n        // support gtid lastCommitted and sequenceNumber\n        // fix bug #776\n        if (buffer.hasRemaining() && buffer.remaining() > 16 && buffer.getUint8() == LOGICAL_TIMESTAMP_TYPE_CODE) {\n            lastCommitted = buffer.getLong64();\n            sequenceNumber = buffer.getLong64();\n        }\n\n        // ignore gtid info read\n        // sid.copy_from((uchar *)ptr_buffer);\n        // ptr_buffer+= ENCODED_SID_LENGTH;\n        //\n        // // SIDNO is only generated if needed, in get_sidno().\n        // spec.gtid.sidno= -1;\n        //\n        // spec.gtid.gno= uint8korr(ptr_buffer);\n        // ptr_buffer+= ENCODED_GNO_LENGTH;\n    }\n\n    public boolean isCommitFlag() {\n        return commitFlag;\n    }\n\n    public UUID getSid() {\n        return sid;\n    }\n\n    public long getGno() {\n        return gno;\n    }\n\n    public long getLastCommitted() {\n        return lastCommitted;\n    }\n\n    public long getSequenceNumber() {\n        return sequenceNumber;\n    }\n\n    public String getGtidStr() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(sid.toString()).append(\":\");\n        sb.append(gno);\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/HeartbeatLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\n\nimport java.nio.charset.StandardCharsets;\n\n/**\n * <pre>\n * Replication event to ensure to slave that master is alive.\n *   The event is originated by master's dump thread and sent straight to\n *   slave without being logged. Slave itself does not store it in relay log\n *   but rather uses a data for immediate checks and throws away the event.\n * \n *   Two members of the class log_ident and Log_event::log_pos comprise \n *   @see the event_coordinates instance. The coordinates that a heartbeat\n *   instance carries correspond to the last event master has sent from\n *   its binlog.\n * </pre>\n * \n * @author jianghang 2013-4-8 上午12:36:29\n * @version 1.0.3\n * @since mysql 5.6\n */\npublic class HeartbeatLogEvent extends LogEvent {\n\n    public static final int FN_REFLEN = 512; /* Max length of full path-name */\n    private int             identLen;\n    private String          logIdent;\n\n    public HeartbeatLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\n        super(header);\n\n        final int commonHeaderLen = descriptionEvent.commonHeaderLen;\n        identLen = buffer.limit() - commonHeaderLen;\n        if (identLen > FN_REFLEN - 1) {\n            identLen = FN_REFLEN - 1;\n        }\n\n        logIdent = buffer.getFullString(commonHeaderLen, identLen, StandardCharsets.ISO_8859_1);\n    }\n\n    public int getIdentLen() {\n        return identLen;\n    }\n\n    public String getLogIdent() {\n        return logIdent;\n    }\n\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/HeartbeatV2LogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\n\n/**\n * <pre>\n *   Replication event to ensure to replica that source is alive.\n *   The event is originated by source's dump thread and sent straight to\n *   replica without being logged. Slave itself does not store it in relay log\n *   but rather uses a data for immediate checks and throws away the event.\n *   Two members of the class m_log_filename and m_log_position comprise\n *   @see the rpl_event_coordinates instance. The coordinates that a heartbeat\n *   instance carries correspond to the last event source has sent from\n *   its binlog.\n *   Also this event will be generated only for the source server with\n *   version > 8.0.26\n * </pre>\n * \n * @author jianghang 2022-09-01 下午16:36:29\n * @version 1.1.6\n * @since mysql 8.0.26\n */\npublic class HeartbeatV2LogEvent extends LogEvent {\n\n    private byte[]          payload;\n\n    public HeartbeatV2LogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\n        super(header);\n\n        final int commonHeaderLen = descriptionEvent.commonHeaderLen;\n        int payloadLenth = buffer.limit() - commonHeaderLen;\n        // see : https://github.com/mysql/mysql-server/commit/59e590738a772b74ad50c4a57c86aaa1bc6501c7#diff-184e9a7d8a58f080974e475d4199fe5c6da5518c8a2811cc5df5988c8f9e9797\n        payload = buffer.getData(payloadLenth);\n    }\n\n    public byte[] getPayload() {\n        return payload;\n    }\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/IgnorableLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\n\n/**\n * <pre>\n *   Base class for ignorable log events. Events deriving from\n *   this class can be safely ignored by slaves that cannot\n *   recognize them. Newer slaves, will be able to read and\n *   handle them. This has been designed to be an open-ended\n *   architecture, so adding new derived events shall not harm\n *   the old slaves that support ignorable log event mechanism\n *   (they will just ignore unrecognized ignorable events).\n * \n *   @note The only thing that makes an event ignorable is that it has\n *   the LOG_EVENT_IGNORABLE_F flag set.  It is not strictly necessary\n *   that ignorable event types derive from Ignorable_log_event; they may\n *   just as well derive from Log_event and pass LOG_EVENT_IGNORABLE_F as\n *   argument to the Log_event constructor.\n * </pre>\n * \n * @author jianghang 2013-4-8 上午12:36:29\n * @version 1.0.3\n * @since mysql 5.6\n */\npublic class IgnorableLogEvent extends LogEvent {\n\n    public IgnorableLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\n        super(header);\n\n        // do nothing , just ignore log event\n    }\n\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/IncidentLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\r\n\r\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\r\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\r\n\r\n/**\r\n * Class representing an incident, an occurance out of the ordinary, that\r\n * happened on the master. The event is used to inform the slave that something\r\n * out of the ordinary happened on the master that might cause the database to\r\n * be in an inconsistent state.\r\n * <table id=\"IncidentFormat\">\r\n * <caption>Incident event format</caption>\r\n * <tr>\r\n * <th>Symbol</th>\r\n * <th>Format</th>\r\n * <th>Description</th>\r\n * </tr>\r\n * <tr>\r\n * <td>INCIDENT</td>\r\n * <td align=\"right\">2</td>\r\n * <td>Incident number as an unsigned integer</td>\r\n * </tr>\r\n * <tr>\r\n * <td>MSGLEN</td>\r\n * <td align=\"right\">1</td>\r\n * <td>Message length as an unsigned integer</td>\r\n * </tr>\r\n * <tr>\r\n * <td>MESSAGE</td>\r\n * <td align=\"right\">MSGLEN</td>\r\n * <td>The message, if present. Not null terminated.</td>\r\n * </tr>\r\n * </table>\r\n * \r\n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\r\n * @version 1.0\r\n */\r\npublic final class IncidentLogEvent extends LogEvent {\r\n\r\n    public static final int INCIDENT_NONE        = 0;\r\n\r\n    /** There are possibly lost events in the replication stream */\r\n    public static final int INCIDENT_LOST_EVENTS = 1;\r\n\r\n    /** Shall be last event of the enumeration */\r\n    public static final int INCIDENT_COUNT       = 2;\r\n\r\n    private final int       incident;\r\n    private final String    message;\r\n\r\n    public IncidentLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\r\n        super(header);\r\n\r\n        final int commonHeaderLen = descriptionEvent.commonHeaderLen;\r\n        final int postHeaderLen = descriptionEvent.postHeaderLen[header.type - 1];\r\n\r\n        buffer.position(commonHeaderLen);\r\n        final int incidentNumber = buffer.getUint16();\r\n        if (incidentNumber >= INCIDENT_COUNT || incidentNumber <= INCIDENT_NONE) {\r\n            // If the incident is not recognized, this binlog event is\r\n            // invalid. If we set incident_number to INCIDENT_NONE, the\r\n            // invalidity will be detected by is_valid().\r\n            incident = INCIDENT_NONE;\r\n            message = null;\r\n            return;\r\n        }\r\n        incident = incidentNumber;\r\n\r\n        buffer.position(commonHeaderLen + postHeaderLen);\r\n        message = buffer.getName();\r\n    }\r\n\r\n    public final int getIncident() {\r\n        return incident;\r\n    }\r\n\r\n    public final String getMessage() {\r\n        return message;\r\n    }\r\n}\r\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/IntvarLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\n\n/**\n * An Intvar_log_event will be created just before a Query_log_event, if the\n * query uses one of the variables LAST_INSERT_ID or INSERT_ID. Each\n * Intvar_log_event holds the value of one of these variables. Binary Format The\n * Post-Header for this event type is empty. The Body has two components:\n * <table>\n * <caption>Body for Intvar_log_event</caption>\n * <tr>\n * <th>Name</th>\n * <th>Format</th>\n * <th>Description</th>\n * </tr>\n * <tr>\n * <td>type</td>\n * <td>1 byte enumeration</td>\n * <td>One byte identifying the type of variable stored. Currently, two\n * identifiers are supported: LAST_INSERT_ID_EVENT==1 and INSERT_ID_EVENT==2.</td>\n * </tr>\n * <tr>\n * <td>value</td>\n * <td>8 byte unsigned integer</td>\n * <td>The value of the variable.</td>\n * </tr>\n * </table>\n * \n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\n * @version 1.0\n */\npublic final class IntvarLogEvent extends LogEvent {\n\n    /**\n     * Fixed data part: Empty\n     * <p>\n     * Variable data part:\n     * <ul>\n     * <li>1 byte. A value indicating the variable type: LAST_INSERT_ID_EVENT =\n     * 1 or INSERT_ID_EVENT = 2.</li>\n     * <li>8 bytes. An unsigned integer indicating the value to be used for the\n     * LAST_INSERT_ID() invocation or AUTO_INCREMENT column.</li>\n     * </ul>\n     * Source : http://forge.mysql.com/wiki/MySQL_Internals_Binary_Log\n     */\n    private final long      value;\n    private final int       type;\n\n    /* Intvar event data */\n    public static final int I_TYPE_OFFSET        = 0;\n    public static final int I_VAL_OFFSET         = 1;\n\n    // enum Int_event_type\n    public static final int INVALID_INT_EVENT    = 0;\n    public static final int LAST_INSERT_ID_EVENT = 1;\n    public static final int INSERT_ID_EVENT      = 2;\n\n    public IntvarLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\n        super(header);\n\n        /* The Post-Header is empty. The Varible Data part begins immediately. */\n        buffer.position(descriptionEvent.commonHeaderLen + descriptionEvent.postHeaderLen[INTVAR_EVENT - 1]\n                        + I_TYPE_OFFSET);\n        type = buffer.getInt8(); // I_TYPE_OFFSET\n        value = buffer.getLong64(); // !uint8korr(buf + I_VAL_OFFSET);\n    }\n\n    public final int getType() {\n        return type;\n    }\n\n    public final long getValue() {\n        return value;\n    }\n\n    public final String getQuery() {\n        return \"SET INSERT_ID = \" + value;\n    }\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/LoadLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\r\n\r\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\r\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\r\n\r\n/**\r\n * This log event corresponds to a \"LOAD DATA INFILE\" SQL query on the following\r\n * form:\r\n * \r\n * <pre>\r\n *    (1)    USE db;\r\n *    (2)    LOAD DATA [CONCURRENT] [LOCAL] INFILE 'file_name'\r\n *    (3)    [REPLACE | IGNORE]\r\n *    (4)    INTO TABLE 'table_name'\r\n *    (5)    [FIELDS\r\n *    (6)      [TERMINATED BY 'field_term']\r\n *    (7)      [[OPTIONALLY] ENCLOSED BY 'enclosed']\r\n *    (8)      [ESCAPED BY 'escaped']\r\n *    (9)    ]\r\n *   (10)    [LINES\r\n *   (11)      [TERMINATED BY 'line_term']\r\n *   (12)      [LINES STARTING BY 'line_start']\r\n *   (13)    ]\r\n *   (14)    [IGNORE skip_lines LINES]\r\n *   (15)    (field_1, field_2, ..., field_n)\r\n * </pre>\r\n * \r\n * Binary Format: The Post-Header consists of the following six components.\r\n * <table>\r\n * <caption>Post-Header for Load_log_event</caption>\r\n * <tr>\r\n * <th>Name</th>\r\n * <th>Format</th>\r\n * <th>Description</th>\r\n * </tr>\r\n * <tr>\r\n * <td>slave_proxy_id</td>\r\n * <td>4 byte unsigned integer</td>\r\n * <td>An integer identifying the client thread that issued the query. The id is\r\n * unique per server. (Note, however, that two threads on different servers may\r\n * have the same slave_proxy_id.) This is used when a client thread creates a\r\n * temporary table local to the client. The slave_proxy_id is used to\r\n * distinguish temporary tables that belong to different clients.</td>\r\n * </tr>\r\n * <tr>\r\n * <td>exec_time</td>\r\n * <td>4 byte unsigned integer</td>\r\n * <td>The time from when the query started to when it was logged in the binlog,\r\n * in seconds.</td>\r\n * </tr>\r\n * <tr>\r\n * <td>skip_lines</td>\r\n * <td>4 byte unsigned integer</td>\r\n * <td>The number on line (14) above, if present, or 0 if line (14) is left out.\r\n * </td>\r\n * </tr>\r\n * <tr>\r\n * <td>table_name_len</td>\r\n * <td>1 byte unsigned integer</td>\r\n * <td>The length of 'table_name' on line (4) above.</td>\r\n * </tr>\r\n * <tr>\r\n * <td>db_len</td>\r\n * <td>1 byte unsigned integer</td>\r\n * <td>The length of 'db' on line (1) above.</td>\r\n * </tr>\r\n * <tr>\r\n * <td>num_fields</td>\r\n * <td>4 byte unsigned integer</td>\r\n * <td>The number n of fields on line (15) above.</td>\r\n * </tr>\r\n * </table>\r\n * The Body contains the following components.\r\n * <table>\r\n * <caption>Body of Load_log_event</caption>\r\n * <tr>\r\n * <th>Name</th>\r\n * <th>Format</th>\r\n * <th>Description</th>\r\n * </tr>\r\n * <tr>\r\n * <td>sql_ex</td>\r\n * <td>variable length</td>\r\n * <td>Describes the part of the query on lines (3) and (5)&ndash;(13) above.\r\n * More precisely, it stores the five strings (on lines) field_term (6),\r\n * enclosed (7), escaped (8), line_term (11), and line_start (12); as well as a\r\n * bitfield indicating the presence of the keywords REPLACE (3), IGNORE (3), and\r\n * OPTIONALLY (7). The data is stored in one of two formats, called \"old\" and\r\n * \"new\". The type field of Common-Header determines which of these two formats\r\n * is used: type LOAD_EVENT means that the old format is used, and type\r\n * NEW_LOAD_EVENT means that the new format is used. When MySQL writes a\r\n * Load_log_event, it uses the new format if at least one of the five strings is\r\n * two or more bytes long. Otherwise (i.e., if all strings are 0 or 1 bytes\r\n * long), the old format is used. The new and old format differ in the way the\r\n * five strings are stored.\r\n * <ul>\r\n * <li>In the new format, the strings are stored in the order field_term,\r\n * enclosed, escaped, line_term, line_start. Each string consists of a length (1\r\n * byte), followed by a sequence of characters (0-255 bytes). Finally, a boolean\r\n * combination of the following flags is stored in 1 byte: REPLACE_FLAG==0x4,\r\n * IGNORE_FLAG==0x8, and OPT_ENCLOSED_FLAG==0x2. If a flag is set, it indicates\r\n * the presence of the corresponding keyword in the SQL query.\r\n * <li>In the old format, we know that each string has length 0 or 1. Therefore,\r\n * only the first byte of each string is stored. The order of the strings is the\r\n * same as in the new format. These five bytes are followed by the same 1 byte\r\n * bitfield as in the new format. Finally, a 1 byte bitfield called empty_flags\r\n * is stored. The low 5 bits of empty_flags indicate which of the five strings\r\n * have length 0. For each of the following flags that is set, the corresponding\r\n * string has length 0; for the flags that are not set, the string has length 1:\r\n * FIELD_TERM_EMPTY==0x1, ENCLOSED_EMPTY==0x2, LINE_TERM_EMPTY==0x4,\r\n * LINE_START_EMPTY==0x8, ESCAPED_EMPTY==0x10.\r\n * </ul>\r\n * Thus, the size of the new format is 6 bytes + the sum of the sizes of the\r\n * five strings. The size of the old format is always 7 bytes.</td>\r\n * </tr>\r\n * <tr>\r\n * <td>field_lens</td>\r\n * <td>num_fields 1 byte unsigned integers</td>\r\n * <td>An array of num_fields integers representing the length of each field in\r\n * the query. (num_fields is from the Post-Header).</td>\r\n * </tr>\r\n * <tr>\r\n * <td>fields</td>\r\n * <td>num_fields null-terminated strings</td>\r\n * <td>An array of num_fields null-terminated strings, each representing a field\r\n * in the query. (The trailing zero is redundant, since the length are stored in\r\n * the num_fields array.) The total length of all strings equals to the sum of\r\n * all field_lens, plus num_fields bytes for all the trailing zeros.</td>\r\n * </tr>\r\n * <tr>\r\n * <td>table_name</td>\r\n * <td>null-terminated string of length table_len+1 bytes</td>\r\n * <td>The 'table_name' from the query, as a null-terminated string. (The\r\n * trailing zero is actually redundant since the table_len is known from\r\n * Post-Header.)</td>\r\n * </tr>\r\n * <tr>\r\n * <td>db</td>\r\n * <td>null-terminated string of length db_len+1 bytes</td>\r\n * <td>The 'db' from the query, as a null-terminated string. (The trailing zero\r\n * is actually redundant since the db_len is known from Post-Header.)</td>\r\n * </tr>\r\n * <tr>\r\n * <td>file_name</td>\r\n * <td>variable length string without trailing zero, extending to the end of the\r\n * event (determined by the length field of the Common-Header)</td>\r\n * <td>The 'file_name' from the query.</td>\r\n * </tr>\r\n * </table>\r\n * This event type is understood by current versions, but only generated by\r\n * MySQL 3.23 and earlier.\r\n * \r\n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\r\n * @version 1.0\r\n */\r\npublic class LoadLogEvent extends LogEvent {\r\n\r\n    private String          table;\r\n    private String          db;\r\n    private String          fname;\r\n    private int             skipLines;\r\n    private int             numFields;\r\n    private String[]        fields;\r\n\r\n    /* sql_ex_info */\r\n    private String          fieldTerm;\r\n    private String          lineTerm;\r\n    private String          lineStart;\r\n    private String          enclosed;\r\n    private String          escaped;\r\n    private int             optFlags;\r\n    private int             emptyFlags;\r\n\r\n    private long            execTime;\r\n\r\n    /* Load event post-header */\r\n    public static final int L_THREAD_ID_OFFSET  = 0;\r\n    public static final int L_EXEC_TIME_OFFSET  = 4;\r\n    public static final int L_SKIP_LINES_OFFSET = 8;\r\n    public static final int L_TBL_LEN_OFFSET    = 12;\r\n    public static final int L_DB_LEN_OFFSET     = 13;\r\n    public static final int L_NUM_FIELDS_OFFSET = 14;\r\n    public static final int L_SQL_EX_OFFSET     = 18;\r\n    public static final int L_DATA_OFFSET       = FormatDescriptionLogEvent.LOAD_HEADER_LEN;\r\n\r\n    /*\r\n     * These are flags and structs to handle all the LOAD DATA INFILE options\r\n     * (LINES TERMINATED etc). DUMPFILE_FLAG is probably useless (DUMPFILE is a\r\n     * clause of SELECT, not of LOAD DATA).\r\n     */\r\n    public static final int DUMPFILE_FLAG       = 0x1;\r\n    public static final int OPT_ENCLOSED_FLAG   = 0x2;\r\n    public static final int REPLACE_FLAG        = 0x4;\r\n    public static final int IGNORE_FLAG         = 0x8;\r\n\r\n    public static final int FIELD_TERM_EMPTY    = 0x1;\r\n    public static final int ENCLOSED_EMPTY      = 0x2;\r\n    public static final int LINE_TERM_EMPTY     = 0x4;\r\n    public static final int LINE_START_EMPTY    = 0x8;\r\n    public static final int ESCAPED_EMPTY       = 0x10;\r\n\r\n    public LoadLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\r\n        super(header);\r\n\r\n        final int loadHeaderLen = FormatDescriptionLogEvent.LOAD_HEADER_LEN;\r\n        /*\r\n         * I (Guilhem) manually tested replication of LOAD DATA INFILE for\r\n         * 3.23->5.0, 4.0->5.0 and 5.0->5.0 and it works.\r\n         */\r\n        copyLogEvent(buffer,\r\n            ((header.type == LOAD_EVENT) ? loadHeaderLen + descriptionEvent.commonHeaderLen : loadHeaderLen\r\n                                                                                              + FormatDescriptionLogEvent.LOG_EVENT_HEADER_LEN),\r\n            descriptionEvent);\r\n    }\r\n\r\n    /**\r\n     * @see mysql-5.1.60/sql/log_event.cc - Load_log_event::copy_log_event\r\n     */\r\n    protected final void copyLogEvent(LogBuffer buffer, final int bodyOffset, FormatDescriptionLogEvent descriptionEvent) {\r\n        /* this is the beginning of the post-header */\r\n        buffer.position(descriptionEvent.commonHeaderLen + L_EXEC_TIME_OFFSET);\r\n\r\n        execTime = buffer.getUint32(); // L_EXEC_TIME_OFFSET\r\n        skipLines = (int) buffer.getUint32(); // L_SKIP_LINES_OFFSET\r\n        final int tableNameLen = buffer.getUint8(); // L_TBL_LEN_OFFSET\r\n        final int dbLen = buffer.getUint8(); // L_DB_LEN_OFFSET\r\n        numFields = (int) buffer.getUint32(); // L_NUM_FIELDS_OFFSET\r\n\r\n        buffer.position(bodyOffset);\r\n        /*\r\n         * Sql_ex.init() on success returns the pointer to the first byte after\r\n         * the sql_ex structure, which is the start of field lengths array.\r\n         */\r\n        if (header.type != LOAD_EVENT /* use_new_format */) {\r\n            /*\r\n             * The code below assumes that buf will not disappear from under our\r\n             * feet during the lifetime of the event. This assumption holds true\r\n             * in the slave thread if the log is in new format, but is not the\r\n             * case when we have old format because we will be reusing net\r\n             * buffer to read the actual file before we write out the\r\n             * Create_file event.\r\n             */\r\n            fieldTerm = buffer.getString();\r\n            enclosed = buffer.getString();\r\n            lineTerm = buffer.getString();\r\n            lineStart = buffer.getString();\r\n            escaped = buffer.getString();\r\n            optFlags = buffer.getInt8();\r\n            emptyFlags = 0;\r\n        } else {\r\n            fieldTerm = buffer.getFixString(1);\r\n            enclosed = buffer.getFixString(1);\r\n            lineTerm = buffer.getFixString(1);\r\n            lineStart = buffer.getFixString(1);\r\n            escaped = buffer.getFixString(1);\r\n            optFlags = buffer.getUint8();\r\n            emptyFlags = buffer.getUint8();\r\n\r\n            if ((emptyFlags & FIELD_TERM_EMPTY) != 0) fieldTerm = null;\r\n            if ((emptyFlags & ENCLOSED_EMPTY) != 0) enclosed = null;\r\n            if ((emptyFlags & LINE_TERM_EMPTY) != 0) lineTerm = null;\r\n            if ((emptyFlags & LINE_START_EMPTY) != 0) lineStart = null;\r\n            if ((emptyFlags & ESCAPED_EMPTY) != 0) escaped = null;\r\n        }\r\n\r\n        final int fieldLenPos = buffer.position();\r\n        buffer.forward(numFields);\r\n        fields = new String[numFields];\r\n        for (int i = 0; i < numFields; i++) {\r\n            final int fieldLen = buffer.getUint8(fieldLenPos + i);\r\n            fields[i] = buffer.getFixString(fieldLen + 1);\r\n        }\r\n\r\n        table = buffer.getFixString(tableNameLen + 1);\r\n        db = buffer.getFixString(dbLen + 1);\r\n\r\n        // null termination is accomplished by the caller\r\n        final int from = buffer.position();\r\n        final int end = from + buffer.limit();\r\n        int found = from;\r\n        for (; (found < end) && buffer.getInt8(found) != '\\0'; found++)\r\n            /* empty loop */;\r\n        fname = buffer.getString(found);\r\n        buffer.forward(1); // The + 1 is for \\0 terminating fname\r\n    }\r\n\r\n    public final String getTable() {\r\n        return table;\r\n    }\r\n\r\n    public final String getDb() {\r\n        return db;\r\n    }\r\n\r\n    public final String getFname() {\r\n        return fname;\r\n    }\r\n\r\n    public final int getSkipLines() {\r\n        return skipLines;\r\n    }\r\n\r\n    public final String[] getFields() {\r\n        return fields;\r\n    }\r\n\r\n    public final String getFieldTerm() {\r\n        return fieldTerm;\r\n    }\r\n\r\n    public final String getLineTerm() {\r\n        return lineTerm;\r\n    }\r\n\r\n    public final String getLineStart() {\r\n        return lineStart;\r\n    }\r\n\r\n    public final String getEnclosed() {\r\n        return enclosed;\r\n    }\r\n\r\n    public final String getEscaped() {\r\n        return escaped;\r\n    }\r\n\r\n    public final int getOptFlags() {\r\n        return optFlags;\r\n    }\r\n\r\n    public final int getEmptyFlags() {\r\n        return emptyFlags;\r\n    }\r\n\r\n    public final long getExecTime() {\r\n        return execTime;\r\n    }\r\n}\r\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/LogHeader.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.GTIDSet;\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\n\n/**\n * The Common-Header, documented in the table @ref Table_common_header \"below\",\n * always has the same form and length within one version of MySQL. Each event\n * type specifies a format and length of the Post-Header. The length of the\n * Common-Header is the same for all events of the same type. The Body may be of\n * different format and length even for different events of the same type. The\n * binary formats of Post-Header and Body are documented separately in each\n * subclass. The binary format of Common-Header is as follows.\n * <table>\n * <caption>Common-Header</caption>\n * <tr>\n * <th>Name</th>\n * <th>Format</th>\n * <th>Description</th>\n * </tr>\n * <tr>\n * <td>timestamp</td>\n * <td>4 byte unsigned integer</td>\n * <td>The time when the query started, in seconds since 1970.</td>\n * </tr>\n * <tr>\n * <td>type</td>\n * <td>1 byte enumeration</td>\n * <td>See enum #Log_event_type.</td>\n * </tr>\n * <tr>\n * <td>server_id</td>\n * <td>4 byte unsigned integer</td>\n * <td>Server ID of the server that created the event.</td>\n * </tr>\n * <tr>\n * <td>total_size</td>\n * <td>4 byte unsigned integer</td>\n * <td>The total size of this event, in bytes. In other words, this is the sum\n * of the sizes of Common-Header, Post-Header, and Body.</td>\n * </tr>\n * <tr>\n * <td>master_position</td>\n * <td>4 byte unsigned integer</td>\n * <td>The position of the next event in the master binary log, in bytes from\n * the beginning of the file. In a binlog that is not a relay log, this is just\n * the position of the next event, in bytes from the beginning of the file. In a\n * relay log, this is the position of the next event in the master's binlog.</td>\n * </tr>\n * <tr>\n * <td>flags</td>\n * <td>2 byte bitfield</td>\n * <td>See Log_event::flags.</td>\n * </tr>\n * </table>\n * Summing up the numbers above, we see that the total size of the common header\n * is 19 bytes.\n * \n * @see mysql-5.1.60/sql/log_event.cc\n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\n * @version 1.0\n */\npublic final class LogHeader {\n\n    protected int                 type;\n\n    /**\n     * The offset in the log where this event originally appeared (it is\n     * preserved in relay logs, making SHOW SLAVE STATUS able to print\n     * coordinates of the event in the master's binlog). Note: when a\n     * transaction is written by the master to its binlog (wrapped in\n     * BEGIN/COMMIT) the log_pos of all the queries it contains is the one of\n     * the BEGIN (this way, when one does SHOW SLAVE STATUS it sees the offset\n     * of the BEGIN, which is logical as rollback may occur), except the COMMIT\n     * query which has its real offset.\n     */\n    protected long      logPos;\n\n    /**\n     * Timestamp on the master(for debugging and replication of\n     * NOW()/TIMESTAMP). It is important for queries and LOAD DATA INFILE. This\n     * is set at the event's creation time, except for Query and Load (et al.)\n     * events where this is set at the query's execution time, which guarantees\n     * good replication (otherwise, we could have a query and its event with\n     * different timestamps).\n     */\n    protected long      when;\n\n    /** Number of bytes written by write() function */\n    protected int       eventLen;\n\n    /**\n     * The master's server id (is preserved in the relay log; used to prevent\n     * from infinite loops in circular replication).\n     */\n    protected long      serverId;\n\n    /**\n     * Some 16 flags. See the definitions above for LOG_EVENT_TIME_F,\n     * LOG_EVENT_FORCED_ROTATE_F, LOG_EVENT_THREAD_SPECIFIC_F, and\n     * LOG_EVENT_SUPPRESS_USE_F for notes.\n     */\n    protected int       flags;\n\n    /**\n     * The value is set by caller of FD constructor and\n     * Log_event::write_header() for the rest. In the FD case it's propagated\n     * into the last byte of post_header_len[] at FD::write(). On the slave side\n     * the value is assigned from post_header_len[last] of the last seen FD\n     * event.\n     */\n    protected int       checksumAlg;\n    /**\n     * Placeholder for event checksum while writing to binlog.\n     */\n    protected long      crc;        // ha_checksum\n\n    /**\n     * binlog fileName\n     */\n    protected String    logFileName;\n\n    protected Map<String, String> gtidMap = new HashMap<>();\n\n    private static final String CURRENT_GTID_STRING = \"curt_gtid\";\n    private static final String CURRENT_GTID_SN = \"curt_gtid_sn\";\n    private static final String CURRENT_GTID_LAST_COMMIT = \"curt_gtid_lct\";\n    private static final String GTID_SET_STRING = \"gtid_str\";\n\n    /* for Start_event_v3 */\n    public LogHeader(final int type){\n        this.type = type;\n    }\n\n    public LogHeader(LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\n        when = buffer.getUint32();\n        type = buffer.getUint8(); // LogEvent.EVENT_TYPE_OFFSET;\n        serverId = buffer.getUint32(); // LogEvent.SERVER_ID_OFFSET;\n        eventLen = (int) buffer.getUint32(); // LogEvent.EVENT_LEN_OFFSET;\n\n        if (descriptionEvent.binlogVersion == 1) {\n            logPos = 0;\n            flags = 0;\n            return;\n        }\n\n        /* 4.0 or newer */\n        logPos = buffer.getUint32(); // LogEvent.LOG_POS_OFFSET\n        /*\n         * If the log is 4.0 (so here it can only be a 4.0 relay log read by the\n         * SQL thread or a 4.0 master binlog read by the I/O thread), log_pos is\n         * the beginning of the event: we transform it into the end of the\n         * event, which is more useful. But how do you know that the log is 4.0:\n         * you know it if description_event is version 3 *and* you are not\n         * reading a Format_desc (remember that mysqlbinlog starts by assuming\n         * that 5.0 logs are in 4.0 format, until it finds a Format_desc).\n         */\n        if (descriptionEvent.binlogVersion == 3 && type < LogEvent.FORMAT_DESCRIPTION_EVENT && logPos != 0) {\n            /*\n             * If log_pos=0, don't change it. log_pos==0 is a marker to mean\n             * \"don't change rli->group_master_log_pos\" (see\n             * inc_group_relay_log_pos()). As it is unreal log_pos, adding the\n             * event len's is nonsense. For example, a fake Rotate event should\n             * not have its log_pos (which is 0) changed or it will modify\n             * Exec_master_log_pos in SHOW SLAVE STATUS, displaying a nonsense\n             * value of (a non-zero offset which does not exist in the master's\n             * binlog, so which will cause problems if the user uses this value\n             * in CHANGE MASTER).\n             */\n            logPos += eventLen; /* purecov: inspected */\n        }\n\n        flags = buffer.getUint16(); // LogEvent.FLAGS_OFFSET\n        if ((type == LogEvent.FORMAT_DESCRIPTION_EVENT) || (type == LogEvent.ROTATE_EVENT)) {\n            /*\n             * These events always have a header which stops here (i.e. their\n             * header is FROZEN).\n             */\n            /*\n             * Initialization to zero of all other Log_event members as they're\n             * not specified. Currently there are no such members; in the future\n             * there will be an event UID (but Format_description and Rotate\n             * don't need this UID, as they are not propagated through\n             * --log-slave-updates (remember the UID is used to not play a query\n             * twice when you have two masters which are slaves of a 3rd\n             * master). Then we are done.\n             */\n\n            if (type == LogEvent.FORMAT_DESCRIPTION_EVENT) {\n                int commonHeaderLen = buffer.getUint8(FormatDescriptionLogEvent.LOG_EVENT_MINIMAL_HEADER_LEN\n                                                      + FormatDescriptionLogEvent.ST_COMMON_HEADER_LEN_OFFSET);\n                buffer.position(commonHeaderLen + FormatDescriptionLogEvent.ST_SERVER_VER_OFFSET);\n                String serverVersion = buffer.getFixString(FormatDescriptionLogEvent.ST_SERVER_VER_LEN); // ST_SERVER_VER_OFFSET\n                int versionSplit[] = new int[] { 0, 0, 0 };\n                FormatDescriptionLogEvent.doServerVersionSplit(serverVersion, versionSplit);\n                checksumAlg = LogEvent.BINLOG_CHECKSUM_ALG_UNDEF;\n                if (FormatDescriptionLogEvent.versionProduct(versionSplit) >= FormatDescriptionLogEvent.checksumVersionProduct) {\n                    buffer.position(eventLen - LogEvent.BINLOG_CHECKSUM_LEN - LogEvent.BINLOG_CHECKSUM_ALG_DESC_LEN);\n                    checksumAlg = buffer.getUint8();\n                }\n\n                processCheckSum(buffer);\n            }\n            return;\n        }\n\n        /*\n         * CRC verification by SQL and Show-Binlog-Events master side. The\n         * caller has to provide @description_event->checksum_alg to be the last\n         * seen FD's (A) descriptor. If event is FD the descriptor is in it.\n         * Notice, FD of the binlog can be only in one instance and therefore\n         * Show-Binlog-Events executing master side thread needs just to know\n         * the only FD's (A) value - whereas RL can contain more. In the RL\n         * case, the alg is kept in FD_e (@description_event) which is reset to\n         * the newer read-out event after its execution with possibly new alg\n         * descriptor. Therefore in a typical sequence of RL: {FD_s^0, FD_m,\n         * E_m^1} E_m^1 will be verified with (A) of FD_m. See legends\n         * definition on MYSQL_BIN_LOG::relay_log_checksum_alg docs lines\n         * (log.h). Notice, a pre-checksum FD version forces alg :=\n         * BINLOG_CHECKSUM_ALG_UNDEF.\n         */\n        checksumAlg = descriptionEvent.getHeader().checksumAlg; // fetch\n                                                                // checksum alg\n        processCheckSum(buffer);\n        /* otherwise, go on with reading the header from buf (nothing now) */\n    }\n\n    /**\n     * The different types of log events.\n     */\n    public final int getType() {\n        return type;\n    }\n\n    /**\n     * The position of the next event in the master binary log, in bytes from\n     * the beginning of the file. In a binlog that is not a relay log, this is\n     * just the position of the next event, in bytes from the beginning of the\n     * file. In a relay log, this is the position of the next event in the\n     * master's binlog.\n     */\n    public final long getLogPos() {\n        return logPos;\n    }\n\n    /**\n     * The total size of this event, in bytes. In other words, this is the sum\n     * of the sizes of Common-Header, Post-Header, and Body.\n     */\n    public final int getEventLen() {\n        return eventLen;\n    }\n\n    /**\n     * The time when the query started, in seconds since 1970.\n     */\n    public final long getWhen() {\n        return when;\n    }\n\n    /**\n     * Server ID of the server that created the event.\n     */\n    public final long getServerId() {\n        return serverId;\n    }\n\n    /**\n     * Some 16 flags. See the definitions above for LOG_EVENT_TIME_F,\n     * LOG_EVENT_FORCED_ROTATE_F, LOG_EVENT_THREAD_SPECIFIC_F, and\n     * LOG_EVENT_SUPPRESS_USE_F for notes.\n     */\n    public final int getFlags() {\n        return flags;\n    }\n\n    public long getCrc() {\n        return crc;\n    }\n\n    public int getChecksumAlg() {\n        return checksumAlg;\n    }\n\n    public String getLogFileName() {\n        return logFileName;\n    }\n\n    public void setLogFileName(String logFileName) {\n        this.logFileName = logFileName;\n    }\n    public void setLogPos(long logPos) {\n        this.logPos = logPos;\n    }\n    public void setEventLen(int eventLen) {\n        this.eventLen = eventLen;\n    }\n\n    private void processCheckSum(LogBuffer buffer) {\n        if (checksumAlg != LogEvent.BINLOG_CHECKSUM_ALG_OFF && checksumAlg != LogEvent.BINLOG_CHECKSUM_ALG_UNDEF) {\n            crc = buffer.getUint32(eventLen - LogEvent.BINLOG_CHECKSUM_LEN);\n        }\n    }\n\n    public String getGtidSetStr() {\n        return gtidMap.get(GTID_SET_STRING);\n    }\n\n    public String getCurrentGtid() {\n        return gtidMap.get(CURRENT_GTID_STRING);\n    }\n\n    public String getCurrentGtidSn() {\n        return gtidMap.get(CURRENT_GTID_SN);\n    }\n\n    public String getCurrentGtidLastCommit() {\n        return gtidMap.get(CURRENT_GTID_LAST_COMMIT);\n    }\n\n    public void putGtid(GTIDSet gtidSet, LogEvent gtidEvent) {\n        if (gtidSet != null) {\n            gtidMap.put(GTID_SET_STRING, gtidSet.toString());\n            if (gtidEvent != null && gtidEvent instanceof GtidLogEvent) {\n                GtidLogEvent event = (GtidLogEvent) gtidEvent;\n                gtidMap.put(CURRENT_GTID_STRING, event.getGtidStr());\n                gtidMap.put(CURRENT_GTID_SN, String.valueOf(event.getSequenceNumber()));\n                gtidMap.put(CURRENT_GTID_LAST_COMMIT, String.valueOf(event.getLastCommitted()));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/PreviousGtidsLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\n\n/**\n * @author jianghang 2013-4-8 上午12:36:29\n * @version 1.0.3\n * @since mysql 5.6\n */\npublic class PreviousGtidsLogEvent extends LogEvent {\n\n    public PreviousGtidsLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\n        super(header);\n        // do nothing , just for mysql gtid search function\n    }\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/QueryLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport java.io.IOException;\nimport java.math.BigInteger;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\n\nimport com.taobao.tddl.dbsync.binlog.CharsetConversion;\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\n\n/**\n * A Query_log_event is created for each query that modifies the database,\n * unless the query is logged row-based. The Post-Header has five components:\n * <table>\n * <caption>Post-Header for Query_log_event</caption>\n * <tr>\n * <th>Name</th>\n * <th>Format</th>\n * <th>Description</th>\n * </tr>\n * <tr>\n * <td>slave_proxy_id</td>\n * <td>4 byte unsigned integer</td>\n * <td>An integer identifying the client thread that issued the query. The id is\n * unique per server. (Note, however, that two threads on different servers may\n * have the same slave_proxy_id.) This is used when a client thread creates a\n * temporary table local to the client. The slave_proxy_id is used to\n * distinguish temporary tables that belong to different clients.</td>\n * </tr>\n * <tr>\n * <td>exec_time</td>\n * <td>4 byte unsigned integer</td>\n * <td>The time from when the query started to when it was logged in the binlog,\n * in seconds.</td>\n * </tr>\n * <tr>\n * <td>db_len</td>\n * <td>1 byte integer</td>\n * <td>The length of the name of the currently selected database.</td>\n * </tr>\n * <tr>\n * <td>error_code</td>\n * <td>2 byte unsigned integer</td>\n * <td>Error code generated by the master. If the master fails, the slave will\n * fail with the same error code, except for the error codes ER_DB_CREATE_EXISTS\n * == 1007 and ER_DB_DROP_EXISTS == 1008.</td>\n * </tr>\n * <tr>\n * <td>status_vars_len</td>\n * <td>2 byte unsigned integer</td>\n * <td>The length of the status_vars block of the Body, in bytes. See\n * query_log_event_status_vars \"below\".</td>\n * </tr>\n * </table>\n * The Body has the following components:\n * <table>\n * <caption>Body for Query_log_event</caption>\n * <tr>\n * <th>Name</th>\n * <th>Format</th>\n * <th>Description</th>\n * </tr>\n * <tr>\n * <td>query_log_event_status_vars status_vars</td>\n * <td>status_vars_len bytes</td>\n * <td>Zero or more status variables. Each status variable consists of one byte\n * identifying the variable stored, followed by the value of the variable. The\n * possible variables are listed separately in the table\n * Table_query_log_event_status_vars \"below\". MySQL always writes events in the\n * order defined below; however, it is capable of reading them in any order.</td>\n * </tr>\n * <tr>\n * <td>db</td>\n * <td>db_len+1</td>\n * <td>The currently selected database, as a null-terminated string. (The\n * trailing zero is redundant since the length is already known; it is db_len\n * from Post-Header.)</td>\n * </tr>\n * <tr>\n * <td>query</td>\n * <td>variable length string without trailing zero, extending to the end of the\n * event (determined by the length field of the Common-Header)</td>\n * <td>The SQL query.</td>\n * </tr>\n * </table>\n * The following table lists the status variables that may appear in the\n * status_vars field. Table_query_log_event_status_vars\n * <table>\n * <caption>Status variables for Query_log_event</caption>\n * <tr>\n * <th>Status variable</th>\n * <th>1 byte identifier</th>\n * <th>Format</th>\n * <th>Description</th>\n * </tr>\n * <tr>\n * <td>flags2</td>\n * <td>Q_FLAGS2_CODE == 0</td>\n * <td>4 byte bitfield</td>\n * <td>The flags in thd->options, binary AND-ed with OPTIONS_WRITTEN_TO_BIN_LOG.\n * The thd->options bitfield contains options for \"SELECT\". OPTIONS_WRITTEN\n * identifies those options that need to be written to the binlog (not all do).\n * Specifically, OPTIONS_WRITTEN_TO_BIN_LOG equals (OPTION_AUTO_IS_NULL |\n * OPTION_NO_FOREIGN_KEY_CHECKS | OPTION_RELAXED_UNIQUE_CHECKS |\n * OPTION_NOT_AUTOCOMMIT), or 0x0c084000 in hex. These flags correspond to the\n * SQL variables SQL_AUTO_IS_NULL, FOREIGN_KEY_CHECKS, UNIQUE_CHECKS, and\n * AUTOCOMMIT, documented in the \"SET Syntax\" section of the MySQL Manual. This\n * field is always written to the binlog in version >= 5.0, and never written in\n * version < 5.0.</td>\n * </tr>\n * <tr>\n * <td>sql_mode</td>\n * <td>Q_SQL_MODE_CODE == 1</td>\n * <td>8 byte bitfield</td>\n * <td>The sql_mode variable. See the section \"SQL Modes\" in the MySQL manual,\n * and see mysql_priv.h for a list of the possible flags. Currently\n * (2007-10-04), the following flags are available:\n * \n * <pre>\n *     MODE_REAL_AS_FLOAT==0x1\n *     MODE_PIPES_AS_CONCAT==0x2\n *     MODE_ANSI_QUOTES==0x4\n *     MODE_IGNORE_SPACE==0x8\n *     MODE_NOT_USED==0x10\n *     MODE_ONLY_FULL_GROUP_BY==0x20\n *     MODE_NO_UNSIGNED_SUBTRACTION==0x40\n *     MODE_NO_DIR_IN_CREATE==0x80\n *     MODE_POSTGRESQL==0x100\n *     MODE_ORACLE==0x200\n *     MODE_MSSQL==0x400\n *     MODE_DB2==0x800\n *     MODE_MAXDB==0x1000\n *     MODE_NO_KEY_OPTIONS==0x2000\n *     MODE_NO_TABLE_OPTIONS==0x4000\n *     MODE_NO_FIELD_OPTIONS==0x8000\n *     MODE_MYSQL323==0x10000\n *     MODE_MYSQL323==0x20000\n *     MODE_MYSQL40==0x40000\n *     MODE_ANSI==0x80000\n *     MODE_NO_AUTO_VALUE_ON_ZERO==0x100000\n *     MODE_NO_BACKSLASH_ESCAPES==0x200000\n *     MODE_STRICT_TRANS_TABLES==0x400000\n *     MODE_STRICT_ALL_TABLES==0x800000\n *     MODE_NO_ZERO_IN_DATE==0x1000000\n *     MODE_NO_ZERO_DATE==0x2000000\n *     MODE_INVALID_DATES==0x4000000\n *     MODE_ERROR_FOR_DIVISION_BY_ZERO==0x8000000\n *     MODE_TRADITIONAL==0x10000000\n *     MODE_NO_AUTO_CREATE_USER==0x20000000\n *     MODE_HIGH_NOT_PRECEDENCE==0x40000000\n *     MODE_PAD_CHAR_TO_FULL_LENGTH==0x80000000\n * </pre>\n * \n * All these flags are replicated from the server. However, all flags except\n * MODE_NO_DIR_IN_CREATE are honored by the slave; the slave always preserves\n * its old value of MODE_NO_DIR_IN_CREATE. For a rationale, see comment in\n * Query_log_event::do_apply_event in log_event.cc. This field is always written\n * to the binlog.</td>\n * </tr>\n * <tr>\n * <td>catalog</td>\n * <td>Q_CATALOG_NZ_CODE == 6</td>\n * <td>Variable-length string: the length in bytes (1 byte) followed by the\n * characters (at most 255 bytes)</td>\n * <td>Stores the client's current catalog. Every database belongs to a catalog,\n * the same way that every table belongs to a database. Currently, there is only\n * one catalog, \"std\". This field is written if the length of the catalog is >\n * 0; otherwise it is not written.</td>\n * </tr>\n * <tr>\n * <td>auto_increment</td>\n * <td>Q_AUTO_INCREMENT == 3</td>\n * <td>two 2 byte unsigned integers, totally 2+2=4 bytes</td>\n * <td>The two variables auto_increment_increment and auto_increment_offset, in\n * that order. For more information, see \"System variables\" in the MySQL manual.\n * This field is written if auto_increment > 1. Otherwise, it is not written.</td>\n * </tr>\n * <tr>\n * <td>charset</td>\n * <td>Q_CHARSET_CODE == 4</td>\n * <td>three 2 byte unsigned integers, totally 2+2+2=6 bytes</td>\n * <td>The three variables character_set_client, collation_connection, and\n * collation_server, in that order. character_set_client is a code identifying\n * the character set and collation used by the client to encode the query.\n * collation_connection identifies the character set and collation that the\n * master converts the query to when it receives it; this is useful when\n * comparing literal strings. collation_server is the default character set and\n * collation used when a new database is created. See also\n * \"Connection Character Sets and Collations\" in the MySQL 5.1 manual. All three\n * variables are codes identifying a (character set, collation) pair. To see\n * which codes map to which pairs, run the query \"SELECT id, character_set_name,\n * collation_name FROM COLLATIONS\". Cf. Q_CHARSET_DATABASE_CODE below. This\n * field is always written.</td>\n * </tr>\n * <tr>\n * <td>time_zone</td>\n * <td>Q_TIME_ZONE_CODE == 5</td>\n * <td>Variable-length string: the length in bytes (1 byte) followed by the\n * characters (at most 255 bytes).\n * <td>The time_zone of the master. See also \"System Variables\" and\n * \"MySQL Server Time Zone Support\" in the MySQL manual. This field is written\n * if the length of the time zone string is > 0; otherwise, it is not written.</td>\n * </tr>\n * <tr>\n * <td>lc_time_names_number</td>\n * <td>Q_LC_TIME_NAMES_CODE == 7</td>\n * <td>2 byte integer</td>\n * <td>A code identifying a table of month and day names. The mapping from codes\n * to languages is defined in sql_locale.cc. This field is written if it is not\n * 0, i.e., if the locale is not en_US.</td>\n * </tr>\n * <tr>\n * <td>charset_database_number</td>\n * <td>Q_CHARSET_DATABASE_CODE == 8</td>\n * <td>2 byte integer</td>\n * <td>The value of the collation_database system variable (in the source code\n * stored in thd->variables.collation_database), which holds the code for a\n * (character set, collation) pair as described above (see Q_CHARSET_CODE).\n * collation_database was used in old versions (???WHEN). Its value was loaded\n * when issuing a \"use db\" query and could be changed by issuing a\n * \"SET collation_database=xxx\" query. It used to affect the \"LOAD DATA INFILE\"\n * and \"CREATE TABLE\" commands. In newer versions, \"CREATE TABLE\" has been\n * changed to take the character set from the database of the created table,\n * rather than the character set of the current database. This makes a\n * difference when creating a table in another database than the current one.\n * \"LOAD DATA INFILE\" has not yet changed to do this, but there are plans to\n * eventually do it, and to make collation_database read-only. This field is\n * written if it is not 0.</td>\n * </tr>\n * <tr>\n * <td>table_map_for_update</td>\n * <td>Q_TABLE_MAP_FOR_UPDATE_CODE == 9</td>\n * <td>8 byte integer</td>\n * <td>The value of the table map that is to be updated by the multi-table\n * update query statement. Every bit of this variable represents a table, and is\n * set to 1 if the corresponding table is to be updated by this statement. The\n * value of this variable is set when executing a multi-table update statement\n * and used by slave to apply filter rules without opening all the tables on\n * slave. This is required because some tables may not exist on slave because of\n * the filter rules.</td>\n * </tr>\n * </table>\n * Query_log_event_notes_on_previous_versions Notes on Previous Versions Status\n * vars were introduced in version 5.0. To read earlier versions correctly,\n * check the length of the Post-Header. The status variable Q_CATALOG_CODE == 2\n * existed in MySQL 5.0.x, where 0<=x<=3. It was identical to Q_CATALOG_CODE,\n * except that the string had a trailing '\\0'. The '\\0' was removed in 5.0.4\n * since it was redundant (the string length is stored before the string). The\n * Q_CATALOG_CODE will never be written by a new master, but can still be\n * understood by a new slave. See Q_CHARSET_DATABASE_CODE in the table above.\n * When adding new status vars, please don't forget to update the\n * MAX_SIZE_LOG_EVENT_STATUS, and update function code_name\n * \n * @see mysql-5.1.6/sql/logevent.cc - Query_log_event\n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\n * @version 1.0\n */\npublic class QueryLogEvent extends LogEvent {\n\n    /**\n     * The maximum number of updated databases that a status of Query-log-event\n     * can carry. It can redefined within a range [1..\n     * OVER_MAX_DBS_IN_EVENT_MTS].\n     */\n    public static final int MAX_DBS_IN_EVENT_MTS      = 16;\n\n    /**\n     * When the actual number of databases exceeds MAX_DBS_IN_EVENT_MTS the\n     * value of OVER_MAX_DBS_IN_EVENT_MTS is is put into the mts_accessed_dbs\n     * status.\n     */\n    public static final int OVER_MAX_DBS_IN_EVENT_MTS = 254;\n\n    public static final int SYSTEM_CHARSET_MBMAXLEN   = 3;\n    public static final int NAME_CHAR_LEN             = 64;\n    /* Field/table name length */\n    public static final int NAME_LEN                  = (NAME_CHAR_LEN * SYSTEM_CHARSET_MBMAXLEN);\n\n    /**\n     * Max number of possible extra bytes in a replication event compared to a\n     * packet (i.e. a query) sent from client to master; First, an auxiliary\n     * log_event status vars estimation:\n     */\n    public static final int MAX_SIZE_LOG_EVENT_STATUS = (1 + 4 /* type, flags2 */ + 1 + 8 /* type,sql_mode */ + 1 + 1 + 255 /* type,length, catalog */\n                                                         + 1 + 4 /* type,auto_increment */\n                                                         + 1 + 6 /* type, charset */\n                                                         + 1 + 1 + 255 /* type, length, time_zone */\n                                                         + 1 + 2 /* type, lc_time_names_number */\n                                                         + 1 + 2 /* type, charset_database_number */\n                                                         + 1 + 8 /* type, table_map_for_update */\n                                                         + 1 + 4 /* type,master_data_written */\n                                                         + 1 + 1 + 32 * 3 /* type, user_len, user */\n                                                         + 1 + 255 /* host_len, host */\n                                                         + 1 + 1 + (MAX_DBS_IN_EVENT_MTS * (1 + NAME_LEN)) /* type, db_1, db_2, ... */\n                                                         + 1 + 3 /* type, microseconds */\n                                                         + 1 + 1 /* type, explicit_def..ts*/\n                                                         + 1 + 8 /* type, xid of DDL */\n                                                         + 1 + 2 /* type, default_collation_for_utf8mb4_number */\n                                                         + 1 + 1 /* sql_require_primary_key */\n                                                         + 1 + 1 /* type, default_table_encryption */\n                                                         + 1 + 1 /* opt_flashback_area */\n                                                         + 1 + 1 /* type, opt_index_format_gpp_enabled */\n                                                         + 1 + 1 /* type, opt_index_format_panda_enabled */\n                                                         + 1 + 1 + NAME_LEN /* type, length, recycle_bin_table_name */);\n\n    /**\n     * Fixed data part:\n     * <ul>\n     * <li>4 bytes. The ID of the thread that issued this statement. Needed for\n     * temporary tables. This is also useful for a DBA for knowing who did what\n     * on the master.</li>\n     * <li>4 bytes. The time in seconds that the statement took to execute. Only\n     * useful for inspection by the DBA.</li>\n     * <li>1 byte. The length of the name of the database which was the default\n     * database when the statement was executed. This name appears later, in the\n     * variable data part. It is necessary for statements such as INSERT INTO t\n     * VALUES(1) that don't specify the database and rely on the default\n     * database previously selected by USE.</li>\n     * <li>2 bytes. The error code resulting from execution of the statement on\n     * the master. Error codes are defined in include/mysqld_error.h. 0 means no\n     * error. How come statements with a non-zero error code can exist in the\n     * binary log? This is mainly due to the use of non-transactional tables\n     * within transactions. For example, if an INSERT ... SELECT fails after\n     * inserting 1000 rows into a MyISAM table (for example, with a\n     * duplicate-key violation), we have to write this statement to the binary\n     * log, because it truly modified the MyISAM table. For transactional\n     * tables, there should be no event with a non-zero error code (though it\n     * can happen, for example if the connection was interrupted (Control-C)).\n     * The slave checks the error code: After executing the statement itself, it\n     * compares the error code it got with the error code in the event, and if\n     * they are different it stops replicating (unless --slave-skip-errors was\n     * used to ignore the error).</li>\n     * <li>2 bytes (not present in v1, v3). The length of the status variable\n     * block.</li>\n     * </ul>\n     * Variable part:\n     * <ul>\n     * <li>Zero or more status variables (not present in v1, v3). Each status\n     * variable consists of one byte code identifying the variable stored,\n     * followed by the value of the variable. The format of the value is\n     * variable-specific, as described later.</li>\n     * <li>The default database name (null-terminated).</li>\n     * <li>The SQL statement. The slave knows the size of the other fields in\n     * the variable part (the sizes are given in the fixed data part), so by\n     * subtraction it can know the size of the statement.</li>\n     * </ul>\n     * Source : http://forge.mysql.com/wiki/MySQL_Internals_Binary_Log\n     */\n    private String          user;\n    private String          host;\n\n    /* using byte for query string */\n    protected String        query;\n    protected String        catalog;\n    protected final String  dbname;\n\n    /** The number of seconds the query took to run on the master. */\n    // The time in seconds that the statement took to execute. Only useful for\n    // inspection by the DBA\n    private final long      execTime;\n    private final int       errorCode;\n    private final long      sessionId;                                                                                     /* thread_id */\n\n    /**\n     * 'flags2' is a second set of flags (on top of those in Log_event), for\n     * session variables. These are thd->options which is & against a mask\n     * (OPTIONS_WRITTEN_TO_BIN_LOG).\n     */\n    private long            flags2;\n\n    /** In connections sql_mode is 32 bits now but will be 64 bits soon */\n    private long            sql_mode;\n\n    private long            autoIncrementIncrement    = -1;\n    private long            autoIncrementOffset       = -1;\n\n    private int             clientCharset             = -1;\n    private int             clientCollation           = -1;\n    private int             serverCollation           = -1;\n    private int             tvSec                     = -1;\n    private BigInteger      ddlXid                    = BigInteger.valueOf(-1L);\n    private Charset         charset;\n    private String          timezone;\n    private boolean         compatiablePercona        = false;\n\n    public QueryLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent)\n                                                                                                         throws IOException{\n        this(header, buffer, descriptionEvent, false);\n    }\n\n    public QueryLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent,\n                         boolean compatiablePercona) throws IOException{\n        this(header, buffer, descriptionEvent, compatiablePercona, false);\n    }\n\n    public QueryLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent,\n                         boolean compatiablePercona,\n                         boolean compress) throws IOException{\n        super(header);\n        this.compatiablePercona = compatiablePercona;\n        final int commonHeaderLen = descriptionEvent.commonHeaderLen;\n        final int postHeaderLen = descriptionEvent.postHeaderLen[header.type - 1];\n        /*\n         * We test if the event's length is sensible, and if so we compute\n         * data_len. We cannot rely on QUERY_HEADER_LEN here as it would not be\n         * format-tolerant. We use QUERY_HEADER_MINIMAL_LEN which is the same\n         * for 3.23, 4.0 & 5.0.\n         */\n        if (buffer.limit() < (commonHeaderLen + postHeaderLen)) {\n            throw new IOException(\"Query event length is too short.\");\n        }\n        int dataLen = buffer.limit() - (commonHeaderLen + postHeaderLen);\n        buffer.position(commonHeaderLen + Q_THREAD_ID_OFFSET);\n\n        sessionId = buffer.getUint32(); // Q_THREAD_ID_OFFSET\n        execTime = buffer.getUint32(); // Q_EXEC_TIME_OFFSET\n\n        // TODO: add a check of all *_len vars\n        final int dbLen = buffer.getUint8(); // Q_DB_LEN_OFFSET\n        errorCode = buffer.getUint16(); // Q_ERR_CODE_OFFSET\n\n        /*\n         * 5.0 format starts here. Depending on the format, we may or not have\n         * affected/warnings etc The remaining post-header to be parsed has\n         * length:\n         */\n        int statusVarsLen = 0;\n        if (postHeaderLen > QUERY_HEADER_MINIMAL_LEN) {\n            statusVarsLen = buffer.getUint16(); // Q_STATUS_VARS_LEN_OFFSET\n            /*\n             * Check if status variable length is corrupt and will lead to very\n             * wrong data. We could be even more strict and require data_len to\n             * be even bigger, but this will suffice to catch most corruption\n             * errors that can lead to a crash.\n             */\n            if (statusVarsLen > Math.min(dataLen, MAX_SIZE_LOG_EVENT_STATUS)) {\n                throw new IOException(\"status_vars_len (\" + statusVarsLen + \") > data_len (\" + dataLen + \")\");\n            }\n            dataLen -= statusVarsLen;\n        }\n        /*\n         * We have parsed everything we know in the post header for QUERY_EVENT,\n         * the rest of post header is either comes from older version MySQL or\n         * dedicated to derived events (e.g. Execute_load_query...)\n         */\n\n        /* variable-part: the status vars; only in MySQL 5.0 */\n        final int start = commonHeaderLen + postHeaderLen;\n        final int limit = buffer.limit(); /* for restore */\n        final int end = start + statusVarsLen;\n        buffer.position(start).limit(end);\n        unpackVariables(buffer, end);\n        buffer.position(end);\n        buffer.limit(limit);\n        /* A 2nd variable part; this is common to all versions */\n        dbname = buffer.getFixName(dbLen + 1);\n        int queryLen = dataLen - dbLen - 1;\n        if (compress) {\n            // mariadb compress log event\n            // see https://github.com/alibaba/canal/issues/4388\n            buffer = buffer.uncompressBuf();\n            queryLen = buffer.limit();\n        }\n        if (clientCharset >= 0) {\n            charset = CharsetConversion.getNioCharset(clientCharset);\n\n            if (charset != null) {\n                query = buffer.getFixString(queryLen, charset);\n            } else {\n                logger.warn(\"unsupported character set in query log: \" + \"\\n    ID = \" + clientCharset + \", Charset = \"\n                            + CharsetConversion.getCharset(clientCharset) + \", Collation = \"\n                            + CharsetConversion.getCollation(clientCharset));\n\n                query = buffer.getFixString(queryLen);\n            }\n        } else {\n            query = buffer.getFixString(queryLen);\n        }\n    }\n\n    /* query event post-header */\n    public static final int Q_THREAD_ID_OFFSET                = 0;\n    public static final int Q_EXEC_TIME_OFFSET                = 4;\n    public static final int Q_DB_LEN_OFFSET                   = 8;\n    public static final int Q_ERR_CODE_OFFSET                 = 9;\n    public static final int Q_STATUS_VARS_LEN_OFFSET          = 11;\n    public static final int Q_DATA_OFFSET                     = QUERY_HEADER_LEN;\n\n    /* these are codes, not offsets; not more than 256 values (1 byte). */\n    public static final int Q_FLAGS2_CODE                     = 0;\n    public static final int Q_SQL_MODE_CODE                   = 1;\n\n    /**\n     * Q_CATALOG_CODE is catalog with end zero stored; it is used only by MySQL\n     * 5.0.x where 0<=x<=3. We have to keep it to be able to replicate these old\n     * masters.\n     */\n    public static final int Q_CATALOG_CODE                    = 2;\n    public static final int Q_AUTO_INCREMENT                  = 3;\n    public static final int Q_CHARSET_CODE                    = 4;\n    public static final int Q_TIME_ZONE_CODE                  = 5;\n\n    /**\n     * Q_CATALOG_NZ_CODE is catalog withOUT end zero stored; it is used by MySQL\n     * 5.0.x where x>=4. Saves one byte in every Query_log_event in binlog,\n     * compared to Q_CATALOG_CODE. The reason we didn't simply re-use\n     * Q_CATALOG_CODE is that then a 5.0.3 slave of this 5.0.x (x>=4) master\n     * would crash (segfault etc) because it would expect a 0 when there is\n     * none.\n     */\n    public static final int Q_CATALOG_NZ_CODE                 = 6;\n\n    public static final int Q_LC_TIME_NAMES_CODE              = 7;\n\n    public static final int Q_CHARSET_DATABASE_CODE           = 8;\n\n    public static final int Q_TABLE_MAP_FOR_UPDATE_CODE       = 9;\n\n    public static final int Q_MASTER_DATA_WRITTEN_CODE        = 10;\n\n    public static final int Q_INVOKER                         = 11;\n\n    /**\n     * Q_UPDATED_DB_NAMES status variable collects of the updated databases\n     * total number and their names to be propagated to the slave in order to\n     * facilitate the parallel applying of the Query events.\n     */\n    public static final int Q_UPDATED_DB_NAMES                = 12;\n\n    public static final int Q_MICROSECONDS                    = 13;\n    /**\n     * A old (unused now) code for Query_log_event status similar to\n     * G_COMMIT_TS.\n     */\n    public static final int Q_COMMIT_TS                       = 14;\n    /**\n     * A code for Query_log_event status, similar to G_COMMIT_TS2.\n     */\n    public static final int Q_COMMIT_TS2                      = 15;\n    /**\n     * The master connection @@session.explicit_defaults_for_timestamp which is\n     * recorded for queries, CREATE and ALTER table that is defined with a\n     * TIMESTAMP column, that are dependent on that feature. For pre-WL6292\n     * master's the associated with this code value is zero.\n     */\n    public static final int Q_EXPLICIT_DEFAULTS_FOR_TIMESTAMP = 16;\n\n    /**\n     * The variable carries xid info of 2pc-aware (recoverable) DDL queries.\n     */\n    public static final int Q_DDL_LOGGED_WITH_XID             = 17;\n    /**\n     * This variable stores the default collation for the utf8mb4 character set.\n     * Used to support cross-version replication.\n     */\n    public static final int Q_DEFAULT_COLLATION_FOR_UTF8MB4   = 18;\n\n    /**\n     * Replicate sql_require_primary_key.\n     */\n    public static final int Q_SQL_REQUIRE_PRIMARY_KEY         = 19;\n\n    /**\n     * Replicate default_table_encryption.\n     */\n    public static final int Q_DEFAULT_TABLE_ENCRYPTION        = 20;\n\n    /**\n     * Replicate PolarDB-X\n     * \n     * @since PolarDB-X 8.0.32\n     */\n    public static final int Q_OPT_FLASHBACK_AREA              = 21;\n\n    /**\n     * Replicate PolarDB-X\n     * \n     * @since PolarDB-X 8.0.32\n     */\n    public static final int Q_OPT_INDEX_FORMAT_GPP_ENABLED    = 22;\n\n    /**\n     * Replicate ddl_skip_rewrite.\n     *\n     * @since percona 8.0.31\n     */\n    public static final int Q_DDL_SKIP_REWRITE                = 21;\n\n    /**\n     * Replicate Q_WSREP_SKIP_READONLY_CHECKS.\n     *\n     * @since percona 8.0.31\n     */\n    public static final int Q_WSREP_SKIP_READONLY_CHECKS      = 128;\n\n    /**\n     * FROM MariaDB 5.5.34\n     */\n    public static final int Q_HRNOW                           = 128;\n\n    /**\n     * Support MariaDB 10.10.1\n     */\n    public static final int Q_XID                             = 129;\n\n    public static final int Q_GTID_FLAGS3                     = 130;\n\n    public static final int Q_CHARACTER_SET_COLLATIONS        = 131;\n\n    /**\n     * support PolarDB-X used for storing snapshot tso or commit tso snapshot tso is\n     * stored in XA End Event with Query_log commit tso is stored in XA Commit Event\n     * with Query_log\n     */\n    public static final int Q_LIZARD_COMMIT_GCN               = 200;\n\n    public static final int Q_LIZARD_PREPARE_GCN              = 201;\n\n    /**\n     * Replicate recycle_bin_table_name.\n     */\n    public static final int Q_OPT_RECYCLE_BIN_TABLE_NAME      = 254;\n\n    public static final int Q_OPT_INDEX_FORMAT_PANDA_ENABLED  = 255;\n\n    private static final String findCodeName(final int code) {\n        switch (code) {\n            case Q_FLAGS2_CODE:\n                return \"Q_FLAGS2_CODE\";\n            case Q_SQL_MODE_CODE:\n                return \"Q_SQL_MODE_CODE\";\n            case Q_CATALOG_CODE:\n                return \"Q_CATALOG_CODE\";\n            case Q_AUTO_INCREMENT:\n                return \"Q_AUTO_INCREMENT\";\n            case Q_CHARSET_CODE:\n                return \"Q_CHARSET_CODE\";\n            case Q_TIME_ZONE_CODE:\n                return \"Q_TIME_ZONE_CODE\";\n            case Q_CATALOG_NZ_CODE:\n                return \"Q_CATALOG_NZ_CODE\";\n            case Q_LC_TIME_NAMES_CODE:\n                return \"Q_LC_TIME_NAMES_CODE\";\n            case Q_CHARSET_DATABASE_CODE:\n                return \"Q_CHARSET_DATABASE_CODE\";\n            case Q_TABLE_MAP_FOR_UPDATE_CODE:\n                return \"Q_TABLE_MAP_FOR_UPDATE_CODE\";\n            case Q_MASTER_DATA_WRITTEN_CODE:\n                return \"Q_MASTER_DATA_WRITTEN_CODE\";\n            case Q_INVOKER:\n                return \"Q_INVOKER\";\n            case Q_MICROSECONDS:\n                return \"Q_MICROSECONDS\";\n            case Q_UPDATED_DB_NAMES:\n                return \"Q_UPDATED_DB_NAMES\";\n            case Q_EXPLICIT_DEFAULTS_FOR_TIMESTAMP:\n                return \"Q_EXPLICIT_DEFAULTS_FOR_TIMESTAMP\";\n            case Q_DDL_LOGGED_WITH_XID:\n                return \"Q_DDL_LOGGED_WITH_XID\";\n            case Q_DEFAULT_COLLATION_FOR_UTF8MB4:\n                return \"Q_DEFAULT_COLLATION_FOR_UTF8MB4\";\n            case Q_SQL_REQUIRE_PRIMARY_KEY:\n                return \"Q_SQL_REQUIRE_PRIMARY_KEY\";\n            case Q_DEFAULT_TABLE_ENCRYPTION:\n                return \"Q_DEFAULT_TABLE_ENCRYPTION\";\n            case Q_OPT_FLASHBACK_AREA:\n                // or Q_DDL_SKIP_REWRITE\n                return \"Q_OPT_FLASHBACK_AREA\";\n            case Q_OPT_INDEX_FORMAT_GPP_ENABLED:\n                return \"Q_OPT_INDEX_FORMAT_GPP_ENABLED\";\n            case Q_OPT_RECYCLE_BIN_TABLE_NAME:\n                return \"Q_OPT_RECYCLE_BIN_TABLE_NAME\";\n            case Q_OPT_INDEX_FORMAT_PANDA_ENABLED:\n                return \"Q_OPT_INDEX_FORMAT_PANDA_ENABLED\";\n            case Q_HRNOW:\n                // or Q_WSREP_SKIP_READONLY_CHECKS\n                return \"Q_HRNOW\";\n            case Q_XID:\n                return \"Q_XID\";\n            case Q_GTID_FLAGS3:\n                return \"Q_GTID_FLAGS3\";\n            case Q_CHARACTER_SET_COLLATIONS :\n                return \"Q_CHARACTER_SET_COLLATIONS\";\n        }\n        return \"CODE#\" + code;\n    }\n\n    private final void unpackVariables(LogBuffer buffer, final int end) throws IOException {\n        int code = -1;\n        try {\n            while (buffer.position() < end) {\n                switch (code = buffer.getUint8()) {\n                    case Q_FLAGS2_CODE:\n                        flags2 = buffer.getUint32();\n                        break;\n                    case Q_SQL_MODE_CODE:\n                        sql_mode = buffer.getLong64(); // QQ: Fix when sql_mode\n                        // is ulonglong\n                        break;\n                    case Q_CATALOG_NZ_CODE:\n                        catalog = buffer.getName();\n                        break;\n                    case Q_AUTO_INCREMENT:\n                        autoIncrementIncrement = buffer.getUint16();\n                        autoIncrementOffset = buffer.getUint16();\n                        break;\n                    case Q_CHARSET_CODE:\n                        // Charset: 6 byte character set flag.\n                        // 1-2 = character set client\n                        // 3-4 = collation client\n                        // 5-6 = collation server\n                        clientCharset = buffer.getUint16();\n                        clientCollation = buffer.getUint16();\n                        serverCollation = buffer.getUint16();\n                        break;\n                    case Q_TIME_ZONE_CODE:\n                        timezone = buffer.getName();\n                        break;\n                    case Q_CATALOG_CODE: /* for 5.0.x where 0<=x<=3 masters */\n                        final int len = buffer.getUint8();\n                        catalog = buffer.getFixString(len + 1);\n                        break;\n                    case Q_LC_TIME_NAMES_CODE:\n                        // lc_time_names_number = buffer.getUint16();\n                        buffer.forward(2);\n                        break;\n                    case Q_CHARSET_DATABASE_CODE:\n                        // charset_database_number = buffer.getUint16();\n                        buffer.forward(2);\n                        break;\n                    case Q_TABLE_MAP_FOR_UPDATE_CODE:\n                        // table_map_for_update = buffer.getUlong64();\n                        buffer.forward(8);\n                        break;\n                    case Q_MASTER_DATA_WRITTEN_CODE:\n                        // data_written = master_data_written =\n                        // buffer.getUint32();\n                        buffer.forward(4);\n                        break;\n                    case Q_INVOKER:\n                        user = buffer.getName();\n                        host = buffer.getName();\n                        break;\n                    case Q_MICROSECONDS:\n                        // when.tv_usec= uint3korr(pos);\n                        tvSec = buffer.getInt24();\n                        break;\n                    case Q_UPDATED_DB_NAMES:\n                        int mtsAccessedDbs = buffer.getUint8();\n                        /**\n                         * Notice, the following check is positive also in case\n                         * of the master's MAX_DBS_IN_EVENT_MTS > the slave's\n                         * one and the event contains e.g the master's\n                         * MAX_DBS_IN_EVENT_MTS db:s.\n                         */\n                        if (mtsAccessedDbs > MAX_DBS_IN_EVENT_MTS) {\n                            mtsAccessedDbs = OVER_MAX_DBS_IN_EVENT_MTS;\n                            break;\n                        }\n                        String mtsAccessedDbNames[] = new String[mtsAccessedDbs];\n                        for (int i = 0; i < mtsAccessedDbs && buffer.position() < end; i++) {\n                            int length = end - buffer.position();\n                            mtsAccessedDbNames[i] = buffer.getFixName(length < NAME_LEN ? length : NAME_LEN);\n                        }\n                        break;\n                    case Q_EXPLICIT_DEFAULTS_FOR_TIMESTAMP:\n                        // thd->variables.explicit_defaults_for_timestamp\n                        buffer.forward(1);\n                        break;\n                    case Q_DDL_LOGGED_WITH_XID:\n                        ddlXid = buffer.getUlong64();\n                        break;\n                    case Q_DEFAULT_COLLATION_FOR_UTF8MB4:\n                        // int2store(start,\n                        // default_collation_for_utf8mb4_number);\n                        buffer.forward(2);\n                        break;\n                    case Q_SQL_REQUIRE_PRIMARY_KEY:\n                        // *start++ = thd->variables.sql_require_primary_key;\n                        buffer.forward(1);\n                        break;\n                    case Q_DEFAULT_TABLE_ENCRYPTION:\n                        // *start++ = thd->variables.default_table_encryption;\n                        buffer.forward(1);\n                        break;\n                    case Q_OPT_FLASHBACK_AREA:\n                        if (compatiablePercona) {\n                            // percona\n                            // *start++ = thd->variables.binlog_ddl_skip_rewrite;\n                            buffer.forward(1);\n                        } else {\n                            // PolarDB-X\n                            // *start++ = thd->variables.opt_flashback_area;\n                            buffer.forward(1);\n                        }\n                        break;\n                    case Q_OPT_INDEX_FORMAT_GPP_ENABLED :\n                        // *start++ = thd->variables.opt_index_format_gpp_enabled;\n                        buffer.forward(1);\n                        break;\n                    case Q_HRNOW:\n                        // https://github.com/alibaba/canal/issues/4940\n                        // percona 和 mariadb各自扩展mysql binlog的格式后有冲突\n                        // 需要精确识别一下数据库类型做兼容处理\n                        if (compatiablePercona) {\n                            // percona 8.0.31\n                            // Q_WSREP_SKIP_READONLY_CHECKS *start++ = 1;\n                            buffer.forward(1);\n                        } else {\n                            // int when_sec_part = buffer.getUint24();\n                            buffer.forward(3);\n                        }\n                        break;\n                    case Q_XID:\n                        // xid= uint8korr(pos);\n                        buffer.forward(8);\n                        break;\n                    case Q_GTID_FLAGS3:\n                        // gtid_flags_extra= *pos++;\n                        // if (gtid_flags_extra & (Gtid_log_event::FL_COMMIT_ALTER_E1 |\n                        // Gtid_log_event::FL_ROLLBACK_ALTER_E1)) {\n                        // sa_seq_no = uint8korr(pos);\n                        // pos+= 8;\n                        // }\n                        int gtid_flags_extra = buffer.getUint8();\n                        final int FL_COMMIT_ALTER_E1= 4;\n                        final int FL_ROLLBACK_ALTER_E1= 8;\n                        if ((gtid_flags_extra & (FL_COMMIT_ALTER_E1 | FL_ROLLBACK_ALTER_E1))> 0) {\n                            buffer.forward(8);\n                        }\n                        break;\n                    case Q_CHARACTER_SET_COLLATIONS :\n                        // mariadb\n                        int count = buffer.getUint8();\n                        // character_set_collations= Lex_cstring((const char *) pos0 , (const char *) pos);\n                        buffer.forward(count * 4);\n                        break;\n                    case Q_LIZARD_COMMIT_GCN:\n                        // commitGCN = buffer.getLong64();\n                        buffer.forward(8);\n                        break;\n                    case Q_LIZARD_PREPARE_GCN:\n                        // prepareGCN = buffer.getLong64();\n                        buffer.forward(8);\n                        break;\n                    case Q_OPT_RECYCLE_BIN_TABLE_NAME:\n                        int recycle_bin_table_name_len = buffer.getUint8();\n                        String recycle_bin_table_name = null;\n                        if (recycle_bin_table_name_len > 0) {\n                            if (charset != null) {\n                                recycle_bin_table_name = buffer.getFixLengthString(recycle_bin_table_name_len, charset);\n                            } else {\n                                recycle_bin_table_name = buffer.getFixLengthString(recycle_bin_table_name_len,\n                                    StandardCharsets.ISO_8859_1);\n                            }\n                        }\n                        break;\n                    case Q_OPT_INDEX_FORMAT_PANDA_ENABLED:\n                        // *start++ = thd->variables.opt_index_format_panda_enabled;\n                        buffer.forward(1);\n                        break;\n                    default:\n                        /*\n                         * That's why you must write status vars in growing\n                         * order of code\n                         */\n                        logger.error(\"Query_log_event has unknown status vars (first has code: \" + code\n                                     + \"), skipping the rest of them\");\n                        return; // Break loop\n                }\n            }\n        } catch (RuntimeException e) {\n            throw new IOException(\"Read \" + findCodeName(code) + \" error: \" + e.getMessage(), e);\n        }\n    }\n\n    public final String getUser() {\n        return user;\n    }\n\n    public final String getHost() {\n        return host;\n    }\n\n    public final String getQuery() {\n        return query;\n    }\n\n    public final String getCatalog() {\n        return catalog;\n    }\n\n    public final String getDbName() {\n        return dbname;\n    }\n\n    /**\n     * The number of seconds the query took to run on the master.\n     */\n    public final long getExecTime() {\n        return execTime;\n    }\n\n    public final int getErrorCode() {\n        return errorCode;\n    }\n\n    public final long getSessionId() {\n        return sessionId;\n    }\n\n    public final long getAutoIncrementIncrement() {\n        return autoIncrementIncrement;\n    }\n\n    public final long getAutoIncrementOffset() {\n        return autoIncrementOffset;\n    }\n\n    public final Charset getCharset() {\n        return charset;\n    }\n\n    public final String getTimezone() {\n        return timezone;\n    }\n\n    /**\n     * Returns the charsetID value.\n     * \n     * @return Returns the charsetID.\n     */\n    public final int getClientCharset() {\n        return clientCharset;\n    }\n\n    /**\n     * Returns the clientCollationId value.\n     * \n     * @return Returns the clientCollationId.\n     */\n    public final int getClientCollation() {\n        return clientCollation;\n    }\n\n    /**\n     * Returns the serverCollationId value.\n     * \n     * @return Returns the serverCollationId.\n     */\n    public final int getServerCollation() {\n        return serverCollation;\n    }\n\n    public int getTvSec() {\n        return tvSec;\n    }\n\n    public BigInteger getDdlXid() {\n        return ddlXid;\n    }\n\n    /**\n     * Returns the sql_mode value.\n     * <p>\n     * The sql_mode variable. See the section \"SQL Modes\" in the MySQL manual,\n     * and see mysql_priv.h for a list of the possible flags. Currently\n     * (2007-10-04), the following flags are available:\n     * <ul>\n     * <li>MODE_REAL_AS_FLOAT==0x1</li>\n     * <li>MODE_PIPES_AS_CONCAT==0x2</li>\n     * <li>MODE_ANSI_QUOTES==0x4</li>\n     * <li>MODE_IGNORE_SPACE==0x8</li>\n     * <li>MODE_NOT_USED==0x10</li>\n     * <li>MODE_ONLY_FULL_GROUP_BY==0x20</li>\n     * <li>MODE_NO_UNSIGNED_SUBTRACTION==0x40</li>\n     * <li>MODE_NO_DIR_IN_CREATE==0x80</li>\n     * <li>MODE_POSTGRESQL==0x100</li>\n     * <li>MODE_ORACLE==0x200</li>\n     * <li>MODE_MSSQL==0x400</li>\n     * <li>MODE_DB2==0x800</li>\n     * <li>MODE_MAXDB==0x1000</li>\n     * <li>MODE_NO_KEY_OPTIONS==0x2000</li>\n     * <li>MODE_NO_TABLE_OPTIONS==0x4000</li>\n     * <li>MODE_NO_FIELD_OPTIONS==0x8000</li>\n     * <li>MODE_MYSQL323==0x10000</li>\n     * <li>MODE_MYSQL40==0x20000</li>\n     * <li>MODE_ANSI==0x40000</li>\n     * <li>MODE_NO_AUTO_VALUE_ON_ZERO==0x80000</li>\n     * <li>MODE_NO_BACKSLASH_ESCAPES==0x100000</li>\n     * <li>MODE_STRICT_TRANS_TABLES==0x200000</li>\n     * <li>MODE_STRICT_ALL_TABLES==0x400000</li>\n     * <li>MODE_NO_ZERO_IN_DATE==0x800000</li>\n     * <li>MODE_NO_ZERO_DATE==0x1000000</li>\n     * <li>MODE_INVALID_DATES==0x2000000</li>\n     * <li>MODE_ERROR_FOR_DIVISION_BY_ZERO==0x4000000</li>\n     * <li>MODE_TRADITIONAL==0x8000000</li>\n     * <li>MODE_NO_AUTO_CREATE_USER==0x10000000</li>\n     * <li>MODE_HIGH_NOT_PRECEDENCE==0x20000000</li>\n     * <li>MODE_NO_ENGINE_SUBSTITUTION=0x40000000</li>\n     * <li>MODE_PAD_CHAR_TO_FULL_LENGTH==0x80000000</li>\n     * </ul>\n     * All these flags are replicated from the server. However, all flags except\n     * MODE_NO_DIR_IN_CREATE are honored by the slave; the slave always\n     * preserves its old value of MODE_NO_DIR_IN_CREATE. This field is always\n     * written to the binlog.\n     */\n    public final long getSqlMode() {\n        return sql_mode;\n    }\n\n    /* FLAGS2 values that can be represented inside the binlog */\n    public static final int OPTION_AUTO_IS_NULL          = 1 << 14;\n    public static final int OPTION_NOT_AUTOCOMMIT        = 1 << 19;\n    public static final int OPTION_NO_FOREIGN_KEY_CHECKS = 1 << 26;\n    public static final int OPTION_RELAXED_UNIQUE_CHECKS = 1 << 27;\n\n    /**\n     * The flags in thd->options, binary AND-ed with OPTIONS_WRITTEN_TO_BIN_LOG.\n     * The thd->options bitfield contains options for \"SELECT\". OPTIONS_WRITTEN\n     * identifies those options that need to be written to the binlog (not all\n     * do). Specifically, OPTIONS_WRITTEN_TO_BIN_LOG equals (OPTION_AUTO_IS_NULL\n     * | OPTION_NO_FOREIGN_KEY_CHECKS | OPTION_RELAXED_UNIQUE_CHECKS |\n     * OPTION_NOT_AUTOCOMMIT), or 0x0c084000 in hex. These flags correspond to\n     * the SQL variables SQL_AUTO_IS_NULL, FOREIGN_KEY_CHECKS, UNIQUE_CHECKS,\n     * and AUTOCOMMIT, documented in the \"SET Syntax\" section of the MySQL\n     * Manual. This field is always written to the binlog in version >= 5.0, and\n     * never written in version < 5.0.\n     */\n    public final long getFlags2() {\n        return flags2;\n    }\n\n    /**\n     * Returns the OPTION_AUTO_IS_NULL flag.\n     */\n    public final boolean isAutoIsNull() {\n        return ((flags2 & OPTION_AUTO_IS_NULL) == OPTION_AUTO_IS_NULL);\n    }\n\n    /**\n     * Returns the OPTION_NO_FOREIGN_KEY_CHECKS flag.\n     */\n    public final boolean isForeignKeyChecks() {\n        return ((flags2 & OPTION_NO_FOREIGN_KEY_CHECKS) != OPTION_NO_FOREIGN_KEY_CHECKS);\n    }\n\n    /**\n     * Returns the OPTION_NOT_AUTOCOMMIT flag.\n     */\n    public final boolean isAutocommit() {\n        return ((flags2 & OPTION_NOT_AUTOCOMMIT) != OPTION_NOT_AUTOCOMMIT);\n    }\n\n    /**\n     * Returns the OPTION_NO_FOREIGN_KEY_CHECKS flag.\n     */\n    public final boolean isUniqueChecks() {\n        return ((flags2 & OPTION_RELAXED_UNIQUE_CHECKS) != OPTION_RELAXED_UNIQUE_CHECKS);\n    }\n\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/RandLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\n\n/**\n * Logs random seed used by the next RAND(), and by PASSWORD() in 4.1.0. 4.1.1\n * does not need it (it's repeatable again) so this event needn't be written in\n * 4.1.1 for PASSWORD() (but the fact that it is written is just a waste, it\n * does not cause bugs). The state of the random number generation consists of\n * 128 bits, which are stored internally as two 64-bit numbers. Binary Format\n * The Post-Header for this event type is empty. The Body has two components:\n * <table>\n * <caption>Body for Rand_log_event</caption>\n * <tr>\n * <th>Name</th>\n * <th>Format</th>\n * <th>Description</th>\n * </tr>\n * <tr>\n * <td>seed1</td>\n * <td>8 byte unsigned integer</td>\n * <td>64 bit random seed1.</td>\n * </tr>\n * <tr>\n * <td>seed2</td>\n * <td>8 byte unsigned integer</td>\n * <td>64 bit random seed2.</td>\n * </tr>\n * </table>\n * \n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\n * @version 1.0\n */\npublic final class RandLogEvent extends LogEvent {\n\n    /**\n     * Fixed data part: Empty\n     * <p>\n     * Variable data part:\n     * <ul>\n     * <li>8 bytes. The value for the first seed.</li>\n     * <li>8 bytes. The value for the second seed.</li>\n     * </ul>\n     * Source : http://forge.mysql.com/wiki/MySQL_Internals_Binary_Log\n     */\n    private final long      seed1;\n    private final long      seed2;\n\n    /* Rand event data */\n    public static final int RAND_SEED1_OFFSET = 0;\n    public static final int RAND_SEED2_OFFSET = 8;\n\n    public RandLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\n        super(header);\n\n        /* The Post-Header is empty. The Variable Data part begins immediately. */\n        buffer.position(descriptionEvent.commonHeaderLen + descriptionEvent.postHeaderLen[RAND_EVENT - 1]\n                        + RAND_SEED1_OFFSET);\n        seed1 = buffer.getLong64(); // !uint8korr(buf+RAND_SEED1_OFFSET);\n        seed2 = buffer.getLong64(); // !uint8korr(buf+RAND_SEED2_OFFSET);\n    }\n\n    public final String getQuery() {\n        return \"SET SESSION rand_seed1 = \" + seed1 + \" , rand_seed2 = \" + seed2;\n    }\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/RotateLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\n\n/**\n * This will be deprecated when we move to using sequence ids. Binary Format The\n * Post-Header has one component:\n * <table>\n * <caption>Post-Header for Rotate_log_event</caption>\n * <tr>\n * <th>Name</th>\n * <th>Format</th>\n * <th>Description</th>\n * </tr>\n * <tr>\n * <td>position</td>\n * <td>8 byte integer</td>\n * <td>The position within the binlog to rotate to.</td>\n * </tr>\n * </table>\n * The Body has one component:\n * <table>\n * <caption>Body for Rotate_log_event</caption>\n * <tr>\n * <th>Name</th>\n * <th>Format</th>\n * <th>Description</th>\n * </tr>\n * <tr>\n * <td>new_log</td>\n * <td>variable length string without trailing zero, extending to the end of the\n * event (determined by the length field of the Common-Header)</td>\n * <td>Name of the binlog to rotate to.</td>\n * </tr>\n * </table>\n * \n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\n * @version 1.0\n */\npublic final class RotateLogEvent extends LogEvent {\n\n    /**\n     * Fixed data part:\n     * <ul>\n     * <li>8 bytes. The position of the first event in the next log file. Always\n     * contains the number 4 (meaning the next event starts at position 4 in the\n     * next binary log). This field is not present in v1; presumably the value\n     * is assumed to be 4.</li>\n     * </ul>\n     * <p>\n     * Variable data part:\n     * <ul>\n     * <li>The name of the next binary log. The filename is not null-terminated.\n     * Its length is the event size minus the size of the fixed parts.</li>\n     * </ul>\n     * Source : http://forge.mysql.com/wiki/MySQL_Internals_Binary_Log\n     */\n    private final String          filename;\n    private final long            position;\n\n    /* Rotate event post-header */\n    public static final int       R_POS_OFFSET   = 0;\n    public static final int       R_IDENT_OFFSET = 8;\n\n    /* Max length of full path-name */\n    public static final int       FN_REFLEN      = 512;\n\n    // Rotate header with all empty fields.\n    public static final LogHeader ROTATE_HEADER  = new LogHeader(ROTATE_EVENT);\n\n    /**\n     * Creates a new <code>Rotate_log_event</code> object read normally from\n     * log.\n     * \n     * @throws MySQLExtractException\n     */\n    public RotateLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\n        super(header);\n\n        final int headerSize = descriptionEvent.commonHeaderLen;\n        final int postHeaderLen = descriptionEvent.postHeaderLen[ROTATE_EVENT - 1];\n\n        buffer.position(headerSize + R_POS_OFFSET);\n        position = (postHeaderLen != 0) ? buffer.getLong64() : 4; // !uint8korr(buf\n                                                                  // +\n                                                                  // R_POS_OFFSET)\n\n        final int filenameOffset = headerSize + postHeaderLen;\n        int filenameLen = buffer.limit() - filenameOffset;\n        if (filenameLen > FN_REFLEN - 1) {\n            filenameLen = FN_REFLEN - 1;\n        }\n        buffer.position(filenameOffset);\n        filename = buffer.getFixString(filenameLen);\n    }\n\n    /**\n     * Creates a new <code>Rotate_log_event</code> without log information. This\n     * is used to generate missing log rotation events.\n     */\n    public RotateLogEvent(String filename){\n        super(ROTATE_HEADER);\n\n        this.filename = filename;\n        this.position = 4;\n    }\n\n    /**\n     * Creates a new <code>Rotate_log_event</code> without log information.\n     */\n    public RotateLogEvent(String filename, final long position){\n        super(ROTATE_HEADER);\n\n        this.filename = filename;\n        this.position = position;\n    }\n\n    public final String getFilename() {\n        return filename;\n    }\n\n    public final long getPosition() {\n        return position;\n    }\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/RowsLogBuffer.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\r\n\r\nimport java.io.Serializable;\r\nimport java.nio.charset.Charset;\r\nimport java.sql.Timestamp;\r\nimport java.sql.Types;\r\nimport java.util.BitSet;\r\n\r\nimport org.apache.commons.logging.Log;\r\nimport org.apache.commons.logging.LogFactory;\r\n\r\nimport com.taobao.tddl.dbsync.binlog.JsonConversion;\r\nimport com.taobao.tddl.dbsync.binlog.JsonConversion.Json_Value;\r\nimport com.taobao.tddl.dbsync.binlog.JsonDiffConversion;\r\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\r\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\r\n\r\n/**\r\n * Extracting JDBC type & value information from packed rows-buffer.\r\n *\r\n * @see mysql-5.1.60/sql/log_event.cc - Rows_log_event::print_verbose_one_row\r\n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\r\n * @version 1.0\r\n */\r\npublic final class RowsLogBuffer {\r\n\r\n    protected static final Log    logger            = LogFactory.getLog(RowsLogBuffer.class);\r\n    public static final Long[]    longCache         = new Long[1024 * 128];\r\n    public static final int       longCacheLimit    = longCache.length + 127;\r\n    public static final Integer[] integerCache      = new Integer[1024 * 128];\r\n    public static final int       integerCacheLimit = longCache.length + 127;\r\n\r\n    public static final long      DATETIMEF_INT_OFS = 0x8000000000L;\r\n    public static final long      TIMEF_INT_OFS     = 0x800000L;\r\n    public static final long      TIMEF_OFS         = 0x800000000000L;\r\n    private static char[]         digits            = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };\r\n\r\n    private final LogBuffer       buffer;\r\n    private final int             columnLen;\r\n    private final int             jsonColumnCount;\r\n    private final Charset         charset;\r\n\r\n    private final BitSet          nullBits;\r\n    private int                   nullBitIndex;\r\n\r\n    // Read value_options if this is AI for PARTIAL_UPDATE_ROWS_EVENT\r\n    private final boolean         partial;\r\n    private final BitSet          partialBits;\r\n\r\n    private boolean               fNull;\r\n    private int                   javaType;\r\n    private int                   length;\r\n    private Serializable          value;\r\n\r\n    public RowsLogBuffer(LogBuffer buffer, final int columnLen, Charset charset, int jsonColumnCount, boolean partial){\r\n        this.buffer = buffer;\r\n        this.columnLen = columnLen;\r\n        this.charset = charset;\r\n        this.partial = partial;\r\n        this.jsonColumnCount = jsonColumnCount;\r\n        this.nullBits = new BitSet(columnLen);\r\n        this.partialBits = new BitSet(1);\r\n    }\r\n\r\n    public final boolean nextOneRow(BitSet columns) {\r\n        return nextOneRow(columns, false);\r\n    }\r\n\r\n    /**\r\n     * Extracting next row from packed buffer.\r\n     *\r\n     * @see mysql-5.1.60/sql/log_event.cc - Rows_log_event::print_verbose_one_row\r\n     */\r\n    public final boolean nextOneRow(BitSet columns, boolean after) {\r\n        final boolean hasOneRow = buffer.hasRemaining();\r\n\r\n        if (hasOneRow) {\r\n            int column = 0;\r\n\r\n            for (int i = 0; i < columnLen; i++)\r\n                if (columns.get(i)) {\r\n                    column++;\r\n                }\r\n\r\n            if (after && partial) {\r\n                partialBits.clear();\r\n                long valueOptions = buffer.getPackedLong();\r\n                int PARTIAL_JSON_UPDATES = 1;\r\n                if ((valueOptions & PARTIAL_JSON_UPDATES) != 0) {\r\n                    partialBits.set(1);\r\n                    buffer.forward((jsonColumnCount + 7) / 8);\r\n                }\r\n            }\r\n            nullBitIndex = 0;\r\n            nullBits.clear();\r\n            buffer.fillBitmap(nullBits, column);\r\n\r\n        }\r\n        return hasOneRow;\r\n    }\r\n\r\n    /**\r\n     * Extracting next field value from packed buffer.\r\n     *\r\n     * @see mysql-5.1.60/sql/log_event.cc - Rows_log_event::print_verbose_one_row\r\n     */\r\n    public final Serializable nextValue(final String columName, final int columnIndex, final int type, final int meta) {\r\n        return nextValue(columName, columnIndex, type, meta, false);\r\n    }\r\n\r\n    /**\r\n     * Extracting next field value from packed buffer.\r\n     *\r\n     * @see mysql-5.1.60/sql/log_event.cc - Rows_log_event::print_verbose_one_row\r\n     */\r\n    public final Serializable nextValue(final String columName, final int columnIndex, final int type, final int meta,\r\n                                        boolean isBinary) {\r\n        fNull = nullBits.get(nullBitIndex++);\r\n\r\n        if (fNull) {\r\n            value = null;\r\n            javaType = mysqlToJavaType(type, meta, isBinary);\r\n            length = 0;\r\n            return null;\r\n        } else {\r\n            // Extracting field value from packed buffer.\r\n            return fetchValue(columName, columnIndex, type, meta, isBinary);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Maps the given MySQL type to the correct JDBC type.\r\n     */\r\n    static int mysqlToJavaType(int type, final int meta, boolean isBinary) {\r\n        int javaType;\r\n\r\n        if (type == LogEvent.MYSQL_TYPE_STRING) {\r\n            if (meta >= 256) {\r\n                int byte0 = meta >> 8;\r\n                if ((byte0 & 0x30) != 0x30) {\r\n                    /* a long CHAR() field: see #37426 */\r\n                    type = byte0 | 0x30;\r\n                } else {\r\n                    switch (byte0) {\r\n                        case LogEvent.MYSQL_TYPE_SET:\r\n                        case LogEvent.MYSQL_TYPE_ENUM:\r\n                        case LogEvent.MYSQL_TYPE_STRING:\r\n                            type = byte0;\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        switch (type) {\r\n            case LogEvent.MYSQL_TYPE_LONG:\r\n                javaType = Types.INTEGER;\r\n                break;\r\n\r\n            case LogEvent.MYSQL_TYPE_TINY:\r\n                javaType = Types.TINYINT;\r\n                break;\r\n\r\n            case LogEvent.MYSQL_TYPE_SHORT:\r\n                javaType = Types.SMALLINT;\r\n                break;\r\n\r\n            case LogEvent.MYSQL_TYPE_INT24:\r\n                javaType = Types.INTEGER;\r\n                break;\r\n\r\n            case LogEvent.MYSQL_TYPE_LONGLONG:\r\n                javaType = Types.BIGINT;\r\n                break;\r\n\r\n            case LogEvent.MYSQL_TYPE_DECIMAL:\r\n                javaType = Types.DECIMAL;\r\n                break;\r\n\r\n            case LogEvent.MYSQL_TYPE_NEWDECIMAL:\r\n                javaType = Types.DECIMAL;\r\n                break;\r\n\r\n            case LogEvent.MYSQL_TYPE_FLOAT:\r\n                javaType = Types.REAL; // Types.FLOAT;\r\n                break;\r\n\r\n            case LogEvent.MYSQL_TYPE_DOUBLE:\r\n                javaType = Types.DOUBLE;\r\n                break;\r\n\r\n            case LogEvent.MYSQL_TYPE_BIT:\r\n                javaType = Types.BIT;\r\n                break;\r\n\r\n            case LogEvent.MYSQL_TYPE_TIMESTAMP:\r\n            case LogEvent.MYSQL_TYPE_DATETIME:\r\n            case LogEvent.MYSQL_TYPE_TIMESTAMP2:\r\n            case LogEvent.MYSQL_TYPE_DATETIME2:\r\n                javaType = Types.TIMESTAMP;\r\n                break;\r\n\r\n            case LogEvent.MYSQL_TYPE_TIME:\r\n            case LogEvent.MYSQL_TYPE_TIME2:\r\n                javaType = Types.TIME;\r\n                break;\r\n\r\n            case LogEvent.MYSQL_TYPE_NEWDATE:\r\n            case LogEvent.MYSQL_TYPE_DATE:\r\n                javaType = Types.DATE;\r\n                break;\r\n\r\n            case LogEvent.MYSQL_TYPE_YEAR:\r\n                javaType = Types.VARCHAR;\r\n                break;\r\n\r\n            case LogEvent.MYSQL_TYPE_ENUM:\r\n                javaType = Types.INTEGER;\r\n                break;\r\n\r\n            case LogEvent.MYSQL_TYPE_SET:\r\n                javaType = Types.BINARY;\r\n                break;\r\n\r\n            case LogEvent.MYSQL_TYPE_TINY_BLOB:\r\n            case LogEvent.MYSQL_TYPE_MEDIUM_BLOB:\r\n            case LogEvent.MYSQL_TYPE_LONG_BLOB:\r\n            case LogEvent.MYSQL_TYPE_BLOB:\r\n                if (meta == 1) {\r\n                    javaType = Types.VARBINARY;\r\n                } else {\r\n                    javaType = Types.LONGVARBINARY;\r\n                }\r\n                break;\r\n\r\n            case LogEvent.MYSQL_TYPE_VARCHAR:\r\n            case LogEvent.MYSQL_TYPE_VAR_STRING:\r\n                if (isBinary) {\r\n                    // varbinary在binlog中为var_string类型\r\n                    javaType = Types.VARBINARY;\r\n                } else {\r\n                    javaType = Types.VARCHAR;\r\n                }\r\n                break;\r\n\r\n            case LogEvent.MYSQL_TYPE_STRING:\r\n                if (isBinary) {\r\n                    // binary在binlog中为string类型\r\n                    javaType = Types.BINARY;\r\n                } else {\r\n                    javaType = Types.CHAR;\r\n                }\r\n                break;\r\n\r\n            case LogEvent.MYSQL_TYPE_GEOMETRY:\r\n                javaType = Types.BINARY;\r\n                break;\r\n\r\n            // case LogEvent.MYSQL_TYPE_BINARY:\r\n            // javaType = Types.BINARY;\r\n            // break;\r\n            //\r\n            // case LogEvent.MYSQL_TYPE_VARBINARY:\r\n            // javaType = Types.VARBINARY;\r\n            // break;\r\n\r\n            default:\r\n                javaType = Types.OTHER;\r\n        }\r\n\r\n        return javaType;\r\n    }\r\n\r\n    /**\r\n     * Extracting next field value from packed buffer.\r\n     *\r\n     * @see mysql-5.1.60/sql/log_event.cc - log_event_print_value\r\n     */\r\n    final Serializable fetchValue(String columnName, int columnIndex, int type, final int meta, boolean isBinary) {\r\n        int len = 0;\r\n\r\n        if (type == LogEvent.MYSQL_TYPE_STRING) {\r\n            if (meta >= 256) {\r\n                int byte0 = meta >> 8;\r\n                int byte1 = meta & 0xff;\r\n                if ((byte0 & 0x30) != 0x30) {\r\n                    /* a long CHAR() field: see #37426 */\r\n                    len = byte1 | (((byte0 & 0x30) ^ 0x30) << 4);\r\n                    type = byte0 | 0x30;\r\n                } else {\r\n                    switch (byte0) {\r\n                        case LogEvent.MYSQL_TYPE_SET:\r\n                        case LogEvent.MYSQL_TYPE_ENUM:\r\n                        case LogEvent.MYSQL_TYPE_STRING:\r\n                            type = byte0;\r\n                            len = byte1;\r\n                            break;\r\n                        default:\r\n                            throw new IllegalArgumentException(String\r\n                                .format(\"!! Don't know how to handle column type=%d meta=%d (%04X)\", type, meta, meta));\r\n                    }\r\n                }\r\n            } else {\r\n                len = meta;\r\n            }\r\n        }\r\n\r\n        switch (type) {\r\n            case LogEvent.MYSQL_TYPE_LONG: {\r\n                // XXX: How to check signed / unsigned?\r\n                // value = unsigned ? Long.valueOf(buffer.getUint32()) :\r\n                // Integer.valueOf(buffer.getInt32());\r\n                value = valueOf(buffer.getInt32());\r\n                javaType = Types.INTEGER;\r\n                length = 4;\r\n                break;\r\n            }\r\n            case LogEvent.MYSQL_TYPE_TINY: {\r\n                // XXX: How to check signed / unsigned?\r\n                // value = Integer.valueOf(unsigned ? buffer.getUint8() :\r\n                // buffer.getInt8());\r\n                value = valueOf(buffer.getInt8());\r\n                javaType = Types.TINYINT; // java.sql.Types.INTEGER;\r\n                length = 1;\r\n                break;\r\n            }\r\n            case LogEvent.MYSQL_TYPE_SHORT: {\r\n                // XXX: How to check signed / unsigned?\r\n                // value = Integer.valueOf(unsigned ? buffer.getUint16() :\r\n                // buffer.getInt16());\r\n                value = valueOf((short) buffer.getInt16());\r\n                javaType = Types.SMALLINT; // java.sql.Types.INTEGER;\r\n                length = 2;\r\n                break;\r\n            }\r\n            case LogEvent.MYSQL_TYPE_INT24: {\r\n                // XXX: How to check signed / unsigned?\r\n                // value = Integer.valueOf(unsigned ? buffer.getUint24() :\r\n                // buffer.getInt24());\r\n                value = valueOf(buffer.getInt24());\r\n                javaType = Types.INTEGER;\r\n                length = 3;\r\n                break;\r\n            }\r\n            case LogEvent.MYSQL_TYPE_LONGLONG: {\r\n                // XXX: How to check signed / unsigned?\r\n                // value = unsigned ? buffer.getUlong64()) :\r\n                // Long.valueOf(buffer.getLong64());\r\n                value = valueOf(buffer.getLong64());\r\n                javaType = Types.BIGINT; // Types.INTEGER;\r\n                length = 8;\r\n                break;\r\n            }\r\n            case LogEvent.MYSQL_TYPE_DECIMAL: {\r\n                /*\r\n                 * log_event.h : This enumeration value is only used internally and cannot exist\r\n                 * in a binlog.\r\n                 */\r\n                logger.warn(\"MYSQL_TYPE_DECIMAL : This enumeration value is \"\r\n                            + \"only used internally and cannot exist in a binlog!\");\r\n                javaType = Types.DECIMAL;\r\n                value = null; /* unknown format */\r\n                length = 0;\r\n                break;\r\n            }\r\n            case LogEvent.MYSQL_TYPE_NEWDECIMAL: {\r\n                final int precision = meta >> 8;\r\n                final int decimals = meta & 0xff;\r\n                value = buffer.getDecimal(precision, decimals);\r\n                javaType = Types.DECIMAL;\r\n                length = precision;\r\n                break;\r\n            }\r\n            case LogEvent.MYSQL_TYPE_FLOAT: {\r\n                value = Float.valueOf(buffer.getFloat32());\r\n                javaType = Types.REAL; // Types.FLOAT;\r\n                length = 4;\r\n                break;\r\n            }\r\n            case LogEvent.MYSQL_TYPE_DOUBLE: {\r\n                value = Double.valueOf(buffer.getDouble64());\r\n                javaType = Types.DOUBLE;\r\n                length = 8;\r\n                break;\r\n            }\r\n            case LogEvent.MYSQL_TYPE_BIT: {\r\n                /* Meta-data: bit_len, bytes_in_rec, 2 bytes */\r\n                final int nbits = ((meta >> 8) * 8) + (meta & 0xff);\r\n                len = (nbits + 7) / 8;\r\n                if (nbits > 1) {\r\n                    // byte[] bits = new byte[len];\r\n                    // buffer.fillBytes(bits, 0, len);\r\n                    // 转化为unsign long\r\n                    switch (len) {\r\n                        case 1:\r\n                            value = buffer.getUint8();\r\n                            break;\r\n                        case 2:\r\n                            value = buffer.getBeUint16();\r\n                            break;\r\n                        case 3:\r\n                            value = buffer.getBeUint24();\r\n                            break;\r\n                        case 4:\r\n                            value = buffer.getBeUint32();\r\n                            break;\r\n                        case 5:\r\n                            value = buffer.getBeUlong40();\r\n                            break;\r\n                        case 6:\r\n                            value = buffer.getBeUlong48();\r\n                            break;\r\n                        case 7:\r\n                            value = buffer.getBeUlong56();\r\n                            break;\r\n                        case 8:\r\n                            value = buffer.getBeUlong64();\r\n                            break;\r\n                        default:\r\n                            throw new IllegalArgumentException(\"!! Unknown Bit len = \" + len);\r\n                    }\r\n                } else {\r\n                    final int bit = buffer.getInt8();\r\n                    // value = (bit != 0) ? Boolean.TRUE : Boolean.FALSE;\r\n                    value = bit;\r\n                }\r\n                javaType = Types.BIT;\r\n                length = nbits;\r\n                break;\r\n            }\r\n            case LogEvent.MYSQL_TYPE_TIMESTAMP: {\r\n                // MYSQL DataTypes: TIMESTAMP\r\n                // range is '1970-01-01 00:00:01' UTC to '2038-01-19 03:14:07'\r\n                // UTC\r\n                // A TIMESTAMP cannot represent the value '1970-01-01 00:00:00'\r\n                // because that is equivalent to 0 seconds from the epoch and\r\n                // the value 0 is reserved for representing '0000-00-00\r\n                // 00:00:00', the “zero” TIMESTAMP value.\r\n                final long i32 = buffer.getUint32();\r\n                if (i32 == 0) {\r\n                    value = \"0000-00-00 00:00:00\";\r\n                } else {\r\n                    String v = new Timestamp(i32 * 1000).toString();\r\n                    value = v.substring(0, v.length() - 2);\r\n                }\r\n                javaType = Types.TIMESTAMP;\r\n                length = 4;\r\n                break;\r\n            }\r\n            case LogEvent.MYSQL_TYPE_TIMESTAMP2: {\r\n                final long tv_sec = buffer.getBeUint32(); // big-endian\r\n                int tv_usec = 0;\r\n                switch (meta) {\r\n                    case 0:\r\n                        tv_usec = 0;\r\n                        break;\r\n                    case 1:\r\n                    case 2:\r\n                        tv_usec = buffer.getInt8() * 10000;\r\n                        break;\r\n                    case 3:\r\n                    case 4:\r\n                        tv_usec = buffer.getBeInt16() * 100;\r\n                        break;\r\n                    case 5:\r\n                    case 6:\r\n                        tv_usec = buffer.getBeInt24();\r\n                        break;\r\n                    default:\r\n                        tv_usec = 0;\r\n                        break;\r\n                }\r\n\r\n                String second = null;\r\n                if (tv_sec == 0) {\r\n                    second = \"0000-00-00 00:00:00\";\r\n                } else {\r\n                    Timestamp time = new Timestamp(tv_sec * 1000);\r\n                    second = time.toString();\r\n                    second = second.substring(0, second.length() - 2);// 去掉毫秒精度.0\r\n                }\r\n\r\n                if (meta >= 1) {\r\n                    String microSecond = usecondsToStr(tv_usec, meta);\r\n                    microSecond = microSecond.substring(0, meta);\r\n                    value = second + '.' + microSecond;\r\n                } else {\r\n                    value = second;\r\n                }\r\n\r\n                javaType = Types.TIMESTAMP;\r\n                length = 4 + (meta + 1) / 2;\r\n                break;\r\n            }\r\n            case LogEvent.MYSQL_TYPE_DATETIME: {\r\n                // MYSQL DataTypes: DATETIME\r\n                // range is '0000-01-01 00:00:00' to '9999-12-31 23:59:59'\r\n                final long i64 = buffer.getLong64(); /* YYYYMMDDhhmmss */\r\n                if (i64 == 0) {\r\n                    value = \"0000-00-00 00:00:00\";\r\n                } else {\r\n                    final int d = (int) (i64 / 1000000);\r\n                    final int t = (int) (i64 % 1000000);\r\n                    // if (cal == null) cal = Calendar.getInstance();\r\n                    // cal.clear();\r\n                    /* month is 0-based, 0 for january. */\r\n                    // cal.set(d / 10000, (d % 10000) / 100 - 1, d % 100, t /\r\n                    // 10000, (t % 10000) / 100, t % 100);\r\n                    // value = new Timestamp(cal.getTimeInMillis());\r\n                    // value = String.format(\"%04d-%02d-%02d %02d:%02d:%02d\",\r\n                    // d / 10000,\r\n                    // (d % 10000) / 100,\r\n                    // d % 100,\r\n                    // t / 10000,\r\n                    // (t % 10000) / 100,\r\n                    // t % 100);\r\n\r\n                    StringBuilder builder = new StringBuilder();\r\n                    appendNumber4(builder, d / 10000);\r\n                    builder.append('-');\r\n                    appendNumber2(builder, (d % 10000) / 100);\r\n                    builder.append('-');\r\n                    appendNumber2(builder, d % 100);\r\n                    builder.append(' ');\r\n                    appendNumber2(builder, t / 10000);\r\n                    builder.append(':');\r\n                    appendNumber2(builder, (t % 10000) / 100);\r\n                    builder.append(':');\r\n                    appendNumber2(builder, t % 100);\r\n                    value = builder.toString();\r\n                }\r\n                javaType = Types.TIMESTAMP;\r\n                length = 8;\r\n                break;\r\n            }\r\n            case LogEvent.MYSQL_TYPE_DATETIME2: {\r\n                /*\r\n                 * DATETIME and DATE low-level memory and disk representation routines 1 bit\r\n                 * sign (used when on disk) 17 bits year*13+month (year 0-9999, month 0-12) 5\r\n                 * bits day (0-31) 5 bits hour (0-23) 6 bits minute (0-59) 6 bits second (0-59)\r\n                 * 24 bits microseconds (0-999999) Total: 64 bits = 8 bytes SYYYYYYY.YYYYYYYY\r\n                 * .YYdddddh.hhhhmmmm.mmssssss.ffffffff.ffffffff.ffffffff\r\n                 */\r\n                long intpart = buffer.getBeUlong40() - DATETIMEF_INT_OFS; // big-endian\r\n                int frac = 0;\r\n                switch (meta) {\r\n                    case 0:\r\n                        frac = 0;\r\n                        break;\r\n                    case 1:\r\n                    case 2:\r\n                        frac = buffer.getInt8() * 10000;\r\n                        break;\r\n                    case 3:\r\n                    case 4:\r\n                        frac = buffer.getBeInt16() * 100;\r\n                        break;\r\n                    case 5:\r\n                    case 6:\r\n                        frac = buffer.getBeInt24();\r\n                        break;\r\n                    default:\r\n                        frac = 0;\r\n                        break;\r\n                }\r\n\r\n                String second = null;\r\n                if (intpart == 0) {\r\n                    second = \"0000-00-00 00:00:00\";\r\n                } else {\r\n                    // 构造TimeStamp只处理到秒\r\n                    long ymd = intpart >> 17;\r\n                    long ym = ymd >> 5;\r\n                    long hms = intpart % (1 << 17);\r\n\r\n                    // if (cal == null) cal = Calendar.getInstance();\r\n                    // cal.clear();\r\n                    // cal.set((int) (ym / 13), (int) (ym % 13) - 1, (int) (ymd\r\n                    // % (1 << 5)), (int) (hms >> 12),\r\n                    // (int) ((hms >> 6) % (1 << 6)), (int) (hms % (1 << 6)));\r\n                    // value = new Timestamp(cal.getTimeInMillis());\r\n                    // second = String.format(\"%04d-%02d-%02d %02d:%02d:%02d\",\r\n                    // (int) (ym / 13),\r\n                    // (int) (ym % 13),\r\n                    // (int) (ymd % (1 << 5)),\r\n                    // (int) (hms >> 12),\r\n                    // (int) ((hms >> 6) % (1 << 6)),\r\n                    // (int) (hms % (1 << 6)));\r\n\r\n                    StringBuilder builder = new StringBuilder(26);\r\n                    appendNumber4(builder, (int) (ym / 13));\r\n                    builder.append('-');\r\n                    appendNumber2(builder, (int) (ym % 13));\r\n                    builder.append('-');\r\n                    appendNumber2(builder, (int) (ymd % (1 << 5)));\r\n                    builder.append(' ');\r\n                    appendNumber2(builder, (int) (hms >> 12));\r\n                    builder.append(':');\r\n                    appendNumber2(builder, (int) ((hms >> 6) % (1 << 6)));\r\n                    builder.append(':');\r\n                    appendNumber2(builder, (int) (hms % (1 << 6)));\r\n                    second = builder.toString();\r\n                }\r\n\r\n                if (meta >= 1) {\r\n                    String microSecond = usecondsToStr(frac, meta);\r\n                    microSecond = microSecond.substring(0, meta);\r\n                    value = second + '.' + microSecond;\r\n                } else {\r\n                    value = second;\r\n                }\r\n\r\n                javaType = Types.TIMESTAMP;\r\n                length = 5 + (meta + 1) / 2;\r\n                break;\r\n            }\r\n            case LogEvent.MYSQL_TYPE_TIME: {\r\n                // MYSQL DataTypes: TIME\r\n                // The range is '-838:59:59' to '838:59:59'\r\n                // final int i32 = buffer.getUint24();\r\n                final int i32 = buffer.getInt24();\r\n                final int u32 = Math.abs(i32);\r\n                if (i32 == 0) {\r\n                    value = \"00:00:00\";\r\n                } else {\r\n                    // if (cal == null) cal = Calendar.getInstance();\r\n                    // cal.clear();\r\n                    // cal.set(70, 0, 1, i32 / 10000, (i32 % 10000) / 100, i32 %\r\n                    // 100);\r\n                    // value = new Time(cal.getTimeInMillis());\r\n                    // value = String.format(\"%s%02d:%02d:%02d\",\r\n                    // (i32 >= 0) ? \"\" : \"-\",\r\n                    // u32 / 10000,\r\n                    // (u32 % 10000) / 100,\r\n                    // u32 % 100);\r\n\r\n                    StringBuilder builder = new StringBuilder(17);\r\n                    if (i32 < 0) {\r\n                        builder.append('-');\r\n                    }\r\n\r\n                    int d = u32 / 10000;\r\n                    if (d > 100) {\r\n                        builder.append(String.valueOf(d));\r\n                    } else {\r\n                        appendNumber2(builder, d);\r\n                    }\r\n                    builder.append(':');\r\n                    appendNumber2(builder, (u32 % 10000) / 100);\r\n                    builder.append(':');\r\n                    appendNumber2(builder, u32 % 100);\r\n                    value = builder.toString();\r\n                }\r\n                javaType = Types.TIME;\r\n                length = 3;\r\n                break;\r\n            }\r\n            case LogEvent.MYSQL_TYPE_TIME2: {\r\n                /*\r\n                 * TIME low-level memory and disk representation routines In-memory format: 1\r\n                 * bit sign (Used for sign, when on disk) 1 bit unused (Reserved for wider hour\r\n                 * range, e.g. for intervals) 10 bit hour (0-836) 6 bit minute (0-59) 6 bit\r\n                 * second (0-59) 24 bits microseconds (0-999999) Total: 48 bits = 6 bytes\r\n                 * Suhhhhhh.hhhhmmmm.mmssssss.ffffffff.ffffffff.ffffffff\r\n                 */\r\n                long intpart = 0;\r\n                int frac = 0;\r\n                long ltime = 0;\r\n                switch (meta) {\r\n                    case 0:\r\n                        intpart = buffer.getBeUint24() - TIMEF_INT_OFS; // big-endian\r\n                        ltime = intpart << 24;\r\n                        break;\r\n                    case 1:\r\n                    case 2:\r\n                        intpart = buffer.getBeUint24() - TIMEF_INT_OFS;\r\n                        frac = buffer.getUint8();\r\n                        if (intpart < 0 && frac > 0) {\r\n                            /*\r\n                             * Negative values are stored with reverse fractional part order, for binary\r\n                             * sort compatibility. Disk value intpart frac Time value Memory value 800000.00\r\n                             * 0 0 00:00:00.00 0000000000.000000 7FFFFF.FF -1 255 -00:00:00.01\r\n                             * FFFFFFFFFF.FFD8F0 7FFFFF.9D -1 99 -00:00:00.99 FFFFFFFFFF.F0E4D0 7FFFFF.00 -1\r\n                             * 0 -00:00:01.00 FFFFFFFFFF.000000 7FFFFE.FF -1 255 -00:00:01.01\r\n                             * FFFFFFFFFE.FFD8F0 7FFFFE.F6 -2 246 -00:00:01.10 FFFFFFFFFE.FE7960 Formula to\r\n                             * convert fractional part from disk format (now stored in \"frac\" variable) to\r\n                             * absolute value: \"0x100 - frac\". To reconstruct in-memory value, we shift to\r\n                             * the next integer value and then substruct fractional part.\r\n                             */\r\n                            intpart++; /* Shift to the next integer value */\r\n                            frac -= 0x100; /* -(0x100 - frac) */\r\n                            // fraclong = frac * 10000;\r\n                        }\r\n                        frac = frac * 10000;\r\n                        ltime = intpart << 24;\r\n                        break;\r\n                    case 3:\r\n                    case 4:\r\n                        intpart = buffer.getBeUint24() - TIMEF_INT_OFS;\r\n                        frac = buffer.getBeUint16();\r\n                        if (intpart < 0 && frac > 0) {\r\n                            /*\r\n                             * Fix reverse fractional part order: \"0x10000 - frac\". See comments for FSP=1\r\n                             * and FSP=2 above.\r\n                             */\r\n                            intpart++; /* Shift to the next integer value */\r\n                            frac -= 0x10000; /* -(0x10000-frac) */\r\n                            // fraclong = frac * 100;\r\n                        }\r\n                        frac = frac * 100;\r\n                        ltime = intpart << 24;\r\n                        break;\r\n                    case 5:\r\n                    case 6:\r\n                        intpart = buffer.getBeUlong48() - TIMEF_OFS;\r\n                        ltime = intpart;\r\n                        frac = (int) (intpart % (1L << 24));\r\n                        break;\r\n                    default:\r\n                        intpart = buffer.getBeUint24() - TIMEF_INT_OFS;\r\n                        ltime = intpart << 24;\r\n                        break;\r\n                }\r\n\r\n                String second = null;\r\n                if (intpart == 0) {\r\n                    second = frac < 0 ? \"-00:00:00\" : \"00:00:00\";\r\n                } else {\r\n                    // 目前只记录秒，不处理us frac\r\n                    // if (cal == null) cal = Calendar.getInstance();\r\n                    // cal.clear();\r\n                    // cal.set(70, 0, 1, (int) ((intpart >> 12) % (1 << 10)),\r\n                    // (int) ((intpart >> 6) % (1 << 6)),\r\n                    // (int) (intpart % (1 << 6)));\r\n                    // value = new Time(cal.getTimeInMillis());\r\n                    long ultime = Math.abs(ltime);\r\n                    intpart = ultime >> 24;\r\n                    // second = String.format(\"%s%02d:%02d:%02d\",\r\n                    // ltime >= 0 ? \"\" : \"-\",\r\n                    // (int) ((intpart >> 12) % (1 << 10)),\r\n                    // (int) ((intpart >> 6) % (1 << 6)),\r\n                    // (int) (intpart % (1 << 6)));\r\n\r\n                    StringBuilder builder = new StringBuilder(12);\r\n                    if (ltime < 0) {\r\n                        builder.append('-');\r\n                    }\r\n\r\n                    int d = (int) ((intpart >> 12) % (1 << 10));\r\n                    if (d >= 100) {\r\n                        builder.append(String.valueOf(d));\r\n                    } else {\r\n                        appendNumber2(builder, d);\r\n                    }\r\n                    builder.append(':');\r\n                    appendNumber2(builder, (int) ((intpart >> 6) % (1 << 6)));\r\n                    builder.append(':');\r\n                    appendNumber2(builder, (int) (intpart % (1 << 6)));\r\n                    second = builder.toString();\r\n                }\r\n\r\n                if (meta >= 1) {\r\n                    String microSecond = usecondsToStr(Math.abs(frac), meta);\r\n                    microSecond = microSecond.substring(0, meta);\r\n                    value = second + '.' + microSecond;\r\n                } else {\r\n                    value = second;\r\n                }\r\n\r\n                javaType = Types.TIME;\r\n                length = 3 + (meta + 1) / 2;\r\n                break;\r\n            }\r\n            case LogEvent.MYSQL_TYPE_NEWDATE: {\r\n                /*\r\n                 * log_event.h : This enumeration value is only used internally and cannot exist\r\n                 * in a binlog.\r\n                 */\r\n                logger.warn(\"MYSQL_TYPE_NEWDATE : This enumeration value is \"\r\n                            + \"only used internally and cannot exist in a binlog!\");\r\n                javaType = Types.DATE;\r\n                value = null; /* unknown format */\r\n                length = 0;\r\n                break;\r\n            }\r\n            case LogEvent.MYSQL_TYPE_DATE: {\r\n                // MYSQL DataTypes:\r\n                // range: 0000-00-00 ~ 9999-12-31\r\n                final int i32 = buffer.getUint24();\r\n                if (i32 == 0) {\r\n                    value = \"0000-00-00\";\r\n                } else {\r\n                    // if (cal == null) cal = Calendar.getInstance();\r\n                    // cal.clear();\r\n                    /* month is 0-based, 0 for january. */\r\n                    // cal.set((i32 / (16 * 32)), (i32 / 32 % 16) - 1, (i32 %\r\n                    // 32));\r\n                    // value = new java.sql.Date(cal.getTimeInMillis());\r\n                    // value = String.format(\"%04d-%02d-%02d\", i32 / (16 * 32),\r\n                    // i32 / 32 % 16, i32 % 32);\r\n\r\n                    StringBuilder builder = new StringBuilder(12);\r\n                    appendNumber4(builder, i32 / (16 * 32));\r\n                    builder.append('-');\r\n                    appendNumber2(builder, i32 / 32 % 16);\r\n                    builder.append('-');\r\n                    appendNumber2(builder, i32 % 32);\r\n                    value = builder.toString();\r\n                }\r\n                javaType = Types.DATE;\r\n                length = 3;\r\n                break;\r\n            }\r\n            case LogEvent.MYSQL_TYPE_YEAR: {\r\n                // MYSQL DataTypes: YEAR[(2|4)]\r\n                // In four-digit format, values display as 1901 to 2155, and\r\n                // 0000.\r\n                // In two-digit format, values display as 70 to 69, representing\r\n                // years from 1970 to 2069.\r\n\r\n                final int i32 = buffer.getUint8();\r\n                // If connection property 'YearIsDateType' has\r\n                // set, value is java.sql.Date.\r\n                /*\r\n                 * if (cal == null) cal = Calendar.getInstance(); cal.clear();\r\n                 * cal.set(Calendar.YEAR, i32 + 1900); value = new\r\n                 * java.sql.Date(cal.getTimeInMillis());\r\n                 */\r\n                // The else, value is java.lang.Short.\r\n                if (i32 == 0) {\r\n                    value = \"0000\";\r\n                } else {\r\n                    value = String.valueOf((short) (i32 + 1900));\r\n                }\r\n                // It might seem more correct to create a java.sql.Types.DATE\r\n                // value\r\n                // for this date, but it is much simpler to pass the value as an\r\n                // integer. The MySQL JDBC specification states that one can\r\n                // pass a java int between 1901 and 2055. Creating a DATE value\r\n                // causes truncation errors with certain SQL_MODES\r\n                // (e.g.\"STRICT_TRANS_TABLES\").\r\n                javaType = Types.VARCHAR; // Types.INTEGER;\r\n                length = 1;\r\n                break;\r\n            }\r\n            case LogEvent.MYSQL_TYPE_ENUM: {\r\n                final int int32;\r\n                /*\r\n                 * log_event.h : This enumeration value is only used internally and cannot exist\r\n                 * in a binlog.\r\n                 */\r\n                switch (len) {\r\n                    case 1:\r\n                        int32 = buffer.getUint8();\r\n                        break;\r\n                    case 2:\r\n                        int32 = buffer.getUint16();\r\n                        break;\r\n                    default:\r\n                        throw new IllegalArgumentException(\"!! Unknown ENUM packlen = \" + len);\r\n                }\r\n                // logger.warn(\"MYSQL_TYPE_ENUM : This enumeration value is \"\r\n                // + \"only used internally and cannot exist in a binlog!\");\r\n                value = valueOf(int32);\r\n                javaType = Types.INTEGER;\r\n                length = len;\r\n                break;\r\n            }\r\n            case LogEvent.MYSQL_TYPE_SET: {\r\n                final int nbits = (meta & 0xFF) * 8;\r\n                len = (nbits + 7) / 8;\r\n                if (nbits > 1) {\r\n                    // byte[] bits = new byte[len];\r\n                    // buffer.fillBytes(bits, 0, len);\r\n                    // 转化为unsign long\r\n                    switch (len) {\r\n                        case 1:\r\n                            value = buffer.getUint8();\r\n                            break;\r\n                        case 2:\r\n                            value = buffer.getUint16();\r\n                            break;\r\n                        case 3:\r\n                            value = buffer.getUint24();\r\n                            break;\r\n                        case 4:\r\n                            value = buffer.getUint32();\r\n                            break;\r\n                        case 5:\r\n                            value = buffer.getUlong40();\r\n                            break;\r\n                        case 6:\r\n                            value = buffer.getUlong48();\r\n                            break;\r\n                        case 7:\r\n                            value = buffer.getUlong56();\r\n                            break;\r\n                        case 8:\r\n                            value = buffer.getUlong64();\r\n                            break;\r\n                        default:\r\n                            throw new IllegalArgumentException(\"!! Unknown Set len = \" + len);\r\n                    }\r\n                } else {\r\n                    final int bit = buffer.getInt8();\r\n                    // value = (bit != 0) ? Boolean.TRUE : Boolean.FALSE;\r\n                    value = bit;\r\n                }\r\n\r\n                javaType = Types.BIT;\r\n                length = len;\r\n                break;\r\n            }\r\n            case LogEvent.MYSQL_TYPE_TINY_BLOB: {\r\n                /*\r\n                 * log_event.h : This enumeration value is only used internally and cannot exist\r\n                 * in a binlog.\r\n                 */\r\n                logger.warn(\"MYSQL_TYPE_TINY_BLOB : This enumeration value is \"\r\n                            + \"only used internally and cannot exist in a binlog!\");\r\n            }\r\n            case LogEvent.MYSQL_TYPE_MEDIUM_BLOB: {\r\n                /*\r\n                 * log_event.h : This enumeration value is only used internally and cannot exist\r\n                 * in a binlog.\r\n                 */\r\n                logger.warn(\"MYSQL_TYPE_MEDIUM_BLOB : This enumeration value is \"\r\n                            + \"only used internally and cannot exist in a binlog!\");\r\n            }\r\n            case LogEvent.MYSQL_TYPE_LONG_BLOB: {\r\n                /*\r\n                 * log_event.h : This enumeration value is only used internally and cannot exist\r\n                 * in a binlog.\r\n                 */\r\n                logger.warn(\"MYSQL_TYPE_LONG_BLOB : This enumeration value is \"\r\n                            + \"only used internally and cannot exist in a binlog!\");\r\n            }\r\n            case LogEvent.MYSQL_TYPE_BLOB: {\r\n                /*\r\n                 * BLOB or TEXT datatype\r\n                 */\r\n                switch (meta) {\r\n                    case 1: {\r\n                        /* TINYBLOB/TINYTEXT */\r\n                        final int len8 = buffer.getUint8();\r\n                        byte[] binary = new byte[len8];\r\n                        buffer.fillBytes(binary, 0, len8);\r\n                        value = binary;\r\n                        javaType = Types.VARBINARY;\r\n                        length = len8;\r\n                        break;\r\n                    }\r\n                    case 2: {\r\n                        /* BLOB/TEXT */\r\n                        final int len16 = buffer.getUint16();\r\n                        byte[] binary = new byte[len16];\r\n                        buffer.fillBytes(binary, 0, len16);\r\n                        value = binary;\r\n                        javaType = Types.LONGVARBINARY;\r\n                        length = len16;\r\n                        break;\r\n                    }\r\n                    case 3: {\r\n                        /* MEDIUMBLOB/MEDIUMTEXT */\r\n                        final int len24 = buffer.getUint24();\r\n                        byte[] binary = new byte[len24];\r\n                        buffer.fillBytes(binary, 0, len24);\r\n                        value = binary;\r\n                        javaType = Types.LONGVARBINARY;\r\n                        length = len24;\r\n                        break;\r\n                    }\r\n                    case 4: {\r\n                        /* LONGBLOB/LONGTEXT */\r\n                        final int len32 = (int) buffer.getUint32();\r\n                        byte[] binary = new byte[len32];\r\n                        buffer.fillBytes(binary, 0, len32);\r\n                        value = binary;\r\n                        javaType = Types.LONGVARBINARY;\r\n                        length = len32;\r\n                        break;\r\n                    }\r\n                    default:\r\n                        throw new IllegalArgumentException(\"!! Unknown BLOB packlen = \" + meta);\r\n                }\r\n                break;\r\n            }\r\n            case LogEvent.MYSQL_TYPE_VARCHAR:\r\n            case LogEvent.MYSQL_TYPE_VAR_STRING: {\r\n                /*\r\n                 * Except for the data length calculation, MYSQL_TYPE_VARCHAR,\r\n                 * MYSQL_TYPE_VAR_STRING and MYSQL_TYPE_STRING are handled the same way.\r\n                 */\r\n                len = meta;\r\n                if (len < 256) {\r\n                    len = buffer.getUint8();\r\n                } else {\r\n                    len = buffer.getUint16();\r\n                }\r\n\r\n                if (isBinary) {\r\n                    // fixed issue #66 ,binary类型在binlog中为var_string\r\n                    /* fill binary */\r\n                    byte[] binary = new byte[len];\r\n                    buffer.fillBytes(binary, 0, len);\r\n\r\n                    javaType = Types.VARBINARY;\r\n                    value = binary;\r\n                } else {\r\n                    value = buffer.getFullString(len, charset);\r\n                    javaType = Types.VARCHAR;\r\n                }\r\n\r\n                length = len;\r\n                break;\r\n            }\r\n            case LogEvent.MYSQL_TYPE_STRING: {\r\n                if (len < 256) {\r\n                    len = buffer.getUint8();\r\n                } else {\r\n                    len = buffer.getUint16();\r\n                }\r\n\r\n                if (isBinary) {\r\n                    /* fill binary */\r\n                    byte[] binary = new byte[len];\r\n                    buffer.fillBytes(binary, 0, len);\r\n\r\n                    javaType = Types.BINARY;\r\n                    value = binary;\r\n                } else {\r\n                    value = buffer.getFullString(len, charset);\r\n                    javaType = Types.CHAR; // Types.VARCHAR;\r\n                }\r\n                length = len;\r\n                break;\r\n            }\r\n            case LogEvent.MYSQL_TYPE_JSON: {\r\n                switch (meta) {\r\n                    case 1: {\r\n                        len = buffer.getUint8();\r\n                        break;\r\n                    }\r\n                    case 2: {\r\n                        len = buffer.getUint16();\r\n                        break;\r\n                    }\r\n                    case 3: {\r\n                        len = buffer.getUint24();\r\n                        break;\r\n                    }\r\n                    case 4: {\r\n                        len = (int) buffer.getUint32();\r\n                        break;\r\n                    }\r\n                    default:\r\n                        throw new IllegalArgumentException(\"!! Unknown JSON packlen = \" + meta);\r\n                }\r\n\r\n                if (partialBits.get(1)) {\r\n                    // print_json_diff\r\n                    int position = buffer.position();\r\n                    try {\r\n                        // https://github.com/alibaba/canal/pull/5018\r\n                        StringBuilder builder = JsonDiffConversion\r\n                            .print_json_diff(buffer, len, columnName, columnIndex, charset);\r\n                        value = builder.toString();\r\n                        buffer.position(position + len);\r\n                    } catch (IllegalArgumentException e) {\r\n                        buffer.position(position);\r\n                        // print_json_diff failed, fallback to parse_value\r\n                        parseJsonFromFullValue(len);\r\n                    }\r\n                } else {\r\n                    parseJsonFromFullValue(len);\r\n                }\r\n                javaType = Types.VARCHAR;\r\n                length = len;\r\n                break;\r\n            }\r\n            case LogEvent.MYSQL_TYPE_GEOMETRY: {\r\n                /*\r\n                 * MYSQL_TYPE_GEOMETRY: copy from BLOB or TEXT\r\n                 */\r\n                switch (meta) {\r\n                    case 1:\r\n                        len = buffer.getUint8();\r\n                        break;\r\n                    case 2:\r\n                        len = buffer.getUint16();\r\n                        break;\r\n                    case 3:\r\n                        len = buffer.getUint24();\r\n                        break;\r\n                    case 4:\r\n                        len = (int) buffer.getUint32();\r\n                        break;\r\n                    default:\r\n                        throw new IllegalArgumentException(\"!! Unknown MYSQL_TYPE_GEOMETRY packlen = \" + meta);\r\n                }\r\n                /* fill binary */\r\n                byte[] binary = new byte[len];\r\n                buffer.fillBytes(binary, 0, len);\r\n                // Warning unsupport cloumn type\r\n                // logger.warn(String.format(\"!! Unsupport column type MYSQL_TYPE_GEOMETRY:\r\n                // meta=%d (%04X), len = %d\", meta,meta, len));\r\n                javaType = Types.BINARY;\r\n                value = binary;\r\n                length = len;\r\n                break;\r\n            }\r\n            case LogEvent.MYSQL_TYPE_BOOL:\r\n            case LogEvent.MYSQL_TYPE_INVALID:\r\n            default:\r\n                logger.error(\r\n                    String.format(\"!! Don't know how to handle column type=%d meta=%d (%04X)\", type, meta, meta));\r\n                javaType = Types.OTHER;\r\n                value = null;\r\n                length = 0;\r\n        }\r\n\r\n        return value;\r\n    }\r\n\r\n    private void parseJsonFromFullValue(int len) {\r\n        if (0 == len) {\r\n            // fixed issue #1 by lava, json column of zero length has no value, value\r\n            // parsing should be skipped\r\n            value = \"\";\r\n        } else {\r\n            int position = buffer.position();\r\n            Json_Value jsonValue = JsonConversion.parse_value(buffer.getUint8(), buffer, len - 1, charset);\r\n            StringBuilder builder = new StringBuilder();\r\n            jsonValue.toJsonString(builder, charset);\r\n            value = builder.toString();\r\n            buffer.position(position + len);\r\n        }\r\n    }\r\n\r\n    public final boolean isNull() {\r\n        return fNull;\r\n    }\r\n\r\n    public final int getJavaType() {\r\n        return javaType;\r\n    }\r\n\r\n    public final Serializable getValue() {\r\n        return value;\r\n    }\r\n\r\n    public final int getLength() {\r\n        return length;\r\n    }\r\n\r\n    public static String usecondsToStr(int frac, int meta) {\r\n        String sec = String.valueOf(frac);\r\n        if (meta > 6) {\r\n            throw new IllegalArgumentException(\"unknow useconds meta : \" + meta);\r\n        }\r\n\r\n        if (sec.length() < 6) {\r\n            StringBuilder result = new StringBuilder(6);\r\n            int len = 6 - sec.length();\r\n            for (; len > 0; len--) {\r\n                result.append('0');\r\n            }\r\n            result.append(sec);\r\n            sec = result.toString();\r\n        }\r\n\r\n        return sec.substring(0, meta);\r\n    }\r\n\r\n    public static void appendNumber4(StringBuilder builder, int d) {\r\n        if (d >= 1000) {\r\n            builder.append(digits[d / 1000])\r\n                .append(digits[(d / 100) % 10])\r\n                .append(digits[(d / 10) % 10])\r\n                .append(digits[d % 10]);\r\n        } else {\r\n            builder.append('0');\r\n            appendNumber3(builder, d);\r\n        }\r\n    }\r\n\r\n    public static void appendNumber3(StringBuilder builder, int d) {\r\n        if (d >= 100) {\r\n            builder.append(digits[d / 100]).append(digits[(d / 10) % 10]).append(digits[d % 10]);\r\n        } else {\r\n            builder.append('0');\r\n            appendNumber2(builder, d);\r\n        }\r\n    }\r\n\r\n    public static void appendNumber2(StringBuilder builder, int d) {\r\n        if (d >= 10) {\r\n            builder.append(digits[(d / 10) % 10]).append(digits[d % 10]);\r\n        } else {\r\n            builder.append('0').append(digits[d]);\r\n        }\r\n    }\r\n\r\n    public static Long valueOf(long value) {\r\n        if (value >= -128 & value <= 127) {\r\n            // if (l >= -128 && l <= 127) {\r\n            return Long.valueOf(value);\r\n        }\r\n        if (value > 127 && value < longCacheLimit) {\r\n            int cacheIndex = (int) value - 127;\r\n            Long cacheValue = longCache[cacheIndex];\r\n            if (cacheValue == null) {\r\n                cacheValue = new Long(value);\r\n                longCache[cacheIndex] = cacheValue;\r\n            }\r\n            return cacheValue;\r\n        }\r\n        return new Long(value);\r\n    }\r\n\r\n    public static Integer valueOf(int value) {\r\n        if (value >= -128 & value <= 127) {\r\n            // if (l >= -128 && l <= 127) {\r\n            return Integer.valueOf(value);\r\n        }\r\n        if (value > 127 && value < integerCacheLimit) {\r\n            int cacheIndex = (int) value - 127;\r\n            Integer cacheValue = integerCache[cacheIndex];\r\n            if (cacheValue == null) {\r\n                cacheValue = new Integer(value);\r\n                integerCache[cacheIndex] = cacheValue;\r\n            }\r\n            return cacheValue;\r\n        }\r\n        return new Integer(value);\r\n    }\r\n}\r\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/RowsLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport java.nio.charset.Charset;\nimport java.util.BitSet;\n\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.LogContext;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.TableMapLogEvent.ColumnInfo;\nimport com.taobao.tddl.dbsync.binlog.exception.TableIdNotFoundException;\n\n/**\n * Common base class for all row-containing log events.\n * \n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\n * @version 1.0\n */\npublic abstract class RowsLogEvent extends LogEvent {\n\n    /**\n     * Fixed data part:\n     * <ul>\n     * <li>6 bytes. The table ID.</li>\n     * <li>2 bytes. Reserved for future use.</li>\n     * </ul>\n     * <p>\n     * Variable data part:\n     * <ul>\n     * <li>Packed integer. The number of columns in the table.</li>\n     * <li>Variable-sized. Bit-field indicating whether each column is used, one\n     * bit per column. For this field, the amount of storage required for N\n     * columns is INT((N+7)/8) bytes.</li>\n     * <li>Variable-sized (for UPDATE_ROWS_LOG_EVENT only). Bit-field indicating\n     * whether each column is used in the UPDATE_ROWS_LOG_EVENT after-image; one\n     * bit per column. For this field, the amount of storage required for N\n     * columns is INT((N+7)/8) bytes.</li>\n     * <li>Variable-sized. A sequence of zero or more rows. The end is\n     * determined by the size of the event. Each row has the following format:\n     * <ul>\n     * <li>Variable-sized. Bit-field indicating whether each field in the row is\n     * NULL. Only columns that are \"used\" according to the second field in the\n     * variable data part are listed here. If the second field in the variable\n     * data part has N one-bits, the amount of storage required for this field\n     * is INT((N+7)/8) bytes.</li>\n     * <li>Variable-sized. The row-image, containing values of all table fields.\n     * This only lists table fields that are used (according to the second field\n     * of the variable data part) and non-NULL (according to the previous\n     * field). In other words, the number of values listed here is equal to the\n     * number of zero bits in the previous field (not counting padding bits in\n     * the last byte). The format of each value is described in the\n     * log_event_print_value() function in log_event.cc.</li>\n     * <li>(for UPDATE_ROWS_EVENT only) the previous two fields are repeated,\n     * representing a second table row.</li>\n     * </ul>\n     * </ul>\n     * Source : http://forge.mysql.com/wiki/MySQL_Internals_Binary_Log\n     */\n    private final long       tableId;                           /* Table ID */\n    private TableMapLogEvent table;                             /*\n                                                                  * The table\n                                                                  * the rows\n                                                                  * belong to\n                                                                  */\n\n    /** Bitmap denoting columns available */\n    protected final int      columnLen;\n    protected final boolean  partial;\n    protected final BitSet   columns;\n\n    /**\n     * Bitmap for columns available in the after image, if present. These fields\n     * are only available for Update_rows events. Observe that the width of both\n     * the before image COLS vector and the after image COLS vector is the same:\n     * the number of columns of the table on the master.\n     */\n    protected final BitSet   changeColumns;\n\n    protected int            jsonColumnCount         = 0;\n\n    /** XXX: Don't handle buffer in another thread. */\n    private final LogBuffer  rowsBuf;                           /*\n                                                                  * The rows in\n                                                                  * packed\n                                                                  * format\n                                                                  */\n\n    /**\n     * enum enum_flag These definitions allow you to combine the flags into an\n     * appropriate flag set using the normal bitwise operators. The implicit\n     * conversion from an enum-constant to an integer is accepted by the\n     * compiler, which is then used to set the real set of flags.\n     */\n    private final int        flags;\n\n    /** Last event of a statement */\n    public static final int  STMT_END_F              = 1;\n\n    /** Value of the OPTION_NO_FOREIGN_KEY_CHECKS flag in thd->options */\n    public static final int  NO_FOREIGN_KEY_CHECKS_F = (1 << 1);\n\n    /** Value of the OPTION_RELAXED_UNIQUE_CHECKS flag in thd->options */\n    public static final int  RELAXED_UNIQUE_CHECKS_F = (1 << 2);\n\n    /**\n     * Indicates that rows in this event are complete, that is contain values\n     * for all columns of the table.\n     */\n    public static final int  COMPLETE_ROWS_F         = (1 << 3);\n\n    /* RW = \"RoWs\" */\n    public static final int  RW_MAPID_OFFSET         = 0;\n    public static final int  RW_FLAGS_OFFSET         = 6;\n    public static final int  RW_VHLEN_OFFSET         = 8;\n    public static final int  RW_V_TAG_LEN            = 1;\n    public static final int  RW_V_EXTRAINFO_TAG      = 0;\n\n    public RowsLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\n        this(header, buffer, descriptionEvent, false);\n    }\n\n    public RowsLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent,\n                        boolean partial){\n        this(header, buffer, descriptionEvent, false, false);\n    }\n\n    public RowsLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent, boolean partial,\n                        boolean compress){\n        super(header);\n        final int commonHeaderLen = descriptionEvent.commonHeaderLen;\n        final int postHeaderLen = descriptionEvent.postHeaderLen[header.type - 1];\n        int headerLen = 0;\n        buffer.position(commonHeaderLen + RW_MAPID_OFFSET);\n        if (postHeaderLen == 6) {\n            /*\n             * Master is of an intermediate source tree before 5.1.4. Id is 4\n             * bytes\n             */\n            tableId = buffer.getUint32();\n        } else {\n            tableId = buffer.getUlong48(); // RW_FLAGS_OFFSET\n        }\n        flags = buffer.getUint16();\n\n        if (postHeaderLen == FormatDescriptionLogEvent.ROWS_HEADER_LEN_V2) {\n            headerLen = buffer.getUint16();\n            headerLen -= 2;\n            int start = buffer.position();\n            int end = start + headerLen;\n            for (int i = start; i < end;) {\n                switch (buffer.getUint8(i++)) {\n                    case RW_V_EXTRAINFO_TAG:\n                        // int infoLen = buffer.getUint8();\n                        buffer.position(i + EXTRA_ROW_INFO_LEN_OFFSET);\n                        int checkLen = buffer.getUint8(); // EXTRA_ROW_INFO_LEN_OFFSET\n                        int val = checkLen - EXTRA_ROW_INFO_HDR_BYTES;\n                        assert (buffer.getUint8() == val); // EXTRA_ROW_INFO_FORMAT_OFFSET\n                        for (int j = 0; j < val; j++) {\n                            assert (buffer.getUint8() == val); // EXTRA_ROW_INFO_HDR_BYTES\n                                                               // + i\n                        }\n                        break;\n                    default:\n                        i = end;\n                        break;\n                }\n            }\n        }\n\n        buffer.position(commonHeaderLen + postHeaderLen + headerLen);\n        columnLen = (int) buffer.getPackedLong();\n        this.partial = partial;\n        columns = buffer.getBitmap(columnLen);\n\n        if (header.type == UPDATE_ROWS_EVENT_V1 || header.type == UPDATE_ROWS_EVENT\n            || header.type == PARTIAL_UPDATE_ROWS_EVENT || header.type == UPDATE_ROWS_COMPRESSED_EVENT\n            || header.type == UPDATE_ROWS_COMPRESSED_EVENT_V1) {\n            changeColumns = buffer.getBitmap(columnLen);\n        } else {\n            changeColumns = columns;\n        }\n\n        // XXX: Don't handle buffer in another thread.\n        int dataSize = buffer.limit() - buffer.position();\n        if (compress) {\n            // mariadb compress log event\n            // see https://github.com/alibaba/canal/issues/4388\n            buffer = buffer.uncompressBuf();\n            dataSize = buffer.limit();\n            // rewrite type\n            if (postHeaderLen == FormatDescriptionLogEvent.ROWS_HEADER_LEN_V2) {\n                header.type = header.type - WRITE_ROWS_COMPRESSED_EVENT + WRITE_ROWS_EVENT;\n            } else {\n                header.type = header.type - WRITE_ROWS_COMPRESSED_EVENT_V1 + WRITE_ROWS_EVENT_V1;\n            }\n        }\n        rowsBuf = buffer.duplicate(dataSize);\n    }\n\n    public final void fillTable(LogContext context) {\n        table = context.getTable(tableId);\n\n        if (table == null) {\n            throw new TableIdNotFoundException(\"not found tableId:\" + tableId);\n        }\n\n        // end of statement check:\n        if ((flags & RowsLogEvent.STMT_END_F) != 0) {\n            // Now is safe to clear ignored map (clear_tables will also\n            // delete original table map events stored in the map).\n            context.clearAllTables();\n        }\n\n        int jsonColumnCount = 0;\n        int columnCnt = table.getColumnCnt();\n        ColumnInfo[] columnInfo = table.getColumnInfo();\n        for (int i = 0; i < columnCnt; i++) {\n            ColumnInfo info = columnInfo[i];\n            if (info.type == LogEvent.MYSQL_TYPE_JSON) {\n                jsonColumnCount++;\n            }\n        }\n        this.jsonColumnCount = jsonColumnCount;\n    }\n\n    public final long getTableId() {\n        return tableId;\n    }\n\n    public final TableMapLogEvent getTable() {\n        return table;\n    }\n\n    public final BitSet getColumns() {\n        return columns;\n    }\n\n    public final BitSet getChangeColumns() {\n        return changeColumns;\n    }\n\n    public final RowsLogBuffer getRowsBuf(Charset charset) {\n        return new RowsLogBuffer(rowsBuf, columnLen, charset, jsonColumnCount, partial);\n    }\n\n    public final int getFlags(final int flags) {\n        return this.flags & flags;\n    }\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/RowsQueryLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\n\nimport java.nio.charset.StandardCharsets;\n\n/**\n * @author jianghang 2013-4-8 上午12:36:29\n * @version 1.0.3\n * @since mysql 5.6\n */\npublic class RowsQueryLogEvent extends IgnorableLogEvent {\n\n    private String rowsQuery;\n\n    public RowsQueryLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\n        super(header, buffer, descriptionEvent);\n\n        final int commonHeaderLen = descriptionEvent.commonHeaderLen;\n        final int postHeaderLen = descriptionEvent.postHeaderLen[header.type - 1];\n\n        /*\n         * m_rows_query length is stored using only one byte, but that length is\n         * ignored and the complete query is read.\n         */\n        int offset = commonHeaderLen + postHeaderLen + 1;\n        int len = buffer.limit() - offset;\n        rowsQuery = buffer.getFullString(offset, len, StandardCharsets.ISO_8859_1);\n    }\n\n    public String getRowsQuery() {\n        return rowsQuery;\n    }\n\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/StartLogEventV3.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\n\n/**\n * Start_log_event_v3 is the Start_log_event of binlog format 3 (MySQL 3.23 and\n * 4.x). Format_description_log_event derives from Start_log_event_v3; it is the\n * Start_log_event of binlog format 4 (MySQL 5.0), that is, the event that\n * describes the other events' Common-Header/Post-Header lengths. This event is\n * sent by MySQL 5.0 whenever it starts sending a new binlog if the requested\n * position is >4 (otherwise if ==4 the event will be sent naturally).\n * \n * @see mysql-5.1.60/sql/log_event.cc - Start_log_event_v3\n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\n * @version 1.0\n */\npublic class StartLogEventV3 extends LogEvent {\n\n    /**\n     * We could have used SERVER_VERSION_LENGTH, but this introduces an obscure\n     * dependency - if somebody decided to change SERVER_VERSION_LENGTH this\n     * would break the replication protocol\n     */\n    public static final int ST_SERVER_VER_LEN    = 50;\n\n    /* start event post-header (for v3 and v4) */\n    public static final int ST_BINLOG_VER_OFFSET = 0;\n    public static final int ST_SERVER_VER_OFFSET = 2;\n\n    protected int           binlogVersion;\n    protected String        serverVersion;\n\n    public StartLogEventV3(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\n        super(header);\n\n        buffer.position(descriptionEvent.commonHeaderLen);\n        binlogVersion = buffer.getUint16(); // ST_BINLOG_VER_OFFSET\n        serverVersion = buffer.getFixName(ST_SERVER_VER_LEN); // ST_SERVER_VER_OFFSET\n    }\n\n    public StartLogEventV3(){\n        super(new LogHeader(START_EVENT_V3));\n    }\n\n    public final String getServerVersion() {\n        return serverVersion;\n    }\n\n    public final int getBinlogVersion() {\n        return binlogVersion;\n    }\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/StopLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\n\n/**\n * Stop_log_event. The Post-Header and Body for this event type are empty; it\n * only has the Common-Header.\n * \n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\n * @version 1.0\n */\npublic final class StopLogEvent extends LogEvent {\n\n    public StopLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent description_event){\n        super(header);\n    }\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/TableMapLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\nimport java.util.ArrayList;\nimport java.util.BitSet;\nimport java.util.List;\n\n/**\n * In row-based mode, every row operation event is preceded by a\n * Table_map_log_event which maps a table definition to a number. The table\n * definition consists of database name, table name, and column definitions. The\n * Post-Header has the following components:\n * <table>\n * <caption>Post-Header for Table_map_log_event</caption>\n * <tr>\n * <th>Name</th>\n * <th>Format</th>\n * <th>Description</th>\n * </tr>\n * <tr>\n * <td>table_id</td>\n * <td>6 bytes unsigned integer</td>\n * <td>The number that identifies the table.</td>\n * </tr>\n * <tr>\n * <td>flags</td>\n * <td>2 byte bitfield</td>\n * <td>Reserved for future use; currently always 0.</td>\n * </tr>\n * </table>\n * The Body has the following components:\n * <table>\n * <caption>Body for Table_map_log_event</caption>\n * <tr>\n * <th>Name</th>\n * <th>Format</th>\n * <th>Description</th>\n * </tr>\n * <tr>\n * <td>database_name</td>\n * <td>one byte string length, followed by null-terminated string</td>\n * <td>The name of the database in which the table resides. The name is\n * represented as a one byte unsigned integer representing the number of bytes\n * in the name, followed by length bytes containing the database name, followed\n * by a terminating 0 byte. (Note the redundancy in the representation of the\n * length.)</td>\n * </tr>\n * <tr>\n * <td>table_name</td>\n * <td>one byte string length, followed by null-terminated string</td>\n * <td>The name of the table, encoded the same way as the database name above.</td>\n * </tr>\n * <tr>\n * <td>column_count</td>\n * <td>packed_integer \"Packed Integer\"</td>\n * <td>The number of columns in the table, represented as a packed\n * variable-length integer.</td>\n * </tr>\n * <tr>\n * <td>column_type</td>\n * <td>List of column_count 1 byte enumeration values</td>\n * <td>The type of each column in the table, listed from left to right. Each\n * byte is mapped to a column type according to the enumeration type\n * enum_field_types defined in mysql_com.h. The mapping of types to numbers is\n * listed in the table Table_table_map_log_event_column_types \"below\" (along\n * with description of the associated metadata field).</td>\n * </tr>\n * <tr>\n * <td>metadata_length</td>\n * <td>packed_integer \"Packed Integer\"</td>\n * <td>The length of the following metadata block</td>\n * </tr>\n * <tr>\n * <td>metadata</td>\n * <td>list of metadata for each column</td>\n * <td>For each column from left to right, a chunk of data who's length and\n * semantics depends on the type of the column. The length and semantics for the\n * metadata for each column are listed in the table\n * Table_table_map_log_event_column_types \"below\".</td>\n * </tr>\n * <tr>\n * <td>null_bits</td>\n * <td>column_count bits, rounded up to nearest byte</td>\n * <td>For each column, a bit indicating whether data in the column can be NULL\n * or not. The number of bytes needed for this is int((column_count+7)/8). The\n * flag for the first column from the left is in the least-significant bit of\n * the first byte, the second is in the second least significant bit of the\n * first byte, the ninth is in the least significant bit of the second byte, and\n * so on.</td>\n * </tr>\n * <tr>\n * <td>optional metadata fields</td>\n * <td>optional metadata fields are stored in Type, Length, Value(TLV) format.\n * Type takes 1 byte. Length is a packed integer value. Values takes Length\n * bytes.</td>\n * <td>There are some optional metadata defined. They are listed in the table\n * \n * @ref Table_table_map_event_optional_metadata. Optional metadata fields follow\n * null_bits. Whether binlogging an optional metadata is decided by the server.\n * The order is not defined, so they can be binlogged in any order. </td>\n * </tr>\n * </table>\n * The table below lists all column types, along with the numerical identifier\n * for it and the size and interpretation of meta-data used to describe the\n * type.\n * <table>\n * <caption>Table_map_log_event column types: numerical identifier and\n * metadata</caption>\n * <tr>\n * <th>Name</th>\n * <th>Identifier</th>\n * <th>Size of metadata in bytes</th>\n * <th>Description of metadata</th>\n * </tr>\n * <tr>\n * <td>MYSQL_TYPE_DECIMAL</td>\n * <td>0</td>\n * <td>0</td>\n * <td>No column metadata.</td>\n * </tr>\n * <tr>\n * <td>MYSQL_TYPE_TINY</td>\n * <td>1</td>\n * <td>0</td>\n * <td>No column metadata.</td>\n * </tr>\n * <tr>\n * <td>MYSQL_TYPE_SHORT</td>\n * <td>2</td>\n * <td>0</td>\n * <td>No column metadata.</td>\n * </tr>\n * <tr>\n * <td>MYSQL_TYPE_LONG</td>\n * <td>3</td>\n * <td>0</td>\n * <td>No column metadata.</td>\n * </tr>\n * <tr>\n * <td>MYSQL_TYPE_FLOAT</td>\n * <td>4</td>\n * <td>1 byte</td>\n * <td>1 byte unsigned integer, representing the \"pack_length\", which is equal\n * to sizeof(float) on the server from which the event originates.</td>\n * </tr>\n * <tr>\n * <td>MYSQL_TYPE_DOUBLE</td>\n * <td>5</td>\n * <td>1 byte</td>\n * <td>1 byte unsigned integer, representing the \"pack_length\", which is equal\n * to sizeof(double) on the server from which the event originates.</td>\n * </tr>\n * <tr>\n * <td>MYSQL_TYPE_NULL</td>\n * <td>6</td>\n * <td>0</td>\n * <td>No column metadata.</td>\n * </tr>\n * <tr>\n * <td>MYSQL_TYPE_TIMESTAMP</td>\n * <td>7</td>\n * <td>0</td>\n * <td>No column metadata.</td>\n * </tr>\n * <tr>\n * <td>MYSQL_TYPE_LONGLONG</td>\n * <td>8</td>\n * <td>0</td>\n * <td>No column metadata.</td>\n * </tr>\n * <tr>\n * <td>MYSQL_TYPE_INT24</td>\n * <td>9</td>\n * <td>0</td>\n * <td>No column metadata.</td>\n * </tr>\n * <tr>\n * <td>MYSQL_TYPE_DATE</td>\n * <td>10</td>\n * <td>0</td>\n * <td>No column metadata.</td>\n * </tr>\n * <tr>\n * <td>MYSQL_TYPE_TIME</td>\n * <td>11</td>\n * <td>0</td>\n * <td>No column metadata.</td>\n * </tr>\n * <tr>\n * <td>MYSQL_TYPE_DATETIME</td>\n * <td>12</td>\n * <td>0</td>\n * <td>No column metadata.</td>\n * </tr>\n * <tr>\n * <td>MYSQL_TYPE_YEAR</td>\n * <td>13</td>\n * <td>0</td>\n * <td>No column metadata.</td>\n * </tr>\n * <tr>\n * <td><i>MYSQL_TYPE_NEWDATE</i></td>\n * <td><i>14</i></td>\n * <td>&ndash;</td>\n * <td><i>This enumeration value is only used internally and cannot exist in a\n * binlog.</i></td>\n * </tr>\n * <tr>\n * <td>MYSQL_TYPE_VARCHAR</td>\n * <td>15</td>\n * <td>2 bytes</td>\n * <td>2 byte unsigned integer representing the maximum length of the string.</td>\n * </tr>\n * <tr>\n * <td>MYSQL_TYPE_BIT</td>\n * <td>16</td>\n * <td>2 bytes</td>\n * <td>A 1 byte unsigned int representing the length in bits of the bitfield (0\n * to 64), followed by a 1 byte unsigned int representing the number of bytes\n * occupied by the bitfield. The number of bytes is either int((length+7)/8) or\n * int(length/8).</td>\n * </tr>\n * <tr>\n * <td>MYSQL_TYPE_NEWDECIMAL</td>\n * <td>246</td>\n * <td>2 bytes</td>\n * <td>A 1 byte unsigned int representing the precision, followed by a 1 byte\n * unsigned int representing the number of decimals.</td>\n * </tr>\n * <tr>\n * <td><i>MYSQL_TYPE_ENUM</i></td>\n * <td><i>247</i></td>\n * <td>&ndash;</td>\n * <td><i>This enumeration value is only used internally and cannot exist in a\n * binlog.</i></td>\n * </tr>\n * <tr>\n * <td><i>MYSQL_TYPE_SET</i></td>\n * <td><i>248</i></td>\n * <td>&ndash;</td>\n * <td><i>This enumeration value is only used internally and cannot exist in a\n * binlog.</i></td>\n * </tr>\n * <tr>\n * <td>MYSQL_TYPE_TINY_BLOB</td>\n * <td>249</td>\n * <td>&ndash;</td>\n * <td><i>This enumeration value is only used internally and cannot exist in a\n * binlog.</i></td>\n * </tr>\n * <tr>\n * <td><i>MYSQL_TYPE_MEDIUM_BLOB</i></td>\n * <td><i>250</i></td>\n * <td>&ndash;</td>\n * <td><i>This enumeration value is only used internally and cannot exist in a\n * binlog.</i></td>\n * </tr>\n * <tr>\n * <td><i>MYSQL_TYPE_LONG_BLOB</i></td>\n * <td><i>251</i></td>\n * <td>&ndash;</td>\n * <td><i>This enumeration value is only used internally and cannot exist in a\n * binlog.</i></td>\n * </tr>\n * <tr>\n * <td>MYSQL_TYPE_BLOB</td>\n * <td>252</td>\n * <td>1 byte</td>\n * <td>The pack length, i.e., the number of bytes needed to represent the length\n * of the blob: 1, 2, 3, or 4.</td>\n * </tr>\n * <tr>\n * <td>MYSQL_TYPE_VAR_STRING</td>\n * <td>253</td>\n * <td>2 bytes</td>\n * <td>This is used to store both strings and enumeration values. The first byte\n * is a enumeration value storing the <i>real type</i>, which may be either\n * MYSQL_TYPE_VAR_STRING or MYSQL_TYPE_ENUM. The second byte is a 1 byte\n * unsigned integer representing the field size, i.e., the number of bytes\n * needed to store the length of the string.</td>\n * </tr>\n * <tr>\n * <td>MYSQL_TYPE_STRING</td>\n * <td>254</td>\n * <td>2 bytes</td>\n * <td>The first byte is always MYSQL_TYPE_VAR_STRING (i.e., 253). The second\n * byte is the field size, i.e., the number of bytes in the representation of\n * size of the string: 3 or 4.</td>\n * </tr>\n * <tr>\n * <td>MYSQL_TYPE_GEOMETRY</td>\n * <td>255</td>\n * <td>1 byte</td>\n * <td>The pack length, i.e., the number of bytes needed to represent the length\n * of the geometry: 1, 2, 3, or 4.</td>\n * </tr>\n * </table>\n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\n * @version 1.0\n */\npublic final class TableMapLogEvent extends LogEvent {\n\n    /**\n     * Fixed data part:\n     * <ul>\n     * <li>6 bytes. The table ID.</li>\n     * <li>2 bytes. Reserved for future use.</li>\n     * </ul>\n     * <p>\n     * Variable data part:\n     * <ul>\n     * <li>1 byte. The length of the database name.</li>\n     * <li>Variable-sized. The database name (null-terminated).</li>\n     * <li>1 byte. The length of the table name.</li>\n     * <li>Variable-sized. The table name (null-terminated).</li>\n     * <li>Packed integer. The number of columns in the table.</li>\n     * <li>Variable-sized. An array of column types, one byte per column.</li>\n     * <li>Packed integer. The length of the metadata block.</li>\n     * <li>Variable-sized. The metadata block; see log_event.h for contents and\n     * format.</li>\n     * <li>Variable-sized. Bit-field indicating whether each column can be NULL,\n     * one bit per column. For this field, the amount of storage required for N\n     * columns is INT((N+7)/8) bytes.</li>\n     * </ul>\n     * Source : http://forge.mysql.com/wiki/MySQL_Internals_Binary_Log\n     */\n    protected String dbname;\n    protected String tblname;\n\n    /**\n     * Holding mysql column information.\n     */\n    public static final class ColumnInfo {\n\n        public int          type;\n        public int          meta;\n        public String       name;\n        public boolean      unsigned;\n        public boolean      pk;\n        public List<String> set_enum_values;\n        public int          charset;        // 可以通过CharsetUtil进行转化\n        public int          geoType;\n        public boolean      nullable;\n        public boolean      visibility;\n        public boolean      array;\n\n        @Override public String toString() {\n            return \"ColumnInfo{\" + \"type=\" + type + \", meta=\" + meta + \", name='\" + name + '\\'' + \", unsigned=\"\n                   + unsigned + \", pk=\" + pk + \", set_enum_values=\" + set_enum_values + \", charset=\" + charset\n                   + \", geoType=\" + geoType + \", nullable=\" + nullable + \", visibility=\" + visibility + \", array=\"\n                   + array + '}';\n        }\n    }\n\n    protected final int          columnCnt;\n    protected final ColumnInfo[] columnInfo;                     // buffer\n                                                                  // for\n                                                                  // field\n                                                                  // metadata\n\n    protected final long         tableId;\n    protected BitSet             nullBits;\n\n    /** TM = \"Table Map\" */\n    public static final int      TM_MAPID_OFFSET         = 0;\n    public static final int      TM_FLAGS_OFFSET         = 6;\n\n    // UNSIGNED flag of numeric columns\n    public static final int      SIGNEDNESS              = 1;\n    // Default character set of string columns\n    public static final int      DEFAULT_CHARSET         = 2;\n    // Character set of string columns\n    public static final int      COLUMN_CHARSET          = 3;\n    public static final int      COLUMN_NAME             = 4;\n    // String value of SET columns\n    public static final int      SET_STR_VALUE           = 5;\n    // String value of ENUM columns\n    public static final int      ENUM_STR_VALUE          = 6;\n    // Real type of geometry columns\n    public static final int      GEOMETRY_TYPE           = 7;\n    // Primary key without prefix\n    public static final int      SIMPLE_PRIMARY_KEY      = 8;\n    // Primary key with prefix\n    public static final int      PRIMARY_KEY_WITH_PREFIX = 9;\n    // Character set of enum and set columns, optimized to minimize space when many columns have the same charset.\n    public static final int      ENUM_AND_SET_DEFAULT_CHARSET = 10;\n    // Character set of enum and set columns, optimized to minimize space when many columns have the same charset.\n    public static final int      ENUM_AND_SET_COLUMN_CHARSET = 11;\n    // Flag to indicate column visibility attribute\n    public static final int      COLUMN_VISIBILITY       = 12;\n\n    private int                  default_charset;\n    private boolean              existOptionalMetaData   = false;\n\n    private static final class Pair {\n\n        public int col_index;\n        public int col_charset;\n    }\n\n    /**\n     * Constructor used by slave to read the event from the binary log.\n     */\n    public TableMapLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\n        super(header);\n\n        final int commonHeaderLen = descriptionEvent.commonHeaderLen;\n        final int postHeaderLen = descriptionEvent.postHeaderLen[header.type - 1];\n        /* Read the post-header */\n        buffer.position(commonHeaderLen + TM_MAPID_OFFSET);\n        if (postHeaderLen == 6) {\n            /*\n             * Master is of an intermediate source tree before 5.1.4. Id is 4\n             * bytes\n             */\n            tableId = buffer.getUint32();\n        } else {\n            // DBUG_ASSERT(post_header_len == TABLE_MAP_HEADER_LEN);\n            tableId = buffer.getUlong48();\n        }\n        // flags = buffer.getUint16();\n\n        /* Read the variable part of the event */\n        buffer.position(commonHeaderLen + postHeaderLen);\n        dbname = buffer.getName();\n        buffer.forward(1); /* termination null */\n        // fixed issue #2714\n        tblname = buffer.getName();\n        buffer.forward(1); /* termination null */\n\n        // Read column information from buffer\n        columnCnt = (int) buffer.getPackedLong();\n        columnInfo = new ColumnInfo[columnCnt];\n        for (int i = 0; i < columnCnt; i++) {\n            ColumnInfo info = new ColumnInfo();\n            info.type = buffer.getUint8();\n            columnInfo[i] = info;\n        }\n\n        if (buffer.position() < buffer.limit()) {\n            final int fieldSize = (int) buffer.getPackedLong();\n            decodeFields(buffer, fieldSize);\n            nullBits = buffer.getBitmap(columnCnt);\n\n            for (int i = 0; i < columnCnt; i++) {\n                if (nullBits.get(i)) {\n                    columnInfo[i].nullable = true;\n                }\n            }\n            /*\n             * After null_bits field, there are some new fields for extra\n             * metadata.\n             */\n            existOptionalMetaData = false;\n            List<TableMapLogEvent.Pair> defaultCharsetPairs = null;\n            List<Integer> columnCharsets = null;\n            while (buffer.hasRemaining()) {\n                // optional metadata fields\n                int type = buffer.getUint8();\n                int len = (int) buffer.getPackedLong();\n\n                switch (type) {\n                    case SIGNEDNESS:\n                        parse_signedness(buffer, len);\n                        break;\n                    case DEFAULT_CHARSET:\n                        defaultCharsetPairs = parse_default_charset(buffer, len);\n                        break;\n                    case COLUMN_CHARSET:\n                        columnCharsets = parse_column_charset(buffer, len);\n                        break;\n                    case COLUMN_NAME:\n                        // set @@global.binlog_row_metadata='FULL'\n                        // 主要是补充列名相关信息\n                        existOptionalMetaData = true;\n                        parse_column_name(buffer, len);\n                        break;\n                    case SET_STR_VALUE:\n                        parse_set_str_value(buffer, len, true);\n                        break;\n                    case ENUM_STR_VALUE:\n                        parse_set_str_value(buffer, len, false);\n                        break;\n                    case GEOMETRY_TYPE:\n                        parse_geometry_type(buffer, len);\n                        break;\n                    case SIMPLE_PRIMARY_KEY:\n                        parse_simple_pk(buffer, len);\n                        break;\n                    case PRIMARY_KEY_WITH_PREFIX:\n                        parse_pk_with_prefix(buffer, len);\n                        break;\n                    case ENUM_AND_SET_DEFAULT_CHARSET:\n                        parse_default_charset(buffer, len);\n                        break;\n                    case ENUM_AND_SET_COLUMN_CHARSET:\n                        parse_column_charset(buffer, len);\n                        break;\n                    case COLUMN_VISIBILITY:\n                        parse_column_visibility(buffer, len);\n                        break;\n                    default:\n                        throw new IllegalArgumentException(\"unknow type : \" + type);\n                }\n            }\n\n            if (existOptionalMetaData) {\n                int index = 0;\n                int char_col_index = 0;\n                for (int i = 0; i < columnCnt; i++) {\n                    int cs = -1;\n                    int type = getRealType(columnInfo[i].type, columnInfo[i].meta);\n                    if (is_character_type(type)) {\n                        if (defaultCharsetPairs != null && !defaultCharsetPairs.isEmpty()) {\n                            if (index < defaultCharsetPairs.size()\n                                && char_col_index == defaultCharsetPairs.get(index).col_index) {\n                                cs = defaultCharsetPairs.get(index).col_charset;\n                                index++;\n                            } else {\n                                cs = default_charset;\n                            }\n\n                            char_col_index++;\n                        } else if (columnCharsets != null) {\n                            cs = columnCharsets.get(index);\n                            index++;\n                        }\n\n                        columnInfo[i].charset = cs;\n                    }\n                }\n            }\n        }\n\n        // for (int i = 0; i < columnCnt; i++) {\n        // System.out.println(columnInfo[i]);\n        // }\n    }\n\n    /**\n     * Decode field metadata by column types.\n     * \n     * @see mysql-5.1.60/sql/rpl_utility.h\n     */\n    private final void decodeFields(LogBuffer buffer, final int len) {\n        final int limit = buffer.limit();\n        buffer.limit(len + buffer.position());\n        for (int i = 0; i < columnCnt; i++) {\n            ColumnInfo info = columnInfo[i];\n\n            int binlogType = info.type;\n            if (binlogType == MYSQL_TYPE_TYPED_ARRAY) {\n                binlogType = buffer.getUint8();\n            }\n\n            switch (binlogType) {\n                case MYSQL_TYPE_TINY_BLOB:\n                case MYSQL_TYPE_BLOB:\n                case MYSQL_TYPE_MEDIUM_BLOB:\n                case MYSQL_TYPE_LONG_BLOB:\n                case MYSQL_TYPE_DOUBLE:\n                case MYSQL_TYPE_FLOAT:\n                case MYSQL_TYPE_GEOMETRY:\n                case MYSQL_TYPE_TIME2:\n                case MYSQL_TYPE_DATETIME2:\n                case MYSQL_TYPE_TIMESTAMP2:\n                case MYSQL_TYPE_JSON:\n                    /*\n                     * These types store a single byte.\n                     */\n                    info.meta = buffer.getUint8();\n                    break;\n                case MYSQL_TYPE_SET:\n                case MYSQL_TYPE_ENUM:\n                case MYSQL_TYPE_STRING: {\n                    /*\n                     * log_event.h : The first byte is always\n                     * MYSQL_TYPE_VAR_STRING (i.e., 253). The second byte is the\n                     * field size, i.e., the number of bytes in the\n                     * representation of size of the string: 3 or 4.\n                     */\n                    int x = (buffer.getUint8() << 8); // real_type\n                    x += buffer.getUint8(); // pack or field length\n                    info.meta = x;\n                    break;\n                }\n                case MYSQL_TYPE_BIT:\n                    info.meta = buffer.getUint16();\n                    break;\n                case MYSQL_TYPE_VARCHAR:\n                    /*\n                     * These types store two bytes.\n                     */\n                    info.meta = buffer.getUint16();\n                    break;\n                case MYSQL_TYPE_NEWDECIMAL: {\n                    int x = buffer.getUint8() << 8; // precision\n                    x += buffer.getUint8(); // decimals\n                    info.meta = x;\n                    break;\n                }\n                default:\n                    info.meta = 0;\n                    break;\n            }\n        }\n        buffer.limit(limit);\n    }\n\n    private void parse_signedness(LogBuffer buffer, int length) {\n        // stores the signedness flags extracted from field\n        List<Boolean> datas = new ArrayList<>();\n        for (int i = 0; i < length; i++) {\n            int ut = buffer.getUint8();\n            for (int c = 0x80; c != 0; c >>= 1) {\n                datas.add((ut & c) > 0);\n            }\n        }\n\n        int index = 0;\n        for (int i = 0; i < columnCnt; i++) {\n            if (is_numeric_type(columnInfo[i].type)) {\n                columnInfo[i].unsigned = datas.get(index);\n                index++;\n            }\n        }\n    }\n\n    private List<TableMapLogEvent.Pair> parse_default_charset(LogBuffer buffer, int length) {\n        // stores collation numbers extracted from field.\n        int limit = buffer.position() + length;\n        this.default_charset = (int) buffer.getPackedLong();\n        List<TableMapLogEvent.Pair> datas = new ArrayList<>();\n        while (buffer.hasRemaining() && buffer.position() < limit) {\n            int col_index = (int) buffer.getPackedLong();\n            int col_charset = (int) buffer.getPackedLong();\n\n            Pair pair = new Pair();\n            pair.col_index = col_index;\n            pair.col_charset = col_charset;\n            datas.add(pair);\n        }\n\n        return datas;\n    }\n\n    private List<Integer> parse_column_charset(LogBuffer buffer, int length) {\n        // stores collation numbers extracted from field.\n        int limit = buffer.position() + length;\n        List<Integer> datas = new ArrayList<>();\n        while (buffer.hasRemaining() && buffer.position() < limit) {\n            int col_charset = (int) buffer.getPackedLong();\n            datas.add(col_charset);\n        }\n\n        return datas;\n    }\n\n\n    private void parse_column_visibility(LogBuffer buffer, int length) {\n        List<Boolean> data = new ArrayList<>(columnInfo.length);\n        for (int i = 0; i < length; i++) {\n            int ut = buffer.getUint8();\n            for (int c = 0x80; c != 0; c >>= 1) {\n                data.add((ut & c) > 0);\n            }\n        }\n        for (int i = 0; i < columnCnt; i++) {\n            columnInfo[i].visibility = data.get(i);\n        }\n    }\n\n    private void parse_column_name(LogBuffer buffer, int length) {\n        // stores column names extracted from field\n        int limit = buffer.position() + length;\n        int index = 0;\n        while (buffer.hasRemaining() && buffer.position() < limit) {\n            int len = (int) buffer.getPackedLong();\n            columnInfo[index++].name = buffer.getFixString(len);\n        }\n    }\n\n    private void parse_set_str_value(LogBuffer buffer, int length, boolean set) {\n        // stores SET/ENUM column's string values extracted from\n        // field. Each SET/ENUM column's string values are stored\n        // into a string separate vector. All of them are stored\n        // in 'vec'.\n        int limit = buffer.position() + length;\n        List<List<String>> datas = new ArrayList<>();\n        while (buffer.hasRemaining() && buffer.position() < limit) {\n            int count = (int) buffer.getPackedLong();\n            List<String> data = new ArrayList<>(count);\n            for (int i = 0; i < count; i++) {\n                int len1 = (int) buffer.getPackedLong();\n                data.add(buffer.getFixString(len1));\n            }\n\n            datas.add(data);\n        }\n\n        int index = 0;\n        for (int i = 0; i < columnCnt; i++) {\n            if (set && getRealType(columnInfo[i].type, columnInfo[i].meta) == LogEvent.MYSQL_TYPE_SET) {\n                columnInfo[i].set_enum_values = datas.get(index);\n                index++;\n            }\n\n            if (!set && getRealType(columnInfo[i].type, columnInfo[i].meta) == LogEvent.MYSQL_TYPE_ENUM) {\n                columnInfo[i].set_enum_values = datas.get(index);\n                index++;\n            }\n        }\n    }\n\n    private void parse_geometry_type(LogBuffer buffer, int length) {\n        // stores geometry column's types extracted from field.\n        int limit = buffer.position() + length;\n\n        List<Integer> datas = new ArrayList<>();\n        while (buffer.hasRemaining() && buffer.position() < limit) {\n            int col_type = (int) buffer.getPackedLong();\n            datas.add(col_type);\n        }\n\n        int index = 0;\n        for (int i = 0; i < columnCnt; i++) {\n            if (columnInfo[i].type == LogEvent.MYSQL_TYPE_GEOMETRY) {\n                columnInfo[i].geoType = datas.get(index);\n                index++;\n            }\n        }\n    }\n\n    private void parse_simple_pk(LogBuffer buffer, int length) {\n        // stores primary key's column information extracted from\n        // field. Each column has an index and a prefix which are\n        // stored as a unit_pair. prefix is always 0 for\n        // SIMPLE_PRIMARY_KEY field.\n\n        int limit = buffer.position() + length;\n        while (buffer.hasRemaining() && buffer.position() < limit) {\n            int col_index = (int) buffer.getPackedLong();\n            columnInfo[col_index].pk = true;\n        }\n    }\n\n    private void parse_pk_with_prefix(LogBuffer buffer, int length) {\n        // stores primary key's column information extracted from\n        // field. Each column has an index and a prefix which are\n        // stored as a unit_pair.\n        int limit = buffer.position() + length;\n        while (buffer.hasRemaining() && buffer.position() < limit) {\n            int col_index = (int) buffer.getPackedLong();\n            // prefix length, 比如 char(32)\n            @SuppressWarnings(\"unused\")\n            int col_prefix = (int) buffer.getPackedLong();\n            columnInfo[col_index].pk = true;\n        }\n    }\n\n    private boolean is_numeric_type(int type) {\n        switch (type) {\n            case MYSQL_TYPE_TINY:\n            case MYSQL_TYPE_SHORT:\n            case MYSQL_TYPE_INT24:\n            case MYSQL_TYPE_LONG:\n            case MYSQL_TYPE_LONGLONG:\n            case MYSQL_TYPE_NEWDECIMAL:\n            case MYSQL_TYPE_FLOAT:\n            case MYSQL_TYPE_DOUBLE:\n                return true;\n            default:\n                return false;\n        }\n    }\n\n    private boolean is_character_type(int type) {\n        switch (type) {\n            case MYSQL_TYPE_STRING:\n            case MYSQL_TYPE_VAR_STRING:\n            case MYSQL_TYPE_VARCHAR:\n            case MYSQL_TYPE_BLOB:\n                return true;\n            default:\n                return false;\n        }\n    }\n\n    private int getRealType(int type, int meta) {\n        if (type == LogEvent.MYSQL_TYPE_STRING) {\n            if (meta >= 256) {\n                int byte0 = meta >> 8;\n                if ((byte0 & 0x30) != 0x30) {\n                    /* a long CHAR() field: see #37426 */\n                    type = byte0 | 0x30;\n                } else {\n                    switch (byte0) {\n                        case LogEvent.MYSQL_TYPE_SET:\n                        case LogEvent.MYSQL_TYPE_ENUM:\n                        case LogEvent.MYSQL_TYPE_STRING:\n                            type = byte0;\n                    }\n                }\n            }\n        }\n\n        return type;\n    }\n\n    public final String getDbName() {\n        return dbname;\n    }\n\n    public final String getTableName() {\n        return tblname;\n    }\n\n    public String getDbname() {\n        return dbname;\n    }\n\n    public void setDbname(String dbname) {\n        this.dbname = dbname;\n    }\n\n    public String getTblname() {\n        return tblname;\n    }\n\n    public void setTblname(String tblname) {\n        this.tblname = tblname;\n    }\n\n    public final int getColumnCnt() {\n        return columnCnt;\n    }\n\n    public final ColumnInfo[] getColumnInfo() {\n        return columnInfo;\n    }\n\n    public final long getTableId() {\n        return tableId;\n    }\n\n    public boolean isExistOptionalMetaData() {\n        return existOptionalMetaData;\n    }\n\n    public void setExistOptionalMetaData(boolean existOptional) {\n        this.existOptionalMetaData = existOptional;\n    }\n\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/TransactionContextLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\n\n/**\n * @author agapple 2018年5月7日 下午7:05:39\n * @version 1.0.26\n * @since mysql 5.7\n */\npublic class TransactionContextLogEvent extends LogEvent {\n\n    public TransactionContextLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\n        super(header);\n    }\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/TransactionPayloadLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\n\n/**\n * @author agapple 2022年5月23日 下午7:05:39\n * @version 1.1.7\n * @since mysql 8.0.20\n */\npublic class TransactionPayloadLogEvent extends LogEvent {\n\n    public static final short COMPRESSION_TYPE_MIN_LENGTH         = 1;\n    public static final short COMPRESSION_TYPE_MAX_LENGTH         = 9;\n    public static final short PAYLOAD_SIZE_MIN_LENGTH             = 0;\n    public static final short PAYLOAD_SIZE_MAX_LENGTH             = 9;\n    public static final short UNCOMPRESSED_SIZE_MIN_LENGTH        = 0;\n    public static final short UNCOMPRESSED_SIZE_MAX_LENGTH        = 9;\n    public static final int   MAX_DATA_LENGTH                     = COMPRESSION_TYPE_MAX_LENGTH\n                                                                    + PAYLOAD_SIZE_MAX_LENGTH\n                                                                    + UNCOMPRESSED_SIZE_MAX_LENGTH;\n\n    /** Marks the end of the payload header. */\n    public static final int   OTW_PAYLOAD_HEADER_END_MARK         = 0;\n\n    /** The payload field */\n    public static final int   OTW_PAYLOAD_SIZE_FIELD              = 1;\n\n    /** The compression type field */\n    public static final int   OTW_PAYLOAD_COMPRESSION_TYPE_FIELD  = 2;\n\n    /** The uncompressed size field */\n    public static final int   OTW_PAYLOAD_UNCOMPRESSED_SIZE_FIELD = 3;\n\n    /* ZSTD compression. */\n    public final static int   COMPRESS_TYPE_ZSTD                  = 0;\n    /* No compression. */\n    public final static int   COMPRESS_TYPE_NONE                  = 255;\n\n    private long              m_compression_type                  = COMPRESS_TYPE_NONE;\n    private long              m_payload_size;\n    private long              m_uncompressed_size;\n    private byte[]            m_payload;\n\n    public TransactionPayloadLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\n        super(header);\n\n        final int commonHeaderLen = descriptionEvent.getCommonHeaderLen();\n        final int postHeaderLen = descriptionEvent.getPostHeaderLen()[header.getType() - 1];\n\n        int offset = commonHeaderLen;\n        buffer.position(offset);\n        long type = 0, length = 0;\n        while (buffer.hasRemaining()) {\n            type = buffer.getPackedLong(); // type\n            if (type == OTW_PAYLOAD_HEADER_END_MARK) {\n                break;\n            }\n\n            length = buffer.getPackedLong(); // length\n            switch ((int) type) {\n                case OTW_PAYLOAD_SIZE_FIELD:\n                    m_payload_size = buffer.getPackedLong(); // value\n                    break;\n                case OTW_PAYLOAD_COMPRESSION_TYPE_FIELD:\n                    m_compression_type = buffer.getPackedLong(); // value\n                    break;\n                case OTW_PAYLOAD_UNCOMPRESSED_SIZE_FIELD:\n                    m_uncompressed_size = buffer.getPackedLong(); // value\n                    break;\n                default:\n                    buffer.forward((int) length);\n                    break;\n            }\n\n        }\n\n        if (m_uncompressed_size == 0) {\n            m_uncompressed_size = m_payload_size;\n        }\n        m_payload = buffer.getData((int) m_payload_size);\n    }\n\n    public boolean isCompressByZstd() {\n        return m_compression_type == COMPRESS_TYPE_ZSTD;\n    }\n\n    public boolean isCompressByNone() {\n        return m_compression_type == COMPRESS_TYPE_NONE;\n    }\n\n    public byte[] getPayload() {\n        return m_payload;\n    }\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/UnknownLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\r\n\r\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\r\n\r\n/**\r\n * Unknown_log_event\r\n * \r\n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\r\n * @version 1.0\r\n */\r\npublic final class UnknownLogEvent extends LogEvent {\r\n\r\n    public UnknownLogEvent(LogHeader header){\r\n        super(header);\r\n    }\r\n}\r\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/UpdateRowsLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\n\n/**\n * Log row updates with a before image. The event contain several update rows\n * for a table. Note that each event contains only rows for one table. Also note\n * that the row data consists of pairs of row data: one row for the old data and\n * one row for the new data.\n * \n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\n * @version 1.0\n */\npublic class UpdateRowsLogEvent extends RowsLogEvent {\n\n    public UpdateRowsLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\n        super(header, buffer, descriptionEvent, false , false);\n    }\n\n    public UpdateRowsLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent,\n                              boolean partial){\n        super(header, buffer, descriptionEvent, partial ,false);\n    }\n\n    public UpdateRowsLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent,\n                              boolean partial , boolean compress){\n        super(header, buffer, descriptionEvent, partial , compress);\n    }\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/UserVarLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport java.io.IOException;\nimport java.io.Serializable;\nimport java.nio.charset.Charset;\n\nimport com.taobao.tddl.dbsync.binlog.CharsetConversion;\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\n\n/**\n * User_var_log_event. Every time a query uses the value of a user variable, a\n * User_var_log_event is written before the Query_log_event, to set the user\n * variable.\n * \n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\n * @version 1.0\n */\npublic final class UserVarLogEvent extends LogEvent {\n\n    /**\n     * Fixed data part: Empty\n     * <p>\n     * Variable data part:\n     * <ul>\n     * <li>4 bytes. the size of the user variable name.</li>\n     * <li>The user variable name.</li>\n     * <li>1 byte. Non-zero if the variable value is the SQL NULL value, 0\n     * otherwise. If this byte is 0, the following parts exist in the event.</li>\n     * <li>1 byte. The user variable type. The value corresponds to elements of\n     * enum Item_result defined in include/mysql_com.h.</li>\n     * <li>4 bytes. The number of the character set for the user variable\n     * (needed for a string variable). The character set number is really a\n     * collation number that indicates a character set/collation pair.</li>\n     * <li>4 bytes. The size of the user variable value (corresponds to member\n     * val_len of class Item_string).</li>\n     * <li>Variable-sized. For a string variable, this is the string. For a\n     * float or integer variable, this is its value in 8 bytes.</li>\n     * </ul>\n     * Source : http://forge.mysql.com/wiki/MySQL_Internals_Binary_Log\n     */\n    private final String       name;\n    private final Serializable value;\n    private final int          type;\n    private final int          charsetNumber;\n    private final boolean      isNull;\n\n    /**\n     * The following is for user defined functions\n     * \n     * @see mysql-5.1.60//include/mysql_com.h\n     */\n    public static final int    STRING_RESULT          = 0;\n    public static final int    REAL_RESULT            = 1;\n    public static final int    INT_RESULT             = 2;\n    public static final int    ROW_RESULT             = 3;\n    public static final int    DECIMAL_RESULT         = 4;\n\n    /* User_var event data */\n    public static final int    UV_VAL_LEN_SIZE        = 4;\n    public static final int    UV_VAL_IS_NULL         = 1;\n    public static final int    UV_VAL_TYPE_SIZE       = 1;\n    public static final int    UV_NAME_LEN_SIZE       = 4;\n    public static final int    UV_CHARSET_NUMBER_SIZE = 4;\n\n    public UserVarLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent)\n                                                                                                          throws IOException{\n        super(header);\n\n        /* The Post-Header is empty. The Variable Data part begins immediately. */\n        buffer.position(descriptionEvent.commonHeaderLen + descriptionEvent.postHeaderLen[USER_VAR_EVENT - 1]);\n        final int nameLen = (int) buffer.getUint32();\n        name = buffer.getFixString(nameLen); // UV_NAME_LEN_SIZE\n        isNull = (0 != buffer.getInt8());\n\n        if (isNull) {\n            type = STRING_RESULT;\n            charsetNumber = 63; /* binary */\n            value = null;\n        } else {\n            type = buffer.getInt8(); // UV_VAL_IS_NULL\n            charsetNumber = (int) buffer.getUint32(); // buf + UV_VAL_TYPE_SIZE\n            final int valueLen = (int) buffer.getUint32(); // buf +\n                                                           // UV_CHARSET_NUMBER_SIZE\n            final int limit = buffer.limit(); /* for restore */\n            buffer.limit(buffer.position() + valueLen);\n\n            /* @see User_var_log_event::print */\n            switch (type) {\n                case REAL_RESULT:\n                    value = Double.valueOf(buffer.getDouble64()); // float8get\n                    break;\n                case INT_RESULT:\n                    if (valueLen == 8) value = Long.valueOf(buffer.getLong64()); // !uint8korr\n                    else if (valueLen == 4) value = Long.valueOf(buffer.getUint32());\n                    else throw new IOException(\"Error INT_RESULT length: \" + valueLen);\n                    break;\n                case DECIMAL_RESULT:\n                    final int precision = buffer.getInt8();\n                    final int scale = buffer.getInt8();\n                    value = buffer.getDecimal(precision, scale); // bin2decimal\n                    break;\n                case STRING_RESULT:\n                    Charset charset = CharsetConversion.getNioCharset(charsetNumber);\n                    value = buffer.getFixString(valueLen, charset);\n                    break;\n                case ROW_RESULT:\n                    // this seems to be banned in MySQL altogether\n                    throw new IOException(\"ROW_RESULT is unsupported\");\n                default:\n                    value = null;\n                    break;\n            }\n            buffer.limit(limit);\n        }\n    }\n\n    public final String getQuery() {\n        if (value == null) {\n            return \"SET @\" + name + \" := NULL\";\n        } else if (type == STRING_RESULT) {\n            // TODO: do escaping !?\n            return \"SET @\" + name + \" := \\'\" + value + '\\'';\n        } else {\n            return \"SET @\" + name + \" := \" + String.valueOf(value);\n        }\n    }\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/ViewChangeEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\n\n/**\n * @author agapple 2018年5月7日 下午7:05:39\n * @version 1.0.26\n * @since mysql 5.7\n */\npublic class ViewChangeEvent extends LogEvent {\n\n    public ViewChangeEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\n        super(header);\n    }\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/WriteRowsLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\n\n/**\n * Log row insertions and updates. The event contain several insert/update rows\n * for a table. Note that each event contains only rows for one table.\n * \n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\n * @version 1.0\n */\npublic class WriteRowsLogEvent extends RowsLogEvent {\n\n    public WriteRowsLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\n        super(header, buffer, descriptionEvent, false, false);\n    }\n\n    public WriteRowsLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent,\n                             boolean compress){\n        super(header, buffer, descriptionEvent, false, compress);\n    }\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/XaPrepareLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\n\n/**\n * @author agapple 2018年5月7日 下午7:05:39\n * @version 1.0.26\n * @since mysql 5.7\n */\npublic class XaPrepareLogEvent extends LogEvent {\n\n    private boolean onePhase;\n    private int     formatId;\n    private int     gtridLength;\n    private int     bqualLength;\n    private byte[]  data;\n\n    public XaPrepareLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\n        super(header);\n\n        final int commonHeaderLen = descriptionEvent.getCommonHeaderLen();\n        final int postHeaderLen = descriptionEvent.getPostHeaderLen()[header.getType() - 1];\n\n        int offset = commonHeaderLen + postHeaderLen;\n        buffer.position(offset);\n\n        onePhase = (buffer.getInt8() == 0x00 ? false : true);\n\n        formatId = buffer.getInt32();\n        gtridLength = buffer.getInt32();\n        bqualLength = buffer.getInt32();\n\n        int MY_XIDDATASIZE = 128;\n        if (MY_XIDDATASIZE >= gtridLength + bqualLength && gtridLength >= 0 && gtridLength <= 64 && bqualLength >= 0\n            && bqualLength <= 64) {\n            data = buffer.getData(gtridLength + bqualLength);\n        } else {\n            formatId = -1;\n            gtridLength = 0;\n            bqualLength = 0;\n        }\n    }\n\n    public boolean isOnePhase() {\n        return onePhase;\n    }\n\n    public int getFormatId() {\n        return formatId;\n    }\n\n    public int getGtridLength() {\n        return gtridLength;\n    }\n\n    public int getBqualLength() {\n        return bqualLength;\n    }\n\n    public byte[] getData() {\n        return data;\n    }\n\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/XidLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\n\n/**\n * Logs xid of the transaction-to-be-committed in the 2pc protocol. Has no\n * meaning in replication, slaves ignore it.\n * \n * @author <a href=\"mailto:changyuan.lh@taobao.com\">Changyuan.lh</a>\n * @version 1.0\n */\npublic final class XidLogEvent extends LogEvent {\n\n    private final long xid;\n\n    public XidLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\n        super(header);\n\n        /* The Post-Header is empty. The Variable Data part begins immediately. */\n        buffer.position(descriptionEvent.commonHeaderLen + descriptionEvent.postHeaderLen[XID_EVENT - 1]);\n        xid = buffer.getLong64(); // !uint8korr\n    }\n\n    public final long getXid() {\n        return xid;\n    }\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/mariadb/AnnotateRowsEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event.mariadb;\n\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.event.FormatDescriptionLogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.IgnorableLogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.LogHeader;\n\nimport java.nio.charset.StandardCharsets;\n\n/**\n * mariadb的ANNOTATE_ROWS_EVENT类型\n * \n * @author jianghang 2014-1-20 下午2:20:35\n * @since 1.0.17\n */\npublic class AnnotateRowsEvent extends IgnorableLogEvent {\n\n    private String rowsQuery;\n\n    public AnnotateRowsEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\n        super(header, buffer, descriptionEvent);\n\n        final int commonHeaderLen = descriptionEvent.getCommonHeaderLen();\n        final int postHeaderLen = descriptionEvent.getPostHeaderLen()[header.getType() - 1];\n\n        int offset = commonHeaderLen + postHeaderLen;\n        int len = buffer.limit() - offset;\n        rowsQuery = buffer.getFullString(offset, len, StandardCharsets.ISO_8859_1);\n    }\n\n    public String getRowsQuery() {\n        return rowsQuery;\n    }\n\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/mariadb/BinlogCheckPointLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event.mariadb;\n\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.event.FormatDescriptionLogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.IgnorableLogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.LogHeader;\n\n/**\n * mariadb10的BINLOG_CHECKPOINT_EVENT类型\n * \n * @author jianghang 2014-1-20 下午2:22:04\n * @since 1.0.17\n */\npublic class BinlogCheckPointLogEvent extends IgnorableLogEvent {\n\n    private final String filename;\n\n    public BinlogCheckPointLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\n        super(header, buffer, descriptionEvent);\n        // mariadb binlog checkpoint\n        final int headerSize = descriptionEvent.getCommonHeaderLen();\n        final int postHeaderLen = descriptionEvent.getPostHeaderLen()[getHeader().getType() - 1];\n\n        buffer.position(headerSize);\n        long binlogFileLen = buffer.getUint32();\n        filename = buffer.getFixString((int) binlogFileLen);\n    }\n\n    public String getFilename() {\n        return filename;\n    }\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/mariadb/DeleteRowsCompressLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event.mariadb;\r\rimport com.taobao.tddl.dbsync.binlog.LogBuffer;\rimport com.taobao.tddl.dbsync.binlog.event.DeleteRowsLogEvent;\rimport com.taobao.tddl.dbsync.binlog.event.FormatDescriptionLogEvent;\rimport com.taobao.tddl.dbsync.binlog.event.LogHeader;\r\r/**\r * mariadb compress rows event\r * \r * @author jianghang\r * @since 1.1.7\r */\rpublic class DeleteRowsCompressLogEvent extends DeleteRowsLogEvent {\r\r    public DeleteRowsCompressLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\r        super(header, buffer, descriptionEvent, true);\r    }\r}\r"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/mariadb/MariaGtidListLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event.mariadb;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.MariaGTIDSet;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.MariaGtid;\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.FormatDescriptionLogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.IgnorableLogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.LogHeader;\n\n/**\n * mariadb的GTID_LIST_EVENT类型\n * \n * @author jianghang 2014-1-20 下午4:51:50\n * @since 1.0.17\n */\npublic class MariaGtidListLogEvent extends LogEvent {\n\n    private MariaGTIDSet mariaGTIDSet;\n    /**\n     * <pre>\n     * mariadb gtidListLog event format\n     *  uint<4> Number of GTIDs\n     *  GTID[0]\n     *      uint<4> Replication Domain ID\n     *      uint<4> Server_ID\n     *      uint<8> GTID sequence ...\n     * GTID[n]\n     * </pre>\n     * @param header\n     * @param buffer\n     * @param descriptionEvent\n     */\n    public MariaGtidListLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\n        super(header);\n        long gtidLenth = buffer.getUint32();\n        mariaGTIDSet = new MariaGTIDSet();\n        for (int i = 0; i < gtidLenth; i++) {\n            long domainId = buffer.getUint32();\n            long serverId = buffer.getUint32();\n            long sequence = buffer.getUlong64().longValue();\n            mariaGTIDSet.add(new MariaGtid(domainId, serverId, sequence));\n        }\n    }\n\n    public String getGtidStr() {\n        return mariaGTIDSet.toString();\n    }\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/mariadb/MariaGtidLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event.mariadb;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.MariaGtid;\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.FormatDescriptionLogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.IgnorableLogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.LogHeader;\n\n/**\n * mariadb的GTID_EVENT类型\n * \n * @author jianghang 2014-1-20 下午4:49:10\n * @since 1.0.17\n */\npublic class MariaGtidLogEvent extends LogEvent {\n\n    private MariaGtid mariaGtid;\n\n    /**\n     * <pre>\n     * mariadb gtidlog event format\n     *     uint<8> GTID sequence\n     *     uint<4> Replication Domain ID\n     *     uint<1> Flags\n     * \n     * \tif flag & FL_GROUP_COMMIT_ID\n     * \t    uint<8> commit_id\n     * \telse\n     * \t    uint<6> 0\n     * </pre>\n     */\n\n    public MariaGtidLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\n        super(header);\n        long sequence = buffer.getUlong64().longValue();\n        long domainId = buffer.getUint32();\n        long serverId = header.getServerId();\n        mariaGtid = new MariaGtid(domainId, serverId, sequence);\n    }\n\n    public String getGtidStr() {\n        return mariaGtid.toString();\n    }\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/mariadb/QueryCompressedLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event.mariadb;\r\rimport java.io.IOException;\r\rimport com.taobao.tddl.dbsync.binlog.LogBuffer;\rimport com.taobao.tddl.dbsync.binlog.event.FormatDescriptionLogEvent;\rimport com.taobao.tddl.dbsync.binlog.event.LogHeader;\rimport com.taobao.tddl.dbsync.binlog.event.QueryLogEvent;\r\r/**\r * mariadb compress query event\r * \r * @author jianghang\r * @since 1.1.7\r */\rpublic class QueryCompressedLogEvent extends QueryLogEvent {\r\r    public QueryCompressedLogEvent(LogHeader header, LogBuffer buffer,\r                                   FormatDescriptionLogEvent descriptionEvent) throws IOException{\r        super(header, buffer, descriptionEvent,false, true);\r    }\r}\r"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/mariadb/StartEncryptionLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event.mariadb;\n\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.FormatDescriptionLogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.LogHeader;\n\n/**\n * mariadb的Start_encryption_log_event\n * \n * @author agapple 2018年5月7日 下午7:23:02\n * @version 1.0.26\n */\npublic class StartEncryptionLogEvent extends LogEvent {\n\n    public StartEncryptionLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\n        super(header);\n    }\n}\n"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/mariadb/UpdateRowsCompressLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event.mariadb;\r\rimport com.taobao.tddl.dbsync.binlog.LogBuffer;\rimport com.taobao.tddl.dbsync.binlog.event.FormatDescriptionLogEvent;\rimport com.taobao.tddl.dbsync.binlog.event.LogHeader;\rimport com.taobao.tddl.dbsync.binlog.event.UpdateRowsLogEvent;\r\r/**\r * mariadb compress rows event\r * \r * @author jianghang\r * @since 1.1.7\r */\rpublic class UpdateRowsCompressLogEvent extends UpdateRowsLogEvent {\r\r    public UpdateRowsCompressLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\r        super(header, buffer, descriptionEvent, false, true);\r    }\r}\r"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/mariadb/WriteRowsCompressLogEvent.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event.mariadb;\r\rimport com.taobao.tddl.dbsync.binlog.LogBuffer;\rimport com.taobao.tddl.dbsync.binlog.event.FormatDescriptionLogEvent;\rimport com.taobao.tddl.dbsync.binlog.event.LogHeader;\rimport com.taobao.tddl.dbsync.binlog.event.WriteRowsLogEvent;\r\r/**\r * mariadb compress rows event\r * \r * @author jianghang\r * @since 1.1.7\r */\rpublic class WriteRowsCompressLogEvent extends WriteRowsLogEvent {\r\r    public WriteRowsCompressLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent){\r        super(header, buffer, descriptionEvent,  true);\r    }\r}\r"
  },
  {
    "path": "dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/exception/TableIdNotFoundException.java",
    "content": "package com.taobao.tddl.dbsync.binlog.exception;\n\nimport com.alibaba.otter.canal.common.CanalException;\n\npublic class TableIdNotFoundException extends CanalException {\n\n    private static final long serialVersionUID = -7288830284122672209L;\n\n    public TableIdNotFoundException(String errorCode){\n        super(errorCode);\n    }\n\n    public TableIdNotFoundException(String errorCode, Throwable cause){\n        super(errorCode, cause);\n    }\n\n    public TableIdNotFoundException(String errorCode, String errorDesc){\n        super(errorCode + \":\" + errorDesc);\n    }\n\n    public TableIdNotFoundException(String errorCode, String errorDesc, Throwable cause){\n        super(errorCode + \":\" + errorDesc, cause);\n    }\n\n    public TableIdNotFoundException(Throwable cause){\n        super(cause);\n    }\n\n}\n"
  },
  {
    "path": "dbsync/src/test/java/com/taobao/tddl/dbsync/FetcherPerformanceTest.java",
    "content": "package com.taobao.tddl.dbsync;\n\nimport java.sql.Connection;\nimport java.sql.DriverManager;\nimport java.sql.Statement;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport com.taobao.tddl.dbsync.binlog.DirectLogFetcher;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\n\npublic class FetcherPerformanceTest {\n\n    public static void main(String args[]) {\n        try (DirectLogFetcher fetcher = new DirectLogFetcher()) {\n            Class.forName(\"com.mysql.jdbc.Driver\");\n            Connection connection = DriverManager.getConnection(\"jdbc:mysql://127.0.0.1:3306\", \"root\", \"hello\");\n            Statement statement = connection.createStatement();\n            statement.execute(\"SET @master_binlog_checksum='@@global.binlog_checksum'\");\n            statement.execute(\"SET @mariadb_slave_capability='\" + LogEvent.MARIA_SLAVE_CAPABILITY_MINE + \"'\");\n\n            fetcher.open(connection, \"mysql-bin.000006\", 120L, 2);\n\n            AtomicLong sum = new AtomicLong(0);\n            long start = System.currentTimeMillis();\n            long last = 0;\n            long end = 0;\n\n            while (fetcher.fetch()) {\n                sum.incrementAndGet();\n                long current = sum.get();\n                if (current - last >= 100000) {\n                    end = System.currentTimeMillis();\n                    long tps = ((current - last) * 1000) / (end - start);\n                    System.out.println(\" total : \" + sum + \" , cost : \" + (end - start) + \" , tps : \" + tps);\n                    last = current;\n                    start = end;\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "dbsync/src/test/java/com/taobao/tddl/dbsync/binlog/BaseLogFetcherTest.java",
    "content": "package com.taobao.tddl.dbsync.binlog;\n\nimport java.io.Serializable;\nimport java.io.UnsupportedEncodingException;\nimport java.nio.charset.Charset;\nimport java.util.BitSet;\n\nimport com.taobao.tddl.dbsync.binlog.event.QueryLogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.RowsLogBuffer;\nimport com.taobao.tddl.dbsync.binlog.event.RowsLogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.RowsQueryLogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.TableMapLogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.TableMapLogEvent.ColumnInfo;\nimport com.taobao.tddl.dbsync.binlog.event.XidLogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.mariadb.AnnotateRowsEvent;\n\npublic class BaseLogFetcherTest {\n\n    protected String  binlogFileName = \"mysql-bin.000001\";\n    protected Charset charset        = Charset.forName(\"utf-8\");\n\n    protected void parseQueryEvent(QueryLogEvent event) {\n        System.out.println(String.format(\"================> binlog[%s:%s] , name[%s]\",\n            binlogFileName,\n            event.getHeader().getLogPos() - event.getHeader().getEventLen(),\n            event.getCatalog()));\n        System.out.println(\"sql : \" + event.getQuery());\n    }\n\n    protected void parseRowsQueryEvent(RowsQueryLogEvent event) throws Exception {\n        System.out.println(String.format(\"================> binlog[%s:%s]\", binlogFileName, event.getHeader()\n            .getLogPos() - event.getHeader().getEventLen()));\n        System.out.println(\"sql : \" + new String(event.getRowsQuery().getBytes(\"ISO-8859-1\"), charset.name()));\n    }\n\n    protected void parseAnnotateRowsEvent(AnnotateRowsEvent event) throws Exception {\n        System.out.println(String.format(\"================> binlog[%s:%s]\", binlogFileName, event.getHeader()\n            .getLogPos() - event.getHeader().getEventLen()));\n        System.out.println(\"sql : \" + new String(event.getRowsQuery().getBytes(\"ISO-8859-1\"), charset.name()));\n    }\n\n    protected void parseXidEvent(XidLogEvent event) throws Exception {\n        System.out.println(String.format(\"================> binlog[%s:%s]\", binlogFileName, event.getHeader()\n            .getLogPos() - event.getHeader().getEventLen()));\n        System.out.println(\"xid : \" + event.getXid());\n    }\n\n    protected void parseRowsEvent(RowsLogEvent event) {\n        try {\n            System.out.println(String.format(\"================> binlog[%s:%s] , name[%s,%s]\",\n                binlogFileName,\n                event.getHeader().getLogPos() - event.getHeader().getEventLen(),\n                event.getTable().getDbName(),\n                event.getTable().getTableName()));\n            RowsLogBuffer buffer = event.getRowsBuf(charset);\n            BitSet columns = event.getColumns();\n            BitSet changeColumns = event.getChangeColumns();\n            while (buffer.nextOneRow(columns)) {\n                // 处理row记录\n                int type = event.getHeader().getType();\n                if (LogEvent.WRITE_ROWS_EVENT_V1 == type || LogEvent.WRITE_ROWS_EVENT == type) {\n                    // insert的记录放在before字段中\n                    parseOneRow(event, buffer, columns, true);\n                } else if (LogEvent.DELETE_ROWS_EVENT_V1 == type || LogEvent.DELETE_ROWS_EVENT == type) {\n                    // delete的记录放在before字段中\n                    parseOneRow(event, buffer, columns, false);\n                } else {\n                    // update需要处理before/after\n                    System.out.println(\"-------> before\");\n                    parseOneRow(event, buffer, columns, false);\n                    if (!buffer.nextOneRow(changeColumns, true)) {\n                        break;\n                    }\n                    System.out.println(\"-------> after\");\n                    parseOneRow(event, buffer, changeColumns, true);\n                }\n\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(\"parse row data failed.\", e);\n        }\n    }\n\n    protected void parseOneRow(RowsLogEvent event, RowsLogBuffer buffer, BitSet cols, boolean isAfter)\n                                                                                                      throws UnsupportedEncodingException {\n        TableMapLogEvent map = event.getTable();\n        if (map == null) {\n            throw new RuntimeException(\"not found TableMap with tid=\" + event.getTableId());\n        }\n\n        final int columnCnt = map.getColumnCnt();\n        final ColumnInfo[] columnInfo = map.getColumnInfo();\n\n        for (int i = 0; i < columnCnt; i++) {\n            if (!cols.get(i)) {\n                continue;\n            }\n\n            ColumnInfo info = columnInfo[i];\n            buffer.nextValue(null , i ,info.type, info.meta);\n\n            if (buffer.isNull()) {\n                //\n            } else {\n                final Serializable value = buffer.getValue();\n                if (value instanceof byte[]) {\n                    System.out.println(new String((byte[]) value));\n                } else {\n                    System.out.println(value);\n                }\n            }\n        }\n\n    }\n}\n"
  },
  {
    "path": "dbsync/src/test/java/com/taobao/tddl/dbsync/binlog/DirectLogFetcherTest.java",
    "content": "package com.taobao.tddl.dbsync.binlog;\n\nimport java.io.IOException;\nimport java.sql.Connection;\nimport java.sql.DriverManager;\nimport java.sql.Statement;\nimport java.util.List;\n\nimport com.taobao.tddl.dbsync.binlog.event.mariadb.BinlogCheckPointLogEvent;\nimport org.junit.Assert;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.taobao.tddl.dbsync.binlog.event.*;\nimport com.taobao.tddl.dbsync.binlog.event.mariadb.AnnotateRowsEvent;\n\n@Ignore\npublic class DirectLogFetcherTest extends BaseLogFetcherTest {\n\n    @Test\n    public void testSimple() {\n        DirectLogFetcher fecther = new DirectLogFetcher();\n        try {\n            Class.forName(\"com.mysql.jdbc.Driver\");\n            Connection connection = DriverManager.getConnection(\"jdbc:mysql://127.0.0.1:3306\", \"root\", \"123456\");\n            Statement statement = connection.createStatement();\n            statement.execute(\"SET @master_binlog_checksum='@@global.binlog_checksum'\");\n            statement.execute(\"SET @mariadb_slave_capability='\" + LogEvent.MARIA_SLAVE_CAPABILITY_MINE + \"'\");\n\n            fecther.open(connection, \"mysql-bin.000002\", 4L, 1);\n\n            LogDecoder decoder = new LogDecoder(LogEvent.UNKNOWN_EVENT, LogEvent.ENUM_END_EVENT);\n            LogContext context = new LogContext();\n            while (fecther.fetch()) {\n                LogEvent event = decoder.decode(fecther, context);\n                processEvent(event, decoder, context);\n            }\n        } catch (Throwable e) {\n            e.printStackTrace();\n            Assert.fail(e.getMessage());\n        } finally {\n            try {\n                fecther.close();\n            } catch (IOException e) {\n                Assert.fail(e.getMessage());\n            }\n        }\n\n    }\n\n    public void processEvent(LogEvent event, LogDecoder decoder, LogContext context) throws Throwable {\n        int eventType = event.getHeader().getType();\n        switch (eventType) {\n            case LogEvent.ROTATE_EVENT:\n                binlogFileName = ((RotateLogEvent) event).getFilename();\n                break;\n            case LogEvent.BINLOG_CHECKPOINT_EVENT:\n                binlogFileName = ((BinlogCheckPointLogEvent) event).getFilename();\n                break;\n            case LogEvent.WRITE_ROWS_EVENT_V1:\n            case LogEvent.WRITE_ROWS_EVENT:\n                parseRowsEvent((WriteRowsLogEvent) event);\n                break;\n            case LogEvent.UPDATE_ROWS_EVENT_V1:\n            case LogEvent.PARTIAL_UPDATE_ROWS_EVENT:\n            case LogEvent.UPDATE_ROWS_EVENT:\n                parseRowsEvent((UpdateRowsLogEvent) event);\n                break;\n            case LogEvent.DELETE_ROWS_EVENT_V1:\n            case LogEvent.DELETE_ROWS_EVENT:\n                parseRowsEvent((DeleteRowsLogEvent) event);\n                break;\n            case LogEvent.QUERY_EVENT:\n                parseQueryEvent((QueryLogEvent) event);\n                break;\n            case LogEvent.ROWS_QUERY_LOG_EVENT:\n                parseRowsQueryEvent((RowsQueryLogEvent) event);\n                break;\n            case LogEvent.ANNOTATE_ROWS_EVENT:\n                parseAnnotateRowsEvent((AnnotateRowsEvent) event);\n                break;\n            case LogEvent.XID_EVENT:\n                parseXidEvent((XidLogEvent) event);\n                break;\n            case LogEvent.TRANSACTION_PAYLOAD_EVENT:\n                List<LogEvent> events = decoder.processIterateDecode(event, context);\n                for (LogEvent deEvent : events) {\n                    processEvent(deEvent, decoder, context);\n                }\n                break;\n            default:\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "dbsync/src/test/java/com/taobao/tddl/dbsync/binlog/FileLogFetcherTest.java",
    "content": "package com.taobao.tddl.dbsync.binlog;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.URL;\nimport java.util.List;\n\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.taobao.tddl.dbsync.binlog.event.DeleteRowsLogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.QueryLogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.RotateLogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.RowsQueryLogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.UpdateRowsLogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.WriteRowsLogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.XidLogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.mariadb.AnnotateRowsEvent;\n@Ignore\npublic class FileLogFetcherTest extends BaseLogFetcherTest {\n\n    private String directory;\n\n    @Before\n    public void setUp() {\n        URL url = Thread.currentThread().getContextClassLoader().getResource(\"dummy.txt\");\n        File dummyFile = new File(url.getFile());\n        directory = new File(dummyFile.getParent() + \"/binlog\").getPath();\n    }\n\n    @Test\n    public void testSimple() {\n        FileLogFetcher fetcher = new FileLogFetcher(1024 * 16);\n        try {\n            LogDecoder decoder = new LogDecoder(LogEvent.UNKNOWN_EVENT, LogEvent.ENUM_END_EVENT);\n            LogContext context = new LogContext();\n\n            File current = new File(directory, \"mysql-bin.000001\");\n            fetcher.open(current, 2051L);\n            context.setLogPosition(new LogPosition(current.getName()));\n\n            while (fetcher.fetch()) {\n                LogEvent event = null;\n                event = decoder.decode(fetcher, context);\n                processEvent(event, decoder, context);\n            }\n        } catch (Throwable e) {\n            Assert.fail(e.getMessage());\n        } finally {\n            try {\n                fetcher.close();\n            } catch (IOException e) {\n                Assert.fail(e.getMessage());\n            }\n        }\n    }\n\n    public void processEvent(LogEvent event, LogDecoder decoder, LogContext context) throws Throwable {\n        int eventType = event.getHeader().getType();\n        switch (eventType) {\n            case LogEvent.ROTATE_EVENT:\n                binlogFileName = ((RotateLogEvent) event).getFilename();\n                break;\n            case LogEvent.WRITE_ROWS_EVENT_V1:\n            case LogEvent.WRITE_ROWS_EVENT:\n                parseRowsEvent((WriteRowsLogEvent) event);\n                break;\n            case LogEvent.UPDATE_ROWS_EVENT_V1:\n            case LogEvent.PARTIAL_UPDATE_ROWS_EVENT:\n            case LogEvent.UPDATE_ROWS_EVENT:\n                parseRowsEvent((UpdateRowsLogEvent) event);\n                break;\n            case LogEvent.DELETE_ROWS_EVENT_V1:\n            case LogEvent.DELETE_ROWS_EVENT:\n                parseRowsEvent((DeleteRowsLogEvent) event);\n                break;\n            case LogEvent.QUERY_EVENT:\n                parseQueryEvent((QueryLogEvent) event);\n                break;\n            case LogEvent.ROWS_QUERY_LOG_EVENT:\n                parseRowsQueryEvent((RowsQueryLogEvent) event);\n                break;\n            case LogEvent.ANNOTATE_ROWS_EVENT:\n                parseAnnotateRowsEvent((AnnotateRowsEvent) event);\n                break;\n            case LogEvent.XID_EVENT:\n                parseXidEvent((XidLogEvent) event);\n                break;\n            case LogEvent.TRANSACTION_PAYLOAD_EVENT:\n                List<LogEvent> events = decoder.processIterateDecode(event, context);\n                for (LogEvent deEvent : events) {\n                    processEvent(deEvent, decoder, context);\n                }\n                break;\n            default:\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "dbsync/src/test/java/com/taobao/tddl/dbsync/binlog/JsonConversion_Json_ValueTest.java",
    "content": "package com.taobao.tddl.dbsync.binlog;\n\nimport java.nio.charset.Charset;\n\nimport org.junit.Assert;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.junit.rules.ExpectedException;\nimport org.junit.rules.Timeout;\n\nimport com.taobao.tddl.dbsync.binlog.JsonConversion.Json_Value;\nimport com.taobao.tddl.dbsync.binlog.JsonConversion.Json_enum_type;\n\npublic class JsonConversion_Json_ValueTest {\n\n    @Rule\n    public final ExpectedException thrown        = ExpectedException.none();\n\n    @SuppressWarnings(\"deprecation\")\n    @Rule\n    public final Timeout           globalTimeout = new Timeout(10000);\n\n    /* testedClasses: JsonConversion_Json_Value */\n    // Test written by Diffblue Cover.\n\n    @Test\n    public void constructorInputNullNotNullOutputVoid() {\n\n        // Arrange\n        final Json_enum_type t = null;\n        final String value = \",\";\n\n        // Act, creating object to test constructor\n        final Json_Value objectUnderTest = new Json_Value(t, value);\n\n        // Assert side effects\n        Assert.assertEquals(\",\", objectUnderTest.m_string_value);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void parse_valueInputZeroNotNullPositiveNotNullOutputIllegalArgumentException() {\n\n        // Arrange\n        final int type = 0;\n        final LogBuffer buffer = new LogBuffer();\n        final long len = 4_294_967_297L;\n        final String charsetName = \"3\";\n\n        // Act\n        thrown.expect(IllegalArgumentException.class);\n        JsonConversion.parse_value(type, buffer, len, charsetName);\n        // Method is not expected to return due to exception thrown\n    }\n\n    // test for 5127\n    @Test\n    public void testJsonKeyContainsSpecialCharacter() {\n\n        // {\"internal_uri_rewrite\": {\"(.*)(/[^/]+\\\\.(mp|MP)4)$\": \"$1/mp4$2\"}}\n        String jsonData = \"{\\\"internal_uri_rewrite\\\": {\\\"(.*)(/[^/]+\\\\\\\\.(mp|MP)4)$\\\": \\\"$1/mp4$2\\\"}}\";\n        byte[] data = new byte[] { 1, 0, 74, 0, 11, 0, 20, 0, 0, 31, 0, 105, 110, 116, 101, 114, 110, 97, 108, 95, 117,\n                                   114, 105, 95, 114, 101, 119, 114, 105, 116, 101, 1, 0, 43, 0, 11, 0, 23, 0, 12, 34,\n                                   0, 40, 46, 42, 41, 40, 47, 91, 94, 47, 93, 43, 92, 46, 40, 109, 112, 124, 77, 80, 41,\n                                   52, 41, 36, 8, 36, 49, 47, 109, 112, 52, 36, 50 };\n        final LogBuffer buffer = new LogBuffer(data, 0, 74);\n\n        Charset charset = Charset.forName(\"UTF-8\");\n        Json_Value jsonValue = JsonConversion.parse_value(0, buffer, 74, charset);\n        StringBuilder builder = new StringBuilder();\n        jsonValue.toJsonString(builder, charset);\n\n        Assert.assertEquals(builder.toString(), jsonData);\n\n        Assert.assertEquals(jsonValue.key(0, charset), \"internal_uri_rewrite\");\n\n        Json_Value element = jsonValue.element(0, charset);\n        Assert.assertEquals(element.key(0, charset), \"(.*)(/[^/]+\\\\.(mp|MP)4)$\");\n    }\n}\n"
  },
  {
    "path": "dbsync/src/test/java/com/taobao/tddl/dbsync/binlog/JsonDiffConversionTest.java",
    "content": "package com.taobao.tddl.dbsync.binlog;\n\nimport java.lang.reflect.InvocationTargetException;\n\nimport org.junit.Assert;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.junit.rules.ExpectedException;\nimport org.junit.rules.Timeout;\n\npublic class JsonDiffConversionTest {\n\n    @Rule\n    public final ExpectedException thrown        = ExpectedException.none();\n\n    @SuppressWarnings(\"deprecation\")\n    @Rule\n    public final Timeout           globalTimeout = new Timeout(10000);\n\n    /* testedClasses: JsonDiffConversion */\n    // Test written by Diffblue Cover.\n    @Test\n    public void print_json_diffInputNotNullPositiveNotNullZeroNotNullOutputIllegalArgumentException()\n                                                                                                     throws InvocationTargetException {\n\n        // Arrange\n        final LogBuffer buffer = new LogBuffer();\n        buffer.position = 28;\n        buffer.semival = 0;\n        final byte[] myByteArray = { (byte) 3, (byte) 3, (byte) 67, (byte) 67, (byte) 67, (byte) 67, (byte) 67,\n                (byte) 66, (byte) 67, (byte) 66, (byte) 67, (byte) 66, (byte) 67, (byte) 67, (byte) 67, (byte) 66,\n                (byte) 67, (byte) 66, (byte) 67, (byte) 66, (byte) 67, (byte) 67, (byte) 67, (byte) 66, (byte) 67,\n                (byte) 67, (byte) 67, (byte) 66, (byte) 2, (byte) 66 };\n        buffer.buffer = myByteArray;\n        buffer.limit = -1_000_000_065;\n        buffer.origin = 1_000_000_096;\n        final long len = 71L;\n        final String columnName = \"foo\";\n        final int columnIndex = 0;\n        final String charsetName = \"gbk\";\n        try {\n\n            // Act\n            thrown.expect(IllegalArgumentException.class);\n            JsonDiffConversion.print_json_diff(buffer, len, columnName, columnIndex, charsetName);\n        } catch (IllegalArgumentException ex) {\n\n            // Assert side effects\n            Assert.assertNotNull(buffer);\n            Assert.assertEquals(30, buffer.position);\n            Assert.assertEquals(0, buffer.semival);\n            Assert.assertArrayEquals(new byte[] { (byte) 3, (byte) 3, (byte) 67, (byte) 67, (byte) 67, (byte) 67,\n                    (byte) 67, (byte) 66, (byte) 67, (byte) 66, (byte) 67, (byte) 66, (byte) 67, (byte) 67, (byte) 67,\n                    (byte) 66, (byte) 67, (byte) 66, (byte) 67, (byte) 66, (byte) 67, (byte) 67, (byte) 67, (byte) 66,\n                    (byte) 67, (byte) 67, (byte) 67, (byte) 66, (byte) 2, (byte) 66 }, buffer.buffer);\n            Assert.assertEquals(-1_000_000_065, buffer.limit);\n            Assert.assertEquals(1_000_000_096, buffer.origin);\n            throw ex;\n        }\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void print_json_diffInputNotNullZeroNotNullZeroNotNullOutputIllegalArgumentException()\n                                                                                                 throws InvocationTargetException {\n\n        // Arrange\n        final LogBuffer buffer = new LogBuffer();\n        buffer.position = 28;\n        buffer.semival = 0;\n        final byte[] myByteArray = { (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2,\n                (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2,\n                (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2,\n                (byte) 3, (byte) 2 };\n        buffer.buffer = myByteArray;\n        buffer.limit = 31;\n        buffer.origin = 0;\n        final long len = 0L;\n        final String columnName = \"foo\";\n        final int columnIndex = 0;\n        final String charsetName = \"gbk\";\n        try {\n\n            // Act\n            thrown.expect(IllegalArgumentException.class);\n            JsonDiffConversion.print_json_diff(buffer, len, columnName, columnIndex, charsetName);\n        } catch (IllegalArgumentException ex) {\n\n            // Assert side effects\n            Assert.assertNotNull(buffer);\n            Assert.assertEquals(29, buffer.position);\n            Assert.assertEquals(0, buffer.semival);\n            Assert.assertArrayEquals(new byte[] { (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2,\n                    (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2,\n                    (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2, (byte) 2,\n                    (byte) 2, (byte) 3, (byte) 2 }, buffer.buffer);\n            Assert.assertEquals(31, buffer.limit);\n            Assert.assertEquals(0, buffer.origin);\n            throw ex;\n        }\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void print_json_diffInputNotNullZeroNotNullZeroNotNullOutputIllegalArgumentException2()\n                                                                                                  throws InvocationTargetException {\n\n        // Arrange\n        final LogBuffer buffer = new LogBuffer();\n        buffer.position = 15;\n        buffer.semival = 0;\n        final byte[] myByteArray = { (byte) 1, (byte) 1, (byte) 0, (byte) 0, (byte) 1, (byte) 1, (byte) 1, (byte) 1,\n                (byte) 1, (byte) 1, (byte) 0, (byte) 1, (byte) 1, (byte) 1, (byte) 1, (byte) 0, (byte) 1, (byte) 1,\n                (byte) 0, (byte) 0, (byte) 1, (byte) 1, (byte) 1, (byte) 1, (byte) 1, (byte) 1, (byte) 1, (byte) 0,\n                (byte) 1, (byte) 1 };\n        buffer.buffer = myByteArray;\n        buffer.limit = -1_215_751_986;\n        buffer.origin = 1_215_752_002;\n        final long len = 0L;\n        final String columnName = \"foo\";\n        final int columnIndex = 0;\n        final String charsetName = \"gbk\";\n        try {\n\n            // Act\n            thrown.expect(IllegalArgumentException.class);\n            JsonDiffConversion.print_json_diff(buffer, len, columnName, columnIndex, charsetName);\n        } catch (IllegalArgumentException ex) {\n\n            // Assert side effects\n            Assert.assertNotNull(buffer);\n            Assert.assertEquals(16, buffer.position);\n            Assert.assertEquals(0, buffer.semival);\n            Assert.assertArrayEquals(new byte[] { (byte) 1, (byte) 1, (byte) 0, (byte) 0, (byte) 1, (byte) 1, (byte) 1,\n                    (byte) 1, (byte) 1, (byte) 1, (byte) 0, (byte) 1, (byte) 1, (byte) 1, (byte) 1, (byte) 0, (byte) 1,\n                    (byte) 1, (byte) 0, (byte) 0, (byte) 1, (byte) 1, (byte) 1, (byte) 1, (byte) 1, (byte) 1, (byte) 1,\n                    (byte) 0, (byte) 1, (byte) 1 }, buffer.buffer);\n            Assert.assertEquals(-1_215_751_986, buffer.limit);\n            Assert.assertEquals(1_215_752_002, buffer.origin);\n            throw ex;\n        }\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void print_json_diffInputNotNullZeroNotNullZeroNotNullOutputIllegalArgumentException3()\n                                                                                                  throws InvocationTargetException {\n\n        // Arrange\n        final LogBuffer buffer = new LogBuffer();\n        buffer.position = 27;\n        buffer.semival = 0;\n        final byte[] myByteArray = { (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0,\n                (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0,\n                (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0,\n                (byte) 1, (byte) 0 };\n        buffer.buffer = myByteArray;\n        buffer.limit = 31;\n        buffer.origin = -1;\n        final long len = 0L;\n        final String columnName = \"foo\";\n        final int columnIndex = 0;\n        final String charsetName = \"gbk\";\n        try {\n\n            // Act\n            thrown.expect(IllegalArgumentException.class);\n            JsonDiffConversion.print_json_diff(buffer, len, columnName, columnIndex, charsetName);\n        } catch (IllegalArgumentException ex) {\n\n            // Assert side effects\n            Assert.assertNotNull(buffer);\n            Assert.assertEquals(29, buffer.position);\n            Assert.assertEquals(0, buffer.semival);\n            Assert.assertArrayEquals(new byte[] { (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0,\n                    (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0,\n                    (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0,\n                    (byte) 0, (byte) 1, (byte) 0 }, buffer.buffer);\n            Assert.assertEquals(31, buffer.limit);\n            Assert.assertEquals(-1, buffer.origin);\n            throw ex;\n        }\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void print_json_diffInputNotNullZeroNotNullZeroNotNullOutputNotNull() {\n\n        // Arrange\n        final LogBuffer buffer = new LogBuffer();\n        final long len = 0L;\n        final String columnName = \",\";\n        final int columnIndex = 0;\n        final String charsetName = \"gbk\";\n\n        // Act\n        final StringBuilder actual = JsonDiffConversion.print_json_diff(buffer,\n            len,\n            columnName,\n            columnIndex,\n            charsetName);\n\n        // Assert result\n        Assert.assertNotNull(actual);\n        Assert.assertEquals(\",\", actual.toString());\n    }\n}\n"
  },
  {
    "path": "dbsync/src/test/java/com/taobao/tddl/dbsync/binlog/LogEventTest.java",
    "content": "package com.taobao.tddl.dbsync.binlog;\n\nimport org.junit.Assert;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.junit.rules.ExpectedException;\nimport org.junit.rules.Timeout;\n\npublic class LogEventTest {\n\n    @Rule\n    public final ExpectedException thrown        = ExpectedException.none();\n\n    @SuppressWarnings(\"deprecation\")\n    @Rule\n    public final Timeout           globalTimeout = new Timeout(10000);\n\n    /* testedClasses: LogEvent */\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull() {\n\n        // Arrange\n        final int type = 8;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Create_file\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull2() {\n\n        // Arrange\n        final int type = 12;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"New_load\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull3() {\n\n        // Arrange\n        final int type = 39;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Update_rows_partial\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull4() {\n\n        // Arrange\n        final int type = 80;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertTrue(actual.startsWith(\"Unknown\"));\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull5() {\n\n        // Arrange\n        final int type = 7;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Slave\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull6() {\n\n        // Arrange\n        final int type = 6;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Load\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull7() {\n\n        // Arrange\n        final int type = 10;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Exec_load\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull8() {\n\n        // Arrange\n        final int type = 5;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Intvar\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull9() {\n\n        // Arrange\n        final int type = 11;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Delete_file\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull10() {\n\n        // Arrange\n        final int type = 4;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Rotate\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull11() {\n\n        // Arrange\n        final int type = 13;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"RAND\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull12() {\n\n        // Arrange\n        final int type = 34;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Anonymous_Gtid\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull13() {\n\n        // Arrange\n        final int type = 15;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Format_desc\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull14() {\n\n        // Arrange\n        final int type = 32;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Delete_rows\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull15() {\n\n        // Arrange\n        final int type = 16;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Xid\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull16() {\n\n        // Arrange\n        final int type = 30;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Write_rows\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull17() {\n\n        // Arrange\n        final int type = 18;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Execute_load_query\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull18() {\n\n        // Arrange\n        final int type = 29;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Rows_query\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull19() {\n\n        // Arrange\n        final int type = 19;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Table_map\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull20() {\n\n        // Arrange\n        final int type = 28;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Ignorable\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull21() {\n\n        // Arrange\n        final int type = 33;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Gtid\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull22() {\n\n        // Arrange\n        final int type = 27;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Heartbeat\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull23() {\n\n        // Arrange\n        final int type = 26;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Incident\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull24() {\n\n        // Arrange\n        final int type = 31;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Update_rows\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull25() {\n\n        // Arrange\n        final int type = 25;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Delete_rows_v1\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull26() {\n\n        // Arrange\n        final int type = 24;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Update_rows_v1\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull27() {\n\n        // Arrange\n        final int type = 23;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Write_rows_v1\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull28() {\n\n        // Arrange\n        final int type = 35;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Previous_gtids\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull29() {\n\n        // Arrange\n        final int type = 22;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Delete_rows_event_old\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull30() {\n\n        // Arrange\n        final int type = 21;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Update_rows_event_old\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull31() {\n\n        // Arrange\n        final int type = 20;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Write_rows_event_old\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull32() {\n\n        // Arrange\n        final int type = 17;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Begin_load_query\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull33() {\n\n        // Arrange\n        final int type = 14;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"User var\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull34() {\n\n        // Arrange\n        final int type = 9;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Append_block\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull35() {\n\n        // Arrange\n        final int type = 2;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Query\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull36() {\n\n        // Arrange\n        final int type = 3;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Stop\", actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeNameInputPositiveOutputNotNull37() {\n\n        // Arrange\n        final int type = 1;\n\n        // Act\n        final String actual = LogEvent.getTypeName(type);\n\n        // Assert result\n        Assert.assertEquals(\"Start_v3\", actual);\n    }\n}\n"
  },
  {
    "path": "dbsync/src/test/java/com/taobao/tddl/dbsync/binlog/event/LogHeaderTest.java",
    "content": "package com.taobao.tddl.dbsync.binlog.event;\n\nimport java.util.HashMap;\n\nimport org.junit.Assert;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.junit.rules.ExpectedException;\nimport org.junit.rules.Timeout;\n\npublic class LogHeaderTest {\n\n    @Rule\n    public final ExpectedException thrown        = ExpectedException.none();\n\n    @SuppressWarnings(\"deprecation\")\n    @Rule\n    public final Timeout           globalTimeout = new Timeout(10000);\n\n    /* testedClasses: LogHeader */\n    // Test written by Diffblue Cover.\n\n    @Test\n    public void constructorInputZeroOutputVoid() {\n\n        // Arrange\n        final int type = 0;\n\n        // Act, creating object to test constructor\n        final LogHeader objectUnderTest = new LogHeader(type);\n\n        // Assert side effects\n        final HashMap<String, String> hashMap = new HashMap<>();\n        Assert.assertEquals(hashMap, objectUnderTest.gtidMap);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getChecksumAlgOutputZero() {\n\n        // Arrange\n        final LogHeader objectUnderTest = new LogHeader(0);\n\n        // Act\n        final int actual = objectUnderTest.getChecksumAlg();\n\n        // Assert result\n        Assert.assertEquals(0, actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getCrcOutputZero() {\n\n        // Arrange\n        final LogHeader objectUnderTest = new LogHeader(0);\n\n        // Act\n        final long actual = objectUnderTest.getCrc();\n\n        // Assert result\n        Assert.assertEquals(0L, actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getCurrentGtidLastCommitOutputNull() {\n\n        // Arrange\n        final LogHeader objectUnderTest = new LogHeader(0);\n\n        // Act\n        final String actual = objectUnderTest.getCurrentGtidLastCommit();\n\n        // Assert result\n        Assert.assertNull(actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getCurrentGtidOutputNull() {\n\n        // Arrange\n        final LogHeader objectUnderTest = new LogHeader(0);\n\n        // Act\n        final String actual = objectUnderTest.getCurrentGtid();\n\n        // Assert result\n        Assert.assertNull(actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getCurrentGtidSnOutputNull() {\n\n        // Arrange\n        final LogHeader objectUnderTest = new LogHeader(0);\n\n        // Act\n        final String actual = objectUnderTest.getCurrentGtidSn();\n\n        // Assert result\n        Assert.assertNull(actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getEventLenOutputZero() {\n\n        // Arrange\n        final LogHeader objectUnderTest = new LogHeader(0);\n\n        // Act\n        final int actual = objectUnderTest.getEventLen();\n\n        // Assert result\n        Assert.assertEquals(0, actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getFlagsOutputZero() {\n\n        // Arrange\n        final LogHeader objectUnderTest = new LogHeader(0);\n\n        // Act\n        final int actual = objectUnderTest.getFlags();\n\n        // Assert result\n        Assert.assertEquals(0, actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getGtidSetStrOutputNull() {\n\n        // Arrange\n        final LogHeader objectUnderTest = new LogHeader(0);\n\n        // Act\n        final String actual = objectUnderTest.getGtidSetStr();\n\n        // Assert result\n        Assert.assertNull(actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getLogFileNameOutputNull() {\n\n        // Arrange\n        final LogHeader objectUnderTest = new LogHeader(0);\n\n        // Act\n        final String actual = objectUnderTest.getLogFileName();\n\n        // Assert result\n        Assert.assertNull(actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getLogPosOutputZero() {\n\n        // Arrange\n        final LogHeader objectUnderTest = new LogHeader(0);\n\n        // Act\n        final long actual = objectUnderTest.getLogPos();\n\n        // Assert result\n        Assert.assertEquals(0L, actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getServerIdOutputZero() {\n\n        // Arrange\n        final LogHeader objectUnderTest = new LogHeader(0);\n\n        // Act\n        final long actual = objectUnderTest.getServerId();\n\n        // Assert result\n        Assert.assertEquals(0L, actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getTypeOutputZero() {\n\n        // Arrange\n        final LogHeader objectUnderTest = new LogHeader(0);\n\n        // Act\n        final int actual = objectUnderTest.getType();\n\n        // Assert result\n        Assert.assertEquals(0, actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void getWhenOutputZero() {\n\n        // Arrange\n        final LogHeader objectUnderTest = new LogHeader(0);\n\n        // Act\n        final long actual = objectUnderTest.getWhen();\n\n        // Assert result\n        Assert.assertEquals(0L, actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void setLogFileNameInputNotNullOutputVoid() {\n\n        // Arrange\n        final LogHeader objectUnderTest = new LogHeader(0);\n        final String logFileName = \"3\";\n\n        // Act\n        objectUnderTest.setLogFileName(logFileName);\n\n        // Assert side effects\n        Assert.assertEquals(\"3\", objectUnderTest.getLogFileName());\n    }\n}\n"
  },
  {
    "path": "dbsync/src/test/resources/dummy.txt",
    "content": "本文件仅仅为定位绝对路径使用"
  },
  {
    "path": "deployer/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>com.alibaba.otter</groupId>\n        <artifactId>canal</artifactId>\n        <version>1.1.9-SNAPSHOT</version>\n        <relativePath>../pom.xml</relativePath>\n    </parent>\n    <groupId>com.alibaba.otter</groupId>\n    <artifactId>canal.deployer</artifactId>\n    <packaging>jar</packaging>\n    <name>canal deployer module for otter ${project.version}</name>\n    <dependencies>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>canal.server</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n\n        <!-- 这里指定runtime的metrics provider-->\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>canal.prometheus</artifactId>\n            <version>${project.version}</version>\n            <scope>runtime</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>connector.kafka</artifactId>\n            <version>${project.version}</version>\n            <exclusions>\n                <exclusion>\n                    <artifactId>*</artifactId>\n                    <groupId>*</groupId>\n                </exclusion>\n            </exclusions>\n            <classifier>jar-with-dependencies</classifier>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>connector.rocketmq</artifactId>\n            <version>${project.version}</version>\n            <exclusions>\n                <exclusion>\n                    <artifactId>*</artifactId>\n                    <groupId>*</groupId>\n                </exclusion>\n            </exclusions>\n            <classifier>jar-with-dependencies</classifier>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>connector.rabbitmq</artifactId>\n            <version>${project.version}</version>\n            <exclusions>\n                <exclusion>\n                    <artifactId>*</artifactId>\n                    <groupId>*</groupId>\n                </exclusion>\n            </exclusions>\n            <classifier>jar-with-dependencies</classifier>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>connector.pulsarmq</artifactId>\n            <version>${project.version}</version>\n            <exclusions>\n                <exclusion>\n                    <artifactId>*</artifactId>\n                    <groupId>*</groupId>\n                </exclusion>\n            </exclusions>\n            <classifier>jar-with-dependencies</classifier>\n            <scope>provided</scope>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <artifactId>maven-jar-plugin</artifactId>\n                <configuration>\n                    <archive>\n                        <addMavenDescriptor>true</addMavenDescriptor>\n                    </archive>\n                    <excludes>\n                        <exclude>**/logback.xml</exclude>\n                        <exclude>**/canal.properties</exclude>\n                        <exclude>**/spring/**</exclude>\n                        <exclude>**/example/**</exclude>\n                        <exclude>**/mq.yml</exclude>\n                    </excludes>\n                </configuration>\n            </plugin>\n\t\t\t<plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-dependency-plugin</artifactId>\n                <version>2.10</version>\n                <executions>\n                    <execution>\n                        <id>copy-dependencies-to-canal-deployer</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>copy-dependencies</goal>\n                        </goals>\n                        <configuration>\n                            <includeClassifiers>jar-with-dependencies</includeClassifiers>\n                            <outputDirectory>${project.basedir}/target/canal/plugin</outputDirectory>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-assembly-plugin</artifactId>\n                <!-- 这是最新版本，推荐使用这个版本 -->\n                <version>2.2.1</version>\n                <executions>\n                    <execution>\n                        <id>assemble</id>\n                        <goals>\n                            <goal>single</goal>\n                        </goals>\n                        <phase>package</phase>\n                    </execution>\n                </executions>\n                <configuration>\n                    <appendAssemblyId>false</appendAssemblyId>\n                    <attach>false</attach>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n    <profiles>\n        <profile>\n            <id>dev</id>\n            <activation>\n                <activeByDefault>true</activeByDefault>\n                <property>\n                    <name>env</name>\n                    <value>!release</value>\n                </property>\n            </activation>\n\n            <build>\n                <plugins>\n                    <plugin>\n                        <artifactId>maven-assembly-plugin</artifactId>\n                        <configuration>\n                            <!-- maven assembly插件需要一个描述文件 来告诉插件包的结构以及打包所需的文件来自哪里 -->\n                            <descriptors>\n                                <descriptor>${basedir}/src/main/assembly/dev.xml</descriptor>\n                            </descriptors>\n                            <finalName>canal</finalName>\n                            <outputDirectory>${project.build.directory}</outputDirectory>\n                        </configuration>\n                    </plugin>\n                </plugins>\n            </build>\n\n        </profile>\n\n        <profile>\n            <id>release</id>\n            <activation>\n                <property>\n                    <name>env</name>\n                    <value>release</value>\n                </property>\n            </activation>\n\n            <build>\n                <plugins>\n                    <plugin>\n                        <artifactId>maven-assembly-plugin</artifactId>\n                        <configuration>\n                            <!-- 发布模式使用的maven assembly插件描述文件 -->\n                            <descriptors>\n                                <descriptor>${basedir}/src/main/assembly/release.xml</descriptor>\n                            </descriptors>\n                            <!-- 如果一个应用的包含多个deploy模块，如果使用同样的包名， 如果把它们复制的一个目录中可能会失败，所以包名加了 artifactId以示区分 -->\n                            <finalName>${project.artifactId}-${project.version}</finalName>\n                            <!-- scm 要求 release 模式打出的包放到顶级目录下的target子目录中 -->\n                            <outputDirectory>${project.parent.build.directory}</outputDirectory>\n                        </configuration>\n                    </plugin>\n                </plugins>\n            </build>\n        </profile>\n    </profiles>\n</project>\n"
  },
  {
    "path": "deployer/src/main/assembly/dev.xml",
    "content": "<assembly xmlns=\"http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\r\n\txsi:schemaLocation=\"http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd\">\r\n\t<id>dist</id>\r\n\t<formats>\r\n\t\t<format>dir</format>\r\n\t</formats>\r\n\t<includeBaseDirectory>false</includeBaseDirectory>\r\n\t<fileSets>\r\n\t\t<fileSet>\r\n\t\t\t<directory>.</directory>\r\n\t\t\t<outputDirectory>/</outputDirectory>\r\n\t\t\t<includes>\r\n\t\t\t\t<include>README*</include>\r\n\t\t\t</includes>\r\n\t\t</fileSet>\r\n\t\t<fileSet>\r\n\t\t\t<directory>./src/main/bin</directory>\r\n\t\t\t<outputDirectory>bin</outputDirectory>\r\n\t\t\t<includes>\r\n\t\t\t\t<include>**/*</include>\r\n\t\t\t</includes>\r\n\t\t\t<fileMode>0755</fileMode>\r\n\t\t</fileSet>\r\n\t\t<fileSet>\r\n\t\t\t<directory>./src/main/conf</directory>\r\n\t\t\t<outputDirectory>/conf</outputDirectory>\r\n\t\t\t<includes>\r\n\t\t\t\t<include>**/*</include>\r\n\t\t\t</includes>\r\n\t\t</fileSet>\r\n\t\t<fileSet>\r\n\t\t\t<directory>./src/main/resources</directory>\r\n\t\t\t<outputDirectory>/conf</outputDirectory>\r\n\t\t\t<includes>\r\n\t\t\t\t<include>**/*</include>\r\n\t\t\t</includes>\r\n\t\t</fileSet>\r\n\t\t<fileSet>\r\n\t\t\t<directory>target</directory>\r\n\t\t\t<outputDirectory>logs</outputDirectory>\r\n\t\t\t<excludes>\r\n\t\t\t\t<exclude>**/*</exclude>\r\n\t\t\t</excludes>\r\n\t\t</fileSet>\r\n\t</fileSets>\r\n\t<dependencySets>\r\n\t\t<dependencySet>\r\n\t\t\t<outputDirectory>lib</outputDirectory>\r\n\t\t\t<excludes>\r\n\t\t\t\t<exclude>junit:junit</exclude>\r\n\t\t\t</excludes>\r\n\t\t</dependencySet>\r\n\t</dependencySets>\r\n</assembly>\r\n"
  },
  {
    "path": "deployer/src/main/assembly/release.xml",
    "content": "<assembly xmlns=\"http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\r\n\txsi:schemaLocation=\"http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd\">\r\n\t<id>dist</id>\r\n\t<formats>\r\n\t\t<format>tar.gz</format>\r\n\t</formats>\r\n\t<includeBaseDirectory>false</includeBaseDirectory>\r\n\t<fileSets>\r\n\t\t<fileSet>\r\n\t\t\t<directory>.</directory>\r\n\t\t\t<outputDirectory>/</outputDirectory>\r\n\t\t\t<includes>\r\n\t\t\t\t<include>README*</include>\r\n\t\t\t</includes>\r\n\t\t</fileSet>\r\n\t\t<fileSet>\r\n\t\t\t<directory>./src/main/bin</directory>\r\n\t\t\t<outputDirectory>bin</outputDirectory>\r\n\t\t\t<includes>\r\n\t\t\t\t<include>**/*</include>\r\n\t\t\t</includes>\r\n\t\t\t<fileMode>0755</fileMode>\r\n\t\t</fileSet>\r\n\t\t<fileSet>\r\n\t\t\t<directory>./src/main/conf</directory>\r\n\t\t\t<outputDirectory>/conf</outputDirectory>\r\n\t\t\t<includes>\r\n\t\t\t\t<include>**/*</include>\r\n\t\t\t</includes>\r\n\t\t</fileSet>\r\n\t\t<fileSet>\r\n\t\t\t<directory>./src/main/resources</directory>\r\n\t\t\t<outputDirectory>/conf</outputDirectory>\r\n\t\t\t<includes>\r\n\t\t\t\t<include>**/*</include>\r\n\t\t\t</includes>\r\n\t\t</fileSet>\r\n\t\t<fileSet>\r\n\t\t\t<directory>target</directory>\r\n\t\t\t<outputDirectory>logs</outputDirectory>\r\n\t\t\t<excludes>\r\n\t\t\t\t<exclude>**/*</exclude>\r\n\t\t\t</excludes>\r\n\t\t</fileSet>\r\n\t\t<fileSet>\r\n\t\t\t<directory>${project.basedir}/target/canal/plugin</directory>\r\n\t\t\t<outputDirectory>/plugin/</outputDirectory>\r\n\t\t</fileSet>\r\n\t</fileSets>\r\n\t<dependencySets>\r\n\t\t<dependencySet>\r\n\t\t\t<outputDirectory>lib</outputDirectory>\r\n\t\t\t<excludes>\r\n\t\t\t\t<exclude>junit:junit</exclude>\r\n\t\t\t</excludes>\r\n\t\t</dependencySet>\r\n\t</dependencySets>\r\n</assembly>\r\n"
  },
  {
    "path": "deployer/src/main/bin/restart.sh",
    "content": "#!/bin/bash\n\nargs=$@\n\ncase $(uname) in\nLinux)\n  bin_abs_path=$(readlink -f $(dirname $0))\n  ;;\n*)\n  bin_abs_path=$(cd $(dirname $0) ||exit ; pwd)\n  ;;\nesac\n\nsh \"$bin_abs_path\"/stop.sh $args\nsh \"$bin_abs_path\"/startup.sh $args\n"
  },
  {
    "path": "deployer/src/main/bin/startup.bat",
    "content": "@echo off\n@if not \"%ECHO%\" == \"\"  echo %ECHO%\n@if \"%OS%\" == \"Windows_NT\"  setlocal\n\nset ENV_PATH=.\\\nif \"%OS%\" == \"Windows_NT\" set ENV_PATH=%~dp0%\n\nset conf_dir=%ENV_PATH%\\..\\conf\nset canal_conf=%conf_dir%\\canal.properties\n@rem set canal_conf=%conf_dir%\\canal_local.properties\nif \"%1\" == \"local\" set canal_conf=%conf_dir%\\canal_local.properties\nset logback_configurationFile=%conf_dir%\\logback.xml\n\nset CLASSPATH=%conf_dir%\nset CLASSPATH=%conf_dir%\\..\\lib\\*;%CLASSPATH%\n\nset JAVA_MEM_OPTS= -Xms128m -Xmx512m -XX:PermSize=128m\nset JAVA_OPTS_EXT= -Djava.awt.headless=true -Djava.net.preferIPv4Stack=false -Dapplication.codeset=UTF-8 -Dfile.encoding=UTF-8\nset JAVA_DEBUG_OPT= -server -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=9099,server=y,suspend=n\nset CANAL_OPTS= -DappName=otter-canal -Dlogback.configurationFile=\"%logback_configurationFile%\" -Dcanal.conf=\"%canal_conf%\"\n\nset JAVA_OPTS= %JAVA_MEM_OPTS% %JAVA_OPTS_EXT% %JAVA_DEBUG_OPT% %CANAL_OPTS%\n\nset CMD_STR= java %JAVA_OPTS% -classpath \"%CLASSPATH%\" java %JAVA_OPTS% -classpath \"%CLASSPATH%\" com.alibaba.otter.canal.deployer.CanalLauncher\necho start cmd : %CMD_STR%\n\njava %JAVA_OPTS% -classpath \"%CLASSPATH%\" com.alibaba.otter.canal.deployer.CanalLauncher\n"
  },
  {
    "path": "deployer/src/main/bin/startup.sh",
    "content": "#!/bin/bash \n\ncurrent_path=`pwd`\ncase \"`uname`\" in\n    Linux)\n\t\tbin_abs_path=$(readlink -f $(dirname $0))\n\t\t;;\n\t*)\n\t\tbin_abs_path=`cd $(dirname $0); pwd`\n\t\t;;\nesac\n\nbase=${bin_abs_path}/..\n\njaas_conf=$base/conf/jaas.conf\ncanal_conf=$base/conf/canal.properties\ncanal_local_conf=$base/conf/canal_local.properties\nlogback_configurationFile=$base/conf/logback.xml\n\nexport LANG=en_US.UTF-8\nexport BASE=$base\n\nif [ -f $base/bin/canal.pid ] ; then\n\techo \"found canal.pid , Please run stop.sh first ,then startup.sh\" 2>&2\n    exit 1\nfi\n\nif [ ! -d $base/logs/canal ] ; then \n\tmkdir -p $base/logs/canal\nfi\n\n## set java path\nif [ -z \"$JAVA\" ] ; then\n  JAVA=$(which java)\nfi\n\nALIBABA_JAVA=\"/usr/alibaba/java/bin/java\"\nTAOBAO_JAVA=\"/opt/taobao/java/bin/java\"\nif [ -z \"$JAVA\" ]; then\n  if [ -f $ALIBABA_JAVA ] ; then\n  \tJAVA=$ALIBABA_JAVA\n  elif [ -f $TAOBAO_JAVA ] ; then\n  \tJAVA=$TAOBAO_JAVA\n  else\n  \techo \"Cannot find a Java JDK. Please set either set JAVA or put java (>=1.5) in your PATH.\" 2>&2\n    exit 1\n  fi\nfi\n\ncase \"$#\" \nin\n0 ) \n\t;;\n1 )\t\n\tvar=$*\n\tif [ \"$var\" = \"local\" ]; then\n\t\tcanal_conf=$canal_local_conf\n\telse\n\t\tif [ -f $var ] ; then \n\t\t\tcanal_conf=$var\n\t\telse\n\t\t\techo \"THE PARAMETER IS NOT CORRECT.PLEASE CHECK AGAIN.\"\n\t\t\texit\n\t\tfi\n\tfi;;\n2 )\t\n\tvar=$1\n\tif [ \"$var\" = \"local\" ]; then\n\t\tcanal_conf=$canal_local_conf\n\telse\n\t\tif [ -f $var ] ; then\n\t\t\tcanal_conf=$var\n\t\telse \n\t\t\tif [ \"$1\" = \"debug\" ]; then\n\t\t\t\tDEBUG_PORT=$2\n\t\t\t\tDEBUG_SUSPEND=\"n\"\n\t\t\t\tJAVA_DEBUG_OPT=\"-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=$DEBUG_PORT,server=y,suspend=$DEBUG_SUSPEND\"\n\t\t\tfi\n\t\tfi\n     fi;;\n* )\n\techo \"THE PARAMETERS MUST BE TWO OR LESS.PLEASE CHECK AGAIN.\"\n\texit;;\nesac\n\nJAVA_VERSION=`$JAVA -version 2>&1 |awk 'NR==1{ gsub(/\"/,\"\"); print $3 }' | awk  -F '.' '{print $1}'`\n\nJAVA_OPTS=\"$JAVA_OPTS -Xss1m -XX:+AggressiveOpts -XX:-UseBiasedLocking -XX:-OmitStackTraceInFastThrow\"\nJAVA_OPTS=\"$JAVA_OPTS -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$base/logs\"\n\nif [ $JAVA_VERSION -ge 11 ] ; then\n  #JAVA_OPTS=\"$JAVA_OPTS -Xlog:gc*:$base_log/gc.log:time \"\n  JAVA_OPTS=\"$JAVA_OPTS -Xlog:gc*:file=$base/logs/adapter/gc.log::filecount=5,filesize=32M\"\nelse\n  JAVA_OPTS=\"$JAVA_OPTS -Xloggc:$base/logs/canal/gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=32M\"\n  JAVA_OPTS=\"$JAVA_OPTS -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:-PrintHeapAtGC -XX:+PrintGCApplicationStoppedTime\"\n  JAVA_OPTS=\"$JAVA_OPTS -XX:+UseFastAccessorMethods -XX:-PrintReferenceGC -XX:+PrintAdaptiveSizePolicy -XX:+PrintTenuringDistribution\"\n  JAVA_OPTS=\"$JAVA_OPTS -XX:+PrintSafepointStatistics -XX:PrintSafepointStatisticsCount=1 -XX:+SafepointTimeout -XX:SafepointTimeoutDelay=2000\"\n  JAVA_OPTS=\"$JAVA_OPTS -XX:+UseCountedLoopSafepoints -XX:+DisableExplicitGC -XX:+ExplicitGCInvokesConcurrent -XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses\"\nfi\n\nOS_ARCH=`file -L $JAVA | grep 64-bit`\n\nif [ -n \"$OS_ARCH\" ]; then\n  if [ $JAVA_VERSION -ge 11 ] ; then\n    # For G1\n    JAVA_OPTS=\"-server -Xms2g -Xmx3g -XX:+UseG1GC -XX:MaxGCPauseMillis=250 -XX:+UseGCOverheadLimit -XX:+ExplicitGCInvokesConcurrent $JAVA_OPTS\"\n  else\n\t  JAVA_OPTS=\"-server -Xms2g -Xmx3g -Xmn1g -XX:SurvivorRatio=2 -XX:PermSize=96m -XX:MaxPermSize=256m -XX:MaxTenuringThreshold=15 -XX:+DisableExplicitGC $JAVA_OPTS\"\n\t  ## JDK 1.8 2c4g [-XX:ConcGCThreads=1 -XX:ParallelGCThreads=2], 4c8g [-XX:ConcGCThreads=2 -XX:ParallelGCThreads=4]\n\t  #JAVA_OPTS=\"$JAVA_OPTS -XX:InitialRAMPercentage=45.0 -XX:MinRAMPercentage=45.0 -XX:MaxRAMPercentage=45.0\"\n\t  #JAVA_OPTS=\"$JAVA_OPTS -XX:-UseParallelGC -XX:+UseConcMarkSweepGC -XX:ConcGCThreads=2 -XX:ParallelGCThreads=4\"\n\t  #JAVA_OPTS=\"$JAVA_OPTS -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70\"\n\t  #JAVA_OPTS=\"-server -XX:NewRatio=1 -XX:SurvivorRatio=2 -XX:MetaspaceSize=96m -XX:MaxMetaspaceSize=128m \"\n\tfi\nelse\n\tJAVA_OPTS=\"-server -Xms1024m -Xmx1024m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:MaxPermSize=128m $JAVA_OPTS\"\nfi\n\nJAVA_OPTS=\" $JAVA_OPTS -Djava.awt.headless=true -Djava.net.preferIPv4Stack=false -Dfile.encoding=UTF-8\"\nCANAL_OPTS=\"-DappName=otter-canal -Dlogback.configurationFile=$logback_configurationFile -Dcanal.conf=$canal_conf\"\nif [ -f \"$jaas_conf\" ]; then\n  CANAL_OPTS=\"$CANAL_OPTS -Djava.security.auth.login.config=$jaas_conf\"\nfi\n\nif [ -e $canal_conf -a -e $logback_configurationFile ]\nthen \n\t\n\tfor i in $base/lib/*;\n\t\tdo CLASSPATH=$i:\"$CLASSPATH\";\n\tdone\n \tCLASSPATH=\"$base/conf:$CLASSPATH\";\n \t\n \techo \"cd to $bin_abs_path for workaround relative path\"\n  \tcd $bin_abs_path\n \t\n\techo LOG CONFIGURATION : $logback_configurationFile\n\techo canal conf : $canal_conf \n\techo CLASSPATH :$CLASSPATH\n\t$JAVA $JAVA_OPTS $JAVA_DEBUG_OPT $CANAL_OPTS -classpath .:$CLASSPATH com.alibaba.otter.canal.deployer.CanalLauncher 1>>$base/logs/canal/canal_stdout.log 2>&1 &\n\techo $! > $base/bin/canal.pid \n\t\n\techo \"cd to $current_path for continue\"\n  \tcd $current_path\nelse \n\techo \"canal conf(\"$canal_conf\") OR log configration file($logback_configurationFile) is not exist,please create then first!\"\nfi\n"
  },
  {
    "path": "deployer/src/main/bin/stop.sh",
    "content": "#!/bin/bash\n\ncygwin=false;\nlinux=false;\ncase \"`uname`\" in\n    CYGWIN*)\n        cygwin=true\n        ;;\n    Linux*)\n    \tlinux=true\n    \t;;\nesac\n\nget_pid() {\t\n\tSTR=$1\n\tPID=$2\n    if $cygwin; then\n        JAVA_CMD=\"$JAVA_HOME\\bin\\java\"\n        JAVA_CMD=`cygpath --path --unix $JAVA_CMD`\n        JAVA_PID=`ps |grep $JAVA_CMD |awk '{print $1}'`\n    else\n    \tif $linux; then\n\t        if [ ! -z \"$PID\" ]; then\n\t        \tJAVA_PID=`ps -C java -f --width 1000|grep \"$STR\"|grep \"$PID\"|grep -v grep|awk '{print $2}'`\n\t\t    else \n\t\t        JAVA_PID=`ps -C java -f --width 1000|grep \"$STR\"|grep -v grep|awk '{print $2}'`\n\t        fi\n\t    else\n\t    \tif [ ! -z \"$PID\" ]; then\n\t        \tJAVA_PID=`ps aux |grep \"$STR\"|grep \"$PID\"|grep -v grep|awk '{print $2}'`\n\t\t    else \n\t\t        JAVA_PID=`ps aux |grep \"$STR\"|grep -v grep|awk '{print $2}'`\n\t        fi\n\t    fi\n    fi\n    echo $JAVA_PID;\n}\n\nbase=`dirname $0`/..\npidfile=$base/bin/canal.pid\nif [ ! -f \"$pidfile\" ];then\n\techo \"canal is not running. exists\"\n\texit\nfi\n\npid=`cat $pidfile`\nif [ \"$pid\" == \"\" ] ; then\n\tpid=`get_pid \"appName=otter-canal\"`\nfi\n\necho -e \"`hostname`: stopping canal $pid ... \"\nkill $pid\n\nLOOPS=0\nwhile (true); \ndo \n\tgpid=`get_pid \"appName=otter-canal\" \"$pid\"`\n    if [ \"$gpid\" == \"\" ] ; then\n    \techo \"Oook! cost:$LOOPS\"\n    \t`rm $pidfile`\n    \tbreak;\n    fi\n    let LOOPS=LOOPS+1\n    sleep 1\ndone"
  },
  {
    "path": "deployer/src/main/java/com/alibaba/otter/canal/deployer/CanalConstants.java",
    "content": "package com.alibaba.otter.canal.deployer;\n\nimport java.text.MessageFormat;\n\n/**\n * 启动常用变量\n *\n * @author jianghang 2012-11-8 下午03:15:55\n * @version 1.0.0\n */\npublic class CanalConstants {\n\n    public static final String MDC_DESTINATION                      = \"destination\";\n    public static final String ROOT                                 = \"canal\";\n    public static final String CANAL_ID                             = ROOT + \".\" + \"id\";\n    public static final String CANAL_IP                             = ROOT + \".\" + \"ip\";\n    public static final String CANAL_REGISTER_IP                    = ROOT + \".\" + \"register.ip\";\n    public static final String CANAL_PORT                           = ROOT + \".\" + \"port\";\n    public static final String CANAL_USER                           = ROOT + \".\" + \"user\";\n    public static final String CANAL_PASSWD                         = ROOT + \".\" + \"passwd\";\n    public static final String CANAL_METRICS_PULL_PORT              = ROOT + \".\" + \"metrics.pull.port\";\n    public static final String CANAL_ADMIN_MANAGER                  = ROOT + \".\" + \"admin.manager\";\n    public static final String CANAL_ADMIN_PORT                     = ROOT + \".\" + \"admin.port\";\n    public static final String CANAL_ADMIN_USER                     = ROOT + \".\" + \"admin.user\";\n    public static final String CANAL_ADMIN_PASSWD                   = ROOT + \".\" + \"admin.passwd\";\n    public static final String CANAL_ADMIN_AUTO_REGISTER            = ROOT + \".\" + \"admin.register.auto\";\n    public static final String CANAL_ADMIN_AUTO_CLUSTER             = ROOT + \".\" + \"admin.register.cluster\";\n    public static final String CANAL_ADMIN_REGISTER_NAME            = ROOT + \".\" + \"admin.register.name\";\n    public static final String CANAL_ZKSERVERS                      = ROOT + \".\" + \"zkServers\";\n    public static final String CANAL_WITHOUT_NETTY                  = ROOT + \".\" + \"withoutNetty\";\n\n    public static final String CANAL_DESTINATIONS                   = ROOT + \".\" + \"destinations\";\n    public static final String CANAL_DESTINATIONS_EXPR              = ROOT + \".\" + \"destinations.expr\";\n    public static final String CANAL_AUTO_SCAN                      = ROOT + \".\" + \"auto.scan\";\n    public static final String CANAL_AUTO_SCAN_INTERVAL             = ROOT + \".\" + \"auto.scan.interval\";\n    public static final String CANAL_CONF_DIR                       = ROOT + \".\" + \"conf.dir\";\n    public static final String CANAL_SERVER_MODE                    = ROOT + \".\" + \"serverMode\";\n\n    public static final String CANAL_DESTINATION_SPLIT              = \",\";\n    public static final String GLOBAL_NAME                          = \"global\";\n\n    public static final String INSTANCE_MODE_TEMPLATE               = ROOT + \".\" + \"instance.{0}.mode\";\n    public static final String INSTANCE_LAZY_TEMPLATE               = ROOT + \".\" + \"instance.{0}.lazy\";\n    public static final String INSTANCE_MANAGER_ADDRESS_TEMPLATE    = ROOT + \".\" + \"instance.{0}.manager.address\";\n    public static final String INSTANCE_SPRING_XML_TEMPLATE         = ROOT + \".\" + \"instance.{0}.spring.xml\";\n\n    public static final String CANAL_DESTINATION_PROPERTY           = ROOT + \".instance.destination\";\n\n    public static final String CANAL_SOCKETCHANNEL                  = ROOT + \".\" + \"socketChannel\";\n\n    public static final String CANAL_ALIYUN_ACCESSKEY               = ROOT + \".\" + \"aliyun.accessKey\";\n    public static final String CANAL_ALIYUN_SECRETKEY               = ROOT + \".\" + \"aliyun.secretKey\";\n\n//    public static final String CANAL_MQ_SERVERS                     = ROOT + \".\" + \"mq.servers\";\n//    public static final String CANAL_MQ_RETRIES                     = ROOT + \".\" + \"mq.retries\";\n//    public static final String CANAL_MQ_BATCHSIZE                   = ROOT + \".\" + \"mq.batchSize\";\n//    public static final String CANAL_MQ_LINGERMS                    = ROOT + \".\" + \"mq.lingerMs\";\n//    public static final String CANAL_MQ_MAXREQUESTSIZE              = ROOT + \".\" + \"mq.maxRequestSize\";\n//    public static final String CANAL_MQ_BUFFERMEMORY                = ROOT + \".\" + \"mq.bufferMemory\";\n//    public static final String CANAL_MQ_CANALBATCHSIZE              = ROOT + \".\" + \"mq.canalBatchSize\";\n//    public static final String CANAL_MQ_CANALGETTIMEOUT             = ROOT + \".\" + \"mq.canalGetTimeout\";\n//    public static final String CANAL_MQ_FLATMESSAGE                 = ROOT + \".\" + \"mq.flatMessage\";\n//    public static final String CANAL_MQ_PARALLELTHREADSIZE          = ROOT + \".\" + \"mq.parallelThreadSize\";\n//    public static final String CANAL_MQ_COMPRESSION_TYPE            = ROOT + \".\" + \"mq.compressionType\";\n//    public static final String CANAL_MQ_ACKS                        = ROOT + \".\" + \"mq.acks\";\n//    public static final String CANAL_MQ_TRANSACTION                 = ROOT + \".\" + \"mq.transaction\";\n//    public static final String CANAL_MQ_PRODUCERGROUP               = ROOT + \".\" + \"mq.producerGroup\";\n//    public static final String CANAL_MQ_PROPERTIES                  = ROOT + \".\" + \"mq.properties\";\n//    public static final String CANAL_MQ_ENABLE_MESSAGE_TRACE        = ROOT + \".\" + \"mq.enableMessageTrace\";\n//    public static final String CANAL_MQ_ACCESS_CHANNEL              = ROOT + \".\" + \"mq.accessChannel\";\n//    public static final String CANAL_MQ_CUSTOMIZED_TRACE_TOPIC      = ROOT + \".\" + \"mq.customizedTraceTopic\";\n//    public static final String CANAL_MQ_NAMESPACE                   = ROOT + \".\" + \"mq.namespace\";\n//    public static final String CANAL_MQ_KAFKA_KERBEROS_ENABLE       = ROOT + \".\" + \"mq.kafka.kerberos.enable\";\n//    public static final String CANAL_MQ_KAFKA_KERBEROS_KRB5FILEPATH = ROOT + \".\" + \"mq.kafka.kerberos.krb5FilePath\";\n//    public static final String CANAL_MQ_KAFKA_KERBEROS_JAASFILEPATH = ROOT + \".\" + \"mq.kafka.kerberos.jaasFilePath\";\n//    public static final String CANAL_MQ_USERNAME                    = ROOT + \".\" + \"mq.username\";\n//    public static final String CANAL_MQ_PASSWORD                    = ROOT + \".\" + \"mq.password\";\n//    public static final String CANAL_MQ_VHOST                       = ROOT + \".\" + \"mq.vhost\";\n//    public static final String CANAL_MQ_ALIYUN_UID                  = ROOT + \".\" + \"mq.aliyunuid\";\n//    public static final String CANAL_MQ_EXCHANGE                    = ROOT + \".\" + \"mq.exchange\";\n//    public static final String CANAL_MQ_DATABASE_HASH               = ROOT + \".\" + \"mq.database.hash\";\n\n    public static String getInstanceModeKey(String destination) {\n        return MessageFormat.format(INSTANCE_MODE_TEMPLATE, destination);\n    }\n\n    public static String getInstanceManagerAddressKey(String destination) {\n        return MessageFormat.format(INSTANCE_MANAGER_ADDRESS_TEMPLATE, destination);\n    }\n\n    public static String getInstancSpringXmlKey(String destination) {\n        return MessageFormat.format(INSTANCE_SPRING_XML_TEMPLATE, destination);\n    }\n\n    public static String getInstancLazyKey(String destination) {\n        return MessageFormat.format(INSTANCE_LAZY_TEMPLATE, destination);\n    }\n}\n"
  },
  {
    "path": "deployer/src/main/java/com/alibaba/otter/canal/deployer/CanalController.java",
    "content": "package com.alibaba.otter.canal.deployer;\n\nimport static com.alibaba.otter.canal.deployer.CanalConstants.CANAL_DESTINATIONS;\nimport static com.alibaba.otter.canal.deployer.CanalConstants.CANAL_DESTINATIONS_EXPR;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\nimport java.util.stream.Collectors;\n\nimport org.I0Itec.zkclient.IZkStateListener;\nimport org.I0Itec.zkclient.exception.ZkNoNodeException;\nimport org.I0Itec.zkclient.exception.ZkNodeExistsException;\nimport org.apache.commons.lang.BooleanUtils;\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.zookeeper.Watcher.Event.KeeperState;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.slf4j.MDC;\n\nimport com.alibaba.otter.canal.common.utils.AddressUtils;\nimport com.alibaba.otter.canal.common.zookeeper.ZkClientx;\nimport com.alibaba.otter.canal.common.zookeeper.ZookeeperPathUtils;\nimport com.alibaba.otter.canal.common.zookeeper.running.ServerRunningData;\nimport com.alibaba.otter.canal.common.zookeeper.running.ServerRunningListener;\nimport com.alibaba.otter.canal.common.zookeeper.running.ServerRunningMonitor;\nimport com.alibaba.otter.canal.common.zookeeper.running.ServerRunningMonitors;\nimport com.alibaba.otter.canal.deployer.InstanceConfig.InstanceMode;\nimport com.alibaba.otter.canal.deployer.monitor.InstanceAction;\nimport com.alibaba.otter.canal.deployer.monitor.InstanceConfigMonitor;\nimport com.alibaba.otter.canal.deployer.monitor.ManagerInstanceConfigMonitor;\nimport com.alibaba.otter.canal.deployer.monitor.SpringInstanceConfigMonitor;\nimport com.alibaba.otter.canal.instance.core.CanalInstanceGenerator;\nimport com.alibaba.otter.canal.instance.manager.PlainCanalInstanceGenerator;\nimport com.alibaba.otter.canal.instance.manager.plain.PlainCanalConfigClient;\nimport com.alibaba.otter.canal.instance.spring.SpringCanalInstanceGenerator;\nimport com.alibaba.otter.canal.server.CanalMQStarter;\nimport com.alibaba.otter.canal.server.embedded.CanalServerWithEmbedded;\nimport com.alibaba.otter.canal.server.exception.CanalServerException;\nimport com.alibaba.otter.canal.server.netty.CanalServerWithNetty;\nimport com.google.common.base.Function;\nimport com.google.common.collect.MapMaker;\nimport com.google.common.collect.MigrateMap;\n\n/**\n * canal调度控制器\n *\n * @author jianghang 2012-11-8 下午12:03:11\n * @version 1.0.0\n */\npublic class CanalController {\n\n    private static final Logger                      logger   = LoggerFactory.getLogger(CanalController.class);\n    private String                                   ip;\n    private String                                   registerIp;\n    private int                                      port;\n    private int                                      adminPort;\n    // 默认使用spring的方式载入\n    private Map<String, InstanceConfig>              instanceConfigs;\n    private InstanceConfig                           globalInstanceConfig;\n    private Map<String, PlainCanalConfigClient>      managerClients;\n    // 监听instance config的变化\n    private boolean                                  autoScan = true;\n    private InstanceAction                           defaultAction;\n    private Map<InstanceMode, InstanceConfigMonitor> instanceConfigMonitors;\n    private CanalServerWithEmbedded                  embeddedCanalServer;\n    private CanalServerWithNetty                     canalServer;\n\n    private CanalInstanceGenerator                   instanceGenerator;\n    private ZkClientx                                zkclientx;\n\n    private CanalMQStarter                           canalMQStarter;\n    private String                                   adminUser;\n    private String                                   adminPasswd;\n\n    public CanalController(){\n        this(System.getProperties());\n    }\n\n    public CanalController(final Properties properties){\n        managerClients = MigrateMap.makeComputingMap(this::getManagerClient);\n\n        // 初始化全局参数设置\n        globalInstanceConfig = initGlobalConfig(properties);\n        instanceConfigs = new MapMaker().makeMap();\n        // 初始化instance config\n        initInstanceConfig(properties);\n\n        // init socketChannel\n        String socketChannel = getProperty(properties, CanalConstants.CANAL_SOCKETCHANNEL);\n        if (StringUtils.isNotEmpty(socketChannel)) {\n            System.setProperty(CanalConstants.CANAL_SOCKETCHANNEL, socketChannel);\n        }\n\n        // 兼容1.1.0版本的ak/sk参数名\n        String accesskey = getProperty(properties, \"canal.instance.rds.accesskey\");\n        String secretkey = getProperty(properties, \"canal.instance.rds.secretkey\");\n        if (StringUtils.isNotEmpty(accesskey)) {\n            System.setProperty(CanalConstants.CANAL_ALIYUN_ACCESSKEY, accesskey);\n        }\n        if (StringUtils.isNotEmpty(secretkey)) {\n            System.setProperty(CanalConstants.CANAL_ALIYUN_SECRETKEY, secretkey);\n        }\n\n        // 准备canal server\n        ip = getProperty(properties, CanalConstants.CANAL_IP);\n        registerIp = getProperty(properties, CanalConstants.CANAL_REGISTER_IP);\n        port = Integer.valueOf(getProperty(properties, CanalConstants.CANAL_PORT, \"11111\"));\n        adminPort = Integer.valueOf(getProperty(properties, CanalConstants.CANAL_ADMIN_PORT, \"11110\"));\n        embeddedCanalServer = CanalServerWithEmbedded.instance();\n        embeddedCanalServer.setCanalInstanceGenerator(instanceGenerator);// 设置自定义的instanceGenerator\n        int metricsPort = Integer.valueOf(getProperty(properties, CanalConstants.CANAL_METRICS_PULL_PORT, \"11112\"));\n        embeddedCanalServer.setMetricsPort(metricsPort);\n\n        this.adminUser = getProperty(properties, CanalConstants.CANAL_ADMIN_USER);\n        this.adminPasswd = getProperty(properties, CanalConstants.CANAL_ADMIN_PASSWD);\n        String user = getProperty(properties, CanalConstants.CANAL_USER);\n        String passwd = getProperty(properties, CanalConstants.CANAL_PASSWD);\n        if (StringUtils.isNotEmpty(user) && StringUtils.isEmpty(passwd)) {\n            throw new IllegalArgumentException(\n                \"canal.user = \" + user + \" , but canal.passwd is empty , pls check https://github.com/alibaba/canal/issues/4941\");\n        }\n        embeddedCanalServer.setUser(user);\n        embeddedCanalServer.setPasswd(passwd);\n\n        String canalWithoutNetty = getProperty(properties, CanalConstants.CANAL_WITHOUT_NETTY);\n        if (canalWithoutNetty == null || \"false\".equals(canalWithoutNetty)) {\n            canalServer = CanalServerWithNetty.instance();\n            canalServer.setIp(ip);\n            canalServer.setPort(port);\n        }\n\n        // 处理下ip为空，默认使用hostIp暴露到zk中\n        if (StringUtils.isEmpty(ip) && StringUtils.isEmpty(registerIp)) {\n            ip = registerIp = AddressUtils.getHostIp();\n        }\n\n        if (StringUtils.isEmpty(ip)) {\n            ip = AddressUtils.getHostIp();\n        }\n\n        if (StringUtils.isEmpty(registerIp)) {\n            registerIp = ip; // 兼容以前配置\n        }\n        final String zkServers = getProperty(properties, CanalConstants.CANAL_ZKSERVERS);\n        if (StringUtils.isNotEmpty(zkServers)) {\n            zkclientx = ZkClientx.getZkClient(zkServers);\n            // 初始化系统目录\n            zkclientx.createPersistent(ZookeeperPathUtils.DESTINATION_ROOT_NODE, true);\n            zkclientx.createPersistent(ZookeeperPathUtils.CANAL_CLUSTER_ROOT_NODE, true);\n        }\n\n        final ServerRunningData serverData = new ServerRunningData(registerIp + \":\" + port);\n        ServerRunningMonitors.setServerData(serverData);\n        ServerRunningMonitors.setRunningMonitors(MigrateMap.makeComputingMap((Function<String, ServerRunningMonitor>) destination -> {\n            ServerRunningMonitor runningMonitor = new ServerRunningMonitor(serverData);\n            runningMonitor.setDestination(destination);\n            runningMonitor.setListener(new ServerRunningListener() {\n\n                public void processActiveEnter() {\n                    try {\n                        MDC.put(CanalConstants.MDC_DESTINATION, String.valueOf(destination));\n                        embeddedCanalServer.start(destination);\n                        if (canalMQStarter != null) {\n                            canalMQStarter.startDestination(destination);\n                        }\n                    } finally {\n                        MDC.remove(CanalConstants.MDC_DESTINATION);\n                    }\n                }\n\n                public void processActiveExit() {\n                    try {\n                        MDC.put(CanalConstants.MDC_DESTINATION, String.valueOf(destination));\n                        if (canalMQStarter != null) {\n                            canalMQStarter.stopDestination(destination);\n                        }\n                        embeddedCanalServer.stop(destination);\n                    } finally {\n                        MDC.remove(CanalConstants.MDC_DESTINATION);\n                    }\n                }\n\n                public void processStart() {\n                    try {\n                        if (zkclientx != null) {\n                            final String path = ZookeeperPathUtils.getDestinationClusterNode(destination,\n                                registerIp + \":\" + port);\n                            initCid(path);\n                            zkclientx.subscribeStateChanges(new IZkStateListener() {\n\n                                public void handleStateChanged(KeeperState state) throws Exception {\n\n                                }\n\n                                public void handleNewSession() throws Exception {\n                                    initCid(path);\n                                }\n\n                                @Override\n                                public void handleSessionEstablishmentError(Throwable error) throws Exception {\n                                    logger.error(\"failed to connect to zookeeper\", error);\n                                }\n                            });\n                        }\n                    } finally {\n                        MDC.remove(CanalConstants.MDC_DESTINATION);\n                    }\n                }\n\n                public void processStop() {\n                    try {\n                        MDC.put(CanalConstants.MDC_DESTINATION, String.valueOf(destination));\n                        if (zkclientx != null) {\n                            final String path = ZookeeperPathUtils.getDestinationClusterNode(destination,\n                                registerIp + \":\" + port);\n                            releaseCid(path);\n                        }\n                    } finally {\n                        MDC.remove(CanalConstants.MDC_DESTINATION);\n                    }\n                }\n\n            });\n            if (zkclientx != null) {\n                runningMonitor.setZkClient(zkclientx);\n            }\n            // 触发创建一下cid节点\n            runningMonitor.init();\n            return runningMonitor;\n        }));\n\n        // 初始化monitor机制\n        autoScan = BooleanUtils.toBoolean(getProperty(properties, CanalConstants.CANAL_AUTO_SCAN));\n        if (autoScan) {\n            defaultAction = new InstanceAction() {\n\n                public void start(String destination) {\n                    InstanceConfig config = instanceConfigs.get(destination);\n                    if (config == null) {\n                        // 重新读取一下instance config\n                        config = parseInstanceConfig(properties, destination);\n                        instanceConfigs.put(destination, config);\n                    }\n\n                    if (!embeddedCanalServer.isStart(destination)) {\n                        // HA机制启动\n                        ServerRunningMonitor runningMonitor = ServerRunningMonitors.getRunningMonitor(destination);\n                        if (!config.getLazy() && !runningMonitor.isStart()) {\n                            runningMonitor.start();\n                        }\n                    }\n\n                    logger.info(\"auto notify start {} successful.\", destination);\n                }\n\n                public void stop(String destination) {\n                    // 此处的stop，代表强制退出，非HA机制，所以需要退出HA的monitor和配置信息\n                    InstanceConfig config = instanceConfigs.remove(destination);\n                    if (config != null) {\n                        embeddedCanalServer.stop(destination);\n                        ServerRunningMonitor runningMonitor = ServerRunningMonitors.getRunningMonitor(destination);\n                        if (runningMonitor.isStart()) {\n                            runningMonitor.stop();\n                        }\n                    }\n\n                    logger.info(\"auto notify stop {} successful.\", destination);\n                }\n\n                public void reload(String destination) {\n                    // 目前任何配置变化，直接重启，简单处理\n                    stop(destination);\n                    start(destination);\n\n                    logger.info(\"auto notify reload {} successful.\", destination);\n                }\n\n                @Override\n                public void release(String destination) {\n                    // 此处的release，代表强制释放，主要针对HA机制释放运行，让给其他机器抢占\n                    InstanceConfig config = instanceConfigs.get(destination);\n                    if (config != null) {\n                        ServerRunningMonitor runningMonitor = ServerRunningMonitors.getRunningMonitor(destination);\n                        if (runningMonitor.isStart()) {\n                            boolean release = runningMonitor.release();\n                            if (!release) {\n                                // 如果是单机模式,则直接清除配置\n                                instanceConfigs.remove(destination);\n                                // 停掉服务\n                                runningMonitor.stop();\n                                if (instanceConfigMonitors.containsKey(InstanceConfig.InstanceMode.MANAGER)) {\n                                    ManagerInstanceConfigMonitor monitor = (ManagerInstanceConfigMonitor) instanceConfigMonitors.get(InstanceConfig.InstanceMode.MANAGER);\n                                    Map<String, InstanceAction> instanceActions = monitor.getActions();\n                                    if (instanceActions.containsKey(destination)) {\n                                        // 清除内存中的autoScan cache\n                                        monitor.release(destination);\n                                    }\n                                }\n                            }\n                        }\n                    }\n\n                    logger.info(\"auto notify release {} successful.\", destination);\n                }\n            };\n\n            instanceConfigMonitors = MigrateMap.makeComputingMap(mode -> {\n                int scanInterval = Integer.valueOf(getProperty(properties,\n                    CanalConstants.CANAL_AUTO_SCAN_INTERVAL,\n                    \"5\"));\n\n                if (mode.isSpring()) {\n                    SpringInstanceConfigMonitor monitor = new SpringInstanceConfigMonitor();\n                    monitor.setScanIntervalInSecond(scanInterval);\n                    monitor.setDefaultAction(defaultAction);\n                    // 设置conf目录，默认是user.dir + conf目录组成\n                    String rootDir = getProperty(properties, CanalConstants.CANAL_CONF_DIR);\n                    if (StringUtils.isEmpty(rootDir)) {\n                        rootDir = \"../conf\";\n                    }\n\n                    if (StringUtils.equals(\"otter-canal\", System.getProperty(\"appName\"))) {\n                        monitor.setRootConf(rootDir);\n                    } else {\n                        // eclipse debug模式\n                        monitor.setRootConf(\"src/main/resources/\");\n                    }\n                    return monitor;\n                } else if (mode.isManager()) {\n                    ManagerInstanceConfigMonitor monitor = new ManagerInstanceConfigMonitor();\n                    monitor.setScanIntervalInSecond(scanInterval);\n                    monitor.setDefaultAction(defaultAction);\n                    String managerAddress = getProperty(properties, CanalConstants.CANAL_ADMIN_MANAGER);\n                    monitor.setConfigClient(getManagerClient(managerAddress));\n                    return monitor;\n                } else {\n                    throw new UnsupportedOperationException(\"unknow mode :\" + mode + \" for monitor\");\n                }\n            });\n        }\n    }\n\n    private InstanceConfig initGlobalConfig(Properties properties) {\n        String adminManagerAddress = getProperty(properties, CanalConstants.CANAL_ADMIN_MANAGER);\n        InstanceConfig globalConfig = new InstanceConfig();\n        String modeStr = getProperty(properties, CanalConstants.getInstanceModeKey(CanalConstants.GLOBAL_NAME));\n        if (StringUtils.isNotEmpty(adminManagerAddress)) {\n            // 如果指定了manager地址,则强制适用manager\n            globalConfig.setMode(InstanceMode.MANAGER);\n        } else if (StringUtils.isNotEmpty(modeStr)) {\n            globalConfig.setMode(InstanceMode.valueOf(StringUtils.upperCase(modeStr)));\n        }\n\n        String lazyStr = getProperty(properties, CanalConstants.getInstancLazyKey(CanalConstants.GLOBAL_NAME));\n        if (StringUtils.isNotEmpty(lazyStr)) {\n            globalConfig.setLazy(Boolean.valueOf(lazyStr));\n        }\n\n        String managerAddress = getProperty(properties,\n            CanalConstants.getInstanceManagerAddressKey(CanalConstants.GLOBAL_NAME));\n        if (StringUtils.isNotEmpty(managerAddress)) {\n            if (StringUtils.equals(managerAddress, \"${canal.admin.manager}\")) {\n                managerAddress = adminManagerAddress;\n            }\n\n            globalConfig.setManagerAddress(managerAddress);\n        }\n\n        String springXml = getProperty(properties, CanalConstants.getInstancSpringXmlKey(CanalConstants.GLOBAL_NAME));\n        if (StringUtils.isNotEmpty(springXml)) {\n            globalConfig.setSpringXml(springXml);\n        }\n\n        instanceGenerator = destination -> {\n            InstanceConfig config = instanceConfigs.get(destination);\n            if (config == null) {\n                throw new CanalServerException(\"can't find destination:\" + destination);\n            }\n\n            if (config.getMode().isManager()) {\n                PlainCanalInstanceGenerator instanceGenerator = new PlainCanalInstanceGenerator(properties);\n                instanceGenerator.setCanalConfigClient(managerClients.get(config.getManagerAddress()));\n                instanceGenerator.setSpringXml(config.getSpringXml());\n                return instanceGenerator.generate(destination);\n            } else if (config.getMode().isSpring()) {\n                SpringCanalInstanceGenerator instanceGenerator = new SpringCanalInstanceGenerator();\n                instanceGenerator.setSpringXml(config.getSpringXml());\n                return instanceGenerator.generate(destination);\n            } else {\n                throw new UnsupportedOperationException(\"unknown mode :\" + config.getMode());\n            }\n\n        };\n\n        return globalConfig;\n    }\n\n    private PlainCanalConfigClient getManagerClient(String managerAddress) {\n        return new PlainCanalConfigClient(managerAddress, this.adminUser, this.adminPasswd, this.registerIp, adminPort);\n    }\n\n    private void initInstanceConfig(Properties properties) {\n        String destinationStr = getDestinations(properties);\n        String[] destinations = StringUtils.split(destinationStr, CanalConstants.CANAL_DESTINATION_SPLIT);\n\n        for (String destination : destinations) {\n            InstanceConfig config = parseInstanceConfig(properties, destination);\n            InstanceConfig oldConfig = instanceConfigs.put(destination, config);\n\n            if (oldConfig != null) {\n                logger.warn(\"destination:{} old config:{} has replace by new config:{}\", destination, oldConfig, config);\n            }\n        }\n    }\n\n    private InstanceConfig parseInstanceConfig(Properties properties, String destination) {\n        String adminManagerAddress = getProperty(properties, CanalConstants.CANAL_ADMIN_MANAGER);\n        InstanceConfig config = new InstanceConfig(globalInstanceConfig);\n        String modeStr = getProperty(properties, CanalConstants.getInstanceModeKey(destination));\n        if (StringUtils.isNotEmpty(adminManagerAddress)) {\n            // 如果指定了manager地址,则强制适用manager\n            config.setMode(InstanceMode.MANAGER);\n        } else if (StringUtils.isNotEmpty(modeStr)) {\n            config.setMode(InstanceMode.valueOf(StringUtils.upperCase(modeStr)));\n        }\n\n        String lazyStr = getProperty(properties, CanalConstants.getInstancLazyKey(destination));\n        if (!StringUtils.isEmpty(lazyStr)) {\n            config.setLazy(Boolean.valueOf(lazyStr));\n        }\n\n        if (config.getMode().isManager()) {\n            String managerAddress = getProperty(properties, CanalConstants.getInstanceManagerAddressKey(destination));\n            if (StringUtils.isNotEmpty(managerAddress)) {\n                if (StringUtils.equals(managerAddress, \"${canal.admin.manager}\")) {\n                    managerAddress = adminManagerAddress;\n                }\n                config.setManagerAddress(managerAddress);\n            }\n        }\n\n        String springXml = getProperty(properties, CanalConstants.getInstancSpringXmlKey(destination));\n        if (StringUtils.isNotEmpty(springXml)) {\n            config.setSpringXml(springXml);\n        }\n\n        return config;\n    }\n\n    public static String getProperty(Properties properties, String key, String defaultValue) {\n        String value = getProperty(properties, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        } else {\n            return value;\n        }\n    }\n\n    public static String getProperty(Properties properties, String key) {\n        key = StringUtils.trim(key);\n        String value = System.getProperty(key);\n\n        if (value == null) {\n            value = System.getenv(key);\n        }\n\n        if (value == null) {\n            value = properties.getProperty(key);\n        }\n\n        return StringUtils.trim(value);\n    }\n\n    public static String getDestinations(Properties properties) {\n        String expr = getProperty(properties, CANAL_DESTINATIONS_EXPR);\n        if (StringUtils.isNotBlank(expr)) {\n            return parseExpr(expr);\n        } else {\n            return getProperty(properties, CANAL_DESTINATIONS);\n        }\n    }\n\n    private static String parseExpr(String expr) {\n        String prefix = StringUtils.substringBefore(expr, \"{\");\n        String range = StringUtils.substringAfter(expr, \"{\");\n        range = StringUtils.substringBefore(range, \"}\");\n\n        String regex = \"(\\\\d+)-(\\\\d+)\";\n        Pattern pattern = Pattern.compile(regex);\n        Matcher matcher = pattern.matcher(range);\n        if (matcher.find()) {\n            String head = matcher.group(1);\n            String tail = matcher.group(2);\n            int start = Integer.parseInt(head);\n            int end = Integer.parseInt(tail);\n\n            List<String> list = new ArrayList<>();\n            for (int i = start; i <= end; i++) {\n                String d = prefix + i;\n                list.add(d);\n            }\n            return list.stream().map(Object::toString).collect(Collectors.joining(\",\"));\n        } else {\n            throw new CanalServerException(\"invalid destinations expr \" + expr);\n        }\n    }\n\n    public void start() throws Throwable {\n        logger.info(\"## start the canal server[{}({}):{}]\", ip, registerIp, port);\n        // 创建整个canal的工作节点\n        final String path = ZookeeperPathUtils.getCanalClusterNode(registerIp + \":\" + port);\n        initCid(path);\n        if (zkclientx != null) {\n            this.zkclientx.subscribeStateChanges(new IZkStateListener() {\n\n                public void handleStateChanged(KeeperState state) throws Exception {\n\n                }\n\n                public void handleNewSession() throws Exception {\n                    initCid(path);\n                }\n\n                @Override\n                public void handleSessionEstablishmentError(Throwable error) throws Exception {\n                    logger.error(\"failed to connect to zookeeper\", error);\n                }\n            });\n        }\n        // 优先启动embedded服务\n        embeddedCanalServer.start();\n        // 尝试启动一下非lazy状态的通道\n        for (Map.Entry<String, InstanceConfig> entry : instanceConfigs.entrySet()) {\n            final String destination = entry.getKey();\n            InstanceConfig config = entry.getValue();\n            // 创建destination的工作节点\n            if (!embeddedCanalServer.isStart(destination)) {\n                // HA机制启动\n                ServerRunningMonitor runningMonitor = ServerRunningMonitors.getRunningMonitor(destination);\n                if (!config.getLazy() && !runningMonitor.isStart()) {\n                    runningMonitor.start();\n                }\n            }\n\n            if (autoScan) {\n                instanceConfigMonitors.get(config.getMode()).register(destination, defaultAction);\n            }\n        }\n\n        if (autoScan) {\n            instanceConfigMonitors.get(globalInstanceConfig.getMode()).start();\n            for (InstanceConfigMonitor monitor : instanceConfigMonitors.values()) {\n                if (!monitor.isStart()) {\n                    monitor.start();\n                }\n            }\n        }\n\n        // 启动网络接口\n        if (canalServer != null) {\n            canalServer.start();\n        }\n    }\n\n    public void stop() throws Throwable {\n\n        if (canalServer != null) {\n            canalServer.stop();\n        }\n\n        if (autoScan) {\n            for (InstanceConfigMonitor monitor : instanceConfigMonitors.values()) {\n                if (monitor.isStart()) {\n                    monitor.stop();\n                }\n            }\n        }\n\n        for (ServerRunningMonitor runningMonitor : ServerRunningMonitors.getRunningMonitors().values()) {\n            if (runningMonitor.isStart()) {\n                runningMonitor.stop();\n            }\n        }\n\n        // 释放canal的工作节点\n        releaseCid(ZookeeperPathUtils.getCanalClusterNode(registerIp + \":\" + port));\n        logger.info(\"## stop the canal server[{}({}):{}]\", ip, registerIp, port);\n\n        if (zkclientx != null) {\n            zkclientx.close();\n        }\n\n        // 关闭时清理缓存\n        if (instanceConfigs != null) {\n            instanceConfigs.clear();\n        }\n        if (managerClients != null) {\n            managerClients.clear();\n        }\n        if (instanceConfigMonitors != null) {\n            instanceConfigMonitors.clear();\n        }\n\n        ZkClientx.clearClients();\n\n        // 需要释放 CanalServerWithEmbedded 否则主线程退出后，进程无法自动完整退出...\n        if (embeddedCanalServer != null && embeddedCanalServer.isStart()) {\n            embeddedCanalServer.stop();\n        }\n    }\n\n    private void initCid(String path) {\n        // logger.info(\"## init the canalId = {}\", cid);\n        // 初始化系统目录\n        if (zkclientx != null) {\n            try {\n                zkclientx.createEphemeral(path);\n            } catch (ZkNoNodeException e) {\n                // 如果父目录不存在，则创建\n                String parentDir = path.substring(0, path.lastIndexOf('/'));\n                zkclientx.createPersistent(parentDir, true);\n                zkclientx.createEphemeral(path);\n            } catch (ZkNodeExistsException e) {\n                // ignore\n                // 因为第一次启动时创建了cid,但在stop/start的时可能会关闭和新建,允许出现NodeExists问题s\n            }\n\n        }\n    }\n\n    private void releaseCid(String path) {\n        // logger.info(\"## release the canalId = {}\", cid);\n        // 初始化系统目录\n        if (zkclientx != null) {\n            zkclientx.delete(path);\n        }\n    }\n\n    public CanalMQStarter getCanalMQStarter() {\n        return canalMQStarter;\n    }\n\n    public void setCanalMQStarter(CanalMQStarter canalMQStarter) {\n        this.canalMQStarter = canalMQStarter;\n    }\n\n    public Map<InstanceMode, InstanceConfigMonitor> getInstanceConfigMonitors() {\n        return instanceConfigMonitors;\n    }\n\n    public Map<String, InstanceConfig> getInstanceConfigs() {\n        return instanceConfigs;\n    }\n\n}\n"
  },
  {
    "path": "deployer/src/main/java/com/alibaba/otter/canal/deployer/CanalLauncher.java",
    "content": "package com.alibaba.otter.canal.deployer;\n\nimport java.io.FileInputStream;\nimport java.util.Properties;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.commons.lang.BooleanUtils;\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.common.utils.AddressUtils;\nimport com.alibaba.otter.canal.common.utils.NamedThreadFactory;\nimport com.alibaba.otter.canal.instance.manager.plain.PlainCanal;\nimport com.alibaba.otter.canal.instance.manager.plain.PlainCanalConfigClient;\n\n/**\n * canal独立版本启动的入口类\n *\n * @author jianghang 2012-11-6 下午05:20:49\n * @version 1.0.0\n */\npublic class CanalLauncher {\n\n    private static final String             CLASSPATH_URL_PREFIX = \"classpath:\";\n    private static final Logger             logger               = LoggerFactory.getLogger(CanalLauncher.class);\n    public static final CountDownLatch      runningLatch         = new CountDownLatch(1);\n    private static ScheduledExecutorService executor             = Executors.newScheduledThreadPool(1,\n                                                                     new NamedThreadFactory(\"canal-server-scan\"));\n\n    public static void main(String[] args) {\n        try {\n            logger.info(\"## set default uncaught exception handler\");\n            setGlobalUncaughtExceptionHandler();\n\n            // 支持rocketmq client 配置日志路径\n            System.setProperty(\"rocketmq.client.logUseSlf4j\",\"true\");\n\n            logger.info(\"## load canal configurations\");\n            String conf = System.getProperty(\"canal.conf\", \"classpath:canal.properties\");\n            Properties properties = new Properties();\n            if (conf.startsWith(CLASSPATH_URL_PREFIX)) {\n                conf = StringUtils.substringAfter(conf, CLASSPATH_URL_PREFIX);\n                properties.load(CanalLauncher.class.getClassLoader().getResourceAsStream(conf));\n            } else {\n                properties.load(new FileInputStream(conf));\n            }\n\n            final CanalStarter canalStater = new CanalStarter(properties);\n            String managerAddress = CanalController.getProperty(properties, CanalConstants.CANAL_ADMIN_MANAGER);\n            if (StringUtils.isNotEmpty(managerAddress)) {\n                String user = CanalController.getProperty(properties, CanalConstants.CANAL_ADMIN_USER);\n                String passwd = CanalController.getProperty(properties, CanalConstants.CANAL_ADMIN_PASSWD);\n                if (StringUtils.isEmpty(passwd)) {\n                    throw new IllegalArgumentException(\n                        \"canal.admin.passwd is empty , pls check https://github.com/alibaba/canal/issues/4941\");\n                }\n                String adminPort = CanalController.getProperty(properties, CanalConstants.CANAL_ADMIN_PORT, \"11110\");\n                boolean autoRegister = BooleanUtils.toBoolean(CanalController.getProperty(properties,\n                    CanalConstants.CANAL_ADMIN_AUTO_REGISTER));\n                String autoCluster = CanalController.getProperty(properties, CanalConstants.CANAL_ADMIN_AUTO_CLUSTER);\n                String name = CanalController.getProperty(properties, CanalConstants.CANAL_ADMIN_REGISTER_NAME);\n                if (StringUtils.isEmpty(name)) {\n                    name = AddressUtils.getHostName();\n                }\n\n                String registerIp = CanalController.getProperty(properties, CanalConstants.CANAL_REGISTER_IP);\n                if (StringUtils.isEmpty(registerIp)) {\n                    registerIp = AddressUtils.getHostIp();\n                }\n                final PlainCanalConfigClient configClient = new PlainCanalConfigClient(managerAddress,\n                    user,\n                    passwd,\n                    registerIp,\n                    Integer.parseInt(adminPort),\n                    autoRegister,\n                    autoCluster,\n                    name);\n                PlainCanal canalConfig = configClient.findServer(null);\n                if (canalConfig == null) {\n                    throw new IllegalArgumentException(\"managerAddress:\" + managerAddress\n                                                       + \" can't not found config for [\" + registerIp + \":\" + adminPort\n                                                       + \"]\");\n                }\n                Properties managerProperties = canalConfig.getProperties();\n                // merge local\n                managerProperties.putAll(properties);\n                int scanIntervalInSecond = Integer.valueOf(CanalController.getProperty(managerProperties,\n                    CanalConstants.CANAL_AUTO_SCAN_INTERVAL,\n                    \"5\"));\n                executor.scheduleWithFixedDelay(new Runnable() {\n\n                    private PlainCanal lastCanalConfig;\n\n                    public void run() {\n                        try {\n                            if (lastCanalConfig == null) {\n                                lastCanalConfig = configClient.findServer(null);\n                            } else {\n                                PlainCanal newCanalConfig = configClient.findServer(lastCanalConfig.getMd5());\n                                if (newCanalConfig != null) {\n                                    // 远程配置canal.properties修改重新加载整个应用\n                                    canalStater.stop();\n                                    Properties managerProperties = newCanalConfig.getProperties();\n                                    // merge local\n                                    managerProperties.putAll(properties);\n                                    canalStater.setProperties(managerProperties);\n                                    canalStater.start();\n\n                                    lastCanalConfig = newCanalConfig;\n                                }\n                            }\n\n                        } catch (Throwable e) {\n                            logger.error(\"scan failed\", e);\n                        }\n                    }\n\n                }, 0, scanIntervalInSecond, TimeUnit.SECONDS);\n                canalStater.setProperties(managerProperties);\n            } else {\n                canalStater.setProperties(properties);\n            }\n\n            canalStater.start();\n            runningLatch.await();\n            executor.shutdownNow();\n        } catch (Throwable e) {\n            logger.error(\"## Something goes wrong when starting up the canal Server:\", e);\n        }\n    }\n\n    private static void setGlobalUncaughtExceptionHandler() {\n        Thread.setDefaultUncaughtExceptionHandler((t, e) -> logger.error(\"UnCaughtException\", e));\n    }\n\n}\n"
  },
  {
    "path": "deployer/src/main/java/com/alibaba/otter/canal/deployer/CanalStarter.java",
    "content": "package com.alibaba.otter.canal.deployer;\n\nimport com.alibaba.otter.canal.connector.core.spi.ProxyCanalMQProducer;\nimport java.util.Properties;\n\nimport com.alibaba.otter.canal.connector.core.config.MQProperties;\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.admin.netty.CanalAdminWithNetty;\nimport com.alibaba.otter.canal.connector.core.spi.CanalMQProducer;\nimport com.alibaba.otter.canal.connector.core.spi.ExtensionLoader;\nimport com.alibaba.otter.canal.deployer.admin.CanalAdminController;\nimport com.alibaba.otter.canal.server.CanalMQStarter;\n\n/**\n * Canal server 启动类\n *\n * @author rewerma 2020-01-27\n * @version 1.0.2\n */\npublic class CanalStarter {\n\n    private static final Logger logger = LoggerFactory.getLogger(CanalStarter.class);\n\n    private static final String CONNECTOR_SPI_DIR = \"/plugin\";\n    private static final String CONNECTOR_STANDBY_SPI_DIR = \"/canal/plugin\";\n\n    private CanalController controller = null;\n    private CanalMQProducer canalMQProducer = null;\n    private Thread shutdownThread = null;\n    private CanalMQStarter canalMQStarter = null;\n    private volatile Properties properties;\n    private volatile boolean running = false;\n\n    private CanalAdminWithNetty canalAdmin;\n\n    public CanalStarter(Properties properties) {\n        this.properties = properties;\n    }\n\n    public boolean isRunning() {\n        return running;\n    }\n\n    public Properties getProperties() {\n        return properties;\n    }\n\n    public void setProperties(Properties properties) {\n        this.properties = properties;\n    }\n\n    public CanalController getController() {\n        return controller;\n    }\n\n    /**\n     * 启动方法\n     *\n     * @throws Throwable\n     */\n    public synchronized void start() throws Throwable {\n        String serverMode = CanalController.getProperty(properties, CanalConstants.CANAL_SERVER_MODE);\n        if (!\"tcp\".equalsIgnoreCase(serverMode)) {\n            ExtensionLoader<CanalMQProducer> loader = ExtensionLoader.getExtensionLoader(CanalMQProducer.class);\n            canalMQProducer = loader\n                .getExtension(serverMode.toLowerCase(), CONNECTOR_SPI_DIR, CONNECTOR_STANDBY_SPI_DIR);\n            if (canalMQProducer != null) {\n                canalMQProducer =  new ProxyCanalMQProducer(canalMQProducer);\n                canalMQProducer.init(properties);\n            }\n        }\n\n        if (canalMQProducer != null) {\n            MQProperties mqProperties = canalMQProducer.getMqProperties();\n            // disable netty\n            System.setProperty(CanalConstants.CANAL_WITHOUT_NETTY, \"true\");\n            if (mqProperties.isFlatMessage()) {\n                // 设置为raw避免ByteString->Entry的二次解析\n                System.setProperty(\"canal.instance.memory.rawEntry\", \"false\");\n            }\n        }\n\n        logger.info(\"## start the canal server.\");\n        controller = new CanalController(properties);\n        controller.start();\n        logger.info(\"## the canal server is running now ......\");\n        shutdownThread = new Thread(() -> {\n            try {\n                logger.info(\"## stop the canal server\");\n                controller.stop();\n                CanalLauncher.runningLatch.countDown();\n            } catch (Throwable e) {\n                logger.warn(\"##something goes wrong when stopping canal Server:\", e);\n            } finally {\n                logger.info(\"## canal server is down.\");\n            }\n        });\n        Runtime.getRuntime().addShutdownHook(shutdownThread);\n\n        if (canalMQProducer != null) {\n            canalMQStarter = new CanalMQStarter(canalMQProducer);\n            String destinations = CanalController.getDestinations(properties);\n            canalMQStarter.start(destinations);\n            controller.setCanalMQStarter(canalMQStarter);\n        }\n\n        // start canalAdmin\n        String port = CanalController.getProperty(properties, CanalConstants.CANAL_ADMIN_PORT);\n        if (canalAdmin == null && StringUtils.isNotEmpty(port)) {\n            String user = CanalController.getProperty(properties, CanalConstants.CANAL_ADMIN_USER);\n            String passwd = CanalController.getProperty(properties, CanalConstants.CANAL_ADMIN_PASSWD);\n            CanalAdminController canalAdmin = new CanalAdminController(this);\n            canalAdmin.setUser(user);\n            canalAdmin.setPasswd(passwd);\n            String ip = CanalController.getProperty(properties, CanalConstants.CANAL_IP);\n\n            logger.debug(\"canal admin port:{}, canal admin user:{}, canal admin password: {}, canal ip:{}\",\n                port,\n                user,\n                passwd,\n                ip);\n\n            CanalAdminWithNetty canalAdminWithNetty = CanalAdminWithNetty.instance();\n            canalAdminWithNetty.setCanalAdmin(canalAdmin);\n            canalAdminWithNetty.setPort(Integer.parseInt(port));\n            canalAdminWithNetty.setIp(ip);\n            canalAdminWithNetty.start();\n            this.canalAdmin = canalAdminWithNetty;\n        }\n\n        running = true;\n    }\n\n    public synchronized void stop() throws Throwable {\n        stop(false);\n    }\n\n    /**\n     * 销毁方法，远程配置变更时调用\n     *\n     * @throws Throwable\n     */\n    public synchronized void stop(boolean stopByAdmin) throws Throwable {\n        if (!stopByAdmin && canalAdmin != null) {\n            canalAdmin.stop();\n            canalAdmin = null;\n        }\n\n        if (controller != null) {\n            controller.stop();\n            controller = null;\n        }\n        if (shutdownThread != null) {\n            Runtime.getRuntime().removeShutdownHook(shutdownThread);\n            shutdownThread = null;\n        }\n        if (canalMQProducer != null && canalMQStarter != null) {\n            canalMQStarter.destroy();\n            canalMQStarter = null;\n            canalMQProducer = null;\n        }\n        running = false;\n    }\n}\n"
  },
  {
    "path": "deployer/src/main/java/com/alibaba/otter/canal/deployer/InstanceConfig.java",
    "content": "package com.alibaba.otter.canal.deployer;\n\nimport org.apache.commons.lang.builder.ToStringBuilder;\n\nimport com.alibaba.otter.canal.common.utils.CanalToStringStyle;\n\n/**\n * 启动的相关配置\n * \n * @author jianghang 2012-11-8 下午02:50:54\n * @version 1.0.0\n */\npublic class InstanceConfig {\n\n    private InstanceConfig globalConfig;\n    private InstanceMode   mode;\n    private Boolean        lazy;\n    private String         managerAddress;\n    private String         springXml;\n\n    public InstanceConfig(){\n\n    }\n\n    public InstanceConfig(InstanceConfig globalConfig){\n        this.globalConfig = globalConfig;\n    }\n\n    public static enum InstanceMode {\n        SPRING, MANAGER;\n\n        public boolean isSpring() {\n            return this == InstanceMode.SPRING;\n        }\n\n        public boolean isManager() {\n            return this == InstanceMode.MANAGER;\n        }\n    }\n\n    public Boolean getLazy() {\n        if (lazy == null && globalConfig != null) {\n            return globalConfig.getLazy();\n        } else {\n            return lazy;\n        }\n    }\n\n    public void setLazy(Boolean lazy) {\n        this.lazy = lazy;\n    }\n\n    public InstanceMode getMode() {\n        if (mode == null && globalConfig != null) {\n            return globalConfig.getMode();\n        } else {\n            return mode;\n        }\n    }\n\n    public void setMode(InstanceMode mode) {\n        this.mode = mode;\n    }\n\n    public String getManagerAddress() {\n        if (managerAddress == null && globalConfig != null) {\n            return globalConfig.getManagerAddress();\n        } else {\n            return managerAddress;\n        }\n    }\n\n    public void setManagerAddress(String managerAddress) {\n        this.managerAddress = managerAddress;\n    }\n\n    public String getSpringXml() {\n        if (springXml == null && globalConfig != null) {\n            return globalConfig.getSpringXml();\n        } else {\n            return springXml;\n        }\n    }\n\n    public void setSpringXml(String springXml) {\n        this.springXml = springXml;\n    }\n\n    public String toString() {\n        return ToStringBuilder.reflectionToString(this, CanalToStringStyle.DEFAULT_STYLE);\n    }\n\n}\n"
  },
  {
    "path": "deployer/src/main/java/com/alibaba/otter/canal/deployer/admin/CanalAdminController.java",
    "content": "package com.alibaba.otter.canal.deployer.admin;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\nimport org.apache.commons.io.filefilter.TrueFileFilter;\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.admin.CanalAdmin;\nimport com.alibaba.otter.canal.common.utils.FileUtils;\nimport com.alibaba.otter.canal.deployer.CanalStarter;\nimport com.alibaba.otter.canal.deployer.InstanceConfig;\nimport com.alibaba.otter.canal.deployer.monitor.InstanceAction;\nimport com.alibaba.otter.canal.deployer.monitor.InstanceConfigMonitor;\nimport com.alibaba.otter.canal.deployer.monitor.ManagerInstanceConfigMonitor;\nimport com.alibaba.otter.canal.deployer.monitor.SpringInstanceConfigMonitor;\nimport com.alibaba.otter.canal.instance.core.CanalInstance;\nimport com.alibaba.otter.canal.protocol.SecurityUtil;\nimport com.alibaba.otter.canal.server.embedded.CanalServerWithEmbedded;\nimport com.google.common.base.Joiner;\n\n/**\n * 提供canal admin的管理操作\n * \n * @author agapple 2019年8月24日 下午11:39:01\n * @since 1.1.4\n */\npublic class CanalAdminController implements CanalAdmin {\n\n    private static final Logger logger = LoggerFactory.getLogger(CanalAdminController.class);\n    private String              user;\n    private String              passwd;\n    private CanalStarter        canalStater;\n\n    public CanalAdminController(CanalStarter canalStater){\n        this.canalStater = canalStater;\n    }\n\n    @Override\n    public boolean check() {\n        return canalStater.isRunning();\n    }\n\n    @Override\n    public synchronized boolean start() {\n        try {\n            if (!canalStater.isRunning()) {\n                canalStater.start();\n                return true;\n            }\n        } catch (Throwable e) {\n            logger.error(e.getMessage(), e);\n        }\n        return false;\n    }\n\n    @Override\n    public synchronized boolean stop() {\n        try {\n            if (canalStater.isRunning()) {\n                canalStater.stop(true);\n                return true;\n            }\n        } catch (Throwable e) {\n            logger.error(e.getMessage(), e);\n        }\n        return false;\n    }\n\n    @Override\n    public synchronized boolean restart() {\n        stop();\n        return start();\n    }\n\n    @Override\n    public boolean auth(String user, String passwd, byte[] seed) {\n        // 如果user/passwd密码为空,则任何用户账户都能登录\n        if ((StringUtils.isEmpty(this.user) || StringUtils.equals(this.user, user))) {\n            if (StringUtils.isEmpty(this.passwd)) {\n                return true;\n            } else if (StringUtils.isEmpty(passwd)) {\n                // 如果server密码有配置,客户端密码为空,则拒绝\n                return false;\n            }\n\n            try {\n                byte[] passForClient = SecurityUtil.hexStr2Bytes(passwd);\n                return SecurityUtil.scrambleServerAuth(passForClient, SecurityUtil.hexStr2Bytes(this.passwd), seed);\n            } catch (NoSuchAlgorithmException e) {\n                return false;\n            }\n        }\n\n        return false;\n    }\n\n    @Override\n    public String getRunningInstances() {\n        try {\n            Map<String, CanalInstance> instances = CanalServerWithEmbedded.instance().getCanalInstances();\n            List<String> runningInstances = new ArrayList<>();\n            instances.forEach((destination, instance) -> {\n                if (instance.isStart()) {\n                    runningInstances.add(destination);\n                }\n            });\n\n            return Joiner.on(\",\").join(runningInstances);\n        } catch (Throwable e) {\n            logger.error(e.getMessage(), e);\n        }\n        return \"\";\n    }\n\n    @Override\n    public boolean checkInstance(String destination) {\n        Map<String, CanalInstance> instances = CanalServerWithEmbedded.instance().getCanalInstances();\n        if (instances == null || !instances.containsKey(destination)) {\n            return false;\n        } else {\n            CanalInstance instance = instances.get(destination);\n            return instance.isStart();\n        }\n    }\n\n    @Override\n    public boolean startInstance(String destination) {\n        try {\n            InstanceAction instanceAction = getInstanceAction(destination);\n            if (instanceAction != null) {\n                instanceAction.start(destination);\n                return true;\n            }\n        } catch (Throwable e) {\n            logger.error(e.getMessage(), e);\n        }\n        return false;\n    }\n\n    @Override\n    public boolean stopInstance(String destination) {\n        try {\n            InstanceAction instanceAction = getInstanceAction(destination);\n            if (instanceAction != null) {\n                instanceAction.stop(destination);\n                return true;\n            }\n        } catch (Throwable e) {\n            logger.error(e.getMessage(), e);\n        }\n        return false;\n    }\n\n    @Override\n    public boolean releaseInstance(String destination) {\n        try {\n            InstanceAction instanceAction = getInstanceAction(destination);\n            if (instanceAction != null) {\n                instanceAction.release(destination);\n                return true;\n            }\n        } catch (Throwable e) {\n            logger.error(e.getMessage(), e);\n        }\n        return false;\n    }\n\n    @Override\n    public boolean restartInstance(String destination) {\n        try {\n            InstanceAction instanceAction = getInstanceAction(destination);\n            if (instanceAction != null) {\n                instanceAction.reload(destination);\n                return true;\n            }\n        } catch (Throwable e) {\n            logger.error(e.getMessage(), e);\n        }\n        return false;\n    }\n\n    @Override\n    public String listCanalLog() {\n        Collection<File> files = org.apache.commons.io.FileUtils.listFiles(new File(\"../logs/canal/\"),\n            TrueFileFilter.TRUE,\n            TrueFileFilter.TRUE);\n        List<String> names = files.stream().map(File::getName).collect(Collectors.toList());\n        return Joiner.on(\",\").join(names);\n    }\n\n    @Override\n    public String canalLog(int lines) {\n        return FileUtils.readFileFromOffset(\"../logs/canal/canal.log\", lines, \"UTF-8\");\n    }\n\n    @Override\n    public String listInstanceLog(String destination) {\n        // 校验destination\n        String desPath = FileUtils.validateFileName(\"../logs\", destination);\n\n        Collection<File> files = org.apache.commons.io.FileUtils.listFiles(new File(desPath),\n            TrueFileFilter.TRUE,\n            TrueFileFilter.TRUE);\n        List<String> names = files.stream().map(File::getName).collect(Collectors.toList());\n        return Joiner.on(\",\").join(names);\n    }\n\n    @Override\n    public String instanceLog(String destination, String fileName, int lines) {\n        if (StringUtils.isEmpty(fileName)) {\n            fileName = destination + \".log\";\n        }\n\n        // 分别校验destination和fileName目录\n        String desPath = FileUtils.validateFileName(\"../logs\", destination);\n        String fullPath = FileUtils.validateFileName(desPath , fileName);\n\n        return FileUtils.readFileFromOffset(fullPath, lines, \"UTF-8\");\n    }\n\n    private InstanceAction getInstanceAction(String destination) {\n        Map<InstanceConfig.InstanceMode, InstanceConfigMonitor> monitors = canalStater.getController()\n            .getInstanceConfigMonitors();\n\n        InstanceAction instanceAction = null;\n        if (monitors.containsKey(InstanceConfig.InstanceMode.SPRING)) {\n            SpringInstanceConfigMonitor monitor = (SpringInstanceConfigMonitor) monitors.get(InstanceConfig.InstanceMode.SPRING);\n            Map<String, InstanceAction> instanceActions = monitor.getActions();\n            instanceAction = instanceActions.get(destination);\n        }\n\n        if (instanceAction != null) {\n            return instanceAction;\n        }\n\n        if (monitors.containsKey(InstanceConfig.InstanceMode.MANAGER)) {\n            ManagerInstanceConfigMonitor monitor = (ManagerInstanceConfigMonitor) monitors.get(InstanceConfig.InstanceMode.MANAGER);\n            Map<String, InstanceAction> instanceActions = monitor.getActions();\n            instanceAction = instanceActions.get(destination);\n        }\n        return instanceAction;\n    }\n\n    public void setUser(String user) {\n        this.user = user;\n    }\n\n    public void setPasswd(String passwd) {\n        this.passwd = passwd;\n    }\n\n    public void setCanalStater(CanalStarter canalStater) {\n        this.canalStater = canalStater;\n    }\n\n}\n"
  },
  {
    "path": "deployer/src/main/java/com/alibaba/otter/canal/deployer/monitor/InstanceAction.java",
    "content": "package com.alibaba.otter.canal.deployer.monitor;\n\n/**\n * config配置变化\n * \n * @author jianghang 2013-2-18 下午01:19:29\n * @version 1.0.1\n */\npublic interface InstanceAction {\n\n    /**\n     * 启动destination\n     */\n    void start(String destination);\n\n    /**\n     * 主动释放destination运行\n     */\n    void release(String destination);\n\n    /**\n     * 停止destination\n     */\n    void stop(String destination);\n\n    /**\n     * 重载destination，可能需要stop,start操作，或者只是更新下内存配置\n     */\n    void reload(String destination);\n}\n"
  },
  {
    "path": "deployer/src/main/java/com/alibaba/otter/canal/deployer/monitor/InstanceConfigMonitor.java",
    "content": "package com.alibaba.otter.canal.deployer.monitor;\n\nimport com.alibaba.otter.canal.common.CanalLifeCycle;\n\n/**\n * 监听instance file的文件变化，触发instance start/stop等操作\n * \n * @author jianghang 2013-2-6 下午06:19:56\n * @version 1.0.1\n */\npublic interface InstanceConfigMonitor extends CanalLifeCycle {\n\n    void register(String destination, InstanceAction action);\n\n    void unregister(String destination);\n}\n"
  },
  {
    "path": "deployer/src/main/java/com/alibaba/otter/canal/deployer/monitor/ManagerInstanceConfigMonitor.java",
    "content": "package com.alibaba.otter.canal.deployer.monitor;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.common.AbstractCanalLifeCycle;\nimport com.alibaba.otter.canal.common.CanalLifeCycle;\nimport com.alibaba.otter.canal.common.utils.NamedThreadFactory;\nimport com.alibaba.otter.canal.instance.manager.plain.PlainCanal;\nimport com.alibaba.otter.canal.instance.manager.plain.PlainCanalConfigClient;\nimport com.google.common.collect.Lists;\nimport com.google.common.collect.MapMaker;\nimport com.google.common.collect.MigrateMap;\n\n/**\n * 基于manager配置的实现\n *\n * @author agapple 2019年8月26日 下午10:00:20\n * @since 1.1.4\n */\npublic class ManagerInstanceConfigMonitor extends AbstractCanalLifeCycle implements InstanceConfigMonitor, CanalLifeCycle {\n\n    private static final Logger         logger               = LoggerFactory.getLogger(ManagerInstanceConfigMonitor.class);\n    private long                        scanIntervalInSecond = 5;\n    private InstanceAction              defaultAction        = null;\n    private Map<String, InstanceAction> actions              = new MapMaker().makeMap();\n    private Map<String, PlainCanal>     configs              = MigrateMap.makeComputingMap(destination -> new PlainCanal());\n    private ScheduledExecutorService    executor             = Executors.newScheduledThreadPool(1,\n                                                                 new NamedThreadFactory(\"canal-instance-scan\"));\n\n    private volatile boolean            isFirst              = true;\n    private PlainCanalConfigClient      configClient;\n\n    public void start() {\n        super.start();\n        executor.scheduleWithFixedDelay(() -> {\n            try {\n                scan();\n                if (isFirst) {\n                    isFirst = false;\n                }\n            } catch (Throwable e) {\n                logger.error(\"scan failed\", e);\n            }\n        }, 0, scanIntervalInSecond, TimeUnit.SECONDS);\n    }\n\n    public void stop() {\n        super.stop();\n        executor.shutdownNow();\n        actions.clear();\n    }\n\n    public void register(String destination, InstanceAction action) {\n        if (action != null) {\n            actions.put(destination, action);\n        } else {\n            actions.put(destination, defaultAction);\n        }\n    }\n\n    public void unregister(String destination) {\n        actions.remove(destination);\n    }\n\n    private void scan() {\n        String instances = configClient.findInstances(null);\n        if (instances == null) {\n            return;\n        }\n\n        final List<String> is = Lists.newArrayList(StringUtils.split(instances, ','));\n        List<String> start = new ArrayList<>();\n        List<String> stop = new ArrayList<>();\n        List<String> restart = new ArrayList<>();\n        for (String instance : is) {\n            if (!configs.containsKey(instance)) {\n                PlainCanal newPlainCanal = configClient.findInstance(instance, null);\n                if (newPlainCanal != null) {\n                    configs.put(instance, newPlainCanal);\n                    start.add(instance);\n                }\n            } else {\n                PlainCanal plainCanal = configs.get(instance);\n                PlainCanal newPlainCanal = configClient.findInstance(instance, plainCanal.getMd5());\n                if (newPlainCanal != null) {\n                    // 配置有变化\n                    restart.add(instance);\n                    configs.put(instance, newPlainCanal);\n                }\n            }\n        }\n\n        configs.forEach((instance, plainCanal) -> {\n            if (!is.contains(instance)) {\n                stop.add(instance);\n            }\n        });\n\n        stop.forEach(instance -> {\n            notifyStop(instance);\n        });\n\n        restart.forEach(instance -> {\n            notifyReload(instance);\n        });\n\n        start.forEach(instance -> {\n            notifyStart(instance);\n        });\n\n    }\n\n    private void notifyStart(String destination) {\n        try {\n            defaultAction.start(destination);\n            actions.put(destination, defaultAction);\n            // 启动成功后记录配置文件信息\n        } catch (Throwable e) {\n            logger.error(String.format(\"scan add found[%s] but start failed\", destination), e);\n        }\n    }\n\n    private void notifyStop(String destination) {\n        InstanceAction action = actions.remove(destination);\n        if (action != null) {\n            try {\n                action.stop(destination);\n                configs.remove(destination);\n            } catch (Throwable e) {\n                logger.error(String.format(\"scan delete found[%s] but stop failed\", destination), e);\n                actions.put(destination, action);// 再重新加回去，下一次scan时再执行删除\n            }\n        }\n    }\n\n    private void notifyReload(String destination) {\n        InstanceAction action = actions.get(destination);\n        if (action != null) {\n            try {\n                action.reload(destination);\n            } catch (Throwable e) {\n                logger.error(String.format(\"scan reload found[%s] but reload failed\", destination), e);\n            }\n        }\n    }\n\n    public void release(String destination) {\n        InstanceAction action = actions.remove(destination);\n        if (action != null) {\n            try {\n                configs.remove(destination);\n            } catch (Throwable e) {\n                logger.error(String.format(\"scan delete found[%s] but stop failed\", destination), e);\n                actions.put(destination, action);// 再重新加回去，下一次scan时再执行删除\n            }\n        }\n    }\n\n    public void setDefaultAction(InstanceAction defaultAction) {\n        this.defaultAction = defaultAction;\n    }\n\n    public void setScanIntervalInSecond(long scanIntervalInSecond) {\n        this.scanIntervalInSecond = scanIntervalInSecond;\n    }\n\n    public void setConfigClient(PlainCanalConfigClient configClient) {\n        this.configClient = configClient;\n    }\n\n    public Map<String, InstanceAction> getActions() {\n        return actions;\n    }\n\n}\n"
  },
  {
    "path": "deployer/src/main/java/com/alibaba/otter/canal/deployer/monitor/SpringInstanceConfigMonitor.java",
    "content": "package com.alibaba.otter.canal.deployer.monitor;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\n\nimport com.alibaba.otter.canal.common.AbstractCanalLifeCycle;\nimport com.alibaba.otter.canal.common.CanalLifeCycle;\nimport com.alibaba.otter.canal.common.utils.NamedThreadFactory;\nimport com.google.common.collect.MapMaker;\nimport com.google.common.collect.MigrateMap;\n\n/**\n * 监听基于spring配置的instance变化\n * \n * @author jianghang 2013-2-6 下午06:23:55\n * @version 1.0.1\n */\npublic class SpringInstanceConfigMonitor extends AbstractCanalLifeCycle implements InstanceConfigMonitor, CanalLifeCycle {\n\n    private static final Logger              logger               = LoggerFactory.getLogger(SpringInstanceConfigMonitor.class);\n    private String                           rootConf;\n    // 扫描周期，单位秒\n    private long                             scanIntervalInSecond = 5;\n    private InstanceAction                   defaultAction        = null;\n    private Map<String, InstanceAction>      actions              = new MapMaker().makeMap();\n    private Map<String, InstanceConfigFiles> lastFiles            = MigrateMap.makeComputingMap(InstanceConfigFiles::new);\n    private ScheduledExecutorService         executor             = Executors.newScheduledThreadPool(1,\n                                                                      new NamedThreadFactory(\"canal-instance-scan\"));\n\n    private volatile boolean                 isFirst              = true;\n\n    public Map<String, InstanceAction> getActions() {\n        return actions;\n    }\n\n    public void start() {\n        super.start();\n        Assert.notNull(rootConf, \"root conf dir is null!\");\n\n        executor.scheduleWithFixedDelay(() -> {\n            try {\n                scan();\n                if (isFirst) {\n                    isFirst = false;\n                }\n            } catch (Throwable e) {\n                logger.error(\"scan failed\", e);\n            }\n        }, 0, scanIntervalInSecond, TimeUnit.SECONDS);\n    }\n\n    public void stop() {\n        super.stop();\n        executor.shutdownNow();\n        actions.clear();\n        lastFiles.clear();\n    }\n\n    public void register(String destination, InstanceAction action) {\n        if (action != null) {\n            actions.put(destination, action);\n        } else {\n            actions.put(destination, defaultAction);\n        }\n    }\n\n    public void unregister(String destination) {\n        actions.remove(destination);\n    }\n\n    public void setRootConf(String rootConf) {\n        this.rootConf = rootConf;\n    }\n\n    private void scan() {\n        File rootdir = new File(rootConf);\n        if (!rootdir.exists()) {\n            return;\n        }\n\n        File[] instanceDirs = rootdir.listFiles(pathname -> {\n            String filename = pathname.getName();\n            return pathname.isDirectory() && !\"spring\".equalsIgnoreCase(filename);\n        });\n\n        // 扫描目录的新增\n        Set<String> currentInstanceNames = new HashSet<>();\n\n        // 判断目录内文件的变化\n        for (File instanceDir : instanceDirs) {\n            String destination = instanceDir.getName();\n            currentInstanceNames.add(destination);\n            File[] instanceConfigs = instanceDir.listFiles((dir, name) -> {\n                // return !StringUtils.endsWithIgnoreCase(name, \".dat\");\n                // 限制一下，只针对instance.properties文件,避免因为.svn或者其他生成的临时文件导致出现reload\n                return StringUtils.equalsIgnoreCase(name, \"instance.properties\");\n            });\n\n            if (!actions.containsKey(destination) && instanceConfigs.length > 0) {\n                // 存在合法的instance.properties，并且第一次添加时，进行启动操作\n                notifyStart(instanceDir, destination, instanceConfigs);\n            } else if (actions.containsKey(destination)) {\n                // 历史已经启动过\n                if (instanceConfigs.length == 0) { // 如果不存在合法的instance.properties\n                    notifyStop(destination);\n                } else {\n                    InstanceConfigFiles lastFile = lastFiles.get(destination);\n                    // 历史启动过 所以配置文件信息必然存在\n                    if (!isFirst && CollectionUtils.isEmpty(lastFile.getInstanceFiles())) {\n                        logger.error(\"[{}] is started, but not found instance file info.\", destination);\n                    }\n\n                    boolean hasChanged = judgeFileChanged(instanceConfigs, lastFile.getInstanceFiles());\n                    // 通知变化\n                    if (hasChanged) {\n                        notifyReload(destination);\n                    }\n\n                    if (hasChanged || CollectionUtils.isEmpty(lastFile.getInstanceFiles())) {\n                        // 更新内容\n                        List<FileInfo> newFileInfo = new ArrayList<>();\n                        for (File instanceConfig : instanceConfigs) {\n                            newFileInfo.add(new FileInfo(instanceConfig.getName(), instanceConfig.lastModified()));\n                        }\n\n                        lastFile.setInstanceFiles(newFileInfo);\n                    }\n                }\n            }\n\n        }\n\n        // 判断目录是否删除\n        Set<String> deleteInstanceNames = new HashSet<>();\n        for (String destination : actions.keySet()) {\n            if (!currentInstanceNames.contains(destination)) {\n                deleteInstanceNames.add(destination);\n            }\n        }\n        for (String deleteInstanceName : deleteInstanceNames) {\n            notifyStop(deleteInstanceName);\n        }\n    }\n\n    private void notifyStart(File instanceDir, String destination, File[] instanceConfigs) {\n        try {\n            defaultAction.start(destination);\n            actions.put(destination, defaultAction);\n\n            // 启动成功后记录配置文件信息\n            InstanceConfigFiles lastFile = lastFiles.get(destination);\n            List<FileInfo> newFileInfo = new ArrayList<>();\n            for (File instanceConfig : instanceConfigs) {\n                newFileInfo.add(new FileInfo(instanceConfig.getName(), instanceConfig.lastModified()));\n            }\n            lastFile.setInstanceFiles(newFileInfo);\n        } catch (Throwable e) {\n            logger.error(String.format(\"scan add found[%s] but start failed\", destination), e);\n        }\n    }\n\n    private void notifyStop(String destination) {\n        InstanceAction action = actions.remove(destination);\n        if (action != null) {\n            try {\n                action.stop(destination);\n                lastFiles.remove(destination);\n            } catch (Throwable e) {\n                logger.error(String.format(\"scan delete found[%s] but stop failed\", destination), e);\n                actions.put(destination, action);// 再重新加回去，下一次scan时再执行删除\n            }\n        }\n    }\n\n    private void notifyReload(String destination) {\n        InstanceAction action = actions.get(destination);\n        if (action != null) {\n            try {\n                action.reload(destination);\n            } catch (Throwable e) {\n                logger.error(String.format(\"scan reload found[%s] but reload failed\", destination), e);\n            }\n        }\n    }\n\n    private boolean judgeFileChanged(File[] instanceConfigs, List<FileInfo> fileInfos) {\n        boolean hasChanged = false;\n        for (File instanceConfig : instanceConfigs) {\n            for (FileInfo fileInfo : fileInfos) {\n                if (instanceConfig.getName().equals(fileInfo.getName())) {\n                    hasChanged |= (instanceConfig.lastModified() != fileInfo.getLastModified());\n                    if (hasChanged) {\n                        return hasChanged;\n                    }\n                }\n            }\n        }\n\n        return hasChanged;\n    }\n\n    public void setDefaultAction(InstanceAction defaultAction) {\n        this.defaultAction = defaultAction;\n    }\n\n    public void setScanIntervalInSecond(long scanIntervalInSecond) {\n        this.scanIntervalInSecond = scanIntervalInSecond;\n    }\n\n    public static class InstanceConfigFiles {\n\n        private String         destination;                              // instance\n                                                                          // name\n        private List<FileInfo> springFile    = new ArrayList<>(); // spring的instance\n                                                                          // xml\n        private FileInfo       rootFile;                                 // canal.properties\n        private List<FileInfo> instanceFiles = new ArrayList<>(); // instance对应的配置\n\n        public InstanceConfigFiles(String destination){\n            this.destination = destination;\n        }\n\n        public String getDestination() {\n            return destination;\n        }\n\n        public void setDestination(String destination) {\n            this.destination = destination;\n        }\n\n        public List<FileInfo> getSpringFile() {\n            return springFile;\n        }\n\n        public void setSpringFile(List<FileInfo> springFile) {\n            this.springFile = springFile;\n        }\n\n        public FileInfo getRootFile() {\n            return rootFile;\n        }\n\n        public void setRootFile(FileInfo rootFile) {\n            this.rootFile = rootFile;\n        }\n\n        public List<FileInfo> getInstanceFiles() {\n            return instanceFiles;\n        }\n\n        public void setInstanceFiles(List<FileInfo> instanceFiles) {\n            this.instanceFiles = instanceFiles;\n        }\n\n    }\n\n    public static class FileInfo {\n\n        private String name;\n        private long   lastModified = 0;\n\n        public FileInfo(String name, long lastModified){\n            this.name = name;\n            this.lastModified = lastModified;\n        }\n\n        public String getName() {\n            return name;\n        }\n\n        public void setName(String name) {\n            this.name = name;\n        }\n\n        public long getLastModified() {\n            return lastModified;\n        }\n\n        public void setLastModified(long lastModified) {\n            this.lastModified = lastModified;\n        }\n\n    }\n}\n"
  },
  {
    "path": "deployer/src/main/resources/canal.properties",
    "content": "#################################################\n######### \t\tcommon argument\t\t#############\n#################################################\n# tcp bind ip\ncanal.ip =\n# register ip to zookeeper\ncanal.register.ip =\ncanal.port = 11111\ncanal.metrics.pull.port = 11112\n# canal instance user/passwd\n# canal.user = canal\n# canal.passwd =\n\n# canal admin config\n#canal.admin.manager = 127.0.0.1:8089\ncanal.admin.port = 11110\ncanal.admin.user = admin\ncanal.admin.passwd =\n# admin auto register\n#canal.admin.register.auto = true\n#canal.admin.register.cluster =\n#canal.admin.register.name =\n\ncanal.zkServers =\n# flush data to zk\ncanal.zookeeper.flush.period = 1000\ncanal.withoutNetty = false\n# tcp, kafka, rocketMQ, rabbitMQ, pulsarMQ\ncanal.serverMode = tcp\n# flush meta cursor/parse position to file\ncanal.file.data.dir = ${canal.conf.dir}\ncanal.file.flush.period = 1000\n## memory store RingBuffer size, should be Math.pow(2,n)\ncanal.instance.memory.buffer.size = 16384\n## memory store RingBuffer used memory unit size , default 1kb\ncanal.instance.memory.buffer.memunit = 1024 \n## meory store gets mode used MEMSIZE or ITEMSIZE\ncanal.instance.memory.batch.mode = MEMSIZE\ncanal.instance.memory.rawEntry = true\n\n## detecing config\ncanal.instance.detecting.enable = false\n#canal.instance.detecting.sql = insert into retl.xdual values(1,now()) on duplicate key update x=now()\ncanal.instance.detecting.sql = select 1\ncanal.instance.detecting.interval.time = 3\ncanal.instance.detecting.retry.threshold = 3\ncanal.instance.detecting.heartbeatHaEnable = false\n\n# support maximum transaction size, more than the size of the transaction will be cut into multiple transactions delivery\ncanal.instance.transaction.size =  1024\n# mysql fallback connected to new master should fallback times\ncanal.instance.fallbackIntervalInSeconds = 60\n\n# network config\ncanal.instance.network.receiveBufferSize = 16384\ncanal.instance.network.sendBufferSize = 16384\ncanal.instance.network.soTimeout = 30\n\n# binlog filter config\ncanal.instance.filter.druid.ddl = true\ncanal.instance.filter.query.dcl = false\ncanal.instance.filter.query.dml = false\ncanal.instance.filter.query.ddl = false\ncanal.instance.filter.table.error = false\ncanal.instance.filter.rows = false\ncanal.instance.filter.transaction.entry = false\ncanal.instance.filter.dml.insert = false\ncanal.instance.filter.dml.update = false\ncanal.instance.filter.dml.delete = false\n\n# binlog format/image check\ncanal.instance.binlog.format = ROW,STATEMENT,MIXED \ncanal.instance.binlog.image = FULL,MINIMAL,NOBLOB\n\n# binlog ddl isolation\ncanal.instance.get.ddl.isolation = false\n\n# parallel parser config\ncanal.instance.parser.parallel = true\n## concurrent thread number, default 60% available processors, suggest not to exceed Runtime.getRuntime().availableProcessors()\n#canal.instance.parser.parallelThreadSize = 16\n## disruptor ringbuffer size, must be power of 2\ncanal.instance.parser.parallelBufferSize = 256\n\n# table meta tsdb info\ncanal.instance.tsdb.enable = true\ncanal.instance.tsdb.dir = ${canal.file.data.dir:../conf}/${canal.instance.destination:}\ncanal.instance.tsdb.url = jdbc:h2:${canal.instance.tsdb.dir}/h2;CACHE_SIZE=1000;MODE=MYSQL;\ncanal.instance.tsdb.dbUsername = canal\ncanal.instance.tsdb.dbPassword = canal\n# dump snapshot interval, default 24 hour\ncanal.instance.tsdb.snapshot.interval = 24\n# purge snapshot expire , default 360 hour(15 days)\ncanal.instance.tsdb.snapshot.expire = 360\n\n#################################################\n######### \t\tdestinations\t\t#############\n#################################################\ncanal.destinations = example\n# conf root dir\ncanal.conf.dir = ../conf\n# auto scan instance dir add/remove and start/stop instance\ncanal.auto.scan = true\ncanal.auto.scan.interval = 5\n# set this value to 'true' means that when binlog pos not found, skip to latest.\n# WARN: pls keep 'false' in production env, or if you know what you want.\ncanal.auto.reset.latest.pos.mode = false\n\ncanal.instance.tsdb.spring.xml = classpath:spring/tsdb/h2-tsdb.xml\n#canal.instance.tsdb.spring.xml = classpath:spring/tsdb/mysql-tsdb.xml\n\ncanal.instance.global.mode = spring\ncanal.instance.global.lazy = false\ncanal.instance.global.manager.address = ${canal.admin.manager}\n#canal.instance.global.spring.xml = classpath:spring/memory-instance.xml\ncanal.instance.global.spring.xml = classpath:spring/file-instance.xml\n#canal.instance.global.spring.xml = classpath:spring/default-instance.xml\n\n##################################################\n######### \t      MQ Properties      #############\n##################################################\n# aliyun ak/sk , support rds/mq\ncanal.aliyun.accessKey =\ncanal.aliyun.secretKey =\ncanal.aliyun.uid=\n\ncanal.mq.flatMessage = true\ncanal.mq.canalBatchSize = 50\ncanal.mq.canalGetTimeout = 100\n# Set this value to \"cloud\", if you want open message trace feature in aliyun.\ncanal.mq.accessChannel = local\n\ncanal.mq.database.hash = true\ncanal.mq.send.thread.size = 30\ncanal.mq.build.thread.size = 8\n\n##################################################\n######### \t\t     Kafka \t\t     #############\n##################################################\nkafka.bootstrap.servers = 127.0.0.1:9092\nkafka.acks = all\nkafka.compression.type = none\nkafka.batch.size = 16384\nkafka.linger.ms = 1\nkafka.max.request.size = 1048576\nkafka.buffer.memory = 33554432\nkafka.max.in.flight.requests.per.connection = 1\nkafka.retries = 0\n\nkafka.kerberos.enable = false\nkafka.kerberos.krb5.file = ../conf/kerberos/krb5.conf\nkafka.kerberos.jaas.file = ../conf/kerberos/jaas.conf\n\n# sasl demo\n# kafka.sasl.jaas.config = org.apache.kafka.common.security.scram.ScramLoginModule required \\\\n username=\\\"alice\\\" \\\\npassword=\"alice-secret\\\";\n# kafka.sasl.mechanism = SCRAM-SHA-512\n# kafka.security.protocol = SASL_PLAINTEXT\n\n##################################################\n######### \t\t    RocketMQ\t     #############\n##################################################\nrocketmq.producer.group = test\nrocketmq.enable.message.trace = false\nrocketmq.customized.trace.topic =\nrocketmq.namespace =\nrocketmq.namesrv.addr = 127.0.0.1:9876\nrocketmq.retry.times.when.send.failed = 0\nrocketmq.vip.channel.enabled = false\nrocketmq.tag = \n\n##################################################\n######### \t\t    RabbitMQ\t     #############\n##################################################\nrabbitmq.host =\nrabbitmq.virtual.host =\nrabbitmq.exchange =\nrabbitmq.username =\nrabbitmq.password =\nrabbitmq.queue =\nrabbitmq.routingKey =\nrabbitmq.deliveryMode =\n\n\n##################################################\n######### \t\t      Pulsar         #############\n##################################################\npulsarmq.serverUrl =\npulsarmq.roleToken =\npulsarmq.topicTenantPrefix =\n"
  },
  {
    "path": "deployer/src/main/resources/canal_local.properties",
    "content": "# register ip\ncanal.register.ip =\n\n# canal admin config\ncanal.admin.manager = 127.0.0.1:8089\ncanal.admin.port = 11110\ncanal.admin.user = admin\ncanal.admin.passwd =\n# admin auto register\ncanal.admin.register.auto = true\ncanal.admin.register.cluster =\ncanal.admin.register.name = \n"
  },
  {
    "path": "deployer/src/main/resources/example/instance.properties",
    "content": "#################################################\n## mysql serverId , v1.0.26+ will autoGen\n# canal.instance.mysql.slaveId=0\n\n# enable gtid use true/false\ncanal.instance.gtidon=false\n\n# rds oss binlog\ncanal.instance.rds.accesskey=\ncanal.instance.rds.secretkey=\ncanal.instance.rds.instanceId=\n\n# position info\ncanal.instance.master.address=127.0.0.1:3306\ncanal.instance.master.journal.name=\ncanal.instance.master.position=\ncanal.instance.master.timestamp=\ncanal.instance.master.gtid=\n\n# multi stream for polardbx\ncanal.instance.multi.stream.on=false\n\n# ssl\n#canal.instance.master.sslMode=DISABLED\n#canal.instance.master.tlsVersions=\n#canal.instance.master.trustCertificateKeyStoreType=\n#canal.instance.master.trustCertificateKeyStoreUrl=\n#canal.instance.master.trustCertificateKeyStorePassword=\n#canal.instance.master.clientCertificateKeyStoreType=\n#canal.instance.master.clientCertificateKeyStoreUrl=\n#canal.instance.master.clientCertificateKeyStorePassword=\n\n# table meta tsdb info\ncanal.instance.tsdb.enable=true\n#canal.instance.tsdb.url=jdbc:mysql://127.0.0.1:3306/canal_tsdb\n#canal.instance.tsdb.dbUsername=canal\n#canal.instance.tsdb.dbPassword=canal\n\n#canal.instance.standby.address =\n#canal.instance.standby.journal.name =\n#canal.instance.standby.position =\n#canal.instance.standby.timestamp =\n#canal.instance.standby.gtid=\n\n# username/password\ncanal.instance.dbUsername=canal\ncanal.instance.dbPassword=canal\ncanal.instance.connectionCharset = UTF-8\n# enable druid Decrypt database password\ncanal.instance.enableDruid=false\n#canal.instance.pwdPublicKey=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALK4BUxdDltRRE5/zXpVEVPUgunvscYFtEip3pmLlhrWpacX7y7GCMo2/JM6LeHmiiNdH1FWgGCpUfircSwlWKUCAwEAAQ==\n\n# table regex\ncanal.instance.filter.regex=.*\\\\..*\n# table black regex\ncanal.instance.filter.black.regex=mysql\\\\.slave_.*\n# table field filter(format: schema1.tableName1:field1/field2,schema2.tableName2:field1/field2)\n#canal.instance.filter.field=test1.t_product:id/subject/keywords,test2.t_company:id/name/contact/ch\n# table field black filter(format: schema1.tableName1:field1/field2,schema2.tableName2:field1/field2)\n#canal.instance.filter.black.field=test1.t_product:subject/product_image,test2.t_company:id/name/contact/ch\n\n# mq config\ncanal.mq.topic=example\n# dynamic topic route by schema or table regex\n#canal.mq.dynamicTopic=mytest1.user,topic2:mytest2\\\\..*,.*\\\\..*\ncanal.mq.partition=0\n# hash partition config\n#canal.mq.enableDynamicQueuePartition=false\n#canal.mq.partitionsNum=3\n#canal.mq.dynamicTopicPartitionNum=test.*:4,mycanal:6\n#canal.mq.partitionHash=test.table:id^name,.*\\\\..*\n#################################################\n"
  },
  {
    "path": "deployer/src/main/resources/logback.xml",
    "content": "<configuration scan=\"true\" scanPeriod=\" 5 seconds\">\n\t<jmxConfigurator />\n\t<appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n\t\t<encoder>\n\t\t\t<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{56} - %msg%n\n\t\t\t</pattern>\n\t\t</encoder>\n\t</appender>\n\n\t<appender name=\"CANAL-ROOT\" class=\"ch.qos.logback.classic.sift.SiftingAppender\">\n\t\t<discriminator>\n\t\t\t<Key>destination</Key>\n\t\t\t<DefaultValue>canal</DefaultValue>\n\t\t</discriminator>\n\t\t<sift>\n\t\t\t<appender name=\"FILE-${destination}\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n\t\t\t\t<File>../logs/${destination}/${destination}.log</File>\n\t\t\t\t<rollingPolicy\n\t\t\t\t\t\tclass=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n\t\t\t\t\t<!-- rollover daily -->\n\t\t\t\t\t<fileNamePattern>../logs/${destination}/%d{yyyy-MM-dd}/${destination}-%d{yyyy-MM-dd}-%i.log.gz</fileNamePattern>\n\t\t\t\t\t<timeBasedFileNamingAndTriggeringPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP\">\n\t\t\t\t\t\t<!-- or whenever the file size reaches 100MB -->\n\t\t\t\t\t\t<maxFileSize>512MB</maxFileSize>\n\t\t\t\t\t</timeBasedFileNamingAndTriggeringPolicy>\n\t\t\t\t\t<maxHistory>14</maxHistory>\n\t\t\t\t</rollingPolicy>\n\t\t\t\t<encoder>\n\t\t\t\t\t<pattern>\n\t\t\t\t\t\t%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{56} - %msg%n\n\t\t\t\t\t</pattern>\n\t\t\t\t</encoder>\n\t\t\t</appender>\n\t\t</sift>\n\t</appender>\n\n\t<appender name=\"CANAL-META\" class=\"ch.qos.logback.classic.sift.SiftingAppender\">\n\t\t<discriminator>\n\t\t\t<Key>destination</Key>\n\t\t\t<DefaultValue>canal</DefaultValue>\n\t\t</discriminator>\n\t\t<sift>\n\t\t\t<appender name=\"META-FILE-${destination}\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n\t\t\t\t<File>../logs/${destination}/meta.log</File>\n\t\t\t\t<rollingPolicy\n\t\t\t\t\t\tclass=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n\t\t\t\t\t<!-- rollover daily -->\n\t\t\t\t\t<fileNamePattern>../logs/${destination}/%d{yyyy-MM-dd}/meta-%d{yyyy-MM-dd}-%i.log.gz</fileNamePattern>\n\t\t\t\t\t<timeBasedFileNamingAndTriggeringPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP\">\n\t\t\t\t\t\t<!-- or whenever the file size reaches 100MB -->\n\t\t\t\t\t\t<maxFileSize>32MB</maxFileSize>\n\t\t\t\t\t</timeBasedFileNamingAndTriggeringPolicy>\n\t\t\t\t\t<maxHistory>14</maxHistory>\n\t\t\t\t</rollingPolicy>\n\t\t\t\t<encoder>\n\t\t\t\t\t<pattern>\n\t\t\t\t\t\t%d{yyyy-MM-dd HH:mm:ss.SSS} - %msg%n\n\t\t\t\t\t</pattern>\n\t\t\t\t</encoder>\n\t\t\t</appender>\n\t\t</sift>\n\t</appender>\n\n\t<appender name=\"RocketmqClientAppender\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n\t\t<file>../logs/canal/rocketmq_client.log</file>\n\t\t<rollingPolicy\n\t\t\t\tclass=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n\t\t\t<!-- rollover daily -->\n\t\t\t<fileNamePattern>../logs/canal/%d{yyyy-MM-dd}/rocketmq_client-%d{yyyy-MM-dd}-%i.log.gz</fileNamePattern>\n\t\t\t<timeBasedFileNamingAndTriggeringPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP\">\n\t\t\t\t<!-- or whenever the file size reaches 100MB -->\n\t\t\t\t<maxFileSize>512MB</maxFileSize>\n\t\t\t</timeBasedFileNamingAndTriggeringPolicy>\n\t\t\t<maxHistory>14</maxHistory>\n\t\t</rollingPolicy>\n\t\t<encoder charset=\"UTF-8\">\n\t\t\t<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{56} - %msg%n</pattern>\n\t\t</encoder>\n\t</appender>\n\n\t<logger name=\"com.alibaba.otter.canal.instance\" additivity=\"false\">\n\t\t<level value=\"INFO\" />\n\t\t<appender-ref ref=\"CANAL-ROOT\" />\n\t</logger>\n\t<logger name=\"com.alibaba.otter.canal.deployer\" additivity=\"false\">\n\t\t<level value=\"INFO\" />\n\t\t<appender-ref ref=\"CANAL-ROOT\" />\n\t</logger>\n\t<logger name=\"com.alibaba.otter.canal.server.embedded\" additivity=\"false\">\n\t\t<level value=\"INFO\" />\n\t\t<appender-ref ref=\"CANAL-ROOT\" />\n\t</logger>\n\t<logger name=\"com.alibaba.otter.canal.meta.FileMixedMetaManager\" additivity=\"false\">\n\t\t<level value=\"INFO\" />\n\t\t<appender-ref ref=\"CANAL-META\" />\n\t</logger>\n\t<logger name=\"com.alibaba.otter.canal.connector.kafka\" additivity=\"false\">\n\t\t<level value=\"INFO\" />\n\t\t<appender-ref ref=\"CANAL-ROOT\" />\n\t</logger>\n\t<logger name=\"com.alibaba.otter.canal.connector.rocketmq\" additivity=\"false\">\n\t\t<level value=\"INFO\" />\n\t\t<appender-ref ref=\"CANAL-ROOT\" />\n\t</logger>\n\t<logger name=\"com.alibaba.otter.canal.connector.rabbitmq\" additivity=\"false\">\n\t\t<level value=\"INFO\" />\n\t\t<appender-ref ref=\"CANAL-ROOT\" />\n\t</logger>\n\t<logger name=\"RocketmqClient\" additivity=\"false\">\n\t\t<level value=\"INFO\" />\n\t\t<appender-ref ref=\"RocketmqClientAppender\" />\n  </logger>\n\t<logger name=\"com.alibaba.otter.canal.connector.pulsarmq\" additivity=\"false\">\n\t\t<level value=\"INFO\" />\n\t\t<appender-ref ref=\"CANAL-ROOT\" />\n\t</logger>\n\t<root level=\"WARN\">\n\t\t<!-- <appender-ref ref=\"STDOUT\"/>  -->\n\t\t<appender-ref ref=\"CANAL-ROOT\" />\n\t</root>\n</configuration>\n"
  },
  {
    "path": "deployer/src/main/resources/metrics/Canal_instances_tmpl.json",
    "content": "{\n  \"__inputs\": [\n    {\n      \"name\": \"DS_PROMETHEUS\",\n      \"label\": \"prometheus\",\n      \"description\": \"\",\n      \"type\": \"datasource\",\n      \"pluginId\": \"prometheus\",\n      \"pluginName\": \"Prometheus\"\n    }\n  ],\n  \"__requires\": [\n    {\n      \"type\": \"grafana\",\n      \"id\": \"grafana\",\n      \"name\": \"Grafana\",\n      \"version\": \"5.2.2\"\n    },\n    {\n      \"type\": \"panel\",\n      \"id\": \"graph\",\n      \"name\": \"Graph\",\n      \"version\": \"5.0.0\"\n    },\n    {\n      \"type\": \"datasource\",\n      \"id\": \"prometheus\",\n      \"name\": \"Prometheus\",\n      \"version\": \"5.0.0\"\n    }\n  ],\n  \"annotations\": {\n    \"list\": [\n      {\n        \"builtIn\": 1,\n        \"datasource\": \"-- Grafana --\",\n        \"enable\": true,\n        \"hide\": true,\n        \"iconColor\": \"rgba(0, 211, 255, 1)\",\n        \"name\": \"Annotations & Alerts\",\n        \"type\": \"dashboard\"\n      }\n    ]\n  },\n  \"editable\": true,\n  \"gnetId\": null,\n  \"graphTooltip\": 0,\n  \"id\": null,\n  \"iteration\": 1536989235272,\n  \"links\": [],\n  \"panels\": [\n    {\n      \"collapsed\": false,\n      \"gridPos\": {\n        \"h\": 1,\n        \"w\": 24,\n        \"x\": 0,\n        \"y\": 0\n      },\n      \"id\": 30,\n      \"panels\": [],\n      \"title\": \"Instance status\",\n      \"type\": \"row\"\n    },\n    {\n      \"aliasColors\": {},\n      \"bars\": false,\n      \"dashLength\": 10,\n      \"dashes\": false,\n      \"datasource\": \"$datasource\",\n      \"description\": \"Canal instance 基本信息。\",\n      \"fill\": 1,\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 6,\n        \"x\": 0,\n        \"y\": 1\n      },\n      \"id\": 24,\n      \"legend\": {\n        \"alignAsTable\": true,\n        \"avg\": false,\n        \"current\": false,\n        \"hideEmpty\": false,\n        \"hideZero\": false,\n        \"max\": false,\n        \"min\": false,\n        \"rightSide\": true,\n        \"show\": true,\n        \"sideWidth\": 500,\n        \"total\": false,\n        \"values\": false\n      },\n      \"lines\": true,\n      \"linewidth\": 1,\n      \"links\": [],\n      \"nullPointMode\": \"null\",\n      \"percentage\": false,\n      \"pointradius\": 5,\n      \"points\": false,\n      \"renderer\": \"flot\",\n      \"repeat\": null,\n      \"seriesOverrides\": [],\n      \"spaceLength\": 10,\n      \"stack\": false,\n      \"steppedLine\": false,\n      \"targets\": [\n        {\n          \"expr\": \"canal_instance{destination=~\\\"$destination\\\"}\",\n          \"format\": \"time_series\",\n          \"instant\": true,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"Destination: {{destination}}\",\n          \"refId\": \"A\"\n        },\n        {\n          \"expr\": \"canal_instance_parser_mode{destination=~\\\"$destination\\\"}\",\n          \"format\": \"time_series\",\n          \"instant\": true,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"Parallel parser: {{parallel}}\",\n          \"refId\": \"B\"\n        },\n        {\n          \"expr\": \"canal_instance_store{destination=~\\\"$destination\\\"}\",\n          \"format\": \"time_series\",\n          \"instant\": true,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"Batch mode: {{batchMode}}\",\n          \"refId\": \"C\"\n        },\n        {\n          \"expr\": \"canal_instance_store{destination=~\\\"$destination\\\"}\",\n          \"format\": \"time_series\",\n          \"instant\": true,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"Buffer size: {{size}}\",\n          \"refId\": \"D\"\n        }\n      ],\n      \"thresholds\": [],\n      \"timeFrom\": null,\n      \"timeShift\": null,\n      \"title\": \"Basic\",\n      \"tooltip\": {\n        \"shared\": true,\n        \"sort\": 0,\n        \"value_type\": \"individual\"\n      },\n      \"transparent\": true,\n      \"type\": \"graph\",\n      \"xaxis\": {\n        \"buckets\": null,\n        \"mode\": \"time\",\n        \"name\": null,\n        \"show\": false,\n        \"values\": []\n      },\n      \"yaxes\": [\n        {\n          \"format\": \"short\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": false\n        },\n        {\n          \"format\": \"short\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": false\n        }\n      ],\n      \"yaxis\": {\n        \"align\": false,\n        \"alignLevel\": null\n      }\n    },\n    {\n      \"aliasColors\": {\n        \"inbound\": \"#bf1b00\"\n      },\n      \"bars\": false,\n      \"dashLength\": 10,\n      \"dashes\": false,\n      \"datasource\": \"$datasource\",\n      \"description\": \"Canal instance 网络带宽占用。\\ninbound: 读取MySQL binlog.\\noutbound: 对Client端传输格式化binlog.\",\n      \"fill\": 1,\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 6,\n        \"x\": 6,\n        \"y\": 1\n      },\n      \"id\": 6,\n      \"legend\": {\n        \"avg\": false,\n        \"current\": false,\n        \"max\": false,\n        \"min\": false,\n        \"show\": true,\n        \"total\": false,\n        \"values\": false\n      },\n      \"lines\": true,\n      \"linewidth\": 1,\n      \"links\": [],\n      \"nullPointMode\": \"null\",\n      \"percentage\": false,\n      \"pointradius\": 5,\n      \"points\": false,\n      \"renderer\": \"flot\",\n      \"seriesOverrides\": [],\n      \"spaceLength\": 10,\n      \"stack\": false,\n      \"steppedLine\": false,\n      \"targets\": [\n        {\n          \"expr\": \"rate(canal_instance_received_binlog_bytes{destination=~\\\"$destination\\\", parser=\\\"0\\\"}[2m]) / 1024\",\n          \"format\": \"time_series\",\n          \"interval\": \"15s\",\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"inbound\",\n          \"refId\": \"A\"\n        },\n        {\n          \"expr\": \"rate(canal_instance_client_bytes{destination=~\\\"$destination\\\"}[2m]) / 1024\",\n          \"format\": \"time_series\",\n          \"interval\": \"15s\",\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"outbound\",\n          \"refId\": \"B\"\n        },\n        {\n          \"expr\": \"rate(canal_instance_received_binlog_bytes{destination=~\\\"$destination\\\", parser=\\\"1\\\"}[2m]) / 1024\",\n          \"format\": \"time_series\",\n          \"interval\": \"15s\",\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"inbound-1\",\n          \"refId\": \"C\"\n        },\n        {\n          \"expr\": \"rate(canal_instance_received_binlog_bytes{destination=~\\\"$destination\\\", parser=\\\"2\\\"}[2m]) / 1024\",\n          \"format\": \"time_series\",\n          \"interval\": \"15s\",\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"inbound-2\",\n          \"refId\": \"D\"\n        }\n      ],\n      \"thresholds\": [],\n      \"timeFrom\": null,\n      \"timeShift\": null,\n      \"title\": \"Network bandwith\",\n      \"tooltip\": {\n        \"shared\": true,\n        \"sort\": 0,\n        \"value_type\": \"individual\"\n      },\n      \"type\": \"graph\",\n      \"xaxis\": {\n        \"buckets\": null,\n        \"mode\": \"time\",\n        \"name\": null,\n        \"show\": true,\n        \"values\": []\n      },\n      \"yaxes\": [\n        {\n          \"format\": \"KBs\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        },\n        {\n          \"format\": \"short\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        }\n      ],\n      \"yaxis\": {\n        \"align\": false,\n        \"alignLevel\": null\n      }\n    },\n    {\n      \"aliasColors\": {\n        \"ack\": \"#f29191\",\n        \"get\": \"#cca300\",\n        \"put\": \"#1f78c1\"\n      },\n      \"bars\": false,\n      \"dashLength\": 10,\n      \"dashes\": false,\n      \"datasource\": \"$datasource\",\n      \"description\": \"master: Canal server相对于MySQL master的延时。通过master heartbeat机制能刷新idle状态下的延时。\\nput: store put操作的时间点为基准。\\nget: client get操作的时间点为基准。\\nack:  client ack操作的时间点为基准。\",\n      \"fill\": 1,\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 6,\n        \"x\": 12,\n        \"y\": 1\n      },\n      \"id\": 4,\n      \"legend\": {\n        \"avg\": false,\n        \"current\": false,\n        \"max\": false,\n        \"min\": false,\n        \"show\": true,\n        \"total\": false,\n        \"values\": false\n      },\n      \"lines\": true,\n      \"linewidth\": 1,\n      \"links\": [],\n      \"nullPointMode\": \"null\",\n      \"percentage\": false,\n      \"pointradius\": 5,\n      \"points\": false,\n      \"renderer\": \"flot\",\n      \"seriesOverrides\": [],\n      \"spaceLength\": 10,\n      \"stack\": false,\n      \"steppedLine\": false,\n      \"targets\": [\n        {\n          \"expr\": \"canal_instance_traffic_delay{destination=~\\\"$destination\\\"} / 1000\",\n          \"format\": \"time_series\",\n          \"hide\": false,\n          \"interval\": \"15s\",\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"master\",\n          \"refId\": \"D\"\n        },\n        {\n          \"expr\": \"canal_instance_put_delay{destination=~\\\"$destination\\\"} / 1000\",\n          \"format\": \"time_series\",\n          \"interval\": \"15s\",\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"put\",\n          \"refId\": \"A\"\n        },\n        {\n          \"expr\": \"canal_instance_get_delay{destination=~\\\"$destination\\\"} / 1000\",\n          \"format\": \"time_series\",\n          \"interval\": \"15s\",\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"get\",\n          \"refId\": \"B\"\n        },\n        {\n          \"expr\": \"canal_instance_ack_delay{destination=~\\\"$destination\\\"} / 1000\",\n          \"format\": \"time_series\",\n          \"interval\": \"15s\",\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"ack\",\n          \"refId\": \"C\"\n        }\n      ],\n      \"thresholds\": [],\n      \"timeFrom\": null,\n      \"timeShift\": null,\n      \"title\": \"Delay\",\n      \"tooltip\": {\n        \"shared\": true,\n        \"sort\": 0,\n        \"value_type\": \"individual\"\n      },\n      \"type\": \"graph\",\n      \"xaxis\": {\n        \"buckets\": null,\n        \"mode\": \"time\",\n        \"name\": null,\n        \"show\": true,\n        \"values\": []\n      },\n      \"yaxes\": [\n        {\n          \"format\": \"s\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        },\n        {\n          \"format\": \"short\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        }\n      ],\n      \"yaxis\": {\n        \"align\": false,\n        \"alignLevel\": null\n      }\n    },\n    {\n      \"aliasColors\": {},\n      \"bars\": false,\n      \"dashLength\": 10,\n      \"dashes\": false,\n      \"datasource\": \"$datasource\",\n      \"description\": \"sink线程blocking占比；dump线程blocking占比(仅parallel mode)。\",\n      \"fill\": 1,\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 6,\n        \"x\": 18,\n        \"y\": 1\n      },\n      \"hideTimeOverride\": false,\n      \"id\": 2,\n      \"legend\": {\n        \"avg\": false,\n        \"current\": false,\n        \"max\": false,\n        \"min\": false,\n        \"show\": true,\n        \"total\": false,\n        \"values\": false\n      },\n      \"lines\": true,\n      \"linewidth\": 1,\n      \"links\": [],\n      \"nullPointMode\": \"null\",\n      \"percentage\": false,\n      \"pointradius\": 5,\n      \"points\": false,\n      \"renderer\": \"flot\",\n      \"seriesOverrides\": [],\n      \"spaceLength\": 10,\n      \"stack\": false,\n      \"steppedLine\": false,\n      \"targets\": [\n        {\n          \"expr\": \"clamp_max(rate(canal_instance_publish_blocking_time{destination=~\\\"$destination\\\", parser=\\\"0\\\"}[2m]), 1000) / 10\",\n          \"format\": \"time_series\",\n          \"interval\": \"15s\",\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"dump\",\n          \"refId\": \"B\"\n        },\n        {\n          \"expr\": \"clamp_max(rate(canal_instance_sink_blocking_time{destination=~\\\"$destination\\\"}[2m]), 1000) / 10\",\n          \"format\": \"time_series\",\n          \"interval\": \"15s\",\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"sink\",\n          \"refId\": \"A\"\n        },\n        {\n          \"expr\": \"clamp_max(rate(canal_instance_publish_blocking_time{destination=~\\\"$destination\\\", parser=\\\"1\\\"}[2m]), 1000) / 10\",\n          \"format\": \"time_series\",\n          \"interval\": \"15s\",\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"dump-1\",\n          \"refId\": \"C\"\n        },\n        {\n          \"expr\": \"clamp_max(rate(canal_instance_publish_blocking_time{destination=~\\\"$destination\\\", parser=\\\"2\\\"}[2m]), 1000) / 10\",\n          \"format\": \"time_series\",\n          \"interval\": \"15s\",\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"dump-2\",\n          \"refId\": \"D\"\n        }\n      ],\n      \"thresholds\": [],\n      \"timeFrom\": null,\n      \"timeShift\": null,\n      \"title\": \"Blocking\",\n      \"tooltip\": {\n        \"shared\": true,\n        \"sort\": 0,\n        \"value_type\": \"individual\"\n      },\n      \"type\": \"graph\",\n      \"xaxis\": {\n        \"buckets\": null,\n        \"mode\": \"time\",\n        \"name\": null,\n        \"show\": true,\n        \"values\": []\n      },\n      \"yaxes\": [\n        {\n          \"format\": \"percent\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        },\n        {\n          \"format\": \"short\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        }\n      ],\n      \"yaxis\": {\n        \"align\": false,\n        \"alignLevel\": null\n      }\n    },\n    {\n      \"collapsed\": false,\n      \"gridPos\": {\n        \"h\": 1,\n        \"w\": 24,\n        \"x\": 0,\n        \"y\": 6\n      },\n      \"id\": 32,\n      \"panels\": [],\n      \"title\": \"Throughput\",\n      \"type\": \"row\"\n    },\n    {\n      \"aliasColors\": {\n        \"rowDatas\": \"#7eb26d\",\n        \"tableRows\": \"#c15c17\"\n      },\n      \"bars\": false,\n      \"dashLength\": 10,\n      \"dashes\": false,\n      \"datasource\": \"$datasource\",\n      \"description\": \"Instance处理binlog的TPS(以master变更行数table rows为基准计算)。\\nput: put操作TPS。\\nget: get操作TPS。\\nack: ack操作TPS。\",\n      \"fill\": 1,\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 6,\n        \"x\": 0,\n        \"y\": 7\n      },\n      \"id\": 14,\n      \"legend\": {\n        \"avg\": false,\n        \"current\": false,\n        \"max\": false,\n        \"min\": false,\n        \"show\": true,\n        \"total\": false,\n        \"values\": false\n      },\n      \"lines\": true,\n      \"linewidth\": 1,\n      \"links\": [],\n      \"nullPointMode\": \"null\",\n      \"percentage\": false,\n      \"pointradius\": 5,\n      \"points\": false,\n      \"renderer\": \"flot\",\n      \"seriesOverrides\": [],\n      \"spaceLength\": 10,\n      \"stack\": false,\n      \"steppedLine\": false,\n      \"targets\": [\n        {\n          \"expr\": \"rate(canal_instance_put_rows{destination=~\\\"$destination\\\"}[2m])\",\n          \"format\": \"time_series\",\n          \"interval\": \"15s\",\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"put\",\n          \"refId\": \"A\"\n        },\n        {\n          \"expr\": \"rate(canal_instance_get_rows{destination=~\\\"$destination\\\"}[2m])\",\n          \"format\": \"time_series\",\n          \"interval\": \"15s\",\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"get\",\n          \"refId\": \"B\"\n        },\n        {\n          \"expr\": \"rate(canal_instance_ack_rows{destination=~\\\"$destination\\\"}[2m])\",\n          \"format\": \"time_series\",\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"ack\",\n          \"refId\": \"C\"\n        }\n      ],\n      \"thresholds\": [],\n      \"timeFrom\": null,\n      \"timeShift\": null,\n      \"title\": \"TPS(table rows)\",\n      \"tooltip\": {\n        \"shared\": true,\n        \"sort\": 0,\n        \"value_type\": \"individual\"\n      },\n      \"type\": \"graph\",\n      \"xaxis\": {\n        \"buckets\": null,\n        \"mode\": \"time\",\n        \"name\": null,\n        \"show\": true,\n        \"values\": []\n      },\n      \"yaxes\": [\n        {\n          \"format\": \"iops\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        },\n        {\n          \"format\": \"short\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        }\n      ],\n      \"yaxis\": {\n        \"align\": false,\n        \"alignLevel\": null\n      }\n    },\n    {\n      \"aliasColors\": {\n        \"transactions\": \"#f9ba8f\"\n      },\n      \"bars\": false,\n      \"dashLength\": 10,\n      \"dashes\": false,\n      \"datasource\": \"$datasource\",\n      \"description\": \"Canal instance 处理binlog的TPS，以MySQL transaction为单位计算。\",\n      \"fill\": 1,\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 6,\n        \"x\": 6,\n        \"y\": 7\n      },\n      \"id\": 12,\n      \"legend\": {\n        \"avg\": false,\n        \"current\": false,\n        \"max\": false,\n        \"min\": false,\n        \"show\": true,\n        \"total\": false,\n        \"values\": false\n      },\n      \"lines\": true,\n      \"linewidth\": 1,\n      \"links\": [],\n      \"nullPointMode\": \"null\",\n      \"percentage\": false,\n      \"pointradius\": 5,\n      \"points\": false,\n      \"renderer\": \"flot\",\n      \"seriesOverrides\": [],\n      \"spaceLength\": 10,\n      \"stack\": false,\n      \"steppedLine\": false,\n      \"targets\": [\n        {\n          \"expr\": \"rate(canal_instance_transactions{destination=~\\\"$destination\\\"}[2m])\",\n          \"format\": \"time_series\",\n          \"interval\": \"15s\",\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"transactions\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"thresholds\": [],\n      \"timeFrom\": null,\n      \"timeShift\": null,\n      \"title\": \"TPS(MySQL transaction)\",\n      \"tooltip\": {\n        \"shared\": true,\n        \"sort\": 0,\n        \"value_type\": \"individual\"\n      },\n      \"type\": \"graph\",\n      \"xaxis\": {\n        \"buckets\": null,\n        \"mode\": \"time\",\n        \"name\": null,\n        \"show\": true,\n        \"values\": []\n      },\n      \"yaxes\": [\n        {\n          \"format\": \"iops\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        },\n        {\n          \"format\": \"short\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        }\n      ],\n      \"yaxis\": {\n        \"align\": false,\n        \"alignLevel\": null\n      }\n    },\n    {\n      \"collapsed\": false,\n      \"gridPos\": {\n        \"h\": 1,\n        \"w\": 24,\n        \"x\": 0,\n        \"y\": 12\n      },\n      \"id\": 34,\n      \"panels\": [],\n      \"title\": \"Client\",\n      \"type\": \"row\"\n    },\n    {\n      \"aliasColors\": {},\n      \"bars\": false,\n      \"dashLength\": 10,\n      \"dashes\": false,\n      \"datasource\": \"$datasource\",\n      \"description\": \"Canal instance接收到的请求统计，结果按packet type分类。\",\n      \"fill\": 1,\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 6,\n        \"x\": 0,\n        \"y\": 13\n      },\n      \"id\": 16,\n      \"legend\": {\n        \"avg\": false,\n        \"current\": false,\n        \"max\": false,\n        \"min\": false,\n        \"show\": true,\n        \"total\": false,\n        \"values\": false\n      },\n      \"lines\": true,\n      \"linewidth\": 1,\n      \"links\": [],\n      \"nullPointMode\": \"null\",\n      \"percentage\": false,\n      \"pointradius\": 5,\n      \"points\": false,\n      \"renderer\": \"flot\",\n      \"seriesOverrides\": [],\n      \"spaceLength\": 10,\n      \"stack\": false,\n      \"steppedLine\": false,\n      \"targets\": [\n        {\n          \"expr\": \"canal_instance_client_packets{destination=~\\\"$destination\\\"}\",\n          \"format\": \"time_series\",\n          \"interval\": \"15s\",\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"{{packetType}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"thresholds\": [],\n      \"timeFrom\": null,\n      \"timeShift\": null,\n      \"title\": \"Client requests\",\n      \"tooltip\": {\n        \"shared\": true,\n        \"sort\": 0,\n        \"value_type\": \"individual\"\n      },\n      \"type\": \"graph\",\n      \"xaxis\": {\n        \"buckets\": null,\n        \"mode\": \"time\",\n        \"name\": null,\n        \"show\": true,\n        \"values\": []\n      },\n      \"yaxes\": [\n        {\n          \"format\": \"none\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        },\n        {\n          \"format\": \"short\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        }\n      ],\n      \"yaxis\": {\n        \"align\": false,\n        \"alignLevel\": null\n      }\n    },\n    {\n      \"aliasColors\": {},\n      \"bars\": false,\n      \"dashLength\": 10,\n      \"dashes\": false,\n      \"datasource\": \"$datasource\",\n      \"description\": \"client 请求的GET与ACK包的QPS。\",\n      \"fill\": 1,\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 6,\n        \"x\": 6,\n        \"y\": 13\n      },\n      \"id\": 38,\n      \"legend\": {\n        \"avg\": false,\n        \"current\": false,\n        \"max\": false,\n        \"min\": false,\n        \"show\": true,\n        \"total\": false,\n        \"values\": false\n      },\n      \"lines\": true,\n      \"linewidth\": 1,\n      \"links\": [],\n      \"nullPointMode\": \"null\",\n      \"percentage\": false,\n      \"pointradius\": 5,\n      \"points\": false,\n      \"renderer\": \"flot\",\n      \"seriesOverrides\": [],\n      \"spaceLength\": 10,\n      \"stack\": false,\n      \"steppedLine\": false,\n      \"targets\": [\n        {\n          \"expr\": \"rate(canal_instance_client_packets{destination=~\\\"$destination\\\",packetType=\\\"GET\\\"}[2m])\",\n          \"format\": \"time_series\",\n          \"interval\": \"15s\",\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"GET\",\n          \"refId\": \"A\"\n        },\n        {\n          \"expr\": \"rate(canal_instance_client_packets{destination=~\\\"$destination\\\",packetType=\\\"CLIENTACK\\\"}[2m])\",\n          \"format\": \"time_series\",\n          \"interval\": \"15s\",\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"ACK\",\n          \"refId\": \"B\"\n        }\n      ],\n      \"thresholds\": [],\n      \"timeFrom\": null,\n      \"timeShift\": null,\n      \"title\": \"Client QPS\",\n      \"tooltip\": {\n        \"shared\": true,\n        \"sort\": 0,\n        \"value_type\": \"individual\"\n      },\n      \"type\": \"graph\",\n      \"xaxis\": {\n        \"buckets\": null,\n        \"mode\": \"time\",\n        \"name\": null,\n        \"show\": true,\n        \"values\": []\n      },\n      \"yaxes\": [\n        {\n          \"format\": \"short\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        },\n        {\n          \"format\": \"short\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        }\n      ],\n      \"yaxis\": {\n        \"align\": false,\n        \"alignLevel\": null\n      }\n    },\n    {\n      \"aliasColors\": {},\n      \"bars\": false,\n      \"dashLength\": 10,\n      \"dashes\": false,\n      \"datasource\": \"$datasource\",\n      \"description\": \"server响应GET请求，但返回空包的占比。\",\n      \"fill\": 1,\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 6,\n        \"x\": 12,\n        \"y\": 13\n      },\n      \"id\": 26,\n      \"legend\": {\n        \"avg\": false,\n        \"current\": false,\n        \"max\": false,\n        \"min\": false,\n        \"show\": true,\n        \"total\": false,\n        \"values\": false\n      },\n      \"lines\": true,\n      \"linewidth\": 1,\n      \"links\": [],\n      \"nullPointMode\": \"null\",\n      \"percentage\": false,\n      \"pointradius\": 5,\n      \"points\": false,\n      \"renderer\": \"flot\",\n      \"seriesOverrides\": [],\n      \"spaceLength\": 10,\n      \"stack\": false,\n      \"steppedLine\": false,\n      \"targets\": [\n        {\n          \"expr\": \"rate(canal_instance_client_empty_batches{destination=~\\\"$destination\\\"}[2m])\",\n          \"format\": \"time_series\",\n          \"interval\": \"15s\",\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"empty\",\n          \"refId\": \"A\"\n        },\n        {\n          \"expr\": \"rate(canal_instance_client_packets{destination=~\\\"$destination\\\", packetType=\\\"GET\\\"}[2m])\",\n          \"format\": \"time_series\",\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"nonempty\",\n          \"refId\": \"B\"\n        }\n      ],\n      \"thresholds\": [],\n      \"timeFrom\": null,\n      \"timeShift\": null,\n      \"title\": \"Empty packets\",\n      \"tooltip\": {\n        \"shared\": true,\n        \"sort\": 0,\n        \"value_type\": \"individual\"\n      },\n      \"type\": \"graph\",\n      \"xaxis\": {\n        \"buckets\": null,\n        \"mode\": \"time\",\n        \"name\": null,\n        \"show\": true,\n        \"values\": []\n      },\n      \"yaxes\": [\n        {\n          \"format\": \"wps\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        },\n        {\n          \"format\": \"short\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        }\n      ],\n      \"yaxis\": {\n        \"align\": false,\n        \"alignLevel\": null\n      }\n    },\n    {\n      \"aliasColors\": {},\n      \"bars\": false,\n      \"dashLength\": 10,\n      \"dashes\": false,\n      \"datasource\": \"$datasource\",\n      \"description\": \"Canal client 请求响应时间的概况。\",\n      \"fill\": 1,\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 6,\n        \"x\": 18,\n        \"y\": 13\n      },\n      \"id\": 18,\n      \"legend\": {\n        \"alignAsTable\": false,\n        \"avg\": false,\n        \"current\": false,\n        \"max\": false,\n        \"min\": false,\n        \"rightSide\": false,\n        \"show\": true,\n        \"total\": false,\n        \"values\": false\n      },\n      \"lines\": true,\n      \"linewidth\": 1,\n      \"links\": [],\n      \"nullPointMode\": \"null\",\n      \"percentage\": false,\n      \"pointradius\": 5,\n      \"points\": false,\n      \"renderer\": \"flot\",\n      \"seriesOverrides\": [\n        {\n          \"alias\": \"25.0\",\n          \"yaxis\": 1\n        },\n        {\n          \"alias\": \"100.0\",\n          \"yaxis\": 1\n        }\n      ],\n      \"spaceLength\": 10,\n      \"stack\": false,\n      \"steppedLine\": false,\n      \"targets\": [\n        {\n          \"expr\": \"rate(canal_instance_client_request_latency_bucket{destination=~\\\"$destination\\\"}[2m])\",\n          \"format\": \"time_series\",\n          \"hide\": false,\n          \"interval\": \"15s\",\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"{{le}}ms\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"thresholds\": [],\n      \"timeFrom\": null,\n      \"timeShift\": null,\n      \"title\": \"Response time\",\n      \"tooltip\": {\n        \"shared\": true,\n        \"sort\": 0,\n        \"value_type\": \"individual\"\n      },\n      \"transparent\": false,\n      \"type\": \"graph\",\n      \"xaxis\": {\n        \"buckets\": null,\n        \"mode\": \"time\",\n        \"name\": null,\n        \"show\": true,\n        \"values\": []\n      },\n      \"yaxes\": [\n        {\n          \"format\": \"short\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        },\n        {\n          \"format\": \"short\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        }\n      ],\n      \"yaxis\": {\n        \"align\": false,\n        \"alignLevel\": null\n      }\n    },\n    {\n      \"collapsed\": false,\n      \"gridPos\": {\n        \"h\": 1,\n        \"w\": 24,\n        \"x\": 0,\n        \"y\": 18\n      },\n      \"id\": 36,\n      \"panels\": [],\n      \"title\": \"Store\",\n      \"type\": \"row\"\n    },\n    {\n      \"aliasColors\": {},\n      \"bars\": false,\n      \"dashLength\": 10,\n      \"dashes\": false,\n      \"datasource\": \"$datasource\",\n      \"description\": \"Canal instance ringbuffer内未释放的events数量。\",\n      \"fill\": 1,\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 6,\n        \"x\": 0,\n        \"y\": 19\n      },\n      \"id\": 20,\n      \"legend\": {\n        \"avg\": false,\n        \"current\": false,\n        \"max\": false,\n        \"min\": false,\n        \"show\": true,\n        \"total\": false,\n        \"values\": false\n      },\n      \"lines\": true,\n      \"linewidth\": 1,\n      \"links\": [],\n      \"nullPointMode\": \"null\",\n      \"percentage\": false,\n      \"pointradius\": 5,\n      \"points\": false,\n      \"renderer\": \"flot\",\n      \"seriesOverrides\": [],\n      \"spaceLength\": 10,\n      \"stack\": false,\n      \"steppedLine\": false,\n      \"targets\": [\n        {\n          \"expr\": \"canal_instance_store_produce_seq{destination=~\\\"$destination\\\"} - canal_instance_store_consume_seq{destination=~\\\"$destination\\\"}\",\n          \"format\": \"time_series\",\n          \"interval\": \"15s\",\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"events\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"thresholds\": [],\n      \"timeFrom\": null,\n      \"timeShift\": null,\n      \"title\": \"Store remain events\",\n      \"tooltip\": {\n        \"shared\": true,\n        \"sort\": 0,\n        \"value_type\": \"individual\"\n      },\n      \"type\": \"graph\",\n      \"xaxis\": {\n        \"buckets\": null,\n        \"mode\": \"time\",\n        \"name\": null,\n        \"show\": true,\n        \"values\": []\n      },\n      \"yaxes\": [\n        {\n          \"decimals\": null,\n          \"format\": \"none\",\n          \"label\": \"\",\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        },\n        {\n          \"decimals\": null,\n          \"format\": \"short\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        }\n      ],\n      \"yaxis\": {\n        \"align\": false,\n        \"alignLevel\": null\n      }\n    },\n    {\n      \"aliasColors\": {},\n      \"bars\": false,\n      \"dashLength\": 10,\n      \"dashes\": false,\n      \"datasource\": \"$datasource\",\n      \"description\": \"Canal instance ringbuffer 内未释放events占用内存。\",\n      \"fill\": 1,\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 6,\n        \"x\": 6,\n        \"y\": 19\n      },\n      \"id\": 22,\n      \"legend\": {\n        \"avg\": false,\n        \"current\": false,\n        \"max\": false,\n        \"min\": false,\n        \"show\": true,\n        \"total\": false,\n        \"values\": false\n      },\n      \"lines\": true,\n      \"linewidth\": 1,\n      \"links\": [],\n      \"nullPointMode\": \"null\",\n      \"percentage\": false,\n      \"pointradius\": 5,\n      \"points\": false,\n      \"renderer\": \"flot\",\n      \"seriesOverrides\": [],\n      \"spaceLength\": 10,\n      \"stack\": false,\n      \"steppedLine\": false,\n      \"targets\": [\n        {\n          \"expr\": \"(canal_instance_store_produce_mem{destination=~\\\"$destination\\\"} - canal_instance_store_consume_mem{destination=~\\\"$destination\\\"}) / 1024\",\n          \"format\": \"time_series\",\n          \"interval\": \"15s\",\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"memsize\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"thresholds\": [],\n      \"timeFrom\": null,\n      \"timeShift\": null,\n      \"title\": \"Store remain mem\",\n      \"tooltip\": {\n        \"shared\": true,\n        \"sort\": 0,\n        \"value_type\": \"individual\"\n      },\n      \"type\": \"graph\",\n      \"xaxis\": {\n        \"buckets\": null,\n        \"mode\": \"time\",\n        \"name\": null,\n        \"show\": true,\n        \"values\": []\n      },\n      \"yaxes\": [\n        {\n          \"format\": \"deckbytes\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        },\n        {\n          \"format\": \"short\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        }\n      ],\n      \"yaxis\": {\n        \"align\": false,\n        \"alignLevel\": null\n      }\n    }\n  ],\n  \"refresh\": false,\n  \"schemaVersion\": 16,\n  \"style\": \"dark\",\n  \"tags\": [\n    \"canal\"\n  ],\n  \"templating\": {\n    \"list\": [\n      {\n        \"current\": {\n          \"text\": \"prometheus\",\n          \"value\": \"prometheus\"\n        },\n        \"hide\": 0,\n        \"label\": \"datasource\",\n        \"name\": \"datasource\",\n        \"options\": [],\n        \"query\": \"prometheus\",\n        \"refresh\": 1,\n        \"regex\": \"\",\n        \"type\": \"datasource\"\n      },\n      {\n        \"allValue\": null,\n        \"current\": {},\n        \"datasource\": \"$datasource\",\n        \"hide\": 0,\n        \"includeAll\": false,\n        \"label\": \"destination\",\n        \"multi\": false,\n        \"name\": \"destination\",\n        \"options\": [],\n        \"query\": \"label_values(canal_instance, destination)\",\n        \"refresh\": 1,\n        \"regex\": \"\",\n        \"sort\": 0,\n        \"tagValuesQuery\": \"\",\n        \"tags\": [],\n        \"tagsQuery\": \"\",\n        \"type\": \"query\",\n        \"useTags\": false\n      }\n    ]\n  },\n  \"time\": {\n    \"from\": \"now-6h\",\n    \"to\": \"now\"\n  },\n  \"timepicker\": {\n    \"refresh_intervals\": [\n      \"5s\",\n      \"10s\",\n      \"30s\",\n      \"1m\",\n      \"5m\",\n      \"15m\",\n      \"30m\",\n      \"1h\",\n      \"2h\",\n      \"1d\"\n    ],\n    \"time_options\": [\n      \"5m\",\n      \"15m\",\n      \"1h\",\n      \"6h\",\n      \"12h\",\n      \"24h\",\n      \"2d\",\n      \"7d\",\n      \"30d\"\n    ]\n  },\n  \"timezone\": \"\",\n  \"title\": \"Canal instances\",\n  \"uid\": \"8vh8NGpiz\",\n  \"version\": 103\n}"
  },
  {
    "path": "deployer/src/main/resources/spring/base-instance.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:tx=\"http://www.springframework.org/schema/tx\"\n\txmlns:aop=\"http://www.springframework.org/schema/aop\" xmlns:lang=\"http://www.springframework.org/schema/lang\"\n\txmlns:context=\"http://www.springframework.org/schema/context\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd\n           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd\n           http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.0.xsd\n           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd\n           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd\"\n\tdefault-autowire=\"byName\">\n\n\t<!-- properties -->\n\t<bean class=\"com.alibaba.otter.canal.instance.spring.support.PropertyPlaceholderConfigurer\" lazy-init=\"false\">\n\t\t<property name=\"ignoreResourceNotFound\" value=\"true\" />\n\t\t<property name=\"systemPropertiesModeName\" value=\"SYSTEM_PROPERTIES_MODE_OVERRIDE\"/><!-- 允许system覆盖 -->\n\t\t<property name=\"locationNames\">\n\t\t\t<list>\n\t\t\t\t<value>classpath:canal.properties</value>\n\t\t\t\t<value>classpath:${canal.instance.destination:}/instance.properties</value>\n\t\t\t</list>\n\t\t</property>\n\t</bean>\n\t\n\t<bean id=\"socketAddressEditor\" class=\"com.alibaba.otter.canal.instance.spring.support.SocketAddressEditor\" />\n\t<bean class=\"org.springframework.beans.factory.config.CustomEditorConfigurer\"> \n\t\t<property name=\"propertyEditorRegistrars\">\n\t\t\t<list>\n\t\t\t\t<ref bean=\"socketAddressEditor\" />\n\t\t\t</list>\n\t\t</property>\n\t</bean>\n\t\n\t<bean id=\"baseEventParser\" class=\"com.alibaba.otter.canal.parse.inbound.mysql.rds.RdsBinlogEventParserProxy\" abstract=\"true\">\n\t\t<property name=\"accesskey\" value=\"${canal.aliyun.accesskey:}\" />\n\t\t<property name=\"secretkey\" value=\"${canal.aliyun.secretkey:}\" />\n\t\t<property name=\"instanceId\" value=\"${canal.instance.rds.instanceId:}\" />\n\t</bean>\n</beans>\n"
  },
  {
    "path": "deployer/src/main/resources/spring/default-instance.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:tx=\"http://www.springframework.org/schema/tx\"\n\txmlns:aop=\"http://www.springframework.org/schema/aop\" xmlns:lang=\"http://www.springframework.org/schema/lang\"\n\txmlns:context=\"http://www.springframework.org/schema/context\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd\n           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd\n           http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.0.xsd\n           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd\n           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd\"\n\tdefault-autowire=\"byName\">\n\n\t<import resource=\"classpath:spring/base-instance.xml\" />\n\n\t<bean id=\"instance\" class=\"com.alibaba.otter.canal.instance.spring.CanalInstanceWithSpring\">\n\t\t<property name=\"destination\" value=\"${canal.instance.destination}\" />\n\t\t<property name=\"eventParser\">\n\t\t\t<ref bean=\"eventParser\" />\n\t\t</property>\n\t\t<property name=\"eventSink\">\n\t\t\t<ref bean=\"eventSink\" />\n\t\t</property>\n\t\t<property name=\"eventStore\">\n\t\t\t<ref bean=\"eventStore\" />\n\t\t</property>\n\t\t<property name=\"metaManager\">\n\t\t\t<ref bean=\"metaManager\" />\n\t\t</property>\n\t\t<property name=\"alarmHandler\">\n\t\t\t<ref bean=\"alarmHandler\" />\n\t\t</property>\n        <property name=\"mqConfig\">\n            <ref bean=\"mqConfig\" />\n        </property>\n\t</bean>\n\n\t<!-- 报警处理类 -->\n\t<bean id=\"alarmHandler\" class=\"com.alibaba.otter.canal.common.alarm.LogAlarmHandler\" />\n\n\t<bean id=\"zkClientx\" class=\"org.springframework.beans.factory.config.MethodInvokingFactoryBean\" >\n\t\t<property name=\"targetClass\" value=\"com.alibaba.otter.canal.common.zookeeper.ZkClientx\" />\n\t\t<property name=\"targetMethod\" value=\"getZkClient\" />\n\t\t<property name=\"arguments\">\n\t\t\t<list>\n\t\t\t\t<value>${canal.zkServers:127.0.0.1:2181}</value>\n\t\t\t</list>\n\t\t</property>\n\t</bean>\n\n\t<bean id=\"metaManager\" class=\"com.alibaba.otter.canal.meta.PeriodMixedMetaManager\">\n\t\t<property name=\"zooKeeperMetaManager\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.meta.ZooKeeperMetaManager\">\n\t\t\t\t<property name=\"zkClientx\" ref=\"zkClientx\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"period\" value=\"${canal.zookeeper.flush.period:1000}\" />\n\t</bean>\n\n\t<bean id=\"eventStore\" class=\"com.alibaba.otter.canal.store.memory.MemoryEventStoreWithBuffer\">\n\t\t<property name=\"bufferSize\" value=\"${canal.instance.memory.buffer.size:16384}\" />\n\t\t<property name=\"bufferMemUnit\" value=\"${canal.instance.memory.buffer.memunit:1024}\" />\n\t\t<property name=\"batchMode\" value=\"${canal.instance.memory.batch.mode:MEMSIZE}\" />\n\t\t<property name=\"ddlIsolation\" value=\"${canal.instance.get.ddl.isolation:false}\" />\n\t\t<property name=\"raw\" value=\"${canal.instance.memory.rawEntry:true}\" />\n\t</bean>\n\n\t<bean id=\"eventSink\" class=\"com.alibaba.otter.canal.sink.entry.EntryEventSink\">\n\t\t<property name=\"eventStore\" ref=\"eventStore\" />\n\t\t<property name=\"filterTransactionEntry\" value=\"${canal.instance.filter.transaction.entry:false}\"/>\n\t</bean>\n\n\t<bean id=\"eventParser\" parent=\"baseEventParser\" >\n\t\t<property name=\"destination\" value=\"${canal.instance.destination}\" />\n\t\t<property name=\"slaveId\" value=\"${canal.instance.mysql.slaveId:0}\" />\n\t\t<!-- 心跳配置 -->\n\t\t<property name=\"detectingEnable\" value=\"${canal.instance.detecting.enable:false}\" />\n\t\t<property name=\"detectingSQL\" value=\"${canal.instance.detecting.sql}\" />\n\t\t<property name=\"detectingIntervalInSeconds\" value=\"${canal.instance.detecting.interval.time:5}\" />\n\t\t<property name=\"haController\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.ha.HeartBeatHAController\">\n\t\t\t\t<property name=\"detectingRetryTimes\" value=\"${canal.instance.detecting.retry.threshold:3}\" />\n\t\t\t\t<property name=\"switchEnable\" value=\"${canal.instance.detecting.heartbeatHaEnable:false}\" />\n\t\t\t</bean>\n\t\t</property>\n\n\t\t<property name=\"alarmHandler\" ref=\"alarmHandler\" />\n\n\t\t<!-- 解析过滤处理 -->\n\t\t<property name=\"eventFilter\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.filter.aviater.AviaterRegexFilter\" >\n\t\t\t\t<constructor-arg index=\"0\" value=\"${canal.instance.filter.regex:.*\\..*}\" />\n\t\t\t</bean>\n\t\t</property>\n\n\t\t<property name=\"eventBlackFilter\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.filter.aviater.AviaterRegexFilter\" >\n\t\t\t\t<constructor-arg index=\"0\" value=\"${canal.instance.filter.black.regex:}\" />\n\t\t\t\t<constructor-arg index=\"1\" value=\"false\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t\n\t\t<property name=\"fieldFilter\" value=\"${canal.instance.filter.field}\" />\n\t\t<property name=\"fieldBlackFilter\" value=\"${canal.instance.filter.black.field}\" />\n\n\t\t<!-- 最大事务解析大小，超过该大小后事务将被切分为多个事务投递 -->\n\t\t<property name=\"transactionSize\" value=\"${canal.instance.transaction.size:1024}\" />\n\n\t\t<!-- 网络链接参数 -->\n\t\t<property name=\"receiveBufferSize\" value=\"${canal.instance.network.receiveBufferSize:16384}\" />\n\t\t<property name=\"sendBufferSize\" value=\"${canal.instance.network.sendBufferSize:16384}\" />\n\t\t<property name=\"defaultConnectionTimeoutInSeconds\" value=\"${canal.instance.network.soTimeout:30}\" />\n\n\t\t<!-- 解析编码 -->\n\t\t<property name=\"connectionCharset\" value=\"${canal.instance.connectionCharset:UTF-8}\" />\n\n\t\t<!-- 解析位点记录 -->\n\t\t<property name=\"logPositionManager\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.index.FailbackLogPositionManager\">\n\t\t\t\t<constructor-arg>\n\t\t\t\t\t<bean class=\"com.alibaba.otter.canal.parse.index.MemoryLogPositionManager\" />\n\t\t\t\t</constructor-arg>\n\t\t\t\t<constructor-arg>\n\t\t\t\t\t<bean class=\"com.alibaba.otter.canal.parse.index.MetaLogPositionManager\">\n\t\t\t\t\t\t<constructor-arg ref=\"metaManager\"/>\n\t\t\t\t\t</bean>\n\t\t\t\t</constructor-arg>\n\t\t\t</bean>\n\t\t</property>\n\n\t\t<!-- failover切换时回退的时间 -->\n\t\t<property name=\"fallbackIntervalInSeconds\" value=\"${canal.instance.fallbackIntervalInSeconds:60}\" />\n\n\t\t<!-- 解析数据库信息 -->\n\t\t<property name=\"masterInfo\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.support.AuthenticationInfo\" init-method=\"initPwd\">\n\t\t\t\t<property name=\"address\" value=\"${canal.instance.master.address}\" />\n\t\t\t\t<property name=\"username\" value=\"${canal.instance.dbUsername:retl}\" />\n\t\t\t\t<property name=\"password\" value=\"${canal.instance.dbPassword:retl}\" />\n\t\t\t\t<property name=\"pwdPublicKey\" value=\"${canal.instance.pwdPublicKey:retl}\" />\n\t\t\t\t<property name=\"enableDruid\" value=\"${canal.instance.enableDruid:false}\" />\n\t\t\t\t<property name=\"defaultDatabaseName\" value=\"${canal.instance.defaultDatabaseName:}\" />\n\t\t\t\t<property name=\"sslInfo\">\n\t\t\t\t\t<bean class=\"com.alibaba.otter.canal.parse.driver.mysql.ssl.SslInfo\">\n\t\t\t\t\t\t<property name=\"sslMode\" value=\"${canal.instance.master.sslMode:DISABLED}\"/>\n\t\t\t\t\t\t<property name=\"tlsVersions\" value=\"${canal.instance.master.tlsVersions:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStoreType\" value=\"${canal.instance.master.trustCertificateKeyStoreType:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStoreUrl\" value=\"${canal.instance.master.trustCertificateKeyStoreUrl:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStorePassword\" value=\"${canal.instance.master.trustCertificateKeyStorePassword:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStoreType\" value=\"${canal.instance.master.clientCertificateKeyStoreType:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStoreUrl\" value=\"${canal.instance.master.clientCertificateKeyStoreUrl:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStorePassword\" value=\"${canal.instance.master.clientCertificateKeyStorePassword:}\"/>\n\t\t\t\t\t</bean>\n\t\t\t\t</property>\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"standbyInfo\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.support.AuthenticationInfo\" init-method=\"initPwd\">\n\t\t\t\t<property name=\"address\" value=\"${canal.instance.standby.address}\" />\n\t\t\t\t<property name=\"username\" value=\"${canal.instance.dbUsername:retl}\" />\n\t\t\t\t<property name=\"password\" value=\"${canal.instance.dbPassword:retl}\" />\n\t\t\t\t<property name=\"pwdPublicKey\" value=\"${canal.instance.pwdPublicKey:retl}\" />\n\t\t\t\t<property name=\"enableDruid\" value=\"${canal.instance.enableDruid:false}\" />\n\t\t\t\t<property name=\"defaultDatabaseName\" value=\"${canal.instance.defaultDatabaseName:}\" />\n\t\t\t\t<property name=\"sslInfo\">\n\t\t\t\t\t<bean class=\"com.alibaba.otter.canal.parse.driver.mysql.ssl.SslInfo\">\n\t\t\t\t\t\t<property name=\"sslMode\" value=\"${canal.instance.standby.sslMode:DISABLED}\"/>\n\t\t\t\t\t\t<property name=\"tlsVersions\" value=\"${canal.instance.standby.tlsVersions:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStoreType\" value=\"${canal.instance.standby.trustCertificateKeyStoreType:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStoreUrl\" value=\"${canal.instance.standby.trustCertificateKeyStoreUrl:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStorePassword\" value=\"${canal.instance.standby.trustCertificateKeyStorePassword:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStoreType\" value=\"${canal.instance.standby.clientCertificateKeyStoreType:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStoreUrl\" value=\"${canal.instance.standby.clientCertificateKeyStoreUrl:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStorePassword\" value=\"${canal.instance.standby.clientCertificateKeyStorePassword:}\"/>\n\t\t\t\t\t</bean>\n\t\t\t\t</property>\n\t\t\t</bean>\n\t\t</property>\n\n\t\t<!-- 解析起始位点 -->\n\t\t<property name=\"masterPosition\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.protocol.position.EntryPosition\">\n\t\t\t\t<property name=\"journalName\" value=\"${canal.instance.master.journal.name}\" />\n\t\t\t\t<property name=\"position\" value=\"${canal.instance.master.position}\" />\n\t\t\t\t<property name=\"timestamp\" value=\"${canal.instance.master.timestamp}\" />\n\t\t\t\t<property name=\"gtid\" value=\"${canal.instance.master.gtid}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"standbyPosition\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.protocol.position.EntryPosition\">\n\t\t\t\t<property name=\"journalName\" value=\"${canal.instance.standby.journal.name}\" />\n\t\t\t\t<property name=\"position\" value=\"${canal.instance.standby.position}\" />\n\t\t\t\t<property name=\"timestamp\" value=\"${canal.instance.standby.timestamp}\" />\n\t\t\t\t<property name=\"gtid\" value=\"${canal.instance.standby.gtid}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"filterQueryDml\" value=\"${canal.instance.filter.query.dml:false}\" />\n\t\t<property name=\"filterQueryDcl\" value=\"${canal.instance.filter.query.dcl:false}\" />\n\t\t<property name=\"filterQueryDdl\" value=\"${canal.instance.filter.query.ddl:false}\" />\n\t\t<property name=\"useDruidDdlFilter\" value=\"${canal.instance.filter.druid.ddl:true}\" />\n\t\t<property name=\"filterDmlInsert\" value=\"${canal.instance.filter.dml.insert:false}\" />\n\t\t<property name=\"filterDmlUpdate\" value=\"${canal.instance.filter.dml.update:false}\" />\n\t\t<property name=\"filterDmlDelete\" value=\"${canal.instance.filter.dml.delete:false}\" />\n\t\t<property name=\"filterRows\" value=\"${canal.instance.filter.rows:false}\" />\n\t\t<property name=\"filterTableError\" value=\"${canal.instance.filter.table.error:false}\" />\n\t\t<property name=\"supportBinlogFormats\" value=\"${canal.instance.binlog.format}\" />\n\t\t<property name=\"supportBinlogImages\" value=\"${canal.instance.binlog.image}\" />\n\n\t\t<!--表结构相关-->\n\t\t<property name=\"enableTsdb\" value=\"${canal.instance.tsdb.enable:true}\"/>\n\t\t<property name=\"tsdbSpringXml\" value=\"${canal.instance.tsdb.spring.xml:}\"/>\n\t\t<property name=\"tsdbJdbcUrl\" value=\"${canal.instance.tsdb.url:}\"/>\n\t\t<property name=\"tsdbJdbcUserName\" value=\"${canal.instance.tsdb.dbUsername:}\"/>\n\t\t<property name=\"tsdbJdbcPassword\" value=\"${canal.instance.tsdb.dbPassword:}\"/>\n\t\t<property name=\"tsdbSnapshotInterval\" value=\"${canal.instance.tsdb.snapshot.interval:24}\" />\n\t\t<property name=\"tsdbSnapshotExpire\" value=\"${canal.instance.tsdb.snapshot.expire:360}\" />\n\n\t\t<!--是否启用GTID模式-->\n\t\t<property name=\"isGTIDMode\" value=\"${canal.instance.gtidon:false}\"/>\n\n\t\t<!-- parallel parser -->\n\t\t<property name=\"parallel\" value=\"${canal.instance.parser.parallel:true}\" />\n\t\t<property name=\"parallelThreadSize\" value=\"${canal.instance.parser.parallelThreadSize}\" />\n\t\t<property name=\"parallelBufferSize\" value=\"${canal.instance.parser.parallelBufferSize:256}\" />\n\n\t\t<property name=\"autoResetLatestPosMode\" value=\"${canal.auto.reset.latest.pos.mode:false}\" />\n\t\t<property name=\"multiStreamEnable\" value=\"${canal.instance.multi.stream.on:false}\"/>\n\t</bean>\n\n\t<bean id=\"mqConfig\" class=\"com.alibaba.otter.canal.instance.core.CanalMQConfig\">\n\t\t<property name=\"topic\" value=\"${canal.mq.topic}\" />\n\t\t<property name=\"dynamicTopic\" value=\"${canal.mq.dynamicTopic}\" />\n\t\t<property name=\"partition\" value=\"${canal.mq.partition}\" />\n\t\t<property name=\"partitionsNum\" value=\"${canal.mq.partitionsNum}\" />\n\t\t<property name=\"partitionHash\" value=\"${canal.mq.partitionHash}\" />\n\t\t<property name=\"dynamicTopicPartitionNum\" value=\"${canal.mq.dynamicTopicPartitionNum}\" />\n\t\t<property name=\"enableDynamicQueuePartition\" value=\"${canal.mq.enableDynamicQueuePartition}\" />\n\t</bean>\n</beans>\n"
  },
  {
    "path": "deployer/src/main/resources/spring/file-instance.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:tx=\"http://www.springframework.org/schema/tx\"\n\txmlns:aop=\"http://www.springframework.org/schema/aop\" xmlns:lang=\"http://www.springframework.org/schema/lang\"\n\txmlns:context=\"http://www.springframework.org/schema/context\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd\n           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd\n           http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.0.xsd\n           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd\n           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd\"\n\tdefault-autowire=\"byName\">\n\n\t<import resource=\"classpath:spring/base-instance.xml\" />\n\n\t<bean id=\"instance\" class=\"com.alibaba.otter.canal.instance.spring.CanalInstanceWithSpring\">\n\t\t<property name=\"destination\" value=\"${canal.instance.destination}\" />\n\t\t<property name=\"eventParser\">\n\t\t\t<ref bean=\"eventParser\" />\n\t\t</property>\n\t\t<property name=\"eventSink\">\n\t\t\t<ref bean=\"eventSink\" />\n\t\t</property>\n\t\t<property name=\"eventStore\">\n\t\t\t<ref bean=\"eventStore\" />\n\t\t</property>\n\t\t<property name=\"metaManager\">\n\t\t\t<ref bean=\"metaManager\" />\n\t\t</property>\n\t\t<property name=\"alarmHandler\">\n\t\t\t<ref bean=\"alarmHandler\" />\n\t\t</property>\n        <property name=\"mqConfig\">\n            <ref bean=\"mqConfig\" />\n        </property>\n\t</bean>\n\n\t<!-- 报警处理类 -->\n\t<bean id=\"alarmHandler\" class=\"com.alibaba.otter.canal.common.alarm.LogAlarmHandler\" />\n\n\t<bean id=\"metaManager\" class=\"com.alibaba.otter.canal.meta.FileMixedMetaManager\">\n\t\t<property name=\"dataDir\" value=\"${canal.file.data.dir:../conf}\" />\n\t\t<property name=\"period\" value=\"${canal.file.flush.period:1000}\" />\n\t</bean>\n\n\t<bean id=\"eventStore\" class=\"com.alibaba.otter.canal.store.memory.MemoryEventStoreWithBuffer\">\n\t\t<property name=\"bufferSize\" value=\"${canal.instance.memory.buffer.size:16384}\" />\n\t\t<property name=\"bufferMemUnit\" value=\"${canal.instance.memory.buffer.memunit:1024}\" />\n\t\t<property name=\"batchMode\" value=\"${canal.instance.memory.batch.mode:MEMSIZE}\" />\n\t\t<property name=\"ddlIsolation\" value=\"${canal.instance.get.ddl.isolation:false}\" />\n\t\t<property name=\"raw\" value=\"${canal.instance.memory.rawEntry:true}\" />\n\t</bean>\n\n\t<bean id=\"eventSink\" class=\"com.alibaba.otter.canal.sink.entry.EntryEventSink\">\n\t\t<property name=\"eventStore\" ref=\"eventStore\" />\n\t\t<property name=\"filterTransactionEntry\" value=\"${canal.instance.filter.transaction.entry:false}\"/>\n\t</bean>\n\n\t<bean id=\"eventParser\" parent=\"baseEventParser\">\n\t\t<property name=\"destination\" value=\"${canal.instance.destination}\" />\n\t\t<property name=\"slaveId\" value=\"${canal.instance.mysql.slaveId:0}\" />\n\t\t<!-- 心跳配置 -->\n\t\t<property name=\"detectingEnable\" value=\"${canal.instance.detecting.enable:false}\" />\n\t\t<property name=\"detectingSQL\" value=\"${canal.instance.detecting.sql}\" />\n\t\t<property name=\"detectingIntervalInSeconds\" value=\"${canal.instance.detecting.interval.time:5}\" />\n\t\t<property name=\"haController\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.ha.HeartBeatHAController\">\n\t\t\t\t<property name=\"detectingRetryTimes\" value=\"${canal.instance.detecting.retry.threshold:3}\" />\n\t\t\t\t<property name=\"switchEnable\" value=\"${canal.instance.detecting.heartbeatHaEnable:false}\" />\n\t\t\t</bean>\n\t\t</property>\n\n\t\t<property name=\"alarmHandler\" ref=\"alarmHandler\" />\n\n\t\t<!-- 解析过滤处理 -->\n\t\t<property name=\"eventFilter\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.filter.aviater.AviaterRegexFilter\" >\n\t\t\t\t<constructor-arg index=\"0\" value=\"${canal.instance.filter.regex:.*\\..*}\" />\n\t\t\t</bean>\n\t\t</property>\n\n\t\t<property name=\"eventBlackFilter\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.filter.aviater.AviaterRegexFilter\" >\n\t\t\t\t<constructor-arg index=\"0\" value=\"${canal.instance.filter.black.regex:}\" />\n\t\t\t\t<constructor-arg index=\"1\" value=\"false\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t\n\t\t<property name=\"fieldFilter\" value=\"${canal.instance.filter.field}\" />\n\t\t<property name=\"fieldBlackFilter\" value=\"${canal.instance.filter.black.field}\" />\n\t\t\n\t\t<!-- 最大事务解析大小，超过该大小后事务将被切分为多个事务投递 -->\n\t\t<property name=\"transactionSize\" value=\"${canal.instance.transaction.size:1024}\" />\n\n\t\t<!-- 网络链接参数 -->\n\t\t<property name=\"receiveBufferSize\" value=\"${canal.instance.network.receiveBufferSize:16384}\" />\n\t\t<property name=\"sendBufferSize\" value=\"${canal.instance.network.sendBufferSize:16384}\" />\n\t\t<property name=\"defaultConnectionTimeoutInSeconds\" value=\"${canal.instance.network.soTimeout:30}\" />\n\n\t\t<!-- 解析编码 -->\n\t\t<property name=\"connectionCharset\" value=\"${canal.instance.connectionCharset:UTF-8}\" />\n\n\t\t<!-- 解析位点记录 -->\n\t\t<property name=\"logPositionManager\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.index.FailbackLogPositionManager\">\n\t\t\t\t<constructor-arg>\n\t\t\t\t\t<bean class=\"com.alibaba.otter.canal.parse.index.MemoryLogPositionManager\" />\n\t\t\t\t</constructor-arg>\n\t\t\t\t<constructor-arg>\n\t\t\t\t\t<bean class=\"com.alibaba.otter.canal.parse.index.MetaLogPositionManager\">\n\t\t\t\t\t\t<constructor-arg ref=\"metaManager\"/>\n\t\t\t\t\t</bean>\n\t\t\t\t</constructor-arg>\n\t\t\t</bean>\n\t\t</property>\n\n\t\t<!-- failover切换时回退的时间 -->\n\t\t<property name=\"fallbackIntervalInSeconds\" value=\"${canal.instance.fallbackIntervalInSeconds:60}\" />\n\n\t\t<!-- 解析数据库信息 -->\n\t\t<property name=\"masterInfo\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.support.AuthenticationInfo\" init-method=\"initPwd\">\n\t\t\t\t<property name=\"address\" value=\"${canal.instance.master.address}\" />\n\t\t\t\t<property name=\"username\" value=\"${canal.instance.dbUsername:retl}\" />\n\t\t\t\t<property name=\"password\" value=\"${canal.instance.dbPassword:retl}\" />\n\t\t\t\t<property name=\"pwdPublicKey\" value=\"${canal.instance.pwdPublicKey:retl}\" />\n\t\t\t\t<property name=\"enableDruid\" value=\"${canal.instance.enableDruid:false}\" />\n\t\t\t\t<property name=\"defaultDatabaseName\" value=\"${canal.instance.defaultDatabaseName:}\" />\n\t\t\t\t<property name=\"sslInfo\">\n\t\t\t\t\t<bean class=\"com.alibaba.otter.canal.parse.driver.mysql.ssl.SslInfo\">\n\t\t\t\t\t\t<property name=\"sslMode\" value=\"${canal.instance.master.sslMode:DISABLED}\"/>\n\t\t\t\t\t\t<property name=\"tlsVersions\" value=\"${canal.instance.master.tlsVersions:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStoreType\" value=\"${canal.instance.master.trustCertificateKeyStoreType:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStoreUrl\" value=\"${canal.instance.master.trustCertificateKeyStoreUrl:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStorePassword\" value=\"${canal.instance.master.trustCertificateKeyStorePassword:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStoreType\" value=\"${canal.instance.master.clientCertificateKeyStoreType:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStoreUrl\" value=\"${canal.instance.master.clientCertificateKeyStoreUrl:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStorePassword\" value=\"${canal.instance.master.clientCertificateKeyStorePassword:}\"/>\n\t\t\t\t\t</bean>\n\t\t\t\t</property>\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"standbyInfo\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.support.AuthenticationInfo\" init-method=\"initPwd\">\n\t\t\t\t<property name=\"address\" value=\"${canal.instance.standby.address}\" />\n\t\t\t\t<property name=\"username\" value=\"${canal.instance.dbUsername:retl}\" />\n\t\t\t\t<property name=\"password\" value=\"${canal.instance.dbPassword:retl}\" />\n\t\t\t\t<property name=\"pwdPublicKey\" value=\"${canal.instance.pwdPublicKey:retl}\" />\n\t\t\t\t<property name=\"enableDruid\" value=\"${canal.instance.enableDruid:false}\" />\n\t\t\t\t<property name=\"defaultDatabaseName\" value=\"${canal.instance.defaultDatabaseName:}\" />\n\t\t\t\t<property name=\"sslInfo\">\n\t\t\t\t\t<bean class=\"com.alibaba.otter.canal.parse.driver.mysql.ssl.SslInfo\">\n\t\t\t\t\t\t<property name=\"sslMode\" value=\"${canal.instance.standby.sslMode:DISABLED}\"/>\n\t\t\t\t\t\t<property name=\"tlsVersions\" value=\"${canal.instance.standby.tlsVersions:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStoreType\" value=\"${canal.instance.standby.trustCertificateKeyStoreType:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStoreUrl\" value=\"${canal.instance.standby.trustCertificateKeyStoreUrl:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStorePassword\" value=\"${canal.instance.standby.trustCertificateKeyStorePassword:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStoreType\" value=\"${canal.instance.standby.clientCertificateKeyStoreType:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStoreUrl\" value=\"${canal.instance.standby.clientCertificateKeyStoreUrl:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStorePassword\" value=\"${canal.instance.standby.clientCertificateKeyStorePassword:}\"/>\n\t\t\t\t\t</bean>\n\t\t\t\t</property>\n\t\t\t</bean>\n\t\t</property>\n\n\t\t<!-- 解析起始位点 -->\n\t\t<property name=\"masterPosition\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.protocol.position.EntryPosition\">\n\t\t\t\t<property name=\"journalName\" value=\"${canal.instance.master.journal.name}\" />\n\t\t\t\t<property name=\"position\" value=\"${canal.instance.master.position}\" />\n\t\t\t\t<property name=\"timestamp\" value=\"${canal.instance.master.timestamp}\" />\n\t\t\t\t<property name=\"gtid\" value=\"${canal.instance.master.gtid}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"standbyPosition\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.protocol.position.EntryPosition\">\n\t\t\t\t<property name=\"journalName\" value=\"${canal.instance.standby.journal.name}\" />\n\t\t\t\t<property name=\"position\" value=\"${canal.instance.standby.position}\" />\n\t\t\t\t<property name=\"timestamp\" value=\"${canal.instance.standby.timestamp}\" />\n\t\t\t\t<property name=\"gtid\" value=\"${canal.instance.standby.gtid}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"filterQueryDml\" value=\"${canal.instance.filter.query.dml:false}\" />\n\t\t<property name=\"filterQueryDcl\" value=\"${canal.instance.filter.query.dcl:false}\" />\n\t\t<property name=\"filterQueryDdl\" value=\"${canal.instance.filter.query.ddl:false}\" />\n\t\t<property name=\"useDruidDdlFilter\" value=\"${canal.instance.filter.druid.ddl:true}\" />\n\t\t<property name=\"filterDmlInsert\" value=\"${canal.instance.filter.dml.insert:false}\" />\n\t\t<property name=\"filterDmlUpdate\" value=\"${canal.instance.filter.dml.update:false}\" />\n\t\t<property name=\"filterDmlDelete\" value=\"${canal.instance.filter.dml.delete:false}\" />\n\t\t<property name=\"filterRows\" value=\"${canal.instance.filter.rows:false}\" />\n\t\t<property name=\"filterTableError\" value=\"${canal.instance.filter.table.error:false}\" />\n\t\t<property name=\"supportBinlogFormats\" value=\"${canal.instance.binlog.format}\" />\n\t\t<property name=\"supportBinlogImages\" value=\"${canal.instance.binlog.image}\" />\n\n\t\t<!--表结构相关-->\n\t\t<property name=\"enableTsdb\" value=\"${canal.instance.tsdb.enable:true}\"/>\n\t\t<property name=\"tsdbSpringXml\" value=\"${canal.instance.tsdb.spring.xml:}\"/>\n\t\t<property name=\"tsdbJdbcUrl\" value=\"${canal.instance.tsdb.url:}\"/>\n\t\t<property name=\"tsdbJdbcUserName\" value=\"${canal.instance.tsdb.dbUsername:}\"/>\n\t\t<property name=\"tsdbJdbcPassword\" value=\"${canal.instance.tsdb.dbPassword:}\"/>\n\t\t<property name=\"tsdbSnapshotInterval\" value=\"${canal.instance.tsdb.snapshot.interval:24}\" />\n\t\t<property name=\"tsdbSnapshotExpire\" value=\"${canal.instance.tsdb.snapshot.expire:360}\" />\n\n\t\t<!--是否启用GTID模式-->\n\t\t<property name=\"isGTIDMode\" value=\"${canal.instance.gtidon:false}\"/>\n\n\t\t<!-- parallel parser -->\n\t\t<property name=\"parallel\" value=\"${canal.instance.parser.parallel:true}\" />\n\t\t<property name=\"parallelThreadSize\" value=\"${canal.instance.parser.parallelThreadSize}\" />\n\t\t<property name=\"parallelBufferSize\" value=\"${canal.instance.parser.parallelBufferSize:256}\" />\n\n\t\t<property name=\"autoResetLatestPosMode\" value=\"${canal.auto.reset.latest.pos.mode:false}\" />\n\t\t<property name=\"multiStreamEnable\" value=\"${canal.instance.multi.stream.on:false}\"/>\n\t</bean>\n\n\t<bean id=\"mqConfig\" class=\"com.alibaba.otter.canal.instance.core.CanalMQConfig\">\n        <property name=\"topic\" value=\"${canal.mq.topic}\" />\n\t\t<property name=\"dynamicTopic\" value=\"${canal.mq.dynamicTopic}\" />\n        <property name=\"partition\" value=\"${canal.mq.partition}\" />\n        <property name=\"partitionsNum\" value=\"${canal.mq.partitionsNum}\" />\n        <property name=\"partitionHash\" value=\"${canal.mq.partitionHash}\" />\n\t\t<property name=\"dynamicTopicPartitionNum\" value=\"${canal.mq.dynamicTopicPartitionNum}\" />\n\t\t<property name=\"enableDynamicQueuePartition\" value=\"${canal.mq.enableDynamicQueuePartition}\" />\n\t</bean>\n</beans>\n"
  },
  {
    "path": "deployer/src/main/resources/spring/group-instance.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:tx=\"http://www.springframework.org/schema/tx\"\n\txmlns:aop=\"http://www.springframework.org/schema/aop\" xmlns:lang=\"http://www.springframework.org/schema/lang\"\n\txmlns:context=\"http://www.springframework.org/schema/context\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd\n           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd\n           http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.0.xsd\n           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd\n           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd\"\n\tdefault-autowire=\"byName\">\n\n\t<import resource=\"classpath:spring/base-instance.xml\" />\n\n\t<bean id=\"instance\" class=\"com.alibaba.otter.canal.instance.spring.CanalInstanceWithSpring\">\n\t\t<property name=\"destination\" value=\"${canal.instance.destination}\" />\n\t\t<property name=\"eventParser\">\n\t\t\t<ref bean=\"eventParser\" />\n\t\t</property>\n\t\t<property name=\"eventSink\">\n\t\t\t<ref bean=\"eventSink\" />\n\t\t</property>\n\t\t<property name=\"eventStore\">\n\t\t\t<ref bean=\"eventStore\" />\n\t\t</property>\n\t\t<property name=\"metaManager\">\n\t\t\t<ref bean=\"metaManager\" />\n\t\t</property>\n\t\t<property name=\"alarmHandler\">\n\t\t\t<ref bean=\"alarmHandler\" />\n\t\t</property>\n\t\t<property name=\"mqConfig\">\n\t\t\t<ref bean=\"mqConfig\" />\n\t\t</property>\n\t</bean>\n\n\t<!-- 报警处理类 -->\n\t<bean id=\"alarmHandler\" class=\"com.alibaba.otter.canal.common.alarm.LogAlarmHandler\" />\n\n\t<bean id=\"metaManager\" class=\"com.alibaba.otter.canal.meta.MemoryMetaManager\" />\n\n\t<bean id=\"eventStore\" class=\"com.alibaba.otter.canal.store.memory.MemoryEventStoreWithBuffer\">\n\t\t<property name=\"bufferSize\" value=\"${canal.instance.memory.buffer.size:16384}\" />\n\t\t<property name=\"bufferMemUnit\" value=\"${canal.instance.memory.buffer.memunit:1024}\" />\n\t\t<property name=\"batchMode\" value=\"${canal.instance.memory.batch.mode:MEMSIZE}\" />\n\t\t<property name=\"ddlIsolation\" value=\"${canal.instance.get.ddl.isolation:false}\" />\n\t\t<property name=\"raw\" value=\"${canal.instance.memory.rawEntry:true}\" />\n\t</bean>\n\n\t<bean id=\"eventSink\" class=\"com.alibaba.otter.canal.sink.entry.EntryEventSink\">\n\t\t<property name=\"eventStore\" ref=\"eventStore\" />\n\t\t<property name=\"filterTransactionEntry\" value=\"${canal.instance.filter.transaction.entry:false}\"/>\n\t</bean>\n\n\t<bean id=\"eventParser\" class=\"com.alibaba.otter.canal.parse.inbound.group.GroupEventParser\">\n\t\t<property name=\"eventParsers\">\n\t\t\t<list>\n\t\t\t\t<ref bean=\"eventParser1\" />\n\t\t\t\t<ref bean=\"eventParser2\" />\n\t\t\t</list>\n\t\t</property>\n\t</bean>\n\n\t<bean id=\"eventParser1\" parent=\"baseEventParser\">\n\t\t<property name=\"destination\" value=\"${canal.instance.destination}\" />\n\t\t<property name=\"slaveId\" value=\"${canal.instance.mysql.slaveId:0}\" />\n\t\t<!-- 心跳配置 -->\n\t\t<property name=\"detectingEnable\" value=\"${canal.instance.detecting.enable:false}\" />\n\t\t<property name=\"detectingSQL\" value=\"${canal.instance.detecting.sql}\" />\n\t\t<property name=\"detectingIntervalInSeconds\" value=\"${canal.instance.detecting.interval.time:5}\" />\n\t\t<property name=\"haController\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.ha.HeartBeatHAController\">\n\t\t\t\t<property name=\"detectingRetryTimes\" value=\"${canal.instance.detecting.retry.threshold:3}\" />\n\t\t\t\t<property name=\"switchEnable\" value=\"${canal.instance.detecting.heartbeatHaEnable:false}\" />\n\t\t\t</bean>\n\t\t</property>\n\n\t\t<property name=\"alarmHandler\" ref=\"alarmHandler\" />\n\n\t\t<!-- 解析过滤处理 -->\n\t\t<property name=\"eventFilter\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.filter.aviater.AviaterRegexFilter\" >\n\t\t\t\t<constructor-arg index=\"0\" value=\"${canal.instance.filter.regex:.*\\..*}\" />\n\t\t\t</bean>\n\t\t</property>\n\n\t\t<property name=\"eventBlackFilter\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.filter.aviater.AviaterRegexFilter\" >\n\t\t\t\t<constructor-arg index=\"0\" value=\"${canal.instance.filter.black.regex:}\" />\n\t\t\t\t<constructor-arg index=\"1\" value=\"false\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t\n\t\t<property name=\"fieldFilter\" value=\"${canal.instance.filter.field}\" />\n\t\t<property name=\"fieldBlackFilter\" value=\"${canal.instance.filter.black.field}\" />\n\t\t\n\t\t<!-- 最大事务解析大小，超过该大小后事务将被切分为多个事务投递 -->\n\t\t<property name=\"transactionSize\" value=\"${canal.instance.transaction.size:1024}\" />\n\n\t\t<!-- 网络链接参数 -->\n\t\t<property name=\"receiveBufferSize\" value=\"${canal.instance.network.receiveBufferSize:16384}\" />\n\t\t<property name=\"sendBufferSize\" value=\"${canal.instance.network.sendBufferSize:16384}\" />\n\t\t<property name=\"defaultConnectionTimeoutInSeconds\" value=\"${canal.instance.network.soTimeout:30}\" />\n\n\t\t<!-- 解析编码 -->\n\t\t<property name=\"connectionCharset\" value=\"${canal.instance.connectionCharset:UTF-8}\" />\n\n\t\t<!-- 解析位点记录 -->\n\t\t<property name=\"logPositionManager\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.index.MemoryLogPositionManager\" />\n\t\t</property>\n\n\t\t<!-- failover切换时回退的时间 -->\n\t\t<property name=\"fallbackIntervalInSeconds\" value=\"${canal.instance.fallbackIntervalInSeconds:60}\" />\n\n\t\t<!-- 解析数据库信息 -->\n\t\t<property name=\"masterInfo\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.support.AuthenticationInfo\" init-method=\"initPwd\">\n\t\t\t\t<property name=\"address\" value=\"${canal.instance.master1.address}\" />\n\t\t\t\t<property name=\"username\" value=\"${canal.instance.dbUsername:retl}\" />\n\t\t\t\t<property name=\"password\" value=\"${canal.instance.dbPassword:retl}\" />\n\t\t\t\t<property name=\"pwdPublicKey\" value=\"${canal.instance.pwdPublicKey:retl}\" />\n\t\t\t\t<property name=\"enableDruid\" value=\"${canal.instance.enableDruid:false}\" />\n\t\t\t\t<property name=\"defaultDatabaseName\" value=\"${canal.instance.defaultDatabaseName:}\" />\n\t\t\t\t<property name=\"sslInfo\">\n\t\t\t\t\t<bean class=\"com.alibaba.otter.canal.parse.driver.mysql.ssl.SslInfo\">\n\t\t\t\t\t\t<property name=\"sslMode\" value=\"${canal.instance.master.sslMode:DISABLED}\"/>\n\t\t\t\t\t\t<property name=\"tlsVersions\" value=\"${canal.instance.master.tlsVersions:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStoreType\" value=\"${canal.instance.master.trustCertificateKeyStoreType:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStoreUrl\" value=\"${canal.instance.master.trustCertificateKeyStoreUrl:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStorePassword\" value=\"${canal.instance.master.trustCertificateKeyStorePassword:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStoreType\" value=\"${canal.instance.master.clientCertificateKeyStoreType:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStoreUrl\" value=\"${canal.instance.master.clientCertificateKeyStoreUrl:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStorePassword\" value=\"${canal.instance.master.clientCertificateKeyStorePassword:}\"/>\n\t\t\t\t\t</bean>\n\t\t\t\t</property>\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"standbyInfo\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.support.AuthenticationInfo\" init-method=\"initPwd\">\n\t\t\t\t<property name=\"address\" value=\"${canal.instance.standby1.address}\" />\n\t\t\t\t<property name=\"username\" value=\"${canal.instance.dbUsername:retl}\" />\n\t\t\t\t<property name=\"password\" value=\"${canal.instance.dbPassword:retl}\" />\n\t\t\t\t<property name=\"pwdPublicKey\" value=\"${canal.instance.pwdPublicKey:retl}\" />\n\t\t\t\t<property name=\"enableDruid\" value=\"${canal.instance.enableDruid:false}\" />\n\t\t\t\t<property name=\"defaultDatabaseName\" value=\"${canal.instance.defaultDatabaseName:}\" />\n\t\t\t\t<property name=\"sslInfo\">\n\t\t\t\t\t<bean class=\"com.alibaba.otter.canal.parse.driver.mysql.ssl.SslInfo\">\n\t\t\t\t\t\t<property name=\"sslMode\" value=\"${canal.instance.standby.sslMode:DISABLED}\"/>\n\t\t\t\t\t\t<property name=\"tlsVersions\" value=\"${canal.instance.standby.tlsVersions:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStoreType\" value=\"${canal.instance.standby.trustCertificateKeyStoreType:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStoreUrl\" value=\"${canal.instance.standby.trustCertificateKeyStoreUrl:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStorePassword\" value=\"${canal.instance.standby.trustCertificateKeyStorePassword:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStoreType\" value=\"${canal.instance.standby.clientCertificateKeyStoreType:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStoreUrl\" value=\"${canal.instance.standby.clientCertificateKeyStoreUrl:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStorePassword\" value=\"${canal.instance.standby.clientCertificateKeyStorePassword:}\"/>\n\t\t\t\t\t</bean>\n\t\t\t\t</property>\n\t\t\t</bean>\n\t\t</property>\n\n\t\t<!-- 解析起始位点 -->\n\t\t<property name=\"masterPosition\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.protocol.position.EntryPosition\">\n\t\t\t\t<property name=\"journalName\" value=\"${canal.instance.master1.journal.name}\" />\n\t\t\t\t<property name=\"position\" value=\"${canal.instance.master1.position}\" />\n\t\t\t\t<property name=\"timestamp\" value=\"${canal.instance.master1.timestamp}\" />\n\t\t\t\t<property name=\"gtid\" value=\"${canal.instance.master1.gtid}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"standbyPosition\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.protocol.position.EntryPosition\">\n\t\t\t\t<property name=\"journalName\" value=\"${canal.instance.standby1.journal.name}\" />\n\t\t\t\t<property name=\"position\" value=\"${canal.instance.standby1.position}\" />\n\t\t\t\t<property name=\"timestamp\" value=\"${canal.instance.standby1.timestamp}\" />\n\t\t\t\t<property name=\"gtid\" value=\"${canal.instance.standby1.gtid}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"filterQueryDml\" value=\"${canal.instance.filter.query.dml:false}\" />\n\t\t<property name=\"filterQueryDcl\" value=\"${canal.instance.filter.query.dcl:false}\" />\n\t\t<property name=\"filterQueryDdl\" value=\"${canal.instance.filter.query.ddl:false}\" />\n\t\t<property name=\"useDruidDdlFilter\" value=\"${canal.instance.filter.druid.ddl:true}\" />\n\t\t<property name=\"filterDmlInsert\" value=\"${canal.instance.filter.dml.insert:false}\" />\n\t\t<property name=\"filterDmlUpdate\" value=\"${canal.instance.filter.dml.update:false}\" />\n\t\t<property name=\"filterDmlDelete\" value=\"${canal.instance.filter.dml.delete:false}\" />\n\t\t<property name=\"filterTableError\" value=\"${canal.instance.filter.table.error:false}\" />\n\t\t<property name=\"supportBinlogFormats\" value=\"${canal.instance.binlog.format}\" />\n\t\t<property name=\"supportBinlogImages\" value=\"${canal.instance.binlog.image}\" />\n\n\t\t<!-- parallel parser -->\n\t\t<property name=\"parallel\" value=\"${canal.instance.parser.parallel:true}\" />\n\t\t<property name=\"parallelThreadSize\" value=\"${canal.instance.parser.parallelThreadSize}\" />\n\t\t<property name=\"parallelBufferSize\" value=\"${canal.instance.parser.parallelBufferSize:256}\" />\n\n\t\t<property name=\"autoResetLatestPosMode\" value=\"${canal.auto.reset.latest.pos.mode:false}\" />\n\t\t<property name=\"multiStreamEnable\" value=\"${canal.instance.multi.stream.on:false}\"/>\n\t</bean>\n\n\t<bean id=\"eventParser2\" parent=\"baseEventParser\">\n\t\t<property name=\"destination\" value=\"${canal.instance.destination}\" />\n\t\t<property name=\"slaveId\" value=\"${canal.instance.mysql.slaveId:0}\" />\n\t\t<!-- 心跳配置 -->\n\t\t<property name=\"detectingEnable\" value=\"${canal.instance.detecting.enable:false}\" />\n\t\t<property name=\"detectingSQL\" value=\"${canal.instance.detecting.sql}\" />\n\t\t<property name=\"detectingIntervalInSeconds\" value=\"${canal.instance.detecting.interval.time:5}\" />\n\t\t<property name=\"haController\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.ha.HeartBeatHAController\">\n\t\t\t\t<property name=\"detectingRetryTimes\" value=\"${canal.instance.detecting.retry.threshold:3}\" />\n\t\t\t\t<property name=\"switchEnable\" value=\"${canal.instance.detecting.heartbeatHaEnable:false}\" />\n\t\t\t</bean>\n\t\t</property>\n\n\t\t<property name=\"alarmHandler\" ref=\"alarmHandler\" />\n\n\t\t<!-- 解析过滤处理 -->\n\t\t<property name=\"eventFilter\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.filter.aviater.AviaterRegexFilter\" >\n\t\t\t\t<constructor-arg index=\"0\" value=\"${canal.instance.filter.regex:.*\\..*}\" />\n\t\t\t</bean>\n\t\t</property>\n\n\t\t<property name=\"eventBlackFilter\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.filter.aviater.AviaterRegexFilter\" >\n\t\t\t\t<constructor-arg index=\"0\" value=\"${canal.instance.filter.black.regex:}\" />\n\t\t\t\t<constructor-arg index=\"1\" value=\"false\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<!-- 最大事务解析大小，超过该大小后事务将被切分为多个事务投递 -->\n\t\t<property name=\"transactionSize\" value=\"${canal.instance.transaction.size:1024}\" />\n\n\t\t<!-- 网络链接参数 -->\n\t\t<property name=\"receiveBufferSize\" value=\"${canal.instance.network.receiveBufferSize:16384}\" />\n\t\t<property name=\"sendBufferSize\" value=\"${canal.instance.network.sendBufferSize:16384}\" />\n\t\t<property name=\"defaultConnectionTimeoutInSeconds\" value=\"${canal.instance.network.soTimeout:30}\" />\n\n\t\t<!-- 解析编码 -->\n\t\t<property name=\"connectionCharset\" value=\"${canal.instance.connectionCharset:UTF-8}\" />\n\n\t\t<!-- 解析位点记录 -->\n\t\t<property name=\"logPositionManager\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.index.MemoryLogPositionManager\" />\n\t\t</property>\n\n\t\t<!-- failover切换时回退的时间 -->\n\t\t<property name=\"fallbackIntervalInSeconds\" value=\"${canal.instance.fallbackIntervalInSeconds:60}\" />\n\n\t\t<!-- 解析数据库信息 -->\n\t\t<property name=\"masterInfo\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.support.AuthenticationInfo\" init-method=\"initPwd\">\n\t\t\t\t<property name=\"address\" value=\"${canal.instance.master2.address}\" />\n\t\t\t\t<property name=\"username\" value=\"${canal.instance.dbUsername:retl}\" />\n\t\t\t\t<property name=\"password\" value=\"${canal.instance.dbPassword:retl}\" />\n\t\t\t\t<property name=\"pwdPublicKey\" value=\"${canal.instance.pwdPublicKey:retl}\" />\n\t\t\t\t<property name=\"enableDruid\" value=\"${canal.instance.enableDruid:false}\" />\n\t\t\t\t<property name=\"defaultDatabaseName\" value=\"${canal.instance.defaultDatabaseName:}\" />\n\t\t\t\t<property name=\"sslInfo\">\n\t\t\t\t\t<bean class=\"com.alibaba.otter.canal.parse.driver.mysql.ssl.SslInfo\">\n\t\t\t\t\t\t<property name=\"sslMode\" value=\"${canal.instance.master.sslMode:DISABLED}\"/>\n\t\t\t\t\t\t<property name=\"tlsVersions\" value=\"${canal.instance.master.tlsVersions:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStoreType\" value=\"${canal.instance.master.trustCertificateKeyStoreType:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStoreUrl\" value=\"${canal.instance.master.trustCertificateKeyStoreUrl:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStorePassword\" value=\"${canal.instance.master.trustCertificateKeyStorePassword:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStoreType\" value=\"${canal.instance.master.clientCertificateKeyStoreType:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStoreUrl\" value=\"${canal.instance.master.clientCertificateKeyStoreUrl:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStorePassword\" value=\"${canal.instance.master.clientCertificateKeyStorePassword:}\"/>\n\t\t\t\t\t</bean>\n\t\t\t\t</property>\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"standbyInfo\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.support.AuthenticationInfo\" init-method=\"initPwd\">\n\t\t\t\t<property name=\"address\" value=\"${canal.instance.standby2.address}\" />\n\t\t\t\t<property name=\"username\" value=\"${canal.instance.dbUsername:retl}\" />\n\t\t\t\t<property name=\"password\" value=\"${canal.instance.dbPassword:retl}\" />\n\t\t\t\t<property name=\"pwdPublicKey\" value=\"${canal.instance.pwdPublicKey:retl}\" />\n\t\t\t\t<property name=\"enableDruid\" value=\"${canal.instance.enableDruid:false}\" />\n\t\t\t\t<property name=\"defaultDatabaseName\" value=\"${canal.instance.defaultDatabaseName:}\" />\n\t\t\t\t<property name=\"sslInfo\">\n\t\t\t\t\t<bean class=\"com.alibaba.otter.canal.parse.driver.mysql.ssl.SslInfo\">\n\t\t\t\t\t\t<property name=\"sslMode\" value=\"${canal.instance.standby.sslMode:DISABLED}\"/>\n\t\t\t\t\t\t<property name=\"tlsVersions\" value=\"${canal.instance.standby.tlsVersions:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStoreType\" value=\"${canal.instance.standby.trustCertificateKeyStoreType:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStoreUrl\" value=\"${canal.instance.standby.trustCertificateKeyStoreUrl:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStorePassword\" value=\"${canal.instance.standby.trustCertificateKeyStorePassword:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStoreType\" value=\"${canal.instance.standby.clientCertificateKeyStoreType:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStoreUrl\" value=\"${canal.instance.standby.clientCertificateKeyStoreUrl:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStorePassword\" value=\"${canal.instance.standby.clientCertificateKeyStorePassword:}\"/>\n\t\t\t\t\t</bean>\n\t\t\t\t</property>\n\t\t\t</bean>\n\t\t</property>\n\n\t\t<!-- 解析起始位点 -->\n\t\t<property name=\"masterPosition\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.protocol.position.EntryPosition\">\n\t\t\t\t<property name=\"journalName\" value=\"${canal.instance.master2.journal.name}\" />\n\t\t\t\t<property name=\"position\" value=\"${canal.instance.master2.position}\" />\n\t\t\t\t<property name=\"timestamp\" value=\"${canal.instance.master2.timestamp}\" />\n\t\t\t\t<property name=\"gtid\" value=\"${canal.instance.master2.gtid}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"standbyPosition\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.protocol.position.EntryPosition\">\n\t\t\t\t<property name=\"journalName\" value=\"${canal.instance.standby2.journal.name}\" />\n\t\t\t\t<property name=\"position\" value=\"${canal.instance.standby2.position}\" />\n\t\t\t\t<property name=\"timestamp\" value=\"${canal.instance.standby2.timestamp}\" />\n\t\t\t\t<property name=\"gtid\" value=\"${canal.instance.standby2.gtid}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"filterQueryDml\" value=\"${canal.instance.filter.query.dml:false}\" />\n\t\t<property name=\"filterQueryDcl\" value=\"${canal.instance.filter.query.dcl:false}\" />\n\t\t<property name=\"filterQueryDdl\" value=\"${canal.instance.filter.query.ddl:false}\" />\n\t\t<property name=\"useDruidDdlFilter\" value=\"${canal.instance.filter.druid.ddl:true}\" />\n\t\t<property name=\"filterDmlInsert\" value=\"${canal.instance.filter.dml.insert:false}\" />\n\t\t<property name=\"filterDmlUpdate\" value=\"${canal.instance.filter.dml.update:false}\" />\n\t\t<property name=\"filterDmlDelete\" value=\"${canal.instance.filter.dml.delete:false}\" />\n\t\t<property name=\"filterRows\" value=\"${canal.instance.filter.rows:false}\" />\n\t\t<property name=\"filterTableError\" value=\"${canal.instance.filter.table.error:false}\" />\n\t\t<property name=\"supportBinlogFormats\" value=\"${canal.instance.binlog.format}\" />\n\t\t<property name=\"supportBinlogImages\" value=\"${canal.instance.binlog.image}\" />\n\n\t\t<!-- parallel parser -->\n\t\t<property name=\"parallel\" value=\"${canal.instance.parser.parallel:true}\" />\n\t\t<property name=\"parallelThreadSize\" value=\"${canal.instance.parser.parallelThreadSize}\" />\n\t\t<property name=\"parallelBufferSize\" value=\"${canal.instance.parser.parallelBufferSize:256}\" />\n\n\t\t<property name=\"autoResetLatestPosMode\" value=\"${canal.auto.reset.latest.pos.mode:false}\" />\n\t\t<property name=\"multiStreamEnable\" value=\"${canal.instance.multi.stream.on:false}\"/>\n\t</bean>\n\n    <bean id=\"mqConfig\" class=\"com.alibaba.otter.canal.instance.core.CanalMQConfig\">\n        <property name=\"topic\" value=\"${canal.mq.topic}\" />\n\t\t<property name=\"dynamicTopic\" value=\"${canal.mq.dynamicTopic}\" />\n        <property name=\"partition\" value=\"${canal.mq.partition}\" />\n        <property name=\"partitionsNum\" value=\"${canal.mq.partitionsNum}\" />\n        <property name=\"partitionHash\" value=\"${canal.mq.partitionHash}\" />\n\t\t<property name=\"dynamicTopicPartitionNum\" value=\"${canal.mq.dynamicTopicPartitionNum}\" />\n\t\t<property name=\"enableDynamicQueuePartition\" value=\"${canal.mq.enableDynamicQueuePartition}\" />\n    </bean>\n</beans>\n"
  },
  {
    "path": "deployer/src/main/resources/spring/memory-instance.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:tx=\"http://www.springframework.org/schema/tx\"\n\txmlns:aop=\"http://www.springframework.org/schema/aop\" xmlns:lang=\"http://www.springframework.org/schema/lang\"\n\txmlns:context=\"http://www.springframework.org/schema/context\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd\n           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd\n           http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.0.xsd\n           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd\n           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd\"\n\tdefault-autowire=\"byName\">\n\n\t<import resource=\"classpath:spring/base-instance.xml\" />\n\n\t<bean id=\"instance\" class=\"com.alibaba.otter.canal.instance.spring.CanalInstanceWithSpring\">\n\t\t<property name=\"destination\" value=\"${canal.instance.destination}\" />\n\t\t<property name=\"eventParser\">\n\t\t\t<ref bean=\"eventParser\" />\n\t\t</property>\n\t\t<property name=\"eventSink\">\n\t\t\t<ref bean=\"eventSink\" />\n\t\t</property>\n\t\t<property name=\"eventStore\">\n\t\t\t<ref bean=\"eventStore\" />\n\t\t</property>\n\t\t<property name=\"metaManager\">\n\t\t\t<ref bean=\"metaManager\" />\n\t\t</property>\n\t\t<property name=\"alarmHandler\">\n\t\t\t<ref bean=\"alarmHandler\" />\n\t\t</property>\n        <property name=\"mqConfig\">\n            <ref bean=\"mqConfig\" />\n        </property>\n\t</bean>\n\n\t<!-- 报警处理类 -->\n\t<bean id=\"alarmHandler\" class=\"com.alibaba.otter.canal.common.alarm.LogAlarmHandler\" />\n\n\t<bean id=\"metaManager\" class=\"com.alibaba.otter.canal.meta.MemoryMetaManager\" />\n\n\t<bean id=\"eventStore\" class=\"com.alibaba.otter.canal.store.memory.MemoryEventStoreWithBuffer\">\n\t\t<property name=\"bufferSize\" value=\"${canal.instance.memory.buffer.size:16384}\" />\n\t\t<property name=\"bufferMemUnit\" value=\"${canal.instance.memory.buffer.memunit:1024}\" />\n\t\t<property name=\"batchMode\" value=\"${canal.instance.memory.batch.mode:MEMSIZE}\" />\n\t\t<property name=\"ddlIsolation\" value=\"${canal.instance.get.ddl.isolation:false}\" />\n\t\t<property name=\"raw\" value=\"${canal.instance.memory.rawEntry:true}\" />\n\t</bean>\n\n\t<bean id=\"eventSink\" class=\"com.alibaba.otter.canal.sink.entry.EntryEventSink\">\n\t\t<property name=\"eventStore\" ref=\"eventStore\" />\n\t\t<property name=\"filterTransactionEntry\" value=\"${canal.instance.filter.transaction.entry:false}\"/>\n\t</bean>\n\n\t<bean id=\"eventParser\" parent=\"baseEventParser\">\n\t\t<property name=\"destination\" value=\"${canal.instance.destination}\" />\n\t\t<property name=\"slaveId\" value=\"${canal.instance.mysql.slaveId:0}\" />\n\t\t<!-- 心跳配置 -->\n\t\t<property name=\"detectingEnable\" value=\"${canal.instance.detecting.enable:false}\" />\n\t\t<property name=\"detectingSQL\" value=\"${canal.instance.detecting.sql}\" />\n\t\t<property name=\"detectingIntervalInSeconds\" value=\"${canal.instance.detecting.interval.time:5}\" />\n\t\t<property name=\"haController\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.ha.HeartBeatHAController\">\n\t\t\t\t<property name=\"detectingRetryTimes\" value=\"${canal.instance.detecting.retry.threshold:3}\" />\n\t\t\t\t<property name=\"switchEnable\" value=\"${canal.instance.detecting.heartbeatHaEnable:false}\" />\n\t\t\t</bean>\n\t\t</property>\n\n\t\t<property name=\"alarmHandler\" ref=\"alarmHandler\" />\n\n\t\t<!-- 解析过滤处理 -->\n\t\t<property name=\"eventFilter\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.filter.aviater.AviaterRegexFilter\" >\n\t\t\t\t<constructor-arg index=\"0\" value=\"${canal.instance.filter.regex:.*\\..*}\" />\n\t\t\t</bean>\n\t\t</property>\n\n\t\t<property name=\"eventBlackFilter\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.filter.aviater.AviaterRegexFilter\" >\n\t\t\t\t<constructor-arg index=\"0\" value=\"${canal.instance.filter.black.regex:}\" />\n\t\t\t\t<constructor-arg index=\"1\" value=\"false\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t\n\t\t<property name=\"fieldFilter\" value=\"${canal.instance.filter.field}\" />\n\t\t<property name=\"fieldBlackFilter\" value=\"${canal.instance.filter.black.field}\" />\n\t\t\n\t\t<!-- 最大事务解析大小，超过该大小后事务将被切分为多个事务投递 -->\n\t\t<property name=\"transactionSize\" value=\"${canal.instance.transaction.size:1024}\" />\n\n\t\t<!-- 网络链接参数 -->\n\t\t<property name=\"receiveBufferSize\" value=\"${canal.instance.network.receiveBufferSize:16384}\" />\n\t\t<property name=\"sendBufferSize\" value=\"${canal.instance.network.sendBufferSize:16384}\" />\n\t\t<property name=\"defaultConnectionTimeoutInSeconds\" value=\"${canal.instance.network.soTimeout:30}\" />\n\n\t\t<!-- 解析编码 -->\n\t\t<property name=\"connectionCharset\" value=\"${canal.instance.connectionCharset:UTF-8}\" />\n\n\t\t<!-- 解析位点记录 -->\n\t\t<property name=\"logPositionManager\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.index.MemoryLogPositionManager\" />\n\t\t</property>\n\n\t\t<!-- failover切换时回退的时间 -->\n\t\t<property name=\"fallbackIntervalInSeconds\" value=\"${canal.instance.fallbackIntervalInSeconds:60}\" />\n\n\t\t<!-- 解析数据库信息 -->\n\t\t<property name=\"masterInfo\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.support.AuthenticationInfo\" init-method=\"initPwd\">\n\t\t\t\t<property name=\"address\" value=\"${canal.instance.master.address}\" />\n\t\t\t\t<property name=\"username\" value=\"${canal.instance.dbUsername:retl}\" />\n\t\t\t\t<property name=\"password\" value=\"${canal.instance.dbPassword:retl}\" />\n\t\t\t\t<property name=\"pwdPublicKey\" value=\"${canal.instance.pwdPublicKey:retl}\" />\n\t\t\t\t<property name=\"enableDruid\" value=\"${canal.instance.enableDruid:false}\" />\n\t\t\t\t<property name=\"defaultDatabaseName\" value=\"${canal.instance.defaultDatabaseName:}\" />\n\t\t\t\t<property name=\"sslInfo\">\n\t\t\t\t\t<bean class=\"com.alibaba.otter.canal.parse.driver.mysql.ssl.SslInfo\">\n\t\t\t\t\t\t<property name=\"sslMode\" value=\"${canal.instance.master.sslMode:DISABLED}\"/>\n\t\t\t\t\t\t<property name=\"tlsVersions\" value=\"${canal.instance.master.tlsVersions:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStoreType\" value=\"${canal.instance.master.trustCertificateKeyStoreType:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStoreUrl\" value=\"${canal.instance.master.trustCertificateKeyStoreUrl:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStorePassword\" value=\"${canal.instance.master.trustCertificateKeyStorePassword:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStoreType\" value=\"${canal.instance.master.clientCertificateKeyStoreType:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStoreUrl\" value=\"${canal.instance.master.clientCertificateKeyStoreUrl:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStorePassword\" value=\"${canal.instance.master.clientCertificateKeyStorePassword:}\"/>\n\t\t\t\t\t</bean>\n\t\t\t\t</property>\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"standbyInfo\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.support.AuthenticationInfo\" init-method=\"initPwd\">\n\t\t\t\t<property name=\"address\" value=\"${canal.instance.standby.address}\" />\n\t\t\t\t<property name=\"username\" value=\"${canal.instance.dbUsername:retl}\" />\n\t\t\t\t<property name=\"password\" value=\"${canal.instance.dbPassword:retl}\" />\n\t\t\t\t<property name=\"pwdPublicKey\" value=\"${canal.instance.pwdPublicKey:retl}\" />\n\t\t\t\t<property name=\"enableDruid\" value=\"${canal.instance.enableDruid:false}\" />\n\t\t\t\t<property name=\"defaultDatabaseName\" value=\"${canal.instance.defaultDatabaseName:}\" />\n\t\t\t\t<property name=\"sslInfo\">\n\t\t\t\t\t<bean class=\"com.alibaba.otter.canal.parse.driver.mysql.ssl.SslInfo\">\n\t\t\t\t\t\t<property name=\"sslMode\" value=\"${canal.instance.standby.sslMode:DISABLED}\"/>\n\t\t\t\t\t\t<property name=\"tlsVersions\" value=\"${canal.instance.standby.tlsVersions:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStoreType\" value=\"${canal.instance.standby.trustCertificateKeyStoreType:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStoreUrl\" value=\"${canal.instance.standby.trustCertificateKeyStoreUrl:}\"/>\n\t\t\t\t\t\t<property name=\"trustCertificateKeyStorePassword\" value=\"${canal.instance.standby.trustCertificateKeyStorePassword:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStoreType\" value=\"${canal.instance.standby.clientCertificateKeyStoreType:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStoreUrl\" value=\"${canal.instance.standby.clientCertificateKeyStoreUrl:}\"/>\n\t\t\t\t\t\t<property name=\"clientCertificateKeyStorePassword\" value=\"${canal.instance.standby.clientCertificateKeyStorePassword:}\"/>\n\t\t\t\t\t</bean>\n\t\t\t\t</property>\n\t\t\t</bean>\n\t\t</property>\n\n\t\t<!-- 解析起始位点 -->\n\t\t<property name=\"masterPosition\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.protocol.position.EntryPosition\">\n\t\t\t\t<property name=\"journalName\" value=\"${canal.instance.master.journal.name}\" />\n\t\t\t\t<property name=\"position\" value=\"${canal.instance.master.position}\" />\n\t\t\t\t<property name=\"timestamp\" value=\"${canal.instance.master.timestamp}\" />\n\t\t\t\t<property name=\"gtid\" value=\"${canal.instance.master.gtid}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"standbyPosition\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.protocol.position.EntryPosition\">\n\t\t\t\t<property name=\"journalName\" value=\"${canal.instance.standby.journal.name}\" />\n\t\t\t\t<property name=\"position\" value=\"${canal.instance.standby.position}\" />\n\t\t\t\t<property name=\"timestamp\" value=\"${canal.instance.standby.timestamp}\" />\n\t\t\t\t<property name=\"gtid\" value=\"${canal.instance.standby.gtid}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"filterQueryDml\" value=\"${canal.instance.filter.query.dml:false}\" />\n\t\t<property name=\"filterQueryDcl\" value=\"${canal.instance.filter.query.dcl:false}\" />\n\t\t<property name=\"filterQueryDdl\" value=\"${canal.instance.filter.query.ddl:false}\" />\n\t\t<property name=\"useDruidDdlFilter\" value=\"${canal.instance.filter.druid.ddl:true}\" />\n\t\t<property name=\"filterDmlInsert\" value=\"${canal.instance.filter.dml.insert:false}\" />\n\t\t<property name=\"filterDmlUpdate\" value=\"${canal.instance.filter.dml.update:false}\" />\n\t\t<property name=\"filterDmlDelete\" value=\"${canal.instance.filter.dml.delete:false}\" />\n\t\t<property name=\"filterRows\" value=\"${canal.instance.filter.rows:false}\" />\n\t\t<property name=\"filterTableError\" value=\"${canal.instance.filter.table.error:false}\" />\n\t\t<property name=\"supportBinlogFormats\" value=\"${canal.instance.binlog.format}\" />\n\t\t<property name=\"supportBinlogImages\" value=\"${canal.instance.binlog.image}\" />\n\n\t\t<!--表结构相关-->\n\t\t<property name=\"enableTsdb\" value=\"${canal.instance.tsdb.enable:false}\"/>\n\t\t<property name=\"tsdbSpringXml\" value=\"${canal.instance.tsdb.spring.xml:}\"/>\n\t\t<property name=\"tsdbJdbcUrl\" value=\"${canal.instance.tsdb.url:}\"/>\n\t\t<property name=\"tsdbJdbcUserName\" value=\"${canal.instance.tsdb.dbUsername:}\"/>\n\t\t<property name=\"tsdbJdbcPassword\" value=\"${canal.instance.tsdb.dbPassword:}\"/>\n\t\t<property name=\"tsdbSnapshotInterval\" value=\"${canal.instance.tsdb.snapshot.interval:24}\" />\n\t\t<property name=\"tsdbSnapshotExpire\" value=\"${canal.instance.tsdb.snapshot.expire:360}\" />\n\n\t\t<!--是否启用GTID模式-->\n\t\t<property name=\"isGTIDMode\" value=\"${canal.instance.gtidon:false}\"/>\n\n\t\t<!-- parallel parser -->\n\t\t<property name=\"parallel\" value=\"${canal.instance.parser.parallel:true}\" />\n\t\t<property name=\"parallelThreadSize\" value=\"${canal.instance.parser.parallelThreadSize}\" />\n\t\t<property name=\"parallelBufferSize\" value=\"${canal.instance.parser.parallelBufferSize:256}\" />\n\n\t\t<property name=\"autoResetLatestPosMode\" value=\"${canal.auto.reset.latest.pos.mode:false}\" />\n\t\t<property name=\"multiStreamEnable\" value=\"${canal.instance.multi.stream.on:false}\"/>\n\t</bean>\n\n\t<bean id=\"mqConfig\" class=\"com.alibaba.otter.canal.instance.core.CanalMQConfig\">\n\t\t<property name=\"topic\" value=\"${canal.mq.topic}\" />\n\t\t<property name=\"dynamicTopic\" value=\"${canal.mq.dynamicTopic}\" />\n\t\t<property name=\"partition\" value=\"${canal.mq.partition}\" />\n\t\t<property name=\"partitionsNum\" value=\"${canal.mq.partitionsNum}\" />\n\t\t<property name=\"partitionHash\" value=\"${canal.mq.partitionHash}\" />\n\t\t<property name=\"dynamicTopicPartitionNum\" value=\"${canal.mq.dynamicTopicPartitionNum}\" />\n\t\t<property name=\"enableDynamicQueuePartition\" value=\"${canal.mq.enableDynamicQueuePartition}\" />\n\t</bean>\n</beans>\n"
  },
  {
    "path": "deployer/src/main/resources/spring/tsdb/h2-tsdb.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:tx=\"http://www.springframework.org/schema/tx\"\n\txmlns:aop=\"http://www.springframework.org/schema/aop\" xmlns:lang=\"http://www.springframework.org/schema/lang\"\n\txmlns:context=\"http://www.springframework.org/schema/context\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd\n           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd\n           http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.0.xsd\n           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd\n           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd\"\n\tdefault-autowire=\"byName\">\n\t\n\t<!-- properties -->\n\t<bean class=\"com.alibaba.otter.canal.instance.spring.support.PropertyPlaceholderConfigurer\" lazy-init=\"false\">\n\t\t<property name=\"ignoreResourceNotFound\" value=\"true\" />\n\t\t<property name=\"systemPropertiesModeName\" value=\"SYSTEM_PROPERTIES_MODE_OVERRIDE\"/><!-- 允许system覆盖 -->\n\t\t<property name=\"locationNames\">\n\t\t\t<list>\n\t\t\t\t<value>classpath:canal.properties</value>\n\t\t\t\t<value>classpath:${canal.instance.destination:}/instance.properties</value>\n\t\t\t</list>\n\t\t</property>\n\t</bean>\n\t\n\t<!-- 基于db的实现 -->\n\t<bean id=\"tableMetaTSDB\" class=\"com.alibaba.otter.canal.parse.inbound.mysql.tsdb.DatabaseTableMeta\" destroy-method=\"destory\">\n\t\t<property name=\"metaHistoryDAO\" ref=\"metaHistoryDAO\"/>\n\t\t<property name=\"metaSnapshotDAO\" ref=\"metaSnapshotDAO\"/>\n\t</bean>\n\t\n    <bean id=\"dataSource\" class=\"com.alibaba.druid.pool.DruidDataSource\" destroy-method=\"close\">\n        <property name=\"driverClassName\" value=\"org.h2.Driver\" />\n\t\t<property name=\"url\" value=\"${canal.instance.tsdb.url:}\" />\n\t\t<property name=\"username\" value=\"${canal.instance.tsdb.dbUsername:}\" />\n\t\t<property name=\"password\" value=\"${canal.instance.tsdb.dbPassword:}\" />\n      \t<property name=\"maxActive\" value=\"30\" />\n        <property name=\"initialSize\" value=\"0\" />\n        <property name=\"minIdle\" value=\"1\" />\n        <property name=\"maxWait\" value=\"10000\" />\n        <property name=\"timeBetweenEvictionRunsMillis\" value=\"60000\" />\n        <property name=\"minEvictableIdleTimeMillis\" value=\"300000\" />\n        <property name=\"testWhileIdle\" value=\"true\" />\n        <property name=\"testOnBorrow\" value=\"false\" />\n        <property name=\"testOnReturn\" value=\"false\" />\n        <property name=\"useUnfairLock\" value=\"true\" />\n        <property name=\"validationQuery\" value=\"SELECT 1\" />\n\t</bean>\n\n\t<bean id=\"sqlSessionFactory\" class=\"org.mybatis.spring.SqlSessionFactoryBean\">\n\t\t<property name=\"dataSource\" ref=\"dataSource\"/>\n\t\t<property name=\"configLocation\" value=\"classpath:spring/tsdb/sql-map/sqlmap-config.xml\"/>\n\t</bean>\n\n    <bean id=\"metaHistoryDAO\" class=\"com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao.MetaHistoryDAO\">\n        <property name=\"sqlSessionFactory\" ref=\"sqlSessionFactory\"/>\n    </bean>\n\n    <bean id=\"metaSnapshotDAO\" class=\"com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao.MetaSnapshotDAO\">\n        <property name=\"sqlSessionFactory\" ref=\"sqlSessionFactory\"/>\n    </bean>\n</beans>\n"
  },
  {
    "path": "deployer/src/main/resources/spring/tsdb/mysql-tsdb.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:tx=\"http://www.springframework.org/schema/tx\"\n\txmlns:aop=\"http://www.springframework.org/schema/aop\" xmlns:lang=\"http://www.springframework.org/schema/lang\"\n\txmlns:context=\"http://www.springframework.org/schema/context\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd\n           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd\n           http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.0.xsd\n           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd\n           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd\"\n\tdefault-autowire=\"byName\">\n\t\n\t<!-- properties -->\n\t<bean class=\"com.alibaba.otter.canal.instance.spring.support.PropertyPlaceholderConfigurer\" lazy-init=\"false\">\n\t\t<property name=\"ignoreResourceNotFound\" value=\"true\" />\n\t\t<property name=\"systemPropertiesModeName\" value=\"SYSTEM_PROPERTIES_MODE_OVERRIDE\"/><!-- 允许system覆盖 -->\n\t\t<property name=\"locationNames\">\n\t\t\t<list>\n\t\t\t\t<value>classpath:canal.properties</value>\n\t\t\t\t<value>classpath:${canal.instance.destination:}/instance.properties</value>\n\t\t\t</list>\n\t\t</property>\n\t</bean>\n\t\n\t<!-- 基于db的实现 -->\n\t<bean id=\"tableMetaTSDB\" class=\"com.alibaba.otter.canal.parse.inbound.mysql.tsdb.DatabaseTableMeta\" destroy-method=\"destory\">\n\t\t<property name=\"metaHistoryDAO\" ref=\"metaHistoryDAO\"/>\n\t\t<property name=\"metaSnapshotDAO\" ref=\"metaSnapshotDAO\"/>\n\t</bean>\n\t\n    <bean id=\"dataSource\" class=\"com.alibaba.druid.pool.DruidDataSource\" destroy-method=\"close\">\n        <property name=\"driverClassName\" value=\"com.mysql.jdbc.Driver\" />\n\t\t<property name=\"url\" value=\"${canal.instance.tsdb.url:}\" />\n\t\t<property name=\"username\" value=\"${canal.instance.tsdb.dbUsername:}\" />\n\t\t<property name=\"password\" value=\"${canal.instance.tsdb.dbPassword:}\" />\n        <property name=\"maxActive\" value=\"30\" />\n        <property name=\"initialSize\" value=\"0\" />\n        <property name=\"minIdle\" value=\"1\" />\n        <property name=\"maxWait\" value=\"10000\" />\n        <property name=\"timeBetweenEvictionRunsMillis\" value=\"60000\" />\n        <property name=\"minEvictableIdleTimeMillis\" value=\"300000\" />\n        <property name=\"validationQuery\" value=\"SELECT 1\" />\n        <property name=\"exceptionSorterClassName\" value=\"com.alibaba.druid.pool.vendor.MySqlExceptionSorter\" />\n        <property name=\"validConnectionCheckerClassName\" value=\"com.alibaba.druid.pool.vendor.MySqlValidConnectionChecker\" />\n        <property name=\"testWhileIdle\" value=\"true\" />\n        <property name=\"testOnBorrow\" value=\"false\" />\n        <property name=\"testOnReturn\" value=\"false\" />\n        <property name=\"useUnfairLock\" value=\"true\" />\n\t</bean>\n\n    <bean id=\"sqlSessionFactory\" class=\"org.mybatis.spring.SqlSessionFactoryBean\">\n        <property name=\"dataSource\" ref=\"dataSource\"/>\n        <property name=\"configLocation\" value=\"classpath:spring/tsdb/sql-map/sqlmap-config.xml\"/>\n    </bean>\n\n    <bean id=\"metaHistoryDAO\" class=\"com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao.MetaHistoryDAO\">\n        <property name=\"sqlSessionFactory\" ref=\"sqlSessionFactory\"/>\n    </bean>\n\n    <bean id=\"metaSnapshotDAO\" class=\"com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao.MetaSnapshotDAO\">\n        <property name=\"sqlSessionFactory\" ref=\"sqlSessionFactory\"/>\n    </bean>\n</beans>\n"
  },
  {
    "path": "deployer/src/main/resources/spring/tsdb/sql/create_table.sql",
    "content": "CREATE TABLE IF NOT EXISTS `meta_snapshot` (\n  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',\n  `gmt_create` datetime NOT NULL COMMENT '创建时间',\n  `gmt_modified` datetime NOT NULL COMMENT '修改时间',\n  `destination` varchar(128) DEFAULT NULL COMMENT '通道名称',\n  `binlog_file` varchar(64) DEFAULT NULL COMMENT 'binlog文件名',\n  `binlog_offest` bigint(20) DEFAULT NULL COMMENT 'binlog偏移量',\n  `binlog_master_id` varchar(64) DEFAULT NULL COMMENT 'binlog节点id',\n  `binlog_timestamp` bigint(20) DEFAULT NULL COMMENT 'binlog应用的时间戳',\n  `data` longtext DEFAULT NULL COMMENT '表结构数据',\n  `extra` text DEFAULT NULL COMMENT '额外的扩展信息',\n  PRIMARY KEY (`id`),\n  UNIQUE KEY binlog_file_offest(`destination`,`binlog_master_id`,`binlog_file`,`binlog_offest`),\n  KEY `destination` (`destination`),\n  KEY `destination_timestamp` (`destination`,`binlog_timestamp`),\n  KEY `gmt_modified` (`gmt_modified`)\n) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='表结构记录表快照表';\n\nCREATE TABLE IF NOT EXISTS `meta_history` (\n  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',\n  `gmt_create` datetime NOT NULL COMMENT '创建时间',\n  `gmt_modified` datetime NOT NULL COMMENT '修改时间',\n  `destination` varchar(128) DEFAULT NULL COMMENT '通道名称',\n  `binlog_file` varchar(64) DEFAULT NULL COMMENT 'binlog文件名',\n  `binlog_offest` bigint(20) DEFAULT NULL COMMENT 'binlog偏移量',\n  `binlog_master_id` varchar(64) DEFAULT NULL COMMENT 'binlog节点id',\n  `binlog_timestamp` bigint(20) DEFAULT NULL COMMENT 'binlog应用的时间戳',\n  `use_schema` varchar(1024) DEFAULT NULL COMMENT '执行sql时对应的schema',\n  `sql_schema` varchar(1024) DEFAULT NULL COMMENT '对应的schema',\n  `sql_table` varchar(1024) DEFAULT NULL COMMENT '对应的table',\n  `sql_text` longtext DEFAULT NULL COMMENT '执行的sql',\n  `sql_type` varchar(256) DEFAULT NULL COMMENT 'sql类型',\n  `extra` text DEFAULT NULL COMMENT '额外的扩展信息',\n  PRIMARY KEY (`id`),\n  UNIQUE KEY binlog_file_offest(`destination`,`binlog_master_id`,`binlog_file`,`binlog_offest`),\n  KEY `destination` (`destination`),\n  KEY `destination_timestamp` (`destination`,`binlog_timestamp`),\n  KEY `gmt_modified` (`gmt_modified`)\n) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='表结构变化明细表';"
  },
  {
    "path": "deployer/src/main/resources/spring/tsdb/sql-map/sqlmap-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE configuration PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n<configuration>\n    <typeAliases>\n        <typeAlias alias=\"metaHistoryDO\" type=\"com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao.MetaHistoryDO\"/>\n        <typeAlias alias=\"metaSnapshotDO\" type=\"com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao.MetaSnapshotDO\"/>\n    </typeAliases>\n\n    <mappers>\n        <mapper resource=\"spring/tsdb/sql-map/sqlmap_history.xml\"/>\n        <mapper resource=\"spring/tsdb/sql-map/sqlmap_snapshot.xml\"/>\n    </mappers>\n</configuration>\n"
  },
  {
    "path": "deployer/src/main/resources/spring/tsdb/sql-map/sqlmap_history.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao.MetaHistoryMapper\">\n    <sql id=\"allColumns\">\n        <![CDATA[\n\t\tgmt_create,gmt_modified,destination,binlog_file,binlog_offest,binlog_master_id,binlog_timestamp,use_schema,sql_schema,sql_table,sql_text,sql_type,extra\n        ]]>\n    </sql>\n    <sql id=\"allVOColumns\">\n        <![CDATA[\n\t\ta.id as id,a.gmt_create as gmtCreate,a.gmt_modified as gmtModified,\n\t\ta.destination as destination,a.binlog_file as binlogFile,a.binlog_offest as binlogOffest,a.binlog_master_id as binlogMasterId,a.binlog_timestamp as binlogTimestamp,\n\t\ta.use_schema as useSchema,a.sql_schema as sqlSchema,a.sql_table as sqlTable,a.sql_text as sqlText,a.sql_type as sqlType,a.extra as extra\n        ]]>\n    </sql>\n\n    <select id=\"findByTimestamp\" parameterType=\"java.util.Map\" resultType=\"metaHistoryDO\">\n        select\n        <include refid=\"allVOColumns\"/>\n        from meta_history a\n        <![CDATA[\n        where destination = #{destination} and binlog_timestamp >= #{snapshotTimestamp} and binlog_timestamp <= #{timestamp}\n        order by binlog_timestamp asc,id asc\n        ]]>\n    </select>\n\n    <insert id=\"insert\" parameterType=\"metaHistoryDO\">\n        insert into meta_history (<include refid=\"allColumns\"/>)\n        values(CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,#{destination},#{binlogFile},#{binlogOffest},#{binlogMasterId},#{binlogTimestamp},#{useSchema},#{sqlSchema},#{sqlTable},#{sqlText},#{sqlType},#{extra})\n    </insert>\n    \n    <delete id=\"deleteByName\" parameterType=\"java.util.Map\">\n        delete from meta_history \n        where destination=#{destination}\n    </delete>\n\n\n    <delete id=\"deleteByTimestamp\" parameterType=\"java.util.Map\">\n        <![CDATA[\n\t\tdelete from meta_history\n\t\twhere destination=#{destination} and binlog_timestamp < #{timestamp}\n        ]]>\n    </delete>\n</mapper>"
  },
  {
    "path": "deployer/src/main/resources/spring/tsdb/sql-map/sqlmap_snapshot.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao.MetaSnapshotMapper\">\n    <sql id=\"allColumns\">\n        <![CDATA[\n\t\tgmt_create,gmt_modified,destination,binlog_file,binlog_offest,binlog_master_id,binlog_timestamp,data,extra\n        ]]>\n    </sql>\n    <sql id=\"allVOColumns\">\n        <![CDATA[\n\t\ta.id as id,a.gmt_create as gmtCreate,a.gmt_modified as gmtModified,\n\t\ta.destination as destination,a.binlog_file as binlogFile,a.binlog_offest as binlogOffest,a.binlog_master_id as binlogMasterId,a.binlog_timestamp as binlogTimestamp,a.data as data,a.extra as extra\n        ]]>\n    </sql>\n\n    <select id=\"findByTimestamp\" parameterType=\"java.util.Map\" resultType=\"metaSnapshotDO\">\n    \tselect <include refid=\"allVOColumns\"/>\n        <![CDATA[\n        from meta_snapshot a\n        where destination = #{destination} and binlog_timestamp < #{timestamp}\n        order by binlog_timestamp desc,id desc\n        limit 1\n        ]]>\n    </select>\n\n    <insert id=\"insert\" parameterType=\"metaSnapshotDO\">\n        insert into meta_snapshot (<include refid=\"allColumns\"/>)\n        values(CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,#{destination},#{binlogFile},#{binlogOffest},#{binlogMasterId},#{binlogTimestamp},#{data},#{extra})\n    </insert>\n\n    <update id=\"update\" parameterType=\"metaSnapshotDO\">\n        update meta_snapshot set gmt_modified=now(),\n        binlog_file=#{binlogFile},binlog_offest=#{binlogOffest},binlog_master_id=#{binlogMasterId},binlog_timestamp=#{binlogTimestamp},data=#{data},extra=#{extra}\n        where destination=#{destination} and binlog_timestamp=0\n    </update>\n\n \t<delete id=\"deleteByName\" parameterType=\"java.util.Map\">\n        delete from meta_snapshot\n        where destination=#{destination}\n    </delete>\n\n    <delete id=\"deleteByTimestamp\" parameterType=\"java.util.Map\">\n        <![CDATA[\n\t\tdelete from meta_snapshot\n\t\twhere destination=#{destination} and binlog_timestamp < #{timestamp} and binlog_timestamp > 0\n        ]]>\n    </delete>\n</mapper>"
  },
  {
    "path": "docker/Dockerfile",
    "content": "FROM canal/osbase:v3-amd64\n#FROM canal/osbase:v3-arm64\n\nLABEL agapple (jianghang115@gmail.com)\n\n# install canal\nCOPY image/ /tmp/docker/\nCOPY canal.deployer-*.tar.gz /home/admin/\n\nRUN \\\n    cp -R /tmp/docker/alidata /alidata && \\\n    chmod +x /alidata/bin/* && \\\n    mkdir -p /home/admin && \\\n    cp -R /tmp/docker/app.sh /home/admin/  && \\\n    cp -R /tmp/docker/admin/* /home/admin/  && \\\n    /bin/cp -f alidata/bin/lark-wait /usr/bin/lark-wait && \\\n\n    mkdir -p /home/admin/canal-server && \\\n    tar -xzvf /home/admin/canal.deployer-*.tar.gz -C /home/admin/canal-server && \\\n    /bin/rm -f /home/admin/canal.deployer-*.tar.gz && \\\n\n    tar zxvf /tmp/node_exporter.tar.gz -C /home/admin && \\\n    ln -s /home/admin/node_exporter-1.6.1* /home/admin/node_exporter && \\\n\n    mkdir -p home/admin/canal-server/logs  && \\\n    chmod +x /home/admin/*.sh  && \\\n    chmod +x /home/admin/bin/*.sh  && \\\n    chown admin: -R /home/admin && \\\n    yum clean all && \\\n    true\n\n# 11110 admin , 11111 canal , 11112 metrics, 9100 exporter\nEXPOSE 11110 11111 11112 9100\n\nWORKDIR /home/admin\n\nENTRYPOINT [ \"/alidata/bin/main.sh\" ]\nCMD [ \"/home/admin/app.sh\" ]\n"
  },
  {
    "path": "docker/Dockerfile_admin",
    "content": "FROM canal/osadmin:v3-amd64\n#FROM canal/osadmin:v3-arm64\n\nMAINTAINER agapple (jianghang115@gmail.com)\n\n# install canal\nCOPY image/ /tmp/docker/\nCOPY canal.admin-*.tar.gz /home/admin/\n\nRUN \\\n    cp -R /tmp/docker/alidata /alidata && \\\n    chmod +x /alidata/bin/* && \\\n    mkdir -p /home/admin && \\\n    mkdir -p /home/admin/bin/ && \\\n    cp -R /tmp/docker/app_admin.sh /home/admin/app.sh  && \\\n    cp -R /tmp/docker/admin/* /home/admin/  && \\\n    /bin/cp -f alidata/bin/lark-wait /usr/bin/lark-wait && \\\n\n    mkdir -p /home/admin/canal-admin && \\\n    tar -xzvf /home/admin/canal.admin-*.tar.gz -C /home/admin/canal-admin && \\\n    /bin/rm -f /home/admin/canal.admin-*.tar.gz && \\\n\n    mkdir -p home/admin/canal-admin/logs  && \\\n    chmod +x /home/admin/*.sh  && \\\n    chmod +x /home/admin/bin/*.sh  && \\\n    chown admin: -R /home/admin && \\\n    yum clean all && \\\n    true\n\n# 8089 web\nEXPOSE 8089\n\nWORKDIR /home/admin\n\nENTRYPOINT [ \"/alidata/bin/main.sh\" ]\nCMD [ \"/home/admin/app.sh\" ]\n"
  },
  {
    "path": "docker/base/README.md",
    "content": "\n# osbase\ncd amd64 && docker build --no-cache -t canal/osbase ./ -f Dockerfile\n\n# osadmin\ncd amd64 && docker build --no-cache -t canal/osadmin ./ -f ./Dockerfile_admin\n"
  },
  {
    "path": "docker/base/amd64/Dockerfile",
    "content": "# amd64\nFROM centos:centos7.9.2009@sha256:dead07b4d8ed7e29e98de0f4504d87e8880d4347859d839686a31da35a3b532f\n\nARG jdk_rpm\nARG platform_env\n\nMAINTAINER agapple (jianghang115@gmail.com)\n# env DOWNLOAD_AMD_LINK=\"https://download.oracle.com/otn/java/jdk/8u361-b09/0ae14417abb444ebb02b9815e2103550/jdk-8u361-linux-x64.rpm\"\n# env DOWNLOAD_ARM_LINK=\"https://download.oracle.com/otn/java/jdk/8u361-b09/0ae14417abb444ebb02b9815e2103550/jdk-8u361-linux-aarch64.rpm\"\nenv NODE_EPORTER_LINK=\"https://github.com/prometheus/node_exporter/releases/download/v1.6.1/node_exporter-1.6.1.linux-amd64.tar.gz\"\n\n# install system\n# update yum config, fix \"centos6.x yum install failure && Determining fastest mirrors slow\" problems\nCOPY yum/ /tmp/\nRUN \\\n    /bin/cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak && \\\n    /bin/cp -f /tmp/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo && \\\n    /bin/cp /etc/yum/pluginconf.d/fastestmirror.conf /etc/yum/pluginconf.d/fastestmirror.conf.bak && \\\n    awk '{ if($0==\"enabled=1\"){print \"enabled=0\";} else{print $0;} }' /etc/yum/pluginconf.d/fastestmirror.conf.bak > /etc/yum/pluginconf.d/fastestmirror.conf && \\\n    /bin/cp /etc/yum.conf /etc/yum.conf.bak && \\\n    echo 'minrate=1' >> /etc/yum.conf && echo 'timeout=600' >> /etc/yum.conf && \\\n    yum clean all && yum makecache\n\nRUN \\\n    /usr/bin/ln -fs /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \\\n    echo 'root:Hello1234' | chpasswd && \\\n    groupadd -r admin && useradd -g admin admin && \\\n    yum install -y man && \\\n    yum install -y dstat && \\\n    yum install -y unzip && \\\n    yum install -y nc && \\\n    yum install -y openssh-server && \\\n    yum install -y tar && \\\n    yum install -y which && \\\n    yum install -y wget && \\\n    yum install -y perl && \\\n    yum install -y file && \\\n    ssh-keygen -q -N \"\" -t dsa -f /etc/ssh/ssh_host_dsa_key && \\\n    ssh-keygen -q -N \"\" -t rsa -f /etc/ssh/ssh_host_rsa_key && \\\n    sed -ri 's/session    required     pam_loginuid.so/#session    required     pam_loginuid.so/g' /etc/pam.d/sshd && \\\n    sed -i -e 's/^#Port 22$/Port 2222/' /etc/ssh/sshd_config && \\\n    mkdir -p /root/.ssh && chown root.root /root && chmod 700 /root/.ssh && \\\n    yum install -y cronie && \\\n    sed -i '/session required pam_loginuid.so/d' /etc/pam.d/crond && \\\n    true\n\nCOPY ${jdk_rpm} /tmp/\nRUN \\\n    touch /var/lib/rpm/* && \\\n    #if [ \"$BUILDPLATFORM\" == \"linux/amd64\" ] ; then wget --no-cookies --no-check-certificate --header \"Cookie: gpw_e24=xxx; oraclelicense=accept-securebackup-cookie\" \"$DOWNLOAD_AMD_LINK\" -O /tmp/jdk-8-linux.rpm  ; fi && \\\n    #if [ \"$BUILDPLATFORM\" == \"linux/arm64\" ] ; then wget --no-cookies --no-check-certificate --header \"Cookie: gpw_e24=xxx; oraclelicense=accept-securebackup-cookie\" \"$DOWNLOAD_ARM_LINK\" -O /tmp/jdk-8-linux.rpm  ; fi && \\\n    yum -y install /tmp/jdk-*.rpm && \\\n    /bin/rm -f /tmp/jdk-*.rpm && \\\n    echo \"export JAVA_HOME=/usr/java/latest\" >> /etc/profile && \\\n    echo \"export PATH=\\$JAVA_HOME/bin:\\$PATH\" >> /etc/profile && \\\n    wget \"$NODE_EPORTER_LINK\" -O /tmp/node_exporter.tar.gz && \\\n    yum clean all && \\\n    true\n\nCMD [\"/bin/bash\"]\n"
  },
  {
    "path": "docker/base/amd64/Dockerfile_admin",
    "content": "# amd64\nFROM canal/osbase:v3-amd64\n\nMAINTAINER agapple (jianghang115@gmail.com)\n\nRUN \\\n    groupadd -r mysql && useradd -r -g mysql mysql && \\\n    wget https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm  && \\\n    rpm -ivh mysql80-community-release-el7-3.noarch.rpm  && \\\n    yum install sudo mysql-community-server --nogpgcheck -y && \\\n    rm -f mysql80-community-release-el7-3.noarch.rpm && \\\n    yum clean all && \\\n    true\n\nCMD [\"/bin/bash\"]\n"
  },
  {
    "path": "docker/base/amd64/yum/CentOS-Base.repo",
    "content": "# CentOS-Base.repo\n#\n# The mirror system uses the connecting IP address of the client and the\n# update status of each mirror to pick mirrors that are updated to and\n# geographically close to the client.  You should use this for CentOS updates\n# unless you are manually picking other mirrors.\n#\n# If the mirrorlist= does not work for you, as a fall back you can try the\n# remarked out baseurl= line instead.\n#\n#\n\n[base]\nname=CentOS-7 - Base\nmirrorlist=http://mirrorlist.centos.org/?release=7&arch=$basearch&repo=os&infra=$infra\n#baseurl=http://mirror.centos.org/centos/7/os/$basearch/\ngpgcheck=1\ngpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7\n\n#released updates\n[updates]\nname=CentOS-7 - Updates\nmirrorlist=http://mirrorlist.centos.org/?release=7&arch=$basearch&repo=updates&infra=$infra\n#baseurl=http://mirror.centos.org/centos/7/updates/$basearch/\ngpgcheck=1\ngpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7\n\n#additional packages that may be useful\n[extras]\nname=CentOS-7 - Extras\nmirrorlist=http://mirrorlist.centos.org/?release=7&arch=$basearch&repo=extras&infra=$infra\n#baseurl=http://mirror.centos.org/centos/7/extras/$basearch/\ngpgcheck=1\ngpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7\n\n#additional packages that extend functionality of existing packages\n[centosplus]\nname=CentOS-7 - Plus\nmirrorlist=http://mirrorlist.centos.org/?release=7&arch=$basearch&repo=centosplus&infra=$infra\n#baseurl=http://mirror.centos.org/centos/7/centosplus/$basearch/\ngpgcheck=1\nenabled=0\ngpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7\n"
  },
  {
    "path": "docker/base/arm64/Dockerfile",
    "content": "# arm64\nFROM centos:centos7.9.2009@sha256:73f11afcbb50d8bc70eab9f0850b3fa30e61a419bc48cf426e63527d14a8373b\n\nARG jdk_rpm\nARG platform_env\n\nMAINTAINER agapple (jianghang115@gmail.com)\n# env DOWNLOAD_AMD_LINK=\"https://download.oracle.com/otn/java/jdk/8u361-b09/0ae14417abb444ebb02b9815e2103550/jdk-8u361-linux-x64.rpm\"\n# env DOWNLOAD_ARM_LINK=\"https://download.oracle.com/otn/java/jdk/8u361-b09/0ae14417abb444ebb02b9815e2103550/jdk-8u361-linux-aarch64.rpm\"\nenv NODE_EPORTER_LINK=\"https://github.com/prometheus/node_exporter/releases/download/v1.6.1/node_exporter-1.6.1.linux-arm64.tar.gz\"\n\n# install system\n# update yum config, fix \"centos6.x yum install failure && Determining fastest mirrors slow\" problems\nCOPY yum/ /tmp/\nRUN \\\n    /bin/cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak && \\\n    /bin/cp -f /tmp/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo && \\\n    /bin/cp /etc/yum/pluginconf.d/fastestmirror.conf /etc/yum/pluginconf.d/fastestmirror.conf.bak && \\\n    awk '{ if($0==\"enabled=1\"){print \"enabled=0\";} else{print $0;} }' /etc/yum/pluginconf.d/fastestmirror.conf.bak > /etc/yum/pluginconf.d/fastestmirror.conf && \\\n    /bin/cp /etc/yum.conf /etc/yum.conf.bak && \\\n    echo 'minrate=1' >> /etc/yum.conf && echo 'timeout=600' >> /etc/yum.conf && \\\n    yum clean all && yum makecache\n\nRUN \\\n    /usr/bin/ln -fs /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \\\n    echo 'root:Hello1234' | chpasswd && \\\n    groupadd -r admin && useradd -g admin admin && \\\n    yum install -y man && \\\n    yum install -y dstat && \\\n    yum install -y unzip && \\\n    yum install -y nc && \\\n    yum install -y openssh-server && \\\n    yum install -y tar && \\\n    yum install -y which && \\\n    yum install -y wget && \\\n    yum install -y perl && \\\n    yum install -y file && \\\n    ssh-keygen -q -N \"\" -t dsa -f /etc/ssh/ssh_host_dsa_key && \\\n    ssh-keygen -q -N \"\" -t rsa -f /etc/ssh/ssh_host_rsa_key && \\\n    sed -ri 's/session    required     pam_loginuid.so/#session    required     pam_loginuid.so/g' /etc/pam.d/sshd && \\\n    sed -i -e 's/^#Port 22$/Port 2222/' /etc/ssh/sshd_config && \\\n    mkdir -p /root/.ssh && chown root.root /root && chmod 700 /root/.ssh && \\\n    yum install -y cronie && \\\n    sed -i '/session required pam_loginuid.so/d' /etc/pam.d/crond && \\\n    true\n\nCOPY ${jdk_rpm} /tmp/\nRUN \\\n    touch /var/lib/rpm/* && \\\n    yum -y install /tmp/jdk-*.rpm && \\\n    /bin/rm -f /tmp/jdk-*.rpm && \\\n    echo \"export JAVA_HOME=/usr/java/latest\" >> /etc/profile && \\\n    echo \"export PATH=\\$JAVA_HOME/bin:\\$PATH\" >> /etc/profile && \\\n    wget \"$NODE_EPORTER_LINK\" -O /tmp/node_exporter.tar.gz && \\\n    yum clean all && \\\n    true\n\nCMD [\"/bin/bash\"]\n"
  },
  {
    "path": "docker/base/arm64/Dockerfile_admin",
    "content": "# arm64\nFROM canal/osbase:v3-arm64\n\nMAINTAINER agapple (jianghang115@gmail.com)\n\nRUN \\\n    groupadd -r mysql && useradd -r -g mysql mysql && \\\n    wget https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm  && \\\n    rpm -ivh mysql80-community-release-el7-3.noarch.rpm  && \\\n    yum install sudo mysql-community-server-8.0.32 --nogpgcheck -y && \\\n    rm -f mysql80-community-release-el7-3.noarch.rpm && \\\n    yum clean all && \\\n    true\n\nCMD [\"/bin/bash\"]\n"
  },
  {
    "path": "docker/base/arm64/yum/CentOS-Base.repo",
    "content": "# CentOS-Base.repo\n#\n# The mirror system uses the connecting IP address of the client and the\n# update status of each mirror to pick mirrors that are updated to and\n# geographically close to the client.  You should use this for CentOS updates\n# unless you are manually picking other mirrors.\n#\n# If the mirrorlist= does not work for you, as a fall back you can try the\n# remarked out baseurl= line instead.\n#\n#\n\n[base]\nname=CentOS-$releasever - Base\nmirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os&infra=$infra\n#baseurl=http://mirror.centos.org/altarch/$releasever/os/$basearch/\ngpgcheck=1\ngpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7\n       file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7-aarch64\n\n#released updates\n[updates]\nname=CentOS-$releasever - Updates\nmirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=updates&infra=$infra\n#baseurl=http://mirror.centos.org/altarch/$releasever/updates/$basearch/\ngpgcheck=1\ngpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7\n       file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7-aarch64\n\n#additional packages that may be useful\n[extras]\nname=CentOS-$releasever - Extras\nmirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=extras&infra=$infra\n#baseurl=http://mirror.centos.org/altarch/$releasever/extras/$basearch/\ngpgcheck=1\ngpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7\n       file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7-aarch64\nenabled=1\n\n#additional packages that extend functionality of existing packages\n[centosplus]\nname=CentOS-$releasever - Plus\nmirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=centosplus&infra=$infra\n#baseurl=http://mirror.centos.org/altarch/$releasever/centosplus/$basearch/\ngpgcheck=1\nenabled=0\ngpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7\n       file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7-aarch64\n"
  },
  {
    "path": "docker/build.sh",
    "content": "#!/bin/bash\n\ncurrent_path=`pwd`\ncase \"`uname`\" in\n    Darwin)\n        bin_abs_path=`cd $(dirname $0); pwd`\n        ;;\n    Linux)\n        bin_abs_path=$(readlink -f $(dirname $0))\n        ;;\n    *)\n        bin_abs_path=`cd $(dirname $0); pwd`\n        ;;\nesac\nBASE=${bin_abs_path}\n\nif [ \"$1\" == \"admin\" ] ; then\n    rm -rf $BASE/canal.*.tar.gz ;\n    cd $BASE/../ && mvn clean package -Dmaven.test.skip -Denv=release && cd $current_path ;\n    cp $BASE/../target/canal.admin-*.tar.gz $BASE/\n    docker build --no-cache -t canal/canal-admin $BASE/ -f $BASE/Dockerfile_admin\n    # docker build --platform linux/arm64 --no-cache -t canal/canal-admin $BASE/ -f $BASE/Dockerfile_admin\nelse \n    rm -rf $BASE/canal.*.tar.gz ; \n    cd $BASE/../ && mvn clean package -Dmaven.test.skip -Denv=release && cd $current_path ;\n    cp $BASE/../target/canal.deployer-*.tar.gz $BASE/\n    docker build --no-cache -t canal/canal-server $BASE/\n    # docker build --platform linux/arm64 --no-cache -t canal/canal-server $BASE/\nfi\n"
  },
  {
    "path": "docker/image/admin/bin/clean_log",
    "content": "# cron clean log once per minute\n*/2 * * * * admin /home/admin/bin/clean_log.sh >>/tmp/clean_log.log 2>&1\n"
  },
  {
    "path": "docker/image/admin/bin/clean_log.sh",
    "content": "#!/bin/bash\n\n# Global Settings\nPATH=\"$HOME/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/bin\"\nexport PATH\n\nCUTOFF=\"85\"\n#获取磁盘使用率最高的分区\nUSAGE=$(df -h|awk 'NR>1 {gsub(/%$/,\"\",$5);print $5 }'|sort -nr|head -1)\nbefore=$USAGE\n\nbaseClean(){\n    #删除tmp目录15天前的文件。\n    #更新文档时间戳\n    if [ -d /tmp/hsperfdata_admin ]\n    then\n        touch /tmp/hsperfdata_admin\n        touch /tmp/hsperfdata_admin/*\n    fi\n\n    find /tmp/ -type f -mtime +15 | xargs -t rm -rf >/dev/null 2>&1\n\n\n    now=$(df -h|awk 'NR>1 {gsub(/%$/,\"\",$5);print $5 }'|sort -nr|head -1)\n    echo \"before:$before; now:$now\"\n}\n\nCANAL_DIR=\"/home/admin/canal-server/logs\"\nif [ ! -d \"$CANAL_DIR\" ]\n  CANAL_DIR=\"/home/admin/canal-admin/logs\"\nfi\n\nif [[ -d $CANAL_DIR ]]; then\n  USAGE=$(df -h|awk 'NR>1 {gsub(/%$/,\"\",$5);print $5 }'|sort -nr|head -1)\n  if [[ $USAGE -ge 90 ]]; then\n        find $CANAL_DIR -type f -mtime +7 | xargs rm -rf {}\n  fi\n  USAGE=$(df -h|awk 'NR>1 {gsub(/%$/,\"\",$5);print $5 }'|sort -nr|head -1)\n  if [[ $USAGE -ge 80 ]]; then\n        find $CANAL_DIR -type f -mtime +3 | xargs rm -rf {}\n  fi\n  USAGE=$(df -h|awk 'NR>1 {gsub(/%$/,\"\",$5);print $5 }'|sort -nr|head -1)\n  if [[ $USAGE -ge 80 ]]; then\n        find $CANAL_DIR -type d -empty -mtime +3 | grep -v canal | xargs rm -rf {}\n        find $CANAL_DIR -type f -iname '*.tmp' | xargs rm -rf {}\n  fi\n  baseClean\n  exit 0\nfi"
  },
  {
    "path": "docker/image/admin/health.sh",
    "content": "#!/bin/sh\n\nif [ -d \"/home/admin/canal-admin\" ]; then\n\tserverPort=`perl -le 'print $ENV{\"server.port\"}'`\n    if [ -z \"$serverPort\" ] ; then\n        serverPort=8089\n    fi\n\n\tCHECK_URL=\"http://127.0.0.1:$serverPort/index.html\"\n\tCHECK_POINT=\"Canal\"\nelse\n\tmetrics_port=`perl -le 'print $ENV{\"canal.metrics.pull.port\"}'`\n\tif [ \"$metrics_port\" == \"\" ]; then\n\t\tmetrics_port=\"11112\"\n\tfi\n\n\tCHECK_URL=\"http://127.0.0.1:$metrics_port/metrics\"\n\tCHECK_POINT=\"canal\"\t\nfi\n\nCHECK_COUNT=`curl -s --connect-timeout 7 --max-time 7 $CHECK_URL | grep -c $CHECK_POINT`\nif [ $CHECK_COUNT -eq 0 ]; then\n    echo \"[FAILED]\"\n    status=0\n\terror=1\nelse\n    echo \"[  OK  ]\"\n    status=1\n\terror=0\nfi\n"
  },
  {
    "path": "docker/image/alidata/bin/exec_rc_local.sh",
    "content": "#!/bin/bash\n\nif [ \"${SKIP_EXEC_RC_LOCAL}\" = \"YES\" ] ; then\n\techo \"skip /etc/rc.local: SKIP_EXEC_RC_LOCAL=${SKIP_EXEC_RC_LOCAL}\"\n\texit\nfi\n\nif [ \"${DOCKER_DEPLOY_TYPE}\" = \"HOST\" ] ; then\n\techo \"skip /etc/rc.local: DOCKER_DEPLOY_TYPE=${DOCKER_DEPLOY_TYPE}\"\n\texit\nfi"
  },
  {
    "path": "docker/image/alidata/bin/lark-wait",
    "content": "#!/bin/bash\nset -e\n\nchown admin: -R /home/admin/\nsource /alidata/lib/proc.sh\nwaitterm\n"
  },
  {
    "path": "docker/image/alidata/bin/main.sh",
    "content": "#!/bin/bash\n\n[ -n \"${DOCKER_DEPLOY_TYPE}\" ] || DOCKER_DEPLOY_TYPE=\"VM\"\necho \"DOCKER_DEPLOY_TYPE=${DOCKER_DEPLOY_TYPE}\"\n\n# run init scripts\nfor e in $(ls /alidata/init/*) ; do\n\t[ -x \"${e}\" ] || continue\n\techo \"==> INIT $e\"\n\t$e\n\techo \"==> EXIT CODE: $?\"\ndone\n\necho \"==> INIT DEFAULT\"\n# disable systemctl\n# systemctl start sshd\n# systemctl start crond\n\n#echo \"check hostname -i: `hostname -i`\"\n#hti_num=`hostname -i|awk '{print NF}'`\n#if [ $hti_num -gt 1 ];then\n#    echo \"hostname -i result error:`hostname -i`\"\n#    exit 120\n#fi\n\necho \"==> INIT DONE\"\necho \"==> RUN ${*}\"\nexec \"${@}\"\n"
  },
  {
    "path": "docker/image/alidata/init/02init-sshd.sh",
    "content": "#!/bin/bash\n\n# set port\nif [ -z \"${SSHD_PORT}\" ] ; then\n\tSSHD_PORT=22\n\t[ \"${DOCKER_DEPLOY_TYPE}\" = \"HOST\" ] && SSHD_PORT=2222\nfi\n\nsed -r -i '/^OPTIONS=/ d' /etc/sysconfig/sshd\necho 'OPTIONS=\"-p '\"${SSHD_PORT}\"'\"' >> /etc/sysconfig/sshd\n\n# set admin ssh pulic key\nif [ \"${USE_ADMIN_PASSAGE}\" = \"YES\" ] ; then\n    echo \"set admin passage\"\n    mkdir -p /home/admin/.ssh\n    chown admin:admin /home/admin/.ssh\n    chown admin:admin /home/admin/.ssh/authorized_keys\n    chmod 644 /home/admin/.ssh/authorized_keys\nfi\n"
  },
  {
    "path": "docker/image/alidata/init/fix-hosts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#****************************************************************#\n# Create Date: 2017-01-06 17:58\n#***************************************************************#\n\nimport socket\nimport shutil\nfrom time import gmtime, strftime\n\n# get host_name\nhost_name = socket.gethostname()\ntmp_file = \"/tmp/.lark-fix-host.hosts\"\nhost_file = \"/etc/hosts\"\nbak_file_name = \"/tmp/hosts-fix-bak.%s\" % ( strftime(\"%Y-%m-%d_%H-%M-%S\", gmtime()) )\n\n# load /etc/hosts file context\nFH = open(host_file,\"r\")\nfile_lines = [ i.rstrip() for i in FH.readlines()]\nFH.close()\nfile_lines_reverse = file_lines[::-1]\nnew_lines = []\nbad_lines = []\nlast_match_line = \"\"\n\nfor line in file_lines_reverse:\n    if line.find(host_name) < 0:  # 不匹配的行直接跳过\n        new_lines.append(line + \"\\n\")\n        continue\n\n    cols = line.split()\n    new_cols = []\n    if cols[0].startswith(\"#\"): # 跳过已经注释掉的行\n        new_lines.append(line + \"\\n\")\n        continue\n    for col in cols:\n        if not col == host_name: # 跳过不匹配的列\n            new_cols.append(col)\n            continue\n\n        if cols[0] == \"127.0.0.1\": # 如果第一列是 127.0.0.1 就跳过匹配的列, 防止 hostname -i 返回 127.0.0.1\n            continue\n\n        # 如果已经发现过匹配的列, 就丢掉重复的列\n        if not len(last_match_line) == 0:\n            continue\n\n        new_cols.append(col)\n        last_match_line = line\n\n    # 跳过 xx.xx.xx.xx hostname 这样的重复列\n    if len(new_cols) == 1:\n        continue\n\n    new_l = \"%s\\n\" % \" \".join(new_cols)\n    new_lines.append(new_l)\n\n# save tmp hosts\n\nFH2=file(tmp_file,\"w+\")\nFH2.writelines( new_lines[::-1])\nFH2.close()\n\n# mv to /etc/hosts\nshutil.copy(host_file, bak_file_name)\nshutil.move(tmp_file, host_file)\n"
  },
  {
    "path": "docker/image/alidata/lib/proc.sh",
    "content": "# waitterm\n#   wait TERM/INT signal.\n#   see: http://veithen.github.io/2014/11/16/sigterm-propagation.html\nwaitterm() {\n\tlocal PID\n\t# any process to block\n\ttail -f /dev/null &\n\tPID=\"$!\"\n\t# setup trap, could do nothing, or just kill the blocker\n\ttrap \"kill -TERM ${PID}\" TERM INT\n\t# wait for signal, ignore wait exit code\n\twait \"${PID}\" || true\n\t# clear trap\n\ttrap - TERM INT\n\t# wait blocker, ignore blocker exit code\n\twait \"${PID}\" 2>/dev/null || true\n}\n\n# waittermpid \"${PIDFILE}\".\n#   monitor process by pidfile && wait TERM/INT signal.\n#   if the process disappeared, return 1, means exit with ERROR.\n#   if TERM or INT signal received, return 0, means OK to exit.\nwaittermpid() {\n\tlocal PIDFILE PID do_run error\n\tPIDFILE=\"${1?}\"\n\tdo_run=true\n\terror=0\n\ttrap \"do_run=false\" TERM INT\n\twhile \"${do_run}\" ; do\n\t\tPID=\"$(cat \"${PIDFILE}\")\"\n\t\tif ! ps -p \"${PID}\" >/dev/null 2>&1 ; then\n\t\t\tdo_run=false\n\t\t\terror=1\n\t\telse\n\t\t\tsleep 1\n\t\tfi\n\tdone\n\ttrap - TERM INT\n\treturn \"${error}\"\n}\n"
  },
  {
    "path": "docker/image/app.sh",
    "content": "#!/bin/bash\nset +e\n\nsource /etc/profile\nexport JAVA_HOME=/usr/java/latest\nexport PATH=$JAVA_HOME/bin:$PATH\ntouch /tmp/start.log\nchown admin: /tmp/start.log\nchown -R admin: /home/admin/canal-server\nhost=`hostname -i`\n\n# waitterm\n#   wait TERM/INT signal.\n#   see: http://veithen.github.io/2014/11/16/sigterm-propagation.html\nwaitterm() {\n        local PID\n        # any process to block\n        tail -f /dev/null &\n        PID=\"$!\"\n        # setup trap, could do nothing, or just kill the blocker\n        trap \"kill -TERM ${PID}\" TERM INT\n        # wait for signal, ignore wait exit code\n        wait \"${PID}\" || true\n        # clear trap\n        trap - TERM INT\n        # wait blocker, ignore blocker exit code\n        wait \"${PID}\" 2>/dev/null || true\n}\n\n# waittermpid \"${PIDFILE}\".\n#   monitor process by pidfile && wait TERM/INT signal.\n#   if the process disappeared, return 1, means exit with ERROR.\n#   if TERM or INT signal received, return 0, means OK to exit.\nwaittermpid() {\n        local PIDFILE PID do_run error\n        PIDFILE=\"${1?}\"\n        do_run=true\n        error=0\n        trap \"do_run=false\" TERM INT\n        while \"${do_run}\" ; do\n                PID=\"$(cat \"${PIDFILE}\")\"\n                if ! ps -p \"${PID}\" >/dev/null 2>&1 ; then\n                        do_run=false\n                        error=1\n                else\n                        sleep 1\n                fi\n        done\n        trap - TERM INT\n        return \"${error}\"\n}\n\n\nfunction checkStart() {\n    local name=$1\n    local cmd=$2\n    local timeout=$3\n    cost=5\n    while [ $timeout -gt 0 ]; do\n        ST=`eval $cmd`\n        if [ \"$ST\" == \"0\" ]; then\n            sleep 1\n            let timeout=timeout-1\n            let cost=cost+1\n        elif [ \"$ST\" == \"\" ]; then\n            sleep 1\n            let timeout=timeout-1\n            let cost=cost+1\n        else\n            break\n        fi\n    done\n    echo \"start $name successful\"\n}\n\n\nfunction start_canal() {\n    echo \"start canal ...\"\n    managerAddress=`perl -le 'print $ENV{\"canal.admin.manager\"}'`\n    if [ ! -z \"$managerAddress\" ] ; then\n        # canal_local.properties mode\n        adminPort=`perl -le 'print $ENV{\"canal.admin.port\"}'`\n        if [ -z \"$adminPort\" ] ; then\n            adminPort=11110\n        fi\n\n        su admin -c 'cd /home/admin/canal-server/bin/ && sh restart.sh local 1>>/tmp/start.log 2>&1'\n        sleep 5\n        #check start\n        checkStart \"canal\" \"nc 127.0.0.1 $adminPort -w 1 -zv 2> /tmp/nc.out && cat /tmp/nc.out | grep -c Connected\" 30\n    else\n        metricsPort=`perl -le 'print $ENV{\"canal.metrics.pull.port\"}'`\n        if [ -z \"$metricsPort\" ] ; then\n            metricsPort=11112\n        fi\n\n        destination=`perl -le 'print $ENV{\"canal.destinations\"}'`\n        destinationExpr=`perl -le 'print $ENV{\"canal.destinations.expr\"}'`\n        multistream=`perl -le 'print $ENV{\"canal.instance.multi.stream.on\"}'`\n\n        if [[ \"$destination\" =~ ',' ]] || [[ -n \"$destinationExpr\" ]]; then\n            if [[ \"$multistream\" = 'true' ]] ; then\n                if [[ -n \"$destinationExpr\" ]] ; then\n                    splitDestinations '1' $destinationExpr\n                else\n                    splitDestinations '2' $destination\n                fi\n            else\n                echo \"multi destination is not support, destinationExpr:$destinationExpr, destinations:$destination\"\n                exit 1;\n            fi\n        else\n            if [ \"$destination\" != \"\" ] && [ \"$destination\" != \"example\" ] ; then\n                if [ -d /home/admin/canal-server/conf/example ]; then\n                    mv /home/admin/canal-server/conf/example /home/admin/canal-server/conf/$destination\n                fi\n            fi \n        fi\n\n        su admin -c 'cd /home/admin/canal-server/bin/ && sh restart.sh 1>>/tmp/start.log 2>&1'\n        sleep 5\n        #check start\n        checkStart \"canal\" \"nc 127.0.0.1 $metricsPort -w 1 -zv 2> /tmp/nc.out && cat /tmp/nc.out | grep -c Connected\" 30\n    fi  \n}\n\nfunction splitDestinations() {\n    holdExample=\"false\"\n    prefix=''\n    array=()\n\n    if [[  \"$1\" == '1' ]] ; then\n        echo \"split destinations expr \"$2\n        prefix=$(echo $2 | sed 's/{.*//')\n        num=$(echo $2 | sed 's/.*{//;s/}//;s/-/ /')\n        array=($(seq $num))\n    else\n        echo \"split destinations \"$2\n        array=(${2//,/ })\n    fi\n\n    for var in ${array[@]}\n    do\n        cp -r /home/admin/canal-server/conf/example /home/admin/canal-server/conf/$prefix$var\n        chown admin:admin -R /home/admin/canal-server/conf/$prefix$var\n        if [[ \"$prefix$var\" = 'example' ]] ; then\n            holdExample=\"true\"\n        fi\n    done\n    if [[ \"$holdExample\" != 'true' ]] ; then\n        rm -rf /home/admin/canal-server/conf/example\n    fi\n}\n\nfunction stop_canal() {\n    echo \"stop canal\"\n    su admin -c 'cd /home/admin/canal-server/bin/ && sh stop.sh 1>>/tmp/start.log 2>&1'\n    echo \"stop canal successful ...\"\n}\n\nfunction start_exporter() {\n    su admin -c 'cd /home/admin/node_exporter && ./node_exporter 1>>/tmp/start.log 2>&1 &'\n}\n\nfunction stop_exporter() {\n    su admin -c 'killall node_exporter'\n}\n\necho \"==> START ...\"\n\nstart_exporter\nstart_canal\n\necho \"==> START SUCCESSFUL ...\"\n\ntail -f /dev/null &\n# wait TERM signal\nwaitterm\n\necho \"==> STOP\"\n\nstop_canal\nstop_exporter\n\necho \"==> STOP SUCCESSFUL ...\"\n"
  },
  {
    "path": "docker/image/app_admin.sh",
    "content": "#!/bin/bash\nset +e\n\nsource /etc/profile\nexport JAVA_HOME=/usr/java/latest\nexport PATH=$JAVA_HOME/bin:$PATH\ntouch /tmp/start.log\nchown admin: /tmp/start.log\nchown -R admin: /home/admin/canal-admin\nhost=`hostname -i`\n\nMYSQL_USER_PASSWORD=`perl -le 'print $ENV{\"spring.datasource.password\"}'`\nMYSQL_USER=`perl -le 'print $ENV{\"spring.datasource.username\"}'`\nMYSQL_DATABASE=`perl -le 'print $ENV{\"spring.datasource.database\"}'`\nMYSQL_ADDRESS=`perl -le 'print $ENV{\"spring.datasource.address\"}'`\n\nif [ -z \"${MYSQL_USER_PASSWORD}\" ]; then\n    MYSQL_USER_PASSWORD=\"canal\"\nfi\nif [ -z \"${MYSQL_USER}\" ]; then\n    MYSQL_USER=\"canal\"\nfi\nif [ -z \"${MYSQL_DATABASE}\" ]; then\n    MYSQL_DATABASE=\"canal_manager\"\nfi\n\n# waitterm\n#   wait TERM/INT signal.\n#   see: http://veithen.github.io/2014/11/16/sigterm-propagation.html\nwaitterm() {\n        local PID\n        # any process to block\n        tail -f /dev/null &\n        PID=\"$!\"\n        # setup trap, could do nothing, or just kill the blocker\n        trap \"kill -TERM ${PID}\" TERM INT\n        # wait for signal, ignore wait exit code\n        wait \"${PID}\" || true\n        # clear trap\n        trap - TERM INT\n        # wait blocker, ignore blocker exit code\n        wait \"${PID}\" 2>/dev/null || true\n}\n\n# waittermpid \"${PIDFILE}\".\n#   monitor process by pidfile && wait TERM/INT signal.\n#   if the process disappeared, return 1, means exit with ERROR.\n#   if TERM or INT signal received, return 0, means OK to exit.\nwaittermpid() {\n        local PIDFILE PID do_run error\n        PIDFILE=\"${1?}\"\n        do_run=true\n        error=0\n        trap \"do_run=false\" TERM INT\n        while \"${do_run}\" ; do\n                PID=\"$(cat \"${PIDFILE}\")\"\n                if ! ps -p \"${PID}\" >/dev/null 2>&1 ; then\n                        do_run=false\n                        error=1\n                else\n                        sleep 1\n                fi\n        done\n        trap - TERM INT\n        return \"${error}\"\n}\n\n\nfunction checkStart() {\n    local name=$1\n    local cmd=$2\n    local timeout=$3\n    cost=5\n    while [ $timeout -gt 0 ]; do\n        ST=`eval $cmd`\n        if [ \"$ST\" == \"0\" ]; then\n            sleep 1\n            let timeout=timeout-1\n            let cost=cost+1\n        elif [ \"$ST\" == \"\" ]; then\n            sleep 1\n            let timeout=timeout-1\n            let cost=cost+1\n        else\n            break\n        fi\n    done\n    echo \"start $name successful\"\n}\n\nfunction start_mysql() {\n    echo \"start mysql ...\"\n    # start mysql\n    MYSQL_ROOT_PASSWORD=Hello1234\n    # connect local mysql\n    if [ -z \"$(ls -A /var/lib/mysql)\" ]; then\n        TEMP_FILE='/tmp/init.sql'\n        echo \"ALTER USER 'root'@'localhost' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}';\" >> $TEMP_FILE\n        /usr/sbin/mysqld --initialize --user=mysql --datadir=/var/lib/mysql  --init-file=/tmp/init.sql --default-authentication-plugin=mysql_native_password 1>>/tmp/start.log 2>&1\n        echo \"default-authentication-plugin=mysql_native_password\" >> /etc/my.cnf\n        # systemctl start mysqld\n        sudo -u mysql /usr/sbin/mysqld &\n        sleep 5\n        checkStart \"mysql\" \"echo 'show status' | mysql -b -s -h127.0.0.1 -P3306 -uroot -p${MYSQL_ROOT_PASSWORD} | grep -c Uptime\" 30\n        # init file\n        rm -f $TEMP_FILE\n        echo \"create database if not exists $MYSQL_DATABASE ;\" >> $TEMP_FILE\n        echo \"create user $MYSQL_USER identified by '$MYSQL_USER_PASSWORD' ;\" >> $TEMP_FILE\n        echo \"grant all privileges on $MYSQL_DATABASE.* to '$MYSQL_USER'@'%' ;\" >> $TEMP_FILE\n        echo \"flush privileges;\" >> $TEMP_FILE\n        # init user\n        cmd=\"mysql -h127.0.0.1 -uroot -p${MYSQL_ROOT_PASSWORD} -e 'source $TEMP_FILE' 1>>/tmp/start.log 2>&1\"\n        eval $cmd\n        /bin/rm -f /tmp/init.sql\n        # init table\n        cmd=\"mysql -h127.0.0.1 -u$MYSQL_USER -p$MYSQL_USER_PASSWORD $MYSQL_DATABASE -e 'source /home/admin/canal-admin/conf/canal_manager.sql' 1>>/tmp/start.log 2>&1\"\n        eval $cmd\n        /bin/rm -f /home/admin/canal-admin/conf/canal_manager.sql\n    else\n        echo \"recover mysql ...\"\n        chown -R mysql:mysql /var/lib/mysql\n        # systemctl start mysqld\n        rm -f /var/lib/mysql/mysql.sock.lock\n        sudo -u mysql /usr/sbin/mysqld &\n        sleep 5\n        #check start\n        checkStart \"mysql\" \"echo 'show status' | mysql -b -s  -h127.0.0.1 -P3306 -uroot -p${MYSQL_ROOT_PASSWORD} | grep -c Uptime\" 30\n    fi\n}\n\nfunction stop_mysql() {\n    echo \"stop mysql ...\"\n    # stop mysql\n    # systemctl stop mysqld\n    ps auxf | grep mysqld | grep -v grep | awk '{print $2}' | xargs kill\n    echo \"stop mysql successful ...\"\n}\n\nfunction start_admin() {\n    echo \"start admin ...\"\n    serverPort=`perl -le 'print $ENV{\"server.port\"}'`\n    if [ -z \"$serverPort\" ] ; then\n        serverPort=8089\n    fi\n    su admin -c 'cd /home/admin/canal-admin/bin/ && sh restart.sh 1>>/tmp/start.log 2>&1'\n    sleep 5\n    #check start\n    checkStart \"canal\" \"nc 127.0.0.1 $serverPort -w 1 -zv 2>/tmp/nc.out && cat /tmp/nc.out | grep -c Connected\" 30\n}\n\nfunction stop_admin() {\n    echo \"stop admin\"\n    su admin -c 'cd /home/admin/canal-admin/bin/ && sh stop.sh 1>>/tmp/start.log 2>&1'\n    echo \"stop admin successful ...\"\n}\n\necho \"==> START ...\"\n\nif [ -z \"${MYSQL_ADDRESS}\" ]; then\n    start_mysql\nfi\nstart_admin\n\necho \"==> START SUCCESSFUL ...\"\n\ntail -f /dev/null &\n# wait TERM signal\nwaitterm\n\necho \"==> STOP\"\n\nif [ -z \"${MYSQL_ADDRESS}\" ]; then\n    stop_admin\nfi\nstop_mysql\n\necho \"==> STOP SUCCESSFUL ...\"\n"
  },
  {
    "path": "docker/image/canal_manager.sql",
    "content": "CREATE DATABASE /*!32312 IF NOT EXISTS*/ `canal_manager` /*!40100 DEFAULT CHARACTER SET utf8 COLLATE utf8_bin */;\n\nUSE `canal_manager`;\n\nSET NAMES utf8;\nSET FOREIGN_KEY_CHECKS = 0;\n\n-- ----------------------------\n-- Table structure for canal_adapter_config\n-- ----------------------------\nDROP TABLE IF EXISTS `canal_adapter_config`;\nCREATE TABLE `canal_adapter_config` (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT,\n  `category` varchar(255) NOT NULL,\n  `name` varchar(255) NOT NULL,\n  `status` varchar(45) DEFAULT NULL,\n  `content` text NOT NULL,\n  `modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Table structure for canal_cluster\n-- ----------------------------\nDROP TABLE IF EXISTS `canal_cluster`;\nCREATE TABLE `canal_cluster` (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT,\n  `name` varchar(255) NOT NULL,\n  `zk_hosts` varchar(255) NOT NULL,\n  `modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Table structure for canal_config\n-- ----------------------------\nDROP TABLE IF EXISTS `canal_config`;\nCREATE TABLE `canal_config` (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT,\n  `cluster_id` bigint(20) DEFAULT NULL,\n  `server_id` bigint(20) DEFAULT NULL,\n  `name` varchar(255) NOT NULL,\n  `status` varchar(45) DEFAULT NULL,\n  `content` text NOT NULL,\n  `content_md5` varchar(128) NOT NULL,\n  `modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n  PRIMARY KEY (`id`),\n  UNIQUE KEY `sid_UNIQUE` (`server_id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Table structure for canal_instance_config\n-- ----------------------------\nDROP TABLE IF EXISTS `canal_instance_config`;\nCREATE TABLE `canal_instance_config` (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT,\n  `cluster_id` bigint(20) DEFAULT NULL,\n  `server_id` bigint(20) DEFAULT NULL,\n  `name` varchar(255) NOT NULL,\n  `status` varchar(45) DEFAULT NULL,\n  `content` text NOT NULL,\n  `content_md5` varchar(128) DEFAULT NULL,\n  `modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n  PRIMARY KEY (`id`),\n  UNIQUE KEY `name_UNIQUE` (`name`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Table structure for canal_node_server\n-- ----------------------------\nDROP TABLE IF EXISTS `canal_node_server`;\nCREATE TABLE `canal_node_server` (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT,\n  `cluster_id` bigint(20) DEFAULT NULL,\n  `name` varchar(255) NOT NULL,\n  `ip` varchar(255) NOT NULL,\n  `admin_port` int(11) DEFAULT NULL,\n  `tcp_port` int(11) DEFAULT NULL,\n  `metric_port` int(11) DEFAULT NULL,\n  `status` varchar(45) DEFAULT NULL,\n  `modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Table structure for canal_user\n-- ----------------------------\nDROP TABLE IF EXISTS `canal_user`;\nCREATE TABLE `canal_user` (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT,\n  `username` varchar(255) NOT NULL,\n  `password` varchar(255) NOT NULL,\n  `name` varchar(255) NOT NULL,\n  `roles` varchar(255) NOT NULL,\n  `introduction` varchar(255) DEFAULT NULL,\n  `avatar` varchar(255) DEFAULT NULL,\n  `creation_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nSET FOREIGN_KEY_CHECKS = 1;\n\n-- ----------------------------\n-- Records of canal_user\n-- ----------------------------\nBEGIN;\nINSERT INTO `canal_user` VALUES (1, 'admin', '6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9', 'Canal Manager', 'admin', NULL, NULL, '2019-07-14 00:05:28');\nCOMMIT;\n\nSET FOREIGN_KEY_CHECKS = 1;\n"
  },
  {
    "path": "docker/run.sh",
    "content": "#!/bin/bash\n\nfunction usage() {\n    echo \"Usage:\"\n    echo \"  run.sh [CONFIG]\"\n    echo \"example 1 :\"\n    echo \"  run.sh -e canal.instance.master.address=127.0.0.1:3306 \\\\\"\n    echo \"         -e canal.instance.dbUsername=canal \\\\\"\n    echo \"         -e canal.instance.dbPassword=canal \\\\\"\n    echo \"         -e canal.instance.connectionCharset=UTF-8 \\\\\"\n    echo \"         -e canal.instance.tsdb.enable=true \\\\\"\n    echo \"         -e canal.instance.gtidon=false \\\\\"\n    echo \"         -e canal.instance.filter.regex=.*\\\\\\\\\\\\..* \"\n    echo \"example 2 :\"\n    echo \"  run.sh -e canal.admin.manager=127.0.0.1:8089 \\\\\"\n    echo \"         -e canal.admin.port=11110 \\\\\"\n    echo \"         -e canal.admin.user=admin \\\\\"\n    echo \"         -e canal.admin.passwd=4ACFE3202A5FF5CF467898FC58AAB1D615029441\"\n    exit\n}\n\nfunction check_port() {\n    local port=$1\n    local TL=$(which telnet)\n    if [ -f $TL ]; then\n        data=`echo quit | telnet 127.0.0.1 $port| grep -ic connected`\n        echo $data\n        return\n    fi\n\n    local NC=$(which nc)\n    if [ -f $NC ]; then\n        data=`nc -z -w 1 127.0.0.1 $port | grep -ic succeeded`\n        echo $data\n        return\n    fi\n    echo \"0\"\n    return\n}\n\nfunction getMyIp() {\n    case \"`uname`\" in\n        Darwin)\n         myip=`echo \"show State:/Network/Global/IPv4\" | scutil | grep PrimaryInterface | awk '{print $3}' | xargs ifconfig | grep inet | grep -v inet6 | awk '{print $2}'`\n         ;;\n        *)\n         myip=`ip route get 1 | awk '{print $NF;exit}'`\n         ;;\n  esac\n  echo $myip\n}\n\nCONFIG=${@:1}\n#VOLUMNS=\"-v $DATA:/home/admin/canal-server/logs\"\nPORTLIST=\"11110 11111 11112 9100\"\nPORTS=\"\"\nfor PORT in $PORTLIST ; do\n    #exist=`check_port $PORT`\n    exist=\"0\"\n    if [ \"$exist\" == \"0\" ]; then\n        PORTS=\"$PORTS -p $PORT:$PORT\"\n    else\n        echo \"port $PORT is used , pls check\"\n        exit 1\n    fi\ndone\n\nNET_MODE=\"\"\ncase \"`uname`\" in\n    Darwin)\n        bin_abs_path=`cd $(dirname $0); pwd`\n        ;;\n    Linux)\n        bin_abs_path=$(readlink -f $(dirname $0))\n        NET_MODE=\"--net=host\"\n        PORTS=\"\"\n        ;;\n    *)\n        bin_abs_path=`cd $(dirname $0); pwd`\n        NET_MODE=\"--net=host\"\n        PORTS=\"\"\n        ;;\nesac\nBASE=${bin_abs_path}\nDATA=\"$BASE/data\"\nmkdir -p $DATA\n\nif [ $# -eq 0 ]; then\n    usage\nelif [ \"$1\" == \"-h\" ] ; then\n    usage\nelif [ \"$1\" == \"help\" ] ; then\n    usage\nfi\n\n\n\nMEMORY=\"-m 4096m\"\nLOCALHOST=`getMyIp`\ncmd=\"docker run -d -it -h $LOCALHOST $CONFIG --name=canal-server $VOLUMNS $NET_MODE $PORTS $MEMORY canal/canal-server\"\necho $cmd\neval $cmd\n"
  },
  {
    "path": "docker/run_admin.sh",
    "content": "#!/bin/bash\n\nfunction usage() {\n    echo \"Usage:\"\n    echo \"  run_admin.sh [CONFIG]\"\n    echo \"example :\"\n    echo \"  run_admin.sh -e server.port=8089 \\\\\"\n    echo \"         -e canal.adminUser=admin \\\\\"\n    echo \"         -e canal.adminPasswd=admin\"\n    exit\n}\n\nfunction check_port() {\n    local port=$1\n    local TL=$(which telnet)\n    if [ -f $TL ]; then\n        data=`echo quit | telnet 127.0.0.1 $port| grep -ic connected`\n        echo $data\n        return\n    fi\n\n    local NC=$(which nc)\n    if [ -f $NC ]; then\n        data=`nc -z -w 1 127.0.0.1 $port | grep -ic succeeded`\n        echo $data\n        return\n    fi\n    echo \"0\"\n    return\n}\n\nfunction getMyIp() {\n    case \"`uname`\" in\n        Darwin)\n         myip=`echo \"show State:/Network/Global/IPv4\" | scutil | grep PrimaryInterface | awk '{print $3}' | xargs ifconfig | grep inet | grep -v inet6 | awk '{print $2}'`\n         ;;\n        *)\n         myip=`ip route get 1 | awk '{print $NF;exit}'`\n         ;;\n  esac\n  echo $myip\n}\n\nCONFIG=${@:1}\n#VOLUMNS=\"-v $DATA:/home/admin/canal-admin/logs\"\nPORTLIST=\"8089\"\nPORTS=\"\"\nfor PORT in $PORTLIST ; do\n    #exist=`check_port $PORT`\n    exist=\"0\"\n    if [ \"$exist\" == \"0\" ]; then\n        PORTS=\"$PORTS -p $PORT:$PORT\"\n    else\n        echo \"port $PORT is used , pls check\"\n        exit 1\n    fi\ndone\n\nNET_MODE=\"\"\ncase \"`uname`\" in\n    Darwin)\n        bin_abs_path=`cd $(dirname $0); pwd`\n        ;;\n    Linux)\n        bin_abs_path=$(readlink -f $(dirname $0))\n        NET_MODE=\"--net=host\"\n        PORTS=\"\"\n        ;;\n    *)\n        NET_MODE=\"--net=host\"\n        PORTS=\"\"\n        bin_abs_path=`cd $(dirname $0); pwd`\n        ;;\nesac\nBASE=${bin_abs_path}\nDATA=\"$BASE/data\"\nmkdir -p $DATA\n\nif [ $# -eq 0 ]; then\n    usage\nelif [ \"$1\" == \"-h\" ] ; then\n    usage\nelif [ \"$1\" == \"help\" ] ; then\n    usage\nfi\n\nMEMORY=\"-m 1024m\"\nLOCALHOST=`getMyIp`\ncmd=\"docker run -d -it -h $LOCALHOST $CONFIG --name=canal-admin $VOLUMNS $NET_MODE $PORTS $MEMORY canal/canal-admin\"\necho $cmd\neval $cmd\n"
  },
  {
    "path": "driver/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>com.alibaba.otter</groupId>\n\t\t<artifactId>canal</artifactId>\n\t\t<version>1.1.9-SNAPSHOT</version>\n\t\t<relativePath>../pom.xml</relativePath>\n\t</parent>\n\t<groupId>com.alibaba.otter</groupId>\n\t<artifactId>canal.parse.driver</artifactId>\n\t<packaging>jar</packaging>\n\t<name>canal driver module for otter ${project.version}</name>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.common</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<!-- log -->\n\t\t<dependency>\n\t\t\t<groupId>ch.qos.logback</groupId>\n\t\t\t<artifactId>logback-core</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>ch.qos.logback</groupId>\n\t\t\t<artifactId>logback-classic</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>jcl-over-slf4j</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.jboss.netty</groupId>\n\t\t\t<artifactId>netty</artifactId>\n\t\t</dependency>\n\t\t<!-- test dependency -->\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n        <dependency>\n            <groupId>org.powermock</groupId>\n            <artifactId>powermock-api-mockito</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.powermock</groupId>\n            <artifactId>powermock-module-junit4</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.mockito</groupId>\n            <artifactId>mockito-all</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.diffblue</groupId>\n            <artifactId>deeptestutils</artifactId>\n            <scope>test</scope>\n        </dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/MysqlConnector.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql;\n\nimport static com.alibaba.otter.canal.parse.driver.mysql.packets.Capability.CLIENT_SSL;\n\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.security.DigestException;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.HeaderPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.client.*;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.server.*;\nimport com.alibaba.otter.canal.parse.driver.mysql.socket.SocketChannel;\nimport com.alibaba.otter.canal.parse.driver.mysql.socket.SocketChannelPool;\nimport com.alibaba.otter.canal.parse.driver.mysql.ssl.SslInfo;\nimport com.alibaba.otter.canal.parse.driver.mysql.ssl.SslMode;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.MSC;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.MySQLPasswordEncrypter;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.PacketManager;\n\n/**\n * 基于mysql socket协议的链接实现\n *\n * @author jianghang 2013-2-18 下午09:22:30\n * @version 1.0.1\n */\npublic class MysqlConnector {\n\n    public static final int     timeout           = 5 * 1000;                                     // 5s\n    private static final Logger logger            = LoggerFactory.getLogger(MysqlConnector.class);\n    private InetSocketAddress   address;\n    private String              username;\n    private String              password;\n    private SslInfo             sslInfo;\n    private String              defaultSchema;\n    private int                 soTimeout         = 30 * 1000;\n    private int                 connTimeout       = 5 * 1000;\n    private int                 receiveBufferSize = 16 * 1024;\n    private int                 sendBufferSize    = 16 * 1024;\n    private SocketChannel       channel;\n    private volatile boolean    dumping           = false;\n    // mysql connectionId\n    private long                connectionId      = -1;\n    private AtomicBoolean       connected         = new AtomicBoolean(false);\n    // serverVersion\n    private String              serverVersion;\n\n    public MysqlConnector(){\n    }\n\n    public MysqlConnector(InetSocketAddress address, String username, String password){\n        String addr = address.getHostString();\n        int port = address.getPort();\n        this.address = new InetSocketAddress(addr, port);\n\n        this.username = username;\n        this.password = password;\n    }\n\n    public MysqlConnector(InetSocketAddress address, String username, String password, String defaultSchema){\n        this(address, username, password);\n\n        this.defaultSchema = defaultSchema;\n    }\n\n    public MysqlConnector(InetSocketAddress address, String username, String password, String defaultSchema,\n                          SslInfo sslInfo){\n        this(address, username, password, defaultSchema);\n        this.sslInfo = sslInfo;\n    }\n\n    public void connect() throws IOException {\n        if (connected.compareAndSet(false, true)) {\n            try {\n                channel = SocketChannelPool.open(address);\n                logger.info(\"connect MysqlConnection to {}...\", address);\n                negotiate(channel);\n                printSslStatus();\n            } catch (Exception e) {\n                disconnect();\n                throw new IOException(\"connect \" + this.address + \" failure\", e);\n            }\n        } else {\n            logger.error(\"the channel can't be connected twice.\");\n        }\n    }\n\n    private void printSslStatus() {\n        try {\n            MysqlQueryExecutor executor = new MysqlQueryExecutor(this);\n            ResultSetPacket result = executor.query(\"SHOW STATUS LIKE 'Ssl_version'\");\n            String sslVersion = \"\";\n            if (result.getFieldValues() != null && result.getFieldValues().size() >= 2) {\n                sslVersion = result.getFieldValues().get(1);\n            }\n            result = executor.query(\"SHOW STATUS LIKE 'Ssl_cipher'\");\n            String sslCipher = \"\";\n            if (result.getFieldValues() != null && result.getFieldValues().size() >= 2) {\n                sslCipher = result.getFieldValues().get(1);\n            }\n            logger.info(\"connect MysqlConnection in sslMode {}, Ssl_version:{}, Ssl_cipher:{}\",\n                (sslInfo != null ? sslInfo.getSslMode() : SslMode.DISABLED),\n                sslVersion,\n                sslCipher);\n        } catch (Exception e) {\n            logger.warn(\"Can't show SSL status, server may not standard MySQL server\", e);\n        }\n    }\n\n    public void reconnect() throws IOException {\n        disconnect();\n        connect();\n    }\n\n    public void disconnect() throws IOException {\n        if (connected.compareAndSet(true, false)) {\n            try {\n                if (channel != null) {\n                    channel.close();\n                }\n                logger.info(\"disConnect MysqlConnection to {}...\", address);\n            } catch (Exception e) {\n                throw new IOException(\"disconnect \" + this.address + \" failure\", e);\n            }\n\n            // 执行一次quit\n            if (dumping && connectionId >= 0) {\n                MysqlConnector connector = null;\n                try {\n                    connector = this.fork();\n                    connector.connect();\n                    MysqlUpdateExecutor executor = new MysqlUpdateExecutor(connector);\n                    executor.update(\"KILL CONNECTION \" + connectionId);\n                } catch (Exception e) {\n                    // 忽略具体异常\n                    logger.info(\"KILL DUMP \" + connectionId + \" failure\", e);\n                } finally {\n                    if (connector != null) {\n                        connector.disconnect();\n                    }\n                }\n\n                dumping = false;\n            }\n        } else {\n            logger.info(\"the channel {} is not connected\", this.address);\n        }\n    }\n\n    public boolean isConnected() {\n        return this.channel != null && this.channel.isConnected();\n    }\n\n    public MysqlConnector fork() {\n        MysqlConnector connector = new MysqlConnector();\n        connector.setDefaultSchema(getDefaultSchema());\n        connector.setAddress(getAddress());\n        connector.setPassword(password);\n        connector.setUsername(getUsername());\n        connector.setReceiveBufferSize(getReceiveBufferSize());\n        connector.setSendBufferSize(getSendBufferSize());\n        connector.setSoTimeout(getSoTimeout());\n        connector.setConnTimeout(connTimeout);\n        connector.setSslInfo(getSslInfo());\n        return connector;\n    }\n\n    public void quit() throws IOException {\n        QuitCommandPacket quit = new QuitCommandPacket();\n        byte[] cmdBody = quit.toBytes();\n\n        HeaderPacket quitHeader = new HeaderPacket();\n        quitHeader.setPacketBodyLength(cmdBody.length);\n        quitHeader.setPacketSequenceNumber((byte) 0x00);\n        PacketManager.writePkg(channel, quitHeader.toBytes(), cmdBody);\n    }\n\n    private void negotiate(SocketChannel channel) throws IOException {\n        // https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol\n        HeaderPacket header = PacketManager.readHeader(channel, 4, timeout);\n        byte[] body = PacketManager.readBytes(channel, header.getPacketBodyLength(), timeout);\n        if (body[0] < 0) {// check field_count\n            if (body[0] == -1) {\n                ErrorPacket error = new ErrorPacket();\n                error.fromBytes(body);\n                throw new IOException(\"handshake exception:\\n\" + error.toString());\n            } else if (body[0] == -2) {\n                throw new IOException(\"Unexpected EOF packet at handshake phase.\");\n            } else {\n                throw new IOException(\"Unexpected packet with field_count=\" + body[0]);\n            }\n        }\n        HandshakeInitializationPacket handshakePacket = new HandshakeInitializationPacket();\n        handshakePacket.fromBytes(body);\n        // default utf8(33)\n        byte serverCharsetNumber = (handshakePacket.serverCharsetNumber != 0) ? handshakePacket.serverCharsetNumber : 33;\n        SslMode sslMode = sslInfo != null ? sslInfo.getSslMode() : SslMode.DISABLED;\n        if (sslMode != SslMode.DISABLED) {\n            boolean serverSupportSsl = (handshakePacket.serverCapabilities & CLIENT_SSL) > 0;\n            if (!serverSupportSsl) {\n                throw new IOException(\"MySQL Server does not support SSL: \" + address + \" serverCapabilities: \"\n                                      + handshakePacket.serverCapabilities);\n            }\n            byte[] sslPacket = new SslRequestCommandPacket(serverCharsetNumber).toBytes();\n            HeaderPacket sslHeader = new HeaderPacket();\n            sslHeader.setPacketBodyLength(sslPacket.length);\n            sslHeader.setPacketSequenceNumber((byte) (header.getPacketSequenceNumber() + 1));\n            header.setPacketSequenceNumber((byte) (header.getPacketSequenceNumber() + 1));\n            PacketManager.writePkg(channel, sslHeader.toBytes(), sslPacket);\n            channel = SocketChannelPool.connectSsl(channel, sslInfo);\n            this.channel = channel;\n        }\n        if (handshakePacket.protocolVersion != MSC.DEFAULT_PROTOCOL_VERSION) {\n            // HandshakeV9\n            auth323(channel, (byte) (header.getPacketSequenceNumber() + 1), handshakePacket.seed);\n            return;\n        }\n\n        connectionId = handshakePacket.threadId; // 记录一下connection\n        serverVersion = handshakePacket.serverVersion; // 记录serverVersion\n        logger.info(\"handshake initialization packet received, prepare the client authentication packet to send\");\n        // 某些老协议的 server 默认不返回 auth plugin，需要使用默认的 mysql_native_password\n        String authPluginName = \"mysql_native_password\";\n        if (handshakePacket.authPluginName != null && handshakePacket.authPluginName.length > 0) {\n            authPluginName = new String(handshakePacket.authPluginName);\n        }\n        logger.info(\"auth plugin: {}\", authPluginName);\n        boolean isSha2Password = false;\n        ClientAuthenticationPacket clientAuth;\n        if (\"caching_sha2_password\".equals(authPluginName)) {\n            clientAuth = new ClientAuthenticationSHA2Packet();\n            isSha2Password = true;\n        } else {\n            clientAuth = new ClientAuthenticationPacket();\n        }\n        clientAuth.setCharsetNumber(serverCharsetNumber);\n\n        clientAuth.setUsername(username);\n        clientAuth.setPassword(password);\n        clientAuth.setServerCapabilities(handshakePacket.serverCapabilities);\n        clientAuth.setDatabaseName(defaultSchema);\n        clientAuth.setScrumbleBuff(joinAndCreateScrumbleBuff(handshakePacket));\n        clientAuth.setAuthPluginName(authPluginName.getBytes());\n\n        byte[] clientAuthPkgBody = clientAuth.toBytes();\n        HeaderPacket h = new HeaderPacket();\n        h.setPacketBodyLength(clientAuthPkgBody.length);\n        h.setPacketSequenceNumber((byte) (header.getPacketSequenceNumber() + 1));\n\n        PacketManager.writePkg(channel, h.toBytes(), clientAuthPkgBody);\n        logger.info(\"client authentication packet is sent out.\");\n\n        // check auth result\n        header = PacketManager.readHeader(channel, 4);\n        body = PacketManager.readBytes(channel, header.getPacketBodyLength(), timeout);\n        assert body != null;\n        byte marker = body[0];\n        if (marker == -2 || marker == 1) {\n            if (isSha2Password && body[1] == 3) {\n                // sha2 auth ok\n                logger.info(\"caching_sha2_password auth success.\");\n                header = PacketManager.readHeader(channel, 4);\n                body = PacketManager.readBytes(channel, header.getPacketBodyLength(), timeout);\n            } else {\n                byte[] authData = null;\n                String pluginName = authPluginName;\n                if (marker == 1) {\n                    AuthSwitchRequestMoreData packet = new AuthSwitchRequestMoreData();\n                    packet.fromBytes(body);\n                    authData = packet.authData;\n                } else {\n                    AuthSwitchRequestPacket packet = new AuthSwitchRequestPacket();\n                    packet.fromBytes(body);\n                    authData = packet.authData;\n                    pluginName = packet.authName;\n                    logger.info(\"auth switch pluginName is {}.\", pluginName);\n                }\n\n                byte[] encryptedPassword = null;\n                if (\"mysql_clear_password\".equals(pluginName)) {\n                    encryptedPassword = getPassword().getBytes();\n                    header = authSwitchAfterAuth(encryptedPassword, header);\n                    body = PacketManager.readBytes(channel, header.getPacketBodyLength(), timeout);\n                } else if (pluginName == null || \"mysql_native_password\".equals(pluginName)) {\n                    try {\n                        encryptedPassword = MySQLPasswordEncrypter.scramble411(getPassword().getBytes(), authData);\n                    } catch (NoSuchAlgorithmException e) {\n                        throw new RuntimeException(\"can't encrypt password that will be sent to MySQL server.\", e);\n                    }\n                    header = authSwitchAfterAuth(encryptedPassword, header);\n                    body = PacketManager.readBytes(channel, header.getPacketBodyLength(), timeout);\n                } else if (\"caching_sha2_password\".equals(pluginName)) {\n                    if (body[0] == 0x01 && body[1] == 0x04) {\n                        // support full auth\n                        // clientAuth提前采用了sha2编码,会减少一次auth交互\n                        header = cachingSha2PasswordFullAuth(channel,\n                            header,\n                            getPassword().getBytes(),\n                            clientAuth.getScrumbleBuff());\n                        body = PacketManager.readBytes(channel, header.getPacketBodyLength(), timeout);\n                    } else {\n                        byte[] scramble = authData;\n                        try {\n                            encryptedPassword = MySQLPasswordEncrypter.scrambleCachingSha2(getPassword().getBytes(),\n                                scramble);\n                        } catch (DigestException e) {\n                            throw new RuntimeException(\"can't encrypt password that will be sent to MySQL server.\", e);\n                        }\n                        header = authSwitchAfterAuth(encryptedPassword, header);\n                        body = PacketManager.readBytes(channel, header.getPacketBodyLength(), timeout);\n                        assert body != null;\n                        if (body[0] == 0x01 && body[1] == 0x04) {\n                            // fixed issue https://github.com/alibaba/canal/pull/4767, support mysql 8.0.30+\n                            header = cachingSha2PasswordFullAuth(channel, header, getPassword().getBytes(), scramble);\n                            body = PacketManager.readBytes(channel, header.getPacketBodyLength(), timeout);\n                        } else {\n                            header = PacketManager.readHeader(channel, 4);\n                            body = PacketManager.readBytes(channel, header.getPacketBodyLength(), timeout);\n                        }\n                    }\n                } else {\n                    header = authSwitchAfterAuth(encryptedPassword, header);\n                    body = PacketManager.readBytes(channel, header.getPacketBodyLength(), timeout);\n                }\n            }\n        }\n        if (body[0] < 0) {\n            if (body[0] == -1) {\n                ErrorPacket err = new ErrorPacket();\n                err.fromBytes(body);\n                throw new IOException(\"Error When doing Client Authentication:\" + err.toString());\n            } else {\n                throw new IOException(\"Unexpected packet with field_count=\" + body[0]);\n            }\n        }\n    }\n\n    private HeaderPacket cachingSha2PasswordFullAuth(SocketChannel channel, HeaderPacket header, byte[] pass,\n                                                     byte[] seed) throws IOException {\n        AuthSwitchResponsePacket responsePacket = new AuthSwitchResponsePacket();\n        responsePacket.authData = new byte[] { 2 };\n        byte[] auth = responsePacket.toBytes();\n        HeaderPacket h = new HeaderPacket();\n        h.setPacketBodyLength(auth.length);\n        h.setPacketSequenceNumber((byte) (header.getPacketSequenceNumber() + 1));\n        PacketManager.writePkg(channel, h.toBytes(), auth);\n        logger.info(\"caching sha2 password fullAuth request public key packet is sent out.\");\n\n        header = PacketManager.readHeader(channel, 4);\n        byte[] body = PacketManager.readBytes(channel, header.getPacketBodyLength(), timeout);\n        AuthSwitchRequestMoreData packet = new AuthSwitchRequestMoreData();\n        packet.fromBytes(body);\n        if (packet.status != 0x01) {\n            throw new IOException(\"caching_sha2_password get public key failed\");\n        }\n\n        logger.info(\"caching sha2 password fullAuth get server public key succeed.\");\n        byte[] publicKeyBytes = packet.authData;\n        byte[] encryptedPassword = null;\n        try {\n            encryptedPassword = MySQLPasswordEncrypter.scrambleRsa(publicKeyBytes, pass, seed);\n        } catch (Exception e) {\n            logger.error(\"rsa encrypt failed {}\", publicKeyBytes);\n            throw new IOException(\"caching_sha2_password auth failed\", e);\n        }\n\n        // send auth\n        responsePacket = new AuthSwitchResponsePacket();\n        responsePacket.authData = encryptedPassword;\n        auth = responsePacket.toBytes();\n        h = new HeaderPacket();\n        h.setPacketBodyLength(auth.length);\n        h.setPacketSequenceNumber((byte) (header.getPacketSequenceNumber() + 1));\n        PacketManager.writePkg(channel, h.toBytes(), auth);\n        logger.info(\"caching sha2 password fullAuth response auth data packet is sent out.\");\n        return PacketManager.readHeader(channel, 4);\n    }\n\n    private HeaderPacket authSwitchAfterAuth(byte[] encryptedPassword, HeaderPacket header) throws IOException {\n        assert encryptedPassword != null;\n        AuthSwitchResponsePacket responsePacket = new AuthSwitchResponsePacket();\n        responsePacket.authData = encryptedPassword;\n        byte[] auth = responsePacket.toBytes();\n\n        HeaderPacket h = new HeaderPacket();\n        h.setPacketBodyLength(auth.length);\n        h.setPacketSequenceNumber((byte) (header.getPacketSequenceNumber() + 1));\n        PacketManager.writePkg(channel, h.toBytes(), auth);\n        logger.info(\"auth switch response packet is sent out.\");\n        header = PacketManager.readHeader(channel, 4);\n        return header;\n    }\n\n    private void auth323(SocketChannel channel, byte packetSequenceNumber, byte[] seed) throws IOException {\n        // auth 323\n        Reply323Packet r323 = new Reply323Packet();\n        if (password != null && password.length() > 0) {\n            r323.seed = MySQLPasswordEncrypter.scramble323(password, new String(seed)).getBytes();\n        }\n        byte[] b323Body = r323.toBytes();\n\n        HeaderPacket h323 = new HeaderPacket();\n        h323.setPacketBodyLength(b323Body.length);\n        h323.setPacketSequenceNumber((byte) (packetSequenceNumber + 1));\n\n        PacketManager.writePkg(channel, h323.toBytes(), b323Body);\n        logger.info(\"client 323 authentication packet is sent out.\");\n        // check auth result\n        HeaderPacket header = PacketManager.readHeader(channel, 4);\n        byte[] body = PacketManager.readBytes(channel, header.getPacketBodyLength());\n        assert body != null;\n        switch (body[0]) {\n            case 0:\n                break;\n            case -1:\n                ErrorPacket err = new ErrorPacket();\n                err.fromBytes(body);\n                throw new IOException(\"Error When doing Client Authentication:\" + err.toString());\n            default:\n                throw new IOException(\"Unexpected packet with field_count=\" + body[0]);\n        }\n    }\n\n    private byte[] joinAndCreateScrumbleBuff(HandshakeInitializationPacket handshakePacket) throws IOException {\n        byte[] dest = new byte[handshakePacket.seed.length + handshakePacket.restOfScrambleBuff.length];\n        System.arraycopy(handshakePacket.seed, 0, dest, 0, handshakePacket.seed.length);\n        System.arraycopy(handshakePacket.restOfScrambleBuff,\n            0,\n            dest,\n            handshakePacket.seed.length,\n            handshakePacket.restOfScrambleBuff.length);\n        return dest;\n    }\n\n    public InetSocketAddress getAddress() {\n        return address;\n    }\n\n    public void setAddress(InetSocketAddress address) {\n        this.address = address;\n    }\n\n    public String getUsername() {\n        return username;\n    }\n\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    public String getDefaultSchema() {\n        return defaultSchema;\n    }\n\n    public void setDefaultSchema(String defaultSchema) {\n        this.defaultSchema = defaultSchema;\n    }\n\n    public int getSoTimeout() {\n        return soTimeout;\n    }\n\n    public void setSoTimeout(int soTimeout) {\n        this.soTimeout = soTimeout;\n    }\n\n    public int getReceiveBufferSize() {\n        return receiveBufferSize;\n    }\n\n    public void setReceiveBufferSize(int receiveBufferSize) {\n        this.receiveBufferSize = receiveBufferSize;\n    }\n\n    public int getSendBufferSize() {\n        return sendBufferSize;\n    }\n\n    public void setSendBufferSize(int sendBufferSize) {\n        this.sendBufferSize = sendBufferSize;\n    }\n\n    public SocketChannel getChannel() {\n        return channel;\n    }\n\n    public void setChannel(SocketChannel channel) {\n        this.channel = channel;\n    }\n\n    public long getConnectionId() {\n        return connectionId;\n    }\n\n    public void setConnectionId(long connectionId) {\n        this.connectionId = connectionId;\n    }\n\n    public boolean isDumping() {\n        return dumping;\n    }\n\n    public void setDumping(boolean dumping) {\n        this.dumping = dumping;\n    }\n\n    public int getConnTimeout() {\n        return connTimeout;\n    }\n\n    public void setConnTimeout(int connTimeout) {\n        this.connTimeout = connTimeout;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    public String getServerVersion() {\n        return serverVersion;\n    }\n\n    public SslInfo getSslInfo() {\n        return sslInfo;\n    }\n\n    public void setSslInfo(SslInfo sslInfo) {\n        this.sslInfo = sslInfo;\n    }\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/MysqlQueryExecutor.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql;\r\n\r\nimport java.io.IOException;\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\n\r\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.HeaderPacket;\r\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.client.QueryCommandPacket;\r\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.server.EOFPacket;\r\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.server.ErrorPacket;\r\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.server.FieldPacket;\r\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.server.ResultSetHeaderPacket;\r\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.server.ResultSetPacket;\r\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.server.RowDataPacket;\r\nimport com.alibaba.otter.canal.parse.driver.mysql.socket.SocketChannel;\r\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.PacketManager;\r\n\r\n/**\r\n * 默认输出的数据编码为UTF-8，如有需要请正确转码\r\n * \r\n * @author jianghang 2013-9-4 上午11:50:26\r\n * @since 1.0.0\r\n */\r\npublic class MysqlQueryExecutor {\r\n\r\n    private SocketChannel channel;\r\n\r\n    public MysqlQueryExecutor(MysqlConnector connector) throws IOException{\r\n        if (!connector.isConnected()) {\r\n            throw new IOException(\"should execute connector.connect() first\");\r\n        }\r\n\r\n        this.channel = connector.getChannel();\r\n    }\r\n\r\n    public MysqlQueryExecutor(SocketChannel ch){\r\n        this.channel = ch;\r\n    }\r\n\r\n    /**\r\n     * (Result Set Header Packet) the number of columns <br>\r\n     * (Field Packets) column descriptors <br>\r\n     * (EOF Packet) marker: end of Field Packets <br>\r\n     * (Row Data Packets) row contents <br>\r\n     * (EOF Packet) marker: end of Data Packets\r\n     * \r\n     * @param queryString\r\n     * @return\r\n     * @throws IOException\r\n     */\r\n    public ResultSetPacket query(String queryString) throws IOException {\r\n        QueryCommandPacket cmd = new QueryCommandPacket();\r\n        cmd.setQueryString(queryString);\r\n        byte[] bodyBytes = cmd.toBytes();\r\n        PacketManager.writeBody(channel, bodyBytes);\r\n        byte[] body = readNextPacket();\r\n\r\n        if (body[0] < 0) {\r\n            ErrorPacket packet = new ErrorPacket();\r\n            packet.fromBytes(body);\r\n            throw new IOException(packet + \"\\n with command: \" + queryString);\r\n        }\r\n\r\n        ResultSetHeaderPacket rsHeader = new ResultSetHeaderPacket();\r\n        rsHeader.fromBytes(body);\r\n\r\n        List<FieldPacket> fields = new ArrayList<>();\r\n        for (int i = 0; i < rsHeader.getColumnCount(); i++) {\r\n            FieldPacket fp = new FieldPacket();\r\n            fp.fromBytes(readNextPacket());\r\n            fields.add(fp);\r\n        }\r\n\r\n        readEofPacket();\r\n\r\n        List<RowDataPacket> rowData = new ArrayList<>();\r\n        while (true) {\r\n            body = readNextPacket();\r\n            if (body[0] == -2) {\r\n                break;\r\n            }\r\n            RowDataPacket rowDataPacket = new RowDataPacket();\r\n            rowDataPacket.fromBytes(body);\r\n            rowData.add(rowDataPacket);\r\n        }\r\n\r\n        ResultSetPacket resultSet = new ResultSetPacket();\r\n        resultSet.getFieldDescriptors().addAll(fields);\r\n        for (RowDataPacket r : rowData) {\r\n            resultSet.getFieldValues().addAll(r.getColumns());\r\n        }\r\n        resultSet.setSourceAddress(channel.getRemoteSocketAddress());\r\n\r\n        return resultSet;\r\n    }\r\n\r\n    public List<ResultSetPacket> queryMulti(String queryString) throws IOException {\r\n        QueryCommandPacket cmd = new QueryCommandPacket();\r\n        cmd.setQueryString(queryString);\r\n        byte[] bodyBytes = cmd.toBytes();\r\n        PacketManager.writeBody(channel, bodyBytes);\r\n        List<ResultSetPacket> resultSets = new ArrayList<>();\r\n        boolean moreResult = true;\r\n        while (moreResult) {\r\n            byte[] body = readNextPacket();\r\n            if (body[0] < 0) {\r\n                ErrorPacket packet = new ErrorPacket();\r\n                packet.fromBytes(body);\r\n                throw new IOException(packet + \"\\n with command: \" + queryString);\r\n            }\r\n\r\n            ResultSetHeaderPacket rsHeader = new ResultSetHeaderPacket();\r\n            rsHeader.fromBytes(body);\r\n\r\n            List<FieldPacket> fields = new ArrayList<>();\r\n            for (int i = 0; i < rsHeader.getColumnCount(); i++) {\r\n                FieldPacket fp = new FieldPacket();\r\n                fp.fromBytes(readNextPacket());\r\n                fields.add(fp);\r\n            }\r\n\r\n            readEofPacket();\r\n\r\n            List<RowDataPacket> rowData = new ArrayList<>();\r\n            while (true) {\r\n                body = readNextPacket();\r\n                if (body[0] == -2) {\r\n                    EOFPacket packet = parseEOFPacket(body);\r\n                    moreResult = (packet.statusFlag & 0x0008) != 0;\r\n                    break;\r\n                }\r\n                RowDataPacket rowDataPacket = new RowDataPacket();\r\n                rowDataPacket.fromBytes(body);\r\n                rowData.add(rowDataPacket);\r\n            }\r\n\r\n            ResultSetPacket resultSet = new ResultSetPacket();\r\n            resultSet.getFieldDescriptors().addAll(fields);\r\n            for (RowDataPacket r : rowData) {\r\n                resultSet.getFieldValues().addAll(r.getColumns());\r\n            }\r\n            resultSet.setSourceAddress(channel.getRemoteSocketAddress());\r\n            resultSets.add(resultSet);\r\n        }\r\n\r\n        return resultSets;\r\n    }\r\n\r\n    private boolean readEofPacket() throws IOException {\r\n        byte[] eofBody = readNextPacket();\r\n        EOFPacket packet = parseEOFPacket(eofBody);\r\n        return (packet.statusFlag & 0x0008) != 0;\r\n    }\r\n\r\n    private EOFPacket parseEOFPacket(byte[] eofBody) throws IOException {\r\n        EOFPacket packet = new EOFPacket();\r\n        packet.fromBytes(eofBody);\r\n        if (eofBody[0] != -2) {\r\n            throw new IOException(\"EOF Packet is expected, but packet with field_count=\" + eofBody[0] + \" is found.\");\r\n        }\r\n        return packet;\r\n    }\r\n\r\n    protected byte[] readNextPacket() throws IOException {\r\n        HeaderPacket h = PacketManager.readHeader(channel, 4);\r\n        return PacketManager.readBytes(channel, h.getPacketBodyLength());\r\n    }\r\n}\r\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/MysqlUpdateExecutor.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql;\r\n\r\nimport java.io.IOException;\r\n\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\n\r\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.client.QueryCommandPacket;\r\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.server.ErrorPacket;\r\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.server.OKPacket;\r\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.PacketManager;\r\n\r\n/**\r\n * 默认输出的数据编码为UTF-8，如有需要请正确转码\r\n * \r\n * @author jianghang 2013-9-4 上午11:51:11\r\n * @since 1.0.0\r\n */\r\npublic class MysqlUpdateExecutor {\r\n\r\n    private static final Logger logger = LoggerFactory.getLogger(MysqlUpdateExecutor.class);\r\n\r\n    private MysqlConnector      connector;\r\n\r\n    public MysqlUpdateExecutor(MysqlConnector connector) throws IOException{\r\n        if (!connector.isConnected()) {\r\n            throw new IOException(\"should execute connector.connect() first\");\r\n        }\r\n\r\n        this.connector = connector;\r\n    }\r\n\r\n    /*\r\n     * public MysqlUpdateExecutor(SocketChannel ch){ this.channel = ch; }\r\n     */\r\n\r\n    public OKPacket update(String updateString) throws IOException {\r\n        QueryCommandPacket cmd = new QueryCommandPacket();\r\n        cmd.setQueryString(updateString);\r\n        byte[] bodyBytes = cmd.toBytes();\r\n        PacketManager.writeBody(connector.getChannel(), bodyBytes);\r\n\r\n        logger.debug(\"read update result...\");\r\n        byte[] body = PacketManager.readBytes(connector.getChannel(),\r\n            PacketManager.readHeader(connector.getChannel(), 4).getPacketBodyLength());\r\n        if (body[0] < 0) {\r\n            ErrorPacket packet = new ErrorPacket();\r\n            packet.fromBytes(body);\r\n            throw new IOException(packet + \"\\n with command: \" + updateString);\r\n        }\r\n\r\n        OKPacket packet = new OKPacket();\r\n        packet.fromBytes(body);\r\n        return packet;\r\n    }\r\n}\r\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/Capability.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets;\n\n/**\n * https://dev.mysql.com/doc/internals/en/capability-flags.html#packet-Protocol\n * ::CapabilityFlags\n */\npublic interface Capability {\n\n    // Use the improved version of Old Password Authentication.\n    // Assumed to be set since 4.1.1.\n    int CLIENT_LONG_PASSWORD                  = 0x00000001;\n\n    // Send found rows instead of affected rows in EOF_Packet.\n    int CLIENT_FOUND_ROWS                     = 0x00000002;\n\n    // https://dev.mysql.com/doc/internals/en/com-query-response.html#packet-Protocol::ColumnDefinition320\n    // Longer flags in Protocol::ColumnDefinition320.\n    // Server:Supports longer flags.\n    // Client:Expects longer flags.\n    // 执行查询sql时，除了返回结果集，还返回元数据\n    int CLIENT_LONG_FLAG                      = 0x00000004;\n\n    // 可以在handshake时，指定一个数据库名\n    // Database (schema) name can be specified on connect in Handshake Response\n    // Packet.\n    // Server: Supports schema-name in Handshake Response Packet.\n    // Client: Handshake Response Packet contains a schema-name.\n    int CLIENT_CONNECT_WITH_DB                = 0x00000008;\n\n    // Server: Do not permit database.table.column.\n    int CLIENT_NO_SCHEMA                      = 0x00000010;\n\n    // Compression protocol supported.\n    // Server:Supports compression.\n    // Client:Switches to Compression compressed protocol after successful\n    // authentication.\n    int CLIENT_COMPRESS                       = 0x00000020;\n\n    // Special handling of ODBC behavior.\n    // No special behavior since 3.22.\n    int CLIENT_ODBC                           = 0x00000040;\n\n    // Can use LOAD DATA LOCAL.\n    // Server:Enables the LOCAL INFILE request of LOAD DATA|XML.\n    // Client:Will handle LOCAL INFILE request.\n    int CLIENT_LOCAL_FILES                    = 0x00000080;\n\n    // Server: Parser can ignore spaces before '('.\n    // Client: Let the parser ignore spaces before '('.\n    int CLIENT_IGNORE_SPACE                   = 0x00000100;\n\n    // Server:Supports the 4.1 protocol,\n    // 4.1协议中，\n    // OKPacket将会包含warning count\n    // ERR_Packet包含SQL state\n    // EOF_Packet包含warning count和status flags\n    // Client:Uses the 4.1 protocol.\n    // Note: this value was CLIENT_CHANGE_USER in 3.22, unused in 4.0\n    // If CLIENT_PROTOCOL_41 is set：\n    // 1、the ok packet contains a warning count.\n    // https://dev.mysql.com/doc/internals/en/packet-OK_Packet.html\n    // 2、ERR_Packet It contains a SQL state value if CLIENT_PROTOCOL_41 is\n    // enabled. //https://dev.mysql.com/doc/internals/en/packet-ERR_Packet.html\n    // 3、EOF_Packet If CLIENT_PROTOCOL_41 is enabled, the EOF packet contains a\n    // warning count and status flags.\n    // https://dev.mysql.com/doc/internals/en/packet-EOF_Packet.html\n    int CLIENT_PROTOCOL_41                    = 0x00000200;\n\n    // wait_timeout versus wait_interactive_timeout.\n    // Server:Supports interactive and noninteractive clients.\n    // Client:Client is interactive.\n    int CLIENT_INTERACTIVE                    = 0x00000400;\n\n    // Server: Supports SSL.\n    // Client: Switch to SSL after sending the capability-flags.\n    int CLIENT_SSL                            = 0x00000800;\n\n    // Client: Do not issue SIGPIPE if network failures occur (libmysqlclient\n    // only).\n    int CLIENT_IGNORE_SIGPIPE                 = 0x00001000;\n\n    // Server: Can send status flags in EOF_Packet.\n    // Client:Expects status flags in EOF_Packet.\n    // Note:This flag is optional in 3.23, but always set by the server since\n    // 4.0.\n    int CLIENT_TRANSACTIONS                   = 0x00002000;\n\n    // Unused\n    // Note: Was named CLIENT_PROTOCOL_41 in 4.1.0.\n    int CLIENT_RESERVED                       = 0x00004000;\n\n    /**\n     * <pre>\n     *      服务端返回20 byte随机字节，客户端利用其对密码进行加密，加密算法如下：\n     *      https://dev.mysql.com/doc/internals/en/secure-password-authentication.html#packet-Authentication::Native41\n     *      Authentication::Native41:\n     *      client-side expects a 20-byte random challenge\n     *      client-side returns a 20-byte response based on the algorithm described later\n     *      Name\n     *      mysql_native_password\n     *      Requires\n     *      CLIENT_SECURE_CONNECTION\n     *      Image description follows.\n     *      Image description\n     *      This method fixes a 2 short-comings of the Old Password Authentication:\n     *      (https://dev.mysql.com/doc/internals/en/old-password-authentication.html#packet-Authentication::Old)\n     *      using a tested, crypto-graphic hashing function which isn't broken\n     *      knowning the content of the hash in the mysql.user table isn't enough to authenticate against the MySQL Server.\n     *      The password is calculated by:\n     *      SHA1( password ) XOR SHA1( \"20-bytes random data from server\" <concat> SHA1( SHA1( password ) ) )\n     * </pre>\n     */\n    int CLIENT_SECURE_CONNECTION              = 0x00008000;\n\n    // Server:Can handle multiple statements per COM_QUERY and COM_STMT_PREPARE.\n    // Client:May send multiple statements per COM_QUERY and COM_STMT_PREPARE.\n    // Note:Was named CLIENT_MULTI_QUERIES in 4.1.0, renamed later.\n    // Requires:CLIENT_PROTOCOL_41\n    int CLIENT_MULTI_STATEMENTS               = 0x00010000;\n\n    // Server: Can send multiple resultsets for COM_QUERY.\n    // Client: Can handle multiple resultsets for COM_QUERY.\n    // Requires:CLIENT_PROTOCOL_41\n    int CLIENT_MULTI_RESULTS                  = 0x00020000;\n\n    // Server: Can send multiple resultsets for ComStmtExecutePacket.\n    // Client: Can handle multiple resultsets for ComStmtExecutePacket.\n    // Requires:CLIENT_PROTOCOL_41\n    int CLIENT_PS_MULTI_RESULTS               = 0x00040000;\n\n    // Server:Sends extra data in Initial Handshake Packet and supports the\n    // pluggable authentication protocol.\n    // Client: Supports authentication plugins.\n    // Requires: CLIENT_PROTOCOL_41\n    int CLIENT_PLUGIN_AUTH                    = 0x00080000;\n\n    // Server: Permits connection attributes in Protocol::HandshakeResponse41.\n    // Client: Sends connection attributes in Protocol::HandshakeResponse41.\n    int CLIENT_CONNECT_ATTRS                  = 0x00100000;\n\n    // Server:Understands length-encoded integer for auth response data in\n    // Protocol::HandshakeResponse41.\n    // Client:Length of auth response data in Protocol::HandshakeResponse41 is a\n    // length-encoded integer.\n    // Note: The flag was introduced in 5.6.6, but had the wrong value.\n    int CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA = 0x00200000;\n\n    // Server: Announces support for expired password extension.\n    // Client: Can handle expired passwords.\n    int CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS   = 0x00400000;\n\n    // Server: Can set SERVER_SESSION_STATE_CHANGED in the Status Flags and send\n    // session-state change data after a OK packet.\n    // Client: Expects the server to send sesson-state changes after a OK\n    // packet.\n    int CLIENT_SESSION_TRACK                  = 0x00800000;\n\n    /**\n     * Server: Can send OK after a Text Resultset. Client: Expects an OK\n     * (instead of EOF) after the resultset rows of a Text Resultset.\n     * Background:To support CLIENT_SESSION_TRACK, additional information must\n     * be sent after all successful commands. Although the OK packet is\n     * extensible, the EOF packet is not due to the overlap of its bytes with\n     * the content of the Text Resultset Row. Therefore, the EOF packet in the\n     * Text Resultset is replaced with an OK packet. EOF packets are deprecated\n     * as of MySQL 5.7.5.\n     */\n    int CLIENT_DEPRECATE_EOF                  = 0x01000000;\n\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/CommandPacket.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets;\n\nimport org.apache.commons.lang.builder.ToStringBuilder;\n\nimport com.alibaba.otter.canal.common.utils.CanalToStringStyle;\n\npublic abstract class CommandPacket implements IPacket {\n\n    private byte command;\n\n    // arg\n\n    public void setCommand(byte command) {\n        this.command = command;\n    }\n\n    public byte getCommand() {\n        return command;\n    }\n\n    public String toString() {\n        return ToStringBuilder.reflectionToString(this, CanalToStringStyle.DEFAULT_STYLE);\n    }\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/GTIDSet.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets;\n\nimport java.io.IOException;\n\n/**\n * Created by hiwjd on 2018/4/23. hiwjd0@gmail.com\n */\npublic interface GTIDSet {\n\n    /**\n     * 序列化成字节数组\n     *\n     * @return\n     */\n    byte[] encode() throws IOException;\n\n    /**\n     * 更新当前实例\n     * \n     * @param str\n     * @throws Exception\n     */\n    void update(String str);\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/HeaderPacket.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets;\n\nimport org.apache.commons.lang.builder.ToStringBuilder;\n\nimport com.alibaba.otter.canal.common.utils.CanalToStringStyle;\n\n/**\n * <pre>\n * Offset  Length     Description\n *   0       3        Packet body length stored with the low byte first.\n *   3       1        Packet sequence number. The sequence numbers are reset with each new command. \n *                      While the correct packet sequencing is ensured by the underlying transmission protocol,\n *                      this field is used for the sanity checks of the application logic.\n * </pre>\n * \n * <br>\n * The Packet Header will not be shown in the descriptions of packets that\n * follow this section. Think of it as always there. But logically, it\n * \"precedes the packet\" rather than \"is included in the packet\".<br>\n * \n * @author fujohnwang\n */\npublic class HeaderPacket implements IPacket {\n\n    /**\n     * this field indicates the packet length that follows the header, with\n     * header packet's 4 bytes excluded.\n     */\n    private int  packetBodyLength;\n    private byte packetSequenceNumber;\n\n    /**\n     * little-endian byte order\n     */\n    public byte[] toBytes() {\n        byte[] data = new byte[4];\n        data[0] = (byte) (packetBodyLength & 0xFF);\n        data[1] = (byte) (packetBodyLength >>> 8);\n        data[2] = (byte) (packetBodyLength >>> 16);\n        data[3] = getPacketSequenceNumber();\n        return data;\n    }\n\n    /**\n     * little-endian byte order\n     */\n    public void fromBytes(byte[] data) {\n        if (data == null || data.length != 4) {\n            throw new IllegalArgumentException(\"invalid header data. It can't be null and the length must be 4 byte.\");\n        }\n        this.packetBodyLength = (data[0] & 0xFF) | ((data[1] & 0xFF) << 8) | ((data[2] & 0xFF) << 16);\n        this.setPacketSequenceNumber(data[3]);\n    }\n\n    public int getPacketBodyLength() {\n        return packetBodyLength;\n    }\n\n    public void setPacketBodyLength(int packetBodyLength) {\n        this.packetBodyLength = packetBodyLength;\n    }\n\n    public void setPacketSequenceNumber(byte packetSequenceNumber) {\n        this.packetSequenceNumber = packetSequenceNumber;\n    }\n\n    public byte getPacketSequenceNumber() {\n        return packetSequenceNumber;\n    }\n\n    public String toString() {\n        return ToStringBuilder.reflectionToString(this, CanalToStringStyle.DEFAULT_STYLE);\n    }\n\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/IPacket.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets;\n\nimport java.io.IOException;\n\n/**\n * Top Abstraction for network packet.<br>\n * it exposes 2 behaviors for sub-class implementation which will be used to\n * marshal data into bytes before sending and to un-marshal data from data after\n * receiving.<br>\n * \n * @author fujohnwang\n * @see 1.0\n */\npublic interface IPacket {\n\n    /**\n     * un-marshal raw bytes into {@link IPacket} state for application usage.<br>\n     * \n     * @param data, the raw byte data received from networking\n     */\n    void fromBytes(byte[] data) throws IOException;\n\n    /**\n     * marshal the {@link IPacket} state into raw bytes for sending out to\n     * network.<br>\n     * \n     * @return the bytes that's collected from {@link IPacket} state\n     */\n    byte[] toBytes() throws IOException;\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/MariaGTIDSet.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets;\n\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.apache.commons.lang.StringUtils;\n\n/**\n * 类 MariaGTIDSet.java 的实现\n *\n * @author winger 2020/9/24 10:31 上午\n * @version 1.0.0\n */\npublic class MariaGTIDSet implements GTIDSet {\n\n    //MariaDB 10.0.2+ representation of Gtid\n    private Map<Long, MariaGtid> gtidMap = new HashMap<>();\n\n    @Override\n    public byte[] encode() throws IOException {\n        return this.toString().getBytes();\n    }\n\n    @Override\n    public void update(String str) {\n        if (StringUtils.isNotEmpty(str)) {\n            // 兼容 GTID 为空的情况，例如 mysql-bin.000001 的 GTID 是空的\n            MariaGtid mariaGtid = MariaGtid.parse(str);\n            gtidMap.put(mariaGtid.getDomainId(), mariaGtid);\n        }\n    }\n\n    public void add(MariaGtid mariaGtid) {\n        gtidMap.put(mariaGtid.getDomainId(), mariaGtid);\n    }\n\n    public static MariaGTIDSet parse(String gtidData) {\n        Map<Long, MariaGtid> gtidMap = new HashMap<>();\n        if (StringUtils.isNotEmpty(gtidData)) {\n            // 存在多个GTID时会有回车符\n            String[] gtidStrs = gtidData.replaceAll(\"\\n\", \"\").split(\",\");\n            for (String gtid : gtidStrs) {\n                MariaGtid mariaGtid = MariaGtid.parse(gtid);\n                gtidMap.put(mariaGtid.getDomainId(), mariaGtid);\n            }\n        }\n        MariaGTIDSet gtidSet = new MariaGTIDSet();\n        gtidSet.gtidMap = gtidMap;\n        return gtidSet;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        for (MariaGtid gtid : gtidMap.values()) {\n            if (sb.length() > 0) {\n                sb.append(\",\");\n            }\n            sb.append(gtid.toString());\n        }\n        return sb.toString();\n    }\n}\n\n\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/MariaGtid.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets;\n\nimport org.apache.commons.lang.math.NumberUtils;\n\n/**\n * 类 MariaGtid.java 的实现\n *\n * @author winger 2020/9/24 11:30 上午\n * @version 1.0.0\n */\npublic class MariaGtid {\n\n    // {domainId}-{serverId}-{sequence}\n    private long domainId;\n    private long serverId;\n    private long sequence;\n\n    public MariaGtid(long domainId, long serverId, long sequence) {\n        this.domainId = domainId;\n        this.serverId = serverId;\n        this.sequence = sequence;\n    }\n\n    public MariaGtid(String gtid) {\n        String[] gtidArr = gtid.split(\"-\");\n        this.domainId = NumberUtils.toLong(gtidArr[0]);\n        this.serverId = NumberUtils.toLong(gtidArr[1]);\n        this.sequence = NumberUtils.toLong(gtidArr[2]);\n    }\n\n    public static MariaGtid parse(String gtid) {\n        return new MariaGtid(gtid);\n    }\n\n    public long getDomainId() {\n        return domainId;\n    }\n\n    public void setDomainId(long domainId) {\n        this.domainId = domainId;\n    }\n\n    public long getServerId() {\n        return serverId;\n    }\n\n    public void setServerId(long serverId) {\n        this.serverId = serverId;\n    }\n\n    public long getSequence() {\n        return sequence;\n    }\n\n    public void setSequence(long sequence) {\n        this.sequence = sequence;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) {\n            return true;\n        }\n        if (o == null || getClass() != o.getClass()) {\n            return false;\n        }\n        MariaGtid mariaGtid = (MariaGtid) o;\n        return domainId == mariaGtid.domainId &&\n                serverId == mariaGtid.serverId &&\n                sequence == mariaGtid.sequence;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder(16);\n        sb.append(domainId).append(\"-\");\n        sb.append(serverId).append(\"-\");\n        return sb.append(sequence).toString();\n    }\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/MysqlGTIDSet.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.ByteHelper;\n\n/**\n * Created by hiwjd on 2018/4/23. hiwjd0@gmail.com\n */\npublic class MysqlGTIDSet implements GTIDSet {\n\n    public Map<String, UUIDSet> sets;\n\n    @Override\n    public byte[] encode() throws IOException {\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n        ByteHelper.writeUnsignedInt64LittleEndian(sets.size(), out);\n\n        for (Map.Entry<String, UUIDSet> entry : sets.entrySet()) {\n            out.write(entry.getValue().encode());\n        }\n\n        return out.toByteArray();\n    }\n\n    @Override\n    public void update(String str) {\n        UUIDSet us = UUIDSet.parse(str);\n        String sid = us.SID.toString();\n        if (sets.containsKey(sid)) {\n            sets.get(sid).intervals.addAll(us.intervals);\n            sets.get(sid).intervals = UUIDSet.combine(sets.get(sid).intervals);\n        } else {\n            sets.put(sid, us);\n        }\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (o == null) return false;\n        if (this == o) return true;\n\n        MysqlGTIDSet gs = (MysqlGTIDSet) o;\n        if (gs.sets == null) return false;\n\n        for (Map.Entry<String, UUIDSet> entry : sets.entrySet()) {\n            if (!entry.getValue().equals(gs.sets.get(entry.getKey()))) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * 解析如下格式的字符串为MysqlGTIDSet: 726757ad-4455-11e8-ae04-0242ac110002:1 =>\n     * MysqlGTIDSet{ sets: { 726757ad-4455-11e8-ae04-0242ac110002: UUIDSet{ SID:\n     * 726757ad-4455-11e8-ae04-0242ac110002, intervals: [{start:1, stop:2}] } }\n     * } 726757ad-4455-11e8-ae04-0242ac110002:1-3 => MysqlGTIDSet{ sets: {\n     * 726757ad-4455-11e8-ae04-0242ac110002: UUIDSet{ SID:\n     * 726757ad-4455-11e8-ae04-0242ac110002, intervals: [{start:1, stop:4}] } }\n     * } 726757ad-4455-11e8-ae04-0242ac110002:1-3:4 => MysqlGTIDSet{ sets: {\n     * 726757ad-4455-11e8-ae04-0242ac110002: UUIDSet{ SID:\n     * 726757ad-4455-11e8-ae04-0242ac110002, intervals: [{start:1, stop:5}] } }\n     * } 726757ad-4455-11e8-ae04-0242ac110002:1-3:7-9 => MysqlGTIDSet{ sets: {\n     * 726757ad-4455-11e8-ae04-0242ac110002: UUIDSet{ SID:\n     * 726757ad-4455-11e8-ae04-0242ac110002, intervals: [{start:1, stop:4},\n     * {start:7, stop: 10}] } } }\n     * 726757ad-4455-11e8-ae04-0242ac110002:1-3,726757\n     * ad-4455-11e8-ae04-0242ac110003:4 => MysqlGTIDSet{ sets: {\n     * 726757ad-4455-11e8-ae04-0242ac110002: UUIDSet{ SID:\n     * 726757ad-4455-11e8-ae04-0242ac110002, intervals: [{start:1, stop:4}] },\n     * 726757ad-4455-11e8-ae04-0242ac110003: UUIDSet{ SID:\n     * 726757ad-4455-11e8-ae04-0242ac110002, intervals: [{start:4, stop:5}] } }\n     * }\n     *\n     * @param gtidData\n     * @return\n     */\n    public static MysqlGTIDSet parse(String gtidData) {\n        Map<String, UUIDSet> m;\n\n        if (gtidData == null || gtidData.length() < 1) {\n            m = new HashMap<>();\n        } else {\n            // 存在多个GTID时会有回车符\n            String[] uuidStrs = gtidData.replaceAll(\"\\n\", \"\").split(\",\");\n            m = new HashMap<>(uuidStrs.length);\n            for (String uuidStr : uuidStrs) {\n                UUIDSet uuidSet = UUIDSet.parse(uuidStr);\n                m.put(uuidSet.SID.toString(), uuidSet);\n            }\n        }\n\n        MysqlGTIDSet gs = new MysqlGTIDSet();\n        gs.sets = m;\n\n        return gs;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n\n        for (Map.Entry<String, UUIDSet> entry : sets.entrySet()) {\n            if (sb.length() > 0) {\n                sb.append(\",\");\n            }\n            sb.append(entry.getValue().toString());\n        }\n\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/PacketWithHeaderPacket.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets;\n\nimport org.apache.commons.lang.builder.ToStringBuilder;\n\nimport com.alibaba.otter.canal.common.utils.CanalToStringStyle;\nimport com.google.common.base.Preconditions;\n\npublic abstract class PacketWithHeaderPacket implements IPacket {\n\n    protected HeaderPacket header;\n\n    protected PacketWithHeaderPacket(){\n    }\n\n    protected PacketWithHeaderPacket(HeaderPacket header){\n        setHeader(header);\n    }\n\n    public void setHeader(HeaderPacket header) {\n        Preconditions.checkNotNull(header);\n        this.header = header;\n    }\n\n    public HeaderPacket getHeader() {\n        return header;\n    }\n\n    public String toString() {\n        return ToStringBuilder.reflectionToString(this, CanalToStringStyle.DEFAULT_STYLE);\n    }\n\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/UUIDSet.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.UUID;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.ByteHelper;\n\n/**\n * Created by hiwjd on 2018/4/23. hiwjd0@gmail.com\n */\npublic class UUIDSet {\n\n    public UUID           SID;\n    public List<Interval> intervals;\n\n    public byte[] encode() throws IOException {\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n\n        ByteBuffer bb = ByteBuffer.wrap(new byte[16]);\n        bb.putLong(SID.getMostSignificantBits());\n        bb.putLong(SID.getLeastSignificantBits());\n\n        out.write(bb.array());\n\n        ByteHelper.writeUnsignedInt64LittleEndian(intervals.size(), out);\n\n        for (Interval interval : intervals) {\n            ByteHelper.writeUnsignedInt64LittleEndian(interval.start, out);\n            ByteHelper.writeUnsignedInt64LittleEndian(interval.stop, out);\n        }\n\n        return out.toByteArray();\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (o == null) return false;\n        if (this == o) return true;\n\n        UUIDSet us = (UUIDSet) o;\n        Collections.sort(intervals);\n        Collections.sort(us.intervals);\n        if (SID.equals(us.SID) && intervals.equals(us.intervals)) {\n            return true;\n        }\n\n        return false;\n    }\n\n    public static class Interval implements Comparable<Interval> {\n\n        public long start;\n        public long stop;\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (o == null || getClass() != o.getClass()) return false;\n\n            Interval interval = (Interval) o;\n\n            if (start != interval.start) return false;\n            return stop == interval.stop;\n        }\n\n        @Override\n        public int hashCode() {\n            int result = (int) (start ^ (start >>> 32));\n            result = 31 * result + (int) (stop ^ (stop >>> 32));\n            return result;\n        }\n\n        @Override\n        public int compareTo(Interval o) {\n            if (equals(o)) {\n                return 1;\n            }\n            return Long.compare(start, o.start);\n        }\n    }\n\n    /**\n     * 解析如下格式字符串为UUIDSet: 726757ad-4455-11e8-ae04-0242ac110002:1 => UUIDSet{SID:\n     * 726757ad-4455-11e8-ae04-0242ac110002, intervals: [{start:1, stop:2}]}\n     * 726757ad-4455-11e8-ae04-0242ac110002:1-3 => UUIDSet{SID:\n     * 726757ad-4455-11e8-ae04-0242ac110002, intervals: [{start:1, stop:4}]}\n     * 726757ad-4455-11e8-ae04-0242ac110002:1-3:4 UUIDSet{SID:\n     * 726757ad-4455-11e8-ae04-0242ac110002, intervals: [{start:1, stop:5}]}\n     * 726757ad-4455-11e8-ae04-0242ac110002:1-3:7-9 UUIDSet{SID:\n     * 726757ad-4455-11e8-ae04-0242ac110002, intervals: [{start:1, stop:4},\n     * {start:7, stop:10}]}\n     *\n     * @param str\n     * @return\n     */\n    public static UUIDSet parse(String str) {\n        String[] ss = str.split(\":\");\n\n        if (ss.length < 2) {\n            throw new RuntimeException(String.format(\"parseUUIDSet failed due to wrong format: %s\", str));\n        }\n\n        List<Interval> intervals = new ArrayList<>();\n        for (int i = 1; i < ss.length; i++) {\n            intervals.add(parseInterval(ss[i]));\n        }\n\n        UUIDSet uuidSet = new UUIDSet();\n        uuidSet.SID = UUID.fromString(ss[0]);\n        uuidSet.intervals = combine(intervals);\n\n        return uuidSet;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n\n        sb.append(SID.toString());\n        for (Interval interval : intervals) {\n            if (interval.start == interval.stop - 1) {\n                sb.append(\":\");\n                sb.append(interval.start);\n            } else {\n                sb.append(\":\");\n                sb.append(interval.start);\n                sb.append(\"-\");\n                sb.append(interval.stop - 1);\n            }\n        }\n\n        return sb.toString();\n    }\n\n    /**\n     * 解析如下格式字符串为Interval: 1 => Interval{start:1, stop:2} 1-3 =>\n     * Interval{start:1, stop:4} 注意！字符串格式表达时[n,m]是两侧都包含的，Interval表达时[n,m)右侧开\n     *\n     * @param str\n     * @return\n     */\n    public static Interval parseInterval(String str) {\n        String[] ss = str.split(\"-\");\n\n        Interval interval = new Interval();\n        switch (ss.length) {\n            case 1:\n                interval.start = Long.parseLong(ss[0]);\n                interval.stop = interval.start + 1;\n                break;\n            case 2:\n                interval.start = Long.parseLong(ss[0]);\n                interval.stop = Long.parseLong(ss[1]) + 1;\n                break;\n            default:\n                throw new RuntimeException(String.format(\"parseInterval failed due to wrong format: %s\", str));\n        }\n\n        return interval;\n    }\n\n    /**\n     * 把{start,stop}连续的合并掉: [{start:1, stop:4},{start:4, stop:5}] => [{start:1,\n     * stop:5}]\n     *\n     * @param intervals\n     * @return\n     */\n    public static List<Interval> combine(List<Interval> intervals) {\n        List<Interval> combined = new ArrayList<>();\n        Collections.sort(intervals);\n        int len = intervals.size();\n        for (int i = 0; i < len; i++) {\n            combined.add(intervals.get(i));\n\n            int j;\n            for (j = i + 1; j < len; j++) {\n                if (intervals.get(i).stop >= intervals.get(j).start) {\n                    intervals.get(i).stop = intervals.get(j).stop;\n                } else {\n                    break;\n                }\n            }\n            i = j - 1;\n        }\n\n        return combined;\n    }\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/client/AuthSwitchResponsePacket.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets.client;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.CommandPacket;\n\npublic class AuthSwitchResponsePacket extends CommandPacket {\n\n    public byte[] authData;\n\n    public void fromBytes(byte[] data) {\n    }\n\n    public byte[] toBytes() throws IOException {\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n        out.write(authData);\n        return out.toByteArray();\n    }\n\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/client/BinlogDumpCommandPacket.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets.client;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\n\nimport org.apache.commons.lang.StringUtils;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.CommandPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.ByteHelper;\n\n/**\n * COM_BINLOG_DUMP\n * \n * @author fujohnwang\n * @since 1.0\n */\npublic class BinlogDumpCommandPacket extends CommandPacket {\n\n    /** BINLOG_DUMP options */\n    public static final int BINLOG_DUMP_NON_BLOCK           = 1;\n    public static final int BINLOG_SEND_ANNOTATE_ROWS_EVENT = 2;\n    public long             binlogPosition;\n    public long             slaveServerId;\n    public String           binlogFileName;\n\n    public BinlogDumpCommandPacket(){\n        setCommand((byte) 0x12);\n    }\n\n    public void fromBytes(byte[] data) {\n        // bypass\n    }\n\n    /**\n     * <pre>\n     * Bytes                        Name\n     *  -----                        ----\n     *  1                            command\n     *  n                            arg\n     *  --------------------------------------------------------\n     *  Bytes                        Name\n     *  -----                        ----\n     *  4                            binlog position to start at (little endian)\n     *  2                            binlog flags (currently not used; always 0)\n     *  4                            server_id of the slave (little endian)\n     *  n                            binlog file name (optional)\n     * \n     * </pre>\n     */\n    public byte[] toBytes() throws IOException {\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n        // 0. write command number\n        out.write(getCommand());\n        // 1. write 4 bytes bin-log position to start at\n        ByteHelper.writeUnsignedIntLittleEndian(binlogPosition, out);\n        // 2. write 2 bytes bin-log flags\n        int binlog_flags = 0;\n        binlog_flags |= BINLOG_SEND_ANNOTATE_ROWS_EVENT;\n        out.write(binlog_flags);\n        out.write(0x00);\n        // 3. write 4 bytes server id of the slave\n        ByteHelper.writeUnsignedIntLittleEndian(this.slaveServerId, out);\n        // 4. write bin-log file name if necessary\n        if (StringUtils.isNotEmpty(this.binlogFileName)) {\n            out.write(this.binlogFileName.getBytes());\n        }\n        return out.toByteArray();\n    }\n\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/client/BinlogDumpGTIDCommandPacket.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets.client;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.CommandPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.GTIDSet;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.ByteHelper;\n\n/**\n * Created by hiwjd on 2018/4/24. hiwjd0@gmail.com\n * https://dev.mysql.com/doc/internals/en/com-binlog-dump-gtid.html\n */\npublic class BinlogDumpGTIDCommandPacket extends CommandPacket {\n\n    public static final int BINLOG_DUMP_NON_BLOCK   = 0x01;\n    public static final int BINLOG_THROUGH_POSITION = 0x02;\n    public static final int BINLOG_THROUGH_GTID     = 0x04;\n\n    public long             slaveServerId;\n    public GTIDSet          gtidSet;\n\n    public BinlogDumpGTIDCommandPacket(){\n        setCommand((byte) 0x1e);\n    }\n\n    @Override\n    public void fromBytes(byte[] data) throws IOException {\n    }\n\n    @Override\n    public byte[] toBytes() throws IOException {\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n\n        // 0. [1] write command number\n        out.write(getCommand());\n        // 1. [2] flags\n        ByteHelper.writeUnsignedShortLittleEndian(BINLOG_THROUGH_GTID, out);\n        // 2. [4] server-id\n        ByteHelper.writeUnsignedIntLittleEndian(slaveServerId, out);\n        // 3. [4] binlog-filename-len\n        ByteHelper.writeUnsignedIntLittleEndian(0, out);\n        // 4. [] binlog-filename\n        // skip\n        // 5. [8] binlog-pos\n        ByteHelper.writeUnsignedInt64LittleEndian(4, out);\n        // if flags & BINLOG_THROUGH_GTID {\n        byte[] bs = gtidSet.encode();\n        // 6. [4] data-size\n        ByteHelper.writeUnsignedIntLittleEndian(bs.length, out);\n        // 7, [] data\n        // [8] n_sids // 文档写的是4个字节，其实是8个字节\n        // for n_sids {\n        // [16] SID\n        // [8] n_intervals\n        // for n_intervals {\n        // [8] start (signed)\n        // [8] end (signed)\n        // }\n        // }\n        out.write(bs);\n        // }\n\n        return out.toByteArray();\n    }\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/client/ClientAuthenticationPacket.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets.client;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.security.NoSuchAlgorithmException;\n\nimport org.apache.commons.lang.StringUtils;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.Capability;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.PacketWithHeaderPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.ByteHelper;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.MSC;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.MySQLPasswordEncrypter;\n\npublic class ClientAuthenticationPacket extends PacketWithHeaderPacket {\n\n    private int    clientCapability = Capability.CLIENT_LONG_PASSWORD | Capability.CLIENT_LONG_FLAG\n                                      | Capability.CLIENT_PROTOCOL_41 | Capability.CLIENT_INTERACTIVE\n                                      | Capability.CLIENT_TRANSACTIONS | Capability.CLIENT_SECURE_CONNECTION\n                                      | Capability.CLIENT_MULTI_STATEMENTS | Capability.CLIENT_PLUGIN_AUTH;\n    private String username;\n    private String password;\n    private byte   charsetNumber;\n    private String databaseName;\n    private int    serverCapabilities;\n    private byte[] scrumbleBuff;\n    private byte[] authPluginName;\n\n    public void fromBytes(byte[] data) {\n        // bypass since nowhere to use.\n    }\n\n    /**\n     * <pre>\n     * VERSION 4.1\n     *  Bytes                        Name\n     *  -----                        ----\n     *  4                            client_flags\n     *  4                            max_packet_size\n     *  1                            charset_number\n     *  23                           (filler) always 0x00...\n     *  n (Null-Terminated String)   user\n     *  n (Length Coded Binary)      scramble_buff (1 + x bytes)\n     *  n (Null-Terminated String)   databasename (optional)\n     *  n (Null-Terminated String)   auth plugin name (optional)\n     * </pre>\n     * \n     * @throws IOException\n     */\n    public byte[] toBytes() throws IOException {\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n        // 1. write client_flags\n        ByteHelper.writeUnsignedIntLittleEndian(clientCapability, out); // remove\n        // client_interactive\n        // feature\n\n        // 2. write max_packet_size\n        ByteHelper.writeUnsignedIntLittleEndian(MSC.MAX_PACKET_LENGTH, out);\n        // 3. write charset_number\n        out.write(this.charsetNumber);\n        // 4. write (filler) always 0x00...\n        out.write(new byte[23]);\n        // 5. write (Null-Terminated String) user\n        ByteHelper.writeNullTerminatedString(getUsername(), out);\n        // 6. write (Length Coded Binary) scramble_buff (1 + x bytes)\n        if (StringUtils.isEmpty(getPassword())) {\n            out.write(0x00);\n        } else {\n            try {\n                byte[] encryptedPassword = MySQLPasswordEncrypter.scramble411(getPassword().getBytes(), scrumbleBuff);\n                ByteHelper.writeBinaryCodedLengthBytes(encryptedPassword, out);\n            } catch (NoSuchAlgorithmException e) {\n                throw new RuntimeException(\"can't encrypt password that will be sent to MySQL server.\", e);\n            }\n        }\n        // 7 . (Null-Terminated String) databasename (optional)\n        if (getDatabaseName() != null) {\n            ByteHelper.writeNullTerminatedString(getDatabaseName(), out);\n        }\n        // 8 . (Null-Terminated String) auth plugin name (optional)\n        if (getAuthPluginName() != null) {\n            ByteHelper.writeNullTerminated(getAuthPluginName(), out);\n        }\n        // end write\n        return out.toByteArray();\n    }\n\n    public String getUsername() {\n        return username;\n    }\n\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    public void setCharsetNumber(byte charsetNumber) {\n        this.charsetNumber = charsetNumber;\n    }\n\n    public byte getCharsetNumber() {\n        return charsetNumber;\n    }\n\n    public void setDatabaseName(String databaseName) {\n        this.databaseName = databaseName;\n        if (databaseName != null) {\n            this.clientCapability |= Capability.CLIENT_CONNECT_WITH_DB;\n        }\n    }\n\n    public String getDatabaseName() {\n        return databaseName;\n    }\n\n    public void setServerCapabilities(int serverCapabilities) {\n        this.serverCapabilities = serverCapabilities;\n    }\n\n    public int getServerCapabilities() {\n        return serverCapabilities;\n    }\n\n    public void setScrumbleBuff(byte[] scrumbleBuff) {\n        this.scrumbleBuff = scrumbleBuff;\n    }\n\n    public byte[] getScrumbleBuff() {\n        return scrumbleBuff;\n    }\n\n    public byte[] getAuthPluginName() {\n        return authPluginName;\n    }\n\n    public void setAuthPluginName(byte[] authPluginName) {\n        this.authPluginName = authPluginName;\n        if (authPluginName != null) {\n            this.clientCapability |= Capability.CLIENT_PLUGIN_AUTH;\n        }\n    }\n\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/client/ClientAuthenticationSHA2Packet.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets.client;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\n\nimport org.apache.commons.lang.StringUtils;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.Capability;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.ByteHelper;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.MSC;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.MySQLPasswordEncrypter;\n\npublic class ClientAuthenticationSHA2Packet extends ClientAuthenticationPacket {\n\n    private int clientCapability = Capability.CLIENT_LONG_PASSWORD | Capability.CLIENT_LONG_FLAG\n                                   | Capability.CLIENT_PROTOCOL_41 | Capability.CLIENT_INTERACTIVE\n                                   | Capability.CLIENT_TRANSACTIONS | Capability.CLIENT_SECURE_CONNECTION\n                                   | Capability.CLIENT_MULTI_STATEMENTS | Capability.CLIENT_PLUGIN_AUTH\n                                   | Capability.CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA;\n\n    @Override\n    public byte[] toBytes() throws IOException {\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n        // 1. write client_flags\n        int capability = clientCapability;\n        if (getDatabaseName() != null) {\n            capability |= Capability.CLIENT_CONNECT_WITH_DB;\n        }\n        ByteHelper.writeUnsignedIntLittleEndian(capability, out);\n\n        // 2. write max_packet_size\n        ByteHelper.writeUnsignedIntLittleEndian(MSC.MAX_PACKET_LENGTH, out);\n        // 3. write charset_number\n        out.write(getCharsetNumber());\n        // 4. write (filler) always 0x00...\n        out.write(new byte[23]);\n        // 5. write (Null-Terminated String) user\n        ByteHelper.writeNullTerminatedString(getUsername(), out);\n        // 6. write (Length Coded Binary) scramble_buff (1 + x bytes)\n        if (StringUtils.isEmpty(getPassword())) {\n            out.write(0x00);\n        } else {\n            try {\n                byte[] encryptedPassword = MySQLPasswordEncrypter.scrambleCachingSha2(getPassword().getBytes(),\n                    getScrumbleBuff());\n                ByteHelper.writeBinaryCodedLengthBytes(encryptedPassword, out);\n            } catch (Exception e) {\n                throw new IOException(\"can't encrypt password that will be sent to MySQL server.\", e);\n            }\n        }\n        // 7 . (Null-Terminated String) databasename (optional)\n        if (getDatabaseName() != null) {\n            ByteHelper.writeNullTerminatedString(getDatabaseName(), out);\n        }\n        // 8 . (Null-Terminated String) auth plugin name (optional)\n        if (getAuthPluginName() != null) {\n            ByteHelper.writeNullTerminated(getAuthPluginName(), out);\n        }\n        // end write\n        return out.toByteArray();\n    }\n\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/client/QueryCommandPacket.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets.client;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.CommandPacket;\n\npublic class QueryCommandPacket extends CommandPacket {\n\n    private String queryString;\n\n    public QueryCommandPacket(){\n        setCommand((byte) 0x03);\n    }\n\n    public void fromBytes(byte[] data) throws IOException {\n    }\n\n    public byte[] toBytes() throws IOException {\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n        out.write(getCommand());\n        out.write(getQueryString().getBytes(\"UTF-8\"));// 链接建立时默认指定编码为UTF-8\n        return out.toByteArray();\n    }\n\n    public void setQueryString(String queryString) {\n        this.queryString = queryString;\n    }\n\n    public String getQueryString() {\n        return queryString;\n    }\n\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/client/QuitCommandPacket.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets.client;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.CommandPacket;\n\n/**\n * quit cmd\n * \n * @author agapple 2016年3月1日 下午8:33:02\n * @since 1.0.22\n */\npublic class QuitCommandPacket extends CommandPacket {\n\n    public QuitCommandPacket(){\n        setCommand((byte) 0x01);\n    }\n\n    @Override\n    public void fromBytes(byte[] data) throws IOException {\n\n    }\n\n    @Override\n    public byte[] toBytes() throws IOException {\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n        out.write(getCommand());\n        return out.toByteArray();\n    }\n\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/client/RegisterSlaveCommandPacket.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets.client;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.CommandPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.ByteHelper;\n\n/**\n * COM_REGISTER_SLAVE\n * \n * @author zhibinliu\n * @since 1.0.24\n */\npublic class RegisterSlaveCommandPacket extends CommandPacket {\n\n    public String reportHost;\n    public int    reportPort;\n    public String reportUser;\n    public String reportPasswd;\n    public long   serverId;\n\n    public RegisterSlaveCommandPacket(){\n        setCommand((byte) 0x15);\n    }\n\n    public void fromBytes(byte[] data) {\n        // bypass\n    }\n\n    public static byte[] toLH(int n) {\n        byte[] b = new byte[4];\n        b[0] = (byte) (n & 0xff);\n        b[1] = (byte) (n >> 8 & 0xff);\n        b[2] = (byte) (n >> 16 & 0xff);\n        b[3] = (byte) (n >> 24 & 0xff);\n        return b;\n    }\n\n    public byte[] toBytes() throws IOException {\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n        out.write(getCommand());\n        ByteHelper.writeUnsignedIntLittleEndian(serverId, out);\n        out.write((byte) reportHost.getBytes().length);\n        ByteHelper.writeFixedLengthBytesFromStart(reportHost.getBytes(), reportHost.getBytes().length, out);\n        out.write((byte) reportUser.getBytes().length);\n        ByteHelper.writeFixedLengthBytesFromStart(reportUser.getBytes(), reportUser.getBytes().length, out);\n        out.write((byte) reportPasswd.getBytes().length);\n        ByteHelper.writeFixedLengthBytesFromStart(reportPasswd.getBytes(), reportPasswd.getBytes().length, out);\n        ByteHelper.writeUnsignedShortLittleEndian(reportPort, out);\n        ByteHelper.writeUnsignedIntLittleEndian(0, out);// Fake\n                                                        // rpl_recovery_rank\n        ByteHelper.writeUnsignedIntLittleEndian(0, out);// master id\n        return out.toByteArray();\n    }\n\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/client/SemiAckCommandPacket.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets.client;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\n\nimport org.apache.commons.lang.StringUtils;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.CommandPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.ByteHelper;\n\n/**\n * semi ack command\n * \n * @author amos_chen\n */\npublic class SemiAckCommandPacket extends CommandPacket {\n\n    public long   binlogPosition;\n    public String binlogFileName;\n\n    public SemiAckCommandPacket(){\n\n    }\n\n    @Override\n    public void fromBytes(byte[] data) throws IOException {\n    }\n\n    /**\n     * <pre>\n     * Bytes                        Name\n     *  --------------------------------------------------------\n     *  Bytes                        Name\n     *  -----                        ----\n     *  1                            semi mark\n     *  8                            binlog position to start at (little endian)\n     *  n                            binlog file name\n     * \n     * </pre>\n     */\n    public byte[] toBytes() throws IOException {\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n        // 0 write semi mark\n        out.write(0xef);\n        // 1 write 8 bytes for position\n        ByteHelper.write8ByteUnsignedIntLittleEndian(binlogPosition, out);\n\n        // 2 write binlog filename\n        if (StringUtils.isNotEmpty(binlogFileName)) {\n            out.write(binlogFileName.getBytes());\n        }\n        return out.toByteArray();\n    }\n\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/client/SslRequestCommandPacket.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets.client;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.Capability;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.IPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.ByteHelper;\n\n/**\n * @author 枭博\n * @date 2024/05/14\n */\npublic class SslRequestCommandPacket implements IPacket {\n\n    private final int serverCharsetNumber;\n\n    public SslRequestCommandPacket(int serverCharsetNumber){\n        this.serverCharsetNumber = serverCharsetNumber;\n    }\n\n    @Override\n    public void fromBytes(byte[] data) throws IOException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public byte[] toBytes() throws IOException {\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n        int clientCapabilities = Capability.CLIENT_LONG_FLAG | Capability.CLIENT_PROTOCOL_41\n                                 | Capability.CLIENT_SECURE_CONNECTION | Capability.CLIENT_PLUGIN_AUTH\n                                 | Capability.CLIENT_SSL;\n        ByteHelper.writeUnsignedIntLittleEndian(clientCapabilities, out);\n        ByteHelper.writeUnsignedIntLittleEndian(0, out);\n        out.write(serverCharsetNumber);\n        for (int i = 0; i < 23; i++) {\n            out.write(0);\n        }\n        return out.toByteArray();\n    }\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/server/AuthSwitchRequestMoreData.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets.server;\n\nimport java.io.IOException;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.CommandPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.ByteHelper;\n\npublic class AuthSwitchRequestMoreData extends CommandPacket {\n\n    public int    status;\n    public byte[] authData;\n\n    public void fromBytes(byte[] data) {\n        int index = 0;\n        // 1. read status\n        status = data[index];\n        index += 1;\n        authData = ByteHelper.readNullTerminatedBytes(data, index);\n    }\n\n    public byte[] toBytes() throws IOException {\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/server/AuthSwitchRequestPacket.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets.server;\n\nimport java.io.IOException;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.CommandPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.ByteHelper;\n\npublic class AuthSwitchRequestPacket extends CommandPacket {\n\n    public int    status;\n    public String authName;\n    public byte[] authData;\n\n    public void fromBytes(byte[] data) {\n        int index = 0;\n        // 1. read status\n        status = data[index];\n        index += 1;\n        byte[] authName = ByteHelper.readNullTerminatedBytes(data, index);\n        this.authName = new String(authName);\n        index += authName.length + 1;\n        authData = ByteHelper.readNullTerminatedBytes(data, index);\n    }\n\n    public byte[] toBytes() throws IOException {\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/server/DataPacket.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets.server;\n\nimport java.io.IOException;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.CommandPacket;\n\npublic class DataPacket extends CommandPacket {\n\n    public void fromBytes(byte[] data) {\n\n    }\n\n    public byte[] toBytes() throws IOException {\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/server/EOFPacket.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets.server;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.PacketWithHeaderPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.ByteHelper;\n\npublic class EOFPacket extends PacketWithHeaderPacket {\n\n    public byte fieldCount;\n    public int  warningCount;\n    public int  statusFlag;\n\n    /**\n     * <pre>\n     *  VERSION 4.1\n     *  Bytes                 Name\n     *  -----                 ----\n     *  1                     field_count, always = 0xfe\n     *  2                     warning_count\n     *  2                     Status Flags\n     * </pre>\n     */\n    public void fromBytes(byte[] data) {\n        int index = 0;\n        // 1. read field count\n        fieldCount = data[index];\n        index++;\n        // 2. read warning count\n        this.warningCount = ByteHelper.readUnsignedShortLittleEndian(data, index);\n        index += 2;\n        // 3. read status flag\n        this.statusFlag = ByteHelper.readUnsignedShortLittleEndian(data, index);\n        // end read\n    }\n\n    public byte[] toBytes() throws IOException {\n        ByteArrayOutputStream out = new ByteArrayOutputStream(5);\n        out.write(this.fieldCount);\n        ByteHelper.writeUnsignedShortLittleEndian(this.warningCount, out);\n        ByteHelper.writeUnsignedShortLittleEndian(this.statusFlag, out);\n        return out.toByteArray();\n    }\n\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/server/ErrorPacket.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets.server;\n\nimport java.io.IOException;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.PacketWithHeaderPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.ByteHelper;\n\npublic class ErrorPacket extends PacketWithHeaderPacket {\n\n    public byte   fieldCount;\n    public int    errorNumber;\n    public byte   sqlStateMarker;\n    public byte[] sqlState;\n    public String message;\n\n    /**\n     * <pre>\n     * VERSION 4.1\n     *  Bytes                       Name\n     *  -----                       ----\n     *  1                           field_count, always = 0xff\n     *  2                           errno\n     *  1                           (sqlstate marker), always '#'\n     *  5                           sqlstate (5 characters)\n     *  n                           message\n     * \n     * </pre>\n     */\n    public void fromBytes(byte[] data) {\n        int index = 0;\n        // 1. read field count\n        this.fieldCount = data[0];\n        index++;\n        // 2. read error no.\n        this.errorNumber = ByteHelper.readUnsignedShortLittleEndian(data, index);\n        index += 2;\n        // 3. read marker\n        this.sqlStateMarker = data[index];\n        index++;\n        // 4. read sqlState\n        this.sqlState = ByteHelper.readFixedLengthBytes(data, index, 5);\n        index += 5;\n        // 5. read message\n        this.message = new String(ByteHelper.readFixedLengthBytes(data, index, data.length - index));\n        // end read\n    }\n\n    public byte[] toBytes() throws IOException {\n        return null;\n    }\n\n    @Override\n    public String toString() {\n        return \"ErrorPacket [errorNumber=\" + errorNumber + \", fieldCount=\" + fieldCount + \", message=\" + message\n               + \", sqlState=\" + sqlStateToString() + \", sqlStateMarker=\" + (char) sqlStateMarker + \"]\";\n    }\n\n    private String sqlStateToString() {\n        StringBuilder builder = new StringBuilder(5);\n        for (byte b : this.sqlState) {\n            builder.append((char) b);\n        }\n        return builder.toString();\n    }\n\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/server/FieldPacket.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets.server;\n\nimport java.io.IOException;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.PacketWithHeaderPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.ByteHelper;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.LengthCodedStringReader;\n\npublic class FieldPacket extends PacketWithHeaderPacket {\n\n    private String catalog;\n    private String db;\n    private String table;\n    private String originalTable;\n    private String name;\n    private String originalName;\n    private int    character;\n    private long   length;\n    private byte   type;\n    private int    flags;\n    private byte   decimals;\n    private String definition;\n\n    /**\n     * <pre>\n     *  VERSION 4.1\n     *  Bytes                      Name\n     *  -----                      ----\n     *  n (Length Coded String)    catalog\n     *  n (Length Coded String)    db\n     *  n (Length Coded String)    table\n     *  n (Length Coded String)    org_table\n     *  n (Length Coded String)    name\n     *  n (Length Coded String)    org_name\n     *  1                          (filler)\n     *  2                          charsetnr\n     *  4                          length\n     *  1                          type\n     *  2                          flags\n     *  1                          decimals\n     *  2                          (filler), always 0x00\n     *  n (Length Coded Binary)    default\n     * \n     * </pre>\n     */\n    public void fromBytes(byte[] data) throws IOException {\n\n        int index = 0;\n        LengthCodedStringReader reader = new LengthCodedStringReader(null, index);\n        // 1.\n        catalog = reader.readLengthCodedString(data);\n        // 2.\n        db = reader.readLengthCodedString(data);\n        this.table = reader.readLengthCodedString(data);\n        this.originalTable = reader.readLengthCodedString(data);\n        this.name = reader.readLengthCodedString(data);\n        this.originalName = reader.readLengthCodedString(data);\n        index = reader.getIndex();\n        //\n        index++;\n        //\n        this.character = ByteHelper.readUnsignedShortLittleEndian(data, index);\n        index += 2;\n        //\n        this.length = ByteHelper.readUnsignedIntLittleEndian(data, index);\n        index += 4;\n        //\n        this.type = data[index];\n        index++;\n        //\n        this.flags = ByteHelper.readUnsignedShortLittleEndian(data, index);\n        index += 2;\n        //\n        this.decimals = data[index];\n        index++;\n        //\n        index += 2;// skip filter\n        //\n        if (index < data.length) {\n            reader.setIndex(index);\n            this.definition = reader.readLengthCodedString(data);\n        }\n    }\n\n    public byte[] toBytes() throws IOException {\n        return null;\n    }\n\n    public String getCatalog() {\n        return catalog;\n    }\n\n    public void setCatalog(String catalog) {\n        this.catalog = catalog;\n    }\n\n    public String getDb() {\n        return db;\n    }\n\n    public void setDb(String db) {\n        this.db = db;\n    }\n\n    public String getTable() {\n        return table;\n    }\n\n    public void setTable(String table) {\n        this.table = table;\n    }\n\n    public String getOriginalTable() {\n        return originalTable;\n    }\n\n    public void setOriginalTable(String originalTable) {\n        this.originalTable = originalTable;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getOriginalName() {\n        return originalName;\n    }\n\n    public void setOriginalName(String originalName) {\n        this.originalName = originalName;\n    }\n\n    public int getCharacter() {\n        return character;\n    }\n\n    public void setCharacter(int character) {\n        this.character = character;\n    }\n\n    public long getLength() {\n        return length;\n    }\n\n    public void setLength(long length) {\n        this.length = length;\n    }\n\n    public byte getType() {\n        return type;\n    }\n\n    public void setType(byte type) {\n        this.type = type;\n    }\n\n    public int getFlags() {\n        return flags;\n    }\n\n    public void setFlags(int flags) {\n        this.flags = flags;\n    }\n\n    public byte getDecimals() {\n        return decimals;\n    }\n\n    public void setDecimals(byte decimals) {\n        this.decimals = decimals;\n    }\n\n    public String getDefinition() {\n        return definition;\n    }\n\n    public void setDefinition(String definition) {\n        this.definition = definition;\n    }\n\n    public String toString() {\n        return \"FieldPacket [catalog=\" + catalog + \", character=\" + character + \", db=\" + db + \", decimals=\" + decimals\n               + \", definition=\" + definition + \", flags=\" + flags + \", length=\" + length + \", name=\" + name\n               + \", originalName=\" + originalName + \", originalTable=\" + originalTable + \", table=\" + table + \", type=\"\n               + type + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/server/HandshakeInitializationPacket.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets.server;\n\nimport java.io.IOException;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.Capability;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.HeaderPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.PacketWithHeaderPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.ByteHelper;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.MSC;\n\n/**\n * MySQL Handshake Initialization Packet.<br>\n * \n * @author fujohnwang\n * @since 1.0\n */\npublic class HandshakeInitializationPacket extends PacketWithHeaderPacket {\n\n    public byte   protocolVersion = MSC.DEFAULT_PROTOCOL_VERSION;\n    public String serverVersion;\n    public long   threadId;\n    public byte[] seed;\n    public int    serverCapabilities;\n    public byte   serverCharsetNumber;\n    public int    serverStatus;\n    public byte[] restOfScrambleBuff;\n    public byte[] authPluginName;\n\n    public HandshakeInitializationPacket(){\n    }\n\n    public HandshakeInitializationPacket(HeaderPacket header){\n        super(header);\n    }\n\n    /**\n     * <pre>\n     * Bytes                        Name\n     *  -----                        ----\n     *  1                            protocol_version\n     *  n (Null-Terminated String)   server_version\n     *  4                            thread_id\n     *  8                            scramble_buff\n     *  1                            (filler) always 0x00\n     *  2                            server_capabilities\n     *  1                            server_language\n     *  2                            server_status\n     *  13                           (filler) always 0x00 ...\n     *  13                           rest of scramble_buff (4.1)\n     * </pre>\n     */\n    public void fromBytes(byte[] data) {\n        int index = 0;\n        // 1. read protocol_version\n        protocolVersion = data[index];\n        index++;\n        // 2. read server_version\n        byte[] serverVersionBytes = ByteHelper.readNullTerminatedBytes(data, index);\n        serverVersion = new String(serverVersionBytes);\n        index += (serverVersionBytes.length + 1);\n        // 3. read thread_id\n        threadId = ByteHelper.readUnsignedIntLittleEndian(data, index);\n        index += 4;\n        // 4. read scramble_buff\n        seed = ByteHelper.readFixedLengthBytes(data, index, 8);\n        index += 8;\n        index += 1; // 1 byte (filler) always 0x00\n        // 5. read server_capabilities\n        this.serverCapabilities = ByteHelper.readUnsignedShortLittleEndian(data, index);\n        index += 2;\n        if (data.length > index) {\n            // 6. read server_language\n            this.serverCharsetNumber = data[index];\n            index++;\n            // 7. read server_status\n            this.serverStatus = ByteHelper.readUnsignedShortLittleEndian(data, index);\n            index += 2;\n            // 8. bypass filtered bytes\n            int capabilityFlags2 = ByteHelper.readUnsignedShortLittleEndian(data, index);\n            index += 2;\n            int capabilities = (capabilityFlags2 << 16) | this.serverCapabilities;\n            // int authPluginDataLen = -1;\n            // if ((capabilities & Capability.CLIENT_PLUGIN_AUTH) != 0) {\n            // authPluginDataLen = data[index];\n            // }\n            index += 1;\n            index += 10;\n            // 9. read rest of scramble_buff\n            if ((capabilities & Capability.CLIENT_SECURE_CONNECTION) != 0) {\n                // int len = Math.max(13, authPluginDataLen - 8);\n                // this.authPluginDataPart2 =\n                // buffer.readFixedLengthString(len);// scramble2\n\n                // Packet规定最后13个byte是剩下的scrumble,\n                // 但实际上最后一个字节是0, 不应该包含在scrumble中.\n                this.restOfScrambleBuff = ByteHelper.readFixedLengthBytes(data, index, 12);\n            }\n\n            index += 12 + 1;\n            if ((capabilities & Capability.CLIENT_PLUGIN_AUTH) != 0) {\n                this.authPluginName = ByteHelper.readNullTerminatedBytes(data, index);\n            }\n            // end read\n        }\n    }\n\n    /**\n     * Bypass implementing it, 'cause nowhere to use it.\n     */\n    public byte[] toBytes() throws IOException {\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/server/OKPacket.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets.server;\n\nimport java.io.IOException;\nimport java.util.Arrays;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.PacketWithHeaderPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.ByteHelper;\n\n/**\n * Aka. OK packet\n * \n * @author fujohnwang\n */\npublic class OKPacket extends PacketWithHeaderPacket {\n\n    public byte   fieldCount;\n    public byte[] affectedRows;\n    public byte[] insertId;\n    public int    serverStatus;\n    public int    warningCount;\n    public String message;\n\n    /**\n     * <pre>\n     *  VERSION 4.1\n     *  Bytes                       Name\n     *  -----                       ----\n     *  1   (Length Coded Binary)   field_count, always = 0\n     *  1-9 (Length Coded Binary)   affected_rows\n     *  1-9 (Length Coded Binary)   insert_id\n     *  2                           server_status\n     *  2                           warning_count\n     *  n   (until end of packet)   message\n     * </pre>\n     * \n     * @throws IOException\n     */\n    public void fromBytes(byte[] data) throws IOException {\n        int index = 0;\n        // 1. read field count\n        this.fieldCount = data[0];\n        index++;\n        // 2. read affected rows\n        this.affectedRows = ByteHelper.readBinaryCodedLengthBytes(data, index);\n        index += this.affectedRows.length;\n        // 3. read insert id\n        this.insertId = ByteHelper.readBinaryCodedLengthBytes(data, index);\n        index += this.insertId.length;\n        // 4. read server status\n        this.serverStatus = ByteHelper.readUnsignedShortLittleEndian(data, index);\n        index += 2;\n        // 5. read warning count\n        this.warningCount = ByteHelper.readUnsignedShortLittleEndian(data, index);\n        index += 2;\n        // 6. read message.\n        this.message = new String(ByteHelper.readFixedLengthBytes(data, index, data.length - index));\n        // end read\n    }\n\n    public byte[] toBytes() throws IOException {\n        return null;\n    }\n\n    public byte getFieldCount() {\n        return fieldCount;\n    }\n\n    public void setFieldCount(byte fieldCount) {\n        this.fieldCount = fieldCount;\n    }\n\n    public byte[] getAffectedRows() {\n        return affectedRows;\n    }\n\n    public void setAffectedRows(byte[] affectedRows) {\n        this.affectedRows = affectedRows;\n    }\n\n    public byte[] getInsertId() {\n        return insertId;\n    }\n\n    public void setInsertId(byte[] insertId) {\n        this.insertId = insertId;\n    }\n\n    public int getServerStatus() {\n        return serverStatus;\n    }\n\n    public void setServerStatus(int serverStatus) {\n        this.serverStatus = serverStatus;\n    }\n\n    public int getWarningCount() {\n        return warningCount;\n    }\n\n    public void setWarningCount(int warningCount) {\n        this.warningCount = warningCount;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n\n    public String toString() {\n        return \"OKPacket [affectedRows=\" + Arrays.toString(affectedRows) + \", fieldCount=\" + fieldCount + \", insertId=\"\n               + Arrays.toString(insertId) + \", message=\" + message + \", serverStatus=\" + serverStatus\n               + \", warningCount=\" + warningCount + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/server/Reply323Packet.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets.server;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.PacketWithHeaderPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.ByteHelper;\n\npublic class Reply323Packet extends PacketWithHeaderPacket {\n\n    public byte[] seed;\n\n    public void fromBytes(byte[] data) throws IOException {\n\n    }\n\n    public byte[] toBytes() throws IOException {\n        if (seed == null) {\n            return new byte[] { (byte) 0 };\n        } else {\n            ByteArrayOutputStream out = new ByteArrayOutputStream();\n            ByteHelper.writeNullTerminated(seed, out);\n            return out.toByteArray();\n        }\n    }\n\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/server/ResultSetHeaderPacket.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets.server;\n\nimport java.io.IOException;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.PacketWithHeaderPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.ByteHelper;\n\n/**\n * <pre>\n * Type Of Result Packet       Hexadecimal Value Of First Byte (field_count)\n * ---------------------------------------------------------------------------\n * Result Set Packet           1-250 (first byte of Length-Coded Binary)\n * </pre>\n * \n * The sequence of result set packet:\n * \n * <pre>\n *   (Result Set Header Packet)  the number of columns\n *   (Field Packets)             column descriptors\n *   (EOF Packet)                marker: end of Field Packets\n *   (Row Data Packets)          row contents\n * (EOF Packet)                marker: end of Data Packets\n * \n * <pre>\n * \n * @author fujohnwang\n */\npublic class ResultSetHeaderPacket extends PacketWithHeaderPacket {\n\n    private long columnCount;\n    private long extra;\n\n    public void fromBytes(byte[] data) throws IOException {\n        int index = 0;\n        byte[] colCountBytes = ByteHelper.readBinaryCodedLengthBytes(data, index);\n        columnCount = ByteHelper.readLengthCodedBinary(colCountBytes, index);\n        index += colCountBytes.length;\n        if (index < data.length - 1) {\n            extra = ByteHelper.readLengthCodedBinary(data, index);\n        }\n    }\n\n    public byte[] toBytes() throws IOException {\n        return null;\n    }\n\n    public long getColumnCount() {\n        return columnCount;\n    }\n\n    public void setColumnCount(long columnCount) {\n        this.columnCount = columnCount;\n    }\n\n    public long getExtra() {\n        return extra;\n    }\n\n    public void setExtra(long extra) {\n        this.extra = extra;\n    }\n\n    public String toString() {\n        return \"ResultSetHeaderPacket [columnCount=\" + columnCount + \", extra=\" + extra + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/server/ResultSetPacket.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets.server;\n\nimport java.net.SocketAddress;\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class ResultSetPacket {\n\n    private SocketAddress     sourceAddress;\n    private List<FieldPacket> fieldDescriptors = new ArrayList<>();\n    private List<String>      fieldValues      = new ArrayList<>();\n\n    public void setFieldDescriptors(List<FieldPacket> fieldDescriptors) {\n        this.fieldDescriptors = fieldDescriptors;\n    }\n\n    public List<FieldPacket> getFieldDescriptors() {\n        return fieldDescriptors;\n    }\n\n    public void setFieldValues(List<String> fieldValues) {\n        this.fieldValues = fieldValues;\n    }\n\n    public List<String> getFieldValues() {\n        return fieldValues;\n    }\n\n    public void setSourceAddress(SocketAddress sourceAddress) {\n        this.sourceAddress = sourceAddress;\n    }\n\n    public SocketAddress getSourceAddress() {\n        return sourceAddress;\n    }\n\n    public String toString() {\n        return \"ResultSetPacket [fieldDescriptors=\" + fieldDescriptors + \", fieldValues=\" + fieldValues\n               + \", sourceAddress=\" + sourceAddress + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/server/RowDataPacket.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets.server;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.PacketWithHeaderPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.LengthCodedStringReader;\n\npublic class RowDataPacket extends PacketWithHeaderPacket {\n\n    private List<String> columns = new ArrayList<>();\n\n    public void fromBytes(byte[] data) throws IOException {\n        int index = 0;\n        LengthCodedStringReader reader = new LengthCodedStringReader(null, index);\n        do {\n            getColumns().add(reader.readLengthCodedString(data));\n        } while (reader.getIndex() < data.length);\n    }\n\n    public byte[] toBytes() throws IOException {\n        return null;\n    }\n\n    public void setColumns(List<String> columns) {\n        this.columns = columns;\n    }\n\n    public List<String> getColumns() {\n        return columns;\n    }\n\n    public String toString() {\n        return \"RowDataPacket [columns=\" + columns + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/socket/BioSocketChannel.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.socket;\n\nimport java.io.BufferedInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.Socket;\nimport java.net.SocketAddress;\nimport java.net.SocketException;\nimport java.net.SocketTimeoutException;\nimport java.nio.channels.ClosedByInterruptException;\n\nimport javax.net.ssl.SSLSocket;\n\n/**\n * 使用BIO进行dump\n *\n * @author chuanyi\n */\npublic class BioSocketChannel implements SocketChannel {\n\n    static final int      DEFAULT_CONNECT_TIMEOUT = 10 * 1000;\n    static final int      SO_TIMEOUT              = 1000;\n    private Socket        socket;\n    private InputStream   input;\n    private OutputStream  output;\n    private final boolean ssl;\n\n    BioSocketChannel(Socket socket) throws IOException{\n        this.socket = socket;\n        this.input = new BufferedInputStream(socket.getInputStream(), 16384);\n        this.output = socket.getOutputStream();\n        this.ssl = (socket instanceof SSLSocket);\n    }\n\n    public void write(byte[]... buf) throws IOException {\n        OutputStream output = this.output;\n        if (output != null) {\n            for (byte[] bs : buf) {\n                output.write(bs);\n            }\n        } else {\n            throw new SocketException(\"Socket already closed.\");\n        }\n    }\n\n    public byte[] read(int readSize) throws IOException {\n        InputStream input = this.input;\n        byte[] data = new byte[readSize];\n        int remain = readSize;\n        if (input == null) {\n            throw new SocketException(\"Socket already closed.\");\n        }\n        while (remain > 0) {\n            try {\n                int read = input.read(data, readSize - remain, remain);\n                if (read > -1) {\n                    remain -= read;\n                } else {\n                    throw new IOException(\"EOF encountered.\");\n                }\n            } catch (SocketTimeoutException te) {\n                if (Thread.interrupted()) {\n                    throw new ClosedByInterruptException();\n                }\n            }\n        }\n        return data;\n    }\n\n    public byte[] read(int readSize, int timeout) throws IOException {\n        InputStream input = this.input;\n        byte[] data = new byte[readSize];\n        int remain = readSize;\n        int accTimeout = 0;\n        if (input == null) {\n            throw new SocketException(\"Socket already closed.\");\n        }\n        while (remain > 0 && accTimeout < timeout) {\n            try {\n                int read = input.read(data, readSize - remain, remain);\n                if (read > -1) {\n                    remain -= read;\n                } else {\n                    throw new IOException(\"EOF encountered.\");\n                }\n            } catch (SocketTimeoutException te) {\n                if (Thread.interrupted()) {\n                    throw new ClosedByInterruptException();\n                }\n                accTimeout += SO_TIMEOUT;\n            }\n        }\n        if (remain > 0 && accTimeout >= timeout) {\n            throw new SocketTimeoutException(\n                \"Timeout occurred, failed to read total \" + readSize + \" bytes in \" + timeout\n                                             + \" milliseconds, actual read only \" + (readSize - remain) + \" bytes\");\n        }\n        return data;\n    }\n\n    @Override\n    public void read(byte[] data, int off, int len, int timeout) throws IOException {\n        InputStream input = this.input;\n        int accTimeout = 0;\n        if (input == null) {\n            throw new SocketException(\"Socket already closed.\");\n        }\n\n        int n = 0;\n        while (n < len && accTimeout < timeout) {\n            try {\n                int read = input.read(data, off + n, len - n);\n                if (read > -1) {\n                    n += read;\n                } else {\n                    throw new IOException(\"EOF encountered.\");\n                }\n            } catch (SocketTimeoutException te) {\n                if (Thread.interrupted()) {\n                    throw new ClosedByInterruptException();\n                }\n                accTimeout += SO_TIMEOUT;\n            }\n        }\n\n        if (n < len && accTimeout >= timeout) {\n            throw new SocketTimeoutException(\"Timeout occurred, failed to read total \" + len + \" bytes in \" + timeout\n                                             + \" milliseconds, actual read only \" + n + \" bytes\");\n        }\n    }\n\n    public boolean isConnected() {\n        Socket socket = this.socket;\n        if (socket != null) {\n            return socket.isConnected();\n        }\n        return false;\n    }\n\n    public boolean isSsl() {\n        return ssl;\n    }\n\n    public Socket getSocket() {\n        return socket;\n    }\n\n    public SocketAddress getRemoteSocketAddress() {\n        Socket socket = this.socket;\n        if (socket != null) {\n            return socket.getRemoteSocketAddress();\n        }\n\n        return null;\n    }\n\n    public SocketAddress getLocalSocketAddress() {\n        Socket socket = this.socket;\n        if (socket != null) {\n            return socket.getLocalSocketAddress();\n        }\n\n        return null;\n    }\n\n    public void close() {\n        Socket socket = this.socket;\n        if (socket != null) {\n            try {\n                socket.close();\n            } catch (IOException e) {\n                // Ignore, could not do anymore\n            }\n        }\n        this.input = null;\n        this.output = null;\n        this.socket = null;\n    }\n\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/socket/BioSocketChannelPool.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.socket;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.Socket;\nimport java.net.SocketAddress;\nimport java.net.URL;\nimport java.security.InvalidAlgorithmParameterException;\nimport java.security.KeyStore;\nimport java.security.cert.*;\nimport java.util.*;\nimport java.util.stream.Collectors;\n\nimport javax.naming.InvalidNameException;\nimport javax.naming.ldap.LdapName;\nimport javax.naming.ldap.Rdn;\nimport javax.net.ssl.*;\nimport javax.security.auth.x500.X500Principal;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.ssl.SslInfo;\nimport com.alibaba.otter.canal.parse.driver.mysql.ssl.SslMode;\n\n/**\n * @author luoyaogui 实现channel的管理（监听连接、读数据、回收） 2016-12-28\n * @author chuanyi 2018-3-3 保留<code>open</code>减少文件变更数量\n */\npublic abstract class BioSocketChannelPool {\n\n    private static final Logger logger = LoggerFactory.getLogger(BioSocketChannelPool.class);\n\n    public static BioSocketChannel open(SocketAddress address) throws Exception {\n        Socket socket = createSocket(address);\n        return new BioSocketChannel(socket);\n    }\n\n    public static BioSocketChannel openSsl(Socket socket, SslInfo sslInfo) throws Exception {\n        SslMode sslMode = sslInfo.getSslMode();\n        switch (sslMode) {\n            case REQUIRED:\n            case PREFERRED:\n            case VERIFY_CA:\n            case VERIFY_IDENTITY:\n                SSLSocket sslSocket = createSslSocket(socket, sslInfo);\n                return new BioSocketChannel(sslSocket);\n            default:\n                throw new UnsupportedOperationException(\"Unsupported ssl mode: \" + sslMode);\n        }\n    }\n\n    private static Socket createSocket(SocketAddress address) throws IOException {\n        Socket socket;\n        socket = new Socket();\n        socket.setSoTimeout(BioSocketChannel.SO_TIMEOUT);\n        socket.setTcpNoDelay(true);\n        socket.setKeepAlive(true);\n        socket.setReuseAddress(true);\n        socket.connect(address, BioSocketChannel.DEFAULT_CONNECT_TIMEOUT);\n        return socket;\n    }\n\n    /**\n     * from JDBC driver com.mysql.cj.protocol.ExportControlled#performTlsHandshake\n     * com.mysql.cj.protocol.ExportControlled#getSSLContext\n     *\n     * @param socket\n     * @param sslInfo\n     * @return\n     * @throws Exception\n     */\n    private static SSLSocket createSslSocket(Socket socket, SslInfo sslInfo) throws Exception {\n        SslMode sslMode = sslInfo.getSslMode();\n        boolean verifyServerCert = sslMode == SslMode.VERIFY_CA || sslMode == SslMode.VERIFY_IDENTITY;\n\n        String clientCertificateKeyStoreUrl = sslInfo.getClientCertificateKeyStoreUrl();\n        String clientCertificateKeyStoreType = sslInfo.getClientCertificateKeyStoreType() != null ? sslInfo\n            .getClientCertificateKeyStoreType() : \"JKS\";\n        String clientCertificateKeyStorePassword = sslInfo.getClientCertificateKeyStorePassword();\n        String trustCertificateKeyStoreUrl = sslInfo.getTrustCertificateKeyStoreUrl();\n        String trustCertificateKeyStoreType = sslInfo.getTrustCertificateKeyStoreType() != null ? sslInfo\n            .getTrustCertificateKeyStoreType() : \"JKS\";\n        String trustCertificateKeyStorePassword = sslInfo.getTrustCertificateKeyStorePassword();\n        boolean fallbackToDefaultTrustStore = true;\n        String hostName = sslMode == SslMode.VERIFY_IDENTITY ? socket.getInetAddress().getHostName() : null;\n\n        SSLContext sslContext = getSSLContext(clientCertificateKeyStoreUrl,\n            clientCertificateKeyStoreType,\n            clientCertificateKeyStorePassword,\n            trustCertificateKeyStoreUrl,\n            trustCertificateKeyStoreType,\n            trustCertificateKeyStorePassword,\n            fallbackToDefaultTrustStore,\n            verifyServerCert,\n            hostName);\n        SSLSocketFactory socketFactory = sslContext.getSocketFactory();\n\n        SSLSocket sslSocket = (SSLSocket) socketFactory\n            .createSocket(socket, socket.getInetAddress().getHostName(), socket.getPort(), true);\n\n        String[] protocolArr = null;\n        if (StringUtils.isNotEmpty(sslInfo.getTlsVersions())) {\n            protocolArr = StringUtils.split(sslInfo.getTlsVersions(), \",\");\n        }\n        if (protocolArr == null || protocolArr.length == 0) {\n            protocolArr = new String[] { \"TLSv1.2\", \"TLSv1.3\" };\n        }\n        logger.info(\"SSL protocol: {}\", StringUtils.join(protocolArr, \",\"));\n        sslSocket.setEnabledProtocols(protocolArr);\n        sslSocket.setSoTimeout(BioSocketChannel.SO_TIMEOUT);\n        sslSocket.startHandshake();\n        logger.info(\"SSL socket handshake success.\");\n        return sslSocket;\n    }\n\n    private static SSLContext getSSLContext(String clientCertificateKeyStoreUrl, String clientCertificateKeyStoreType,\n                                            String clientCertificateKeyStorePassword,\n                                            String trustCertificateKeyStoreUrl, String trustCertificateKeyStoreType,\n                                            String trustCertificateKeyStorePassword,\n                                            boolean fallbackToDefaultTrustStore, boolean verifyServerCert,\n                                            String hostName) throws Exception {\n\n        KeyManager[] kms = null;\n        List<TrustManager> tms = new ArrayList<>();\n\n        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());\n        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());\n\n        if (StringUtils.isNotEmpty(clientCertificateKeyStoreUrl)) {\n            InputStream ksIS = null;\n            try {\n                if (StringUtils.isNotEmpty(clientCertificateKeyStoreType)) {\n                    KeyStore clientKeyStore = KeyStore.getInstance(clientCertificateKeyStoreType);\n                    URL ksURL = new URL(clientCertificateKeyStoreUrl);\n                    char[] password = (clientCertificateKeyStorePassword == null) ? new char[0] : clientCertificateKeyStorePassword\n                        .toCharArray();\n                    ksIS = ksURL.openStream();\n                    clientKeyStore.load(ksIS, password);\n                    kmf.init(clientKeyStore, password);\n                    kms = kmf.getKeyManagers();\n                }\n            } finally {\n                if (ksIS != null) {\n                    try {\n                        ksIS.close();\n                    } catch (IOException e) {\n                        // can't close input stream, but keystore can be properly initialized so we\n                        // shouldn't throw this exception\n                    }\n                }\n            }\n        }\n\n        InputStream trustStoreIS = null;\n        try {\n            String trustStoreType = \"\";\n            char[] trustStorePassword = null;\n            KeyStore trustKeyStore = null;\n\n            if (StringUtils.isNotEmpty(trustCertificateKeyStoreUrl)\n                && StringUtils.isNotEmpty(trustCertificateKeyStoreType)) {\n                trustStoreType = trustCertificateKeyStoreType;\n                trustStorePassword = (trustCertificateKeyStorePassword == null) ? new char[0] : trustCertificateKeyStorePassword\n                    .toCharArray();\n                trustStoreIS = new URL(trustCertificateKeyStoreUrl).openStream();\n\n                trustKeyStore = KeyStore.getInstance(trustStoreType);\n                trustKeyStore.load(trustStoreIS, trustStorePassword);\n            }\n\n            if (trustKeyStore != null || fallbackToDefaultTrustStore) {\n                tmf.init(trustKeyStore);\n                // (trustKeyStore == null) initializes the TrustManagerFactory with the default\n                // truststore.\n\n                // building the customized list of TrustManagers from original one if it's\n                // available\n                TrustManager[] origTms = tmf.getTrustManagers();\n\n                for (TrustManager tm : origTms) {\n                    // wrap X509TrustManager or put original if non-X509 TrustManager\n                    tms.add(tm instanceof X509TrustManager ? new X509TrustManagerWrapper((X509TrustManager) tm,\n                        verifyServerCert,\n                        hostName) : tm);\n                }\n            }\n\n        } finally {\n            if (trustStoreIS != null) {\n                try {\n                    trustStoreIS.close();\n                } catch (IOException e) {\n                    // can't close input stream, but keystore can be properly initialized so we\n                    // shouldn't throw this exception\n                }\n            }\n        }\n\n        // if original TrustManagers are not available then putting one\n        // X509TrustManagerWrapper which take care only\n        // about expiration check\n        if (tms.size() == 0) {\n            tms.add(new X509TrustManagerWrapper(verifyServerCert, hostName));\n        }\n\n        SSLContext sslContext = SSLContext.getInstance(\"TLS\");\n        sslContext.init(kms, tms.toArray(new TrustManager[tms.size()]), null);\n        return sslContext;\n    }\n\n    public static class X509TrustManagerWrapper implements X509TrustManager {\n\n        private X509TrustManager   origTm           = null;\n        private boolean            verifyServerCert = false;\n        private String             hostName         = null;\n        private CertificateFactory certFactory      = null;\n        private PKIXParameters     validatorParams  = null;\n        private CertPathValidator  validator        = null;\n\n        public X509TrustManagerWrapper(X509TrustManager tm, boolean verifyServerCertificate,\n                                       String hostName) throws CertificateException{\n            this.origTm = tm;\n            this.verifyServerCert = verifyServerCertificate;\n            this.hostName = hostName;\n\n            if (verifyServerCertificate) {\n                try {\n                    Set<TrustAnchor> anch = Arrays.stream(tm.getAcceptedIssuers())\n                        .map(c -> new TrustAnchor(c, null))\n                        .collect(Collectors.toSet());\n                    this.validatorParams = new PKIXParameters(anch);\n                    this.validatorParams.setRevocationEnabled(false);\n                    this.validator = CertPathValidator.getInstance(\"PKIX\");\n                    this.certFactory = CertificateFactory.getInstance(\"X.509\");\n                } catch (Exception e) {\n                    throw new CertificateException(e);\n                }\n            }\n\n        }\n\n        public X509TrustManagerWrapper(boolean verifyServerCertificate, String hostName){\n            this.verifyServerCert = verifyServerCertificate;\n            this.hostName = hostName;\n        }\n\n        public X509Certificate[] getAcceptedIssuers() {\n            return this.origTm != null ? this.origTm.getAcceptedIssuers() : new X509Certificate[0];\n        }\n\n        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {\n            for (int i = 0; i < chain.length; i++) {\n                chain[i].checkValidity();\n            }\n\n            if (this.validatorParams != null) {\n                X509CertSelector certSelect = new X509CertSelector();\n                certSelect.setSerialNumber(chain[0].getSerialNumber());\n\n                try {\n                    CertPath certPath = this.certFactory.generateCertPath(Arrays.asList(chain));\n                    // Validate against truststore\n                    CertPathValidatorResult result = this.validator.validate(certPath, this.validatorParams);\n                    // Check expiration for the CA used to validate this path\n                    ((PKIXCertPathValidatorResult) result).getTrustAnchor().getTrustedCert().checkValidity();\n\n                } catch (InvalidAlgorithmParameterException e) {\n                    throw new CertificateException(e);\n                } catch (CertPathValidatorException e) {\n                    throw new CertificateException(e);\n                }\n            }\n\n            if (this.verifyServerCert) {\n                if (this.origTm != null) {\n                    this.origTm.checkServerTrusted(chain, authType);\n                } else {\n                    throw new CertificateException(\n                        \"Can't verify server certificate because no trust manager is found.\");\n                }\n\n                // verify server certificate identity\n                if (this.hostName != null) {\n                    logger.info(\"verify hostName: {}\", this.hostName);\n                    Set<String> expectHostNames = new HashSet<>();\n                    for (X509Certificate certificate : chain) {\n                        String dn = certificate.getSubjectX500Principal().getName(X500Principal.RFC2253);\n                        String cn = null;\n                        try {\n                            LdapName ldapDN = new LdapName(dn);\n                            for (Rdn rdn : ldapDN.getRdns()) {\n                                if (rdn.getType().equalsIgnoreCase(\"CN\")) {\n                                    cn = rdn.getValue().toString();\n                                    break;\n                                }\n                            }\n                        } catch (InvalidNameException e) {\n                            throw new CertificateException(\n                                \"Failed to retrieve the Common Name (CN) from the server certificate.\");\n                        }\n                        expectHostNames.add(cn);\n                    }\n\n                    if (!expectHostNames.contains(this.hostName)) {\n                        throw new CertificateException(\n                            \"Server certificate identity check failed. The certificate Common Name \"\n                                                       + expectHostNames.stream()\n                                                           .map(h -> \"'\" + h + \"'\")\n                                                           .collect(Collectors.joining(\", \"))\n                                                       + \" does not match with '\" + this.hostName + \"'.\");\n                    }\n\n                }\n            }\n        }\n\n        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {\n            this.origTm.checkClientTrusted(chain, authType);\n        }\n    }\n\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/socket/NettySocketChannel.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.socket;\r\n\r\nimport io.netty.buffer.ByteBuf;\r\nimport io.netty.buffer.PooledByteBufAllocator;\r\nimport io.netty.buffer.Unpooled;\r\nimport io.netty.channel.Channel;\r\nimport io.netty.util.internal.OutOfDirectMemoryError;\r\nimport io.netty.util.internal.PlatformDependent;\r\nimport io.netty.util.internal.SystemPropertyUtil;\r\n\r\nimport java.io.IOException;\r\nimport java.net.SocketAddress;\r\n\r\nimport org.apache.commons.lang.NotImplementedException;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\n\r\n/**\r\n * 封装netty的通信channel和数据接收缓存，实现读、写、连接校验的功能。 2016-12-28\r\n * \r\n * @author luoyaogui\r\n */\r\npublic class NettySocketChannel implements SocketChannel {\r\n\r\n    private static final Logger logger                   = LoggerFactory.getLogger(SocketChannel.class);\r\n    private static final int    WAIT_PERIOD              = 10;                                                                   // milliseconds\r\n    private static final int    DEFAULT_INIT_BUFFER_SIZE = 1024 * 1024;                                                          // 1MB，默认初始缓存大小\r\n    // 参考 mysql-connector-java-5.1.40.jar: com.mysql.jdbc.MysqlIO.maxThreeBytes\r\n    // < 256 * 256 * 256 = 16MB\r\n    private static final int    DEFAULT_MAX_BUFFER_SIZE  = 16 * DEFAULT_INIT_BUFFER_SIZE;                                        // 16MB，默认最大缓存大小\r\n    private Channel             channel                  = null;\r\n    private Object              lock                     = new Object();\r\n    private ByteBuf             cache                    = PooledByteBufAllocator.DEFAULT.directBuffer(DEFAULT_INIT_BUFFER_SIZE); // 缓存大小\r\n    private int                 maxDirectBuffer          = cache.maxCapacity();\r\n\r\n    public Channel getChannel() {\r\n        return channel;\r\n    }\r\n\r\n    public void setChannel(Channel channel) {\r\n        this.channel = channel;\r\n    }\r\n\r\n    public void writeCache(ByteBuf buf) throws InterruptedException, IOException {\r\n        synchronized (lock) {\r\n            while (true) {\r\n                if (null == cache) {\r\n                    throw new IOException(\"socket is closed !\");\r\n                }\r\n\r\n                // source buffer is empty.\r\n                if (!buf.isReadable()) {\r\n                    break;\r\n                }\r\n\r\n                // 默认缓存大小不够用时需自动清理或扩充，否则将因缓存空间不足而造成I/O超时假象\r\n                int length = buf.readableBytes();\r\n                int deltaSize = length - cache.writableBytes();\r\n                if (deltaSize > 0) {\r\n                    // 首先避免频繁分配内存（扩容/收缩），其次避免频繁移动内存（清理）\r\n                    if (cache.readerIndex() >= deltaSize) { // 可以清理\r\n                        // 回收已读空间，重置读写指针\r\n                        cache.discardReadBytes();\r\n                        // 恢复自动扩充的过大缓存到默认初始缓存大小，释放空间\r\n                        int oldCapacity = cache.capacity();\r\n                        if (oldCapacity > DEFAULT_MAX_BUFFER_SIZE) { // 尝试收缩\r\n                            int newCapacity = cache.writerIndex();\r\n                            newCapacity = ((newCapacity - 1) / DEFAULT_INIT_BUFFER_SIZE + 1) * DEFAULT_INIT_BUFFER_SIZE; // 对齐\r\n                            int quarter = (newCapacity >> 2); // 至少留空四分之一\r\n                            quarter = ((quarter - 1) / DEFAULT_INIT_BUFFER_SIZE + 1) * DEFAULT_INIT_BUFFER_SIZE; // 对齐\r\n                            newCapacity += quarter; // 留空四分之一\r\n                            if (newCapacity < (oldCapacity >> 1)) { // 至少收缩二分之一\r\n                                try {\r\n                                    cache.capacity(newCapacity);\r\n                                    logger.info(\"shrink cache capacity: {} - {} = {} bytes\",\r\n                                        oldCapacity,\r\n                                        oldCapacity - newCapacity,\r\n                                        newCapacity);\r\n                                } catch (OutOfMemoryError ignore) {\r\n                                    maxDirectBuffer = oldCapacity; // 未来不再超过当前容量，记录日志后继续\r\n                                    logger.warn(\"cache OutOfMemoryError: {} bytes\", newCapacity, ignore);\r\n                                }\r\n                            }\r\n                        }\r\n                    } else { // 尝试扩容\r\n                        int oldCapacity = cache.capacity();\r\n                        if (oldCapacity < maxDirectBuffer) {\r\n                            int quarter = (oldCapacity >> 2); // 至少扩容四分之一\r\n                            quarter = ((quarter - 1) / DEFAULT_INIT_BUFFER_SIZE + 1) * DEFAULT_INIT_BUFFER_SIZE; // 对齐\r\n                            deltaSize = ((deltaSize - 1) / quarter + 1) * quarter; // 对齐\r\n                            int newCapacity = oldCapacity + deltaSize;\r\n                            if (newCapacity > maxDirectBuffer) {\r\n                                newCapacity = maxDirectBuffer;\r\n                            }\r\n                            try {\r\n                                cache.capacity(newCapacity);\r\n                                logger.info(\"expand cache capacity: {} + {} = {} bytes\",\r\n                                    oldCapacity,\r\n                                    newCapacity - oldCapacity,\r\n                                    newCapacity);\r\n                            } catch (OutOfDirectMemoryError e) {\r\n                                // failed to allocate 885571168 byte(s) of\r\n                                // direct memory (used: 1002946176, max:\r\n                                // 1888485376)\r\n                                long maxDirectMemory = SystemPropertyUtil.getLong(\"io.netty.maxDirectMemory\", -1);\r\n                                if (maxDirectMemory < 0) {\r\n                                    maxDirectMemory = PlatformDependent.maxDirectMemory();\r\n                                }\r\n                                if (maxDirectBuffer > maxDirectMemory) {\r\n                                    maxDirectBuffer = (int) maxDirectMemory;\r\n                                    newCapacity = maxDirectBuffer;\r\n                                    logger.warn(\"resize maxDirectBuffer: {} bytes\", maxDirectBuffer, e);\r\n                                    try {\r\n                                        cache.capacity(newCapacity);\r\n                                        logger.info(\"expand cache capacity: {} + {} = {} bytes\",\r\n                                            oldCapacity,\r\n                                            newCapacity - oldCapacity,\r\n                                            newCapacity);\r\n                                    } catch (OutOfMemoryError ignore) {\r\n                                        maxDirectBuffer = oldCapacity; // 未来不再超过当前容量，记录日志后继续\r\n                                        logger.warn(\"cache OutOfMemoryError: {} bytes\", newCapacity, ignore);\r\n                                    }\r\n                                } else {\r\n                                    maxDirectBuffer = oldCapacity; // 未来不再超过当前容量，记录日志后继续\r\n                                    logger.warn(\"cache OutOfDirectMemoryError: {} bytes\", newCapacity, e);\r\n                                }\r\n                            } catch (OutOfMemoryError ignore) {\r\n                                maxDirectBuffer = oldCapacity; // 未来不再超过当前容量，记录日志后继续\r\n                                logger.warn(\"cache OutOfMemoryError: {} bytes\", newCapacity, ignore);\r\n                            }\r\n                        }\r\n                    }\r\n                    deltaSize = length - cache.writableBytes();\r\n                }\r\n\r\n                if (deltaSize != length) {\r\n                    // deltaSize <= 0 可全部写入，deltaSize > 0 只能部分写入\r\n                    if (deltaSize <= 0) {\r\n                        cache.writeBytes(buf, length);\r\n                        break;\r\n                    } else {\r\n                        cache.writeBytes(buf, length - deltaSize);\r\n                    }\r\n                }\r\n                // dest buffer is full.\r\n                lock.wait(WAIT_PERIOD);\r\n                // 回收已读空间，重置读写指针\r\n                cache.discardReadBytes();\r\n            }\r\n        }\r\n    }\r\n\r\n    public void write(byte[]... buf) throws IOException {\r\n        if (channel != null && channel.isWritable()) {\r\n            channel.writeAndFlush(Unpooled.copiedBuffer(buf));\r\n        } else {\r\n            throw new IOException(\"write failed ! please checking !\");\r\n        }\r\n    }\r\n\r\n    public byte[] read(int readSize) throws IOException {\r\n        return read(readSize, 0);\r\n    }\r\n\r\n    public byte[] read(int readSize, int timeout) throws IOException {\r\n        int accumulatedWaitTime = 0;\r\n\r\n        // 若读取内容较长，则自动扩充超时时间，以初始缓存大小为基准计算倍数\r\n        if (timeout > 0 && readSize > DEFAULT_INIT_BUFFER_SIZE) {\r\n            timeout *= (readSize / DEFAULT_INIT_BUFFER_SIZE + 1);\r\n        }\r\n        do {\r\n            if (readSize > cache.readableBytes()) {\r\n                if (null == channel) {\r\n                    throw new IOException(\"socket has Interrupted !\");\r\n                }\r\n\r\n                if (timeout > 0) {\r\n                    accumulatedWaitTime += WAIT_PERIOD;\r\n                    if (accumulatedWaitTime > timeout) {\r\n                        StringBuilder sb = new StringBuilder(\"socket read timeout occured !\");\r\n                        sb.append(\" readSize = \").append(readSize);\r\n                        sb.append(\", readableBytes = \").append(cache.readableBytes());\r\n                        sb.append(\", timeout = \").append(timeout);\r\n                        throw new IOException(sb.toString());\r\n                    }\r\n                }\r\n\r\n                synchronized (this) {\r\n                    try {\r\n                        wait(WAIT_PERIOD);\r\n                    } catch (InterruptedException e) {\r\n                        throw new IOException(\"socket has Interrupted !\");\r\n                    }\r\n                }\r\n            } else {\r\n                byte[] back = new byte[readSize];\r\n                synchronized (lock) {\r\n                    cache.readBytes(back);\r\n                }\r\n                return back;\r\n            }\r\n        } while (true);\r\n    }\r\n\r\n    @Override\r\n    public void read(byte[] data, int off, int len, int timeout) throws IOException {\r\n        throw new NotImplementedException();\r\n    }\r\n\r\n    public boolean isConnected() {\r\n        return channel != null ? true : false;\r\n    }\r\n\r\n    public SocketAddress getRemoteSocketAddress() {\r\n        return channel != null ? channel.remoteAddress() : null;\r\n    }\r\n\r\n    public SocketAddress getLocalSocketAddress() {\r\n        return channel != null ? channel.localAddress() : null;\r\n    }\r\n\r\n    public void close() {\r\n        if (channel != null) {\r\n            channel.close();\r\n        }\r\n        channel = null;\r\n        // A fatal error has been detected by the Java Runtime Environment:\r\n        // EXCEPTION_ACCESS_VIOLATION (0xc0000005)\r\n        synchronized (lock) {\r\n            cache.discardReadBytes();// 回收已占用的内存\r\n            cache.release();// 释放整个内存\r\n            cache = null;\r\n        }\r\n    }\r\n\r\n\r\n}\r\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/socket/NettySocketChannelPool.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.socket;\r\n\r\nimport io.netty.bootstrap.Bootstrap;\r\nimport io.netty.buffer.ByteBuf;\r\nimport io.netty.buffer.PooledByteBufAllocator;\r\nimport io.netty.channel.AdaptiveRecvByteBufAllocator;\r\nimport io.netty.channel.Channel;\r\nimport io.netty.channel.ChannelFuture;\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelOption;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.SimpleChannelInboundHandler;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.nio.NioSocketChannel;\r\n\r\nimport java.io.IOException;\r\nimport java.net.SocketAddress;\r\nimport java.util.Map;\r\nimport java.util.concurrent.ConcurrentHashMap;\r\nimport java.util.concurrent.CountDownLatch;\r\n\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\n\r\n/**\r\n * @author luoyaogui 实现channel的管理（监听连接、读数据、回收） 2016-12-28\r\n */\r\n@SuppressWarnings({ \"rawtypes\", \"deprecation\" })\r\npublic abstract class NettySocketChannelPool {\r\n\r\n    private static EventLoopGroup              group     = new NioEventLoopGroup();                              // 非阻塞IO线程组\r\n    private static Bootstrap                   boot      = new Bootstrap();                                      // 主\r\n    private static Map<Channel, SocketChannel> chManager = new ConcurrentHashMap<>();\r\n    private static final Logger                logger    = LoggerFactory.getLogger(NettySocketChannelPool.class);\r\n\r\n    static {\r\n        boot.group(group)\r\n            .channel(NioSocketChannel.class)\r\n            .option(ChannelOption.TCP_NODELAY, true)\r\n            // 如果是延时敏感型应用，建议关闭Nagle算法\r\n            .option(ChannelOption.SO_KEEPALIVE, true)\r\n            .option(ChannelOption.SO_REUSEADDR, true)\r\n            .option(ChannelOption.RCVBUF_ALLOCATOR, AdaptiveRecvByteBufAllocator.DEFAULT)\r\n            .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)\r\n            //\r\n            .handler(new ChannelInitializer() {\r\n\r\n                @Override\r\n                protected void initChannel(Channel ch) throws Exception {\r\n                    ch.pipeline().addLast(new BusinessHandler());// 命令过滤和handler添加管理\r\n                }\r\n            });\r\n    }\r\n\r\n    public static SocketChannel open(SocketAddress address) throws Exception {\r\n        SocketChannel socket = null;\r\n        ChannelFuture future = boot.connect(address).sync();\r\n\r\n        if (future.isSuccess()) {\r\n            future.channel().pipeline().get(BusinessHandler.class).latch.await();\r\n            socket = chManager.get(future.channel());\r\n        }\r\n\r\n        if (null == socket) {\r\n            throw new IOException(\"can't create socket!\");\r\n        }\r\n\r\n        return socket;\r\n    }\r\n\r\n    public static class BusinessHandler extends SimpleChannelInboundHandler<ByteBuf> {\r\n\r\n        private NettySocketChannel   socket = null;\r\n        private final CountDownLatch latch  = new CountDownLatch(1);\r\n\r\n        @Override\r\n        public void channelInactive(ChannelHandlerContext ctx) throws Exception {\r\n            socket.setChannel(null);\r\n            chManager.remove(ctx.channel());// 移除\r\n            super.channelInactive(ctx);\r\n        }\r\n\r\n        @Override\r\n        public void channelActive(ChannelHandlerContext ctx) throws Exception {\r\n            socket = new NettySocketChannel();\r\n            socket.setChannel(ctx.channel());\r\n            chManager.put(ctx.channel(), socket);\r\n            latch.countDown();\r\n            super.channelActive(ctx);\r\n        }\r\n\r\n        @Override\r\n        protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {\r\n            if (socket != null) {\r\n                socket.writeCache(msg);\r\n            } else {\r\n                // TODO: need graceful error handler.\r\n                logger.error(\"no socket available.\");\r\n            }\r\n        }\r\n\r\n        @Override\r\n        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {\r\n            // need output error for troubeshooting.\r\n            logger.error(\"business error.\", cause);\r\n            ctx.close();\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/socket/SocketChannel.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.socket;\r\n\r\nimport java.io.IOException;\r\nimport java.net.SocketAddress;\r\n\r\n/**\r\n * @author agapple 2018年3月12日 下午10:36:44\r\n * @since 1.0.26\r\n */\r\npublic interface SocketChannel {\r\n\r\n    public void write(byte[]... buf) throws IOException;\r\n\r\n    public byte[] read(int readSize) throws IOException;\r\n\r\n    public byte[] read(int readSize, int timeout) throws IOException;\r\n\r\n    public void read(byte[] data, int off, int len, int timeout) throws IOException;\r\n\r\n    public boolean isConnected();\r\n\r\n    public SocketAddress getRemoteSocketAddress();\r\n\r\n    public SocketAddress getLocalSocketAddress();\r\n\r\n    public void close();\r\n}\r\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/socket/SocketChannelPool.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.socket;\n\nimport java.io.IOException;\nimport java.net.SocketAddress;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.ssl.SslInfo;\nimport com.alibaba.otter.canal.parse.driver.mysql.ssl.SslMode;\n\n/**\n * @author agapple 2018年3月12日 下午10:46:22\n * @since 1.0.26\n */\npublic abstract class SocketChannelPool {\n\n    private static final Logger logger = LoggerFactory.getLogger(SocketChannelPool.class);\n\n    public static SocketChannel open(SocketAddress address) throws Exception {\n        String type = chooseSocketChannel();\n        if (\"netty\".equalsIgnoreCase(type)) {\n            return NettySocketChannelPool.open(address);\n        } else {\n            return BioSocketChannelPool.open(address);\n        }\n    }\n\n    public static SocketChannel connectSsl(SocketChannel channel, SslInfo sslInfo) throws IOException {\n        SslMode sslMode = sslInfo.getSslMode();\n        String type = chooseSocketChannel();\n        if (\"netty\".equalsIgnoreCase(type)) {\n            throw new UnsupportedOperationException(\"canal socketChannel netty not support ssl mode: \" + sslMode);\n        } else {\n            SocketAddress remoteSocketAddress = channel.getRemoteSocketAddress();\n            try {\n                return BioSocketChannelPool.openSsl(((BioSocketChannel) channel).getSocket(), sslInfo);\n            } catch (Exception e) {\n                if (sslMode == SslMode.PREFERRED) {\n                    // still use non ssl channel\n                    logger.info(\"{} still use non SSL channel due to SSL connect failed.\", remoteSocketAddress, e);\n                    return channel;\n                }\n                IOException ioe;\n                if (e instanceof IOException) {\n                    ioe = (IOException) e;\n                } else {\n                    ioe = new IOException(e);\n                }\n                throw ioe;\n            }\n        }\n    }\n\n    private static String chooseSocketChannel() {\n        String socketChannel = System.getenv(\"canal.socketChannel\");\n        if (StringUtils.isEmpty(socketChannel)) {\n            socketChannel = System.getProperty(\"canal.socketChannel\");\n        }\n\n        if (StringUtils.isEmpty(socketChannel)) {\n            socketChannel = \"bio\"; // bio or netty\n        }\n\n        return socketChannel;\n    }\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/ssl/SslInfo.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.ssl;\n\n/**\n * @author 枭博\n * @date 2024/05/14\n */\npublic class SslInfo {\n\n    private SslMode sslMode = SslMode.DISABLED;\n    private String  tlsVersions;                       // 和 enabledTLSProtocols 同含义，TLSv1.2,TLSv1.3\n    private String  trustCertificateKeyStoreType;      // trustStore 证书类型，支持 JKS (默认) 和 PKCS12\n    private String  trustCertificateKeyStoreUrl;       // trustStore 证书\n    private String  trustCertificateKeyStorePassword;  // trustStore 证书密码\n    private String  clientCertificateKeyStoreType;     // client 证书类型，支持 JKS (默认) 和 PKCS12\n    private String  clientCertificateKeyStoreUrl;      // client 证书\n    private String  clientCertificateKeyStorePassword; // client 证书密码\n\n    public SslInfo(SslMode sslMode, String tlsVersions, String trustCertificateKeyStoreType,\n                   String trustCertificateKeyStoreUrl, String trustCertificateKeyStorePassword,\n                   String clientCertificateKeyStoreType, String clientCertificateKeyStoreUrl,\n                   String clientCertificateKeyStorePassword) {\n        this.sslMode = sslMode;\n        this.tlsVersions = tlsVersions;\n        this.trustCertificateKeyStoreType = trustCertificateKeyStoreType;\n        this.trustCertificateKeyStoreUrl = trustCertificateKeyStoreUrl;\n        this.trustCertificateKeyStorePassword = trustCertificateKeyStorePassword;\n        this.clientCertificateKeyStoreType = clientCertificateKeyStoreType;\n        this.clientCertificateKeyStoreUrl = clientCertificateKeyStoreUrl;\n        this.clientCertificateKeyStorePassword = clientCertificateKeyStorePassword;\n    }\n\n    public SslInfo() {\n    }\n\n    public SslMode getSslMode() {\n        return sslMode;\n    }\n\n    public void setSslMode(SslMode sslMode) {\n        this.sslMode = sslMode;\n    }\n\n    public String getTlsVersions() {\n        return tlsVersions;\n    }\n\n    public void setTlsVersions(String tlsVersions) {\n        this.tlsVersions = tlsVersions;\n    }\n\n    public String getTrustCertificateKeyStoreType() {\n        return trustCertificateKeyStoreType;\n    }\n\n    public void setTrustCertificateKeyStoreType(String trustCertificateKeyStoreType) {\n        this.trustCertificateKeyStoreType = trustCertificateKeyStoreType;\n    }\n\n    public String getTrustCertificateKeyStoreUrl() {\n        return trustCertificateKeyStoreUrl;\n    }\n\n    public void setTrustCertificateKeyStoreUrl(String trustCertificateKeyStoreUrl) {\n        this.trustCertificateKeyStoreUrl = trustCertificateKeyStoreUrl;\n    }\n\n    public String getTrustCertificateKeyStorePassword() {\n        return trustCertificateKeyStorePassword;\n    }\n\n    public void setTrustCertificateKeyStorePassword(String trustCertificateKeyStorePassword) {\n        this.trustCertificateKeyStorePassword = trustCertificateKeyStorePassword;\n    }\n\n    public String getClientCertificateKeyStoreType() {\n        return clientCertificateKeyStoreType;\n    }\n\n    public void setClientCertificateKeyStoreType(String clientCertificateKeyStoreType) {\n        this.clientCertificateKeyStoreType = clientCertificateKeyStoreType;\n    }\n\n    public String getClientCertificateKeyStoreUrl() {\n        return clientCertificateKeyStoreUrl;\n    }\n\n    public void setClientCertificateKeyStoreUrl(String clientCertificateKeyStoreUrl) {\n        this.clientCertificateKeyStoreUrl = clientCertificateKeyStoreUrl;\n    }\n\n    public String getClientCertificateKeyStorePassword() {\n        return clientCertificateKeyStorePassword;\n    }\n\n    public void setClientCertificateKeyStorePassword(String clientCertificateKeyStorePassword) {\n        this.clientCertificateKeyStorePassword = clientCertificateKeyStorePassword;\n    }\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/ssl/SslMode.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.ssl;\n\npublic enum SslMode {\n\n    /**\n     * 关闭SSL\n     */\n    DISABLED,\n    /**\n     * 尝试SSL传输\n     */\n    PREFERRED,\n    /**\n     * 要求SSL传输，不校验证书\n     */\n    REQUIRED,\n    /**\n     * 要求SSL传输，校验证书，不校验证书里的域名\n     */\n    VERIFY_CA,\n    /**\n     * 要求SSL传输，校验证书，校验证书里的域名\n     */\n    VERIFY_IDENTITY\n\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/utils/BinlogDumpCommandBuilder.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.utils;\n\nimport java.io.IOException;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.jboss.netty.buffer.ChannelBuffer;\nimport org.jboss.netty.buffer.ChannelBuffers;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.HeaderPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.client.BinlogDumpCommandPacket;\n\npublic class BinlogDumpCommandBuilder {\n\n    public BinlogDumpCommandPacket build(String binglogFile, long position, long slaveId) {\n        BinlogDumpCommandPacket command = new BinlogDumpCommandPacket();\n        command.binlogPosition = position;\n        if (!StringUtils.isEmpty(binglogFile)) {\n            command.binlogFileName = binglogFile;\n        }\n        command.slaveServerId = slaveId;\n        // end settings.\n        return command;\n    }\n\n    public ChannelBuffer toChannelBuffer(BinlogDumpCommandPacket command) throws IOException {\n        byte[] commandBytes = command.toBytes();\n        byte[] headerBytes = assembleHeaderBytes(commandBytes.length);\n        ChannelBuffer buffer = ChannelBuffers.wrappedBuffer(headerBytes, commandBytes);\n        return buffer;\n    }\n\n    private byte[] assembleHeaderBytes(int length) {\n        HeaderPacket header = new HeaderPacket();\n        header.setPacketBodyLength(length);\n        header.setPacketSequenceNumber((byte) 0x00);\n        return header.toBytes();\n    }\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/utils/ByteHelper.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.utils;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\n\npublic abstract class ByteHelper {\n\n    public static final long NULL_LENGTH = -1;\n\n    public static byte[] readNullTerminatedBytes(byte[] data, int index) {\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n        for (int i = index; i < data.length; i++) {\n            byte item = data[i];\n            if (item == MSC.NULL_TERMINATED_STRING_DELIMITER) {\n                break;\n            }\n            out.write(item);\n        }\n        return out.toByteArray();\n    }\n\n    public static void writeNullTerminatedString(String str, ByteArrayOutputStream out) throws IOException {\n        out.write(str.getBytes());\n        out.write(MSC.NULL_TERMINATED_STRING_DELIMITER);\n    }\n\n    public static void writeNullTerminated(byte[] data, ByteArrayOutputStream out) throws IOException {\n        out.write(data);\n        out.write(MSC.NULL_TERMINATED_STRING_DELIMITER);\n    }\n\n    public static byte[] readFixedLengthBytes(byte[] data, int index, int length) {\n        byte[] bytes = new byte[length];\n        System.arraycopy(data, index, bytes, 0, length);\n        return bytes;\n    }\n\n    /**\n     * Read 4 bytes in Little-endian byte order.\n     * \n     * @param data, the original byte array\n     * @param index, start to read from.\n     * @return\n     */\n    public static long readUnsignedIntLittleEndian(byte[] data, int index) {\n        long result = (long) (data[index] & 0xFF) | (long) ((data[index + 1] & 0xFF) << 8)\n                      | (long) ((data[index + 2] & 0xFF) << 16) | (long) ((data[index + 3] & 0xFF) << 24);\n        return result;\n    }\n\n    public static long readUnsignedLongLittleEndian(byte[] data, int index) {\n        long accumulation = 0;\n        int position = index;\n        for (int shiftBy = 0; shiftBy < 64; shiftBy += 8) {\n            accumulation |= (long) ((data[position++] & 0xff) << shiftBy);\n        }\n        return accumulation;\n    }\n\n    public static int readUnsignedShortLittleEndian(byte[] data, int index) {\n        int result = (data[index] & 0xFF) | ((data[index + 1] & 0xFF) << 8);\n        return result;\n    }\n\n    public static int readUnsignedMediumLittleEndian(byte[] data, int index) {\n        int result = (data[index] & 0xFF) | ((data[index + 1] & 0xFF) << 8) | ((data[index + 2] & 0xFF) << 16);\n        return result;\n    }\n\n    public static long readLengthCodedBinary(byte[] data, int index) throws IOException {\n        int firstByte = data[index] & 0xFF;\n        switch (firstByte) {\n            case 251:\n                return NULL_LENGTH;\n            case 252:\n                return readUnsignedShortLittleEndian(data, index + 1);\n            case 253:\n                return readUnsignedMediumLittleEndian(data, index + 1);\n            case 254:\n                return readUnsignedLongLittleEndian(data, index + 1);\n            default:\n                return firstByte;\n        }\n    }\n\n    public static byte[] readBinaryCodedLengthBytes(byte[] data, int index) throws IOException {\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n        out.write(data[index]);\n\n        byte[] buffer = null;\n        int value = data[index] & 0xFF;\n        if (value == 251) {\n            buffer = new byte[0];\n        }\n        if (value == 252) {\n            buffer = new byte[2];\n        }\n        if (value == 253) {\n            buffer = new byte[3];\n        }\n        if (value == 254) {\n            buffer = new byte[8];\n        }\n        if (buffer != null) {\n            System.arraycopy(data, index + 1, buffer, 0, buffer.length);\n            out.write(buffer);\n        }\n\n        return out.toByteArray();\n    }\n\n    public static void write8ByteUnsignedIntLittleEndian(long data, ByteArrayOutputStream out) {\n        out.write((byte) (data & 0xFF));\n        out.write((byte) (data >>> 8));\n        out.write((byte) (data >>> 16));\n        out.write((byte) (data >>> 24));\n        out.write((byte) (data >>> 32));\n        out.write((byte) (data >>> 40));\n        out.write((byte) (data >>> 48));\n        out.write((byte) (data >>> 56));\n    }\n\n    public static void writeUnsignedIntLittleEndian(long data, ByteArrayOutputStream out) {\n        out.write((byte) (data & 0xFF));\n        out.write((byte) (data >>> 8));\n        out.write((byte) (data >>> 16));\n        out.write((byte) (data >>> 24));\n    }\n\n    public static void writeUnsignedInt64LittleEndian(long data, ByteArrayOutputStream out) {\n        out.write((byte) (data & 0xFF));\n        out.write((byte) (data >>> 8));\n        out.write((byte) (data >>> 16));\n        out.write((byte) (data >>> 24));\n        out.write((byte) (data >>> 32));\n        out.write((byte) (data >>> 40));\n        out.write((byte) (data >>> 48));\n        out.write((byte) (data >>> 56));\n    }\n\n    public static void writeUnsignedShortLittleEndian(int data, ByteArrayOutputStream out) {\n        out.write((byte) (data & 0xFF));\n        out.write((byte) ((data >>> 8) & 0xFF));\n    }\n\n    public static void writeUnsignedMediumLittleEndian(int data, ByteArrayOutputStream out) {\n        out.write((byte) (data & 0xFF));\n        out.write((byte) ((data >>> 8) & 0xFF));\n        out.write((byte) ((data >>> 16) & 0xFF));\n    }\n\n    public static void writeBinaryCodedLengthBytes(byte[] data, ByteArrayOutputStream out) throws IOException {\n        // 1. write length byte/bytes\n        if (data.length < 252) {\n            out.write((byte) data.length);\n        } else if (data.length < (1 << 16L)) {\n            out.write((byte) 252);\n            writeUnsignedShortLittleEndian(data.length, out);\n        } else if (data.length < (1 << 24L)) {\n            out.write((byte) 253);\n            writeUnsignedMediumLittleEndian(data.length, out);\n        } else {\n            out.write((byte) 254);\n            writeUnsignedIntLittleEndian(data.length, out);\n        }\n        // 2. write real data followed length byte/bytes\n        out.write(data);\n    }\n\n    public static void writeFixedLengthBytes(byte[] data, int index, int length, ByteArrayOutputStream out) {\n        for (int i = index; i < index + length; i++) {\n            out.write(data[i]);\n        }\n    }\n\n    public static void writeFixedLengthBytesFromStart(byte[] data, int length, ByteArrayOutputStream out) {\n        writeFixedLengthBytes(data, 0, length, out);\n    }\n\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/utils/ChannelBufferHelper.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.utils;\n\nimport java.io.IOException;\n\nimport org.jboss.netty.buffer.ChannelBuffer;\nimport org.jboss.netty.buffer.ChannelBuffers;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.HeaderPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.IPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.PacketWithHeaderPacket;\n\npublic class ChannelBufferHelper {\n\n    protected transient final Logger logger = LoggerFactory.getLogger(ChannelBufferHelper.class);\n\n    public final HeaderPacket assembleHeaderPacket(ChannelBuffer buffer) {\n        HeaderPacket header = new HeaderPacket();\n        byte[] headerBytes = new byte[MSC.HEADER_PACKET_LENGTH];\n        buffer.readBytes(headerBytes);\n        header.fromBytes(headerBytes);\n        return header;\n    }\n\n    public final PacketWithHeaderPacket assembleBodyPacketWithHeader(ChannelBuffer buffer, HeaderPacket header,\n                                                                     PacketWithHeaderPacket body) throws IOException {\n        if (body.getHeader() == null) {\n            body.setHeader(header);\n        }\n        logger.debug(\"body packet type:{}\", body.getClass());\n        logger.debug(\"read body packet with packet length: {} \", header.getPacketBodyLength());\n        byte[] packetBytes = new byte[header.getPacketBodyLength()];\n\n        logger.debug(\"readable bytes before reading body:{}\", buffer.readableBytes());\n        buffer.readBytes(packetBytes);\n        body.fromBytes(packetBytes);\n\n        logger.debug(\"body packet: {}\", body);\n        return body;\n    }\n\n    public final ChannelBuffer createHeaderWithPacketNumberPlusOne(int bodyLength, byte packetNumber) {\n        HeaderPacket header = new HeaderPacket();\n        header.setPacketBodyLength(bodyLength);\n        header.setPacketSequenceNumber((byte) (packetNumber + 1));\n        return ChannelBuffers.wrappedBuffer(header.toBytes());\n    }\n\n    public final ChannelBuffer createHeader(int bodyLength, byte packetNumber) {\n        HeaderPacket header = new HeaderPacket();\n        header.setPacketBodyLength(bodyLength);\n        header.setPacketSequenceNumber(packetNumber);\n        return ChannelBuffers.wrappedBuffer(header.toBytes());\n    }\n\n    public final ChannelBuffer buildChannelBufferFromCommandPacket(IPacket packet) throws IOException {\n        byte[] bodyBytes = packet.toBytes();\n        ChannelBuffer header = createHeader(bodyBytes.length, (byte) 0);\n        return ChannelBuffers.wrappedBuffer(header, ChannelBuffers.wrappedBuffer(bodyBytes));\n    }\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/utils/CharsetUtil.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.utils;\r\n\r\nimport java.util.HashMap;\r\nimport java.util.Map;\r\n\r\nimport org.apache.commons.lang.StringUtils;\r\n\r\n/**\r\n * mysql collation转换mapping关系表\r\n * \r\n * @author agapple 2018年11月5日 下午1:01:15\r\n * @since 1.1.2\r\n */\r\npublic class CharsetUtil {\r\n\r\n    private static final String[]             INDEX_TO_CHARSET = new String[2048];\r\n    private static final Map<String, Integer> CHARSET_TO_INDEX = new HashMap<>();\r\n    static {\r\n        INDEX_TO_CHARSET[1] = \"big5\";\r\n        INDEX_TO_CHARSET[84] = \"big5\";\r\n\r\n        INDEX_TO_CHARSET[3] = \"dec8\";\r\n        INDEX_TO_CHARSET[69] = \"dec8\";\r\n\r\n        INDEX_TO_CHARSET[4] = \"cp850\";\r\n        INDEX_TO_CHARSET[80] = \"cp850\";\r\n\r\n        INDEX_TO_CHARSET[6] = \"hp8\";\r\n        INDEX_TO_CHARSET[72] = \"hp8\";\r\n\r\n        INDEX_TO_CHARSET[7] = \"koi8r\";\r\n        INDEX_TO_CHARSET[74] = \"koi8r\";\r\n\r\n        INDEX_TO_CHARSET[5] = \"latin1\";\r\n        INDEX_TO_CHARSET[8] = \"latin1\";\r\n        INDEX_TO_CHARSET[15] = \"latin1\";\r\n        INDEX_TO_CHARSET[31] = \"latin1\";\r\n        INDEX_TO_CHARSET[47] = \"latin1\";\r\n        INDEX_TO_CHARSET[48] = \"latin1\";\r\n        INDEX_TO_CHARSET[49] = \"latin1\";\r\n        INDEX_TO_CHARSET[94] = \"latin1\";\r\n\r\n        INDEX_TO_CHARSET[9] = \"latin2\";\r\n        INDEX_TO_CHARSET[21] = \"latin2\";\r\n        INDEX_TO_CHARSET[27] = \"latin2\";\r\n        INDEX_TO_CHARSET[77] = \"latin2\";\r\n\r\n        INDEX_TO_CHARSET[10] = \"swe7\";\r\n        INDEX_TO_CHARSET[82] = \"swe7\";\r\n\r\n        INDEX_TO_CHARSET[11] = \"ascii\";\r\n        INDEX_TO_CHARSET[65] = \"ascii\";\r\n\r\n        INDEX_TO_CHARSET[12] = \"ujis\";\r\n        INDEX_TO_CHARSET[91] = \"ujis\";\r\n\r\n        INDEX_TO_CHARSET[13] = \"sjis\";\r\n        INDEX_TO_CHARSET[88] = \"sjis\";\r\n\r\n        INDEX_TO_CHARSET[16] = \"hebrew\";\r\n        INDEX_TO_CHARSET[71] = \"hebrew\";\r\n\r\n        INDEX_TO_CHARSET[18] = \"tis620\";\r\n        INDEX_TO_CHARSET[69] = \"tis620\";\r\n\r\n        INDEX_TO_CHARSET[19] = \"euckr\";\r\n        INDEX_TO_CHARSET[85] = \"euckr\";\r\n\r\n        INDEX_TO_CHARSET[22] = \"koi8u\";\r\n        INDEX_TO_CHARSET[75] = \"koi8u\";\r\n\r\n        INDEX_TO_CHARSET[24] = \"gb2312\";\r\n        INDEX_TO_CHARSET[86] = \"gb2312\";\r\n\r\n        INDEX_TO_CHARSET[25] = \"greek\";\r\n        INDEX_TO_CHARSET[70] = \"greek\";\r\n\r\n        INDEX_TO_CHARSET[26] = \"cp1250\";\r\n        INDEX_TO_CHARSET[34] = \"cp1250\";\r\n        INDEX_TO_CHARSET[44] = \"cp1250\";\r\n        INDEX_TO_CHARSET[66] = \"cp1250\";\r\n        INDEX_TO_CHARSET[99] = \"cp1250\";\r\n\r\n        INDEX_TO_CHARSET[28] = \"gbk\";\r\n        INDEX_TO_CHARSET[87] = \"gbk\";\r\n\r\n        INDEX_TO_CHARSET[30] = \"latin5\";\r\n        INDEX_TO_CHARSET[78] = \"latin5\";\r\n\r\n        INDEX_TO_CHARSET[32] = \"armscii8\";\r\n        INDEX_TO_CHARSET[64] = \"armscii8\";\r\n\r\n        INDEX_TO_CHARSET[33] = \"utf8\";\r\n        INDEX_TO_CHARSET[83] = \"utf8\";\r\n        for (int i = 192; i <= 223; i++) {\r\n            INDEX_TO_CHARSET[i] = \"utf8\";\r\n        }\r\n        for (int i = 336; i <= 337; i++) {\r\n            INDEX_TO_CHARSET[i] = \"utf8\";\r\n        }\r\n        for (int i = 352; i <= 357; i++) {\r\n            INDEX_TO_CHARSET[i] = \"utf8\";\r\n        }\r\n        INDEX_TO_CHARSET[368] = \"utf8\";\r\n        INDEX_TO_CHARSET[2047] = \"utf8\";\r\n\r\n        INDEX_TO_CHARSET[35] = \"ucs2\";\r\n        INDEX_TO_CHARSET[90] = \"ucs2\";\r\n        for (int i = 128; i <= 151; i++) {\r\n            INDEX_TO_CHARSET[i] = \"ucs2\";\r\n        }\r\n        INDEX_TO_CHARSET[159] = \"ucs2\";\r\n        for (int i = 358; i <= 360; i++) {\r\n            INDEX_TO_CHARSET[i] = \"ucs2\";\r\n        }\r\n\r\n        INDEX_TO_CHARSET[36] = \"cp866\";\r\n        INDEX_TO_CHARSET[68] = \"cp866\";\r\n\r\n        INDEX_TO_CHARSET[37] = \"keybcs2\";\r\n        INDEX_TO_CHARSET[73] = \"keybcs2\";\r\n\r\n        INDEX_TO_CHARSET[38] = \"macce\";\r\n        INDEX_TO_CHARSET[43] = \"macce\";\r\n\r\n        INDEX_TO_CHARSET[39] = \"macroman\";\r\n        INDEX_TO_CHARSET[53] = \"macroman\";\r\n\r\n        INDEX_TO_CHARSET[40] = \"cp852\";\r\n        INDEX_TO_CHARSET[81] = \"cp852\";\r\n\r\n        INDEX_TO_CHARSET[20] = \"latin7\";\r\n        INDEX_TO_CHARSET[41] = \"latin7\";\r\n        INDEX_TO_CHARSET[42] = \"latin7\";\r\n        INDEX_TO_CHARSET[79] = \"latin7\";\r\n\r\n        INDEX_TO_CHARSET[45] = \"utf8mb4\";\r\n        INDEX_TO_CHARSET[46] = \"utf8mb4\";\r\n        for (int i = 224; i <= 247; i++) {\r\n            INDEX_TO_CHARSET[i] = \"utf8mb4\";\r\n        }\r\n        for (int i = 255; i <= 271; i++) {\r\n            INDEX_TO_CHARSET[i] = \"utf8mb4\";\r\n        }\r\n        for (int i = 273; i <= 275; i++) {\r\n            INDEX_TO_CHARSET[i] = \"utf8mb4\";\r\n        }\r\n        for (int i = 277; i <= 294; i++) {\r\n            INDEX_TO_CHARSET[i] = \"utf8mb4\";\r\n        }\r\n        for (int i = 296; i <= 298; i++) {\r\n            INDEX_TO_CHARSET[i] = \"utf8mb4\";\r\n        }\r\n        INDEX_TO_CHARSET[300] = \"utf8mb4\";\r\n        for (int i = 303; i <= 307; i++) {\r\n            INDEX_TO_CHARSET[i] = \"utf8mb4\";\r\n        }\r\n        INDEX_TO_CHARSET[326] = \"utf8mb4\";\r\n        INDEX_TO_CHARSET[328] = \"utf8mb4\";\r\n\r\n        INDEX_TO_CHARSET[14] = \"cp1251\";\r\n        INDEX_TO_CHARSET[23] = \"cp1251\";\r\n        INDEX_TO_CHARSET[50] = \"cp1251\";\r\n        INDEX_TO_CHARSET[51] = \"cp1251\";\r\n        INDEX_TO_CHARSET[52] = \"cp1251\";\r\n\r\n        INDEX_TO_CHARSET[54] = \"utf16\";\r\n        INDEX_TO_CHARSET[55] = \"utf16\";\r\n        for (int i = 101; i <= 124; i++) {\r\n            INDEX_TO_CHARSET[i] = \"utf16\";\r\n        }\r\n        INDEX_TO_CHARSET[327] = \"utf16\";\r\n\r\n        INDEX_TO_CHARSET[56] = \"utf16le\";\r\n        INDEX_TO_CHARSET[62] = \"utf16le\";\r\n\r\n        INDEX_TO_CHARSET[57] = \"cp1256\";\r\n        INDEX_TO_CHARSET[67] = \"cp1256\";\r\n\r\n        INDEX_TO_CHARSET[29] = \"cp1257\";\r\n        INDEX_TO_CHARSET[58] = \"cp1257\";\r\n        INDEX_TO_CHARSET[59] = \"cp1257\";\r\n\r\n        INDEX_TO_CHARSET[60] = \"utf32\";\r\n        INDEX_TO_CHARSET[61] = \"utf32\";\r\n        for (int i = 160; i <= 183; i++) {\r\n            INDEX_TO_CHARSET[i] = \"utf32\";\r\n        }\r\n        INDEX_TO_CHARSET[391] = \"utf32\";\r\n\r\n        INDEX_TO_CHARSET[63] = \"binary\";\r\n\r\n        INDEX_TO_CHARSET[92] = \"geostd8\";\r\n        INDEX_TO_CHARSET[93] = \"geostd8\";\r\n\r\n        INDEX_TO_CHARSET[95] = \"cp932\";\r\n        INDEX_TO_CHARSET[96] = \"cp932\";\r\n\r\n        INDEX_TO_CHARSET[97] = \"eucjpms\";\r\n        INDEX_TO_CHARSET[98] = \"eucjpms\";\r\n\r\n        for (int i = 248; i <= 250; i++) {\r\n            INDEX_TO_CHARSET[i] = \"gb18030\";\r\n        }\r\n\r\n        // charset --> index\r\n        for (int i = 0; i < 2048; i++) {\r\n            String charset = INDEX_TO_CHARSET[i];\r\n            if (charset != null && CHARSET_TO_INDEX.get(charset) == null) {\r\n                CHARSET_TO_INDEX.put(charset, i);\r\n            }\r\n        }\r\n        CHARSET_TO_INDEX.put(\"iso-8859-1\", 14);\r\n        CHARSET_TO_INDEX.put(\"iso_8859_1\", 14);\r\n        CHARSET_TO_INDEX.put(\"utf-8\", 33);\r\n        CHARSET_TO_INDEX.put(\"utf8mb4\", 45);\r\n    }\r\n\r\n    public static final String getCharset(int index) {\r\n        return INDEX_TO_CHARSET[index];\r\n    }\r\n\r\n    public static final int getIndex(String charset) {\r\n        if (charset == null || charset.length() == 0) {\r\n            return 0;\r\n        } else {\r\n            Integer i = CHARSET_TO_INDEX.get(charset.toLowerCase());\r\n            return (i == null) ? 0 : i.intValue();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 'utf8' COLLATE 'utf8_general_ci'\r\n     * \r\n     * @param charset\r\n     * @return\r\n     */\r\n    public static final String collateCharset(String charset) {\r\n        String[] output = StringUtils.split(charset, \"COLLATE\");\r\n        return output[0].replace('\\'', ' ').trim();\r\n    }\r\n\r\n    public static String getJavaCharset(String charset) {\r\n        if (\"utf8\".equals(charset)) {\r\n            return charset;\r\n        }\r\n\r\n        if (StringUtils.endsWithIgnoreCase(charset, \"utf8mb4\")) {\r\n            return \"utf-8\";\r\n        }\r\n\r\n        if (StringUtils.endsWithIgnoreCase(charset, \"binary\")) {\r\n            return \"iso_8859_1\";\r\n        }\r\n\r\n        return charset;\r\n    }\r\n}\r\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/utils/GtidUtil.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.utils;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.GTIDSet;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.MariaGTIDSet;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.MysqlGTIDSet;\n\n/**\n * 类 GtidUtil.java 的实现\n *\n * @author winger 2020/9/24 1:25 下午\n * @version 1.0.0\n */\npublic class GtidUtil {\n\n    public static GTIDSet parseGtidSet(String gtid, boolean isMariaDB) {\n        if (isMariaDB) {\n            return MariaGTIDSet.parse(gtid);\n        } else {\n            return MysqlGTIDSet.parse(gtid);\n        }\n    }\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/utils/LengthCodedStringReader.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.utils;\n\nimport java.io.IOException;\n\nimport org.apache.commons.lang.ArrayUtils;\n\npublic class LengthCodedStringReader {\n\n    public static final String CODE_PAGE_1252 = \"UTF-8\";\n\n    private String             encoding;\n    private int                index          = 0;      // 数组下标\n\n    public LengthCodedStringReader(String encoding, int startIndex){\n        this.encoding = encoding;\n        this.index = startIndex;\n    }\n\n    public String readLengthCodedString(byte[] data) throws IOException {\n        byte[] lengthBytes = ByteHelper.readBinaryCodedLengthBytes(data, getIndex());\n        long length = ByteHelper.readLengthCodedBinary(data, getIndex());\n        setIndex(getIndex() + lengthBytes.length);\n        if (ByteHelper.NULL_LENGTH == length) {\n            return null;\n        }\n\n        try {\n            return new String(ArrayUtils.subarray(data, getIndex(), (int) (getIndex() + length)),\n                encoding == null ? CODE_PAGE_1252 : encoding);\n        } finally {\n            setIndex((int) (getIndex() + length));\n        }\n\n    }\n\n    public void setIndex(int index) {\n        this.index = index;\n    }\n\n    public int getIndex() {\n        return index;\n    }\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/utils/MSC.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.utils;\n\n/**\n * MySQL Constants.<br>\n * constants that is used in mysql server.<br>\n * \n * @author fujohnwang\n */\npublic abstract class MSC {\n\n    public static final int  MAX_PACKET_LENGTH                  = (1 << 24);\n    public static final int  HEADER_PACKET_LENGTH_FIELD_LENGTH  = 3;\n    public static final int  HEADER_PACKET_LENGTH_FIELD_OFFSET  = 0;\n    public static final int  HEADER_PACKET_LENGTH               = 4;\n    public static final int  HEADER_PACKET_NUMBER_FIELD_LENGTH  = 1;\n\n    public static final byte NULL_TERMINATED_STRING_DELIMITER   = 0x00;\n    public static final byte DEFAULT_PROTOCOL_VERSION           = 0x0a;\n\n    public static final int  FIELD_COUNT_FIELD_LENGTH           = 1;\n\n    public static final int  EVENT_TYPE_OFFSET                  = 4;\n    public static final int  EVENT_LEN_OFFSET                   = 9;\n\n    public static final long DEFAULT_BINLOG_FILE_START_POSITION = 4;\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/utils/MySQLPasswordEncrypter.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.utils;\n\nimport java.security.*;\nimport java.security.spec.InvalidKeySpecException;\nimport java.security.spec.X509EncodedKeySpec;\n\nimport javax.crypto.BadPaddingException;\nimport javax.crypto.Cipher;\nimport javax.crypto.IllegalBlockSizeException;\nimport javax.crypto.NoSuchPaddingException;\n\npublic class MySQLPasswordEncrypter {\n\n    private static final int CACHING_SHA2_DIGEST_LENGTH = 32;\n\n    public static byte[] scrambleCachingSha2(byte[] password, byte[] seed) throws DigestException {\n        MessageDigest md;\n        try {\n            md = MessageDigest.getInstance(\"SHA-256\");\n        } catch (NoSuchAlgorithmException ex) {\n            throw new DigestException(ex);\n        }\n\n        byte[] dig1 = new byte[CACHING_SHA2_DIGEST_LENGTH];\n        byte[] dig2 = new byte[CACHING_SHA2_DIGEST_LENGTH];\n        byte[] scramble1 = new byte[CACHING_SHA2_DIGEST_LENGTH];\n\n        // SHA2(src) => digest_stage1\n        md.update(password, 0, password.length);\n        md.digest(dig1, 0, CACHING_SHA2_DIGEST_LENGTH);\n        md.reset();\n\n        // SHA2(digest_stage1) => digest_stage2\n        md.update(dig1, 0, dig1.length);\n        md.digest(dig2, 0, CACHING_SHA2_DIGEST_LENGTH);\n        md.reset();\n\n        // SHA2(digest_stage2, m_rnd) => scramble_stage1\n        md.update(dig2, 0, dig1.length);\n        md.update(seed, 0, seed.length);\n        md.digest(scramble1, 0, CACHING_SHA2_DIGEST_LENGTH);\n\n        // XOR(digest_stage1, scramble_stage1) => scramble\n        byte[] mysqlScrambleBuff = new byte[CACHING_SHA2_DIGEST_LENGTH];\n        xorString(dig1, mysqlScrambleBuff, scramble1, CACHING_SHA2_DIGEST_LENGTH);\n\n        return mysqlScrambleBuff;\n    }\n\n    public static final byte[] scramble411(byte[] pass, byte[] seed) throws NoSuchAlgorithmException {\n        MessageDigest md = MessageDigest.getInstance(\"SHA-1\");\n        byte[] pass1 = md.digest(pass);\n        md.reset();\n        byte[] pass2 = md.digest(pass1);\n        md.reset();\n        md.update(seed);\n        byte[] pass3 = md.digest(pass2);\n        for (int i = 0; i < pass3.length; i++) {\n            pass3[i] = (byte) (pass3[i] ^ pass1[i]);\n        }\n        return pass3;\n    }\n\n    public static String scramble323(String pass, String seed) {\n        if ((pass == null) || (pass.length() == 0)) {\n            return pass;\n        }\n        byte b;\n        double d;\n        long[] pw = hash(seed);\n        long[] msg = hash(pass);\n        long max = 0x3fffffffL;\n        long seed1 = (pw[0] ^ msg[0]) % max;\n        long seed2 = (pw[1] ^ msg[1]) % max;\n        char[] chars = new char[seed.length()];\n        for (int i = 0; i < seed.length(); i++) {\n            seed1 = ((seed1 * 3) + seed2) % max;\n            seed2 = (seed1 + seed2 + 33) % max;\n            d = (double) seed1 / (double) max;\n            b = (byte) java.lang.Math.floor((d * 31) + 64);\n            chars[i] = (char) b;\n        }\n        seed1 = ((seed1 * 3) + seed2) % max;\n        seed2 = (seed1 + seed2 + 33) % max;\n        d = (double) seed1 / (double) max;\n        b = (byte) java.lang.Math.floor(d * 31);\n        for (int i = 0; i < seed.length(); i++) {\n            chars[i] ^= (char) b;\n        }\n        return new String(chars);\n    }\n\n    public static final byte[] scrambleRsa(byte[] publicKeyBytes, byte[] pass,\n                                           byte[] seed) throws NoSuchAlgorithmException, InvalidKeySpecException,\n                                                        NoSuchPaddingException, InvalidKeyException,\n                                                        IllegalBlockSizeException, BadPaddingException {\n        byte[] input = new byte[pass.length + 1];\n        System.arraycopy(pass, 0, input, 0, pass.length);\n        byte[] encryptedPassword = new byte[input.length];\n        xorString(input, encryptedPassword, seed, input.length);\n        String publicKeyPem = new String(publicKeyBytes).replace(\"\\n\", \"\")\n            .replace(\"-----BEGIN PUBLIC KEY-----\", \"\")\n            .replace(\"-----END PUBLIC KEY-----\", \"\");\n        byte[] certificateData = java.util.Base64.getDecoder().decode(publicKeyPem.getBytes());\n        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(certificateData);\n        KeyFactory keyFactory = KeyFactory.getInstance(\"RSA\");\n        PublicKey publicKey = keyFactory.generatePublic(keySpec);\n        Cipher cipher = Cipher.getInstance(\"RSA/ECB/OAEPWithSHA-1AndMGF1Padding\");\n        cipher.init(Cipher.ENCRYPT_MODE, publicKey);\n        return cipher.doFinal(encryptedPassword);\n    }\n\n    private static long[] hash(String src) {\n        long nr = 1345345333L;\n        long add = 7;\n        long nr2 = 0x12345671L;\n        long tmp;\n        for (int i = 0; i < src.length(); ++i) {\n            switch (src.charAt(i)) {\n                case ' ':\n                case '\\t':\n                    continue;\n                default:\n                    tmp = (0xff & src.charAt(i));\n                    nr ^= ((((nr & 63) + add) * tmp) + (nr << 8));\n                    nr2 += ((nr2 << 8) ^ nr);\n                    add += tmp;\n            }\n        }\n        long[] result = new long[2];\n        result[0] = nr & 0x7fffffffL;\n        result[1] = nr2 & 0x7fffffffL;\n        return result;\n    }\n\n    private static void xorString(byte[] from, byte[] to, byte[] scramble, int length) {\n        int pos = 0;\n        int scrambleLength = scramble.length;\n        while (pos < length) {\n            to[pos] = (byte) (from[pos] ^ scramble[pos % scrambleLength]);\n            pos++;\n        }\n    }\n\n}\n"
  },
  {
    "path": "driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/utils/PacketManager.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.utils;\r\n\r\nimport java.io.ByteArrayOutputStream;\r\nimport java.io.IOException;\r\n\r\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.HeaderPacket;\r\nimport com.alibaba.otter.canal.parse.driver.mysql.socket.SocketChannel;\r\n\r\npublic abstract class PacketManager {\r\n\r\n    public static HeaderPacket readHeader(SocketChannel ch, int len) throws IOException {\r\n        HeaderPacket header = new HeaderPacket();\r\n        header.fromBytes(ch.read(len));\r\n        return header;\r\n    }\r\n\r\n    public static HeaderPacket readHeader(SocketChannel ch, int len, int timeout) throws IOException {\r\n        HeaderPacket header = new HeaderPacket();\r\n        header.fromBytes(ch.read(len, timeout));\r\n        return header;\r\n    }\r\n\r\n    public static byte[] readBytes(SocketChannel ch, int len) throws IOException {\r\n        return ch.read(len);\r\n    }\r\n\r\n    public static byte[] readBytes(SocketChannel ch, int len, int timeout) throws IOException {\r\n        return ch.read(len, timeout);\r\n    }\r\n\r\n    public static void writePkg(SocketChannel ch, byte[]... srcs) throws IOException {\r\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\r\n        for (byte[] src : srcs) {\r\n            out.write(src);\r\n        }\r\n        ch.write(out.toByteArray());\r\n    }\r\n\r\n    public static void writeBody(SocketChannel ch, byte[] body) throws IOException {\r\n        writeBody0(ch, body, (byte) 0);\r\n    }\r\n\r\n    public static void writeBody0(SocketChannel ch, byte[] body, byte packetSeqNumber) throws IOException {\r\n        HeaderPacket header = new HeaderPacket();\r\n        header.setPacketBodyLength(body.length);\r\n        header.setPacketSequenceNumber(packetSeqNumber);\r\n        ch.write(header.toBytes(), body);\r\n    }\r\n}\r\n"
  },
  {
    "path": "driver/src/test/java/com/alibaba/otter/canal/parse/driver/mysql/CharsetUtilTest.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.CharsetUtil;\n\npublic class CharsetUtilTest {\n\n    @Test\n    public void testLatin1() {\n        int charsetIndex = 5;\n        String charset = \"latin1\";\n        Assert.assertTrue(charset.equals(CharsetUtil.getCharset(charsetIndex)));\n    }\n\n    @Test\n    public void testGbk() {\n        int charsetIndex = 87;\n        String charset = \"gbk\";\n        Assert.assertTrue(charset.equals(CharsetUtil.getCharset(charsetIndex)));\n    }\n\n    @Test\n    public void testGb2312() {\n        int charsetIndex = 24;\n        String charset = \"gb2312\";\n        Assert.assertTrue(charset.equals(CharsetUtil.getCharset(charsetIndex)));\n    }\n\n    @Test\n    public void testUtf8() {\n        int charsetIndex = 213;\n        String charset = \"utf8\";\n        Assert.assertTrue(charset.equals(CharsetUtil.getCharset(charsetIndex)));\n    }\n\n    @Test\n    public void testUtf8mb4() {\n        int charsetIndex = 235;\n        String charset = \"utf8mb4\";\n        Assert.assertTrue(charset.equals(CharsetUtil.getCharset(charsetIndex)));\n    }\n\n    @Test\n    public void testBinary() {\n        int charsetIndex = 63;\n        String charset = \"binary\";\n        Assert.assertTrue(charset.equals(CharsetUtil.getCharset(charsetIndex)));\n    }\n}\n"
  },
  {
    "path": "driver/src/test/java/com/alibaba/otter/canal/parse/driver/mysql/MysqlConnectorTest.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql;\n\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\n\nimport org.junit.Assert;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.server.ResultSetPacket;\n\n@Ignore\npublic class MysqlConnectorTest {\n\n    @Test\n    public void testQuery() {\n\n        MysqlConnector connector = new MysqlConnector(new InetSocketAddress(\"127.0.0.1\", 3306), \"xxxxx\", \"xxxxx\");\n        try {\n            connector.connect();\n            MysqlQueryExecutor executor = new MysqlQueryExecutor(connector);\n            ResultSetPacket result = executor.query(\"show variables like '%char%';\");\n            System.out.println(result);\n            result = executor.query(\"select * from test.test1\");\n            System.out.println(result);\n        } catch (IOException e) {\n            Assert.fail(e.getMessage());\n        } finally {\n            try {\n                connector.disconnect();\n            } catch (IOException e) {\n                Assert.fail(e.getMessage());\n            }\n        }\n    }\n\n    // @Test\n    public void testUpdate() {\n\n        MysqlConnector connector = new MysqlConnector(new InetSocketAddress(\"127.0.0.1\", 3306), \"xxxxx\", \"xxxxx\");\n        try {\n            connector.connect();\n            MysqlUpdateExecutor executor = new MysqlUpdateExecutor(connector);\n            executor.update(\"insert into test.test2(id,name,score,text_value) values(null,'中文1',10,'中文2')\");\n        } catch (IOException e) {\n            Assert.fail(e.getMessage());\n        } finally {\n            try {\n                connector.disconnect();\n            } catch (IOException e) {\n                Assert.fail(e.getMessage());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "driver/src/test/java/com/alibaba/otter/canal/parse/driver/mysql/MysqlGTIDSetTest.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql;\n\nimport static org.junit.Assert.assertEquals;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.UUID;\n\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.GTIDSet;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.MysqlGTIDSet;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.UUIDSet;\n\n/**\n * Created by hiwjd on 2018/4/25. hiwjd0@gmail.com\n */\npublic class MysqlGTIDSetTest {\n\n    @Test\n    public void testEncode() throws IOException {\n        GTIDSet gtidSet = MysqlGTIDSet.parse(\"726757ad-4455-11e8-ae04-0242ac110002:1\");\n        byte[] bytes = gtidSet.encode();\n\n        byte[] expected = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x67, 0x57, (byte) 0xad, 0x44, 0x55,\n                0x11, (byte) 0xe8, (byte) 0xae, 0x04, 0x02, 0x42, (byte) 0xac, 0x11, 0x00, 0x02, 0x01, 0x00, 0x00,\n                0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n                0x00, 0x00, 0x00, 0x00 };\n\n        for (int i = 0; i < bytes.length; i++) {\n            assertEquals(expected[i], bytes[i]);\n        }\n    }\n\n    @Test\n    public void testUpdate() {\n        String gtid1 = \"726757ad-4455-11e8-ae04-0242ac110002:1-25536412\";\n        MysqlGTIDSet mysqlGTIDSet1 = MysqlGTIDSet.parse(gtid1);\n\n        String gtid2 = \"726757ad-4455-11e8-ae04-0242ac110002:1-20304074\";\n\n        mysqlGTIDSet1.update(gtid2);\n        assertEquals(\"726757ad-4455-11e8-ae04-0242ac110002:1-20304074\", mysqlGTIDSet1.toString());\n    }\n\n    @Test\n    public void testParse() {\n        Map<String, MysqlGTIDSet> cases = new HashMap<>(5);\n        cases.put(\"726757ad-4455-11e8-ae04-0242ac110002:1\",\n            buildForTest(new Material(\"726757ad-4455-11e8-ae04-0242ac110002\", 1, 2)));\n        cases.put(\"726757ad-4455-11e8-ae04-0242ac110002:1-3\",\n            buildForTest(new Material(\"726757ad-4455-11e8-ae04-0242ac110002\", 1, 4)));\n        cases.put(\"726757ad-4455-11e8-ae04-0242ac110002:1-3:4\",\n            buildForTest(new Material(\"726757ad-4455-11e8-ae04-0242ac110002\", 1, 5)));\n        cases.put(\"726757ad-4455-11e8-ae04-0242ac110002:1-3:7-9\",\n            buildForTest(new Material(\"726757ad-4455-11e8-ae04-0242ac110002\", 1, 4, 7, 10)));\n        cases.put(\"726757ad-4455-11e8-ae04-0242ac110002:1-3,726757ad-4455-11e8-ae04-0242ac110003:4\",\n            buildForTest(Arrays.asList(new Material(\"726757ad-4455-11e8-ae04-0242ac110002\", 1, 4),\n                new Material(\"726757ad-4455-11e8-ae04-0242ac110003\", 4, 5))));\n\n        for (Map.Entry<String, MysqlGTIDSet> entry : cases.entrySet()) {\n            MysqlGTIDSet expected = entry.getValue();\n            MysqlGTIDSet actual = MysqlGTIDSet.parse(entry.getKey());\n\n            assertEquals(expected, actual);\n        }\n    }\n\n    private static class Material {\n\n        public Material(String uuid, long start, long stop){\n            this.uuid = uuid;\n            this.start = start;\n            this.stop = stop;\n            this.start1 = 0;\n            this.stop1 = 0;\n        }\n\n        public Material(String uuid, long start, long stop, long start1, long stop1){\n            this.uuid = uuid;\n            this.start = start;\n            this.stop = stop;\n            this.start1 = start1;\n            this.stop1 = stop1;\n        }\n\n        public String uuid;\n        public long   start;\n        public long   stop;\n        public long   start1;\n        public long   stop1;\n    }\n\n    private MysqlGTIDSet buildForTest(Material material) {\n        return buildForTest(Arrays.asList(material));\n    }\n\n    private MysqlGTIDSet buildForTest(List<Material> materials) {\n        Map<String, UUIDSet> sets = new HashMap<>();\n        for (Material a : materials) {\n            UUIDSet.Interval interval = new UUIDSet.Interval();\n            interval.start = a.start;\n            interval.stop = a.stop;\n            List<UUIDSet.Interval> intervals = new ArrayList<>();\n            intervals.add(interval);\n\n            if (a.start1 > 0 && a.stop1 > 0) {\n                UUIDSet.Interval interval1 = new UUIDSet.Interval();\n                interval1.start = a.start1;\n                interval1.stop = a.stop1;\n                intervals.add(interval1);\n            }\n\n            UUIDSet us = new UUIDSet();\n            us.SID = UUID.fromString(a.uuid);\n            us.intervals = intervals;\n\n            sets.put(a.uuid, us);\n        }\n\n        MysqlGTIDSet gs = new MysqlGTIDSet();\n        gs.sets = sets;\n\n        return gs;\n    }\n}\n"
  },
  {
    "path": "driver/src/test/java/com/alibaba/otter/canal/parse/driver/mysql/UUIDSetTest.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql;\n\nimport static org.junit.Assert.assertEquals;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.UUIDSet;\n\n/**\n * Created by hiwjd on 2018/4/26. hiwjd0@gmail.com\n */\npublic class UUIDSetTest {\n\n    @Test\n    public void testToString() {\n        Map<String, String> cases = new HashMap<>(4);\n        cases.put(\"726757ad-4455-11e8-ae04-0242ac110002:1\", \"726757ad-4455-11e8-ae04-0242ac110002:1\");\n        cases.put(\"726757ad-4455-11e8-ae04-0242ac110002:1-3\", \"726757ad-4455-11e8-ae04-0242ac110002:1-3\");\n        cases.put(\"726757ad-4455-11e8-ae04-0242ac110002:1-3:4-6\", \"726757ad-4455-11e8-ae04-0242ac110002:1-6\");\n        cases.put(\"726757ad-4455-11e8-ae04-0242ac110002:1-3:5-7\", \"726757ad-4455-11e8-ae04-0242ac110002:1-3:5-7\");\n\n        for (Map.Entry<String, String> entry : cases.entrySet()) {\n            String expected = entry.getValue();\n            assertEquals(expected, UUIDSet.parse(entry.getKey()).toString());\n        }\n    }\n}\n"
  },
  {
    "path": "driver/src/test/java/com/alibaba/otter/canal/parse/driver/mysql/packets/client/RegisterSlaveCommandPacketTest.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.packets.client;\n\nimport java.io.IOException;\nimport java.lang.reflect.InvocationTargetException;\n\nimport org.junit.Assert;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.junit.rules.ExpectedException;\nimport org.junit.rules.Timeout;\n\npublic class RegisterSlaveCommandPacketTest {\n\n    @Rule\n    public final ExpectedException thrown        = ExpectedException.none();\n\n    @SuppressWarnings(\"deprecation\")\n    @Rule\n    public final Timeout           globalTimeout = new Timeout(10000);\n\n    /* testedClasses: RegisterSlaveCommandPacket */\n    // Test written by Diffblue Cover.\n    @Test\n    public void toBytesOutput27() throws IOException, InvocationTargetException {\n\n        // Arrange\n        final RegisterSlaveCommandPacket objectUnderTest = new RegisterSlaveCommandPacket();\n        objectUnderTest.serverId = 0L;\n        objectUnderTest.reportPort = 0;\n        objectUnderTest.reportPasswd = \"foo\";\n        objectUnderTest.reportHost = \"foo\";\n        objectUnderTest.reportUser = \"foo\";\n        objectUnderTest.setCommand((byte) 0);\n\n        // Act\n        final byte[] actual = objectUnderTest.toBytes();\n\n        // Assert result\n        Assert.assertArrayEquals(new byte[] { (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 3, (byte) 102,\n                (byte) 111, (byte) 111, (byte) 3, (byte) 102, (byte) 111, (byte) 111, (byte) 3, (byte) 102, (byte) 111,\n                (byte) 111, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0,\n                (byte) 0 }, actual);\n    }\n\n    // Test written by Diffblue Cover.\n    @Test\n    public void toLHInputZeroOutput4() {\n\n        // Arrange\n        final int n = 0;\n\n        // Act\n        final byte[] actual = RegisterSlaveCommandPacket.toLH(n);\n\n        // Assert result\n        Assert.assertArrayEquals(new byte[] { (byte) 0, (byte) 0, (byte) 0, (byte) 0 }, actual);\n    }\n}\n"
  },
  {
    "path": "driver/src/test/java/com/alibaba/otter/canal/parse/driver/mysql/utils/ByteHelperTest.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.utils; \n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class ByteHelperTest {\n\n\t@Test\n\tpublic void testReadBinaryCodedLengthBytes() throws Exception {\n\t\tAssert.assertArrayEquals(new byte[] {95},\n\t\t\tByteHelper.readBinaryCodedLengthBytes(new byte[] {94, 95, 96}, 1));\n\t\tAssert.assertArrayEquals(new byte[] {-5},\n\t\t\tByteHelper.readBinaryCodedLengthBytes(new byte[] {-4, -5, -6}, 1));\n\t\tAssert.assertArrayEquals(new byte[] {-4, -6, -7},\n\t\t\tByteHelper.readBinaryCodedLengthBytes(new byte[] {-6, -4, -6, -7, -8}, 1));\n\t\tAssert.assertArrayEquals(new byte[] {-3, -4, -5, -6},\n\t\t\tByteHelper.readBinaryCodedLengthBytes(new byte[] {-2, -3, -4, -5, -6}, 1));\n\t\tAssert.assertArrayEquals(new byte[] {-2, -3, -4, -5, -6, -7, -8, -9, -10},\n\t\t\tByteHelper.readBinaryCodedLengthBytes(new byte[] {-1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, 1));\n\t}\n\n\t@Test\n\tpublic void testReadFixedLengthBytes() {\n\t\tAssert.assertArrayEquals(new byte[] {}, ByteHelper.readFixedLengthBytes(new byte[0], 0, 0));\n\t}\n\n\t@Test\n\tpublic void testReadLengthCodedBinary() throws IOException {\n\t\tAssert.assertEquals(0L,\n\t\t\tByteHelper.readLengthCodedBinary(new byte[] {0}, 0));\n\t\tAssert.assertEquals(-1L,\n\t\t\tByteHelper.readLengthCodedBinary(new byte[] {-5, -1, -7, 4, -7}, 0));\n\t\tAssert.assertEquals(65_021L,\n\t\t\tByteHelper.readLengthCodedBinary(new byte[] {-3, -3, -3, 0, -3}, 0));\n\t\tAssert.assertEquals(37_119L,\n\t\t\tByteHelper.readLengthCodedBinary(new byte[] {-4, -1, -112, 1, -112}, 0));\n\t}\n\n\t@Test\n\tpublic void testReadNullTerminatedBytes() {\n\t\tAssert.assertArrayEquals(new byte[] {},\n\t\t\tByteHelper.readNullTerminatedBytes(new byte[] {0}, 0));\n\t\tAssert.assertArrayEquals(new byte[] {8},\n\t\t\tByteHelper.readNullTerminatedBytes(new byte[] {8}, 0));\n\t}\n\n\t@Test\n\tpublic void testReadUnsignedIntLittleEndian() {\n\t\tAssert.assertEquals(0L,\n\t\t\tByteHelper.readUnsignedIntLittleEndian(new byte[] {0, 0, 0, 0}, 0));\n\t}\n\n\t@Test\n\tpublic void testReadUnsignedMediumLittleEndian() {\n\t\tAssert.assertEquals(0,\n\t\t\tByteHelper.readUnsignedMediumLittleEndian(new byte[] {0, 0, 0}, 0));\n\t}\n\n\t@Test\n\tpublic void testReadUnsignedShortLittleEndian() {\n\t\tAssert.assertEquals(0,\n\t\t\tByteHelper.readUnsignedShortLittleEndian(new byte[] {0, 0}, 0));\n\t}\n\n\t@Test\n\tpublic void testWrite8ByteUnsignedIntLittleEndian() {\n\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\tByteHelper.write8ByteUnsignedIntLittleEndian(72_340_168_547_287_295L, out);\n\n\t\tAssert.assertArrayEquals(new byte[] {-1, -64, 64, 1, 0, 1, 1, 1}, out.toByteArray());\n\t}\n\n\t@Test\n\tpublic void testWriteBinaryCodedLengthBytes1() throws IOException {\n\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\tByteHelper.writeBinaryCodedLengthBytes(new byte[] {2, 4}, out);\n\n\t\tAssert.assertArrayEquals(new byte[] {2, 2, 4}, (out.toByteArray()));\n\t}\n\n\t@Test\n\tpublic void testWriteBinaryCodedLengthBytes2() throws IOException {\n\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\tByteHelper.writeBinaryCodedLengthBytes(new byte[252], out);\n\n\t\tbyte[] expected = new byte[255];\n\t\texpected[0] = -4;\n\t\texpected[1] = -4;\n\n\t\tAssert.assertArrayEquals(expected, (out.toByteArray()));\n\t}\n\n\t@Test\n\tpublic void testWriteBinaryCodedLengthBytes3() throws IOException {\n\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\tByteHelper.writeBinaryCodedLengthBytes(new byte[65536], out);\n\n\t\tbyte[] expected = new byte[65540];\n\t\texpected[0] = -3;\n\t\texpected[3] = 1;\n\n\t\tAssert.assertArrayEquals(expected, (out.toByteArray()));\n\t}\n\n\t@Test\n\tpublic void testWriteBinaryCodedLengthBytes4() throws IOException {\n\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\tByteHelper.writeBinaryCodedLengthBytes(new byte[16777216], out);\n\n\t\tbyte[] expected = new byte[16777221];\n\t\texpected[0] = -2;\n\t\texpected[4] = 1;\n\n\t\tAssert.assertArrayEquals(expected, (out.toByteArray()));\n\t}\n\n\t@Test\n\tpublic void testWriteFixedLengthBytesFromStart() {\n\t\tByteHelper.writeFixedLengthBytesFromStart(null, 0, null);\n\t}\n\n\t@Test\n\tpublic void testWriteFixedLengthBytes() {\n\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\tByteHelper.writeFixedLengthBytes(new byte[] {1, -128, 2, 0, 0}, 2, 3, out);\n\n\t\tAssert.assertArrayEquals(new byte[] {2, 0, 0}, out.toByteArray());\n\t}\n\n\t@Test\n\tpublic void testWriteNullTerminated() throws IOException {\n\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\tByteHelper.writeNullTerminated(new byte[] {3}, out);\n\n\t\tAssert.assertArrayEquals(new byte[] {3, 0}, out.toByteArray());\n\t}\n\n\t@Test\n\tpublic void testWriteNullTerminatedString() throws IOException {\n\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\tByteHelper.writeNullTerminatedString(\"5\", out);\n\n\t\tAssert.assertArrayEquals(new byte[] {53, 0}, out.toByteArray());\n\t}\n\n\t@Test\n\tpublic void testWriteUnsignedInt64LittleEndian() {\n\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\tByteHelper.writeUnsignedInt64LittleEndian(72_340_168_547_287_295L, out);\n\n\t\tAssert.assertArrayEquals(new byte[] {-1, -64, 64, 1, 0, 1, 1, 1}, out.toByteArray());\n\t}\n\n\t@Test\n\tpublic void testWriteUnsignedIntLittleEndian() {\n\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\tByteHelper.writeUnsignedIntLittleEndian(50_332_648L, out);\n\n\t\tAssert.assertArrayEquals(new byte[] {-24, 3, 0, 3}, out.toByteArray());\n\t}\n\n\t@Test\n\tpublic void testWriteUnsignedMediumLittleEndian() {\n\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\tByteHelper.writeUnsignedMediumLittleEndian(131_072, out);\n\n\t\tAssert.assertArrayEquals(new byte[] {0, 0, 2}, out.toByteArray());\n\t}\n\n\t@Test\n\tpublic void testWriteUnsignedShortLittleEndian() {\n\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\tByteHelper.writeUnsignedShortLittleEndian(1044, out);\n\n\t\tAssert.assertArrayEquals(new byte[] {20, 4}, out.toByteArray());\n\t}\n}\n"
  },
  {
    "path": "driver/src/test/java/com/alibaba/otter/canal/parse/driver/mysql/utils/MySQLPasswordEncrypterTest.java",
    "content": "package com.alibaba.otter.canal.parse.driver.mysql.utils;\n\nimport java.security.DigestException;\nimport java.security.NoSuchAlgorithmException;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class MySQLPasswordEncrypterTest {\n\n    @Test\n    public void testScrambleCachingSha2() throws DigestException {\n        byte[] bytes1 = new byte[]{73, -38, 6, -106, 14, -28, -98, -32,\n                -80, -49, -88, -66, -116, -101, -86, 25, -7, 32, 44, -118,\n                24, -128, -8, 12, 10, -38, 111, -11, 42, -111, 43, -123};\n\n        byte[] bytes2 = new byte[]{-86, 63, -63, 80, 93, 3, 105, -59, 71,\n                -41, 81, 112, 35, -29, 28, -115, -68, 16, -119, -60, -53,\n                -80, -4, -19, 60, -37, 27, -22, -23, -23, 49, -36};\n\n        Assert.assertArrayEquals(bytes1, MySQLPasswordEncrypter\n                .scrambleCachingSha2(new byte[0], new byte[0]));\n        Assert.assertArrayEquals(bytes2, MySQLPasswordEncrypter\n                .scrambleCachingSha2(\n                        new byte[]{1, 2, 3, 4, 5, 6, 7, 8}, new byte[]{1, 1}));\n    }\n\n    @Test\n    public void testScramble411() throws NoSuchAlgorithmException {\n        byte[] bytes1 = new byte[]{90, 11, -19, 60, 27, -27, 22, 92,\n                -38, 4, 40, -62, -100, 74, 17, 6, 115, -37, -119, -126};\n\n        byte[] bytes2 = new byte[]{-101, -23, 45, 38, -113, 65, -12,\n                -55, 106, 25, -88, 107, 66, 59, -104, 11, -63, 110, -23, 83};\n\n        Assert.assertArrayEquals(bytes1, MySQLPasswordEncrypter\n                .scramble411(new byte[0], new byte[0]));\n        Assert.assertArrayEquals(bytes2, MySQLPasswordEncrypter\n                .scramble411(\n                        new byte[]{1, 2, 3, 4, 5, 6, 7, 8}, new byte[]{1, 1}));\n    }\n\n    @Test\n    public void testScramble323() {\n        Assert.assertNull(MySQLPasswordEncrypter.scramble323(null, \"foo\"));\n\n        Assert.assertEquals(\"\", MySQLPasswordEncrypter.scramble323(\"\", \"foo\"));\n        Assert.assertEquals(\"X\",\n                MySQLPasswordEncrypter.scramble323(\"bar123\\tbaz\", \"a\"));\n    }\n}\n"
  },
  {
    "path": "example/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>com.alibaba.otter</groupId>\n\t\t<artifactId>canal</artifactId>\n\t\t<version>1.1.9-SNAPSHOT</version>\n\t\t<relativePath>../pom.xml</relativePath>\n\t</parent>\n\t<groupId>com.alibaba.otter</groupId>\n\t<artifactId>canal.example</artifactId>\n\t<packaging>jar</packaging>\n\t<name>canal example module for otter ${project.version}</name>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.client</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.protocol</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<!-- 客户端要使用请单独引入mq-clients依赖 -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.rocketmq</groupId>\n\t\t\t<artifactId>rocketmq-client</artifactId>\n\t\t\t<version>${rocketmq_version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.rocketmq</groupId>\n\t\t\t<artifactId>rocketmq-acl</artifactId>\n\t\t\t<version>${rocketmq_version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.rabbitmq</groupId>\n\t\t\t<artifactId>amqp-client</artifactId>\n\t\t\t<version>${rabbitmq_version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.mq-amqp</groupId>\n\t\t\t<artifactId>mq-amqp-client</artifactId>\n\t\t\t<version>${mq_amqp_client}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.kafka</groupId>\n\t\t\t<artifactId>kafka-clients</artifactId>\n\t\t\t<version>${kafka_version}</version>\n\t\t</dependency>\n\t\t<!-- Pulsar -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.pulsar</groupId>\n\t\t\t<artifactId>pulsar-client</artifactId>\n\t\t\t<version>${pulsar_version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.pulsar</groupId>\n\t\t\t<artifactId>pulsar-client-admin</artifactId>\n\t\t\t<version>${pulsar_version}</version>\n\t\t</dependency>\n\t\t<!-- test dependency -->\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\t\n\t<build>\n\t\t<plugins>\n\t\t\t<!-- deploy模块的packaging通常是jar，如果项目中没有java 源代码或资源文件，加上这一段配置使项目能通过构建 -->\n\t\t\t<plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-jar-plugin</artifactId>\n                <version>2.5</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<archive>\n\t\t\t\t\t\t<addMavenDescriptor>true</addMavenDescriptor>\n\t\t\t\t\t</archive>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-assembly-plugin</artifactId>\n\t\t\t\t<!-- 这是最新版本，推荐使用这个版本 -->\n\t\t\t\t<version>2.2.1</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>assemble</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>single</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t\t<configuration>\n\t\t\t\t\t<appendAssemblyId>false</appendAssemblyId>\n\t\t\t\t\t<attach>false</attach>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n\t<profiles>\n\t\t<profile>\n\t\t\t<id>dev</id>\n\t\t\t<activation>\n\t\t\t\t<activeByDefault>true</activeByDefault>\n\t\t\t\t<property>\n\t\t\t\t\t<name>env</name>\n\t\t\t\t\t<value>!release</value>\n\t\t\t\t</property>\n\t\t\t</activation>\n\n\t\t\t<build>\n\t\t\t\t<plugins>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<artifactId>maven-assembly-plugin</artifactId>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<!-- maven assembly插件需要一个描述文件 来告诉插件包的结构以及打包所需的文件来自哪里 -->\n\t\t\t\t\t\t\t<descriptors>\n\t\t\t\t\t\t\t\t<descriptor>${basedir}/src/main/assembly/dev.xml</descriptor>\n\t\t\t\t\t\t\t</descriptors>\n\t\t\t\t\t\t\t<finalName>canal-example</finalName>\n\t\t\t\t\t\t\t<outputDirectory>${project.build.directory}</outputDirectory>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</plugin>\n\t\t\t\t</plugins>\n\t\t\t</build>\n\n\t\t</profile>\n\n\t\t<profile>\n\t\t\t<id>release</id>\n\t\t\t<activation>\n\t\t\t\t<property>\n\t\t\t\t\t<name>env</name>\n\t\t\t\t\t<value>release</value>\n\t\t\t\t</property>\n\t\t\t</activation>\n\n\t\t\t<build>\n\t\t\t\t<plugins>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<artifactId>maven-assembly-plugin</artifactId>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<!-- 发布模式使用的maven assembly插件描述文件 -->\n\t\t\t\t\t\t\t<descriptors>\n\t\t\t\t\t\t\t\t<descriptor>${basedir}/src/main/assembly/release.xml</descriptor>\n\t\t\t\t\t\t\t</descriptors>\n\t\t\t\t\t\t\t<!-- 如果一个应用的包含多个deploy模块，如果使用同样的包名， 如果把它们复制的一个目录中可能会失败，所以包名加了 artifactId以示区分 -->\n\t\t\t\t\t\t\t<finalName>${project.artifactId}-${project.version}</finalName>\n\t\t\t\t\t\t\t<!-- scm 要求 release 模式打出的包放到顶级目录下的target子目录中 -->\n\t\t\t\t\t\t\t<outputDirectory>${project.parent.build.directory}</outputDirectory>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</plugin>\n\t\t\t\t</plugins>\n\t\t\t</build>\n\t\t</profile>\n\t</profiles>\n</project>\n"
  },
  {
    "path": "example/src/main/assembly/dev.xml",
    "content": "<assembly xmlns=\"http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\r\n\txsi:schemaLocation=\"http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd\">\r\n\t<id>dist</id>\r\n\t<formats>\r\n\t\t<format>dir</format>\r\n\t</formats>\r\n\t<includeBaseDirectory>false</includeBaseDirectory>\r\n\t<fileSets>\r\n\t\t<fileSet>\r\n\t\t\t<directory>.</directory>\r\n\t\t\t<outputDirectory>/</outputDirectory>\r\n\t\t\t<includes>\r\n\t\t\t\t<include>README*</include>\r\n\t\t\t</includes>\r\n\t\t</fileSet>\r\n\t\t<fileSet>\r\n\t\t\t<directory>./src/main/bin</directory>\r\n\t\t\t<outputDirectory>bin</outputDirectory>\r\n\t\t\t<includes>\r\n\t\t\t\t<include>**/*</include>\r\n\t\t\t</includes>\r\n\t\t\t<fileMode>0755</fileMode>\r\n\t\t</fileSet>\r\n\t\t<fileSet>\r\n\t\t\t<directory>./src/main/conf</directory>\r\n\t\t\t<outputDirectory>/conf</outputDirectory>\r\n\t\t\t<includes>\r\n\t\t\t\t<include>**/*</include>\r\n\t\t\t</includes>\r\n\t\t</fileSet>\r\n\t\t<fileSet>\r\n\t\t\t<directory>./src/main/resources</directory>\r\n\t\t\t<outputDirectory>/conf</outputDirectory>\r\n\t\t\t<includes>\r\n\t\t\t\t<include>**/*</include>\r\n\t\t\t</includes>\r\n\t\t</fileSet>\r\n\t\t<fileSet>\r\n\t\t\t<directory>target</directory>\r\n\t\t\t<outputDirectory>logs</outputDirectory>\r\n\t\t\t<excludes>\r\n\t\t\t\t<exclude>**/*</exclude>\r\n\t\t\t</excludes>\r\n\t\t</fileSet>\r\n\t</fileSets>\r\n\t<dependencySets>\r\n\t\t<dependencySet>\r\n\t\t\t<outputDirectory>lib</outputDirectory>\r\n\t\t\t<excludes>\r\n\t\t\t\t<exclude>junit:junit</exclude>\r\n\t\t\t</excludes>\r\n\t\t</dependencySet>\r\n\t</dependencySets>\r\n</assembly>\r\n"
  },
  {
    "path": "example/src/main/assembly/release.xml",
    "content": "<assembly xmlns=\"http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\r\n\txsi:schemaLocation=\"http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd\">\r\n\t<id>dist</id>\r\n\t<formats>\r\n\t\t<format>tar.gz</format>\r\n\t</formats>\r\n\t<includeBaseDirectory>false</includeBaseDirectory>\r\n\t<fileSets>\r\n\t\t<fileSet>\r\n\t\t\t<directory>.</directory>\r\n\t\t\t<outputDirectory>/</outputDirectory>\r\n\t\t\t<includes>\r\n\t\t\t\t<include>README*</include>\r\n\t\t\t</includes>\r\n\t\t</fileSet>\r\n\t\t<fileSet>\r\n\t\t\t<directory>./src/main/bin</directory>\r\n\t\t\t<outputDirectory>bin</outputDirectory>\r\n\t\t\t<includes>\r\n\t\t\t\t<include>**/*</include>\r\n\t\t\t</includes>\r\n\t\t\t<fileMode>0755</fileMode>\r\n\t\t</fileSet>\r\n\t\t<fileSet>\r\n\t\t\t<directory>./src/main/conf</directory>\r\n\t\t\t<outputDirectory>/conf</outputDirectory>\r\n\t\t\t<includes>\r\n\t\t\t\t<include>**/*</include>\r\n\t\t\t</includes>\r\n\t\t</fileSet>\r\n\t\t<fileSet>\r\n\t\t\t<directory>./src/main/resources</directory>\r\n\t\t\t<outputDirectory>/conf</outputDirectory>\r\n\t\t\t<includes>\r\n\t\t\t\t<include>**/*</include>\r\n\t\t\t</includes>\r\n\t\t</fileSet>\r\n\t\t<fileSet>\r\n\t\t\t<directory>target</directory>\r\n\t\t\t<outputDirectory>logs</outputDirectory>\r\n\t\t\t<excludes>\r\n\t\t\t\t<exclude>**/*</exclude>\r\n\t\t\t</excludes>\r\n\t\t</fileSet>\r\n\t</fileSets>\r\n\t<dependencySets>\r\n\t\t<dependencySet>\r\n\t\t\t<outputDirectory>lib</outputDirectory>\r\n\t\t\t<excludes>\r\n\t\t\t\t<exclude>junit:junit</exclude>\r\n\t\t\t</excludes>\r\n\t\t</dependencySet>\r\n\t</dependencySets>\r\n</assembly>\r\n"
  },
  {
    "path": "example/src/main/bin/init.sh",
    "content": "#! /bin/bash\ncurrent_path=`pwd`\ncase \"`uname`\" in\n    Linux)\n                bin_abs_path=$(readlink -f $(dirname $0))\n                ;;\n        *)\n                bin_abs_path=`cd $(dirname $0); pwd`\n                ;;\nesac\nbase=${bin_abs_path}/..\n\n# default values\nPORT=3306\nMYSQL_IP=\"0\"\n\n# parse arguments\nwhile getopts \"h:p:\" opt; do\n    case $opt in\n        p)\n            if [[ $OPTARG -gt 0 ]]; then\n\t\tPORT=$OPTARG\n            else\n                echo \"Invalid -p option: -$OPTARG, should be positive integer >&2\"\n                exit 1\n            fi\n            ;;\n       h)\n            MYSQL_IP=$OPTARG\n            ;;\n        \\?)\n            printUsage\n            exit 1\n            ;;\n    esac\ndone\n\nfunction printUsage\n{\n    cat << __Usage\n\nInitialise the instance config property file automatically. This tool will connect to Mysql master server and get the binlog file and position then update the instance config property file for you.\n\nUsage: $0 -p [port] -h [hostname]\nOptions:\n    -p: mysql port, default to 3306\n    -h: mysql host ip.\n    For example:\n        $0 -p 3306 -h 172.17.0.2\n\nEnjoy!!!\n\n__Usage\n}\n\nif [[ $PORT -lt 0 ]]; then\n  echo \"invalid port argument $PORT\"\n  printUsage\n  exit 1\nfi\n\n# check if mysql ip is specified\nif [[ $MYSQL_IP = \"0\" ]]; then\n  echo '-h mysql host ip argument is required.'\n  printUsage\n  exit 1\nfi\n\nMYSQL_ADDR=\"$MYSQL_IP:$PORT\"\n\nMASTER_STATUS=`mysql -ucanal -pcanal -h$MYSQL_IP -P$PORT -e 'show master status' 2>/dev/null | head -n 2 | tail -n 1`\n\nLOG_FILE=`echo \"$MASTER_STATUS\" | cut -f 1`\nLOG_POS=`echo \"$MASTER_STATUS\" | cut -f 2`\n\nINSTANCE_CONF_FILE=$base/conf/example/instance.properties\n\nif [ ! -f $INSTANCE_CONF_FILE ]; then\n  echo \"Can not find instance config file: $INSTANCE_CONF_FILE\"\n  exit 1\nfi\n\n# replace the binlog file and position\nsed -i.bak -e \"s/canal\\.instance\\.master\\.address = .*/canal\\.instance\\.master\\.address = $MYSQL_ADDR/\" -e \"s/canal\\.instance\\.master\\.journal\\.name = .*/canal\\.instance\\.master\\.journal\\.name = $LOG_FILE/\" -e \"s/canal\\.instance\\.master\\.position = .*/canal\\.instance\\.master\\.position = $LOG_POS/\" $INSTANCE_CONF_FILE\n\ncat $INSTANCE_CONF_FILE\n\necho\necho 'Above is your instance config file, check if the settings are correct'\necho\n"
  },
  {
    "path": "example/src/main/bin/startup.bat",
    "content": "@echo off\r\n@if not \"%ECHO%\" == \"\"  echo %ECHO%\r\n@if \"%OS%\" == \"Windows_NT\"  setlocal\r\n\r\nset ENV_PATH=.\\\r\nif \"%OS%\" == \"Windows_NT\" set ENV_PATH=%~dp0%\r\n\r\nset conf_dir=%ENV_PATH%\\..\\conf\r\nset logback_configurationFile=%conf_dir%\\logback.xml\r\nset client_mode=Simple\r\nif not \"%1\" == \"\" set client_mode=%1\r\n\r\nset CLASSPATH=%conf_dir%\r\nset CLASSPATH=%conf_dir%\\..\\lib\\*;%CLASSPATH%\r\n\r\nset JAVA_MEM_OPTS= -Xms128m -Xmx512m -XX:PermSize=128m\r\nset JAVA_OPTS_EXT= -Djava.awt.headless=true -Djava.net.preferIPv4Stack=false -Dapplication.codeset=UTF-8 -Dfile.encoding=UTF-8\r\nset JAVA_DEBUG_OPT= -server -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=9199,server=y,suspend=n\r\nset CANAL_OPTS= -DappName=otter-canal-example -Dlogback.configurationFile=\"%logback_configurationFile%\"\r\n\r\nset JAVA_OPTS= %JAVA_MEM_OPTS% %JAVA_OPTS_EXT% %JAVA_DEBUG_OPT% %CANAL_OPTS%\r\n\r\nif \"%client_mode%\" == \"Cluster\" (\r\n\tjava %JAVA_OPTS% -classpath \"%CLASSPATH%\" com.alibaba.otter.canal.example.ClusterCanalClientTest\r\n) else (\r\n\tjava %JAVA_OPTS% -classpath \"%CLASSPATH%\" com.alibaba.otter.canal.example.SimpleCanalClientTest\r\n)\r\n"
  },
  {
    "path": "example/src/main/bin/startup.sh",
    "content": "#!/bin/bash \n\ncurrent_path=`pwd`\ncase \"`uname`\" in\n    Linux)\n\t\tbin_abs_path=$(readlink -f $(dirname $0))\n\t\t;;\n\t*)\n\t\tbin_abs_path=`cd $(dirname $0); pwd`\n\t\t;;\nesac\nbase=${bin_abs_path}/..\nclient_mode=\"Simple\"\nlogback_configurationFile=$base/conf/logback.xml\nexport LANG=en_US.UTF-8\nexport BASE=$base\n\nif [ -f $base/bin/canal.pid ] ; then\n\techo \"found canal.pid , Please run stop.sh first ,then startup.sh\" 2>&2\n    exit 1\nfi\n\n## set java path\nif [ -z \"$JAVA\" ] ; then\n  JAVA=$(which java)\nfi\n\nALIBABA_JAVA=\"/usr/alibaba/java/bin/java\"\nTAOBAO_JAVA=\"/opt/taobao/java/bin/java\"\nif [ -z \"$JAVA\" ]; then\n  if [ -f $ALIBABA_JAVA ] ; then\n  \tJAVA=$ALIBABA_JAVA\n  elif [ -f $TAOBAO_JAVA ] ; then\n  \tJAVA=$TAOBAO_JAVA\n  else\n  \techo \"Cannot find a Java JDK. Please set either set JAVA or put java (>=1.5) in your PATH.\" 2>&2\n    exit 1\n  fi\nfi\n\ncase \"$#\" \nin\n0 ) \n\t;;\n1 )\t\n\tclient_mode=$*\n\t;;\n2 )\t\n\tif [ \"$1\" = \"debug\" ]; then\n\t\tDEBUG_PORT=$2\n\t\tDEBUG_SUSPEND=\"y\"\n\t\tJAVA_DEBUG_OPT=\"-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=$DEBUG_PORT,server=y,suspend=$DEBUG_SUSPEND\"\n\telse \n\t\tclient_mode=$1\n \tfi;;\n* )\n\techo \"THE PARAMETERS MUST BE TWO OR LESS.PLEASE CHECK AGAIN.\"\n\texit;;\nesac\n\nJavaVersion=`$JAVA -version 2>&1 |awk 'NR==1{ gsub(/\"/,\"\"); print $3 }' | awk  -F '.' '{print $1}'`\nstr=`file -L $JAVA | grep 64-bit`\n\nJAVA_OPTS=\"$JAVA_OPTS -Xss1m -XX:+AggressiveOpts -XX:-UseBiasedLocking -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$base/logs\"\nif [ $JavaVersion -ge 11 ] ; then\n  #JAVA_OPTS=\"$JAVA_OPTS -Xlog:gc*:$base_log/gc.log:time \"\n  JAVA_OPTS=\"$JAVA_OPTS\"\nelse\n  #JAVA_OPTS=\"$JAVA_OPTS -Xloggc:$base/logs/canal/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime\"\n  JAVA_OPTS=\"$JAVA_OPTS -XX:+UseFastAccessorMethods -XX:+PrintAdaptiveSizePolicy -XX:+PrintTenuringDistribution\"\nfi\n\nif [ -n \"$str\" ]; then\n\tif [ $JavaVersion -ge 11 ] ; then\n    # For G1\n    JAVA_OPTS=\"-server -Xms2g -Xmx3g -XX:+UseG1GC -XX:MaxGCPauseMillis=250 -XX:+UseGCOverheadLimit -XX:+ExplicitGCInvokesConcurrent $JAVA_OPTS\"\n  else\n\t  JAVA_OPTS=\"-server -Xms2g -Xmx3g -Xmn1g -XX:SurvivorRatio=2 -XX:PermSize=96m -XX:MaxPermSize=256m -XX:MaxTenuringThreshold=15 -XX:+DisableExplicitGC $JAVA_OPTS\"\n\tfi\nelse\n\tJAVA_OPTS=\"-server -Xms1024m -Xmx1024m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:MaxPermSize=128m $JAVA_OPTS\"\nfi\n\nJAVA_OPTS=\" $JAVA_OPTS -Djava.awt.headless=true -Djava.net.preferIPv4Stack=false -Dfile.encoding=UTF-8\"\nCANAL_OPTS=\"-DappName=otter-canal-example -Dlogback.configurationFile=$logback_configurationFile\"\n\nif [ -e $logback_configurationFile ]\nthen \n\t\n\tfor i in $base/lib/*;\n\t\tdo CLASSPATH=$i:\"$CLASSPATH\";\n\tdone\n \tCLASSPATH=\"$base/conf:$CLASSPATH\";\n \t\n \techo \"cd to $bin_abs_path for workaround relative path\"\n  \tcd $bin_abs_path\n \t\n\techo LOG CONFIGURATION : $logback_configurationFile\n\techo client mode : $client_mode \n\techo CLASSPATH :$CLASSPATH\n\tif [ $client_mode == \"Cluster\" ] ; then \n\t\t$JAVA $JAVA_OPTS $JAVA_DEBUG_OPT $CANAL_OPTS -classpath .:$CLASSPATH com.alibaba.otter.canal.example.ClusterCanalClientTest 1>>$base/bin/nohup.out 2>&1 &\n\telse \n\t\t$JAVA $JAVA_OPTS $JAVA_DEBUG_OPT $CANAL_OPTS -classpath .:$CLASSPATH com.alibaba.otter.canal.example.SimpleCanalClientTest 1>>$base/bin/nohup.out 2>&1 &\n\tfi\n\t\n\techo $! > $base/bin/canal.pid \n\techo \"cd to $current_path for continue\"\n  \tcd $current_path\nelse \n\techo \"client mode(\"$client_mode\") OR log configration file($logback_configurationFile) is not exist,please create then first!\"\nfi\n"
  },
  {
    "path": "example/src/main/bin/stop.sh",
    "content": "#!/bin/bash\n\ncygwin=false;\ncase \"`uname`\" in\n    CYGWIN*)\n        cygwin=true\n        ;;\nesac\n\nget_pid() {\t\n\tSTR=$1\n\tPID=$2\n    if $cygwin; then\n        JAVA_CMD=\"$JAVA_HOME\\bin\\java\"\n        JAVA_CMD=`cygpath --path --unix $JAVA_CMD`\n        JAVA_PID=`ps |grep $JAVA_CMD |awk '{print $1}'`\n    else\n        if [ ! -z \"$PID\" ]; then\n        \tJAVA_PID=`ps -C java -f --width 1000|grep \"$STR\"|grep \"$PID\"|grep -v grep|awk '{print $2}'`\n\t    else \n\t        JAVA_PID=`ps -C java -f --width 1000|grep \"$STR\"|grep -v grep|awk '{print $2}'`\n        fi\n    fi\n    echo $JAVA_PID;\n}\n\nbase=`dirname $0`/..\npidfile=$base/bin/canal.pid\nif [ ! -f \"$pidfile\" ];then\n\techo \"canal is not running. exists\"\n\texit\nfi\n\npid=`cat $pidfile`\nif [ \"$pid\" == \"\" ] ; then\n\tpid=`get_pid \"appName=otter-canal-example\"`\nfi\n\necho -e \"`hostname`: stopping canal $pid ... \"\nkill $pid\n\nLOOPS=0\nwhile (true); \ndo \n\tgpid=`get_pid \"appName=otter-canal-example\" \"$pid\"`\n    if [ \"$gpid\" == \"\" ] ; then\n    \techo \"Oook! cost:$LOOPS\"\n    \t`rm $pidfile`\n    \tbreak;\n    fi\n    let LOOPS=LOOPS+1\n    sleep 1\ndone"
  },
  {
    "path": "example/src/main/java/com/alibaba/otter/canal/example/AbstractCanalClientTest.java",
    "content": "package com.alibaba.otter.canal.example;\n\nimport org.slf4j.MDC;\nimport org.springframework.util.Assert;\n\nimport com.alibaba.otter.canal.client.CanalConnector;\nimport com.alibaba.otter.canal.protocol.Message;\n\n/**\n * 测试基类\n * \n * @author jianghang 2013-4-15 下午04:17:12\n * @version 1.0.4\n */\npublic class AbstractCanalClientTest extends BaseCanalClientTest {\n\n    public AbstractCanalClientTest(String destination){\n        this(destination, null);\n    }\n\n    public AbstractCanalClientTest(String destination, CanalConnector connector){\n        this.destination = destination;\n        this.connector = connector;\n    }\n\n    protected void start() {\n        Assert.notNull(connector, \"connector is null\");\n        thread = new Thread(this::process);\n\n        thread.setUncaughtExceptionHandler(handler);\n        running = true;\n        thread.start();\n    }\n\n    protected void stop() {\n        if (!running) {\n            return;\n        }\n        running = false;\n        if (thread != null) {\n            try {\n                thread.join();\n            } catch (InterruptedException e) {\n                // ignore\n            }\n        }\n\n        MDC.remove(\"destination\");\n    }\n\n    protected void process() {\n        int batchSize = 5 * 1024;\n        while (running) {\n            try {\n                MDC.put(\"destination\", destination);\n                connector.connect();\n                connector.subscribe();\n                while (running) {\n                    Message message = connector.getWithoutAck(batchSize); // 获取指定数量的数据\n                    long batchId = message.getId();\n                    int size = message.getEntries().size();\n                    if (batchId == -1 || size == 0) {\n                        // try {\n                        // Thread.sleep(1000);\n                        // } catch (InterruptedException e) {\n                        // }\n                    } else {\n                        printSummary(message, batchId, size);\n                        printEntry(message.getEntries());\n                    }\n\n                    if (batchId != -1) {\n                        connector.ack(batchId); // 提交确认\n                    }\n                }\n            } catch (Throwable e) {\n                logger.error(\"process error!\", e);\n                try {\n                    Thread.sleep(1000L);\n                } catch (InterruptedException e1) {\n                    // ignore\n                }\n\n                connector.rollback(); // 处理失败, 回滚数据\n            } finally {\n                connector.disconnect();\n                MDC.remove(\"destination\");\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "example/src/main/java/com/alibaba/otter/canal/example/BaseCanalClientTest.java",
    "content": "package com.alibaba.otter.canal.example;\n\nimport java.io.UnsupportedEncodingException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.List;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.commons.lang.SystemUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.util.CollectionUtils;\n\nimport com.alibaba.otter.canal.client.CanalConnector;\nimport com.alibaba.otter.canal.protocol.CanalEntry;\nimport com.alibaba.otter.canal.protocol.Message;\nimport com.alibaba.otter.canal.protocol.CanalEntry.*;\nimport com.google.protobuf.InvalidProtocolBufferException;\n\npublic class BaseCanalClientTest {\n\n    protected final static Logger             logger             = LoggerFactory\n        .getLogger(AbstractCanalClientTest.class);\n    protected static final String             SEP                = SystemUtils.LINE_SEPARATOR;\n    protected static final String             DATE_FORMAT        = \"yyyy-MM-dd HH:mm:ss\";\n    protected volatile boolean                running            = false;\n    protected Thread.UncaughtExceptionHandler handler            = (t, e) -> logger.error(\"parse events has an error\",\n        e);\n    protected Thread                          thread             = null;\n    protected CanalConnector                  connector;\n    protected static String                   context_format     = null;\n    protected static String                   row_format         = null;\n    protected static String                   transaction_format = null;\n    protected String                          destination;\n\n    static {\n        context_format = SEP + \"****************************************************\" + SEP;\n        context_format += \"* Batch Id: [{}] ,count : [{}] , memsize : [{}] , Time : {}\" + SEP;\n        context_format += \"* Start : [{}] \" + SEP;\n        context_format += \"* End : [{}] \" + SEP;\n        context_format += \"****************************************************\" + SEP;\n\n        row_format = SEP\n                     + \"----------------> binlog[{}:{}] , name[{},{}] , eventType : {} , executeTime : {}({}) , gtid : ({}) , delay : {} ms\"\n                     + SEP;\n\n        transaction_format = SEP + \"================> binlog[{}:{}] , executeTime : {}({}) , gtid : ({}) , delay : {}ms\"\n                             + SEP;\n\n    }\n\n    protected void printSummary(Message message, long batchId, int size) {\n        long memsize = 0;\n        for (Entry entry : message.getEntries()) {\n            memsize += entry.getHeader().getEventLength();\n        }\n\n        String startPosition = null;\n        String endPosition = null;\n        if (!CollectionUtils.isEmpty(message.getEntries())) {\n            startPosition = buildPositionForDump(message.getEntries().get(0));\n            endPosition = buildPositionForDump(message.getEntries().get(message.getEntries().size() - 1));\n        }\n\n        SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT);\n        logger.info(context_format,\n            new Object[] { batchId, size, memsize, format.format(new Date()), startPosition, endPosition });\n    }\n\n    protected String buildPositionForDump(Entry entry) {\n        long time = entry.getHeader().getExecuteTime();\n        Date date = new Date(time);\n        SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT);\n        String position = entry.getHeader().getLogfileName() + \":\" + entry.getHeader().getLogfileOffset() + \":\"\n                          + entry.getHeader().getExecuteTime() + \"(\" + format.format(date) + \")\";\n        if (StringUtils.isNotEmpty(entry.getHeader().getGtid())) {\n            position += \" gtid(\" + entry.getHeader().getGtid() + \")\";\n        }\n        return position;\n    }\n\n    protected void printEntry(List<Entry> entrys) {\n        for (Entry entry : entrys) {\n            long executeTime = entry.getHeader().getExecuteTime();\n            long delayTime = new Date().getTime() - executeTime;\n            Date date = new Date(entry.getHeader().getExecuteTime());\n            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n\n            if (entry.getEntryType() == EntryType.TRANSACTIONBEGIN\n                || entry.getEntryType() == EntryType.TRANSACTIONEND) {\n                if (entry.getEntryType() == EntryType.TRANSACTIONBEGIN) {\n                    TransactionBegin begin = null;\n                    try {\n                        begin = TransactionBegin.parseFrom(entry.getStoreValue());\n                    } catch (InvalidProtocolBufferException e) {\n                        throw new RuntimeException(\"parse event has an error , data:\" + entry.toString(), e);\n                    }\n                    // 打印事务头信息，执行的线程id，事务耗时\n                    logger.info(transaction_format,\n                        new Object[] { entry.getHeader().getLogfileName(),\n                                       String.valueOf(entry.getHeader().getLogfileOffset()),\n                                       String.valueOf(entry.getHeader().getExecuteTime()),\n                                       simpleDateFormat.format(date), entry.getHeader().getGtid(),\n                                       String.valueOf(delayTime) });\n                    logger.info(\" BEGIN ----> Thread id: {}\", begin.getThreadId());\n                    printXAInfo(begin.getPropsList());\n                } else if (entry.getEntryType() == EntryType.TRANSACTIONEND) {\n                    TransactionEnd end = null;\n                    try {\n                        end = TransactionEnd.parseFrom(entry.getStoreValue());\n                    } catch (InvalidProtocolBufferException e) {\n                        throw new RuntimeException(\"parse event has an error , data:\" + entry.toString(), e);\n                    }\n                    // 打印事务提交信息，事务id\n                    logger.info(\"----------------\\n\");\n                    logger.info(\" END ----> transaction id: {}\", end.getTransactionId());\n                    printXAInfo(end.getPropsList());\n                    logger.info(transaction_format,\n                        new Object[] { entry.getHeader().getLogfileName(),\n                                       String.valueOf(entry.getHeader().getLogfileOffset()),\n                                       String.valueOf(entry.getHeader().getExecuteTime()),\n                                       simpleDateFormat.format(date), entry.getHeader().getGtid(),\n                                       String.valueOf(delayTime) });\n                }\n\n                continue;\n            }\n\n            if (entry.getEntryType() == EntryType.ROWDATA) {\n                RowChange rowChange = null;\n                try {\n                    rowChange = RowChange.parseFrom(entry.getStoreValue());\n                } catch (Exception e) {\n                    throw new RuntimeException(\"parse event has an error , data:\" + entry.toString(), e);\n                }\n\n                EventType eventType = rowChange.getEventType();\n\n                logger.info(row_format,\n                    new Object[] { entry.getHeader().getLogfileName(),\n                                   String.valueOf(entry.getHeader().getLogfileOffset()),\n                                   entry.getHeader().getSchemaName(), entry.getHeader().getTableName(), eventType,\n                                   String.valueOf(entry.getHeader().getExecuteTime()), simpleDateFormat.format(date),\n                                   entry.getHeader().getGtid(), String.valueOf(delayTime) });\n\n                if (eventType == EventType.QUERY || rowChange.getIsDdl()) {\n                    logger.info(\"ddl : \" + rowChange.getIsDdl() + \" ,  sql ----> \" + rowChange.getSql() + SEP);\n                    continue;\n                }\n\n                printXAInfo(rowChange.getPropsList());\n                for (RowData rowData : rowChange.getRowDatasList()) {\n                    if (eventType == EventType.DELETE) {\n                        printColumn(rowData.getBeforeColumnsList());\n                    } else if (eventType == EventType.INSERT) {\n                        printColumn(rowData.getAfterColumnsList());\n                    } else {\n                        printColumn(rowData.getAfterColumnsList());\n                    }\n                }\n            }\n        }\n    }\n\n    protected void printColumn(List<Column> columns) {\n        for (Column column : columns) {\n            StringBuilder builder = new StringBuilder();\n            try {\n                if (StringUtils.containsIgnoreCase(column.getMysqlType(), \"BLOB\")\n                    || StringUtils.containsIgnoreCase(column.getMysqlType(), \"BINARY\")) {\n                    // get value bytes\n                    builder.append(\n                        column.getName() + \" : \" + new String(column.getValue().getBytes(\"ISO-8859-1\"), \"UTF-8\"));\n                } else {\n                    builder.append(column.getName() + \" : \" + column.getValue());\n                }\n            } catch (UnsupportedEncodingException e) {\n            }\n            builder.append(\"    type=\" + column.getMysqlType());\n            if (column.getUpdated()) {\n                builder.append(\"    update=\" + column.getUpdated());\n            }\n            builder.append(SEP);\n            logger.info(builder.toString());\n        }\n    }\n\n    protected void printXAInfo(List<Pair> pairs) {\n        if (pairs == null) {\n            return;\n        }\n\n        String xaType = null;\n        String xaXid = null;\n        for (Pair pair : pairs) {\n            String key = pair.getKey();\n            if (StringUtils.endsWithIgnoreCase(key, \"XA_TYPE\")) {\n                xaType = pair.getValue();\n            } else if (StringUtils.endsWithIgnoreCase(key, \"XA_XID\")) {\n                xaXid = pair.getValue();\n            }\n        }\n\n        if (xaType != null && xaXid != null) {\n            logger.info(\" ------> \" + xaType + \" \" + xaXid);\n        }\n    }\n\n    public void setConnector(CanalConnector connector) {\n        this.connector = connector;\n    }\n\n    /**\n     * 获取当前Entry的 GTID信息示例\n     *\n     * @param header\n     * @return\n     */\n    public static String getCurrentGtid(CanalEntry.Header header) {\n        List<CanalEntry.Pair> props = header.getPropsList();\n        if (props != null && props.size() > 0) {\n            for (CanalEntry.Pair pair : props) {\n                if (\"curtGtid\".equals(pair.getKey())) {\n                    return pair.getValue();\n                }\n            }\n        }\n        return \"\";\n    }\n\n    /**\n     * 获取当前Entry的 GTID Sequence No信息示例\n     *\n     * @param header\n     * @return\n     */\n    public static String getCurrentGtidSn(CanalEntry.Header header) {\n        List<CanalEntry.Pair> props = header.getPropsList();\n        if (props != null && props.size() > 0) {\n            for (CanalEntry.Pair pair : props) {\n                if (\"curtGtidSn\".equals(pair.getKey())) {\n                    return pair.getValue();\n                }\n            }\n        }\n        return \"\";\n    }\n\n    /**\n     * 获取当前Entry的 GTID Last Committed信息示例\n     *\n     * @param header\n     * @return\n     */\n    public static String getCurrentGtidLct(CanalEntry.Header header) {\n        List<CanalEntry.Pair> props = header.getPropsList();\n        if (props != null && props.size() > 0) {\n            for (CanalEntry.Pair pair : props) {\n                if (\"curtGtidLct\".equals(pair.getKey())) {\n                    return pair.getValue();\n                }\n            }\n        }\n        return \"\";\n    }\n\n}\n"
  },
  {
    "path": "example/src/main/java/com/alibaba/otter/canal/example/ClusterCanalClientTest.java",
    "content": "package com.alibaba.otter.canal.example;\n\nimport com.alibaba.otter.canal.client.CanalConnector;\nimport com.alibaba.otter.canal.client.CanalConnectors;\n\n/**\n * 集群模式的测试例子\n * \n * @author jianghang 2013-4-15 下午04:19:20\n * @version 1.0.4\n */\npublic class ClusterCanalClientTest extends AbstractCanalClientTest {\n\n    public ClusterCanalClientTest(String destination){\n        super(destination);\n    }\n\n    public static void main(String args[]) {\n        String destination = \"example\";\n\n        // 基于固定canal server的地址，建立链接，其中一台server发生crash，可以支持failover\n        // CanalConnector connector = CanalConnectors.newClusterConnector(\n        // Arrays.asList(new InetSocketAddress(\n        // AddressUtils.getHostIp(),\n        // 11111)),\n        // \"stability_test\", \"\", \"\");\n\n        // 基于zookeeper动态获取canal server的地址，建立链接，其中一台server发生crash，可以支持failover\n        CanalConnector connector = CanalConnectors.newClusterConnector(\"127.0.0.1:2181\", destination, \"canal\", \"canal\");\n\n        final ClusterCanalClientTest clientTest = new ClusterCanalClientTest(destination);\n        clientTest.setConnector(connector);\n        clientTest.start();\n\n        Runtime.getRuntime().addShutdownHook(new Thread(() -> {\n            try {\n                logger.info(\"## stop the canal client\");\n                clientTest.stop();\n            } catch (Throwable e) {\n                logger.warn(\"##something goes wrong when stopping canal:\", e);\n            } finally {\n                logger.info(\"## canal client is down.\");\n            }\n        }));\n    }\n}\n"
  },
  {
    "path": "example/src/main/java/com/alibaba/otter/canal/example/SimpleCanalClientPermanceTest.java",
    "content": "package com.alibaba.otter.canal.example;\n\nimport java.net.InetSocketAddress;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.TimeUnit;\n\nimport com.alibaba.otter.canal.client.CanalConnector;\nimport com.alibaba.otter.canal.client.CanalConnectors;\nimport com.alibaba.otter.canal.client.impl.SimpleCanalConnector;\nimport com.alibaba.otter.canal.protocol.Message;\n\npublic class SimpleCanalClientPermanceTest {\n\n    public static void main(String args[]) {\n        String destination = \"example\";\n        String ip = \"127.0.0.1\";\n        int batchSize = 1024;\n        int count = 0;\n        int sum = 0;\n        int perSum = 0;\n        long start = System.currentTimeMillis();\n        long end = 0;\n        final ArrayBlockingQueue<Long> queue = new ArrayBlockingQueue<>(100);\n        try {\n            final CanalConnector connector = CanalConnectors\n                .newSingleConnector(new InetSocketAddress(ip, 11111), destination, \"canal\", \"canal\");\n\n            Thread ackThread = new Thread(() -> {\n                while (true) {\n                    try {\n                        long batchId = queue.take();\n                        connector.ack(batchId);\n                    } catch (InterruptedException e) {\n                    }\n                }\n            });\n            ackThread.start();\n\n            ((SimpleCanalConnector) connector).setLazyParseEntry(true);\n            connector.connect();\n            connector.subscribe();\n            while (true) {\n                Message message = connector.getWithoutAck(batchSize, 100L, TimeUnit.MILLISECONDS);\n                long batchId = message.getId();\n                int size = message.getRawEntries().size();\n                sum += size;\n                perSum += size;\n                count++;\n                queue.add(batchId);\n                if (count % 10 == 0) {\n                    end = System.currentTimeMillis();\n                    if (end - start != 0) {\n                        long tps = (perSum * 1000) / (end - start);\n                        System.out.println(\" total : \" + sum + \" , current : \" + perSum + \" , cost : \" + (end - start)\n                                           + \" , tps : \" + tps);\n                        start = end;\n                        perSum = 0;\n                    }\n                }\n            }\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n    }\n\n}\n"
  },
  {
    "path": "example/src/main/java/com/alibaba/otter/canal/example/SimpleCanalClientTest.java",
    "content": "package com.alibaba.otter.canal.example;\n\nimport java.net.InetSocketAddress;\n\nimport com.alibaba.otter.canal.client.CanalConnector;\nimport com.alibaba.otter.canal.client.CanalConnectors;\nimport com.alibaba.otter.canal.common.utils.AddressUtils;\n\n/**\n * 单机模式的测试例子\n * \n * @author jianghang 2013-4-15 下午04:19:20\n * @version 1.0.4\n */\npublic class SimpleCanalClientTest extends AbstractCanalClientTest {\n\n    public SimpleCanalClientTest(String destination){\n        super(destination);\n    }\n\n    public static void main(String args[]) {\n        // 根据ip，直接创建链接，无HA的功能\n        String destination = \"example\";\n        String ip = AddressUtils.getHostIp();\n        CanalConnector connector = CanalConnectors\n            .newSingleConnector(new InetSocketAddress(ip, 11111), destination, \"canal\", \"canal\");\n\n        final SimpleCanalClientTest clientTest = new SimpleCanalClientTest(destination);\n        clientTest.setConnector(connector);\n        clientTest.start();\n        Runtime.getRuntime().addShutdownHook(new Thread(() -> {\n            try {\n                logger.info(\"## stop the canal client\");\n                clientTest.stop();\n            } catch (Throwable e) {\n                logger.warn(\"##something goes wrong when stopping canal:\", e);\n            } finally {\n                logger.info(\"## canal client is down.\");\n            }\n        }));\n    }\n\n}\n"
  },
  {
    "path": "example/src/main/java/com/alibaba/otter/canal/example/kafka/AbstractKafkaTest.java",
    "content": "package com.alibaba.otter.canal.example.kafka;\n\nimport com.alibaba.otter.canal.example.BaseCanalClientTest;\n\n/**\n * Kafka 测试基类\n *\n * @author machengyuan @ 2018-6-12\n * @version 1.0.0\n */\npublic abstract class AbstractKafkaTest extends BaseCanalClientTest {\n\n    public static String  topic     = \"example\";\n    public static Integer partition = null;\n    public static String  groupId   = \"g4\";\n    public static String  servers   = \"127.0.0.1:9092\";\n    public static String  zkServers = \"127.0.0.1:2181\";\n\n    public void sleep(long time) {\n        try {\n            Thread.sleep(time);\n        } catch (InterruptedException e) {\n        }\n    }\n}\n"
  },
  {
    "path": "example/src/main/java/com/alibaba/otter/canal/example/kafka/CanalKafkaClientExample.java",
    "content": "package com.alibaba.otter.canal.example.kafka;\n\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.util.Assert;\n\nimport com.alibaba.otter.canal.client.kafka.KafkaCanalConnector;\nimport com.alibaba.otter.canal.protocol.Message;\n\n/**\n * Kafka client example\n *\n * @author machengyuan @ 2018-6-12\n * @version 1.0.0\n */\npublic class CanalKafkaClientExample {\n\n    protected final static Logger           logger  = LoggerFactory.getLogger(CanalKafkaClientExample.class);\n\n    private KafkaCanalConnector             connector;\n\n    private static volatile boolean         running = false;\n\n    private Thread                          thread  = null;\n\n    private Thread.UncaughtExceptionHandler handler = (t, e) -> logger.error(\"parse events has an error\", e);\n\n    public CanalKafkaClientExample(String zkServers, String servers, String topic, Integer partition, String groupId){\n        connector = new KafkaCanalConnector(servers, topic, partition, groupId, null, false);\n    }\n\n    public static void main(String[] args) {\n        try {\n            final CanalKafkaClientExample kafkaCanalClientExample = new CanalKafkaClientExample(\n                AbstractKafkaTest.zkServers,\n                AbstractKafkaTest.servers,\n                AbstractKafkaTest.topic,\n                AbstractKafkaTest.partition,\n                AbstractKafkaTest.groupId);\n            logger.info(\"## start the kafka consumer: {}-{}\", AbstractKafkaTest.topic, AbstractKafkaTest.groupId);\n            kafkaCanalClientExample.start();\n            logger.info(\"## the canal kafka consumer is running now ......\");\n            Runtime.getRuntime().addShutdownHook(new Thread(() -> {\n                try {\n                    logger.info(\"## stop the kafka consumer\");\n                    kafkaCanalClientExample.stop();\n                } catch (Throwable e) {\n                    logger.warn(\"##something goes wrong when stopping kafka consumer:\", e);\n                } finally {\n                    logger.info(\"## kafka consumer is down.\");\n                }\n            }));\n            while (running)\n                ;\n        } catch (Throwable e) {\n            logger.error(\"## Something goes wrong when starting up the kafka consumer:\", e);\n            System.exit(0);\n        }\n    }\n\n    public void start() {\n        Assert.notNull(connector, \"connector is null\");\n        thread = new Thread(this::process);\n        thread.setUncaughtExceptionHandler(handler);\n        thread.start();\n        running = true;\n    }\n\n    public void stop() {\n        if (!running) {\n            return;\n        }\n        running = false;\n        if (thread != null) {\n            try {\n                thread.join();\n            } catch (InterruptedException e) {\n                // ignore\n            }\n        }\n    }\n\n    private void process() {\n        while (!running) {\n            try {\n                Thread.sleep(1000);\n            } catch (InterruptedException e) {\n            }\n        }\n\n        while (running) {\n            try {\n                connector.connect();\n                connector.subscribe();\n                while (running) {\n                    try {\n                        List<Message> messages = connector.getListWithoutAck(100L, TimeUnit.MILLISECONDS); // 获取message\n                        if (messages == null) {\n                            continue;\n                        }\n                        for (Message message : messages) {\n                            long batchId = message.getId();\n                            int size = message.getEntries().size();\n                            if (batchId == -1 || size == 0) {\n                                // try {\n                                // Thread.sleep(1000);\n                                // } catch (InterruptedException e) {\n                                // }\n                            } else {\n                                // printSummary(message, batchId, size);\n                                // printEntry(message.getEntries());\n                                logger.info(message.toString());\n                            }\n                        }\n\n                        connector.ack(); // 提交确认\n                    } catch (Exception e) {\n                        logger.error(e.getMessage(), e);\n                    }\n                }\n            } catch (Exception e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n\n        connector.unsubscribe();\n        connector.disconnect();\n    }\n}\n"
  },
  {
    "path": "example/src/main/java/com/alibaba/otter/canal/example/kafka/CanalKafkaClientFlatMessageExample.java",
    "content": "package com.alibaba.otter.canal.example.kafka;\n\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.util.Assert;\n\nimport com.alibaba.otter.canal.client.kafka.KafkaCanalConnector;\nimport com.alibaba.otter.canal.protocol.FlatMessage;\n\n/**\n * Kafka client example\n *\n * @author machengyuan @ 2018-6-12\n * @version 1.0.0\n */\npublic class CanalKafkaClientFlatMessageExample {\n\n    protected final static Logger           logger  = LoggerFactory.getLogger(CanalKafkaClientFlatMessageExample.class);\n\n    private KafkaCanalConnector             connector;\n\n    private static volatile boolean         running = false;\n\n    private Thread                          thread  = null;\n\n    private Thread.UncaughtExceptionHandler handler = (t, e) -> logger.error(\"parse events has an error\", e);\n\n    public CanalKafkaClientFlatMessageExample(String zkServers, String servers, String topic, Integer partition,\n                                              String groupId){\n        connector = new KafkaCanalConnector(servers, topic, partition, groupId, null, true);\n    }\n\n    public static void main(String[] args) {\n        try {\n            final CanalKafkaClientFlatMessageExample kafkaCanalClientExample = new CanalKafkaClientFlatMessageExample(\n                AbstractKafkaTest.zkServers,\n                AbstractKafkaTest.servers,\n                AbstractKafkaTest.topic,\n                AbstractKafkaTest.partition,\n                AbstractKafkaTest.groupId);\n            logger.info(\"## start the kafka consumer: {}-{}\", AbstractKafkaTest.topic, AbstractKafkaTest.groupId);\n            kafkaCanalClientExample.start();\n            logger.info(\"## the canal kafka consumer is running now ......\");\n            Runtime.getRuntime().addShutdownHook(new Thread(() -> {\n                try {\n                    logger.info(\"## stop the kafka consumer\");\n                    kafkaCanalClientExample.stop();\n                } catch (Throwable e) {\n                    logger.warn(\"##something goes wrong when stopping kafka consumer:\", e);\n                } finally {\n                    logger.info(\"## kafka consumer is down.\");\n                }\n            }));\n            while (running)\n                ;\n        } catch (Throwable e) {\n            logger.error(\"## Something goes wrong when starting up the kafka consumer:\", e);\n            System.exit(0);\n        }\n    }\n\n    public void start() {\n        Assert.notNull(connector, \"connector is null\");\n        thread = new Thread(this::process);\n        thread.setUncaughtExceptionHandler(handler);\n        thread.start();\n        running = true;\n    }\n\n    public void stop() {\n        if (!running) {\n            return;\n        }\n        running = false;\n        if (thread != null) {\n            try {\n                thread.join();\n            } catch (InterruptedException e) {\n                // ignore\n            }\n        }\n    }\n\n    private void process() {\n        while (!running) {\n            try {\n                Thread.sleep(1000);\n            } catch (InterruptedException e) {\n            }\n        }\n\n        while (running) {\n            try {\n                connector.connect();\n                connector.subscribe();\n                while (running) {\n                    try {\n                        List<FlatMessage> messages = connector.getFlatList(100L, TimeUnit.MILLISECONDS); // 获取message\n                        if (messages == null) {\n                            continue;\n                        }\n                        for (FlatMessage message : messages) {\n                            long batchId = message.getId();\n                            if (batchId == -1 || message.getData() == null) {\n                                // try {\n                                // Thread.sleep(1000);\n                                // } catch (InterruptedException e) {\n                                // }\n                            } else {\n                                // printSummary(message, batchId, size);\n                                // printEntry(message.getEntries());\n                                logger.info(message.toString());\n                            }\n                        }\n\n                        connector.ack(); // 提交确认\n                    } catch (Exception e) {\n                        logger.error(e.getMessage(), e);\n                    }\n                }\n            } catch (Exception e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n\n        connector.unsubscribe();\n        connector.disconnect();\n    }\n}\n"
  },
  {
    "path": "example/src/main/java/com/alibaba/otter/canal/example/kafka/CanalKafkaOffsetClientExample.java",
    "content": "package com.alibaba.otter.canal.example.kafka;\n\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.util.Assert;\n\nimport com.alibaba.otter.canal.client.kafka.KafkaOffsetCanalConnector;\nimport com.alibaba.otter.canal.client.kafka.protocol.KafkaMessage;\n\n/**\n * KafkaOffsetCanalConnector 使用示例\n * <p>\n * KafkaOffsetCanalConnector 与 KafkaCanalConnector 的另一区别是 auto.offset.reset\n * 默认值不同；\n * </p>\n * <p>\n * KafkaOffsetCanalConnector 默认为\n * earliest；canal-kafka-client重启后从未被消费的记录开始拉取消息，同时提供了修改 auto.offset.reset 的方法\n * setAutoOffsetReset\n * </p>\n *\n * @author panjianping @ 2018-12-18\n * @version 1.1.3\n */\npublic class CanalKafkaOffsetClientExample {\n\n    protected final static Logger           logger  = LoggerFactory.getLogger(CanalKafkaOffsetClientExample.class);\n\n    private KafkaOffsetCanalConnector       connector;\n\n    private static volatile boolean         running = false;\n\n    private Thread                          thread  = null;\n\n    private Thread.UncaughtExceptionHandler handler = (t, e) -> logger.error(\"parse events has an error\", e);\n\n    public CanalKafkaOffsetClientExample(String servers, String topic, Integer partition, String groupId){\n        connector = new KafkaOffsetCanalConnector(servers, topic, partition, groupId, false);\n    }\n\n    public static void main(String[] args) {\n        try {\n            final CanalKafkaOffsetClientExample kafkaCanalClientExample = new CanalKafkaOffsetClientExample(\n                AbstractKafkaTest.servers,\n                AbstractKafkaTest.topic,\n                AbstractKafkaTest.partition,\n                AbstractKafkaTest.groupId);\n            logger.info(\"## start the kafka consumer: {}-{}\", AbstractKafkaTest.topic, AbstractKafkaTest.groupId);\n            kafkaCanalClientExample.start();\n            logger.info(\"## the canal kafka consumer is running now ......\");\n            Runtime.getRuntime().addShutdownHook(new Thread(() -> {\n                try {\n                    logger.info(\"## stop the kafka consumer\");\n                    kafkaCanalClientExample.stop();\n                } catch (Throwable e) {\n                    logger.warn(\"##something goes wrong when stopping kafka consumer:\", e);\n                } finally {\n                    logger.info(\"## kafka consumer is down.\");\n                }\n            }));\n            while (running)\n                ;\n        } catch (Throwable e) {\n            logger.error(\"## Something goes wrong when starting up the kafka consumer:\", e);\n            System.exit(0);\n        }\n    }\n\n    public void start() {\n        Assert.notNull(connector, \"connector is null\");\n        thread = new Thread(this::process);\n        thread.setUncaughtExceptionHandler(handler);\n        thread.start();\n        running = true;\n    }\n\n    public void stop() {\n        if (!running) {\n            return;\n        }\n        running = false;\n        if (thread != null) {\n            try {\n                thread.join();\n            } catch (InterruptedException e) {\n                // ignore\n            }\n        }\n    }\n\n    private void process() {\n        while (!running) {\n            try {\n                Thread.sleep(1000);\n            } catch (InterruptedException e) {\n            }\n        }\n\n        while (running) {\n            try {\n                // 修改 AutoOffsetReset 的值，默认（earliest）\n                // connector.setAutoOffsetReset(null);\n                connector.connect();\n                connector.subscribe();\n                // 消息起始偏移地址\n                long offset = -1;\n                // 错误次数\n                int errorCount = 0;\n                while (running) {\n                    try {\n                        // 错误重试次数超过3次后，每30秒递增重试\n                        if (errorCount > 2) {\n                            Thread.sleep((errorCount - 2) * 1000 * 30);\n                        }\n\n                        List<KafkaMessage> messages = connector.getListWithoutAck(100L, TimeUnit.MILLISECONDS, offset); // 获取message\n                        if (messages == null) {\n                            continue;\n                        }\n                        for (KafkaMessage message : messages) {\n                            long batchId = message.getId();\n                            int size = message.getEntries().size();\n\n                            if (batchId == -1 || size == 0) {\n                                continue;\n                            }\n\n                            // 记录第一条消息的offset，用于处理数据异常时重新从此位置获取消息\n                            if (offset < 0) {\n                                offset = message.getOffset();\n                            }\n\n                            // printSummary(message, batchId, size);\n                            // printEntry(message.getEntries());\n                            logger.info(message.toString());\n                        }\n\n                        connector.ack(); // 提交确认\n                        // 还原offset\n                        offset = -1;\n                        errorCount = 0;\n                    } catch (Exception e) {\n                        errorCount++;\n                        logger.error(e.getMessage(), e);\n                        if (errorCount == 3) {\n                            // 重试3次后发送邮件提醒异常\n                            // mailService.sendMail(\"同步数据异常，请及时处理\", \"错误消息\");\n                        }\n                    }\n                }\n            } catch (Exception e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n\n        connector.unsubscribe();\n        connector.disconnect();\n    }\n}\n"
  },
  {
    "path": "example/src/main/java/com/alibaba/otter/canal/example/kafka/KafkaClientRunningTest.java",
    "content": "package com.alibaba.otter.canal.example.kafka;\n\nimport java.util.List;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.TimeUnit;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.client.kafka.KafkaCanalConnector;\nimport com.alibaba.otter.canal.protocol.Message;\n\n/**\n * Kafka consumer获取Message的测试例子\n *\n * @author machengyuan @ 2018-6-12\n * @version 1.0.0\n */\npublic class KafkaClientRunningTest extends AbstractKafkaTest {\n\n    private Logger  logger  = LoggerFactory.getLogger(KafkaClientRunningTest.class);\n\n    private boolean running = true;\n\n    public void testKafkaConsumer() {\n        final ExecutorService executor = Executors.newFixedThreadPool(1);\n        final KafkaCanalConnector connector = new KafkaCanalConnector(servers, topic, partition, groupId, null, false);\n        executor.submit(() -> {\n            connector.connect();\n            connector.subscribe();\n            while (running) {\n                List<Message> messages = connector.getList(3L, TimeUnit.SECONDS);\n                if (messages != null) {\n                    System.out.println(messages);\n                }\n                connector.ack();\n            }\n            connector.unsubscribe();\n            connector.disconnect();\n        });\n\n        sleep(60000);\n        running = false;\n        executor.shutdown();\n        logger.info(\"shutdown completed\");\n    }\n\n}\n"
  },
  {
    "path": "example/src/main/java/com/alibaba/otter/canal/example/rocketmq/AbstractRocektMQTest.java",
    "content": "package com.alibaba.otter.canal.example.rocketmq;\n\nimport com.alibaba.otter.canal.example.BaseCanalClientTest;\n\npublic abstract class AbstractRocektMQTest extends BaseCanalClientTest {\n\n    public static String  topic              = \"example\";\n    public static String  groupId            = \"group\";\n    public static String  nameServers        = \"127.0.0.1:9876\";\n    public static String  accessKey          = \"\";\n    public static String  secretKey          = \"\";\n    public static boolean enableMessageTrace = false;\n    public static String  accessChannel      = \"local\";\n    public static String  namespace          = \"\";\n}\n"
  },
  {
    "path": "example/src/main/java/com/alibaba/otter/canal/example/rocketmq/CanalRocketMQClientExample.java",
    "content": "package com.alibaba.otter.canal.example.rocketmq;\n\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.util.Assert;\n\nimport com.alibaba.otter.canal.client.rocketmq.RocketMQCanalConnector;\nimport com.alibaba.otter.canal.protocol.Message;\n\n/**\n * RocketMQ client example\n *\n * @author machengyuan @ 2018-6-12\n * @version 1.0.0\n */\npublic class CanalRocketMQClientExample extends AbstractRocektMQTest {\n\n    protected final static Logger           logger  = LoggerFactory.getLogger(CanalRocketMQClientExample.class);\n\n    private RocketMQCanalConnector          connector;\n\n    private static volatile boolean         running = false;\n\n    private Thread                          thread  = null;\n\n    private Thread.UncaughtExceptionHandler handler = (t, e) -> logger.error(\"parse events has an error\", e);\n\n    public CanalRocketMQClientExample(String nameServers, String topic, String groupId){\n        connector = new RocketMQCanalConnector(nameServers, topic, groupId, 500, false);\n    }\n\n    public CanalRocketMQClientExample(String nameServers, String topic, String groupId, boolean enableMessageTrace,\n                                      String accessKey, String secretKey, String accessChannel, String namespace){\n        connector = new RocketMQCanalConnector(nameServers,\n            topic,\n            groupId,\n            accessKey,\n            secretKey,\n            -1,\n            false,\n            enableMessageTrace,\n            null,\n            accessChannel,\n            namespace);\n    }\n\n    public static void main(String[] args) {\n        try {\n            final CanalRocketMQClientExample rocketMQClientExample = new CanalRocketMQClientExample(nameServers,\n                topic,\n                groupId,\n                enableMessageTrace,\n                accessKey,\n                secretKey,\n                accessChannel,\n                namespace);\n            logger.info(\"## Start the rocketmq consumer: {}-{}\", topic, groupId);\n            rocketMQClientExample.start();\n            logger.info(\"## The canal rocketmq consumer is running now ......\");\n            Runtime.getRuntime().addShutdownHook(new Thread(() -> {\n                try {\n                    logger.info(\"## Stop the rocketmq consumer\");\n                    rocketMQClientExample.stop();\n                } catch (Throwable e) {\n                    logger.warn(\"## Something goes wrong when stopping rocketmq consumer:\", e);\n                } finally {\n                    logger.info(\"## Rocketmq consumer is down.\");\n                }\n            }));\n            while (running)\n                ;\n        } catch (Throwable e) {\n            logger.error(\"## Something going wrong when starting up the rocketmq consumer:\", e);\n            System.exit(0);\n        }\n    }\n\n    public void start() {\n        Assert.notNull(connector, \"connector is null\");\n        thread = new Thread(this::process);\n        thread.setUncaughtExceptionHandler(handler);\n        thread.start();\n        running = true;\n    }\n\n    public void stop() {\n        if (!running) {\n            return;\n        }\n        running = false;\n        if (thread != null) {\n            try {\n                thread.join();\n            } catch (InterruptedException e) {\n                // ignore\n            }\n        }\n    }\n\n    private void process() {\n        while (!running) {\n            try {\n                Thread.sleep(1000);\n            } catch (InterruptedException e) {\n            }\n        }\n\n        while (running) {\n            try {\n                connector.connect();\n                connector.subscribe();\n                while (running) {\n                    List<Message> messages = connector.getListWithoutAck(1000L, TimeUnit.MILLISECONDS); // 获取message\n                    for (Message message : messages) {\n                        long batchId = message.getId();\n                        int size = message.getEntries().size();\n                        if (batchId == -1 || size == 0) {\n                            // try {\n                            // Thread.sleep(1000);\n                            // } catch (InterruptedException e) {\n                            // }\n                        } else {\n                            printSummary(message, batchId, size);\n                            printEntry(message.getEntries());\n                            // logger.info(message.toString());\n                        }\n                    }\n\n                    connector.ack(); // 提交确认\n                }\n            } catch (Exception e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n\n        connector.unsubscribe();\n        // connector.stopRunning();\n    }\n}\n"
  },
  {
    "path": "example/src/main/java/com/alibaba/otter/canal/example/rocketmq/CanalRocketMQClientFlatMessageExample.java",
    "content": "package com.alibaba.otter.canal.example.rocketmq;\n\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.util.Assert;\n\nimport com.alibaba.otter.canal.client.rocketmq.RocketMQCanalConnector;\nimport com.alibaba.otter.canal.protocol.FlatMessage;\n\n/**\n * RocketMQ client example\n *\n * @author machengyuan @ 2018-6-12\n * @version 1.0.0\n */\npublic class CanalRocketMQClientFlatMessageExample extends AbstractRocektMQTest {\n\n    protected final static Logger           logger  = LoggerFactory\n        .getLogger(CanalRocketMQClientFlatMessageExample.class);\n\n    private RocketMQCanalConnector          connector;\n\n    private static volatile boolean         running = false;\n\n    private Thread                          thread  = null;\n\n    private Thread.UncaughtExceptionHandler handler = (t, e) -> logger.error(\"parse events has an error\", e);\n\n    public CanalRocketMQClientFlatMessageExample(String nameServers, String topic, String groupId){\n        connector = new RocketMQCanalConnector(nameServers, topic, groupId, 500, true);\n    }\n\n    public static void main(String[] args) {\n        try {\n            final CanalRocketMQClientFlatMessageExample rocketMQClientExample = new CanalRocketMQClientFlatMessageExample(\n                nameServers,\n                topic,\n                groupId);\n            logger.info(\"## Start the rocketmq consumer: {}-{}\", topic, groupId);\n            rocketMQClientExample.start();\n            logger.info(\"## The canal rocketmq consumer is running now ......\");\n            Runtime.getRuntime().addShutdownHook(new Thread(() -> {\n                try {\n                    logger.info(\"## Stop the rocketmq consumer\");\n                    rocketMQClientExample.stop();\n                } catch (Throwable e) {\n                    logger.warn(\"## Something goes wrong when stopping rocketmq consumer:\", e);\n                } finally {\n                    logger.info(\"## Rocketmq consumer is down.\");\n                }\n            }));\n            while (running)\n                ;\n        } catch (Throwable e) {\n            logger.error(\"## Something going wrong when starting up the rocketmq consumer:\", e);\n            System.exit(0);\n        }\n    }\n\n    public void start() {\n        Assert.notNull(connector, \"connector is null\");\n        thread = new Thread(this::process);\n        thread.setUncaughtExceptionHandler(handler);\n        thread.start();\n        running = true;\n    }\n\n    public void stop() {\n        if (!running) {\n            return;\n        }\n        running = false;\n        if (thread != null) {\n            try {\n                thread.join();\n            } catch (InterruptedException e) {\n                // ignore\n            }\n        }\n    }\n\n    private void process() {\n        while (!running) {\n            try {\n                Thread.sleep(1000);\n            } catch (InterruptedException e) {\n            }\n        }\n\n        while (running) {\n            try {\n                connector.connect();\n                connector.subscribe();\n                while (running) {\n                    List<FlatMessage> messages = connector.getFlatList(100L, TimeUnit.MILLISECONDS); // 获取message\n                    for (FlatMessage message : messages) {\n                        long batchId = message.getId();\n                        if (batchId == -1 || message.getData() == null) {\n                            // try {\n                            // Thread.sleep(1000);\n                            // } catch (InterruptedException e) {\n                            // }\n                        } else {\n                            logger.info(message.toString());\n                        }\n                    }\n\n                    connector.ack(); // 提交确认\n                }\n            } catch (Exception e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n\n        connector.unsubscribe();\n        // connector.stopRunning();\n    }\n}\n"
  },
  {
    "path": "example/src/main/resources/logback.xml",
    "content": "<configuration scan=\"true\" scanPeriod=\" 5 seconds\">\n\n\t<jmxConfigurator />\n\t<appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n\t\t<encoder>\n\t\t\t<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{56} - %msg%n\n\t\t\t</pattern>\n\t\t</encoder>\n\t</appender>\n\t\n\t<appender name=\"ENTRY_LOG\" class=\"ch.qos.logback.core.ConsoleAppender\">\n\t\t<encoder>\n\t\t\t<pattern>%msg</pattern>\n\t\t</encoder>\n\t</appender>\n\t\n\t<logger name=\"com.alibaba.otter.canal.example.AbstractCanalClientTest\" additivity=\"false\">  \n        <level value=\"INFO\" />  \n        <appender-ref ref=\"ENTRY_LOG\" />\n    </logger>\n\t\n\t<root level=\"INFO\">\n\t\t<appender-ref ref=\"STDOUT\"/>\n\t</root>\n</configuration>"
  },
  {
    "path": "filter/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>com.alibaba.otter</groupId>\n\t\t<artifactId>canal</artifactId>\n\t\t<version>1.1.9-SNAPSHOT</version>\n\t\t<relativePath>../pom.xml</relativePath>\n\t</parent>\n\t<groupId>com.alibaba.otter</groupId>\n\t<artifactId>canal.filter</artifactId>\n\t<packaging>jar</packaging>\n\t<name>canal sink module for otter ${project.version}</name>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.common</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.protocol</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.googlecode.aviator</groupId>\n\t\t\t<artifactId>aviator</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>oro</groupId>\n\t\t\t<artifactId>oro</artifactId>\n\t\t</dependency>\n\t\t<!-- test dependency -->\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "filter/src/main/java/com/alibaba/otter/canal/filter/CanalEventFilter.java",
    "content": "package com.alibaba.otter.canal.filter;\n\nimport com.alibaba.otter.canal.filter.exception.CanalFilterException;\n\n/**\n * 数据过滤机制\n * \n * @author jianghang 2012-7-20 下午03:51:27\n */\npublic interface CanalEventFilter<T> {\n\n    boolean filter(T event) throws CanalFilterException;\n}\n"
  },
  {
    "path": "filter/src/main/java/com/alibaba/otter/canal/filter/PatternUtils.java",
    "content": "package com.alibaba.otter.canal.filter;\n\nimport java.util.Map;\n\nimport org.apache.oro.text.regex.MalformedPatternException;\nimport org.apache.oro.text.regex.Pattern;\nimport org.apache.oro.text.regex.PatternCompiler;\nimport org.apache.oro.text.regex.Perl5Compiler;\n\nimport com.google.common.cache.CacheBuilder;\nimport com.google.common.collect.MigrateMap;\n\npublic class PatternUtils {\n\n    private static Map<String, Pattern> patterns = MigrateMap.makeComputingMap(CacheBuilder.newBuilder().softValues(),\n            pattern -> {\n                try {\n                    PatternCompiler pc = new Perl5Compiler();\n                    return pc.compile(pattern,\n                        Perl5Compiler.CASE_INSENSITIVE_MASK\n                                | Perl5Compiler.READ_ONLY_MASK\n                                | Perl5Compiler.SINGLELINE_MASK);\n                } catch (MalformedPatternException e) {\n                    throw new RuntimeException(e);\n                }\n            });\n\n    public static Pattern getPattern(String pattern) {\n        return patterns.get(pattern);\n    }\n\n    public static void clear() {\n        patterns.clear();\n    }\n}\n"
  },
  {
    "path": "filter/src/main/java/com/alibaba/otter/canal/filter/aviater/AviaterELFilter.java",
    "content": "package com.alibaba.otter.canal.filter.aviater;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.apache.commons.lang.StringUtils;\n\nimport com.alibaba.otter.canal.filter.CanalEventFilter;\nimport com.alibaba.otter.canal.filter.exception.CanalFilterException;\nimport com.alibaba.otter.canal.protocol.CanalEntry;\nimport com.googlecode.aviator.AviatorEvaluator;\n\n/**\n * 基于aviater el表达式的匹配过滤\n * \n * @author jianghang 2012-7-23 上午10:46:32\n */\npublic class AviaterELFilter implements CanalEventFilter<CanalEntry.Entry> {\n\n    public static final String ROOT_KEY = \"entry\";\n    private String             expression;\n\n    public AviaterELFilter(String expression){\n        this.expression = expression;\n    }\n\n    public boolean filter(CanalEntry.Entry entry) throws CanalFilterException {\n        if (StringUtils.isEmpty(expression)) {\n            return true;\n        }\n\n        Map<String, Object> env = new HashMap<>();\n        env.put(ROOT_KEY, entry);\n        return (Boolean) AviatorEvaluator.execute(expression, env);\n    }\n\n}\n"
  },
  {
    "path": "filter/src/main/java/com/alibaba/otter/canal/filter/aviater/AviaterRegexFilter.java",
    "content": "package com.alibaba.otter.canal.filter.aviater;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.lang.StringUtils;\n\nimport com.alibaba.otter.canal.filter.CanalEventFilter;\nimport com.alibaba.otter.canal.filter.exception.CanalFilterException;\nimport com.googlecode.aviator.AviatorEvaluator;\nimport com.googlecode.aviator.Expression;\n\n/**\n * 基于aviater进行tableName正则匹配的过滤算法\n * \n * @author jianghang 2012-7-20 下午06:01:34\n */\npublic class AviaterRegexFilter implements CanalEventFilter<String> {\n\n    private static final String             SPLIT             = \",\";\n    private static final String             PATTERN_SPLIT     = \"|\";\n    private static final String             FILTER_EXPRESSION = \"regex(pattern,target)\";\n    private static final RegexFunction      regexFunction     = new RegexFunction();\n    private final Expression                exp               = AviatorEvaluator.compile(FILTER_EXPRESSION, true);\n    static {\n        AviatorEvaluator.addFunction(regexFunction);\n    }\n\n    private static final Comparator<String> COMPARATOR        = new StringComparator();\n\n    final private String                    pattern;\n    final private boolean                   defaultEmptyValue;\n\n    public AviaterRegexFilter(String pattern){\n        this(pattern, true);\n    }\n\n    public AviaterRegexFilter(String pattern, boolean defaultEmptyValue){\n        this.defaultEmptyValue = defaultEmptyValue;\n        List<String> list = null;\n        if (StringUtils.isEmpty(pattern)) {\n            list = new ArrayList<>();\n        } else {\n            String[] ss = StringUtils.split(pattern, SPLIT);\n            list = Arrays.asList(ss);\n        }\n\n        // 对pattern按照从长到短的排序\n        // 因为 foo|foot 匹配 foot 会出错，原因是 foot 匹配了 foo 之后，会返回 foo，但是 foo 的长度和 foot\n        // 的长度不一样\n        list.sort(COMPARATOR);\n        // 对pattern进行头尾完全匹配\n        list = completionPattern(list);\n        this.pattern = StringUtils.join(list, PATTERN_SPLIT);\n    }\n\n    public boolean filter(String filtered) throws CanalFilterException {\n        if (StringUtils.isEmpty(pattern)) {\n            return defaultEmptyValue;\n        }\n\n        if (StringUtils.isEmpty(filtered)) {\n            return defaultEmptyValue;\n        }\n\n        Map<String, Object> env = new HashMap<>();\n        env.put(\"pattern\", pattern);\n        env.put(\"target\", filtered.toLowerCase());\n        return (Boolean) exp.execute(env);\n    }\n\n    /**\n     * 修复正则表达式匹配的问题，因为使用了 oro 的 matches，会出现：\n     * \n     * <pre>\n     * foo|foot 匹配 foot 出错，原因是 foot 匹配了 foo 之后，会返回 foo，但是 foo 的长度和 foot 的长度不一样\n     * </pre>\n     * \n     * 因此此类对正则表达式进行了从长到短的排序\n     * \n     * @author zebin.xuzb 2012-10-22 下午2:02:26\n     * @version 1.0.0\n     */\n    private static class StringComparator implements Comparator<String> {\n\n        @Override\n        public int compare(String str1, String str2) {\n            return Integer.compare(str2.length(), str1.length());\n        }\n    }\n\n    /**\n     * 修复正则表达式匹配的问题，即使按照长度递减排序，还是会出现以下问题：\n     * \n     * <pre>\n     * foooo|f.*t 匹配 fooooot 出错，原因是 fooooot 匹配了 foooo 之后，会将 fooo 和数据进行匹配，但是 foooo 的长度和 fooooot 的长度不一样\n     * </pre>\n     * \n     * 因此此类对正则表达式进行头尾完全匹配\n     * \n     * @author simon\n     * @version 1.0.0\n     */\n\n    private List<String> completionPattern(List<String> patterns) {\n        List<String> result = new ArrayList<>();\n        for (String pattern : patterns) {\n            StringBuilder stringBuilder = new StringBuilder();\n            stringBuilder.append(\"^\");\n            stringBuilder.append(pattern);\n            stringBuilder.append(\"$\");\n            result.add(stringBuilder.toString());\n        }\n        return result;\n    }\n\n    @Override\n    public String toString() {\n        return pattern;\n    }\n\n}\n"
  },
  {
    "path": "filter/src/main/java/com/alibaba/otter/canal/filter/aviater/AviaterSimpleFilter.java",
    "content": "package com.alibaba.otter.canal.filter.aviater;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.Arrays;\r\nimport java.util.HashMap;\r\nimport java.util.List;\r\nimport java.util.Map;\r\n\r\nimport org.apache.commons.lang.StringUtils;\r\n\r\nimport com.alibaba.otter.canal.filter.CanalEventFilter;\r\nimport com.alibaba.otter.canal.filter.exception.CanalFilterException;\r\nimport com.googlecode.aviator.AviatorEvaluator;\r\nimport com.googlecode.aviator.Expression;\r\n\r\n/**\r\n * 基于aviater进行tableName简单过滤计算，不支持正则匹配\r\n * \r\n * @author jianghang 2012-7-20 下午05:53:30\r\n */\r\npublic class AviaterSimpleFilter implements CanalEventFilter<String> {\r\n\r\n    private static final String SPLIT             = \",\";\r\n\r\n    private static final String FILTER_EXPRESSION = \"include(list,target)\";\r\n\r\n    private final Expression    exp               = AviatorEvaluator.compile(FILTER_EXPRESSION, true);\r\n\r\n    private final List<String>  list;\r\n\r\n    public AviaterSimpleFilter(String filterExpression){\r\n        if (StringUtils.isEmpty(filterExpression)) {\r\n            list = new ArrayList<>();\r\n        } else {\r\n            String[] ss = filterExpression.toLowerCase().split(SPLIT);\r\n            list = Arrays.asList(ss);\r\n        }\r\n    }\r\n\r\n    public boolean filter(String filtered) throws CanalFilterException {\r\n        if (list.isEmpty()) {\r\n            return true;\r\n        }\r\n        if (StringUtils.isEmpty(filtered)) {\r\n            return true;\r\n        }\r\n        Map<String, Object> env = new HashMap<>();\r\n        env.put(\"list\", list);\r\n        env.put(\"target\", filtered.toLowerCase());\r\n        return (Boolean) exp.execute(env);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "filter/src/main/java/com/alibaba/otter/canal/filter/aviater/RegexFunction.java",
    "content": "package com.alibaba.otter.canal.filter.aviater;\n\nimport java.util.Map;\n\nimport org.apache.oro.text.regex.Perl5Matcher;\n\nimport com.alibaba.otter.canal.filter.PatternUtils;\nimport com.googlecode.aviator.runtime.function.AbstractFunction;\nimport com.googlecode.aviator.runtime.function.FunctionUtils;\nimport com.googlecode.aviator.runtime.type.AviatorBoolean;\nimport com.googlecode.aviator.runtime.type.AviatorObject;\n\n/**\n * 提供aviator regex的代码扩展\n *\n * @author jianghang 2012-7-23 上午10:29:23\n */\npublic class RegexFunction extends AbstractFunction {\n\n    public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {\n        String pattern = FunctionUtils.getStringValue(arg1, env);\n        String text = FunctionUtils.getStringValue(arg2, env);\n        Perl5Matcher matcher = new Perl5Matcher();\n        boolean isMatch = matcher.matches(text, PatternUtils.getPattern(pattern));\n        return AviatorBoolean.valueOf(isMatch);\n    }\n\n    public String getName() {\n        return \"regex\";\n    }\n\n}\n"
  },
  {
    "path": "filter/src/main/java/com/alibaba/otter/canal/filter/exception/CanalFilterException.java",
    "content": "package com.alibaba.otter.canal.filter.exception;\r\n\r\nimport com.alibaba.otter.canal.common.CanalException;\r\n\r\n/**\r\n * canal 异常定义\r\n * \r\n * @author jianghang 2012-6-15 下午04:57:35\r\n * @version 1.0.0\r\n */\r\npublic class CanalFilterException extends CanalException {\r\n\r\n    private static final long serialVersionUID = -7288830284122672209L;\r\n\r\n    public CanalFilterException(String errorCode){\r\n        super(errorCode);\r\n    }\r\n\r\n    public CanalFilterException(String errorCode, Throwable cause){\r\n        super(errorCode, cause);\r\n    }\r\n\r\n    public CanalFilterException(String errorCode, String errorDesc){\r\n        super(errorCode + \":\" + errorDesc);\r\n    }\r\n\r\n    public CanalFilterException(String errorCode, String errorDesc, Throwable cause){\r\n        super(errorCode + \":\" + errorDesc, cause);\r\n    }\r\n\r\n    public CanalFilterException(Throwable cause){\r\n        super(cause);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "filter/src/test/java/com/alibaba/otter/canal/filter/AviaterFilterTest.java",
    "content": "package com.alibaba.otter.canal.filter;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.filter.aviater.AviaterELFilter;\nimport com.alibaba.otter.canal.filter.aviater.AviaterRegexFilter;\nimport com.alibaba.otter.canal.filter.aviater.AviaterSimpleFilter;\nimport com.alibaba.otter.canal.protocol.CanalEntry;\n\npublic class AviaterFilterTest {\n\n    @Test\n    public void test_simple() {\n        AviaterSimpleFilter filter = new AviaterSimpleFilter(\"s1.t1,s2.t2\");\n        boolean result = filter.filter(\"s1.t1\");\n        Assert.assertEquals(true, result);\n\n        result = filter.filter(\"s1.t2\");\n        Assert.assertEquals(false, result);\n\n        result = filter.filter(\"\");\n        Assert.assertEquals(true, result);\n\n        result = filter.filter(\"s1.t1,s2.t2\");\n        Assert.assertEquals(false, result);\n\n        result = filter.filter(\"s2.t2\");\n        Assert.assertEquals(true, result);\n    }\n\n    @Test\n    public void test_regex() {\n        AviaterRegexFilter filter = new AviaterRegexFilter(\"s1\\\\..*,s2\\\\..*\");\n        boolean result = filter.filter(\"s1.t1\");\n        Assert.assertEquals(true, result);\n\n        result = filter.filter(\"s1.t2\");\n        Assert.assertEquals(true, result);\n\n        result = filter.filter(\"\");\n        Assert.assertEquals(true, result);\n\n        result = filter.filter(\"s12.t1\");\n        Assert.assertEquals(false, result);\n\n        result = filter.filter(\"s2.t2\");\n        Assert.assertEquals(true, result);\n\n        result = filter.filter(\"s3.t2\");\n        Assert.assertEquals(false, result);\n\n        result = filter.filter(\"S1.S2\");\n        Assert.assertEquals(true, result);\n\n        result = filter.filter(\"S2.S1\");\n        Assert.assertEquals(true, result);\n\n        AviaterRegexFilter filter2 = new AviaterRegexFilter(\"s1\\\\..*,s2.t1\");\n\n        result = filter2.filter(\"s1.t1\");\n        Assert.assertEquals(true, result);\n\n        result = filter2.filter(\"s1.t2\");\n        Assert.assertEquals(true, result);\n\n        result = filter2.filter(\"s2.t1\");\n        Assert.assertEquals(true, result);\n\n        AviaterRegexFilter filter3 = new AviaterRegexFilter(\"foooo,f.*t\");\n\n        result = filter3.filter(\"fooooot\");\n        Assert.assertEquals(true, result);\n\n        AviaterRegexFilter filter4 = new AviaterRegexFilter(\"otter2.otter_stability1|otter1.otter_stability1|retl.retl_mark|retl.retl_buffer|retl.xdual\");\n        result = filter4.filter(\"otter1.otter_stability1\");\n        Assert.assertEquals(true, result);\n    }\n\n    @Test\n    public void testDisordered() {\n        AviaterRegexFilter filter = new AviaterRegexFilter(\"u\\\\..*,uvw\\\\..*,uv\\\\..*,a\\\\.x,a\\\\.xyz,a\\\\.xy,abc\\\\.x,abc\\\\.xyz,abc\\\\.xy,ab\\\\.x,ab\\\\.xyz,ab\\\\.xy\");\n\n        boolean result = filter.filter(\"u.abc\");\n        Assert.assertEquals(true, result);\n\n        result = filter.filter(\"ab.x\");\n        Assert.assertEquals(true, result);\n\n        result = filter.filter(\"ab.xyz1\");\n        Assert.assertEquals(false, result);\n\n        result = filter.filter(\"abc.xyz\");\n        Assert.assertEquals(true, result);\n\n        result = filter.filter(\"uv.xyz\");\n        Assert.assertEquals(true, result);\n\n    }\n\n    @Test\n    public void test_el() {\n        AviaterELFilter filter = new AviaterELFilter(\"str(entry.entryType) == 'ROWDATA'\");\n\n        CanalEntry.Entry.Builder entry = CanalEntry.Entry.newBuilder();\n        entry.setEntryType(CanalEntry.EntryType.ROWDATA);\n\n        boolean result = filter.filter(entry.build());\n        Assert.assertEquals(true, result);\n    }\n}\n"
  },
  {
    "path": "filter/src/test/java/com/alibaba/otter/canal/filter/MutliAviaterFilterTest.java",
    "content": "package com.alibaba.otter.canal.filter;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.apache.commons.lang.RandomStringUtils;\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.filter.aviater.AviaterRegexFilter;\n\npublic class MutliAviaterFilterTest {\n\n    @Test\n    public void test_simple() {\n        int count = 5;\n        ExecutorService executor = Executors.newFixedThreadPool(count);\n\n        final CountDownLatch countDown = new CountDownLatch(count);\n        final AtomicInteger successed = new AtomicInteger(0);\n        for (int i = 0; i < count; i++) {\n            executor.submit(() -> {\n                try {\n                    for (int i1 = 0; i1 < 100; i1++) {\n                        doRegexTest();\n                        // try {\n                        // Thread.sleep(10);\n                        // } catch (InterruptedException e) {\n                        // }\n                    }\n\n                    successed.incrementAndGet();\n                } finally {\n                    countDown.countDown();\n                }\n            });\n        }\n\n        try {\n            countDown.await();\n        } catch (InterruptedException e) {\n        }\n\n        Assert.assertEquals(count, successed.get());\n        executor.shutdownNow();\n    }\n\n    private void doRegexTest() {\n        AviaterRegexFilter filter3 = new AviaterRegexFilter(\"otter2.otter_stability1|otter1.otter_stability1|\"\n                                                            + RandomStringUtils.randomAlphabetic(200));\n        boolean result = filter3.filter(\"otter1.otter_stability1\");\n        Assert.assertEquals(true, result);\n        result = filter3.filter(\"otter2.otter_stability1\");\n        Assert.assertEquals(true, result);\n    }\n\n}\n"
  },
  {
    "path": "instance/core/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>com.alibaba.otter</groupId>\n\t\t<artifactId>canal</artifactId>\n\t\t<version>1.1.9-SNAPSHOT</version>\n\t\t<relativePath>../../pom.xml</relativePath>\n\t</parent>\n\t<artifactId>canal.instance.core</artifactId>\n\t<packaging>jar</packaging>\n\t<name>canal instance core module for otter ${project.version}</name>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.common</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.store</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.meta</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.parse</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "instance/core/src/main/java/com/alibaba/otter/canal/instance/core/AbstractCanalInstance.java",
    "content": "package com.alibaba.otter.canal.instance.core;\n\nimport java.util.List;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.common.AbstractCanalLifeCycle;\nimport com.alibaba.otter.canal.common.alarm.CanalAlarmHandler;\nimport com.alibaba.otter.canal.filter.aviater.AviaterRegexFilter;\nimport com.alibaba.otter.canal.meta.CanalMetaManager;\nimport com.alibaba.otter.canal.parse.CanalEventParser;\nimport com.alibaba.otter.canal.parse.ha.CanalHAController;\nimport com.alibaba.otter.canal.parse.ha.HeartBeatHAController;\nimport com.alibaba.otter.canal.parse.inbound.AbstractEventParser;\nimport com.alibaba.otter.canal.parse.inbound.group.GroupEventParser;\nimport com.alibaba.otter.canal.parse.inbound.mysql.MysqlEventParser;\nimport com.alibaba.otter.canal.parse.index.CanalLogPositionManager;\nimport com.alibaba.otter.canal.protocol.CanalEntry;\nimport com.alibaba.otter.canal.protocol.ClientIdentity;\nimport com.alibaba.otter.canal.sink.CanalEventSink;\nimport com.alibaba.otter.canal.store.CanalEventStore;\nimport com.alibaba.otter.canal.store.model.Event;\n\n/**\n * Created with Intellig IDEA. Author: yinxiu Date: 2016-01-07 Time: 22:26\n */\npublic class AbstractCanalInstance extends AbstractCanalLifeCycle implements CanalInstance {\n\n    private static final Logger                      logger = LoggerFactory.getLogger(AbstractCanalInstance.class);\n\n    protected Long                                   canalId;                                                      // 和manager交互唯一标示\n    protected String                                 destination;                                                  // 队列名字\n    protected CanalEventStore<Event>                 eventStore;                                                   // 有序队列\n\n    protected CanalEventParser                       eventParser;                                                  // 解析对应的数据信息\n    protected CanalEventSink<List<CanalEntry.Entry>> eventSink;                                                    // 链接parse和store的桥接器\n    protected CanalMetaManager                       metaManager;                                                  // 消费信息管理器\n    protected CanalAlarmHandler                      alarmHandler;                                                 // alarm报警机制\n    protected CanalMQConfig                          mqConfig;                                                     // mq的配置\n\n\n\n    @Override\n    public boolean subscribeChange(ClientIdentity identity) {\n        if (StringUtils.isNotEmpty(identity.getFilter())) {\n            logger.info(\"subscribe filter change to \" + identity.getFilter());\n            AviaterRegexFilter aviaterFilter = new AviaterRegexFilter(identity.getFilter());\n\n            boolean isGroup = (eventParser instanceof GroupEventParser);\n            if (isGroup) {\n                // 处理group的模式\n                List<CanalEventParser> eventParsers = ((GroupEventParser) eventParser).getEventParsers();\n                for (CanalEventParser singleEventParser : eventParsers) {// 需要遍历启动\n                    if(singleEventParser instanceof AbstractEventParser) {\n                        ((AbstractEventParser) singleEventParser).setEventFilter(aviaterFilter);\n                    }\n                }\n            } else {\n                if(eventParser instanceof AbstractEventParser) {\n                    ((AbstractEventParser) eventParser).setEventFilter(aviaterFilter);\n                }\n            }\n\n        }\n\n        // filter的处理规则\n        // a. parser处理数据过滤处理\n        // b. sink处理数据的路由&分发,一份parse数据经过sink后可以分发为多份，每份的数据可以根据自己的过滤规则不同而有不同的数据\n        // 后续内存版的一对多分发，可以考虑\n        return true;\n    }\n\n    @Override\n    public void start() {\n        super.start();\n        if (!metaManager.isStart()) {\n            metaManager.start();\n        }\n\n        if (!alarmHandler.isStart()) {\n            alarmHandler.start();\n        }\n\n        if (!eventStore.isStart()) {\n            eventStore.start();\n        }\n\n        if (!eventSink.isStart()) {\n            eventSink.start();\n        }\n\n        if (!eventParser.isStart()) {\n            beforeStartEventParser(eventParser);\n            eventParser.start();\n            afterStartEventParser(eventParser);\n        }\n        logger.info(\"start successful....\");\n    }\n\n    @Override\n    public void stop() {\n        super.stop();\n        logger.info(\"stop CannalInstance for {}-{} \", new Object[] { canalId, destination });\n\n        if (eventParser.isStart()) {\n            beforeStopEventParser(eventParser);\n            eventParser.stop();\n            afterStopEventParser(eventParser);\n        }\n\n        if (eventSink.isStart()) {\n            eventSink.stop();\n        }\n\n        if (eventStore.isStart()) {\n            eventStore.stop();\n        }\n\n        if (metaManager.isStart()) {\n            metaManager.stop();\n        }\n\n        if (alarmHandler.isStart()) {\n            alarmHandler.stop();\n        }\n\n        logger.info(\"stop successful....\");\n    }\n\n    protected void beforeStartEventParser(CanalEventParser eventParser) {\n\n        boolean isGroup = (eventParser instanceof GroupEventParser);\n        if (isGroup) {\n            // 处理group的模式\n            List<CanalEventParser> eventParsers = ((GroupEventParser) eventParser).getEventParsers();\n            for (CanalEventParser singleEventParser : eventParsers) {// 需要遍历启动\n                startEventParserInternal(singleEventParser, true);\n            }\n        } else {\n            startEventParserInternal(eventParser, false);\n        }\n    }\n\n    // around event parser, default impl\n    protected void afterStartEventParser(CanalEventParser eventParser) {\n        // 读取一下历史订阅的filter信息\n        List<ClientIdentity> clientIdentitys = metaManager.listAllSubscribeInfo(destination);\n        for (ClientIdentity clientIdentity : clientIdentitys) {\n            subscribeChange(clientIdentity);\n        }\n    }\n\n    // around event parser\n    protected void beforeStopEventParser(CanalEventParser eventParser) {\n        // noop\n    }\n\n    protected void afterStopEventParser(CanalEventParser eventParser) {\n\n        boolean isGroup = (eventParser instanceof GroupEventParser);\n        if (isGroup) {\n            // 处理group的模式\n            List<CanalEventParser> eventParsers = ((GroupEventParser) eventParser).getEventParsers();\n            for (CanalEventParser singleEventParser : eventParsers) {// 需要遍历启动\n                stopEventParserInternal(singleEventParser);\n            }\n        } else {\n            stopEventParserInternal(eventParser);\n        }\n    }\n\n    /**\n     * 初始化单个eventParser，不需要考虑group\n     */\n    protected void startEventParserInternal(CanalEventParser eventParser, boolean isGroup) {\n        if (eventParser instanceof AbstractEventParser) {\n            AbstractEventParser abstractEventParser = (AbstractEventParser) eventParser;\n            // 首先启动log position管理器\n            CanalLogPositionManager logPositionManager = abstractEventParser.getLogPositionManager();\n            if (!logPositionManager.isStart()) {\n                logPositionManager.start();\n            }\n        }\n\n        if (eventParser instanceof MysqlEventParser) {\n            MysqlEventParser mysqlEventParser = (MysqlEventParser) eventParser;\n            CanalHAController haController = mysqlEventParser.getHaController();\n\n            if (haController instanceof HeartBeatHAController) {\n                ((HeartBeatHAController) haController).setCanalHASwitchable(mysqlEventParser);\n            }\n\n            if (!haController.isStart()) {\n                haController.start();\n            }\n\n        }\n    }\n\n    protected void stopEventParserInternal(CanalEventParser eventParser) {\n        if (eventParser instanceof AbstractEventParser) {\n            AbstractEventParser abstractEventParser = (AbstractEventParser) eventParser;\n            // 首先启动log position管理器\n            CanalLogPositionManager logPositionManager = abstractEventParser.getLogPositionManager();\n            if (logPositionManager.isStart()) {\n                logPositionManager.stop();\n            }\n        }\n\n        if (eventParser instanceof MysqlEventParser) {\n            MysqlEventParser mysqlEventParser = (MysqlEventParser) eventParser;\n            CanalHAController haController = mysqlEventParser.getHaController();\n            if (haController.isStart()) {\n                haController.stop();\n            }\n        }\n    }\n\n    // ==================getter==================================\n    @Override\n    public String getDestination() {\n        return destination;\n    }\n\n    @Override\n    public CanalEventParser getEventParser() {\n        return eventParser;\n    }\n\n    @Override\n    public CanalEventSink getEventSink() {\n        return eventSink;\n    }\n\n    @Override\n    public CanalEventStore getEventStore() {\n        return eventStore;\n    }\n\n    @Override\n    public CanalMetaManager getMetaManager() {\n        return metaManager;\n    }\n\n    @Override\n    public CanalAlarmHandler getAlarmHandler() {\n        return alarmHandler;\n    }\n\n    @Override\n    public CanalMQConfig getMqConfig() {\n        return mqConfig;\n    }\n}\n"
  },
  {
    "path": "instance/core/src/main/java/com/alibaba/otter/canal/instance/core/CanalInstance.java",
    "content": "package com.alibaba.otter.canal.instance.core;\n\nimport com.alibaba.otter.canal.common.CanalLifeCycle;\nimport com.alibaba.otter.canal.common.alarm.CanalAlarmHandler;\nimport com.alibaba.otter.canal.meta.CanalMetaManager;\nimport com.alibaba.otter.canal.parse.CanalEventParser;\nimport com.alibaba.otter.canal.protocol.ClientIdentity;\nimport com.alibaba.otter.canal.sink.CanalEventSink;\nimport com.alibaba.otter.canal.store.CanalEventStore;\n\n/**\n * 代表单个canal实例，比如一个destination会独立一个实例\n * \n * @author jianghang 2012-7-12 下午12:04:58\n * @version 1.0.0\n */\npublic interface CanalInstance extends CanalLifeCycle {\n\n    String getDestination();\n\n    CanalEventParser getEventParser();\n\n    CanalEventSink getEventSink();\n\n    CanalEventStore getEventStore();\n\n    CanalMetaManager getMetaManager();\n\n    CanalAlarmHandler getAlarmHandler();\n\n    /**\n     * 客户端发生订阅/取消订阅行为\n     */\n    boolean subscribeChange(ClientIdentity identity);\n\n    CanalMQConfig getMqConfig();\n}\n"
  },
  {
    "path": "instance/core/src/main/java/com/alibaba/otter/canal/instance/core/CanalInstanceGenerator.java",
    "content": "package com.alibaba.otter.canal.instance.core;\n\n/**\n * @author zebin.xuzb @ 2012-7-12\n * @version 1.0.0\n */\npublic interface CanalInstanceGenerator {\n\n    /**\n     * 通过 destination 产生特定的 {@link CanalInstance}\n     * \n     * @param destination\n     * @return\n     */\n    CanalInstance generate(String destination);\n}\n"
  },
  {
    "path": "instance/core/src/main/java/com/alibaba/otter/canal/instance/core/CanalMQConfig.java",
    "content": "package com.alibaba.otter.canal.instance.core;\n\npublic class CanalMQConfig {\n\n    private String  topic;\n    private Integer partition;\n    private Integer partitionsNum;\n    private String  partitionHash;\n    private String  dynamicTopic;\n    private String  dynamicTopicPartitionNum;\n    private Boolean enableDynamicQueuePartition;\n\n    public String getTopic() {\n        return topic;\n    }\n\n    public void setTopic(String topic) {\n        this.topic = topic;\n    }\n\n    public Integer getPartition() {\n        return partition;\n    }\n\n    public void setPartition(Integer partition) {\n        this.partition = partition;\n    }\n\n    public Integer getPartitionsNum() {\n        return partitionsNum;\n    }\n\n    public void setPartitionsNum(Integer partitionsNum) {\n        this.partitionsNum = partitionsNum;\n    }\n\n    public String getPartitionHash() {\n        return partitionHash;\n    }\n\n    public void setPartitionHash(String partitionHash) {\n        this.partitionHash = partitionHash;\n    }\n\n    public String getDynamicTopic() {\n        return dynamicTopic;\n    }\n\n    public void setDynamicTopic(String dynamicTopic) {\n        this.dynamicTopic = dynamicTopic;\n    }\n\n    public String getDynamicTopicPartitionNum() {\n        return dynamicTopicPartitionNum;\n    }\n\n    public void setDynamicTopicPartitionNum(String dynamicTopicPartitionNum) {\n        this.dynamicTopicPartitionNum = dynamicTopicPartitionNum;\n    }\n\n    public Boolean getEnableDynamicQueuePartition() {\n        return enableDynamicQueuePartition;\n    }\n\n    public void setEnableDynamicQueuePartition(Boolean enableDynamicQueuePartition) {\n        this.enableDynamicQueuePartition = enableDynamicQueuePartition;\n    }\n}\n"
  },
  {
    "path": "instance/manager/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>com.alibaba.otter</groupId>\n\t\t<artifactId>canal</artifactId>\n\t\t<version>1.1.9-SNAPSHOT</version>\n\t\t<relativePath>../../pom.xml</relativePath>\n\t</parent>\n\t<groupId>com.alibaba.otter</groupId>\n\t<artifactId>canal.instance.manager</artifactId>\n\t<packaging>jar</packaging>\n\t<name>canal instance manager module for otter ${project.version}</name>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.instance.core</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.instance.spring</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<!-- junit -->\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "instance/manager/src/main/java/com/alibaba/otter/canal/instance/manager/CanalConfigClient.java",
    "content": "package com.alibaba.otter.canal.instance.manager;\n\nimport com.alibaba.otter.canal.instance.manager.model.Canal;\n\n/**\n * 对应canal的配置\n * \n * @author jianghang 2012-7-4 下午03:09:17\n * @version 1.0.0\n */\npublic class CanalConfigClient {\n\n    /**\n     * 根据对应的destinantion查询Canal信息\n     */\n    public Canal findCanal(String destination) {\n        // TODO 根据自己的业务实现\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * 根据对应的destinantion查询filter信息\n     */\n    public String findFilter(String destination) {\n        // TODO 根据自己的业务实现\n        throw new UnsupportedOperationException();\n    }\n\n}\n"
  },
  {
    "path": "instance/manager/src/main/java/com/alibaba/otter/canal/instance/manager/CanalInstanceWithManager.java",
    "content": "package com.alibaba.otter.canal.instance.manager;\n\nimport java.io.File;\nimport java.net.InetSocketAddress;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.apache.commons.lang.BooleanUtils;\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.commons.lang.exception.ExceptionUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.util.CollectionUtils;\n\nimport com.alibaba.otter.canal.common.CanalException;\nimport com.alibaba.otter.canal.common.alarm.CanalAlarmHandler;\nimport com.alibaba.otter.canal.common.alarm.LogAlarmHandler;\nimport com.alibaba.otter.canal.common.utils.JsonUtils;\nimport com.alibaba.otter.canal.common.zookeeper.ZkClientx;\nimport com.alibaba.otter.canal.filter.aviater.AviaterRegexFilter;\nimport com.alibaba.otter.canal.instance.core.AbstractCanalInstance;\nimport com.alibaba.otter.canal.instance.manager.model.Canal;\nimport com.alibaba.otter.canal.instance.manager.model.CanalParameter;\nimport com.alibaba.otter.canal.instance.manager.model.CanalParameter.*;\nimport com.alibaba.otter.canal.meta.FileMixedMetaManager;\nimport com.alibaba.otter.canal.meta.MemoryMetaManager;\nimport com.alibaba.otter.canal.meta.PeriodMixedMetaManager;\nimport com.alibaba.otter.canal.meta.ZooKeeperMetaManager;\nimport com.alibaba.otter.canal.parse.CanalEventParser;\nimport com.alibaba.otter.canal.parse.ha.CanalHAController;\nimport com.alibaba.otter.canal.parse.ha.HeartBeatHAController;\nimport com.alibaba.otter.canal.parse.inbound.AbstractEventParser;\nimport com.alibaba.otter.canal.parse.inbound.group.GroupEventParser;\nimport com.alibaba.otter.canal.parse.inbound.mysql.LocalBinlogEventParser;\nimport com.alibaba.otter.canal.parse.inbound.mysql.MysqlEventParser;\nimport com.alibaba.otter.canal.parse.inbound.mysql.rds.RdsBinlogEventParserProxy;\nimport com.alibaba.otter.canal.parse.inbound.mysql.tsdb.DefaultTableMetaTSDBFactory;\nimport com.alibaba.otter.canal.parse.inbound.mysql.tsdb.TableMetaTSDB;\nimport com.alibaba.otter.canal.parse.inbound.mysql.tsdb.TableMetaTSDBBuilder;\nimport com.alibaba.otter.canal.parse.index.*;\nimport com.alibaba.otter.canal.parse.support.AuthenticationInfo;\nimport com.alibaba.otter.canal.protocol.position.EntryPosition;\nimport com.alibaba.otter.canal.sink.entry.EntryEventSink;\nimport com.alibaba.otter.canal.sink.entry.group.GroupEventSink;\nimport com.alibaba.otter.canal.store.AbstractCanalStoreScavenge;\nimport com.alibaba.otter.canal.store.memory.MemoryEventStoreWithBuffer;\nimport com.alibaba.otter.canal.store.model.BatchMode;\n\n/**\n * 单个canal实例，比如一个destination会独立一个实例\n *\n * @author jianghang 2012-7-11 下午09:26:51\n * @version 1.0.0\n */\npublic class CanalInstanceWithManager extends AbstractCanalInstance {\n\n    private static final Logger logger = LoggerFactory.getLogger(CanalInstanceWithManager.class);\n    protected String            filter;                                                          // 过滤表达式\n    protected CanalParameter    parameters;                                                      // 对应参数\n\n    public CanalInstanceWithManager(Canal canal, String filter){\n        this.parameters = canal.getCanalParameter();\n        this.canalId = canal.getId();\n        this.destination = canal.getName();\n        this.filter = filter;\n\n        logger.info(\"init CanalInstance for {}-{} with parameters:{}\", canalId, destination, parameters);\n        // 初始化报警机制\n        initAlarmHandler();\n        // 初始化metaManager\n        initMetaManager();\n        // 初始化eventStore\n        initEventStore();\n        // 初始化eventSink\n        initEventSink();\n        // 初始化eventParser;\n        initEventParser();\n\n        // 基础工具，需要提前start，会有先订阅再根据filter条件启动parse的需求\n        if (!alarmHandler.isStart()) {\n            alarmHandler.start();\n        }\n\n        if (!metaManager.isStart()) {\n            metaManager.start();\n        }\n        logger.info(\"init successful....\");\n    }\n\n    public void start() {\n        // 初始化metaManager\n        logger.info(\"start CannalInstance for {}-{} with parameters:{}\", canalId, destination, parameters);\n        super.start();\n    }\n\n    @SuppressWarnings(\"resource\")\n    protected void initAlarmHandler() {\n        logger.info(\"init alarmHandler begin...\");\n        String alarmHandlerClass = parameters.getAlarmHandlerClass();\n        String alarmHandlerPluginDir = parameters.getAlarmHandlerPluginDir();\n        if (alarmHandlerClass == null || alarmHandlerPluginDir == null) {\n            alarmHandler = new LogAlarmHandler();\n        } else {\n            try {\n                File externalLibDir = new File(alarmHandlerPluginDir);\n                File[] jarFiles = externalLibDir.listFiles((dir, name) -> name.endsWith(\".jar\"));\n                if (jarFiles == null || jarFiles.length == 0) {\n                    throw new IllegalStateException(String.format(\"alarmHandlerPluginDir [%s] can't find any name endswith \\\".jar\\\" file.\",\n                        alarmHandlerPluginDir));\n                }\n                URL[] urls = new URL[jarFiles.length];\n                for (int i = 0; i < jarFiles.length; i++) {\n                    urls[i] = jarFiles[i].toURI().toURL();\n                }\n                ClassLoader currentClassLoader = new URLClassLoader(urls,\n                    CanalInstanceWithManager.class.getClassLoader());\n                Class<CanalAlarmHandler> _alarmClass = (Class<CanalAlarmHandler>) currentClassLoader.loadClass(alarmHandlerClass);\n                alarmHandler = _alarmClass.newInstance();\n                logger.info(\"init [{}] alarm handler success.\", alarmHandlerClass);\n            } catch (Throwable e) {\n                String errorMsg = String.format(\"init alarmHandlerPluginDir [%s] alarm handler [%s] error: %s\",\n                    alarmHandlerPluginDir,\n                    alarmHandlerClass,\n                    ExceptionUtils.getFullStackTrace(e));\n                logger.error(errorMsg);\n                throw new CanalException(errorMsg, e);\n            }\n        }\n        logger.info(\"init alarmHandler end! \\n\\t load CanalAlarmHandler:{} \", alarmHandler.getClass().getName());\n    }\n\n    protected void initMetaManager() {\n        logger.info(\"init metaManager begin...\");\n        MetaMode mode = parameters.getMetaMode();\n        if (mode.isMemory()) {\n            metaManager = new MemoryMetaManager();\n        } else if (mode.isZookeeper()) {\n            metaManager = new ZooKeeperMetaManager();\n            ((ZooKeeperMetaManager) metaManager).setZkClientx(getZkclientx());\n        } else if (mode.isMixed()) {\n            // metaManager = new MixedMetaManager();\n            metaManager = new PeriodMixedMetaManager();// 换用优化过的mixed, at\n                                                       // 2012-09-11\n            // 设置内嵌的zk metaManager\n            ZooKeeperMetaManager zooKeeperMetaManager = new ZooKeeperMetaManager();\n            zooKeeperMetaManager.setZkClientx(getZkclientx());\n            ((PeriodMixedMetaManager) metaManager).setZooKeeperMetaManager(zooKeeperMetaManager);\n        } else if (mode.isLocalFile()) {\n            FileMixedMetaManager fileMixedMetaManager = new FileMixedMetaManager();\n            fileMixedMetaManager.setDataDir(parameters.getDataDir());\n            fileMixedMetaManager.setPeriod(parameters.getMetaFileFlushPeriod());\n            metaManager = fileMixedMetaManager;\n        } else {\n            throw new CanalException(\"unsupport MetaMode for \" + mode);\n        }\n\n        logger.info(\"init metaManager end! \\n\\t load CanalMetaManager:{} \", metaManager.getClass().getName());\n    }\n\n    protected void initEventStore() {\n        logger.info(\"init eventStore begin...\");\n        StorageMode mode = parameters.getStorageMode();\n        if (mode.isMemory()) {\n            MemoryEventStoreWithBuffer memoryEventStore = new MemoryEventStoreWithBuffer();\n            memoryEventStore.setBufferSize(parameters.getMemoryStorageBufferSize());\n            memoryEventStore.setBufferMemUnit(parameters.getMemoryStorageBufferMemUnit());\n            memoryEventStore.setBatchMode(BatchMode.valueOf(parameters.getStorageBatchMode().name()));\n            memoryEventStore.setDdlIsolation(parameters.getDdlIsolation());\n            memoryEventStore.setRaw(parameters.getMemoryStorageRawEntry());\n            eventStore = memoryEventStore;\n        } else if (mode.isFile()) {\n            // 后续版本支持\n            throw new CanalException(\"unsupport MetaMode for \" + mode);\n        } else if (mode.isMixed()) {\n            // 后续版本支持\n            throw new CanalException(\"unsupport MetaMode for \" + mode);\n        } else {\n            throw new CanalException(\"unsupport MetaMode for \" + mode);\n        }\n\n        if (eventStore instanceof AbstractCanalStoreScavenge) {\n            StorageScavengeMode scavengeMode = parameters.getStorageScavengeMode();\n            AbstractCanalStoreScavenge eventScavengeStore = (AbstractCanalStoreScavenge) eventStore;\n            eventScavengeStore.setDestination(destination);\n            eventScavengeStore.setCanalMetaManager(metaManager);\n            eventScavengeStore.setOnAck(scavengeMode.isOnAck());\n            eventScavengeStore.setOnFull(scavengeMode.isOnFull());\n            eventScavengeStore.setOnSchedule(scavengeMode.isOnSchedule());\n            if (scavengeMode.isOnSchedule()) {\n                eventScavengeStore.setScavengeSchedule(parameters.getScavengeSchdule());\n            }\n        }\n        logger.info(\"init eventStore end! \\n\\t load CanalEventStore:{}\", eventStore.getClass().getName());\n    }\n\n    protected void initEventSink() {\n        logger.info(\"init eventSink begin...\");\n\n        int groupSize = getGroupSize();\n        if (groupSize <= 1) {\n            eventSink = new EntryEventSink();\n        } else {\n            eventSink = new GroupEventSink(groupSize);\n        }\n\n        if (eventSink instanceof EntryEventSink) {\n            ((EntryEventSink) eventSink).setFilterTransactionEntry(false);\n            ((EntryEventSink) eventSink).setEventStore(getEventStore());\n        }\n        // if (StringUtils.isNotEmpty(filter)) {\n        // AviaterRegexFilter aviaterFilter = new AviaterRegexFilter(filter);\n        // ((AbstractCanalEventSink) eventSink).setFilter(aviaterFilter);\n        // }\n        logger.info(\"init eventSink end! \\n\\t load CanalEventSink:{}\", eventSink.getClass().getName());\n    }\n\n    protected void initEventParser() {\n        logger.info(\"init eventParser begin...\");\n        SourcingType type = parameters.getSourcingType();\n\n        List<List<DataSourcing>> groupDbAddresses = parameters.getGroupDbAddresses();\n        if (!CollectionUtils.isEmpty(groupDbAddresses)) {\n            int size = groupDbAddresses.get(0).size();// 取第一个分组的数量，主备分组的数量必须一致\n            List<CanalEventParser> eventParsers = new ArrayList<>();\n            for (int i = 0; i < size; i++) {\n                List<InetSocketAddress> dbAddress = new ArrayList<>();\n                SourcingType lastType = null;\n                for (List<DataSourcing> groupDbAddress : groupDbAddresses) {\n                    if (lastType != null && !lastType.equals(groupDbAddress.get(i).getType())) {\n                        throw new CanalException(String.format(\"master/slave Sourcing type is unmatch. %s vs %s\",\n                            lastType,\n                            groupDbAddress.get(i).getType()));\n                    }\n\n                    lastType = groupDbAddress.get(i).getType();\n                    dbAddress.add(groupDbAddress.get(i).getDbAddress());\n                }\n\n                // 初始化其中的一个分组parser\n                eventParsers.add(doInitEventParser(lastType, dbAddress));\n            }\n\n            if (eventParsers.size() > 1) { // 如果存在分组，构造分组的parser\n                GroupEventParser groupEventParser = new GroupEventParser();\n                groupEventParser.setEventParsers(eventParsers);\n                this.eventParser = groupEventParser;\n            } else {\n                this.eventParser = eventParsers.get(0);\n            }\n        } else {\n            // 创建一个空数据库地址的parser，可能使用了tddl指定地址，启动的时候才会从tddl获取地址\n            this.eventParser = doInitEventParser(type, new ArrayList<>());\n        }\n\n        logger.info(\"init eventParser end! \\n\\t load CanalEventParser:{}\", eventParser.getClass().getName());\n    }\n\n    private CanalEventParser doInitEventParser(SourcingType type, List<InetSocketAddress> dbAddresses) {\n        CanalEventParser eventParser;\n        if (type.isMysql()) {\n            MysqlEventParser mysqlEventParser = null;\n            if (StringUtils.isNotEmpty(parameters.getRdsAccesskey())\n                && StringUtils.isNotEmpty(parameters.getRdsSecretkey())\n                && StringUtils.isNotEmpty(parameters.getRdsInstanceId())) {\n\n                mysqlEventParser = new RdsBinlogEventParserProxy();\n                ((RdsBinlogEventParserProxy) mysqlEventParser).setAccesskey(parameters.getRdsAccesskey());\n                ((RdsBinlogEventParserProxy) mysqlEventParser).setSecretkey(parameters.getRdsSecretkey());\n                ((RdsBinlogEventParserProxy) mysqlEventParser).setInstanceId(parameters.getRdsInstanceId());\n            } else {\n                mysqlEventParser = new MysqlEventParser();\n            }\n            mysqlEventParser.setDestination(destination);\n            // 编码参数\n            mysqlEventParser.setConnectionCharset(parameters.getConnectionCharset());\n            // 网络相关参数1\n            mysqlEventParser.setDefaultConnectionTimeoutInSeconds(parameters.getDefaultConnectionTimeoutInSeconds());\n            mysqlEventParser.setSendBufferSize(parameters.getSendBufferSize());\n            mysqlEventParser.setReceiveBufferSize(parameters.getReceiveBufferSize());\n            // 心跳检查参数\n            mysqlEventParser.setDetectingEnable(parameters.getDetectingEnable());\n            mysqlEventParser.setDetectingSQL(parameters.getDetectingSQL());\n            mysqlEventParser.setDetectingIntervalInSeconds(parameters.getDetectingIntervalInSeconds());\n            // 数据库信息参数\n            mysqlEventParser.setSlaveId(parameters.getSlaveId());\n            if (!CollectionUtils.isEmpty(dbAddresses)) {\n                mysqlEventParser.setMasterInfo(new AuthenticationInfo(dbAddresses.get(0),\n                    parameters.getDbUsername(),\n                    parameters.getDbPassword(),\n                    parameters.getDefaultDatabaseName(),\n                    parameters.getSslInfo()));\n\n                if (dbAddresses.size() > 1) {\n                    mysqlEventParser.setStandbyInfo(new AuthenticationInfo(dbAddresses.get(1),\n                        parameters.getDbUsername(),\n                        parameters.getDbPassword(),\n                        parameters.getDefaultDatabaseName(),\n                        parameters.getSslInfo()));\n                }\n            }\n\n            if (!CollectionUtils.isEmpty(parameters.getPositions())) {\n                EntryPosition masterPosition = JsonUtils.unmarshalFromString(parameters.getPositions().get(0),\n                    EntryPosition.class);\n                // binlog位置参数\n                mysqlEventParser.setMasterPosition(masterPosition);\n\n                if (parameters.getPositions().size() > 1) {\n                    EntryPosition standbyPosition = JsonUtils.unmarshalFromString(parameters.getPositions().get(1),\n                        EntryPosition.class);\n                    mysqlEventParser.setStandbyPosition(standbyPosition);\n                }\n            }\n            mysqlEventParser.setFallbackIntervalInSeconds(parameters.getFallbackIntervalInSeconds());\n            mysqlEventParser.setProfilingEnabled(false);\n            mysqlEventParser.setFilterTableError(parameters.getFilterTableError());\n            mysqlEventParser.setParallel(parameters.getParallel());\n            mysqlEventParser.setIsGTIDMode(BooleanUtils.toBoolean(parameters.getGtidEnable()));\n            mysqlEventParser.setMultiStreamEnable(parameters.getMultiStreamEnable());\n            // tsdb\n            if (parameters.getTsdbSnapshotInterval() != null) {\n                mysqlEventParser.setTsdbSnapshotInterval(parameters.getTsdbSnapshotInterval());\n            }\n            if (parameters.getTsdbSnapshotExpire() != null) {\n                mysqlEventParser.setTsdbSnapshotExpire(parameters.getTsdbSnapshotExpire());\n            }\n            boolean tsdbEnable = BooleanUtils.toBoolean(parameters.getTsdbEnable());\n            // manager启动模式默认使用mysql tsdb机制\n            final String tsdbSpringXml = \"classpath:spring/tsdb/mysql-tsdb.xml\";\n            if (tsdbEnable) {\n                mysqlEventParser.setTableMetaTSDBFactory(new DefaultTableMetaTSDBFactory() {\n\n                    @Override\n                    public void destory(String destination) {\n                        TableMetaTSDBBuilder.destory(destination);\n                    }\n\n                    @Override\n                    public TableMetaTSDB build(String destination, String springXml) {\n                        synchronized (CanalInstanceWithManager.class) {\n                            try {\n                                System.setProperty(\"canal.instance.tsdb.url\", parameters.getTsdbJdbcUrl());\n                                System.setProperty(\"canal.instance.tsdb.dbUsername\", parameters.getTsdbJdbcUserName());\n                                System.setProperty(\"canal.instance.tsdb.dbPassword\", parameters.getTsdbJdbcPassword());\n                                System.setProperty(\"canal.instance.destination\", destination);\n\n                                return TableMetaTSDBBuilder.build(destination, tsdbSpringXml);\n                            } finally {\n                                // reset\n                                System.setProperty(\"canal.instance.destination\", \"\");\n                                System.setProperty(\"canal.instance.tsdb.url\", \"\");\n                                System.setProperty(\"canal.instance.tsdb.dbUsername\", \"\");\n                                System.setProperty(\"canal.instance.tsdb.dbPassword\", \"\");\n                            }\n                        }\n                    }\n                });\n                mysqlEventParser.setTsdbJdbcUrl(parameters.getTsdbJdbcUrl());\n                mysqlEventParser.setTsdbJdbcUserName(parameters.getTsdbJdbcUserName());\n                mysqlEventParser.setTsdbJdbcPassword(parameters.getTsdbJdbcPassword());\n                mysqlEventParser.setTsdbSpringXml(tsdbSpringXml);\n                mysqlEventParser.setEnableTsdb(tsdbEnable);\n            }\n            eventParser = mysqlEventParser;\n        } else if (type.isLocalBinlog()) {\n            LocalBinlogEventParser localBinlogEventParser = new LocalBinlogEventParser();\n            localBinlogEventParser.setDestination(destination);\n            localBinlogEventParser.setBufferSize(parameters.getReceiveBufferSize());\n            localBinlogEventParser.setConnectionCharset(parameters.getConnectionCharset());\n            localBinlogEventParser.setDirectory(parameters.getLocalBinlogDirectory());\n            localBinlogEventParser.setProfilingEnabled(false);\n            localBinlogEventParser.setDetectingEnable(parameters.getDetectingEnable());\n            localBinlogEventParser.setDetectingIntervalInSeconds(parameters.getDetectingIntervalInSeconds());\n            localBinlogEventParser.setFilterTableError(parameters.getFilterTableError());\n            localBinlogEventParser.setParallel(parameters.getParallel());\n            // 数据库信息，反查表结构时需要\n            if (!CollectionUtils.isEmpty(dbAddresses)) {\n                localBinlogEventParser.setMasterInfo(new AuthenticationInfo(dbAddresses.get(0),\n                    parameters.getDbUsername(),\n                    parameters.getDbPassword(),\n                    parameters.getDefaultDatabaseName(),\n                    parameters.getSslInfo()));\n            }\n\n            eventParser = localBinlogEventParser;\n        } else if (type.isOracle()) {\n            throw new CanalException(\"unsupport SourcingType for \" + type);\n        } else {\n            throw new CanalException(\"unsupport SourcingType for \" + type);\n        }\n\n        // add transaction support at 2012-12-06\n        if (eventParser instanceof AbstractEventParser) {\n            AbstractEventParser abstractEventParser = (AbstractEventParser) eventParser;\n            abstractEventParser.setTransactionSize(parameters.getTransactionSize());\n            abstractEventParser.setLogPositionManager(initLogPositionManager());\n            abstractEventParser.setAlarmHandler(getAlarmHandler());\n            abstractEventParser.setEventSink(getEventSink());\n\n            if (StringUtils.isNotEmpty(filter)) {\n                AviaterRegexFilter aviaterFilter = new AviaterRegexFilter(filter);\n                abstractEventParser.setEventFilter(aviaterFilter);\n            }\n\n            // 设置黑名单\n            if (StringUtils.isNotEmpty(parameters.getBlackFilter())) {\n                AviaterRegexFilter aviaterFilter = new AviaterRegexFilter(parameters.getBlackFilter());\n                abstractEventParser.setEventBlackFilter(aviaterFilter);\n            }\n        }\n        if (eventParser instanceof MysqlEventParser) {\n            MysqlEventParser mysqlEventParser = (MysqlEventParser) eventParser;\n\n            // 初始化haController，绑定与eventParser的关系，haController会控制eventParser\n            CanalHAController haController = initHaController();\n            mysqlEventParser.setHaController(haController);\n        }\n        return eventParser;\n    }\n\n    protected CanalHAController initHaController() {\n        logger.info(\"init haController begin...\");\n        HAMode haMode = parameters.getHaMode();\n        CanalHAController haController = null;\n        if (haMode.isHeartBeat()) {\n            haController = new HeartBeatHAController();\n            ((HeartBeatHAController) haController).setDetectingRetryTimes(parameters.getDetectingRetryTimes());\n            ((HeartBeatHAController) haController).setSwitchEnable(parameters.getHeartbeatHaEnable());\n        } else {\n            throw new CanalException(\"unsupport HAMode for \" + haMode);\n        }\n        logger.info(\"init haController end! \\n\\t load CanalHAController:{}\", haController.getClass().getName());\n\n        return haController;\n    }\n\n    protected CanalLogPositionManager initLogPositionManager() {\n        logger.info(\"init logPositionPersistManager begin...\");\n        IndexMode indexMode = parameters.getIndexMode();\n        CanalLogPositionManager logPositionManager;\n        if (indexMode.isMemory()) {\n            logPositionManager = new MemoryLogPositionManager();\n        } else if (indexMode.isZookeeper()) {\n            logPositionManager = new ZooKeeperLogPositionManager(getZkclientx());\n        } else if (indexMode.isMixed()) {\n            MemoryLogPositionManager memoryLogPositionManager = new MemoryLogPositionManager();\n            ZooKeeperLogPositionManager zooKeeperLogPositionManager = new ZooKeeperLogPositionManager(getZkclientx());\n            logPositionManager = new PeriodMixedLogPositionManager(memoryLogPositionManager,\n                zooKeeperLogPositionManager,\n                1000L);\n        } else if (indexMode.isMeta()) {\n            logPositionManager = new MetaLogPositionManager(metaManager);\n        } else if (indexMode.isMemoryMetaFailback()) {\n            MemoryLogPositionManager primary = new MemoryLogPositionManager();\n            MetaLogPositionManager secondary = new MetaLogPositionManager(metaManager);\n\n            logPositionManager = new FailbackLogPositionManager(primary, secondary);\n        } else {\n            throw new CanalException(\"unsupport indexMode for \" + indexMode);\n        }\n\n        logger.info(\"init logPositionManager end! \\n\\t load CanalLogPositionManager:{}\", logPositionManager.getClass()\n            .getName());\n\n        return logPositionManager;\n    }\n\n    protected void startEventParserInternal(CanalEventParser eventParser, boolean isGroup) {\n        if (eventParser instanceof AbstractEventParser) {\n            AbstractEventParser abstractEventParser = (AbstractEventParser) eventParser;\n            abstractEventParser.setAlarmHandler(getAlarmHandler());\n        }\n\n        super.startEventParserInternal(eventParser, isGroup);\n    }\n\n    private int getGroupSize() {\n        List<List<DataSourcing>> groupDbAddresses = parameters.getGroupDbAddresses();\n        if (!CollectionUtils.isEmpty(groupDbAddresses)) {\n            return groupDbAddresses.get(0).size();\n        } else {\n            // 可能是基于tddl的启动\n            return 1;\n        }\n    }\n\n    private synchronized ZkClientx getZkclientx() {\n        // 做一下排序，保证相同的机器只使用同一个链接\n        List<String> zkClusters = new ArrayList<>(parameters.getZkClusters());\n        Collections.sort(zkClusters);\n\n        return ZkClientx.getZkClient(StringUtils.join(zkClusters, \";\"));\n    }\n\n    public void setAlarmHandler(CanalAlarmHandler alarmHandler) {\n        this.alarmHandler = alarmHandler;\n    }\n\n}\n"
  },
  {
    "path": "instance/manager/src/main/java/com/alibaba/otter/canal/instance/manager/ManagerCanalInstanceGenerator.java",
    "content": "package com.alibaba.otter.canal.instance.manager;\n\nimport com.alibaba.otter.canal.instance.core.CanalInstance;\nimport com.alibaba.otter.canal.instance.core.CanalInstanceGenerator;\nimport com.alibaba.otter.canal.instance.manager.model.Canal;\n\n/**\n * 基于manager生成对应的{@linkplain CanalInstance}\n * \n * @author jianghang 2012-7-12 下午05:37:09\n * @version 1.0.0\n */\npublic class ManagerCanalInstanceGenerator implements CanalInstanceGenerator {\n\n    private CanalConfigClient canalConfigClient;\n\n    public CanalInstance generate(String destination) {\n        Canal canal = canalConfigClient.findCanal(destination);\n        String filter = canalConfigClient.findFilter(destination);\n        return new CanalInstanceWithManager(canal, filter);\n    }\n\n    // ================ setter / getter ================\n\n    public void setCanalConfigClient(CanalConfigClient canalConfigClient) {\n        this.canalConfigClient = canalConfigClient;\n    }\n\n}\n"
  },
  {
    "path": "instance/manager/src/main/java/com/alibaba/otter/canal/instance/manager/PlainCanalInstanceGenerator.java",
    "content": "package com.alibaba.otter.canal.instance.manager;\n\nimport java.util.Properties;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.support.ClassPathXmlApplicationContext;\n\nimport com.alibaba.otter.canal.common.CanalException;\nimport com.alibaba.otter.canal.instance.core.CanalInstance;\nimport com.alibaba.otter.canal.instance.core.CanalInstanceGenerator;\nimport com.alibaba.otter.canal.instance.manager.plain.PlainCanal;\nimport com.alibaba.otter.canal.instance.manager.plain.PlainCanalConfigClient;\nimport com.alibaba.otter.canal.parse.CanalEventParser;\n\n/**\n * 基于manager生成对应的{@linkplain CanalInstance}\n *\n * @author jianghang 2012-7-12 下午05:37:09\n * @version 1.0.0\n */\npublic class PlainCanalInstanceGenerator implements CanalInstanceGenerator {\n\n    private static final Logger    logger      = LoggerFactory.getLogger(PlainCanalInstanceGenerator.class);\n    private String                 springXml;\n    private PlainCanalConfigClient canalConfigClient;\n    private String                 defaultName = \"instance\";\n    private BeanFactory            beanFactory;\n    private Properties             canalConfig;\n\n    public PlainCanalInstanceGenerator(Properties canalConfig){\n        this.canalConfig = canalConfig;\n    }\n\n    public CanalInstance generate(String destination) {\n        synchronized (CanalEventParser.class) {\n            try {\n                PlainCanal canal = canalConfigClient.findInstance(destination, null);\n                if (canal == null) {\n                    throw new CanalException(\"instance : \" + destination + \" config is not found\");\n                }\n                Properties properties = canal.getProperties();\n                // merge local\n                properties.putAll(canalConfig);\n\n                // 设置动态properties,替换掉本地properties\n                com.alibaba.otter.canal.instance.spring.support.PropertyPlaceholderConfigurer.propertiesLocal.set(properties);\n                // 设置当前正在加载的通道，加载spring查找文件时会用到该变量\n                System.setProperty(\"canal.instance.destination\", destination);\n                this.beanFactory = getBeanFactory(springXml);\n                String beanName = destination;\n                if (!beanFactory.containsBean(beanName)) {\n                    beanName = defaultName;\n                }\n\n                return (CanalInstance) beanFactory.getBean(beanName);\n            } catch (Throwable e) {\n                logger.error(\"generator instance failed.\", e);\n                throw new CanalException(e);\n            } finally {\n                System.setProperty(\"canal.instance.destination\", \"\");\n                com.alibaba.otter.canal.instance.spring.support.PropertyPlaceholderConfigurer.propertiesLocal.remove();\n            }\n        }\n    }\n\n    // ================ setter / getter ================\n\n    private BeanFactory getBeanFactory(String springXml) {\n        if (!StringUtils.startsWithIgnoreCase(springXml, \"classpath:\")) {\n            springXml = \"classpath:\" + springXml;\n        }\n        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(springXml);\n        return applicationContext;\n    }\n\n    public void setCanalConfigClient(PlainCanalConfigClient canalConfigClient) {\n        this.canalConfigClient = canalConfigClient;\n    }\n\n    public void setSpringXml(String springXml) {\n        this.springXml = springXml;\n    }\n\n}\n"
  },
  {
    "path": "instance/manager/src/main/java/com/alibaba/otter/canal/instance/manager/model/Canal.java",
    "content": "package com.alibaba.otter.canal.instance.manager.model;\n\nimport java.io.Serializable;\nimport java.util.Date;\n\nimport org.apache.commons.lang.builder.ToStringBuilder;\n\nimport com.alibaba.otter.canal.common.utils.CanalToStringStyle;\n\n/**\n * 对应的canal模型对象\n * \n * @author jianghang 2012-7-4 下午02:32:39\n * @version 1.0.0\n */\npublic class Canal implements Serializable {\n\n    private static final long serialVersionUID = 8333284022624682754L;\n\n    private Long              id;\n    private String            name;                                   // 对应的名字\n    private String            desc;                                   // 描述\n    private CanalStatus       status;\n    private CanalParameter    canalParameter;                         // 参数定义\n    private Date              gmtCreate;                              // 创建时间\n    private Date              gmtModified;                            // 修改时间\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getDesc() {\n        return desc;\n    }\n\n    public void setDesc(String desc) {\n        this.desc = desc;\n    }\n\n    public CanalParameter getCanalParameter() {\n        return canalParameter;\n    }\n\n    public void setCanalParameter(CanalParameter canalParameter) {\n        this.canalParameter = canalParameter;\n    }\n\n    public CanalStatus getStatus() {\n        return status;\n    }\n\n    public void setStatus(CanalStatus status) {\n        this.status = status;\n    }\n\n    public Date getGmtCreate() {\n        return gmtCreate;\n    }\n\n    public void setGmtCreate(Date gmtCreate) {\n        this.gmtCreate = gmtCreate;\n    }\n\n    public Date getGmtModified() {\n        return gmtModified;\n    }\n\n    public void setGmtModified(Date gmtModified) {\n        this.gmtModified = gmtModified;\n    }\n\n    public String toString() {\n        return ToStringBuilder.reflectionToString(this, CanalToStringStyle.DEFAULT_STYLE);\n    }\n\n}\n"
  },
  {
    "path": "instance/manager/src/main/java/com/alibaba/otter/canal/instance/manager/model/CanalParameter.java",
    "content": "package com.alibaba.otter.canal.instance.manager.model;\n\nimport java.io.Serializable;\nimport java.net.InetSocketAddress;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.commons.lang.builder.ToStringBuilder;\n\nimport com.alibaba.otter.canal.common.utils.CanalToStringStyle;\nimport com.alibaba.otter.canal.parse.driver.mysql.ssl.SslInfo;\nimport com.alibaba.otter.canal.parse.driver.mysql.ssl.SslMode;\n\n/**\n * canal运行相关参数\n *\n * @author jianghang 2012-7-4 下午02:52:52\n * @version 1.0.0\n */\npublic class CanalParameter implements Serializable {\n\n    private static final long        serialVersionUID                   = -5893459662315430900L;\n    private Long                     canalId;\n\n    // 相关参数\n    private RunMode                  runMode                            = RunMode.EMBEDDED;          // 运行模式：嵌入式/服务式\n    private ClusterMode              clusterMode                        = ClusterMode.STANDALONE;    // 集群模式：单机/冷备/热备份\n\n    private Long                     zkClusterId;                                                    // zk集群id，为管理方便\n    private List<String>             zkClusters;                                                     // zk集群地址\n\n    private String                   dataDir                            = \"../conf\";                 // 默认本地文件数据的目录默认是conf\n    // meta相关参数\n    private MetaMode                 metaMode                           = MetaMode.MEMORY;           // meta机制\n    private Integer                  metaFileFlushPeriod                = 1000;                      // meta刷新间隔\n\n    // storage存储\n    private Integer                  transactionSize                    = 1024;                      // 支持处理的transaction事务大小\n    private StorageMode              storageMode                        = StorageMode.MEMORY;        // 存储机制\n    private BatchMode                storageBatchMode                   = BatchMode.MEMSIZE;         // 基于大小返回结果\n    private Integer                  memoryStorageBufferSize            = 16 * 1024;                 // 内存存储的buffer大小\n    private Integer                  memoryStorageBufferMemUnit         = 1024;                      // 内存存储的buffer内存占用单位，默认为1kb\n    private Boolean                  memoryStorageRawEntry              = Boolean.TRUE;              // 内存存储的对象是否启用raw的ByteString模式\n    private String                   fileStorageDirectory;                                           // 文件存储的目录位置\n    private Integer                  fileStorageStoreCount;                                          // 每个文件store存储的记录数\n    private Integer                  fileStorageRollverCount;                                        // store文件的个数\n    private Integer                  fileStoragePercentThresold;                                     // 整个store存储占disk硬盘的百分比，超过百分比及时条数还未满也不写入\n    private StorageScavengeMode      storageScavengeMode                = StorageScavengeMode.ON_ACK;\n    private String                   scavengeSchdule;                                                // 调度规则\n\n    // replcation相关参数\n    private SourcingType             sourcingType                       = SourcingType.MYSQL;        // 数据来源类型\n    private String                   localBinlogDirectory;                                           // 本地localBinlog目录\n    private HAMode                   haMode                             = HAMode.HEARTBEAT;          // ha机制\n    // 网络链接参数\n    private Integer                  port                               = 11111;                     // 服务端口，独立运行时需要配置\n    private Integer                  defaultConnectionTimeoutInSeconds  = 30;                        // sotimeout\n    private Integer                  receiveBufferSize                  = 64 * 1024;\n    private Integer                  sendBufferSize                     = 64 * 1024;\n    private String                   connectionCharset                  = \"UTF-8\";\n\n    // 数据库信息\n    private List<InetSocketAddress>  dbAddresses;                                                    // 数据库链接信息\n    private List<List<DataSourcing>> groupDbAddresses;                                               // 数据库链接信息，包含多组信息\n    private String                   dbUsername;                                                     // 数据库用户\n    private String                   dbPassword;                                                     // 数据库密码\n\n    private String                   sslMode                            = SslMode.DISABLED.name();\n    private String                   tlsVersions;                                                    // 和\n                                                                                                     // enabledTLSProtocols\n                                                                                                     // 同含义，TLSv1.2,TLSv1.3\n    private String                   trustCertificateKeyStoreType;                                   // trustStore\n                                                                                                     // 证书类型，支持 JKS (默认)\n                                                                                                     // 和 PKCS12\n    private String                   trustCertificateKeyStoreUrl;                                    // trustStore 证书路径\n    private String                   trustCertificateKeyStorePassword;                               // trustStore 证书密码\n    private String                   clientCertificateKeyStoreType;                                  // client 证书类型，支持\n                                                                                                     // JKS (默认) 和\n                                                                                                     // PKCS12\n    private String                   clientCertificateKeyStoreUrl;                                   // client 证书路径\n    private String                   clientCertificateKeyStorePassword;                              // client 证书密码\n\n    // binlog链接信息\n    private IndexMode                indexMode;\n    private List<String>             positions;                                                      // 数据库positions信息\n    private String                   defaultDatabaseName;                                            // 默认链接的数据库schmea\n    private Long                     slaveId;                                                        // 链接到mysql的slaveId\n    private Integer                  fallbackIntervalInSeconds          = 60;                        // 数据库发生切换查找时回退的时间\n\n    // 心跳检查信息\n    private Boolean                  detectingEnable                    = true;                      // 是否开启心跳语句\n    private Boolean                  heartbeatHaEnable                  = false;                     // 是否开启基于心跳检查的ha功能\n    private String                   detectingSQL;                                                   // 心跳sql\n    private Integer                  detectingIntervalInSeconds         = 3;                         // 检测频率\n    private Integer                  detectingTimeoutThresholdInSeconds = 30;                        // 心跳超时时间\n    private Integer                  detectingRetryTimes                = 3;                         // 心跳检查重试次数\n\n    // tddl/diamond 配置信息\n    private String                   app;\n    private String                   group;\n    // media配置信息\n    private String                   mediaGroup;\n    // metaq 存储配置信息\n    private String                   metaqStoreUri;\n\n    // ddl同步支持，隔离dml/ddl\n    private Boolean                  ddlIsolation                       = Boolean.FALSE;             // 是否将ddl单条返回\n    private Boolean                  filterTableError                   = Boolean.FALSE;             // 是否忽略表解析异常\n    private String                   blackFilter                        = null;                      // 匹配黑名单,忽略解析\n\n    private Boolean                  tsdbEnable                         = Boolean.FALSE;             // 是否开启tableMetaTSDB\n    private String                   tsdbJdbcUrl;\n    private String                   tsdbJdbcUserName;\n    private String                   tsdbJdbcPassword;\n    private Integer                  tsdbSnapshotInterval               = 24;\n    private Integer                  tsdbSnapshotExpire                 = 360;\n    private String                   rdsAccesskey;\n    private String                   rdsSecretkey;\n    private String                   rdsInstanceId;\n    private Boolean                  gtidEnable                         = Boolean.FALSE;             // 是否开启gtid\n    // ================================== 兼容字段处理\n    private InetSocketAddress        masterAddress;                                                  // 主库信息\n    private String                   masterUsername;                                                 // 帐号\n    private String                   masterPassword;                                                 // 密码\n    private String                   masterSslMode                      = SslMode.DISABLED.name();\n    private String                   masterTlsVersions;                                              // 和\n                                                                                                     // enabledTLSProtocols\n                                                                                                     // 同含义，TLSv1.2,TLSv1.3\n    private String                   masterTrustCertificateKeyStoreType;                             // trustStore\n                                                                                                     // 证书类型，支持 JKS (默认)\n                                                                                                     // 和 PKCS12\n    private String                   masterTrustCertificateKeyStoreUrl;                              // trustStore 证书路径\n    private String                   masterTrustCertificateKeyStorePassword;                         // trustStore 证书密码\n    private String                   masterClientCertificateKeyStoreType;                            // client 证书类型，支持\n                                                                                                     // JKS (默认) 和\n                                                                                                     // PKCS12\n    private String                   masterClientCertificateKeyStoreUrl;                             // client 证书路径\n    private String                   masterClientCertificateKeyStorePassword;                        // client 证书密码\n\n    private InetSocketAddress        standbyAddress;                                                 // 备库信息\n    private String                   standbyUsername;                                                // 帐号\n    private String                   standbyPassword;\n    private String                   standbySslMode                     = SslMode.DISABLED.name();\n    private String                   standbyTlsVersions;                                             // 和\n                                                                                                     // enabledTLSProtocols\n                                                                                                     // 同含义，TLSv1.2,TLSv1.3\n    private String                   standbyTrustCertificateKeyStoreType;                            // trustStore\n                                                                                                     // 证书类型，支持 JKS (默认)\n                                                                                                     // 和 PKCS12\n    private String                   standbyTrustCertificateKeyStoreUrl;                             // trustStore 证书路径\n    private String                   standbyTrustCertificateKeyStorePassword;                        // trustStore 证书密码\n    private String                   standbyClientCertificateKeyStoreType;                           // client 证书类型，支持\n                                                                                                     // JKS (默认) 和\n                                                                                                     // PKCS12\n    private String                   standbyClientCertificateKeyStoreUrl;                            // client 证书路径\n    private String                   standbyClientCertificateKeyStorePassword;                       // client 证书密码\n\n    private String                   masterLogfileName                  = null;                      // master起始位置\n    private Long                     masterLogfileOffest                = null;\n    private Long                     masterTimestamp                    = null;\n    private String                   standbyLogfileName                 = null;                      // standby起始位置\n    private Long                     standbyLogfileOffest               = null;\n    private Long                     standbyTimestamp                   = null;\n    private Boolean                  parallel                           = Boolean.FALSE;\n\n    // 自定义alarmHandler类全路径\n    private String                   alarmHandlerClass                  = null;\n    // 自定义alarmHandler插件文件夹路径\n    private String                   alarmHandlerPluginDir              = null;\n    // 是否支持多流消费\n    private Boolean                  multiStreamEnable                  = Boolean.FALSE;\n\n    public static enum RunMode {\n\n        /** 嵌入式 */\n        EMBEDDED,\n        /** 服务式 */\n        SERVICE;\n\n        public boolean isEmbedded() {\n            return this.equals(RunMode.EMBEDDED);\n        }\n\n        public boolean isService() {\n            return this.equals(RunMode.SERVICE);\n        }\n    }\n\n    public static enum ClusterMode {\n\n        /** 嵌入式 */\n        STANDALONE,\n        /** 冷备 */\n        STANDBY,\n        /** 热备 */\n        ACTIVE;\n\n        public boolean isStandalone() {\n            return this.equals(ClusterMode.STANDALONE);\n        }\n\n        public boolean isStandby() {\n            return this.equals(ClusterMode.STANDBY);\n        }\n\n        public boolean isActive() {\n            return this.equals(ClusterMode.ACTIVE);\n        }\n    }\n\n    public static enum HAMode {\n\n        /** 心跳检测 */\n        HEARTBEAT,\n        /** otter media */\n        MEDIA;\n\n        public boolean isHeartBeat() {\n            return this.equals(HAMode.HEARTBEAT);\n        }\n\n        public boolean isMedia() {\n            return this.equals(HAMode.MEDIA);\n        }\n\n    }\n\n    public static enum StorageMode {\n\n        /** 内存存储模式 */\n        MEMORY,\n        /** 文件存储模式 */\n        FILE,\n        /** 混合模式，内存+文件 */\n        MIXED;\n\n        public boolean isMemory() {\n            return this.equals(StorageMode.MEMORY);\n        }\n\n        public boolean isFile() {\n            return this.equals(StorageMode.FILE);\n        }\n\n        public boolean isMixed() {\n            return this.equals(StorageMode.MIXED);\n        }\n\n    }\n\n    public static enum StorageScavengeMode {\n\n        /** 在存储满的时候触发 */\n        ON_FULL,\n        /** 在每次有ack请求时触发 */\n        ON_ACK,\n        /** 定时触发，需要外部控制 */\n        ON_SCHEDULE,\n        /** 不做任何操作，由外部进行清理 */\n        NO_OP;\n\n        public boolean isOnFull() {\n            return this.equals(StorageScavengeMode.ON_FULL);\n        }\n\n        public boolean isOnAck() {\n            return this.equals(StorageScavengeMode.ON_ACK);\n        }\n\n        public boolean isOnSchedule() {\n            return this.equals(StorageScavengeMode.ON_SCHEDULE);\n        }\n\n        public boolean isNoop() {\n            return this.equals(StorageScavengeMode.NO_OP);\n        }\n    }\n\n    public static enum SourcingType {\n\n        /** mysql DB */\n        MYSQL,\n        /** localBinLog */\n        LOCALBINLOG,\n        /** oracle DB */\n        ORACLE,\n        /** 多库合并模式 */\n        GROUP;\n\n        public boolean isMysql() {\n            return this.equals(SourcingType.MYSQL);\n        }\n\n        public boolean isLocalBinlog() {\n            return this.equals(SourcingType.LOCALBINLOG);\n        }\n\n        public boolean isOracle() {\n            return this.equals(SourcingType.ORACLE);\n        }\n\n        public boolean isGroup() {\n            return this.equals(SourcingType.GROUP);\n        }\n    }\n\n    public static enum MetaMode {\n\n        /** 内存存储模式 */\n        MEMORY,\n        /** 文件存储模式 */\n        ZOOKEEPER,\n        /** 混合模式，内存+文件 */\n        MIXED,\n        /** 本地文件存储模式 */\n        LOCAL_FILE;\n\n        public boolean isMemory() {\n            return this.equals(MetaMode.MEMORY);\n        }\n\n        public boolean isZookeeper() {\n            return this.equals(MetaMode.ZOOKEEPER);\n        }\n\n        public boolean isMixed() {\n            return this.equals(MetaMode.MIXED);\n        }\n\n        public boolean isLocalFile() {\n            return this.equals(MetaMode.LOCAL_FILE);\n        }\n    }\n\n    public static enum IndexMode {\n\n        /** 内存存储模式 */\n        MEMORY,\n        /** 文件存储模式 */\n        ZOOKEEPER,\n        /** 混合模式，内存+文件 */\n        MIXED,\n        /** 基于meta信息 */\n        META,\n        /** 基于内存+meta的failback实现 */\n        MEMORY_META_FAILBACK;\n\n        public boolean isMemory() {\n            return this.equals(IndexMode.MEMORY);\n        }\n\n        public boolean isZookeeper() {\n            return this.equals(IndexMode.ZOOKEEPER);\n        }\n\n        public boolean isMixed() {\n            return this.equals(IndexMode.MIXED);\n        }\n\n        public boolean isMeta() {\n            return this.equals(IndexMode.META);\n        }\n\n        public boolean isMemoryMetaFailback() {\n            return this.equals(IndexMode.MEMORY_META_FAILBACK);\n        }\n    }\n\n    public static enum BatchMode {\n\n        /** 对象数量 */\n        ITEMSIZE,\n\n        /** 内存大小 */\n        MEMSIZE;\n\n        public boolean isItemSize() {\n            return this == BatchMode.ITEMSIZE;\n        }\n\n        public boolean isMemSize() {\n            return this == BatchMode.MEMSIZE;\n        }\n    }\n\n    /**\n     * 数据来源描述\n     *\n     * @author jianghang 2012-12-26 上午11:05:20\n     * @version 4.1.5\n     */\n    public static class DataSourcing implements Serializable {\n\n        private static final long serialVersionUID = -1770648468678085234L;\n        private SourcingType      type;\n        private InetSocketAddress dbAddress;\n\n        public DataSourcing(){\n\n        }\n\n        public DataSourcing(SourcingType type, InetSocketAddress dbAddress){\n            this.type = type;\n            this.dbAddress = dbAddress;\n        }\n\n        public SourcingType getType() {\n            return type;\n        }\n\n        public void setType(SourcingType type) {\n            this.type = type;\n        }\n\n        public InetSocketAddress getDbAddress() {\n            return dbAddress;\n        }\n\n        public void setDbAddress(InetSocketAddress dbAddress) {\n            this.dbAddress = dbAddress;\n        }\n\n    }\n\n    public Long getCanalId() {\n        return canalId;\n    }\n\n    public void setCanalId(Long canalId) {\n        this.canalId = canalId;\n    }\n\n    public RunMode getRunMode() {\n        return runMode;\n    }\n\n    public void setRunMode(RunMode runMode) {\n        this.runMode = runMode;\n    }\n\n    public ClusterMode getClusterMode() {\n        return clusterMode;\n    }\n\n    public void setClusterMode(ClusterMode clusterMode) {\n        this.clusterMode = clusterMode;\n    }\n\n    public List<String> getZkClusters() {\n        return zkClusters;\n    }\n\n    public void setZkClusters(List<String> zkClusters) {\n        this.zkClusters = zkClusters;\n    }\n\n    public MetaMode getMetaMode() {\n        return metaMode;\n    }\n\n    public void setMetaMode(MetaMode metaMode) {\n        this.metaMode = metaMode;\n    }\n\n    public StorageMode getStorageMode() {\n        return storageMode;\n    }\n\n    public String getDataDir() {\n        return dataDir;\n    }\n\n    public void setDataDir(String dataDir) {\n        this.dataDir = dataDir;\n    }\n\n    public Integer getMetaFileFlushPeriod() {\n        return metaFileFlushPeriod;\n    }\n\n    public void setMetaFileFlushPeriod(Integer metaFileFlushPeriod) {\n        this.metaFileFlushPeriod = metaFileFlushPeriod;\n    }\n\n    public void setStorageMode(StorageMode storageMode) {\n        this.storageMode = storageMode;\n    }\n\n    public Integer getMemoryStorageBufferSize() {\n        return memoryStorageBufferSize;\n    }\n\n    public void setMemoryStorageBufferSize(Integer memoryStorageBufferSize) {\n        this.memoryStorageBufferSize = memoryStorageBufferSize;\n    }\n\n    public String getFileStorageDirectory() {\n        return fileStorageDirectory;\n    }\n\n    public void setFileStorageDirectory(String fileStorageDirectory) {\n        this.fileStorageDirectory = fileStorageDirectory;\n    }\n\n    public Integer getFileStorageStoreCount() {\n        return fileStorageStoreCount;\n    }\n\n    public void setFileStorageStoreCount(Integer fileStorageStoreCount) {\n        this.fileStorageStoreCount = fileStorageStoreCount;\n    }\n\n    public Integer getFileStorageRollverCount() {\n        return fileStorageRollverCount;\n    }\n\n    public void setFileStorageRollverCount(Integer fileStorageRollverCount) {\n        this.fileStorageRollverCount = fileStorageRollverCount;\n    }\n\n    public Integer getFileStoragePercentThresold() {\n        return fileStoragePercentThresold;\n    }\n\n    public void setFileStoragePercentThresold(Integer fileStoragePercentThresold) {\n        this.fileStoragePercentThresold = fileStoragePercentThresold;\n    }\n\n    public SourcingType getSourcingType() {\n        return sourcingType;\n    }\n\n    public void setSourcingType(SourcingType sourcingType) {\n        this.sourcingType = sourcingType;\n    }\n\n    public String getLocalBinlogDirectory() {\n        return localBinlogDirectory;\n    }\n\n    public void setLocalBinlogDirectory(String localBinlogDirectory) {\n        this.localBinlogDirectory = localBinlogDirectory;\n    }\n\n    public HAMode getHaMode() {\n        return haMode;\n    }\n\n    public void setHaMode(HAMode haMode) {\n        this.haMode = haMode;\n    }\n\n    public Integer getPort() {\n        return port;\n    }\n\n    public void setPort(Integer port) {\n        this.port = port;\n    }\n\n    public Integer getDefaultConnectionTimeoutInSeconds() {\n        return defaultConnectionTimeoutInSeconds;\n    }\n\n    public void setDefaultConnectionTimeoutInSeconds(Integer defaultConnectionTimeoutInSeconds) {\n        this.defaultConnectionTimeoutInSeconds = defaultConnectionTimeoutInSeconds;\n    }\n\n    public Integer getReceiveBufferSize() {\n        return receiveBufferSize;\n    }\n\n    public void setReceiveBufferSize(Integer receiveBufferSize) {\n        this.receiveBufferSize = receiveBufferSize;\n    }\n\n    public Integer getSendBufferSize() {\n        return sendBufferSize;\n    }\n\n    public void setSendBufferSize(Integer sendBufferSize) {\n        this.sendBufferSize = sendBufferSize;\n    }\n\n    public String getConnectionCharset() {\n        return connectionCharset;\n    }\n\n    public void setConnectionCharset(String connectionCharset) {\n        this.connectionCharset = connectionCharset;\n    }\n\n    public IndexMode getIndexMode() {\n        return indexMode;\n    }\n\n    public void setIndexMode(IndexMode indexMode) {\n        this.indexMode = indexMode;\n    }\n\n    public String getDefaultDatabaseName() {\n        return defaultDatabaseName;\n    }\n\n    public void setDefaultDatabaseName(String defaultDatabaseName) {\n        this.defaultDatabaseName = defaultDatabaseName;\n    }\n\n    public Long getSlaveId() {\n        return slaveId;\n    }\n\n    public void setSlaveId(Long slaveId) {\n        this.slaveId = slaveId;\n    }\n\n    public Boolean getDetectingEnable() {\n        return detectingEnable;\n    }\n\n    public void setDetectingEnable(Boolean detectingEnable) {\n        this.detectingEnable = detectingEnable;\n    }\n\n    public String getDetectingSQL() {\n        return detectingSQL;\n    }\n\n    public void setDetectingSQL(String detectingSQL) {\n        this.detectingSQL = detectingSQL;\n    }\n\n    public Integer getDetectingIntervalInSeconds() {\n        return detectingIntervalInSeconds;\n    }\n\n    public void setDetectingIntervalInSeconds(Integer detectingIntervalInSeconds) {\n        this.detectingIntervalInSeconds = detectingIntervalInSeconds;\n    }\n\n    public Integer getDetectingTimeoutThresholdInSeconds() {\n        return detectingTimeoutThresholdInSeconds;\n    }\n\n    public void setDetectingTimeoutThresholdInSeconds(Integer detectingTimeoutThresholdInSeconds) {\n        this.detectingTimeoutThresholdInSeconds = detectingTimeoutThresholdInSeconds;\n    }\n\n    public Integer getDetectingRetryTimes() {\n        return detectingRetryTimes;\n    }\n\n    public void setDetectingRetryTimes(Integer detectingRetryTimes) {\n        this.detectingRetryTimes = detectingRetryTimes;\n    }\n\n    public StorageScavengeMode getStorageScavengeMode() {\n        return storageScavengeMode;\n    }\n\n    public void setStorageScavengeMode(StorageScavengeMode storageScavengeMode) {\n        this.storageScavengeMode = storageScavengeMode;\n    }\n\n    public String getScavengeSchdule() {\n        return scavengeSchdule;\n    }\n\n    public void setScavengeSchdule(String scavengeSchdule) {\n        this.scavengeSchdule = scavengeSchdule;\n    }\n\n    public String getApp() {\n        return app;\n    }\n\n    public String getGroup() {\n        return group;\n    }\n\n    public void setApp(String app) {\n        this.app = app;\n    }\n\n    public void setGroup(String group) {\n        this.group = group;\n    }\n\n    public String getMetaqStoreUri() {\n        return metaqStoreUri;\n    }\n\n    public void setMetaqStoreUri(String metaqStoreUri) {\n        this.metaqStoreUri = metaqStoreUri;\n    }\n\n    public Integer getTransactionSize() {\n        return transactionSize != null ? transactionSize : 1024;\n    }\n\n    public void setTransactionSize(Integer transactionSize) {\n        this.transactionSize = transactionSize;\n    }\n\n    public List<InetSocketAddress> getDbAddresses() {\n        if (dbAddresses == null) {\n            dbAddresses = new ArrayList<>();\n            if (masterAddress != null) {\n                dbAddresses.add(masterAddress);\n            }\n\n            if (standbyAddress != null) {\n                dbAddresses.add(standbyAddress);\n            }\n        }\n        return dbAddresses;\n    }\n\n    public List<List<DataSourcing>> getGroupDbAddresses() {\n        if (groupDbAddresses == null) {\n            groupDbAddresses = new ArrayList<>();\n            if (dbAddresses != null) {\n                for (InetSocketAddress address : dbAddresses) {\n                    List<DataSourcing> groupAddresses = new ArrayList<>();\n                    groupAddresses.add(new DataSourcing(sourcingType, address));\n                    groupDbAddresses.add(groupAddresses);\n                }\n            } else {\n                if (masterAddress != null) {\n                    List<DataSourcing> groupAddresses = new ArrayList<>();\n                    groupAddresses.add(new DataSourcing(sourcingType, masterAddress));\n                    groupDbAddresses.add(groupAddresses);\n                }\n\n                if (standbyAddress != null) {\n                    List<DataSourcing> groupAddresses = new ArrayList<>();\n                    groupAddresses.add(new DataSourcing(sourcingType, standbyAddress));\n                    groupDbAddresses.add(groupAddresses);\n                }\n            }\n        }\n        return groupDbAddresses;\n    }\n\n    public void setGroupDbAddresses(List<List<DataSourcing>> groupDbAddresses) {\n        this.groupDbAddresses = groupDbAddresses;\n    }\n\n    public void setDbAddresses(List<InetSocketAddress> dbAddresses) {\n        this.dbAddresses = dbAddresses;\n    }\n\n    public String getDbUsername() {\n        if (dbUsername == null) {\n            dbUsername = (masterUsername != null ? masterUsername : standbyUsername);\n        }\n        return dbUsername;\n    }\n\n    public void setDbUsername(String dbUsername) {\n        this.dbUsername = dbUsername;\n    }\n\n    public String getDbPassword() {\n        if (dbPassword == null) {\n            dbPassword = (masterPassword != null ? masterPassword : standbyPassword);\n        }\n        return dbPassword;\n    }\n\n    public void setDbPassword(String dbPassword) {\n        this.dbPassword = dbPassword;\n    }\n\n    public SslInfo getSslInfo() {\n        if (dbUsername == null) {\n            if (masterUsername != null) {\n                return new SslInfo(SslMode.valueOf(masterSslMode),\n                    masterTlsVersions,\n                    masterTrustCertificateKeyStoreType,\n                    masterTrustCertificateKeyStoreUrl,\n                    masterTrustCertificateKeyStorePassword,\n                    masterClientCertificateKeyStoreType,\n                    masterClientCertificateKeyStoreUrl,\n                    masterClientCertificateKeyStorePassword);\n            } else {\n                return new SslInfo(SslMode.valueOf(standbySslMode),\n                    standbyTlsVersions,\n                    standbyTrustCertificateKeyStoreType,\n                    standbyTrustCertificateKeyStoreUrl,\n                    standbyTrustCertificateKeyStorePassword,\n                    standbyClientCertificateKeyStoreType,\n                    standbyClientCertificateKeyStoreUrl,\n                    standbyClientCertificateKeyStorePassword);\n            }\n        }\n        return new SslInfo(SslMode.valueOf(sslMode),\n            tlsVersions,\n            trustCertificateKeyStoreType,\n            trustCertificateKeyStoreUrl,\n            trustCertificateKeyStorePassword,\n            clientCertificateKeyStoreType,\n            clientCertificateKeyStoreUrl,\n            clientCertificateKeyStorePassword);\n    }\n\n    public void setSslMode(String sslMode) {\n        this.sslMode = sslMode;\n    }\n\n    public void setTlsVersions(String tlsVersions) {\n        this.tlsVersions = tlsVersions;\n    }\n\n    public void setTrustCertificateKeyStoreType(String trustCertificateKeyStoreType) {\n        this.trustCertificateKeyStoreType = trustCertificateKeyStoreType;\n    }\n\n    public void setTrustCertificateKeyStoreUrl(String trustCertificateKeyStoreUrl) {\n        this.trustCertificateKeyStoreUrl = trustCertificateKeyStoreUrl;\n    }\n\n    public void setTrustCertificateKeyStorePassword(String trustCertificateKeyStorePassword) {\n        this.trustCertificateKeyStorePassword = trustCertificateKeyStorePassword;\n    }\n\n    public void setClientCertificateKeyStoreType(String clientCertificateKeyStoreType) {\n        this.clientCertificateKeyStoreType = clientCertificateKeyStoreType;\n    }\n\n    public void setClientCertificateKeyStoreUrl(String clientCertificateKeyStoreUrl) {\n        this.clientCertificateKeyStoreUrl = clientCertificateKeyStoreUrl;\n    }\n\n    public void setClientCertificateKeyStorePassword(String clientCertificateKeyStorePassword) {\n        this.clientCertificateKeyStorePassword = clientCertificateKeyStorePassword;\n    }\n\n    public void setMasterSslMode(String masterSslMode) {\n        this.masterSslMode = masterSslMode;\n    }\n\n    public void setMasterTlsVersions(String masterTlsVersions) {\n        this.masterTlsVersions = masterTlsVersions;\n    }\n\n    public void setMasterTrustCertificateKeyStoreType(String masterTrustCertificateKeyStoreType) {\n        this.masterTrustCertificateKeyStoreType = masterTrustCertificateKeyStoreType;\n    }\n\n    public void setMasterTrustCertificateKeyStoreUrl(String masterTrustCertificateKeyStoreUrl) {\n        this.masterTrustCertificateKeyStoreUrl = masterTrustCertificateKeyStoreUrl;\n    }\n\n    public void setMasterTrustCertificateKeyStorePassword(String masterTrustCertificateKeyStorePassword) {\n        this.masterTrustCertificateKeyStorePassword = masterTrustCertificateKeyStorePassword;\n    }\n\n    public void setMasterClientCertificateKeyStoreType(String masterClientCertificateKeyStoreType) {\n        this.masterClientCertificateKeyStoreType = masterClientCertificateKeyStoreType;\n    }\n\n    public void setMasterClientCertificateKeyStoreUrl(String masterClientCertificateKeyStoreUrl) {\n        this.masterClientCertificateKeyStoreUrl = masterClientCertificateKeyStoreUrl;\n    }\n\n    public void setMasterClientCertificateKeyStorePassword(String masterClientCertificateKeyStorePassword) {\n        this.masterClientCertificateKeyStorePassword = masterClientCertificateKeyStorePassword;\n    }\n\n    public void setStandbySslMode(String standbySslMode) {\n        this.standbySslMode = standbySslMode;\n    }\n\n    public void setStandbyTlsVersions(String standbyTlsVersions) {\n        this.standbyTlsVersions = standbyTlsVersions;\n    }\n\n    public void setStandbyTrustCertificateKeyStoreType(String standbyTrustCertificateKeyStoreType) {\n        this.standbyTrustCertificateKeyStoreType = standbyTrustCertificateKeyStoreType;\n    }\n\n    public void setStandbyTrustCertificateKeyStoreUrl(String standbyTrustCertificateKeyStoreUrl) {\n        this.standbyTrustCertificateKeyStoreUrl = standbyTrustCertificateKeyStoreUrl;\n    }\n\n    public void setStandbyTrustCertificateKeyStorePassword(String standbyTrustCertificateKeyStorePassword) {\n        this.standbyTrustCertificateKeyStorePassword = standbyTrustCertificateKeyStorePassword;\n    }\n\n    public void setStandbyClientCertificateKeyStoreType(String standbyClientCertificateKeyStoreType) {\n        this.standbyClientCertificateKeyStoreType = standbyClientCertificateKeyStoreType;\n    }\n\n    public void setStandbyClientCertificateKeyStoreUrl(String standbyClientCertificateKeyStoreUrl) {\n        this.standbyClientCertificateKeyStoreUrl = standbyClientCertificateKeyStoreUrl;\n    }\n\n    public void setStandbyClientCertificateKeyStorePassword(String standbyClientCertificateKeyStorePassword) {\n        this.standbyClientCertificateKeyStorePassword = standbyClientCertificateKeyStorePassword;\n    }\n\n    public List<String> getPositions() {\n        if (positions == null) {\n            positions = new ArrayList<>();\n            String masterPosition = buildPosition(masterLogfileName, masterLogfileOffest, masterTimestamp);\n            if (masterPosition != null) {\n                positions.add(masterPosition);\n            }\n\n            String standbyPosition = buildPosition(standbyLogfileName, standbyLogfileOffest, standbyTimestamp);\n            if (standbyPosition != null) {\n                positions.add(standbyPosition);\n            }\n\n        }\n        return positions;\n    }\n\n    public void setPositions(List<String> positions) {\n        this.positions = positions;\n    }\n\n    // ===========================兼容字段\n\n    private String buildPosition(String journalName, Long position, Long timestamp) {\n        StringBuilder masterBuilder = new StringBuilder();\n        if (StringUtils.isNotEmpty(journalName) || position != null || timestamp != null) {\n            masterBuilder.append('{');\n            if (StringUtils.isNotEmpty(journalName)) {\n                masterBuilder.append(\"\\\"journalName\\\":\\\"\").append(journalName).append(\"\\\"\");\n            }\n\n            if (position != null) {\n                if (masterBuilder.length() > 1) {\n                    masterBuilder.append(\",\");\n                }\n                masterBuilder.append(\"\\\"position\\\":\").append(position);\n            }\n\n            if (timestamp != null) {\n                if (masterBuilder.length() > 1) {\n                    masterBuilder.append(\",\");\n                }\n                masterBuilder.append(\"\\\"timestamp\\\":\").append(timestamp);\n            }\n            masterBuilder.append('}');\n            return masterBuilder.toString();\n        } else {\n            return null;\n        }\n    }\n\n    public void setMasterUsername(String masterUsername) {\n        this.masterUsername = masterUsername;\n    }\n\n    public void setMasterPassword(String masterPassword) {\n        this.masterPassword = masterPassword;\n    }\n\n    public void setStandbyAddress(InetSocketAddress standbyAddress) {\n        this.standbyAddress = standbyAddress;\n    }\n\n    public void setStandbyUsername(String standbyUsername) {\n        this.standbyUsername = standbyUsername;\n    }\n\n    public void setStandbyPassword(String standbyPassword) {\n        this.standbyPassword = standbyPassword;\n    }\n\n    public void setMasterLogfileName(String masterLogfileName) {\n        this.masterLogfileName = masterLogfileName;\n    }\n\n    public void setMasterLogfileOffest(Long masterLogfileOffest) {\n        this.masterLogfileOffest = masterLogfileOffest;\n    }\n\n    public void setMasterTimestamp(Long masterTimestamp) {\n        this.masterTimestamp = masterTimestamp;\n    }\n\n    public void setStandbyLogfileName(String standbyLogfileName) {\n        this.standbyLogfileName = standbyLogfileName;\n    }\n\n    public void setStandbyLogfileOffest(Long standbyLogfileOffest) {\n        this.standbyLogfileOffest = standbyLogfileOffest;\n    }\n\n    public void setStandbyTimestamp(Long standbyTimestamp) {\n        this.standbyTimestamp = standbyTimestamp;\n    }\n\n    public void setMasterAddress(InetSocketAddress masterAddress) {\n        this.masterAddress = masterAddress;\n    }\n\n    public Integer getFallbackIntervalInSeconds() {\n        return fallbackIntervalInSeconds == null ? 60 : fallbackIntervalInSeconds;\n    }\n\n    public void setFallbackIntervalInSeconds(Integer fallbackIntervalInSeconds) {\n        this.fallbackIntervalInSeconds = fallbackIntervalInSeconds;\n    }\n\n    public Boolean getHeartbeatHaEnable() {\n        return heartbeatHaEnable == null ? false : heartbeatHaEnable;\n    }\n\n    public void setHeartbeatHaEnable(Boolean heartbeatHaEnable) {\n        this.heartbeatHaEnable = heartbeatHaEnable;\n    }\n\n    public BatchMode getStorageBatchMode() {\n        return storageBatchMode == null ? BatchMode.MEMSIZE : storageBatchMode;\n    }\n\n    public void setStorageBatchMode(BatchMode storageBatchMode) {\n        this.storageBatchMode = storageBatchMode;\n    }\n\n    public Integer getMemoryStorageBufferMemUnit() {\n        return memoryStorageBufferMemUnit == null ? 1024 : memoryStorageBufferMemUnit;\n    }\n\n    public void setMemoryStorageBufferMemUnit(Integer memoryStorageBufferMemUnit) {\n        this.memoryStorageBufferMemUnit = memoryStorageBufferMemUnit;\n    }\n\n    public String getMediaGroup() {\n        return mediaGroup;\n    }\n\n    public void setMediaGroup(String mediaGroup) {\n        this.mediaGroup = mediaGroup;\n    }\n\n    public Long getZkClusterId() {\n        return zkClusterId;\n    }\n\n    public void setZkClusterId(Long zkClusterId) {\n        this.zkClusterId = zkClusterId;\n    }\n\n    public Boolean getDdlIsolation() {\n        return ddlIsolation == null ? false : ddlIsolation;\n    }\n\n    public void setDdlIsolation(Boolean ddlIsolation) {\n        this.ddlIsolation = ddlIsolation;\n    }\n\n    public Boolean getFilterTableError() {\n        return filterTableError == null ? false : filterTableError;\n    }\n\n    public void setFilterTableError(Boolean filterTableError) {\n        this.filterTableError = filterTableError;\n    }\n\n    public String getBlackFilter() {\n        return blackFilter;\n    }\n\n    public void setBlackFilter(String blackFilter) {\n        this.blackFilter = blackFilter;\n    }\n\n    public Boolean getTsdbEnable() {\n        return tsdbEnable;\n    }\n\n    public void setTsdbEnable(Boolean tsdbEnable) {\n        this.tsdbEnable = tsdbEnable;\n    }\n\n    public String getTsdbJdbcUrl() {\n        return tsdbJdbcUrl;\n    }\n\n    public void setTsdbJdbcUrl(String tsdbJdbcUrl) {\n        this.tsdbJdbcUrl = tsdbJdbcUrl;\n    }\n\n    public String getTsdbJdbcUserName() {\n        return tsdbJdbcUserName;\n    }\n\n    public void setTsdbJdbcUserName(String tsdbJdbcUserName) {\n        this.tsdbJdbcUserName = tsdbJdbcUserName;\n    }\n\n    public String getTsdbJdbcPassword() {\n        return tsdbJdbcPassword;\n    }\n\n    public void setTsdbJdbcPassword(String tsdbJdbcPassword) {\n        this.tsdbJdbcPassword = tsdbJdbcPassword;\n    }\n\n    public String getRdsAccesskey() {\n        return rdsAccesskey;\n    }\n\n    public void setRdsAccesskey(String rdsAccesskey) {\n        this.rdsAccesskey = rdsAccesskey;\n    }\n\n    public String getRdsSecretkey() {\n        return rdsSecretkey;\n    }\n\n    public void setRdsSecretkey(String rdsSecretkey) {\n        this.rdsSecretkey = rdsSecretkey;\n    }\n\n    public String getRdsInstanceId() {\n        return rdsInstanceId;\n    }\n\n    public void setRdsInstanceId(String rdsInstanceId) {\n        this.rdsInstanceId = rdsInstanceId;\n    }\n\n    public Boolean getGtidEnable() {\n        return gtidEnable;\n    }\n\n    public void setGtidEnable(Boolean gtidEnable) {\n        this.gtidEnable = gtidEnable;\n    }\n\n    public Boolean getMemoryStorageRawEntry() {\n        return memoryStorageRawEntry;\n    }\n\n    public void setMemoryStorageRawEntry(Boolean memoryStorageRawEntry) {\n        this.memoryStorageRawEntry = memoryStorageRawEntry;\n    }\n\n    public Integer getTsdbSnapshotInterval() {\n        return tsdbSnapshotInterval;\n    }\n\n    public void setTsdbSnapshotInterval(Integer tsdbSnapshotInterval) {\n        this.tsdbSnapshotInterval = tsdbSnapshotInterval;\n    }\n\n    public Integer getTsdbSnapshotExpire() {\n        return tsdbSnapshotExpire;\n    }\n\n    public void setTsdbSnapshotExpire(Integer tsdbSnapshotExpire) {\n        this.tsdbSnapshotExpire = tsdbSnapshotExpire;\n    }\n\n    public Boolean getParallel() {\n        return parallel;\n    }\n\n    public void setParallel(Boolean parallel) {\n        this.parallel = parallel;\n    }\n\n    public String getAlarmHandlerClass() {\n        return alarmHandlerClass;\n    }\n\n    public void setAlarmHandlerClass(String alarmHandlerClass) {\n        this.alarmHandlerClass = alarmHandlerClass;\n    }\n\n    public String getAlarmHandlerPluginDir() {\n        return alarmHandlerPluginDir;\n    }\n\n    public void setAlarmHandlerPluginDir(String alarmHandlerPluginDir) {\n        this.alarmHandlerPluginDir = alarmHandlerPluginDir;\n    }\n\n    public Boolean getMultiStreamEnable() {\n        return multiStreamEnable;\n    }\n\n    public void setMultiStreamEnable(Boolean multiStreamEnable) {\n        this.multiStreamEnable = multiStreamEnable;\n    }\n\n    public String toString() {\n        return ToStringBuilder.reflectionToString(this, CanalToStringStyle.DEFAULT_STYLE);\n    }\n}\n"
  },
  {
    "path": "instance/manager/src/main/java/com/alibaba/otter/canal/instance/manager/model/CanalStatus.java",
    "content": "package com.alibaba.otter.canal.instance.manager.model;\n\n/**\n * 运行状态\n * \n * @author jianghang 2012-7-13 下午12:54:13\n * @version 1.0.0\n */\npublic enum CanalStatus {\n    /** 启动 */\n    START,\n    /** 停止 */\n    STOP;\n\n    public boolean isStart() {\n        return this.equals(CanalStatus.START);\n    }\n\n    public boolean isStop() {\n        return this.equals(CanalStatus.STOP);\n    }\n}\n"
  },
  {
    "path": "instance/manager/src/main/java/com/alibaba/otter/canal/instance/manager/plain/HttpHelper.java",
    "content": "package com.alibaba.otter.canal.instance.manager.plain;\n\nimport static org.apache.http.client.config.RequestConfig.custom;\n\nimport java.io.IOException;\nimport java.net.URI;\nimport java.util.Map;\n\nimport javax.net.ssl.SSLContext;\n\nimport org.apache.http.HttpStatus;\nimport org.apache.http.client.config.RequestConfig;\nimport org.apache.http.client.methods.CloseableHttpResponse;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.client.methods.HttpPost;\nimport org.apache.http.client.protocol.HttpClientContext;\nimport org.apache.http.client.utils.URIBuilder;\nimport org.apache.http.config.RegistryBuilder;\nimport org.apache.http.conn.socket.ConnectionSocketFactory;\nimport org.apache.http.conn.socket.PlainConnectionSocketFactory;\nimport org.apache.http.conn.ssl.NoopHostnameVerifier;\nimport org.apache.http.conn.ssl.SSLConnectionSocketFactory;\nimport org.apache.http.entity.StringEntity;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.HttpClientBuilder;\nimport org.apache.http.impl.conn.PoolingHttpClientConnectionManager;\nimport org.apache.http.ssl.SSLContextBuilder;\nimport org.apache.http.util.EntityUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.fastjson2.JSON;\n\n/**\n * http client 工具类\n *\n * @author rewerma 2019-08-26 上午09:40:36\n * @version 1.0.0\n */\npublic class HttpHelper {\n\n    private final static Logger logger                   = LoggerFactory.getLogger(HttpHelper.class);\n\n    public static final Integer REST_STATE_OK            = 20000;\n    public static final Integer REST_STATE_TOKEN_INVALID = 50014;\n    public static final Integer REST_STATE_ERROR         = 50000;\n\n    private CloseableHttpClient httpclient;\n\n    public HttpHelper(){\n        HttpClientBuilder builder = HttpClientBuilder.create();\n        builder.setMaxConnPerRoute(50);\n        builder.setMaxConnTotal(100);\n\n        // 创建支持忽略证书的https\n        try {\n            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (x509Certificates, s) -> true).build();\n\n            httpclient = HttpClientBuilder.create()\n                .setSSLContext(sslContext)\n                .setConnectionManager(new PoolingHttpClientConnectionManager(RegistryBuilder.<ConnectionSocketFactory> create()\n                    .register(\"http\", PlainConnectionSocketFactory.INSTANCE)\n                    .register(\"https\", new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE))\n                    .build()))\n                .build();\n        } catch (Throwable e) {\n            // ignore\n        }\n    }\n\n    public String get(String url, Map<String, String> heads, int timeout) {\n        url = url.trim();\n        CloseableHttpResponse response = null;\n        HttpGet httpGet = null;\n        try {\n            URI uri = new URIBuilder(url).build();\n            RequestConfig config = custom().setConnectTimeout(timeout)\n                .setConnectionRequestTimeout(timeout)\n                .setSocketTimeout(timeout)\n                .build();\n            httpGet = new HttpGet(uri);\n            if (heads != null) {\n                for (Map.Entry<String, String> entry : heads.entrySet()) {\n                    httpGet.setHeader(entry.getKey(), entry.getValue());\n                }\n            }\n\n            HttpClientContext context = HttpClientContext.create();\n            context.setRequestConfig(config);\n            response = httpclient.execute(httpGet, context);\n            int statusCode = response.getStatusLine().getStatusCode();\n            if (statusCode == HttpStatus.SC_OK) {\n                return EntityUtils.toString(response.getEntity());\n            } else {\n                String errorMsg = EntityUtils.toString(response.getEntity());\n                throw new RuntimeException(\"requestGet remote error, url=\" + uri.toString() + \", code=\" + statusCode\n                                           + \", error msg=\" + errorMsg);\n            }\n        } catch (Throwable t) {\n            throw new RuntimeException(\"requestGet remote error, request : \" + url, t);\n        } finally {\n            if (response != null) {\n                try {\n                    response.close();\n                } catch (IOException e) {\n                    // ignore\n                }\n            }\n            if (httpGet != null) {\n                httpGet.releaseConnection();\n            }\n        }\n    }\n\n    public String post(String url, Map<String, String> heads, Object requestBody, int timeout) {\n        return post0(url, heads, JSON.toJSONString(requestBody), timeout);\n    }\n\n    public String post0(String url, Map<String, String> heads, String requestBody, int timeout) {\n        url = url.trim();\n        HttpPost httpPost = null;\n        CloseableHttpResponse response = null;\n        try {\n            URI uri = new URIBuilder(url).build();\n            RequestConfig config = custom().setConnectTimeout(timeout)\n                .setConnectionRequestTimeout(timeout)\n                .setSocketTimeout(timeout)\n                .build();\n            httpPost = new HttpPost(uri);\n            StringEntity entity = new StringEntity(requestBody, \"UTF-8\");\n            httpPost.setEntity(entity);\n            httpPost.setHeader(\"Content-Type\", \"application/json;charset=utf8\");\n            if (heads != null) {\n                for (Map.Entry<String, String> entry : heads.entrySet()) {\n                    httpPost.setHeader(entry.getKey(), entry.getValue());\n                }\n            }\n\n            HttpClientContext context = HttpClientContext.create();\n            context.setRequestConfig(config);\n\n            response = httpclient.execute(httpPost, context);\n            int statusCode = response.getStatusLine().getStatusCode();\n            if (statusCode == HttpStatus.SC_OK) {\n                return EntityUtils.toString(response.getEntity());\n            } else {\n                throw new RuntimeException(\"requestPost remote error, request : \" + url + \", statusCode=\" + statusCode\n                                           + \";\" + EntityUtils.toString(response.getEntity()));\n            }\n        } catch (Throwable t) {\n            throw new RuntimeException(\"requestPost remote error, request : \" + url, t);\n        } finally {\n            if (response != null) {\n                try {\n                    response.close();\n                } catch (IOException e) {\n                    // ignore\n                }\n            }\n            if (httpPost != null) {\n                httpPost.releaseConnection();\n            }\n        }\n    }\n\n    public void close() {\n        if (httpclient != null) {\n            try {\n                httpclient.close();\n            } catch (IOException e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "instance/manager/src/main/java/com/alibaba/otter/canal/instance/manager/plain/PlainCanal.java",
    "content": "package com.alibaba.otter.canal.instance.manager.plain;\n\nimport java.util.Properties;\n\n/**\n * plain远程配置，提供基于properties纯文本的配置\n *\n * @author rewerma 2019-01-25 下午05:20:16\n * @author agapple\n * @version 1.0.0\n */\npublic class PlainCanal {\n\n    private Properties properties;\n    private String     md5;\n    private String     status;\n\n    public PlainCanal(){\n    }\n\n    public PlainCanal(Properties properties, String status, String md5){\n        this.properties = properties;\n        this.md5 = md5;\n        this.status = status;\n    }\n\n    public Properties getProperties() {\n        return properties;\n    }\n\n    public void setProperties(Properties properties) {\n        this.properties = properties;\n    }\n\n    public String getMd5() {\n        return md5;\n    }\n\n    public void setMd5(String md5) {\n        this.md5 = md5;\n    }\n\n    public String getStatus() {\n        return status;\n    }\n\n    public void setStatus(String status) {\n        this.status = status;\n    }\n\n    @Override\n    public String toString() {\n        return \"PlainCanal [properties=\" + properties + \", md5=\" + md5 + \", status=\" + status + \"]\";\n    }\n}\n"
  },
  {
    "path": "instance/manager/src/main/java/com/alibaba/otter/canal/instance/manager/plain/PlainCanalConfigClient.java",
    "content": "package com.alibaba.otter.canal.instance.manager.plain;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport org.apache.commons.lang.StringUtils;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.TypeReference;\nimport com.alibaba.otter.canal.common.AbstractCanalLifeCycle;\nimport com.alibaba.otter.canal.common.CanalException;\nimport com.alibaba.otter.canal.common.CanalLifeCycle;\nimport com.alibaba.otter.canal.protocol.SecurityUtil;\nimport com.google.common.net.UrlEscapers;\n\n/**\n * 远程配置获取\n *\n * @author rewerma 2019-01-25 下午05:20:16\n * @author agapple 2019年8月26日 下午7:52:06\n * @since 1.1.4\n */\npublic class PlainCanalConfigClient extends AbstractCanalLifeCycle implements CanalLifeCycle {\n\n    private final static Integer REQUEST_TIMEOUT = 5000;\n    private String               configURL;\n    private String               user;\n    private String               passwd;\n    private HttpHelper           httpHelper;\n    private String               localIp;\n    private int                  adminPort;\n    private boolean              autoRegister;\n    private String               autoCluster;\n    private String               name;\n\n    public PlainCanalConfigClient(String configURL, String user, String passwd, String localIp, int adminPort,\n                                  boolean autoRegister, String autoCluster, String name){\n        this(configURL, user, passwd, localIp, adminPort);\n        this.autoCluster = autoCluster;\n        this.autoRegister = autoRegister;\n        this.name = name;\n    }\n\n    public PlainCanalConfigClient(String configURL, String user, String passwd, String localIp, int adminPort){\n        this.configURL = configURL;\n        if (!StringUtils.startsWithIgnoreCase(configURL, \"http\")) {\n            this.configURL = \"http://\" + configURL;\n        } else {\n            this.configURL = configURL;\n        }\n        this.user = user;\n        this.passwd = passwd;\n        this.httpHelper = new HttpHelper();\n        if (StringUtils.isEmpty(localIp)) {\n            this.localIp = \"127.0.0.1\";// 本地测试用\n        } else {\n            this.localIp = localIp;\n        }\n        this.adminPort = adminPort;\n    }\n\n    /**\n     * 加载canal.properties文件\n     *\n     * @return 远程配置的properties\n     */\n    public PlainCanal findServer(String md5) {\n        if (StringUtils.isEmpty(md5)) {\n            md5 = \"\";\n        }\n        String url = configURL + \"/api/v1/config/server_polling?ip=\" + localIp + \"&port=\" + adminPort + \"&md5=\" + md5\n                     + \"&register=\" + (autoRegister ? 1 : 0) + \"&cluster=\" + StringUtils.stripToEmpty(autoCluster) + \"&name=\" + StringUtils.stripToEmpty(name);\n        return queryConfig(url);\n    }\n\n    /**\n     * 加载远程的instance.properties\n     */\n    public PlainCanal findInstance(String destination, String md5) {\n        if (StringUtils.isEmpty(md5)) {\n            md5 = \"\";\n        }\n        String url = configURL + \"/api/v1/config/instance_polling/\" + UrlEscapers.urlPathSegmentEscaper().escape(destination) + \"?md5=\" + md5;\n        return queryConfig(url);\n    }\n\n    /**\n     * 返回需要运行的instance列表\n     */\n    public String findInstances(String md5) {\n        if (StringUtils.isEmpty(md5)) {\n            md5 = \"\";\n        }\n        String url = configURL + \"/api/v1/config/instances_polling?md5=\" + md5 + \"&ip=\" + localIp + \"&port=\"\n                     + adminPort;\n        ResponseModel<CanalConfig> config = doQuery(url);\n        if (config.data != null) {\n            return config.data.content;\n        } else {\n            return null;\n        }\n    }\n\n    private PlainCanal queryConfig(String url) {\n        try {\n            ResponseModel<CanalConfig> config = doQuery(url);\n            return processData(config.data);\n        } catch (Throwable e) {\n            throw new CanalException(\"load manager config failed.\", e);\n        }\n    }\n\n    private ResponseModel<CanalConfig> doQuery(String url) {\n        Map<String, String> heads = new HashMap<>();\n        heads.put(\"user\", user);\n        heads.put(\"passwd\", passwd);\n        String response = httpHelper.get(url, heads, REQUEST_TIMEOUT);\n        ResponseModel<CanalConfig> resp = JSON.parseObject(response,\n            new TypeReference<ResponseModel<CanalConfig>>() {\n            });\n\n        if (!HttpHelper.REST_STATE_OK.equals(resp.code)) {\n            throw new CanalException(\"requestGet for canal config error: \" + resp.message);\n        }\n\n        return resp;\n    }\n\n    private PlainCanal processData(CanalConfig config) throws IOException, NoSuchAlgorithmException {\n        Properties properties = new Properties();\n        String md5 = null;\n        String status = null;\n        if (config != null && StringUtils.isNotEmpty(config.content)) {\n            md5 = SecurityUtil.md5String(config.content);\n            status = config.status;\n            properties.load(new ByteArrayInputStream(config.content.getBytes(StandardCharsets.UTF_8)));\n        } else {\n            // null代表没有新配置变更\n            return null;\n        }\n\n        return new PlainCanal(properties, status, md5);\n    }\n\n    private static class ResponseModel<T> {\n\n        public Integer code;\n        public String  message;\n        public T       data;\n    }\n\n    private static class CanalConfig {\n\n        public String content;\n        public String status;\n\n    }\n}\n"
  },
  {
    "path": "instance/manager/src/test/java/com/alibaba/otter/canal/instance/manager/PlainCanalConfigClientIntegration.java",
    "content": "package com.alibaba.otter.canal.instance.manager;\n\nimport org.junit.Test;\nimport org.springframework.util.Assert;\n\nimport com.alibaba.otter.canal.instance.manager.plain.PlainCanal;\nimport com.alibaba.otter.canal.instance.manager.plain.PlainCanalConfigClient;\n\npublic class PlainCanalConfigClientIntegration {\n\n    @Test\n    public void testSimple() {\n        PlainCanalConfigClient client = new PlainCanalConfigClient(\"http://127.0.0.1:8089\",\n            \"admin\",\n            \"4ACFE3202A5FF5CF467898FC58AAB1D615029441\",\n            \"127.0.0.1\",\n            11110);\n\n        PlainCanal plain = client.findServer(null);\n        Assert.notNull(plain);\n\n        plain = client.findServer(plain.getMd5());\n        Assert.isNull(plain);\n\n        String instances = client.findInstances(null);\n        Assert.notNull(instances);\n\n        plain = client.findInstance(\"example\", null);\n        Assert.notNull(plain);\n\n        plain = client.findInstance(\"example\", plain.getMd5());\n        Assert.isNull(plain);\n    }\n}\n"
  },
  {
    "path": "instance/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>com.alibaba.otter</groupId>\n\t\t<artifactId>canal</artifactId>\n\t\t<version>1.1.9-SNAPSHOT</version>\n\t\t<relativePath>../pom.xml</relativePath>\n\t</parent>\n\t<groupId>com.alibaba.otter</groupId>\n\t<artifactId>canal.instance</artifactId>\n\t<packaging>pom</packaging>\n\t<name>canal instance module for otter ${project.version}</name>\n\t\n\t<modules>\n\t\t<module>core</module>\n\t\t<module>manager</module>\n\t\t<module>spring</module>\n\t</modules>\n</project>\n"
  },
  {
    "path": "instance/spring/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>com.alibaba.otter</groupId>\n\t\t<artifactId>canal</artifactId>\n\t\t<version>1.1.9-SNAPSHOT</version>\n\t\t<relativePath>../../pom.xml</relativePath>\n\t</parent>\n\t<groupId>com.alibaba.otter</groupId>\n\t<artifactId>canal.instance.spring</artifactId>\n\t<packaging>jar</packaging>\n\t<name>canal instance spring module for otter ${project.version}</name>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.instance.core</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<!-- test dependency -->\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "instance/spring/src/main/java/com/alibaba/otter/canal/instance/spring/CanalInstanceWithSpring.java",
    "content": "package com.alibaba.otter.canal.instance.spring;\n\nimport java.util.List;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.common.alarm.CanalAlarmHandler;\nimport com.alibaba.otter.canal.instance.core.AbstractCanalInstance;\nimport com.alibaba.otter.canal.instance.core.CanalMQConfig;\nimport com.alibaba.otter.canal.meta.CanalMetaManager;\nimport com.alibaba.otter.canal.parse.CanalEventParser;\nimport com.alibaba.otter.canal.protocol.CanalEntry;\nimport com.alibaba.otter.canal.sink.CanalEventSink;\nimport com.alibaba.otter.canal.store.CanalEventStore;\nimport com.alibaba.otter.canal.store.model.Event;\n\n/**\n * 基于spring容器启动canal实例，方便独立于manager启动\n * \n * @author jianghang 2012-7-12 下午01:21:26\n * @author zebin.xuzb\n * @version 1.0.0\n */\npublic class CanalInstanceWithSpring extends AbstractCanalInstance {\n\n    private static final Logger logger = LoggerFactory.getLogger(CanalInstanceWithSpring.class);\n\n    public void start() {\n        logger.info(\"start CannalInstance for {}-{} \", new Object[] { 1, destination });\n        super.start();\n    }\n\n    // ======== setter ========\n\n    public void setDestination(String destination) {\n        this.destination = destination;\n    }\n\n    public void setEventParser(CanalEventParser eventParser) {\n        this.eventParser = eventParser;\n    }\n\n    public void setEventSink(CanalEventSink<List<CanalEntry.Entry>> eventSink) {\n        this.eventSink = eventSink;\n    }\n\n    public void setEventStore(CanalEventStore<Event> eventStore) {\n        this.eventStore = eventStore;\n    }\n\n    public void setMetaManager(CanalMetaManager metaManager) {\n        this.metaManager = metaManager;\n    }\n\n    public void setAlarmHandler(CanalAlarmHandler alarmHandler) {\n        this.alarmHandler = alarmHandler;\n    }\n\n    public void setMqConfig(CanalMQConfig mqConfig) {\n        this.mqConfig = mqConfig;\n    }\n\n}\n"
  },
  {
    "path": "instance/spring/src/main/java/com/alibaba/otter/canal/instance/spring/SpringCanalInstanceGenerator.java",
    "content": "package com.alibaba.otter.canal.instance.spring;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.support.ClassPathXmlApplicationContext;\n\nimport com.alibaba.otter.canal.common.CanalException;\nimport com.alibaba.otter.canal.instance.core.CanalInstance;\nimport com.alibaba.otter.canal.instance.core.CanalInstanceGenerator;\nimport com.alibaba.otter.canal.parse.CanalEventParser;\n\n/**\n * @author zebin.xuzb @ 2012-7-12\n * @version 1.0.0\n */\npublic class SpringCanalInstanceGenerator implements CanalInstanceGenerator {\n\n    private static final Logger logger      = LoggerFactory.getLogger(SpringCanalInstanceGenerator.class);\n    private String              springXml;\n    private String              defaultName = \"instance\";\n    private BeanFactory         beanFactory;\n\n    public CanalInstance generate(String destination) {\n        synchronized (CanalEventParser.class) {\n            try {\n                // 设置当前正在加载的通道，加载spring查找文件时会用到该变量\n                System.setProperty(\"canal.instance.destination\", destination);\n                this.beanFactory = getBeanFactory(springXml);\n                String beanName = destination;\n                if (!beanFactory.containsBean(beanName)) {\n                    beanName = defaultName;\n                }\n\n                return (CanalInstance) beanFactory.getBean(beanName);\n            } catch (Throwable e) {\n                logger.error(\"generator instance failed.\", e);\n                throw new CanalException(e);\n            } finally {\n                System.setProperty(\"canal.instance.destination\", \"\");\n            }\n        }\n    }\n\n    private BeanFactory getBeanFactory(String springXml) {\n        if (!StringUtils.startsWithIgnoreCase(springXml, \"classpath:\")) {\n            springXml = \"classpath:\" + springXml;\n        }\n        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(springXml);\n        return applicationContext;\n    }\n\n    public void setSpringXml(String springXml) {\n        this.springXml = springXml;\n    }\n}\n"
  },
  {
    "path": "instance/spring/src/main/java/com/alibaba/otter/canal/instance/spring/support/PropertyPlaceholderConfigurer.java",
    "content": "package com.alibaba.otter.canal.instance.spring.support;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Properties;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.context.ResourceLoaderAware;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.util.Assert;\n\n/**\n * 扩展Spring的\n * {@linkplain org.springframework.beans.factory.config.PropertyPlaceholderConfigurer}\n * ，增加默认值的功能。 例如：${placeholder:defaultValue}，假如placeholder的值不存在，则默认取得\n * defaultValue。\n * \n * @author jianghang 2013-1-24 下午03:37:56\n * @version 1.0.0\n */\npublic class PropertyPlaceholderConfigurer extends org.springframework.beans.factory.config.PropertyPlaceholderConfigurer implements ResourceLoaderAware, InitializingBean {\n\n    private static final String           PLACEHOLDER_PREFIX = \"${\";\n    private static final String           PLACEHOLDER_SUFFIX = \"}\";\n    public static ThreadLocal<Properties> propertiesLocal    = ThreadLocal.withInitial(Properties::new);\n\n    private ResourceLoader                loader;\n    private String[]                      locationNames;\n\n    public PropertyPlaceholderConfigurer(){\n        setIgnoreUnresolvablePlaceholders(true);\n    }\n\n    public void setResourceLoader(ResourceLoader loader) {\n        this.loader = loader;\n    }\n\n    public void setLocationNames(String[] locations) {\n        this.locationNames = locations;\n    }\n\n    public void afterPropertiesSet() throws Exception {\n        Assert.notNull(loader, \"no resourceLoader\");\n\n        if (locationNames != null) {\n            for (int i = 0; i < locationNames.length; i++) {\n                locationNames[i] = resolveSystemPropertyPlaceholders(locationNames[i]);\n            }\n        }\n\n        if (locationNames != null) {\n            List<Resource> resources = new ArrayList<>(locationNames.length);\n\n            for (String location : locationNames) {\n                location = trimToNull(location);\n\n                if (location != null) {\n                    resources.add(loader.getResource(location));\n                }\n            }\n\n            super.setLocations(resources.toArray(new Resource[resources.size()]));\n        }\n    }\n\n    private String resolveSystemPropertyPlaceholders(String text) {\n        StringBuilder buf = new StringBuilder(text);\n\n        for (int startIndex = buf.indexOf(PLACEHOLDER_PREFIX); startIndex >= 0;) {\n            int endIndex = buf.indexOf(PLACEHOLDER_SUFFIX, startIndex + PLACEHOLDER_PREFIX.length());\n\n            if (endIndex != -1) {\n                String placeholder = buf.substring(startIndex + PLACEHOLDER_PREFIX.length(), endIndex);\n                int nextIndex = endIndex + PLACEHOLDER_SUFFIX.length();\n\n                try {\n                    String value = resolveSystemPropertyPlaceholder(placeholder);\n\n                    if (value != null) {\n                        buf.replace(startIndex, endIndex + PLACEHOLDER_SUFFIX.length(), value);\n                        nextIndex = startIndex + value.length();\n                    } else {\n                        System.err.println(\"Could not resolve placeholder '\"\n                                           + placeholder\n                                           + \"' in [\"\n                                           + text\n                                           + \"] as system property: neither system property nor environment variable found\");\n                    }\n                } catch (Throwable ex) {\n                    System.err.println(\"Could not resolve placeholder '\" + placeholder + \"' in [\" + text\n                                       + \"] as system property: \" + ex);\n                }\n\n                startIndex = buf.indexOf(PLACEHOLDER_PREFIX, nextIndex);\n            } else {\n                startIndex = -1;\n            }\n        }\n\n        return buf.toString();\n    }\n\n    private String resolveSystemPropertyPlaceholder(String placeholder) {\n        DefaultablePlaceholder dp = new DefaultablePlaceholder(placeholder);\n        String value = System.getProperty(dp.placeholder);\n\n        if (value == null) {\n            value = System.getenv(dp.placeholder);\n        }\n\n        if (value == null) {\n            value = dp.defaultValue;\n        }\n\n        return value;\n    }\n\n    @Override\n    protected String resolvePlaceholder(String placeholder, Properties props, int systemPropertiesMode) {\n        DefaultablePlaceholder dp = new DefaultablePlaceholder(placeholder);\n        String propVal = null;\n        // 以system为准覆盖本地配置, 适用于docker\n        if (systemPropertiesMode == SYSTEM_PROPERTIES_MODE_OVERRIDE) {\n            propVal = resolveSystemProperty(dp.placeholder);\n        }\n\n        // 以threadlocal的为准覆盖file properties\n        if (StringUtils.isBlank(propVal)) {\n            Properties localProperties = propertiesLocal.get();\n            propVal = resolvePlaceholder(dp.placeholder, localProperties);\n        }\n\n        if (StringUtils.isBlank(propVal)) {\n            propVal = resolvePlaceholder(dp.placeholder, props);\n        }\n\n        if (StringUtils.isBlank(propVal) && systemPropertiesMode == SYSTEM_PROPERTIES_MODE_FALLBACK) {\n            propVal = resolveSystemProperty(dp.placeholder);\n        }\n\n        if (StringUtils.isBlank(propVal)) {\n            propVal = dp.defaultValue;\n        }\n\n        return trimToEmpty(propVal);\n    }\n\n    private static class DefaultablePlaceholder {\n\n        private final String defaultValue;\n        private final String placeholder;\n\n        public DefaultablePlaceholder(String placeholder){\n            int commaIndex = placeholder.indexOf(\":\");\n            String defaultValue = null;\n\n            if (commaIndex >= 0) {\n                defaultValue = trimToEmpty(placeholder.substring(commaIndex + 1));\n                placeholder = trimToEmpty(placeholder.substring(0, commaIndex));\n            }\n\n            this.placeholder = placeholder;\n            this.defaultValue = defaultValue;\n        }\n    }\n\n    private String trimToNull(String str) {\n        if (str == null) {\n            return null;\n        }\n\n        String result = str.trim();\n\n        if (result == null || result.length() == 0) {\n            return null;\n        }\n\n        return result;\n    }\n\n    public static String trimToEmpty(String str) {\n        if (str == null) {\n            return \"\";\n        }\n\n        return str.trim();\n    }\n}\n"
  },
  {
    "path": "instance/spring/src/main/java/com/alibaba/otter/canal/instance/spring/support/SocketAddressEditor.java",
    "content": "package com.alibaba.otter.canal.instance.spring.support;\n\nimport java.beans.PropertyEditorSupport;\nimport java.net.InetSocketAddress;\n\nimport org.springframework.beans.PropertyEditorRegistrar;\nimport org.springframework.beans.PropertyEditorRegistry;\n\nimport com.alibaba.otter.canal.common.utils.AddressUtils;\n\npublic class SocketAddressEditor extends PropertyEditorSupport implements PropertyEditorRegistrar {\n\n    public void registerCustomEditors(PropertyEditorRegistry registry) {\n        registry.registerCustomEditor(InetSocketAddress.class, this);\n    }\n\n    public void setAsText(String text) throws IllegalArgumentException {\n        String[] addresses = AddressUtils.splitIPAndPort(text);\n        if (addresses.length > 0) {\n            if (addresses.length != 2) {\n                throw new RuntimeException(\"address[\" + text + \"] is illegal, eg.127.0.0.1:3306\");\n            } else {\n                setValue(new InetSocketAddress(addresses[0], Integer.valueOf(addresses[1])));\n            }\n        } else {\n            setValue(null);\n        }\n    }\n}\n"
  },
  {
    "path": "instance/spring/src/test/java/com/alibaba/otter/canal/instance/spring/integrated/DefaultSpringInstanceTest.java",
    "content": "package com.alibaba.otter.canal.instance.spring.integrated;\n\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.support.AbstractApplicationContext;\nimport org.springframework.context.support.ClassPathXmlApplicationContext;\nimport org.springframework.util.Assert;\n\nimport com.alibaba.otter.canal.instance.core.CanalInstance;\nimport com.alibaba.otter.canal.instance.core.CanalInstanceGenerator;\n\n/**\n * @author zebin.xuzb @ 2012-7-13\n * @version 1.0.0\n */\n@Ignore\npublic class DefaultSpringInstanceTest {\n\n    private ApplicationContext context;\n\n    @Before\n    public void start() {\n        System.setProperty(\"canal.instance.destination\", \"retl\");\n        context = new ClassPathXmlApplicationContext(new String[] { \"classpath:spring/default-instance.xml\" });\n    }\n\n    @After\n    public void close() {\n        if (context != null && context instanceof AbstractApplicationContext) {\n            ((AbstractApplicationContext) context).close();\n        }\n    }\n\n    @Test\n    public void testInstance() {\n        CanalInstanceGenerator generator = (CanalInstanceGenerator) context.getBean(\"canalInstanceGenerator\");\n        CanalInstance canalInstance = generator.generate(\"instance\");\n        Assert.notNull(canalInstance);\n\n        canalInstance.start();\n        try {\n            Thread.sleep(10 * 1000);\n        } catch (InterruptedException e) {\n        }\n        canalInstance.stop();\n    }\n}\n"
  },
  {
    "path": "instance/spring/src/test/java/com/alibaba/otter/canal/instance/spring/integrated/GroupSpringInstanceTest.java",
    "content": "package com.alibaba.otter.canal.instance.spring.integrated;\n\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.support.AbstractApplicationContext;\nimport org.springframework.context.support.ClassPathXmlApplicationContext;\nimport org.springframework.util.Assert;\n\nimport com.alibaba.otter.canal.instance.core.CanalInstance;\nimport com.alibaba.otter.canal.instance.core.CanalInstanceGenerator;\n\n/**\n * @author zebin.xuzb @ 2012-7-13\n * @version 1.0.0\n */\n@Ignore\npublic class GroupSpringInstanceTest {\n\n    private ApplicationContext context;\n\n    @Before\n    public void start() {\n        System.setProperty(\"canal.instance.destination\", \"retl\");\n        context = new ClassPathXmlApplicationContext(new String[] { \"classpath:spring/group-instance.xml\" });\n    }\n\n    @After\n    public void close() {\n        if (context != null && context instanceof AbstractApplicationContext) {\n            ((AbstractApplicationContext) context).close();\n        }\n    }\n\n    @Test\n    public void testInstance() {\n        CanalInstanceGenerator generator = (CanalInstanceGenerator) context.getBean(\"canalInstanceGenerator\");\n        CanalInstance canalInstance = generator.generate(\"instance\");\n        Assert.notNull(canalInstance);\n\n        canalInstance.start();\n        try {\n            Thread.sleep(10 * 1000);\n        } catch (InterruptedException e) {\n        }\n        canalInstance.stop();\n    }\n}\n"
  },
  {
    "path": "instance/spring/src/test/java/com/alibaba/otter/canal/instance/spring/integrated/MemorySpringInstanceTest.java",
    "content": "package com.alibaba.otter.canal.instance.spring.integrated;\n\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.support.AbstractApplicationContext;\nimport org.springframework.context.support.ClassPathXmlApplicationContext;\nimport org.springframework.util.Assert;\n\nimport com.alibaba.otter.canal.instance.core.CanalInstance;\nimport com.alibaba.otter.canal.instance.core.CanalInstanceGenerator;\n\n/**\n * @author zebin.xuzb @ 2012-7-13\n * @version 1.0.0\n */\n@Ignore\npublic class MemorySpringInstanceTest {\n\n    private ApplicationContext context;\n\n    @Before\n    public void start() {\n        System.setProperty(\"canal.instance.destination\", \"retl\");\n        context = new ClassPathXmlApplicationContext(new String[] { \"classpath:spring/memory-instance.xml\" });\n    }\n\n    @After\n    public void close() {\n        if (context != null && context instanceof AbstractApplicationContext) {\n            ((AbstractApplicationContext) context).close();\n        }\n    }\n\n    @Test\n    public void testInstance() {\n        CanalInstanceGenerator generator = (CanalInstanceGenerator) context.getBean(\"canalInstanceGenerator\");\n        CanalInstance canalInstance = generator.generate(\"instance\");\n        Assert.notNull(canalInstance);\n\n        canalInstance.start();\n        try {\n            Thread.sleep(10 * 1000);\n        } catch (InterruptedException e) {\n        }\n        canalInstance.stop();\n    }\n}\n"
  },
  {
    "path": "instance/spring/src/test/resources/canal.properties",
    "content": "#################################################\n######### \t\tcommon argument\t\t############# \n#################################################\ncanal.id= 1\ncanal.ip=\ncanal.port= 11111\ncanal.zkServers=\n# flush data to zk\ncanal.zookeeper.flush.period = 1000\n## memory store RingBuffer size, should be Math.pow(2,n)\ncanal.instance.memory.buffer.size = 16384\n## memory store RingBuffer used memory unit size , default 1kb\ncanal.instance.memory.buffer.memunit = 1024 \n## meory store gets mode used MEMSIZE or ITEMSIZE\ncanal.instance.memory.batch.mode = MEMSIZE\n\n## detecing config\ncanal.instance.detecting.enable = false\ncanal.instance.detecting.sql = insert into retl.xdual values(1,now()) on duplicate key update x=now()\ncanal.instance.detecting.interval.time = 3\ncanal.instance.detecting.retry.threshold = 3\ncanal.instance.detecting.heartbeatHaEnable = false\n\n# support maximum transaction size, more than the size of the transaction will be cut into multiple transactions delivery\ncanal.instance.transaction.size =  1024\n# mysql fallback connected to new master should fallback times\ncanal.instance.fallbackIntervalInSeconds = 60\n\n# network config\ncanal.instance.network.receiveBufferSize = 16384\ncanal.instance.network.sendBufferSize = 16384\ncanal.instance.network.soTimeout = 30\n\n# binlog filter config\ncanal.instance.filter.query.dcl = false\ncanal.instance.filter.query.dml = false\n\n#################################################\n######### \t\tdestinations\t\t############# \n#################################################\ncanal.destinations= example\n# conf root dir\ncanal.conf.dir = ../conf\n# auto scan instance dir add/remove and start/stop instance\ncanal.auto.scan = true\ncanal.auto.scan.interval = 5\n# as far as possible to stop canal instance where client disconnect\ncanal.stopInstanceAsPossible = true\n\ncanal.instance.global.mode = spring \ncanal.instance.global.lazy = false\n#canal.instance.global.manager.address = 127.0.0.1:1099\ncanal.instance.global.spring.xml = classpath:spring/memory-instance.xml\n#canal.instance.global.spring.xml = classpath:spring/default-instance.xml"
  },
  {
    "path": "instance/spring/src/test/resources/retl/instance.properties",
    "content": "canal.instance.detecting.enable = true\n\n#################################################\n## mysql serverId\ncanal.instance.mysql.slaveId = 1234\n\n# position info\ncanal.instance.master.address = 127.0.0.1:3306\ncanal.instance.master.journal.name = \ncanal.instance.master.position = \ncanal.instance.master.timestamp = \n\ncanal.instance.master1.address = 127.0.0.1:3306\ncanal.instance.master1.journal.name = \ncanal.instance.master1.position = \ncanal.instance.master1.timestamp = \n\ncanal.instance.master2.address = 127.0.0.1:3306\ncanal.instance.master2.journal.name = \ncanal.instance.master2.position = \ncanal.instance.master2.timestamp = \n\n#canal.instance.standby.address = \n#canal.instance.standby.journal.name =\n#canal.instance.standby.position = \n#canal.instance.standby.timestamp = \n\n# username/password\ncanal.instance.dbUsername = xxxxx\ncanal.instance.dbPassword=cZozNf1mzW6EQLGO2q9u99619xbZLO0fbua3EX08r4BWNXb8lAt1aHrTEOBttd6UY8Vnuc0easlVXZDdLtt8BQ==\ncanal.instance.pwdPublicKey=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALK4BUxdDltRRE5/zXpVEVPUgunvscYFtEip3pmLlhrWpacX7y7GCMo2/JM6LeHmiiNdH1FWgGCpUfircSwlWKUCAwEAAQ==\ncanal.instance.defaultDatabaseName =\ncanal.instance.connectionCharset = UTF-8\n# enable druid Decrypt database password\ncanal.instance.enableDruid=true\n\n# table regex\ncanal.instance.filter.regex = .*\\\\..*\n\n#################################################"
  },
  {
    "path": "instance/spring/src/test/resources/spring/default-instance.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:tx=\"http://www.springframework.org/schema/tx\"\n\txmlns:aop=\"http://www.springframework.org/schema/aop\" xmlns:lang=\"http://www.springframework.org/schema/lang\"\n\txmlns:context=\"http://www.springframework.org/schema/context\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd\n           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd\n           http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.0.xsd\n           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd\n           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd\"\n\tdefault-autowire=\"byName\">\n\n\t<!-- properties -->\n\t<bean class=\"com.alibaba.otter.canal.instance.spring.support.PropertyPlaceholderConfigurer\" lazy-init=\"false\">\n\t\t<property name=\"ignoreResourceNotFound\" value=\"true\" />\n\t\t<property name=\"systemPropertiesModeName\" value=\"SYSTEM_PROPERTIES_MODE_OVERRIDE\"/><!-- 允许system覆盖 -->\n\t\t<property name=\"locationNames\">\n\t\t\t<list>\n\t\t\t\t<value>classpath:canal.properties</value>\n\t\t\t\t<value>classpath:${canal.instance.destination:}/instance.properties</value>\n\t\t\t</list>\n\t\t</property>\n\t</bean>\n\t\n\t<bean id=\"socketAddressEditor\" class=\"com.alibaba.otter.canal.instance.spring.support.SocketAddressEditor\" />\n\t<bean class=\"org.springframework.beans.factory.config.CustomEditorConfigurer\"> \n\t\t<property name=\"propertyEditorRegistrars\">\n\t\t\t<list>\n\t\t\t\t<ref bean=\"socketAddressEditor\" />\n\t\t\t</list>\n\t\t</property>\n\t</bean>\n\t\n\t<bean id=\"instance\" class=\"com.alibaba.otter.canal.instance.spring.CanalInstanceWithSpring\">\n\t\t<property name=\"destination\" value=\"${canal.instance.destination}\" />\n\t\t<property name=\"eventParser\">\n\t\t\t<ref bean=\"eventParser\" />\n\t\t</property>\n\t\t<property name=\"eventSink\">\n\t\t\t<ref bean=\"eventSink\" />\n\t\t</property>\n\t\t<property name=\"eventStore\">\n\t\t\t<ref bean=\"eventStore\" />\n\t\t</property>\n\t\t<property name=\"metaManager\">\n\t\t\t<ref bean=\"metaManager\" />\n\t\t</property>\n\t\t<property name=\"alarmHandler\">\n\t\t\t<ref bean=\"alarmHandler\" />\n\t\t</property>\n\t</bean>\n\t\n\t<!-- 报警处理类 -->\n\t<bean id=\"alarmHandler\" class=\"com.alibaba.otter.canal.common.alarm.LogAlarmHandler\" />\n\t\n\t<bean id=\"zkClientx\" class=\"org.springframework.beans.factory.config.MethodInvokingFactoryBean\" >\n\t\t<property name=\"targetClass\" value=\"com.alibaba.otter.canal.common.zookeeper.ZkClientx\" />\n\t\t<property name=\"targetMethod\" value=\"getZkClient\" />\n\t\t<property name=\"arguments\">\n\t\t\t<list>\n\t\t\t\t<value>${canal.zkServers:127.0.0.1:2181}</value>\n\t\t\t</list>\n\t\t</property>\n\t</bean>\n\t\n\t<bean id=\"metaManager\" class=\"com.alibaba.otter.canal.meta.PeriodMixedMetaManager\">\n\t\t<property name=\"zooKeeperMetaManager\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.meta.ZooKeeperMetaManager\">\n\t\t\t\t<property name=\"zkClientx\" ref=\"zkClientx\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"period\" value=\"${canal.zookeeper.flush.period:1000}\" />\n\t</bean>\n\t\n\t<bean id=\"eventStore\" class=\"com.alibaba.otter.canal.store.memory.MemoryEventStoreWithBuffer\">\n\t\t<property name=\"bufferSize\" value=\"${canal.instance.memory.buffer.size:16384}\" />\n\t\t<property name=\"bufferMemUnit\" value=\"${canal.instance.memory.buffer.memunit:1024}\" />\n\t\t<property name=\"batchMode\" value=\"${canal.instance.memory.batch.mode:MEMSIZE}\" />\n\t</bean>\n\t\n\t<bean id=\"eventSink\" class=\"com.alibaba.otter.canal.sink.entry.EntryEventSink\">\n\t\t<property name=\"eventStore\" ref=\"eventStore\" />\n\t</bean>\n\n\t<bean id=\"eventParser\" class=\"com.alibaba.otter.canal.parse.inbound.mysql.MysqlEventParser\">\n\t\t<property name=\"destination\" value=\"${canal.instance.destination}\" />\n\t\t<property name=\"slaveId\" value=\"${canal.instance.mysql.slaveId:1234}\" />\n\t\t<!-- 心跳配置 -->\n\t\t<property name=\"detectingEnable\" value=\"${canal.instance.detecting.enable:false}\" />\n\t\t<property name=\"detectingSQL\" value=\"${canal.instance.detecting.sql}\" />\n\t\t<property name=\"detectingIntervalInSeconds\" value=\"${canal.instance.detecting.interval.time:5}\" />\n\t\t<property name=\"haController\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.ha.HeartBeatHAController\">\n\t\t\t\t<property name=\"detectingRetryTimes\" value=\"${canal.instance.detecting.retry.threshold:3}\" />\n\t\t\t\t<property name=\"switchEnable\" value=\"${canal.instance.detecting.heartbeatHaEnable:false}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t\n\t\t<property name=\"alarmHandler\" ref=\"alarmHandler\" />\n\t\t\n\t\t<!-- 解析过滤处理 -->\n\t\t<property name=\"eventFilter\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.filter.aviater.AviaterRegexFilter\" >\n\t\t\t\t<constructor-arg index=\"0\" value=\"${canal.instance.filter.regex:.*\\..*}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t\n\t\t<!-- 最大事务解析大小，超过该大小后事务将被切分为多个事务投递 -->\n\t\t<property name=\"transactionSize\" value=\"${canal.instance.transaction.size:1024}\" />\n\t\t\n\t\t<!-- 网络链接参数 -->\n\t\t<property name=\"receiveBufferSize\" value=\"${canal.instance.network.receiveBufferSize:16384}\" />\n\t\t<property name=\"sendBufferSize\" value=\"${canal.instance.network.sendBufferSize:16384}\" />\n\t\t<property name=\"defaultConnectionTimeoutInSeconds\" value=\"${canal.instance.network.soTimeout:30}\" />\n\t\t\n\t\t<!-- 解析编码 -->\n\t\t<property name=\"connectionCharset\" value=\"${canal.instance.connectionCharset:UTF-8}\" />\n\t\n\t\t<!-- 解析位点记录 -->\n\t\t<property name=\"logPositionManager\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.index.FailbackLogPositionManager\">\n\t\t\t\t<constructor-arg>\n\t\t\t\t\t<bean class=\"com.alibaba.otter.canal.parse.index.MemoryLogPositionManager\" />\n\t\t\t\t</constructor-arg>\n\t\t\t\t<constructor-arg>\n\t\t\t\t\t<bean class=\"com.alibaba.otter.canal.parse.index.MetaLogPositionManager\">\n\t\t\t\t\t\t<constructor-arg ref=\"metaManager\"/>\n\t\t\t\t\t</bean>\n\t\t\t\t</constructor-arg>\n\t\t\t</bean>\n\t\t</property>\n\t\t\n\t\t<!-- failover切换时回退的时间 -->\n\t\t<property name=\"fallbackIntervalInSeconds\" value=\"${canal.instance.fallbackIntervalInSeconds:60}\" />\n\t\t\n\t\t<!-- 解析数据库信息 -->\n\t\t<property name=\"masterInfo\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.support.AuthenticationInfo\">\n\t\t\t\t<property name=\"address\" value=\"${canal.instance.master.address}\" />\n\t\t\t\t<property name=\"username\" value=\"${canal.instance.dbUsername:retl}\" />\n\t\t\t\t<property name=\"password\" value=\"${canal.instance.dbPassword:retl}\" />\n\t\t\t\t<property name=\"defaultDatabaseName\" value=\"${canal.instance.defaultDatabaseName:}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"standbyInfo\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.support.AuthenticationInfo\">\n\t\t\t\t<property name=\"address\" value=\"${canal.instance.standby.address}\" />\n\t\t\t\t<property name=\"username\" value=\"${canal.instance.dbUsername:retl}\" />\n\t\t\t\t<property name=\"password\" value=\"${canal.instance.dbPassword:retl}\" />\n\t\t\t\t<property name=\"defaultDatabaseName\" value=\"${canal.instance.defaultDatabaseName:}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t\n\t\t<!-- 解析起始位点 -->\n\t\t<property name=\"masterPosition\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.protocol.position.EntryPosition\">\n\t\t\t\t<property name=\"journalName\" value=\"${canal.instance.master.journal.name}\" />\n\t\t\t\t<property name=\"position\" value=\"${canal.instance.master.position}\" />\n\t\t\t\t<property name=\"timestamp\" value=\"${canal.instance.master.timestamp}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"standbyPosition\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.protocol.position.EntryPosition\">\n\t\t\t\t<property name=\"journalName\" value=\"${canal.instance.standby.journal.name}\" />\n\t\t\t\t<property name=\"position\" value=\"${canal.instance.standby.position}\" />\n\t\t\t\t<property name=\"timestamp\" value=\"${canal.instance.standby.timestamp}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"filterQueryDml\" value=\"${canal.instance.filter.query.dml:false}\" />\n\t\t<property name=\"filterQueryDcl\" value=\"${canal.instance.filter.query.dcl:false}\" />\n\t</bean>\n</beans>"
  },
  {
    "path": "instance/spring/src/test/resources/spring/file-instance.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:tx=\"http://www.springframework.org/schema/tx\"\n\txmlns:aop=\"http://www.springframework.org/schema/aop\" xmlns:lang=\"http://www.springframework.org/schema/lang\"\n\txmlns:context=\"http://www.springframework.org/schema/context\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd\n           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd\n           http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.0.xsd\n           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd\n           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd\"\n\tdefault-autowire=\"byName\">\n\n\t<!-- properties -->\n\t<bean class=\"com.alibaba.otter.canal.instance.spring.support.PropertyPlaceholderConfigurer\" lazy-init=\"false\">\n\t\t<property name=\"ignoreResourceNotFound\" value=\"true\" />\n\t\t<property name=\"systemPropertiesModeName\" value=\"SYSTEM_PROPERTIES_MODE_OVERRIDE\"/><!-- 允许system覆盖 -->\n\t\t<property name=\"locationNames\">\n\t\t\t<list>\n\t\t\t\t<value>classpath:canal.properties</value>\n\t\t\t\t<value>classpath:${canal.instance.destination:}/instance.properties</value>\n\t\t\t</list>\n\t\t</property>\n\t</bean>\n\t\n\t<bean id=\"socketAddressEditor\" class=\"com.alibaba.otter.canal.instance.spring.support.SocketAddressEditor\" />\n\t<bean class=\"org.springframework.beans.factory.config.CustomEditorConfigurer\"> \n\t\t<property name=\"propertyEditorRegistrars\">\n\t\t\t<list>\n\t\t\t\t<ref bean=\"socketAddressEditor\" />\n\t\t\t</list>\n\t\t</property>\n\t</bean>\n\t\n\t<bean id=\"instance\" class=\"com.alibaba.otter.canal.instance.spring.CanalInstanceWithSpring\">\n\t\t<property name=\"destination\" value=\"${canal.instance.destination}\" />\n\t\t<property name=\"eventParser\">\n\t\t\t<ref bean=\"eventParser\" />\n\t\t</property>\n\t\t<property name=\"eventSink\">\n\t\t\t<ref bean=\"eventSink\" />\n\t\t</property>\n\t\t<property name=\"eventStore\">\n\t\t\t<ref bean=\"eventStore\" />\n\t\t</property>\n\t\t<property name=\"metaManager\">\n\t\t\t<ref bean=\"metaManager\" />\n\t\t</property>\n\t\t<property name=\"alarmHandler\">\n\t\t\t<ref bean=\"alarmHandler\" />\n\t\t</property>\n\t</bean>\n\t\n\t<!-- 报警处理类 -->\n\t<bean id=\"alarmHandler\" class=\"com.alibaba.otter.canal.common.alarm.LogAlarmHandler\" />\n\t\n\t<bean id=\"metaManager\" class=\"com.alibaba.otter.canal.meta.FileMixedMetaManager\">\n\t\t<property name=\"dataDir\" value=\"${canal.file.data.dir:../conf}\" />\n\t\t<property name=\"period\" value=\"${canal.file.flush.period:1000}\" />\n\t</bean>\n\t\n\t<bean id=\"eventStore\" class=\"com.alibaba.otter.canal.store.memory.MemoryEventStoreWithBuffer\">\n\t\t<property name=\"bufferSize\" value=\"${canal.instance.memory.buffer.size:16384}\" />\n\t\t<property name=\"bufferMemUnit\" value=\"${canal.instance.memory.buffer.memunit:1024}\" />\n\t\t<property name=\"batchMode\" value=\"${canal.instance.memory.batch.mode:MEMSIZE}\" />\n\t</bean>\n\t\n\t<bean id=\"eventSink\" class=\"com.alibaba.otter.canal.sink.entry.EntryEventSink\">\n\t\t<property name=\"eventStore\" ref=\"eventStore\" />\n\t</bean>\n\n\t<bean id=\"eventParser\" class=\"com.alibaba.otter.canal.parse.inbound.mysql.MysqlEventParser\">\n\t\t<property name=\"destination\" value=\"${canal.instance.destination}\" />\n\t\t<property name=\"slaveId\" value=\"${canal.instance.mysql.slaveId:1234}\" />\n\t\t<!-- 心跳配置 -->\n\t\t<property name=\"detectingEnable\" value=\"${canal.instance.detecting.enable:false}\" />\n\t\t<property name=\"detectingSQL\" value=\"${canal.instance.detecting.sql}\" />\n\t\t<property name=\"detectingIntervalInSeconds\" value=\"${canal.instance.detecting.interval.time:5}\" />\n\t\t<property name=\"haController\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.ha.HeartBeatHAController\">\n\t\t\t\t<property name=\"detectingRetryTimes\" value=\"${canal.instance.detecting.retry.threshold:3}\" />\n\t\t\t\t<property name=\"switchEnable\" value=\"${canal.instance.detecting.heartbeatHaEnable:false}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t\n\t\t<property name=\"alarmHandler\" ref=\"alarmHandler\" />\n\t\t\n\t\t<!-- 解析过滤处理 -->\n\t\t<property name=\"eventFilter\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.filter.aviater.AviaterRegexFilter\" >\n\t\t\t\t<constructor-arg index=\"0\" value=\"${canal.instance.filter.regex:.*\\..*}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t\n\t\t<!-- 最大事务解析大小，超过该大小后事务将被切分为多个事务投递 -->\n\t\t<property name=\"transactionSize\" value=\"${canal.instance.transaction.size:1024}\" />\n\t\t\n\t\t<!-- 网络链接参数 -->\n\t\t<property name=\"receiveBufferSize\" value=\"${canal.instance.network.receiveBufferSize:16384}\" />\n\t\t<property name=\"sendBufferSize\" value=\"${canal.instance.network.sendBufferSize:16384}\" />\n\t\t<property name=\"defaultConnectionTimeoutInSeconds\" value=\"${canal.instance.network.soTimeout:30}\" />\n\t\t\n\t\t<!-- 解析编码 -->\n\t\t<property name=\"connectionCharset\" value=\"${canal.instance.connectionCharset:UTF-8}\" />\n\n\t\t<!-- 解析位点记录 -->\n\t\t<property name=\"logPositionManager\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.index.FailbackLogPositionManager\">\n\t\t\t\t<constructor-arg>\n\t\t\t\t\t<bean class=\"com.alibaba.otter.canal.parse.index.MemoryLogPositionManager\" />\n\t\t\t\t</constructor-arg>\n\t\t\t\t<constructor-arg>\n\t\t\t\t\t<bean class=\"com.alibaba.otter.canal.parse.index.MetaLogPositionManager\">\n\t\t\t\t\t\t<constructor-arg>\n\t\t\t\t\t\t\t<ref bean=\"metaManager\"/>\n\t\t\t\t\t\t</constructor-arg>\n\t\t\t\t\t</bean>\n\t\t\t\t</constructor-arg>\n\t\t\t</bean>\n\t\t</property>\n\t\t\n\t\t<!-- failover切换时回退的时间 -->\n\t\t<property name=\"fallbackIntervalInSeconds\" value=\"${canal.instance.fallbackIntervalInSeconds:60}\" />\n\t\t\n\t\t<!-- 解析数据库信息 -->\n\t\t<property name=\"masterInfo\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.support.AuthenticationInfo\">\n\t\t\t\t<property name=\"address\" value=\"${canal.instance.master.address}\" />\n\t\t\t\t<property name=\"username\" value=\"${canal.instance.dbUsername:retl}\" />\n\t\t\t\t<property name=\"password\" value=\"${canal.instance.dbPassword:retl}\" />\n\t\t\t\t<property name=\"defaultDatabaseName\" value=\"${canal.instance.defaultDatabaseName:}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"standbyInfo\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.support.AuthenticationInfo\">\n\t\t\t\t<property name=\"address\" value=\"${canal.instance.standby.address}\" />\n\t\t\t\t<property name=\"username\" value=\"${canal.instance.dbUsername:retl}\" />\n\t\t\t\t<property name=\"password\" value=\"${canal.instance.dbPassword:retl}\" />\n\t\t\t\t<property name=\"defaultDatabaseName\" value=\"${canal.instance.defaultDatabaseName:}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t\n\t\t<!-- 解析起始位点 -->\n\t\t<property name=\"masterPosition\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.protocol.position.EntryPosition\">\n\t\t\t\t<property name=\"journalName\" value=\"${canal.instance.master.journal.name}\" />\n\t\t\t\t<property name=\"position\" value=\"${canal.instance.master.position}\" />\n\t\t\t\t<property name=\"timestamp\" value=\"${canal.instance.master.timestamp}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"standbyPosition\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.protocol.position.EntryPosition\">\n\t\t\t\t<property name=\"journalName\" value=\"${canal.instance.standby.journal.name}\" />\n\t\t\t\t<property name=\"position\" value=\"${canal.instance.standby.position}\" />\n\t\t\t\t<property name=\"timestamp\" value=\"${canal.instance.standby.timestamp}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"filterQueryDml\" value=\"${canal.instance.filter.query.dml:false}\" />\n\t\t<property name=\"filterQueryDcl\" value=\"${canal.instance.filter.query.dcl:false}\" />\n\t</bean>\n</beans>"
  },
  {
    "path": "instance/spring/src/test/resources/spring/group-instance.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:tx=\"http://www.springframework.org/schema/tx\"\n\txmlns:aop=\"http://www.springframework.org/schema/aop\" xmlns:lang=\"http://www.springframework.org/schema/lang\"\n\txmlns:context=\"http://www.springframework.org/schema/context\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd\n           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd\n           http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.0.xsd\n           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd\n           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd\"\n\tdefault-autowire=\"byName\">\n\t\n\t<!-- properties -->\n\t<bean class=\"com.alibaba.otter.canal.instance.spring.support.PropertyPlaceholderConfigurer\" lazy-init=\"false\">\n\t\t<property name=\"ignoreResourceNotFound\" value=\"true\" />\n\t\t<property name=\"systemPropertiesModeName\" value=\"SYSTEM_PROPERTIES_MODE_OVERRIDE\"/><!-- 允许system覆盖 -->\n\t\t<property name=\"locationNames\">\n\t\t\t<list>\n\t\t\t\t<value>classpath:canal.properties</value>\n\t\t\t\t<value>classpath:${canal.instance.destination:}/instance.properties</value>\n\t\t\t</list>\n\t\t</property>\n\t</bean>\n\t\n\t<bean id=\"socketAddressEditor\" class=\"com.alibaba.otter.canal.instance.spring.support.SocketAddressEditor\" />\n\t<bean class=\"org.springframework.beans.factory.config.CustomEditorConfigurer\"> \n\t\t<property name=\"propertyEditorRegistrars\">\n\t\t\t<list>\n\t\t\t\t<ref bean=\"socketAddressEditor\" />\n\t\t\t</list>\n\t\t</property>\n\t</bean>\n\n\t<bean id=\"instance\" class=\"com.alibaba.otter.canal.instance.spring.CanalInstanceWithSpring\">\n\t\t<property name=\"destination\" value=\"${canal.instance.destination}\" />\n\t\t<property name=\"eventParser\">\n\t\t\t<ref bean=\"eventParser\" />\n\t\t</property>\n\t\t<property name=\"eventSink\">\n\t\t\t<ref bean=\"eventSink\" />\n\t\t</property>\n\t\t<property name=\"eventStore\">\n\t\t\t<ref bean=\"eventStore\" />\n\t\t</property>\n\t\t<property name=\"metaManager\">\n\t\t\t<ref bean=\"metaManager\" />\n\t\t</property>\n\t\t<property name=\"alarmHandler\">\n\t\t\t<ref bean=\"alarmHandler\" />\n\t\t</property>\n\t</bean>\n\t\n\t<!-- 报警处理类 -->\n\t<bean id=\"alarmHandler\" class=\"com.alibaba.otter.canal.common.alarm.LogAlarmHandler\" />\n\t\n\t<bean id=\"metaManager\" class=\"com.alibaba.otter.canal.meta.MemoryMetaManager\" />\n\t\n\t<bean id=\"eventStore\" class=\"com.alibaba.otter.canal.store.memory.MemoryEventStoreWithBuffer\">\n\t\t<property name=\"bufferSize\" value=\"${canal.instance.memory.buffer.size:16384}\" />\n\t\t<property name=\"bufferMemUnit\" value=\"${canal.instance.memory.buffer.memunit:1024}\" />\n\t\t<property name=\"batchMode\" value=\"${canal.instance.memory.batch.mode:MEMSIZE}\" />\n\t</bean>\n\t\n\t<bean id=\"eventSink\" class=\"com.alibaba.otter.canal.sink.entry.EntryEventSink\">\n\t\t<property name=\"eventStore\" ref=\"eventStore\" />\n\t</bean>\n\t\n\t<bean id=\"eventParser\" class=\"com.alibaba.otter.canal.parse.inbound.group.GroupEventParser\">\n\t\t<property name=\"eventParsers\">\n\t\t\t<list>\n\t\t\t\t<ref bean=\"eventParser1\" />\n\t\t\t\t<ref bean=\"eventParser2\" />\n\t\t\t</list>\n\t\t</property>\n\t</bean>\n\n\t<bean id=\"eventParser1\" class=\"com.alibaba.otter.canal.parse.inbound.mysql.MysqlEventParser\">\n\t\t<property name=\"destination\" value=\"${canal.instance.destination}\" />\n\t\t<property name=\"slaveId\" value=\"${canal.instance.mysql.slaveId:1234}\" />\n\t\t<!-- 心跳配置 -->\n\t\t<property name=\"detectingEnable\" value=\"${canal.instance.detecting.enable:false}\" />\n\t\t<property name=\"detectingSQL\" value=\"${canal.instance.detecting.sql}\" />\n\t\t<property name=\"detectingIntervalInSeconds\" value=\"${canal.instance.detecting.interval.time:5}\" />\n\t\t<property name=\"haController\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.ha.HeartBeatHAController\">\n\t\t\t\t<property name=\"detectingRetryTimes\" value=\"${canal.instance.detecting.retry.threshold:3}\" />\n\t\t\t\t<property name=\"switchEnable\" value=\"${canal.instance.detecting.heartbeatHaEnable:false}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t\n\t\t<property name=\"alarmHandler\" ref=\"alarmHandler\" />\n\t\t\n\t\t<!-- 解析过滤处理 -->\n\t\t<property name=\"eventFilter\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.filter.aviater.AviaterRegexFilter\" >\n\t\t\t\t<constructor-arg index=\"0\" value=\"${canal.instance.filter.regex:.*\\..*}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t\n\t\t<!-- 最大事务解析大小，超过该大小后事务将被切分为多个事务投递 -->\n\t\t<property name=\"transactionSize\" value=\"${canal.instance.transaction.size:1024}\" />\n\t\t\n\t\t<!-- 网络链接参数 -->\n\t\t<property name=\"receiveBufferSize\" value=\"${canal.instance.network.receiveBufferSize:16384}\" />\n\t\t<property name=\"sendBufferSize\" value=\"${canal.instance.network.sendBufferSize:16384}\" />\n\t\t<property name=\"defaultConnectionTimeoutInSeconds\" value=\"${canal.instance.network.soTimeout:30}\" />\n\t\t\n\t\t<!-- 解析编码 -->\n\t\t<property name=\"connectionCharset\" value=\"${canal.instance.connectionCharset:UTF-8}\" />\n\t\n\t\t<!-- 解析位点记录 -->\n\t\t<property name=\"logPositionManager\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.index.MemoryLogPositionManager\" />\n\t\t</property>\n\t\t\n\t\t<!-- failover切换时回退的时间 -->\n\t\t<property name=\"fallbackIntervalInSeconds\" value=\"${canal.instance.fallbackIntervalInSeconds:60}\" />\n\t\t\n\t\t<!-- 解析数据库信息 -->\n\t\t<property name=\"masterInfo\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.support.AuthenticationInfo\">\n\t\t\t\t<property name=\"address\" value=\"${canal.instance.master1.address}\" />\n\t\t\t\t<property name=\"username\" value=\"${canal.instance.dbUsername:retl}\" />\n\t\t\t\t<property name=\"password\" value=\"${canal.instance.dbPassword:retl}\" />\n\t\t\t\t<property name=\"defaultDatabaseName\" value=\"${canal.instance.defaultDatabaseName:}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"standbyInfo\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.support.AuthenticationInfo\">\n\t\t\t\t<property name=\"address\" value=\"${canal.instance.standby1.address}\" />\n\t\t\t\t<property name=\"username\" value=\"${canal.instance.dbUsername:retl}\" />\n\t\t\t\t<property name=\"password\" value=\"${canal.instance.dbPassword:retl}\" />\n\t\t\t\t<property name=\"defaultDatabaseName\" value=\"${canal.instance.defaultDatabaseName:}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t\n\t\t<!-- 解析起始位点 -->\n\t\t<property name=\"masterPosition\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.protocol.position.EntryPosition\">\n\t\t\t\t<property name=\"journalName\" value=\"${canal.instance.master1.journal.name}\" />\n\t\t\t\t<property name=\"position\" value=\"${canal.instance.master1.position}\" />\n\t\t\t\t<property name=\"timestamp\" value=\"${canal.instance.master1.timestamp}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"standbyPosition\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.protocol.position.EntryPosition\">\n\t\t\t\t<property name=\"journalName\" value=\"${canal.instance.standby1.journal.name}\" />\n\t\t\t\t<property name=\"position\" value=\"${canal.instance.standby1.position}\" />\n\t\t\t\t<property name=\"timestamp\" value=\"${canal.instance.standby1.timestamp}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"filterQueryDml\" value=\"${canal.instance.filter.query.dml:false}\" />\n\t\t<property name=\"filterQueryDcl\" value=\"${canal.instance.filter.query.dcl:false}\" />\n\t</bean>\n\t\n\t<bean id=\"eventParser2\" class=\"com.alibaba.otter.canal.parse.inbound.mysql.MysqlEventParser\">\n\t\t<property name=\"destination\" value=\"${canal.instance.destination}\" />\n\t\t<property name=\"slaveId\" value=\"${canal.instance.mysql.slaveId:1234}\" />\n\t\t<!-- 心跳配置 -->\n\t\t<property name=\"detectingEnable\" value=\"${canal.instance.detecting.enable:false}\" />\n\t\t<property name=\"detectingSQL\" value=\"${canal.instance.detecting.sql}\" />\n\t\t<property name=\"detectingIntervalInSeconds\" value=\"${canal.instance.detecting.interval.time:5}\" />\n\t\t<property name=\"haController\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.ha.HeartBeatHAController\">\n\t\t\t\t<property name=\"detectingRetryTimes\" value=\"${canal.instance.detecting.retry.threshold:3}\" />\n\t\t\t\t<property name=\"switchEnable\" value=\"${canal.instance.detecting.heartbeatHaEnable:false}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t\n\t\t<property name=\"alarmHandler\" ref=\"alarmHandler\" />\n\t\t\n\t\t<!-- 解析过滤处理 -->\n\t\t<property name=\"eventFilter\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.filter.aviater.AviaterRegexFilter\" >\n\t\t\t\t<constructor-arg index=\"0\" value=\"${canal.instance.filter.regex:.*\\..*}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t\n\t\t<!-- 最大事务解析大小，超过该大小后事务将被切分为多个事务投递 -->\n\t\t<property name=\"transactionSize\" value=\"${canal.instance.transaction.size:1024}\" />\n\t\t\n\t\t<!-- 网络链接参数 -->\n\t\t<property name=\"receiveBufferSize\" value=\"${canal.instance.network.receiveBufferSize:16384}\" />\n\t\t<property name=\"sendBufferSize\" value=\"${canal.instance.network.sendBufferSize:16384}\" />\n\t\t<property name=\"defaultConnectionTimeoutInSeconds\" value=\"${canal.instance.network.soTimeout:30}\" />\n\t\t\n\t\t<!-- 解析编码 -->\n\t\t<property name=\"connectionCharset\" value=\"${canal.instance.connectionCharset:UTF-8}\" />\n\t\n\t\t<!-- 解析位点记录 -->\n\t\t<property name=\"logPositionManager\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.index.MemoryLogPositionManager\" />\n\t\t</property>\n\t\t\n\t\t<!-- failover切换时回退的时间 -->\n\t\t<property name=\"fallbackIntervalInSeconds\" value=\"${canal.instance.fallbackIntervalInSeconds:60}\" />\n\t\t\n\t\t<!-- 解析数据库信息 -->\n\t\t<property name=\"masterInfo\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.support.AuthenticationInfo\">\n\t\t\t\t<property name=\"address\" value=\"${canal.instance.master2.address}\" />\n\t\t\t\t<property name=\"username\" value=\"${canal.instance.dbUsername:retl}\" />\n\t\t\t\t<property name=\"password\" value=\"${canal.instance.dbPassword:retl}\" />\n\t\t\t\t<property name=\"defaultDatabaseName\" value=\"${canal.instance.defaultDatabaseName:}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"standbyInfo\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.support.AuthenticationInfo\">\n\t\t\t\t<property name=\"address\" value=\"${canal.instance.standby2.address}\" />\n\t\t\t\t<property name=\"username\" value=\"${canal.instance.dbUsername:retl}\" />\n\t\t\t\t<property name=\"password\" value=\"${canal.instance.dbPassword:retl}\" />\n\t\t\t\t<property name=\"defaultDatabaseName\" value=\"${canal.instance.defaultDatabaseName:}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t\n\t\t<!-- 解析起始位点 -->\n\t\t<property name=\"masterPosition\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.protocol.position.EntryPosition\">\n\t\t\t\t<property name=\"journalName\" value=\"${canal.instance.master2.journal.name}\" />\n\t\t\t\t<property name=\"position\" value=\"${canal.instance.master2.position}\" />\n\t\t\t\t<property name=\"timestamp\" value=\"${canal.instance.master2.timestamp}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"standbyPosition\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.protocol.position.EntryPosition\">\n\t\t\t\t<property name=\"journalName\" value=\"${canal.instance.standby2.journal.name}\" />\n\t\t\t\t<property name=\"position\" value=\"${canal.instance.standby2.position}\" />\n\t\t\t\t<property name=\"timestamp\" value=\"${canal.instance.standby2.timestamp}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"filterQueryDml\" value=\"${canal.instance.filter.query.dml:false}\" />\n\t\t<property name=\"filterQueryDcl\" value=\"${canal.instance.filter.query.dcl:false}\" />\n\t</bean>\n</beans>"
  },
  {
    "path": "instance/spring/src/test/resources/spring/memory-instance.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:tx=\"http://www.springframework.org/schema/tx\"\n\txmlns:aop=\"http://www.springframework.org/schema/aop\" xmlns:lang=\"http://www.springframework.org/schema/lang\"\n\txmlns:context=\"http://www.springframework.org/schema/context\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd\n           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd\n           http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.0.xsd\n           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd\n           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd\"\n\tdefault-autowire=\"byName\">\n\t\n\t<!-- properties -->\n\t<bean class=\"com.alibaba.otter.canal.instance.spring.support.PropertyPlaceholderConfigurer\" lazy-init=\"false\">\n\t\t<property name=\"ignoreResourceNotFound\" value=\"true\" />\n\t\t<property name=\"systemPropertiesModeName\" value=\"SYSTEM_PROPERTIES_MODE_OVERRIDE\"/><!-- 允许system覆盖 -->\n\t\t<property name=\"locationNames\">\n\t\t\t<list>\n\t\t\t\t<value>classpath:canal.properties</value>\n\t\t\t\t<value>classpath:${canal.instance.destination:}/instance.properties</value>\n\t\t\t</list>\n\t\t</property>\n\t</bean>\n\t\n\t<bean id=\"socketAddressEditor\" class=\"com.alibaba.otter.canal.instance.spring.support.SocketAddressEditor\" />\n\t<bean class=\"org.springframework.beans.factory.config.CustomEditorConfigurer\"> \n\t\t<property name=\"propertyEditorRegistrars\">\n\t\t\t<list>\n\t\t\t\t<ref bean=\"socketAddressEditor\" />\n\t\t\t</list>\n\t\t</property>\n\t</bean>\n\n\t<bean id=\"instance\" class=\"com.alibaba.otter.canal.instance.spring.CanalInstanceWithSpring\">\n\t\t<property name=\"destination\" value=\"${canal.instance.destination}\" />\n\t\t<property name=\"eventParser\">\n\t\t\t<ref bean=\"eventParser\" />\n\t\t</property>\n\t\t<property name=\"eventSink\">\n\t\t\t<ref bean=\"eventSink\" />\n\t\t</property>\n\t\t<property name=\"eventStore\">\n\t\t\t<ref bean=\"eventStore\" />\n\t\t</property>\n\t\t<property name=\"metaManager\">\n\t\t\t<ref bean=\"metaManager\" />\n\t\t</property>\n\t\t<property name=\"alarmHandler\">\n\t\t\t<ref bean=\"alarmHandler\" />\n\t\t</property>\n\t</bean>\n\t\n\t<!-- 报警处理类 -->\n\t<bean id=\"alarmHandler\" class=\"com.alibaba.otter.canal.common.alarm.LogAlarmHandler\" />\n\t\n\t<bean id=\"metaManager\" class=\"com.alibaba.otter.canal.meta.MemoryMetaManager\" />\n\t\n\t<bean id=\"eventStore\" class=\"com.alibaba.otter.canal.store.memory.MemoryEventStoreWithBuffer\">\n\t\t<property name=\"bufferSize\" value=\"${canal.instance.memory.buffer.size:16384}\" />\n\t\t<property name=\"bufferMemUnit\" value=\"${canal.instance.memory.buffer.memunit:1024}\" />\n\t\t<property name=\"batchMode\" value=\"${canal.instance.memory.batch.mode:MEMSIZE}\" />\n\t</bean>\n\t\n\t<bean id=\"eventSink\" class=\"com.alibaba.otter.canal.sink.entry.EntryEventSink\">\n\t\t<property name=\"eventStore\" ref=\"eventStore\" />\n\t</bean>\n\n\t<bean id=\"eventParser\" class=\"com.alibaba.otter.canal.parse.inbound.mysql.MysqlEventParser\">\n\t\t<property name=\"destination\" value=\"${canal.instance.destination}\" />\n\t\t<property name=\"slaveId\" value=\"${canal.instance.mysql.slaveId:1234}\" />\n\t\t<!-- 心跳配置 -->\n\t\t<property name=\"detectingEnable\" value=\"${canal.instance.detecting.enable:false}\" />\n\t\t<property name=\"detectingSQL\" value=\"${canal.instance.detecting.sql}\" />\n\t\t<property name=\"detectingIntervalInSeconds\" value=\"${canal.instance.detecting.interval.time:5}\" />\n\t\t<property name=\"haController\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.ha.HeartBeatHAController\">\n\t\t\t\t<property name=\"detectingRetryTimes\" value=\"${canal.instance.detecting.retry.threshold:3}\" />\n\t\t\t\t<property name=\"switchEnable\" value=\"${canal.instance.detecting.heartbeatHaEnable:false}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t\n\t\t<property name=\"alarmHandler\" ref=\"alarmHandler\" />\n\t\t\n\t\t<!-- 解析过滤处理 -->\n\t\t<property name=\"eventFilter\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.filter.aviater.AviaterRegexFilter\" >\n\t\t\t\t<constructor-arg index=\"0\" value=\"${canal.instance.filter.regex:.*\\..*}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t\n\t\t<!-- 最大事务解析大小，超过该大小后事务将被切分为多个事务投递 -->\n\t\t<property name=\"transactionSize\" value=\"${canal.instance.transaction.size:1024}\" />\n\t\t\n\t\t<!-- 网络链接参数 -->\n\t\t<property name=\"receiveBufferSize\" value=\"${canal.instance.network.receiveBufferSize:16384}\" />\n\t\t<property name=\"sendBufferSize\" value=\"${canal.instance.network.sendBufferSize:16384}\" />\n\t\t<property name=\"defaultConnectionTimeoutInSeconds\" value=\"${canal.instance.network.soTimeout:30}\" />\n\t\t\n\t\t<!-- 解析编码 -->\n\t\t<property name=\"connectionCharset\" value=\"${canal.instance.connectionCharset:UTF-8}\" />\n\t\n\t\t<!-- 解析位点记录 -->\n\t\t<property name=\"logPositionManager\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.index.MemoryLogPositionManager\" />\n\t\t</property>\n\t\t\n\t\t<!-- failover切换时回退的时间 -->\n\t\t<property name=\"fallbackIntervalInSeconds\" value=\"${canal.instance.fallbackIntervalInSeconds:60}\" />\n\t\t\n\t\t<!-- 解析数据库信息 -->\n\t\t<property name=\"masterInfo\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.support.AuthenticationInfo\">\n\t\t\t\t<property name=\"address\" value=\"${canal.instance.master.address}\" />\n\t\t\t\t<property name=\"username\" value=\"${canal.instance.dbUsername:retl}\" />\n\t\t\t\t<property name=\"password\" value=\"${canal.instance.dbPassword:retl}\" />\n\t\t\t\t<property name=\"defaultDatabaseName\" value=\"${canal.instance.defaultDatabaseName:}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"standbyInfo\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.parse.support.AuthenticationInfo\">\n\t\t\t\t<property name=\"address\" value=\"${canal.instance.standby.address}\" />\n\t\t\t\t<property name=\"username\" value=\"${canal.instance.dbUsername:retl}\" />\n\t\t\t\t<property name=\"password\" value=\"${canal.instance.dbPassword:retl}\" />\n\t\t\t\t<property name=\"defaultDatabaseName\" value=\"${canal.instance.defaultDatabaseName:}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t\n\t\t<!-- 解析起始位点 -->\n\t\t<property name=\"masterPosition\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.protocol.position.EntryPosition\">\n\t\t\t\t<property name=\"journalName\" value=\"${canal.instance.master.journal.name}\" />\n\t\t\t\t<property name=\"position\" value=\"${canal.instance.master.position}\" />\n\t\t\t\t<property name=\"timestamp\" value=\"${canal.instance.master.timestamp}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"standbyPosition\">\n\t\t\t<bean class=\"com.alibaba.otter.canal.protocol.position.EntryPosition\">\n\t\t\t\t<property name=\"journalName\" value=\"${canal.instance.standby.journal.name}\" />\n\t\t\t\t<property name=\"position\" value=\"${canal.instance.standby.position}\" />\n\t\t\t\t<property name=\"timestamp\" value=\"${canal.instance.standby.timestamp}\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"filterQueryDml\" value=\"${canal.instance.filter.query.dml:false}\" />\n\t\t<property name=\"filterQueryDcl\" value=\"${canal.instance.filter.query.dcl:false}\" />\n\t</bean>\n</beans>"
  },
  {
    "path": "meta/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>com.alibaba.otter</groupId>\n\t\t<artifactId>canal</artifactId>\n\t\t<version>1.1.9-SNAPSHOT</version>\n\t\t<relativePath>../pom.xml</relativePath>\n\t</parent>\n\t<groupId>com.alibaba.otter</groupId>\n\t<artifactId>canal.meta</artifactId>\n\t<packaging>jar</packaging>\n\t<name>canal meta module for otter ${project.version}</name>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.common</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.protocol</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<!-- test dependency -->\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "meta/src/main/java/com/alibaba/otter/canal/meta/CanalMetaManager.java",
    "content": "package com.alibaba.otter.canal.meta;\r\n\r\nimport java.util.List;\r\nimport java.util.Map;\r\n\r\nimport com.alibaba.otter.canal.common.CanalLifeCycle;\r\nimport com.alibaba.otter.canal.meta.exception.CanalMetaManagerException;\r\nimport com.alibaba.otter.canal.protocol.ClientIdentity;\r\nimport com.alibaba.otter.canal.protocol.position.Position;\r\nimport com.alibaba.otter.canal.protocol.position.PositionRange;\r\n\r\n/**\r\n * meta信息管理器\r\n * \r\n * @author jianghang 2012-6-14 下午09:28:48\r\n * @author zebin.xuzb\r\n * @version 1.0.0\r\n */\r\npublic interface CanalMetaManager extends CanalLifeCycle {\r\n\r\n    /**\r\n     * 增加一个 client订阅 <br/>\r\n     * 如果 client已经存在，则不做任何修改\r\n     */\r\n    void subscribe(ClientIdentity clientIdentity) throws CanalMetaManagerException;\r\n\r\n    /**\r\n     * 判断是否订阅\r\n     */\r\n    boolean hasSubscribe(ClientIdentity clientIdentity) throws CanalMetaManagerException;\r\n\r\n    /**\r\n     * 取消client订阅\r\n     */\r\n    void unsubscribe(ClientIdentity clientIdentity) throws CanalMetaManagerException;\r\n\r\n    /**\r\n     * 获取 cursor 游标\r\n     */\r\n    Position getCursor(ClientIdentity clientIdentity) throws CanalMetaManagerException;\r\n\r\n    /**\r\n     * 更新 cursor 游标\r\n     */\r\n    void updateCursor(ClientIdentity clientIdentity, Position position) throws CanalMetaManagerException;\r\n\r\n    /**\r\n     * 根据指定的destination列出当前所有的clientIdentity信息\r\n     */\r\n    List<ClientIdentity> listAllSubscribeInfo(String destination) throws CanalMetaManagerException;\r\n\r\n    /**\r\n     * 获得该client最新的一个位置\r\n     */\r\n    PositionRange getFirstBatch(ClientIdentity clientIdentity) throws CanalMetaManagerException;\r\n\r\n    /**\r\n     * 获得该clientId最新的一个位置\r\n     */\r\n    PositionRange getLastestBatch(ClientIdentity clientIdentity) throws CanalMetaManagerException;\r\n\r\n    /**\r\n     * 为 client 产生一个唯一、递增的id\r\n     */\r\n    Long addBatch(ClientIdentity clientIdentity, PositionRange positionRange) throws CanalMetaManagerException;\r\n\r\n    /**\r\n     * 指定batchId，插入batch数据\r\n     */\r\n    void addBatch(ClientIdentity clientIdentity, PositionRange positionRange, Long batchId)\r\n                                                                                           throws CanalMetaManagerException;\r\n\r\n    /**\r\n     * 根据唯一messageId，查找对应的数据起始信息\r\n     */\r\n    PositionRange getBatch(ClientIdentity clientIdentity, Long batchId) throws CanalMetaManagerException;\r\n\r\n    /**\r\n     * 对一个batch的确认\r\n     */\r\n    PositionRange removeBatch(ClientIdentity clientIdentity, Long batchId) throws CanalMetaManagerException;\r\n\r\n    /**\r\n     * 查询当前的所有batch信息\r\n     */\r\n    Map<Long, PositionRange> listAllBatchs(ClientIdentity clientIdentity) throws CanalMetaManagerException;\r\n\r\n    /**\r\n     * 清除对应的batch信息\r\n     */\r\n    void clearAllBatchs(ClientIdentity clientIdentity) throws CanalMetaManagerException;\r\n\r\n}\r\n"
  },
  {
    "path": "meta/src/main/java/com/alibaba/otter/canal/meta/FileMixedMetaManager.java",
    "content": "package com.alibaba.otter.canal.meta;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.commons.io.FileUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.slf4j.MDC;\nimport org.springframework.util.Assert;\n\nimport com.alibaba.otter.canal.common.utils.JsonUtils;\nimport com.alibaba.otter.canal.meta.exception.CanalMetaManagerException;\nimport com.alibaba.otter.canal.protocol.ClientIdentity;\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\nimport com.alibaba.otter.canal.protocol.position.Position;\nimport com.google.common.collect.Lists;\nimport com.google.common.collect.MigrateMap;\n\n/**\n * 基于文件刷新的metaManager实现\n * \n * <pre>\n * 策略：\n * 1. 先写内存，然后定时刷新数据到File\n * 2. 数据采取overwrite模式(只保留最后一次)，通过logger实施append模式(记录历史版本)\n * </pre>\n * \n * @author jianghang 2013-4-15 下午05:55:57\n * @version 1.0.4\n */\npublic class FileMixedMetaManager extends MemoryMetaManager implements CanalMetaManager {\n\n    private static final Logger      logger       = LoggerFactory.getLogger(FileMixedMetaManager.class);\n    private static final Charset     charset      = StandardCharsets.UTF_8;\n    private File                     dataDir;\n    private String                   dataFileName = \"meta.dat\";\n    private Map<String, File>        dataFileCaches;\n    private ScheduledExecutorService executor;\n    @SuppressWarnings(\"serial\")\n    private final Position           nullCursor   = new Position() {\n                                                  };\n    private long                     period       = 1000;                                               // 单位ms\n    private Set<ClientIdentity>      updateCursorTasks;\n\n    public void start() {\n        super.start();\n        Assert.notNull(dataDir);\n        if (!dataDir.exists()) {\n            try {\n                FileUtils.forceMkdir(dataDir);\n            } catch (IOException e) {\n                throw new CanalMetaManagerException(e);\n            }\n        }\n\n        if (!dataDir.canRead() || !dataDir.canWrite()) {\n            throw new CanalMetaManagerException(\"dir[\" + dataDir.getPath() + \"] can not read/write\");\n        }\n\n        dataFileCaches = MigrateMap.makeComputingMap(this::getDataFile);\n\n        executor = Executors.newScheduledThreadPool(1);\n        destinations = MigrateMap.makeComputingMap(this::loadClientIdentity);\n\n        cursors = MigrateMap.makeComputingMap(clientIdentity -> {\n            Position position = loadCursor(clientIdentity.getDestination(), clientIdentity);\n            if (position == null) {\n                return nullCursor; // 返回一个空对象标识，避免出现异常\n            } else {\n                return position;\n            }\n        });\n\n        updateCursorTasks = Collections.synchronizedSet(new HashSet<>());\n\n        // 启动定时工作任务\n        executor.scheduleAtFixedRate(() -> {\n            List<ClientIdentity> tasks = new ArrayList<>(updateCursorTasks);\n            for (ClientIdentity clientIdentity : tasks) {\n                MDC.put(\"destination\", String.valueOf(clientIdentity.getDestination()));\n                try {\n                    updateCursorTasks.remove(clientIdentity);\n\n                    // 定时将内存中的最新值刷到file中，多次变更只刷一次\n                    if (logger.isInfoEnabled()) {\n                        LogPosition cursor = (LogPosition) getCursor(clientIdentity);\n                        logger.info(\"clientId:{} cursor:[{},{},{},{},{}] address[{}]\", clientIdentity.getClientId(), cursor.getPostion().getJournalName(),\n                                cursor.getPostion().getPosition(), cursor.getPostion().getTimestamp(),\n                                cursor.getPostion().getServerId(), cursor.getPostion().getGtid(),\n                                cursor.getIdentity().getSourceAddress().toString());\n                    }\n                    flushDataToFile(clientIdentity.getDestination());\n                } catch (Throwable e) {\n                    // ignore\n                    logger.error(\"period update\" + clientIdentity.toString() + \" curosr failed!\", e);\n                }\n            }\n        },\n            period,\n            period,\n            TimeUnit.MILLISECONDS);\n    }\n\n    public void stop() {\n        flushDataToFile();// 刷新数据\n\n        super.stop();\n        executor.shutdownNow();\n        destinations.clear();\n        batches.clear();\n    }\n\n    public void subscribe(final ClientIdentity clientIdentity) throws CanalMetaManagerException {\n        super.subscribe(clientIdentity);\n\n        // 订阅信息频率发生比较低，不需要做定时merge处理\n        executor.submit(() -> flushDataToFile(clientIdentity.getDestination()));\n    }\n\n    public void unsubscribe(final ClientIdentity clientIdentity) throws CanalMetaManagerException {\n        super.unsubscribe(clientIdentity);\n\n        // 订阅信息频率发生比较低，不需要做定时merge处理\n        executor.submit(() -> flushDataToFile(clientIdentity.getDestination()));\n    }\n\n    public void updateCursor(ClientIdentity clientIdentity, Position position) throws CanalMetaManagerException {\n        updateCursorTasks.add(clientIdentity);// 添加到任务队列中进行触发\n        super.updateCursor(clientIdentity, position);\n    }\n\n    public Position getCursor(ClientIdentity clientIdentity) throws CanalMetaManagerException {\n        Position position = super.getCursor(clientIdentity);\n        if (position == nullCursor) {\n            return null;\n        } else {\n            return position;\n        }\n    }\n\n    // ============================ helper method ======================\n\n    private File getDataFile(String destination) {\n        File destinationMetaDir = new File(dataDir, destination);\n        if (!destinationMetaDir.exists()) {\n            try {\n                FileUtils.forceMkdir(destinationMetaDir);\n            } catch (IOException e) {\n                throw new CanalMetaManagerException(e);\n            }\n        }\n\n        return new File(destinationMetaDir, dataFileName);\n    }\n\n    private FileMetaInstanceData loadDataFromFile(File dataFile) {\n        try {\n            if (!dataFile.exists()) {\n                return null;\n            }\n\n            String json = FileUtils.readFileToString(dataFile, charset);\n            return JsonUtils.unmarshalFromString(json, FileMetaInstanceData.class);\n        } catch (IOException e) {\n            throw new CanalMetaManagerException(e);\n        }\n    }\n\n    private void flushDataToFile() {\n        for (String destination : destinations.keySet()) {\n            flushDataToFile(destination);\n        }\n    }\n\n    private void flushDataToFile(String destination) {\n        flushDataToFile(destination, dataFileCaches.get(destination));\n    }\n\n    private void flushDataToFile(String destination, File dataFile) {\n        FileMetaInstanceData data = new FileMetaInstanceData();\n        if (destinations.containsKey(destination)) {\n            synchronized (destination.intern()) { // 基于destination控制一下并发更新\n                data.setDestination(destination);\n\n                List<FileMetaClientIdentityData> clientDatas = new ArrayList<>();\n                List<ClientIdentity> clientIdentitys = destinations.get(destination);\n                for (ClientIdentity clientIdentity : clientIdentitys) {\n                    FileMetaClientIdentityData clientData = new FileMetaClientIdentityData();\n                    clientData.setClientIdentity(clientIdentity);\n                    Position position = cursors.get(clientIdentity);\n                    if (position != null && position != nullCursor) {\n                        clientData.setCursor((LogPosition) position);\n                    }\n\n                    clientDatas.add(clientData);\n                }\n\n                data.setClientDatas(clientDatas);\n            }\n            //fixed issue https://github.com/alibaba/canal/issues/4312\n            //客户端数据为空时不覆盖文件内容 （适合单客户端）\n            if(data.getClientDatas().isEmpty()){\n                return;\n            }\n            String json = JsonUtils.marshalToString(data);\n            try {\n                FileUtils.writeStringToFile(dataFile, json);\n            } catch (IOException e) {\n                throw new CanalMetaManagerException(e);\n            }\n        }\n    }\n\n    private List<ClientIdentity> loadClientIdentity(String destination) {\n        List<ClientIdentity> result = Lists.newArrayList();\n\n        FileMetaInstanceData data = loadDataFromFile(dataFileCaches.get(destination));\n        if (data == null) {\n            return result;\n        }\n\n        List<FileMetaClientIdentityData> clientDatas = data.getClientDatas();\n        if (clientDatas == null) {\n            return result;\n        }\n\n        for (FileMetaClientIdentityData clientData : clientDatas) {\n            if (clientData.getClientIdentity().getDestination().equals(destination)) {\n                result.add(clientData.getClientIdentity());\n            }\n        }\n\n        return result;\n    }\n\n    private Position loadCursor(String destination, ClientIdentity clientIdentity) {\n        FileMetaInstanceData data = loadDataFromFile(dataFileCaches.get(destination));\n        if (data == null) {\n            return null;\n        }\n\n        List<FileMetaClientIdentityData> clientDatas = data.getClientDatas();\n        if (clientDatas == null) {\n            return null;\n        }\n\n        for (FileMetaClientIdentityData clientData : clientDatas) {\n            if (clientData.getClientIdentity() != null && clientData.getClientIdentity().equals(clientIdentity)) {\n                return clientData.getCursor();\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * 描述一个clientIdentity对应的数据对象\n     * \n     * @author jianghang 2013-4-15 下午06:19:40\n     * @version 1.0.4\n     */\n    public static class FileMetaClientIdentityData {\n\n        private ClientIdentity clientIdentity;\n        private LogPosition    cursor;\n\n        public FileMetaClientIdentityData(){\n\n        }\n\n        public FileMetaClientIdentityData(ClientIdentity clientIdentity, MemoryClientIdentityBatch batch,\n                                          LogPosition cursor){\n            this.clientIdentity = clientIdentity;\n            this.cursor = cursor;\n        }\n\n        public ClientIdentity getClientIdentity() {\n            return clientIdentity;\n        }\n\n        public void setClientIdentity(ClientIdentity clientIdentity) {\n            this.clientIdentity = clientIdentity;\n        }\n\n        public Position getCursor() {\n            return cursor;\n        }\n\n        public void setCursor(LogPosition cursor) {\n            this.cursor = cursor;\n        }\n\n    }\n\n    /**\n     * 描述整个canal instance对应数据对象\n     * \n     * @author jianghang 2013-4-15 下午06:20:22\n     * @version 1.0.4\n     */\n    public static class FileMetaInstanceData {\n\n        private String                           destination;\n        private List<FileMetaClientIdentityData> clientDatas;\n\n        public FileMetaInstanceData(){\n\n        }\n\n        public FileMetaInstanceData(String destination, List<FileMetaClientIdentityData> clientDatas){\n            this.destination = destination;\n            this.clientDatas = clientDatas;\n        }\n\n        public String getDestination() {\n            return destination;\n        }\n\n        public void setDestination(String destination) {\n            this.destination = destination;\n        }\n\n        public List<FileMetaClientIdentityData> getClientDatas() {\n            return clientDatas;\n        }\n\n        public void setClientDatas(List<FileMetaClientIdentityData> clientDatas) {\n            this.clientDatas = clientDatas;\n        }\n\n    }\n\n    public void setDataDir(String dataDir) {\n        this.dataDir = new File(dataDir);\n    }\n\n    public void setDataDirByFile(File dataDir) {\n        this.dataDir = dataDir;\n    }\n\n    public void setPeriod(long period) {\n        this.period = period;\n    }\n\n}\n"
  },
  {
    "path": "meta/src/main/java/com/alibaba/otter/canal/meta/MemoryMetaManager.java",
    "content": "package com.alibaba.otter.canal.meta;\n\nimport java.util.*;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport com.alibaba.otter.canal.common.AbstractCanalLifeCycle;\nimport com.alibaba.otter.canal.meta.exception.CanalMetaManagerException;\nimport com.alibaba.otter.canal.protocol.ClientIdentity;\nimport com.alibaba.otter.canal.protocol.position.Position;\nimport com.alibaba.otter.canal.protocol.position.PositionRange;\nimport com.google.common.collect.Lists;\nimport com.google.common.collect.MapMaker;\nimport com.google.common.collect.Maps;\nimport com.google.common.collect.MigrateMap;\n\n/**\n * 内存版实现\n * \n * @author zebin.xuzb @ 2012-7-2\n * @version 1.0.0\n */\npublic class MemoryMetaManager extends AbstractCanalLifeCycle implements CanalMetaManager {\n\n    protected Map<String, List<ClientIdentity>>              destinations;\n    protected Map<ClientIdentity, MemoryClientIdentityBatch> batches;\n    protected Map<ClientIdentity, Position>                  cursors;\n\n    public void start() {\n        super.start();\n\n        batches = MigrateMap.makeComputingMap(MemoryClientIdentityBatch::create);\n\n        cursors = new MapMaker().makeMap();\n\n        destinations = MigrateMap.makeComputingMap(destination -> new ArrayList<>());\n    }\n\n    public void stop() {\n        super.stop();\n\n        destinations.clear();\n        cursors.clear();\n        for (MemoryClientIdentityBatch batch : batches.values()) {\n            batch.clearPositionRanges();\n        }\n    }\n\n    public synchronized void subscribe(ClientIdentity clientIdentity) throws CanalMetaManagerException {\n        List<ClientIdentity> clientIdentitys = destinations.get(clientIdentity.getDestination());\n\n        if (clientIdentitys.contains(clientIdentity)) {\n            clientIdentitys.remove(clientIdentity);\n        }\n\n        clientIdentitys.add(clientIdentity);\n    }\n\n    public synchronized boolean hasSubscribe(ClientIdentity clientIdentity) throws CanalMetaManagerException {\n        List<ClientIdentity> clientIdentitys = destinations.get(clientIdentity.getDestination());\n        return clientIdentitys != null && clientIdentitys.contains(clientIdentity);\n    }\n\n    public synchronized void unsubscribe(ClientIdentity clientIdentity) throws CanalMetaManagerException {\n        List<ClientIdentity> clientIdentitys = destinations.get(clientIdentity.getDestination());\n        if (clientIdentitys != null && clientIdentitys.contains(clientIdentity)) {\n            clientIdentitys.remove(clientIdentity);\n        }\n    }\n\n    public synchronized List<ClientIdentity> listAllSubscribeInfo(String destination) throws CanalMetaManagerException {\n        // fixed issue #657, fixed ConcurrentModificationException\n        return Lists.newArrayList(destinations.get(destination));\n    }\n\n    public Position getCursor(ClientIdentity clientIdentity) throws CanalMetaManagerException {\n        return cursors.get(clientIdentity);\n    }\n\n    public void updateCursor(ClientIdentity clientIdentity, Position position) throws CanalMetaManagerException {\n        cursors.put(clientIdentity, position);\n    }\n\n    public Long addBatch(ClientIdentity clientIdentity, PositionRange positionRange) throws CanalMetaManagerException {\n        return batches.get(clientIdentity).addPositionRange(positionRange);\n    }\n\n    public void addBatch(ClientIdentity clientIdentity, PositionRange positionRange, Long batchId)\n                                                                                                  throws CanalMetaManagerException {\n        batches.get(clientIdentity).addPositionRange(positionRange, batchId);// 添加记录到指定batchId\n    }\n\n    public PositionRange removeBatch(ClientIdentity clientIdentity, Long batchId) throws CanalMetaManagerException {\n        return batches.get(clientIdentity).removePositionRange(batchId);\n    }\n\n    public PositionRange getBatch(ClientIdentity clientIdentity, Long batchId) throws CanalMetaManagerException {\n        return batches.get(clientIdentity).getPositionRange(batchId);\n    }\n\n    public PositionRange getLastestBatch(ClientIdentity clientIdentity) throws CanalMetaManagerException {\n        return batches.get(clientIdentity).getLastestPositionRange();\n    }\n\n    public PositionRange getFirstBatch(ClientIdentity clientIdentity) throws CanalMetaManagerException {\n        return batches.get(clientIdentity).getFirstPositionRange();\n    }\n\n    public Map<Long, PositionRange> listAllBatchs(ClientIdentity clientIdentity) throws CanalMetaManagerException {\n        return batches.get(clientIdentity).listAllPositionRange();\n    }\n\n    public void clearAllBatchs(ClientIdentity clientIdentity) throws CanalMetaManagerException {\n        batches.get(clientIdentity).clearPositionRanges();\n    }\n\n    // ============================\n\n    public static class MemoryClientIdentityBatch {\n\n        private ClientIdentity           clientIdentity;\n        private Map<Long, PositionRange> batches          = new MapMaker().makeMap();\n        private AtomicLong               atomicMaxBatchId = new AtomicLong(1);\n\n        public static MemoryClientIdentityBatch create(ClientIdentity clientIdentity) {\n            return new MemoryClientIdentityBatch(clientIdentity);\n        }\n\n        public MemoryClientIdentityBatch(){\n\n        }\n\n        protected MemoryClientIdentityBatch(ClientIdentity clientIdentity){\n            this.clientIdentity = clientIdentity;\n        }\n\n        public synchronized void addPositionRange(PositionRange positionRange, Long batchId) {\n            updateMaxId(batchId);\n            batches.put(batchId, positionRange);\n        }\n\n        public synchronized Long addPositionRange(PositionRange positionRange) {\n            Long batchId = atomicMaxBatchId.getAndIncrement();\n            batches.put(batchId, positionRange);\n            return batchId;\n        }\n\n        public synchronized PositionRange removePositionRange(Long batchId) {\n            if (batches.containsKey(batchId)) {\n                Long minBatchId = Collections.min(batches.keySet());\n                if (!minBatchId.equals(batchId)) {\n                    // 检查一下提交的ack/rollback，必须按batchId分出去的顺序提交，否则容易出现丢数据\n                    throw new CanalMetaManagerException(String.format(\"batchId:%d is not the firstly:%d\",\n                        batchId,\n                        minBatchId));\n                }\n                return batches.remove(batchId);\n            } else {\n                return null;\n            }\n        }\n\n        public synchronized PositionRange getPositionRange(Long batchId) {\n            return batches.get(batchId);\n        }\n\n        public synchronized PositionRange getLastestPositionRange() {\n            if (batches.size() == 0) {\n                return null;\n            } else {\n                Long batchId = Collections.max(batches.keySet());\n                return batches.get(batchId);\n            }\n        }\n\n        public synchronized PositionRange getFirstPositionRange() {\n            if (batches.size() == 0) {\n                return null;\n            } else {\n                Long batchId = Collections.min(batches.keySet());\n                return batches.get(batchId);\n            }\n        }\n\n        public synchronized Map<Long, PositionRange> listAllPositionRange() {\n            Set<Long> batchIdSets = batches.keySet();\n            List<Long> batchIds = new ArrayList<>(batchIdSets);\n            Collections.sort(new ArrayList<>(batchIds));\n\n            return Maps.newHashMap(batches);\n        }\n\n        public synchronized void clearPositionRanges() {\n            batches.clear();\n        }\n\n        private synchronized void updateMaxId(Long batchId) {\n            if (atomicMaxBatchId.get() < batchId + 1) {\n                atomicMaxBatchId.set(batchId + 1);\n            }\n        }\n\n        // ============ setter & getter =========\n\n        public ClientIdentity getClientIdentity() {\n            return clientIdentity;\n        }\n\n        public void setClientIdentity(ClientIdentity clientIdentity) {\n            this.clientIdentity = clientIdentity;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "meta/src/main/java/com/alibaba/otter/canal/meta/MixedMetaManager.java",
    "content": "package com.alibaba.otter.canal.meta;\n\nimport java.util.Map;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport org.springframework.util.Assert;\n\nimport com.alibaba.otter.canal.meta.exception.CanalMetaManagerException;\nimport com.alibaba.otter.canal.protocol.ClientIdentity;\nimport com.alibaba.otter.canal.protocol.position.Position;\nimport com.alibaba.otter.canal.protocol.position.PositionRange;\nimport com.google.common.collect.MigrateMap;\n\n/**\n * 组合memory + zookeeper的使用模式\n *\n * @author jianghang 2012-7-11 下午03:58:00\n * @version 1.0.0\n */\n\npublic class MixedMetaManager extends MemoryMetaManager implements CanalMetaManager {\n\n    private ExecutorService      executor;\n    private ZooKeeperMetaManager zooKeeperMetaManager;\n    @SuppressWarnings(\"serial\")\n    private final Position       nullCursor = new Position() {\n                                            };\n\n    public void start() {\n        super.start();\n        Assert.notNull(zooKeeperMetaManager);\n        if (!zooKeeperMetaManager.isStart()) {\n            zooKeeperMetaManager.start();\n        }\n\n        executor = Executors.newFixedThreadPool(1);\n        destinations = MigrateMap.makeComputingMap(destination -> zooKeeperMetaManager.listAllSubscribeInfo(destination));\n\n        cursors = MigrateMap.makeComputingMap(clientIdentity -> {\n            Position position = zooKeeperMetaManager.getCursor(clientIdentity);\n            if (position == null) {\n                return nullCursor; // 返回一个空对象标识，避免出现异常\n            } else {\n                return position;\n            }\n        });\n\n        batches = MigrateMap.makeComputingMap(clientIdentity -> {\n            // 读取一下zookeeper信息，初始化一次\n            MemoryClientIdentityBatch batches = MemoryClientIdentityBatch.create(clientIdentity);\n            Map<Long, PositionRange> positionRanges = zooKeeperMetaManager.listAllBatchs(clientIdentity);\n            for (Map.Entry<Long, PositionRange> entry : positionRanges.entrySet()) {\n                batches.addPositionRange(entry.getValue(), entry.getKey()); // 添加记录到指定batchId\n            }\n            return batches;\n        });\n    }\n\n    public void stop() {\n        super.stop();\n\n        if (zooKeeperMetaManager.isStart()) {\n            zooKeeperMetaManager.stop();\n        }\n\n        executor.shutdownNow();\n        destinations.clear();\n        batches.clear();\n    }\n\n    public void subscribe(final ClientIdentity clientIdentity) throws CanalMetaManagerException {\n        super.subscribe(clientIdentity);\n\n        executor.submit(() -> zooKeeperMetaManager.subscribe(clientIdentity));\n    }\n\n    public void unsubscribe(final ClientIdentity clientIdentity) throws CanalMetaManagerException {\n        super.unsubscribe(clientIdentity);\n\n        executor.submit(() -> zooKeeperMetaManager.unsubscribe(clientIdentity));\n    }\n\n    public void updateCursor(final ClientIdentity clientIdentity, final Position position)\n                                                                                          throws CanalMetaManagerException {\n        super.updateCursor(clientIdentity, position);\n\n        // 异步刷新\n        executor.submit(() -> zooKeeperMetaManager.updateCursor(clientIdentity, position));\n    }\n\n    @Override\n    public Position getCursor(ClientIdentity clientIdentity) throws CanalMetaManagerException {\n        Position position = super.getCursor(clientIdentity);\n        if (position == nullCursor) {\n            return null;\n        } else {\n            return position;\n        }\n    }\n\n    public Long addBatch(final ClientIdentity clientIdentity, final PositionRange positionRange)\n                                                                                                throws CanalMetaManagerException {\n        final Long batchId = super.addBatch(clientIdentity, positionRange);\n        // 异步刷新\n        executor.submit(() -> zooKeeperMetaManager.addBatch(clientIdentity, positionRange, batchId));\n        return batchId;\n    }\n\n    public void addBatch(final ClientIdentity clientIdentity, final PositionRange positionRange, final Long batchId)\n                                                                                                                    throws CanalMetaManagerException {\n        super.addBatch(clientIdentity, positionRange, batchId);\n        // 异步刷新\n        executor.submit(() -> zooKeeperMetaManager.addBatch(clientIdentity, positionRange, batchId));\n    }\n\n    public PositionRange removeBatch(final ClientIdentity clientIdentity, final Long batchId)\n                                                                                             throws CanalMetaManagerException {\n        PositionRange positionRange = super.removeBatch(clientIdentity, batchId);\n        // 异步刷新\n        executor.submit(() -> {\n            zooKeeperMetaManager.removeBatch(clientIdentity, batchId);\n        });\n\n        return positionRange;\n    }\n\n    public void clearAllBatchs(final ClientIdentity clientIdentity) throws CanalMetaManagerException {\n        super.clearAllBatchs(clientIdentity);\n\n        // 异步刷新\n        executor.submit(() -> zooKeeperMetaManager.clearAllBatchs(clientIdentity));\n    }\n\n    // =============== setter / getter ================\n    public void setZooKeeperMetaManager(ZooKeeperMetaManager zooKeeperMetaManager) {\n        this.zooKeeperMetaManager = zooKeeperMetaManager;\n    }\n}\n"
  },
  {
    "path": "meta/src/main/java/com/alibaba/otter/canal/meta/PeriodMixedMetaManager.java",
    "content": "package com.alibaba.otter.canal.meta;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.util.Assert;\n\nimport com.alibaba.otter.canal.meta.exception.CanalMetaManagerException;\nimport com.alibaba.otter.canal.protocol.ClientIdentity;\nimport com.alibaba.otter.canal.protocol.position.Position;\nimport com.alibaba.otter.canal.protocol.position.PositionRange;\nimport com.google.common.collect.MigrateMap;\n\n/**\n * 基于定时刷新的策略的mixed实现\n * \n * <pre>\n * 几个优化：\n * 1. 去除batch数据刷新到zk中，切换时batch数据可忽略，重新从头开始获取\n * 2. cursor的更新，启用定时刷新，合并多次请求。如果最近没有变化则不更新\n * </pre>\n * \n * @author jianghang 2012-9-11 下午02:41:15\n * @version 1.0.0\n */\npublic class PeriodMixedMetaManager extends MemoryMetaManager implements CanalMetaManager {\n\n    private static final Logger      logger     = LoggerFactory.getLogger(PeriodMixedMetaManager.class);\n    private ScheduledExecutorService executor;\n    private ZooKeeperMetaManager     zooKeeperMetaManager;\n    @SuppressWarnings(\"serial\")\n    private final Position           nullCursor = new Position() {\n                                                };\n    private long                     period     = 1000;                                                 // 单位ms\n    private Set<ClientIdentity>      updateCursorTasks;\n\n    public void start() {\n        super.start();\n        Assert.notNull(zooKeeperMetaManager);\n        if (!zooKeeperMetaManager.isStart()) {\n            zooKeeperMetaManager.start();\n        }\n\n        executor = Executors.newScheduledThreadPool(1);\n        destinations = MigrateMap.makeComputingMap(destination -> zooKeeperMetaManager.listAllSubscribeInfo(destination));\n\n        cursors = MigrateMap.makeComputingMap(clientIdentity -> {\n            Position position = zooKeeperMetaManager.getCursor(clientIdentity);\n            if (position == null) {\n                return nullCursor; // 返回一个空对象标识，避免出现异常\n            } else {\n                return position;\n            }\n        });\n\n        batches = MigrateMap.makeComputingMap(clientIdentity -> {\n            // 读取一下zookeeper信息，初始化一次\n            MemoryClientIdentityBatch batches = MemoryClientIdentityBatch.create(clientIdentity);\n            Map<Long, PositionRange> positionRanges = zooKeeperMetaManager.listAllBatchs(clientIdentity);\n            for (Map.Entry<Long, PositionRange> entry : positionRanges.entrySet()) {\n                batches.addPositionRange(entry.getValue(), entry.getKey()); // 添加记录到指定batchId\n            }\n            return batches;\n        });\n\n        updateCursorTasks = Collections.synchronizedSet(new HashSet<>());\n\n        // 启动定时工作任务\n        executor.scheduleAtFixedRate(() -> {\n            List<ClientIdentity> tasks = new ArrayList<>(updateCursorTasks);\n            for (ClientIdentity clientIdentity : tasks) {\n                try {\n                    updateCursorTasks.remove(clientIdentity);\n\n                    // 定时将内存中的最新值刷到zookeeper中，多次变更只刷一次\n                    zooKeeperMetaManager.updateCursor(clientIdentity, getCursor(clientIdentity));\n                } catch (Throwable e) {\n                    // ignore\n                    logger.error(\"period update\" + clientIdentity.toString() + \" curosr failed!\", e);\n                }\n            }\n        }, period, period, TimeUnit.MILLISECONDS);\n    }\n\n    public void stop() {\n        super.stop();\n\n        if (zooKeeperMetaManager.isStart()) {\n            zooKeeperMetaManager.stop();\n        }\n\n        executor.shutdownNow();\n        destinations.clear();\n        batches.clear();\n    }\n\n    public void subscribe(final ClientIdentity clientIdentity) throws CanalMetaManagerException {\n        super.subscribe(clientIdentity);\n\n        // 订阅信息频率发生比较低，不需要做定时merge处理\n        executor.submit(() -> zooKeeperMetaManager.subscribe(clientIdentity));\n    }\n\n    public void unsubscribe(final ClientIdentity clientIdentity) throws CanalMetaManagerException {\n        super.unsubscribe(clientIdentity);\n\n        // 订阅信息频率发生比较低，不需要做定时merge处理\n        executor.submit(() -> zooKeeperMetaManager.unsubscribe(clientIdentity));\n    }\n\n    public void updateCursor(ClientIdentity clientIdentity, Position position) throws CanalMetaManagerException {\n        super.updateCursor(clientIdentity, position);\n        updateCursorTasks.add(clientIdentity);// 添加到任务队列中进行触发\n    }\n\n    public Position getCursor(ClientIdentity clientIdentity) throws CanalMetaManagerException {\n        Position position = super.getCursor(clientIdentity);\n        if (position == nullCursor) {\n            return null;\n        } else {\n            return position;\n        }\n    }\n\n    // =============== setter / getter ================\n\n    public void setZooKeeperMetaManager(ZooKeeperMetaManager zooKeeperMetaManager) {\n        this.zooKeeperMetaManager = zooKeeperMetaManager;\n    }\n\n    public void setPeriod(long period) {\n        this.period = period;\n    }\n\n}\n"
  },
  {
    "path": "meta/src/main/java/com/alibaba/otter/canal/meta/ZooKeeperMetaManager.java",
    "content": "package com.alibaba.otter.canal.meta;\n\nimport java.io.UnsupportedEncodingException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.I0Itec.zkclient.exception.ZkNoNodeException;\nimport org.I0Itec.zkclient.exception.ZkNodeExistsException;\nimport org.apache.commons.lang.StringUtils;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\n\nimport com.alibaba.fastjson2.JSONWriter;\nimport com.alibaba.otter.canal.common.AbstractCanalLifeCycle;\nimport com.alibaba.otter.canal.common.utils.JsonUtils;\nimport com.alibaba.otter.canal.common.zookeeper.ZkClientx;\nimport com.alibaba.otter.canal.common.zookeeper.ZookeeperPathUtils;\nimport com.alibaba.otter.canal.meta.exception.CanalMetaManagerException;\nimport com.alibaba.otter.canal.protocol.ClientIdentity;\nimport com.alibaba.otter.canal.protocol.position.Position;\nimport com.alibaba.otter.canal.protocol.position.PositionRange;\nimport com.google.common.collect.Lists;\nimport com.google.common.collect.Maps;\n\n/**\n * zk 版本的 canal manager， 存储结构：\n *\n * <pre>\n * /otter\n *    canal\n *      destinations\n *        dest1\n *          client1\n *            filter\n *            batch_mark\n *              1\n *              2\n *              3\n * </pre>\n *\n * @author zebin.xuzb @ 2012-6-21\n * @author jianghang\n * @version 1.0.0\n */\npublic class ZooKeeperMetaManager extends AbstractCanalLifeCycle implements CanalMetaManager {\n\n    private static final String ENCODE = \"UTF-8\";\n    private ZkClientx           zkClientx;\n\n    public void start() {\n        super.start();\n\n        Assert.notNull(zkClientx);\n    }\n\n    public void stop() {\n        zkClientx = null; //关闭时置空\n        super.stop();\n    }\n\n    public void subscribe(ClientIdentity clientIdentity) throws CanalMetaManagerException {\n        String path = ZookeeperPathUtils.getClientIdNodePath(clientIdentity.getDestination(),\n            clientIdentity.getClientId());\n\n        try {\n            zkClientx.createPersistent(path, true);\n        } catch (ZkNodeExistsException e) {\n            // ignore\n        }\n        if (clientIdentity.hasFilter()) {\n            String filterPath = ZookeeperPathUtils.getFilterPath(clientIdentity.getDestination(),\n                clientIdentity.getClientId());\n\n            byte[] bytes = null;\n            try {\n                bytes = clientIdentity.getFilter().getBytes(ENCODE);\n            } catch (UnsupportedEncodingException e) {\n                throw new CanalMetaManagerException(e);\n            }\n\n            try {\n                zkClientx.createPersistent(filterPath, bytes);\n            } catch (ZkNodeExistsException e) {\n                // ignore\n                zkClientx.writeData(filterPath, bytes);\n            }\n        }\n    }\n\n    public boolean hasSubscribe(ClientIdentity clientIdentity) throws CanalMetaManagerException {\n        String path = ZookeeperPathUtils.getClientIdNodePath(clientIdentity.getDestination(),\n            clientIdentity.getClientId());\n        return zkClientx.exists(path);\n    }\n\n    public void unsubscribe(ClientIdentity clientIdentity) throws CanalMetaManagerException {\n        String path = ZookeeperPathUtils.getClientIdNodePath(clientIdentity.getDestination(),\n            clientIdentity.getClientId());\n        zkClientx.deleteRecursive(path); // 递归删除所有信息\n    }\n\n    public List<ClientIdentity> listAllSubscribeInfo(String destination) throws CanalMetaManagerException {\n        if (zkClientx == null) { //重新加载时可能为空\n            return new ArrayList<>();\n        }\n        String path = ZookeeperPathUtils.getDestinationPath(destination);\n        List<String> childs = null;\n        try {\n            childs = zkClientx.getChildren(path);\n        } catch (ZkNoNodeException e) {\n            // ignore\n        }\n\n        if (CollectionUtils.isEmpty(childs)) {\n            return new ArrayList<>();\n        }\n        List<Short> clientIds = new ArrayList<>();\n        for (String child : childs) {\n            if (StringUtils.isNumeric(child)) {\n                clientIds.add(ZookeeperPathUtils.getClientId(child));\n            }\n        }\n\n        Collections.sort(clientIds); // 进行一个排序\n        List<ClientIdentity> clientIdentities = Lists.newArrayList();\n        for (Short clientId : clientIds) {\n            path = ZookeeperPathUtils.getFilterPath(destination, clientId);\n            byte[] bytes = zkClientx.readData(path, true);\n            String filter = null;\n            if (bytes != null) {\n                try {\n                    filter = new String(bytes, ENCODE);\n                } catch (UnsupportedEncodingException e) {\n                    throw new CanalMetaManagerException(e);\n                }\n            }\n            clientIdentities.add(new ClientIdentity(destination, clientId, filter));\n        }\n\n        return clientIdentities;\n    }\n\n    public Position getCursor(ClientIdentity clientIdentity) throws CanalMetaManagerException {\n        String path = ZookeeperPathUtils.getCursorPath(clientIdentity.getDestination(), clientIdentity.getClientId());\n\n        byte[] data = zkClientx.readData(path, true);\n        if (data == null || data.length == 0) {\n            return null;\n        }\n\n        return JsonUtils.unmarshalFromByte(data, Position.class);\n    }\n\n    public void updateCursor(ClientIdentity clientIdentity, Position position) throws CanalMetaManagerException {\n        String path = ZookeeperPathUtils.getCursorPath(clientIdentity.getDestination(), clientIdentity.getClientId());\n        byte[] data = JsonUtils.marshalToByte(position, JSONWriter.Feature.WriteClassName);\n        try {\n            zkClientx.writeData(path, data);\n        } catch (ZkNoNodeException e) {\n            zkClientx.createPersistent(path, data, true);// 第一次节点不存在，则尝试重建\n        }\n    }\n\n    public Long addBatch(ClientIdentity clientIdentity, PositionRange positionRange) throws CanalMetaManagerException {\n        String path = ZookeeperPathUtils.getBatchMarkPath(clientIdentity.getDestination(),\n            clientIdentity.getClientId());\n        byte[] data = JsonUtils.marshalToByte(positionRange, JSONWriter.Feature.WriteClassName);\n        String batchPath = zkClientx\n            .createPersistentSequential(path + ZookeeperPathUtils.ZOOKEEPER_SEPARATOR, data, true);\n        String batchIdString = StringUtils.substringAfterLast(batchPath, ZookeeperPathUtils.ZOOKEEPER_SEPARATOR);\n        return ZookeeperPathUtils.getBatchMarkId(batchIdString);\n    }\n\n    public void addBatch(ClientIdentity clientIdentity, PositionRange positionRange,\n                         Long batchId) throws CanalMetaManagerException {\n        String path = ZookeeperPathUtils\n            .getBatchMarkWithIdPath(clientIdentity.getDestination(), clientIdentity.getClientId(), batchId);\n        byte[] data = JsonUtils.marshalToByte(positionRange, JSONWriter.Feature.WriteClassName);\n        zkClientx.createPersistent(path, data, true);\n    }\n\n    public PositionRange removeBatch(ClientIdentity clientIdentity, Long batchId) throws CanalMetaManagerException {\n        String batchsPath = ZookeeperPathUtils.getBatchMarkPath(clientIdentity.getDestination(),\n            clientIdentity.getClientId());\n        List<String> nodes = zkClientx.getChildren(batchsPath);\n        if (CollectionUtils.isEmpty(nodes)) {\n            // 没有batch记录\n            return null;\n        }\n\n        // 找到最小的Id\n        ArrayList<Long> batchIds = new ArrayList<>(nodes.size());\n        for (String batchIdString : nodes) {\n            batchIds.add(Long.valueOf(batchIdString));\n        }\n        Long minBatchId = Collections.min(batchIds);\n        if (!minBatchId.equals(batchId)) {\n            // 检查一下提交的ack/rollback，必须按batchId分出去的顺序提交，否则容易出现丢数据\n            throw new CanalMetaManagerException(String.format(\"batchId:%d is not the firstly:%d\", batchId, minBatchId));\n        }\n\n        if (!batchIds.contains(batchId)) {\n            // 不存在对应的batchId\n            return null;\n        }\n        PositionRange positionRange = getBatch(clientIdentity, batchId);\n        if (positionRange != null) {\n            String path = ZookeeperPathUtils\n                .getBatchMarkWithIdPath(clientIdentity.getDestination(), clientIdentity.getClientId(), batchId);\n            zkClientx.delete(path);\n        }\n\n        return positionRange;\n    }\n\n    public PositionRange getBatch(ClientIdentity clientIdentity, Long batchId) throws CanalMetaManagerException {\n        String path = ZookeeperPathUtils\n            .getBatchMarkWithIdPath(clientIdentity.getDestination(), clientIdentity.getClientId(), batchId);\n        byte[] data = zkClientx.readData(path, true);\n        if (data == null) {\n            return null;\n        }\n\n        PositionRange positionRange = JsonUtils.unmarshalFromByte(data, PositionRange.class);\n        return positionRange;\n    }\n\n    public void clearAllBatchs(ClientIdentity clientIdentity) throws CanalMetaManagerException {\n        String path = ZookeeperPathUtils.getBatchMarkPath(clientIdentity.getDestination(),\n            clientIdentity.getClientId());\n        List<String> batchChilds = zkClientx.getChildren(path);\n\n        for (String batchChild : batchChilds) {\n            String batchPath = path + ZookeeperPathUtils.ZOOKEEPER_SEPARATOR + batchChild;\n            zkClientx.delete(batchPath);\n        }\n    }\n\n    public PositionRange getLastestBatch(ClientIdentity clientIdentity) {\n        String path = ZookeeperPathUtils.getBatchMarkPath(clientIdentity.getDestination(),\n            clientIdentity.getClientId());\n        List<String> nodes = null;\n        try {\n            nodes = zkClientx.getChildren(path);\n        } catch (ZkNoNodeException e) {\n            // ignore\n        }\n\n        if (CollectionUtils.isEmpty(nodes)) {\n            return null;\n        }\n        // 找到最大的Id\n        ArrayList<Long> batchIds = new ArrayList<>(nodes.size());\n        for (String batchIdString : nodes) {\n            batchIds.add(Long.valueOf(batchIdString));\n        }\n        Long maxBatchId = Collections.max(batchIds);\n        PositionRange result = getBatch(clientIdentity, maxBatchId);\n        if (result == null) { // 出现为null，说明zk节点有变化，重新获取\n            return getLastestBatch(clientIdentity);\n        } else {\n            return result;\n        }\n    }\n\n    public PositionRange getFirstBatch(ClientIdentity clientIdentity) {\n        String path = ZookeeperPathUtils.getBatchMarkPath(clientIdentity.getDestination(),\n            clientIdentity.getClientId());\n        List<String> nodes = null;\n        try {\n            nodes = zkClientx.getChildren(path);\n        } catch (ZkNoNodeException e) {\n            // ignore\n        }\n\n        if (CollectionUtils.isEmpty(nodes)) {\n            return null;\n        }\n        // 找到最小的Id\n        ArrayList<Long> batchIds = new ArrayList<>(nodes.size());\n        for (String batchIdString : nodes) {\n            batchIds.add(Long.valueOf(batchIdString));\n        }\n        Long minBatchId = Collections.min(batchIds);\n        PositionRange result = getBatch(clientIdentity, minBatchId);\n        if (result == null) { // 出现为null，说明zk节点有变化，重新获取\n            return getFirstBatch(clientIdentity);\n        } else {\n            return result;\n        }\n    }\n\n    public Map<Long, PositionRange> listAllBatchs(ClientIdentity clientIdentity) {\n        String path = ZookeeperPathUtils.getBatchMarkPath(clientIdentity.getDestination(),\n            clientIdentity.getClientId());\n        List<String> nodes = null;\n        try {\n            nodes = zkClientx.getChildren(path);\n        } catch (ZkNoNodeException e) {\n            // ignore\n        }\n\n        if (CollectionUtils.isEmpty(nodes)) {\n            return Maps.newHashMap();\n        }\n        // 找到最大的Id\n        ArrayList<Long> batchIds = new ArrayList<>(nodes.size());\n        for (String batchIdString : nodes) {\n            batchIds.add(Long.valueOf(batchIdString));\n        }\n\n        Collections.sort(batchIds); // 从小到大排序\n        Map<Long, PositionRange> positionRanges = Maps.newLinkedHashMap();\n        for (Long batchId : batchIds) {\n            PositionRange result = getBatch(clientIdentity, batchId);\n            if (result == null) {// 出现为null，说明zk节点有变化，重新获取\n                return listAllBatchs(clientIdentity);\n            } else {\n                positionRanges.put(batchId, result);\n            }\n        }\n\n        return positionRanges;\n    }\n\n    // =========== setter ==========\n\n    public void setZkClientx(ZkClientx zkClientx) {\n        this.zkClientx = zkClientx;\n    }\n\n}\n"
  },
  {
    "path": "meta/src/main/java/com/alibaba/otter/canal/meta/exception/CanalMetaManagerException.java",
    "content": "package com.alibaba.otter.canal.meta.exception;\n\nimport com.alibaba.otter.canal.common.CanalException;\n\n/**\n * @author zebin.xuzb @ 2012-6-21\n * @version 1.0.0\n */\npublic class CanalMetaManagerException extends CanalException {\n\n    private static final long serialVersionUID = -654893533794556357L;\n\n    public CanalMetaManagerException(String errorCode){\n        super(errorCode);\n    }\n\n    public CanalMetaManagerException(String errorCode, Throwable cause){\n        super(errorCode, cause);\n    }\n\n    public CanalMetaManagerException(String errorCode, String errorDesc){\n        super(errorCode + \":\" + errorDesc);\n    }\n\n    public CanalMetaManagerException(String errorCode, String errorDesc, Throwable cause){\n        super(errorCode + \":\" + errorDesc, cause);\n    }\n\n    public CanalMetaManagerException(Throwable cause){\n        super(cause);\n    }\n\n}\n"
  },
  {
    "path": "meta/src/test/java/com/alibaba/otter/canal/meta/AbstractMetaManagerTest.java",
    "content": "package com.alibaba.otter.canal.meta;\n\nimport java.net.InetSocketAddress;\nimport java.util.Arrays;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.Assert;\n\nimport com.alibaba.otter.canal.protocol.ClientIdentity;\nimport com.alibaba.otter.canal.protocol.position.EntryPosition;\nimport com.alibaba.otter.canal.protocol.position.LogIdentity;\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\nimport com.alibaba.otter.canal.protocol.position.Position;\nimport com.alibaba.otter.canal.protocol.position.PositionRange;\nimport org.junit.Ignore;\nimport org.junit.Test;\n@Ignore\npublic class AbstractMetaManagerTest extends AbstractZkTest {\n\n    private static final String MYSQL_ADDRESS  = \"127.0.0.1\";\n    protected ClientIdentity    clientIdentity = new ClientIdentity(destination, (short) 1);\n\n    @Test\n    public void doSubscribeTest(CanalMetaManager metaManager) {\n        ClientIdentity client1 = new ClientIdentity(destination, (short) 1);\n        metaManager.subscribe(client1);\n        metaManager.subscribe(client1); // 重复调用\n        ClientIdentity client2 = new ClientIdentity(destination, (short) 2);\n        metaManager.subscribe(client2);\n\n        List<ClientIdentity> clients = metaManager.listAllSubscribeInfo(destination);\n        Assert.assertEquals(Arrays.asList(client1, client2), clients);\n\n        metaManager.unsubscribe(client2);\n        ClientIdentity client3 = new ClientIdentity(destination, (short) 3);\n        metaManager.subscribe(client3);\n\n        clients = metaManager.listAllSubscribeInfo(destination);\n        Assert.assertEquals(Arrays.asList(client1, client3), clients);\n\n    }\n\n    @Test\n    public void doBatchTest(CanalMetaManager metaManager) {\n        metaManager.subscribe(clientIdentity);\n\n        PositionRange first = metaManager.getFirstBatch(clientIdentity);\n        PositionRange lastest = metaManager.getLastestBatch(clientIdentity);\n\n        Assert.assertNull(first);\n        Assert.assertNull(lastest);\n\n        PositionRange range1 = buildRange(1);\n        Long batchId1 = metaManager.addBatch(clientIdentity, range1);\n\n        PositionRange range2 = buildRange(2);\n        Long batchId2 = metaManager.addBatch(clientIdentity, range2);\n        Assert.assertEquals((batchId1.longValue() + 1), batchId2.longValue());\n\n        // 验证get\n        PositionRange getRange1 = metaManager.getBatch(clientIdentity, batchId1);\n        Assert.assertEquals(range1, getRange1);\n        PositionRange getRange2 = metaManager.getBatch(clientIdentity, batchId2);\n        Assert.assertEquals(range2, getRange2);\n\n        PositionRange range3 = buildRange(3);\n        Long batchId3 = batchId2 + 1;\n        metaManager.addBatch(clientIdentity, range3, batchId3);\n\n        PositionRange range4 = buildRange(4);\n        Long batchId4 = metaManager.addBatch(clientIdentity, range4);\n        Assert.assertEquals((batchId3.longValue() + 1), batchId4.longValue());\n\n        // 验证remove\n        metaManager.removeBatch(clientIdentity, batchId1);\n        range1 = metaManager.getBatch(clientIdentity, batchId1);\n        Assert.assertNull(range1);\n\n        // 验证first / lastest\n        first = metaManager.getFirstBatch(clientIdentity);\n        lastest = metaManager.getLastestBatch(clientIdentity);\n\n        Assert.assertEquals(range2, first);\n        Assert.assertEquals(range4, lastest);\n\n        Map<Long, PositionRange> ranges = metaManager.listAllBatchs(clientIdentity);\n        Assert.assertEquals(3, ranges.size());\n    }\n\n    public Position doCursorTest(CanalMetaManager metaManager) {\n        metaManager.subscribe(clientIdentity);\n\n        Position position1 = metaManager.getCursor(clientIdentity);\n        Assert.assertNull(position1);\n\n        PositionRange range = buildRange(1);\n\n        metaManager.updateCursor(clientIdentity, range.getStart());\n        Position position2 = metaManager.getCursor(clientIdentity);\n        Assert.assertEquals(range.getStart(), position2);\n\n        metaManager.updateCursor(clientIdentity, range.getEnd());\n        Position position3 = metaManager.getCursor(clientIdentity);\n        Assert.assertEquals(range.getEnd(), position3);\n\n        return position3;\n    }\n\n    private PositionRange<LogPosition> buildRange(int number) {\n        LogPosition start = new LogPosition();\n        start.setIdentity(new LogIdentity(new InetSocketAddress(MYSQL_ADDRESS, 3306), 1234L));\n        start.setPostion(new EntryPosition(\"mysql-bin.000000\" + number, 106L, new Date().getTime()));\n\n        LogPosition end = new LogPosition();\n        end.setIdentity(new LogIdentity(new InetSocketAddress(MYSQL_ADDRESS, 3306), 1234L));\n        end.setPostion(new EntryPosition(\"mysql-bin.000000\" + (number + 1), 106L, (new Date().getTime()) + 1000 * 1000L));\n        return new PositionRange<>(start, end);\n    }\n}\n"
  },
  {
    "path": "meta/src/test/java/com/alibaba/otter/canal/meta/AbstractZkTest.java",
    "content": "package com.alibaba.otter.canal.meta;\n\nimport org.junit.Assert;\n\npublic class AbstractZkTest {\n\n    protected String destination = \"ljhtest1\";\n    protected String cluster1    = \"127.0.0.1:2188\";\n    protected String cluster2    = \"127.0.0.1:2188,127.0.0.1:2188\";\n\n    public void sleep(long time) {\n        try {\n            Thread.sleep(time);\n        } catch (InterruptedException e) {\n            Assert.fail(e.getMessage());\n        }\n    }\n}\n"
  },
  {
    "path": "meta/src/test/java/com/alibaba/otter/canal/meta/FileMixedMetaManagerTest.java",
    "content": "package com.alibaba.otter.canal.meta;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.io.FileUtils;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.protocol.ClientIdentity;\nimport com.alibaba.otter.canal.protocol.position.Position;\nimport com.alibaba.otter.canal.protocol.position.PositionRange;\n@Ignore\npublic class FileMixedMetaManagerTest extends AbstractMetaManagerTest {\n\n    private static final String tmp     = System.getProperty(\"java.io.tmpdir\", \"/tmp\");\n    private static final File   dataDir = new File(tmp, \"canal\");\n\n    @Before\n    public void setUp() {\n        try {\n            FileUtils.deleteDirectory(dataDir);\n        } catch (IOException e) {\n            Assert.fail(e.getMessage());\n        }\n    }\n\n    @Test\n    public void testSubscribeAll() {\n        FileMixedMetaManager metaManager = new FileMixedMetaManager();\n        metaManager.setDataDirByFile(dataDir);\n        metaManager.setPeriod(100);\n\n        metaManager.start();\n        doSubscribeTest(metaManager);\n\n        sleep(2000L);\n        // 重新构建一次，能获得上一次zk上的记录\n        FileMixedMetaManager metaManager2 = new FileMixedMetaManager();\n        metaManager2.setDataDirByFile(dataDir);\n        metaManager2.setPeriod(100);\n        metaManager2.start();\n\n        List<ClientIdentity> clients = metaManager2.listAllSubscribeInfo(destination);\n        Assert.assertEquals(2, clients.size());\n        metaManager.stop();\n    }\n\n    @Test\n    public void testBatchAll() {\n        FileMixedMetaManager metaManager = new FileMixedMetaManager();\n        metaManager.setDataDirByFile(dataDir);\n        metaManager.setPeriod(100);\n\n        metaManager.start();\n        doBatchTest(metaManager);\n\n        metaManager.clearAllBatchs(clientIdentity);\n        Map<Long, PositionRange> ranges = metaManager.listAllBatchs(clientIdentity);\n        Assert.assertEquals(0, ranges.size());\n        metaManager.stop();\n    }\n\n    @Test\n    public void testCursorAll() {\n        FileMixedMetaManager metaManager = new FileMixedMetaManager();\n        metaManager.setDataDirByFile(dataDir);\n        metaManager.setPeriod(100);\n        metaManager.start();\n\n        Position lastPosition = doCursorTest(metaManager);\n\n        sleep(1000L);\n        // 重新构建一次，能获得上一次zk上的记录\n        FileMixedMetaManager metaManager2 = new FileMixedMetaManager();\n        metaManager2.setDataDirByFile(dataDir);\n        metaManager2.setPeriod(100);\n        metaManager2.start();\n\n        Position position = metaManager2.getCursor(clientIdentity);\n        Assert.assertEquals(position, lastPosition);\n        metaManager.stop();\n    }\n}\n"
  },
  {
    "path": "meta/src/test/java/com/alibaba/otter/canal/meta/MemoryMetaManagerTest.java",
    "content": "package com.alibaba.otter.canal.meta;\n\nimport java.util.Map;\n\nimport org.junit.Assert;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.protocol.position.PositionRange;\n@Ignore\npublic class MemoryMetaManagerTest extends AbstractMetaManagerTest {\n\n    @Test\n    public void testSubscribeAll() {\n        MemoryMetaManager metaManager = new MemoryMetaManager();\n        metaManager.start();\n        doSubscribeTest(metaManager);\n        metaManager.stop();\n    }\n\n    @Test\n    public void testBatchAll() {\n        MemoryMetaManager metaManager = new MemoryMetaManager();\n        metaManager.start();\n        doBatchTest(metaManager);\n\n        metaManager.clearAllBatchs(clientIdentity);\n        Map<Long, PositionRange> ranges = metaManager.listAllBatchs(clientIdentity);\n        Assert.assertEquals(0, ranges.size());\n        metaManager.stop();\n    }\n\n    @Test\n    public void testCursorAll() {\n        MemoryMetaManager metaManager = new MemoryMetaManager();\n        metaManager.start();\n        doCursorTest(metaManager);\n        metaManager.stop();\n    }\n}\n"
  },
  {
    "path": "meta/src/test/java/com/alibaba/otter/canal/meta/MixedMetaManagerTest.java",
    "content": "package com.alibaba.otter.canal.meta;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.common.zookeeper.ZkClientx;\nimport com.alibaba.otter.canal.common.zookeeper.ZookeeperPathUtils;\nimport com.alibaba.otter.canal.protocol.ClientIdentity;\nimport com.alibaba.otter.canal.protocol.position.Position;\nimport com.alibaba.otter.canal.protocol.position.PositionRange;\n@Ignore\npublic class MixedMetaManagerTest extends AbstractMetaManagerTest {\n\n    private ZkClientx zkclientx = new ZkClientx(cluster1 + \";\" + cluster2);\n\n    @Before\n    public void setUp() {\n        String path = ZookeeperPathUtils.getDestinationPath(destination);\n        zkclientx.deleteRecursive(path);\n    }\n\n    @After\n    public void tearDown() {\n        String path = ZookeeperPathUtils.getDestinationPath(destination);\n        zkclientx.deleteRecursive(path);\n    }\n\n    @Test\n    public void testSubscribeAll() {\n        MixedMetaManager metaManager = new MixedMetaManager();\n\n        ZooKeeperMetaManager zooKeeperMetaManager = new ZooKeeperMetaManager();\n        zooKeeperMetaManager.setZkClientx(zkclientx);\n\n        metaManager.setZooKeeperMetaManager(zooKeeperMetaManager);\n        metaManager.start();\n        doSubscribeTest(metaManager);\n\n        sleep(1000L);\n        // 重新构建一次，能获得上一次zk上的记录\n        MixedMetaManager metaManager2 = new MixedMetaManager();\n        metaManager2.setZooKeeperMetaManager(zooKeeperMetaManager);\n        metaManager2.start();\n\n        List<ClientIdentity> clients = metaManager2.listAllSubscribeInfo(destination);\n        Assert.assertEquals(2, clients.size());\n        metaManager.stop();\n    }\n\n    @Test\n    public void testBatchAll() {\n        MixedMetaManager metaManager = new MixedMetaManager();\n\n        ZooKeeperMetaManager zooKeeperMetaManager = new ZooKeeperMetaManager();\n        zooKeeperMetaManager.setZkClientx(zkclientx);\n\n        metaManager.setZooKeeperMetaManager(zooKeeperMetaManager);\n        metaManager.start();\n        doBatchTest(metaManager);\n\n        sleep(1000L);\n        // 重新构建一次，能获得上一次zk上的记录\n        MixedMetaManager metaManager2 = new MixedMetaManager();\n        metaManager2.setZooKeeperMetaManager(zooKeeperMetaManager);\n        metaManager2.start();\n\n        Map<Long, PositionRange> ranges = metaManager2.listAllBatchs(clientIdentity);\n        Assert.assertEquals(3, ranges.size());\n\n        metaManager.clearAllBatchs(clientIdentity);\n        ranges = metaManager.listAllBatchs(clientIdentity);\n        Assert.assertEquals(0, ranges.size());\n        metaManager.stop();\n        metaManager2.stop();\n    }\n\n    @Test\n    public void testCursorAll() {\n        MixedMetaManager metaManager = new MixedMetaManager();\n\n        ZooKeeperMetaManager zooKeeperMetaManager = new ZooKeeperMetaManager();\n        zooKeeperMetaManager.setZkClientx(zkclientx);\n\n        metaManager.setZooKeeperMetaManager(zooKeeperMetaManager);\n        metaManager.start();\n        Position lastPosition = doCursorTest(metaManager);\n\n        sleep(1000L);\n        // 重新构建一次，能获得上一次zk上的记录\n        MixedMetaManager metaManager2 = new MixedMetaManager();\n        metaManager2.setZooKeeperMetaManager(zooKeeperMetaManager);\n        metaManager2.start();\n\n        Position position = metaManager2.getCursor(clientIdentity);\n        Assert.assertEquals(position, lastPosition);\n        metaManager.stop();\n    }\n}\n"
  },
  {
    "path": "meta/src/test/java/com/alibaba/otter/canal/meta/PeriodMixedMetaManagerTest.java",
    "content": "package com.alibaba.otter.canal.meta;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.common.zookeeper.ZkClientx;\nimport com.alibaba.otter.canal.common.zookeeper.ZookeeperPathUtils;\nimport com.alibaba.otter.canal.protocol.ClientIdentity;\nimport com.alibaba.otter.canal.protocol.position.Position;\nimport com.alibaba.otter.canal.protocol.position.PositionRange;\n@Ignore\npublic class PeriodMixedMetaManagerTest extends AbstractMetaManagerTest {\n\n    private ZkClientx zkclientx = new ZkClientx(cluster1 + \";\" + cluster2);\n\n    @Before\n    public void setUp() {\n        String path = ZookeeperPathUtils.getDestinationPath(destination);\n        zkclientx.deleteRecursive(path);\n    }\n\n    @After\n    public void tearDown() {\n        String path = ZookeeperPathUtils.getDestinationPath(destination);\n        zkclientx.deleteRecursive(path);\n    }\n\n    @Test\n    public void testSubscribeAll() {\n        PeriodMixedMetaManager metaManager = new PeriodMixedMetaManager();\n\n        ZooKeeperMetaManager zooKeeperMetaManager = new ZooKeeperMetaManager();\n        zooKeeperMetaManager.setZkClientx(zkclientx);\n\n        metaManager.setZooKeeperMetaManager(zooKeeperMetaManager);\n        metaManager.start();\n        doSubscribeTest(metaManager);\n\n        sleep(1000L);\n        // 重新构建一次，能获得上一次zk上的记录\n        PeriodMixedMetaManager metaManager2 = new PeriodMixedMetaManager();\n        metaManager2.setZooKeeperMetaManager(zooKeeperMetaManager);\n        metaManager2.start();\n\n        List<ClientIdentity> clients = metaManager2.listAllSubscribeInfo(destination);\n        Assert.assertEquals(2, clients.size());\n        metaManager.stop();\n    }\n\n    @Test\n    public void testBatchAll() {\n        PeriodMixedMetaManager metaManager = new PeriodMixedMetaManager();\n\n        ZooKeeperMetaManager zooKeeperMetaManager = new ZooKeeperMetaManager();\n        zooKeeperMetaManager.setZkClientx(zkclientx);\n\n        metaManager.setZooKeeperMetaManager(zooKeeperMetaManager);\n        metaManager.start();\n        doBatchTest(metaManager);\n\n        metaManager.clearAllBatchs(clientIdentity);\n        Map<Long, PositionRange> ranges = metaManager.listAllBatchs(clientIdentity);\n        Assert.assertEquals(0, ranges.size());\n        metaManager.stop();\n    }\n\n    @Test\n    public void testCursorAll() {\n        PeriodMixedMetaManager metaManager = new PeriodMixedMetaManager();\n\n        ZooKeeperMetaManager zooKeeperMetaManager = new ZooKeeperMetaManager();\n        zooKeeperMetaManager.setZkClientx(zkclientx);\n\n        metaManager.setZooKeeperMetaManager(zooKeeperMetaManager);\n        metaManager.start();\n        Position lastPosition = doCursorTest(metaManager);\n\n        sleep(1000L);\n        // 重新构建一次，能获得上一次zk上的记录\n        PeriodMixedMetaManager metaManager2 = new PeriodMixedMetaManager();\n        metaManager2.setZooKeeperMetaManager(zooKeeperMetaManager);\n        metaManager2.start();\n\n        Position position = metaManager2.getCursor(clientIdentity);\n        Assert.assertEquals(position, lastPosition);\n        metaManager.stop();\n    }\n}\n"
  },
  {
    "path": "meta/src/test/java/com/alibaba/otter/canal/meta/ZooKeeperMetaManagerTest.java",
    "content": "package com.alibaba.otter.canal.meta;\n\nimport java.util.Map;\n\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.common.zookeeper.ZkClientx;\nimport com.alibaba.otter.canal.common.zookeeper.ZookeeperPathUtils;\nimport com.alibaba.otter.canal.protocol.position.PositionRange;\n@Ignore\npublic class ZooKeeperMetaManagerTest extends AbstractMetaManagerTest {\n\n    private ZkClientx zkclientx = new ZkClientx(cluster1 + \";\" + cluster2);\n\n    @Before\n    public void setUp() {\n        String path = ZookeeperPathUtils.getDestinationPath(destination);\n        zkclientx.deleteRecursive(path);\n    }\n\n    @After\n    public void tearDown() {\n        String path = ZookeeperPathUtils.getDestinationPath(destination);\n        zkclientx.deleteRecursive(path);\n    }\n\n    @Test\n    public void testSubscribeAll() {\n        ZooKeeperMetaManager metaManager = new ZooKeeperMetaManager();\n        metaManager.setZkClientx(zkclientx);\n        metaManager.start();\n\n        doSubscribeTest(metaManager);\n        metaManager.stop();\n    }\n\n    @Test\n    public void testBatchAll() {\n        ZooKeeperMetaManager metaManager = new ZooKeeperMetaManager();\n        metaManager.setZkClientx(zkclientx);\n        metaManager.start();\n        doBatchTest(metaManager);\n\n        metaManager.clearAllBatchs(clientIdentity);\n        Map<Long, PositionRange> ranges = metaManager.listAllBatchs(clientIdentity);\n        Assert.assertEquals(0, ranges.size());\n        metaManager.stop();\n    }\n\n    @Test\n    public void testCursorhAll() {\n        ZooKeeperMetaManager metaManager = new ZooKeeperMetaManager();\n        metaManager.setZkClientx(zkclientx);\n        metaManager.start();\n        doCursorTest(metaManager);\n        metaManager.stop();\n    }\n}\n"
  },
  {
    "path": "mvnw",
    "content": "#!/bin/sh\n# ----------------------------------------------------------------------------\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#    http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n# ----------------------------------------------------------------------------\n\n# ----------------------------------------------------------------------------\n# Maven2 Start Up Batch script\n#\n# Required ENV vars:\n# ------------------\n#   JAVA_HOME - location of a JDK home dir\n#\n# Optional ENV vars\n# -----------------\n#   M2_HOME - location of maven2's installed home dir\n#   MAVEN_OPTS - parameters passed to the Java VM when running Maven\n#     e.g. to debug Maven itself, use\n#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n# ----------------------------------------------------------------------------\n\nif [ -z \"$MAVEN_SKIP_RC\" ] ; then\n\n  if [ -f /etc/mavenrc ] ; then\n    . /etc/mavenrc\n  fi\n\n  if [ -f \"$HOME/.mavenrc\" ] ; then\n    . \"$HOME/.mavenrc\"\n  fi\n\nfi\n\n# OS specific support.  $var _must_ be set to either true or false.\ncygwin=false;\ndarwin=false;\nmingw=false\ncase \"`uname`\" in\n  CYGWIN*) cygwin=true ;;\n  MINGW*) mingw=true;;\n  Darwin*) darwin=true\n    # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home\n    # See https://developer.apple.com/library/mac/qa/qa1170/_index.html\n    if [ -z \"$JAVA_HOME\" ]; then\n      if [ -x \"/usr/libexec/java_home\" ]; then\n        export JAVA_HOME=\"`/usr/libexec/java_home`\"\n      else\n        export JAVA_HOME=\"/Library/Java/Home\"\n      fi\n    fi\n    ;;\nesac\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  if [ -r /etc/gentoo-release ] ; then\n    JAVA_HOME=`java-config --jre-home`\n  fi\nfi\n\nif [ -z \"$M2_HOME\" ] ; then\n  ## resolve links - $0 may be a link to maven's home\n  PRG=\"$0\"\n\n  # need this for relative symlinks\n  while [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n      PRG=\"$link\"\n    else\n      PRG=\"`dirname \"$PRG\"`/$link\"\n    fi\n  done\n\n  saveddir=`pwd`\n\n  M2_HOME=`dirname \"$PRG\"`/..\n\n  # make it fully qualified\n  M2_HOME=`cd \"$M2_HOME\" && pwd`\n\n  cd \"$saveddir\"\n  # echo Using m2 at $M2_HOME\nfi\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched\nif $cygwin ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --unix \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --unix \"$CLASSPATH\"`\nfi\n\n# For Mingw, ensure paths are in UNIX format before anything is touched\nif $mingw ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=\"`(cd \"$M2_HOME\"; pwd)`\"\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=\"`(cd \"$JAVA_HOME\"; pwd)`\"\n  # TODO classpath?\nfi\n\nif [ -z \"$JAVA_HOME\" ]; then\n  javaExecutable=\"`which javac`\"\n  if [ -n \"$javaExecutable\" ] && ! [ \"`expr \\\"$javaExecutable\\\" : '\\([^ ]*\\)'`\" = \"no\" ]; then\n    # readlink(1) is not available as standard on Solaris 10.\n    readLink=`which readlink`\n    if [ ! `expr \"$readLink\" : '\\([^ ]*\\)'` = \"no\" ]; then\n      if $darwin ; then\n        javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n        javaExecutable=\"`cd \\\"$javaHome\\\" && pwd -P`/javac\"\n      else\n        javaExecutable=\"`readlink -f \\\"$javaExecutable\\\"`\"\n      fi\n      javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n      javaHome=`expr \"$javaHome\" : '\\(.*\\)/bin'`\n      JAVA_HOME=\"$javaHome\"\n      export JAVA_HOME\n    fi\n  fi\nfi\n\nif [ -z \"$JAVACMD\" ] ; then\n  if [ -n \"$JAVA_HOME\"  ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n      # IBM's JDK on AIX uses strange locations for the executables\n      JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n      JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n  else\n    JAVACMD=\"`which java`\"\n  fi\nfi\n\nif [ ! -x \"$JAVACMD\" ] ; then\n  echo \"Error: JAVA_HOME is not defined correctly.\" >&2\n  echo \"  We cannot execute $JAVACMD\" >&2\n  exit 1\nfi\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  echo \"Warning: JAVA_HOME environment variable is not set.\"\nfi\n\nCLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher\n\n# traverses directory structure from process work directory to filesystem root\n# first directory with .mvn subdirectory is considered project base directory\nfind_maven_basedir() {\n\n  if [ -z \"$1\" ]\n  then\n    echo \"Path not specified to find_maven_basedir\"\n    return 1\n  fi\n\n  basedir=\"$1\"\n  wdir=\"$1\"\n  while [ \"$wdir\" != '/' ] ; do\n    if [ -d \"$wdir\"/.mvn ] ; then\n      basedir=$wdir\n      break\n    fi\n    # workaround for JBEAP-8937 (on Solaris 10/Sparc)\n    if [ -d \"${wdir}\" ]; then\n      wdir=`cd \"$wdir/..\"; pwd`\n    fi\n    # end of workaround\n  done\n  echo \"${basedir}\"\n}\n\n# concatenates all lines of a file\nconcat_lines() {\n  if [ -f \"$1\" ]; then\n    echo \"$(tr -s '\\n' ' ' < \"$1\")\"\n  fi\n}\n\nBASE_DIR=`find_maven_basedir \"$(pwd)\"`\nif [ -z \"$BASE_DIR\" ]; then\n  exit 1;\nfi\n\nexport MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-\"$BASE_DIR\"}\nif [ \"$MVNW_VERBOSE\" = true ]; then\n  echo $MAVEN_PROJECTBASEDIR\nfi\nMAVEN_OPTS=\"$(concat_lines \"$MAVEN_PROJECTBASEDIR/.mvn/jvm.config\") $MAVEN_OPTS\"\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --path --windows \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --path --windows \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --windows \"$CLASSPATH\"`\n  [ -n \"$MAVEN_PROJECTBASEDIR\" ] &&\n    MAVEN_PROJECTBASEDIR=`cygpath --path --windows \"$MAVEN_PROJECTBASEDIR\"`\nfi\n\nWRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\nexec \"$JAVACMD\" \\\n  $MAVEN_OPTS \\\n  -classpath \"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar\" \\\n  \"-Dmaven.home=${M2_HOME}\" \"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}\" \\\n  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG \"$@\"\n\n"
  },
  {
    "path": "parse/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>com.alibaba.otter</groupId>\n\t\t<artifactId>canal</artifactId>\n\t\t<version>1.1.9-SNAPSHOT</version>\n\t\t<relativePath>../pom.xml</relativePath>\n\t</parent>\n\t<artifactId>canal.parse</artifactId>\n\t<packaging>jar</packaging>\n\t<name>canal parse module for otter ${project.version}</name>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.common</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.protocol</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.meta</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.sink</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.parse.dbsync</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.filter</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.parse.driver</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.polardbx</groupId>\n\t\t\t<artifactId>polardbx-parser</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.mybatis</groupId>\n\t\t\t<artifactId>mybatis-spring</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.mybatis</groupId>\n\t\t\t<artifactId>mybatis</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.h2database</groupId>\n\t\t\t<artifactId>h2</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.httpcomponents</groupId>\n\t\t\t<artifactId>httpclient</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.commons</groupId>\n\t\t\t<artifactId>commons-compress</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t    <groupId>com.lmax</groupId>\n\t\t    <artifactId>disruptor</artifactId>\n\t\t</dependency>\n\t\t<!-- test dependency -->\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>javax.annotation</groupId>\n\t\t\t<artifactId>javax.annotation-api</artifactId>\n\t\t</dependency>\n        <dependency>\n            <groupId>org.powermock</groupId>\n            <artifactId>powermock-api-mockito</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.powermock</groupId>\n            <artifactId>powermock-module-junit4</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.mockito</groupId>\n            <artifactId>mockito-all</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.diffblue</groupId>\n            <artifactId>deeptestutils</artifactId>\n            <scope>test</scope>\n        </dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/CanalEventParser.java",
    "content": "package com.alibaba.otter.canal.parse;\n\nimport com.alibaba.otter.canal.common.CanalLifeCycle;\n\n/**\n * 数据复制控制器\n * \n * @author jianghang 2012-6-21 下午04:03:25\n * @version 1.0.0\n */\npublic interface CanalEventParser<EVENT> extends CanalLifeCycle {\n\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/CanalHASwitchable.java",
    "content": "package com.alibaba.otter.canal.parse;\n\nimport com.alibaba.otter.canal.parse.support.AuthenticationInfo;\n\n/**\n * 支持可切换的数据复制控制器\n * \n * @author jianghang 2012-6-26 下午05:41:43\n * @version 1.0.0\n */\npublic interface CanalHASwitchable {\n\n    public void doSwitch();\n\n    public void doSwitch(AuthenticationInfo newAuthenticationInfo);\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/exception/CanalHAException.java",
    "content": "package com.alibaba.otter.canal.parse.exception;\r\n\r\nimport com.alibaba.otter.canal.common.CanalException;\r\n\r\n/**\r\n * canal 异常定义\r\n * \r\n * @author jianghang 2012-6-15 下午04:57:35\r\n * @version 1.0.0\r\n */\r\npublic class CanalHAException extends CanalException {\r\n\r\n    private static final long serialVersionUID = -7288830284122672209L;\r\n\r\n    public CanalHAException(String errorCode){\r\n        super(errorCode);\r\n    }\r\n\r\n    public CanalHAException(String errorCode, Throwable cause){\r\n        super(errorCode, cause);\r\n    }\r\n\r\n    public CanalHAException(String errorCode, String errorDesc){\r\n        super(errorCode + \":\" + errorDesc);\r\n    }\r\n\r\n    public CanalHAException(String errorCode, String errorDesc, Throwable cause){\r\n        super(errorCode + \":\" + errorDesc, cause);\r\n    }\r\n\r\n    public CanalHAException(Throwable cause){\r\n        super(cause);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/exception/CanalParseException.java",
    "content": "package com.alibaba.otter.canal.parse.exception;\r\n\r\nimport com.alibaba.otter.canal.common.CanalException;\r\n\r\n/**\r\n * canal 异常定义\r\n * \r\n * @author jianghang 2012-6-15 下午04:57:35\r\n * @version 1.0.0\r\n */\r\npublic class CanalParseException extends CanalException {\r\n\r\n    private static final long serialVersionUID = -7288830284122672209L;\r\n\r\n    public CanalParseException(String errorCode){\r\n        super(errorCode);\r\n    }\r\n\r\n    public CanalParseException(String errorCode, Throwable cause){\r\n        super(errorCode, cause);\r\n    }\r\n\r\n    public CanalParseException(String errorCode, String errorDesc){\r\n        super(errorCode + \":\" + errorDesc);\r\n    }\r\n\r\n    public CanalParseException(String errorCode, String errorDesc, Throwable cause){\r\n        super(errorCode + \":\" + errorDesc, cause);\r\n    }\r\n\r\n    public CanalParseException(Throwable cause){\r\n        super(cause);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/exception/PositionNotFoundException.java",
    "content": "package com.alibaba.otter.canal.parse.exception;\n\n/**\n * @author chengjin.lyf on 2018/7/20 下午2:54\n * @since 1.0.25\n */\npublic class PositionNotFoundException extends CanalParseException {\n\n    private static final long serialVersionUID = -7382448928116244017L;\n\n    public PositionNotFoundException(String errorCode){\n        super(errorCode);\n    }\n\n    public PositionNotFoundException(String errorCode, Throwable cause){\n        super(errorCode, cause);\n    }\n\n    public PositionNotFoundException(String errorCode, String errorDesc){\n        super(errorCode, errorDesc);\n    }\n\n    public PositionNotFoundException(String errorCode, String errorDesc, Throwable cause){\n        super(errorCode, errorDesc, cause);\n    }\n\n    public PositionNotFoundException(Throwable cause){\n        super(cause);\n    }\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/exception/ServerIdNotMatchException.java",
    "content": "package com.alibaba.otter.canal.parse.exception;\n\nimport com.alibaba.otter.canal.common.CanalException;\n\n/**\n * @author chengjin.lyf on 2018/8/8 下午1:07\n * @since 1.0.25\n */\npublic class ServerIdNotMatchException extends CanalException {\n\n    private static final long serialVersionUID = -6124989280379293953L;\n\n    public ServerIdNotMatchException(String errorCode){\n        super(errorCode);\n    }\n\n    public ServerIdNotMatchException(String errorCode, Throwable cause){\n        super(errorCode, cause);\n    }\n\n    public ServerIdNotMatchException(String errorCode, String errorDesc){\n        super(errorCode, errorDesc);\n    }\n\n    public ServerIdNotMatchException(String errorCode, String errorDesc, Throwable cause){\n        super(errorCode, errorDesc, cause);\n    }\n\n    public ServerIdNotMatchException(Throwable cause){\n        super(cause);\n    }\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/exception/ServerLogPurgedException.java",
    "content": "package com.alibaba.otter.canal.parse.exception;\r\rimport com.alibaba.otter.canal.common.CanalException;\r\rpublic class ServerLogPurgedException extends CanalException {\r\r    public ServerLogPurgedException(String errorCode){\r        super(\"ServerLogPurged by \" + errorCode);\r    }\r}\r"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/ha/CanalHAController.java",
    "content": "package com.alibaba.otter.canal.parse.ha;\n\nimport com.alibaba.otter.canal.common.CanalLifeCycle;\nimport com.alibaba.otter.canal.parse.exception.CanalHAException;\n\n/**\n * HA 控制器实现\n * \n * @author jianghang 2012-6-26 下午05:21:07\n * @version 1.0.0\n */\npublic interface CanalHAController extends CanalLifeCycle {\n\n    public void start() throws CanalHAException;\n\n    public void stop() throws CanalHAException;\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/ha/HeartBeatHAController.java",
    "content": "package com.alibaba.otter.canal.parse.ha;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.common.AbstractCanalLifeCycle;\nimport com.alibaba.otter.canal.parse.CanalHASwitchable;\nimport com.alibaba.otter.canal.parse.inbound.HeartBeatCallback;\n\n/**\n * 基于HeartBeat信息的HA控制 , 注意：非线程安全，需要做做多例化\n * \n * @author jianghang 2012-7-6 下午02:33:30\n * @version 1.0.0\n */\npublic class HeartBeatHAController extends AbstractCanalLifeCycle implements CanalHAController, HeartBeatCallback {\n\n    private static final Logger logger              = LoggerFactory.getLogger(HeartBeatHAController.class);\n    // default 3 times\n    private int                 detectingRetryTimes = 3;\n    private int                 failedTimes         = 0;\n    private boolean             switchEnable        = false;\n    private CanalHASwitchable   eventParser;\n\n    public HeartBeatHAController(){\n\n    }\n\n    public void onSuccess(long costTime) {\n        failedTimes = 0;\n    }\n\n    public void onFailed(Throwable e) {\n        failedTimes++;\n        // 检查一下是否超过失败次数\n        synchronized (this) {\n            if (failedTimes > detectingRetryTimes) {\n                if (switchEnable) {\n                    eventParser.doSwitch();// 通知执行一次切换\n                    failedTimes = 0;\n                } else {\n                    logger.warn(\"HeartBeat failed Times:{} , should auto switch ?\", failedTimes);\n                }\n            }\n        }\n    }\n\n    // ============================= setter / getter\n    // ============================\n\n    public void setCanalHASwitchable(CanalHASwitchable canalHASwitchable) {\n        this.eventParser = canalHASwitchable;\n    }\n\n    public void setDetectingRetryTimes(int detectingRetryTimes) {\n        this.detectingRetryTimes = detectingRetryTimes;\n    }\n\n    public void setSwitchEnable(boolean switchEnable) {\n        this.switchEnable = switchEnable;\n    }\n\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/AbstractBinlogParser.java",
    "content": "package com.alibaba.otter.canal.parse.inbound;\n\nimport com.alibaba.otter.canal.common.AbstractCanalLifeCycle;\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\nimport com.alibaba.otter.canal.protocol.CanalEntry.Entry;\n\npublic abstract class AbstractBinlogParser<T> extends AbstractCanalLifeCycle implements BinlogParser<T> {\n\n    public void reset() {\n    }\n\n    public Entry parse(T event, TableMeta tableMeta) throws CanalParseException {\n        return null;\n    }\n\n    public Entry parse(T event) throws CanalParseException {\n        return null;\n    }\n\n    public void stop() {\n        reset();\n        super.stop();\n    }\n\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/AbstractEventParser.java",
    "content": "package com.alibaba.otter.canal.parse.inbound;\r\n\r\nimport static com.alibaba.otter.canal.parse.driver.mysql.utils.GtidUtil.parseGtidSet;\r\n\r\nimport java.io.IOException;\r\nimport java.util.*;\r\nimport java.util.concurrent.atomic.AtomicBoolean;\r\nimport java.util.concurrent.atomic.AtomicLong;\r\n\r\nimport org.apache.commons.lang.StringUtils;\r\nimport org.apache.commons.lang.exception.ExceptionUtils;\r\nimport org.apache.commons.lang.math.RandomUtils;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\nimport org.slf4j.MDC;\r\n\r\nimport com.alibaba.otter.canal.common.AbstractCanalLifeCycle;\r\nimport com.alibaba.otter.canal.common.alarm.CanalAlarmHandler;\r\nimport com.alibaba.otter.canal.filter.CanalEventFilter;\r\nimport com.alibaba.otter.canal.parse.CanalEventParser;\r\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.GTIDSet;\r\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\r\nimport com.alibaba.otter.canal.parse.exception.PositionNotFoundException;\r\nimport com.alibaba.otter.canal.parse.inbound.mysql.MysqlConnection;\r\nimport com.alibaba.otter.canal.parse.inbound.mysql.MysqlMultiStageCoprocessor;\r\nimport com.alibaba.otter.canal.parse.index.CanalLogPositionManager;\r\nimport com.alibaba.otter.canal.parse.support.AuthenticationInfo;\r\nimport com.alibaba.otter.canal.protocol.CanalEntry;\r\nimport com.alibaba.otter.canal.protocol.CanalEntry.Entry;\r\nimport com.alibaba.otter.canal.protocol.CanalEntry.EntryType;\r\nimport com.alibaba.otter.canal.protocol.CanalEntry.Header;\r\nimport com.alibaba.otter.canal.protocol.position.EntryPosition;\r\nimport com.alibaba.otter.canal.protocol.position.LogIdentity;\r\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\r\nimport com.alibaba.otter.canal.sink.CanalEventSink;\r\nimport com.alibaba.otter.canal.sink.exception.CanalSinkException;\r\nimport com.taobao.tddl.dbsync.binlog.exception.TableIdNotFoundException;\r\n\r\n/**\r\n * 抽象的EventParser, 最大化共用mysql/oracle版本的实现\r\n * \r\n * @author jianghang 2013-1-20 下午08:10:25\r\n * @version 1.0.0\r\n */\r\npublic abstract class AbstractEventParser<EVENT> extends AbstractCanalLifeCycle implements CanalEventParser<EVENT> {\r\n\r\n    protected final Logger                           logger                     = LoggerFactory.getLogger(this.getClass());\r\n\r\n    protected CanalLogPositionManager                logPositionManager         = null;\r\n    protected CanalEventSink<List<CanalEntry.Entry>> eventSink                  = null;\r\n    protected CanalEventFilter                       eventFilter                = null;\r\n    protected CanalEventFilter                       eventBlackFilter           = null;\r\n\r\n    // 字段过滤\r\n    protected String\t\t  \t\t\t  \t\t\tfieldFilter;\r\n    protected Map<String, List<String>> \t\t\tfieldFilterMap;\r\n    protected String\t\t  \t\t\t  \t\t\tfieldBlackFilter;\r\n    protected Map<String, List<String>> \t\t\tfieldBlackFilterMap;\r\n    \r\n    private CanalAlarmHandler                        alarmHandler               = null;\r\n\r\n    // 统计参数\r\n    protected AtomicBoolean                          profilingEnabled           = new AtomicBoolean(false);                // profile开关参数\r\n    protected AtomicLong                             receivedEventCount         = new AtomicLong();\r\n    protected AtomicLong                             parsedEventCount           = new AtomicLong();\r\n    protected AtomicLong                             consumedEventCount         = new AtomicLong();\r\n    protected long                                   parsingInterval            = -1;\r\n    protected long                                   processingInterval         = -1;\r\n\r\n    // 认证信息\r\n    protected volatile AuthenticationInfo            runningInfo;\r\n    protected String                                 destination;\r\n\r\n    // binLogParser\r\n    protected BinlogParser                           binlogParser               = null;\r\n\r\n    protected Thread                                 parseThread                = null;\r\n\r\n    protected Thread.UncaughtExceptionHandler        handler                    = (t, e) -> logger.error(\"parse events has an error\",\r\n        e);\r\n\r\n    protected EventTransactionBuffer                 transactionBuffer;\r\n    protected int                                    transactionSize            = 1024;\r\n    protected AtomicBoolean                          needTransactionPosition    = new AtomicBoolean(false);\r\n    protected long                                   lastEntryTime              = 0L;\r\n    protected volatile boolean                       detectingEnable            = true;                                    // 是否开启心跳检查\r\n    protected Integer                                detectingIntervalInSeconds = 3;                                       // 检测频率\r\n    protected volatile Timer                         timer;\r\n    protected TimerTask                              heartBeatTimerTask;\r\n    protected Throwable                              exception                  = null;\r\n\r\n    protected boolean                                isGTIDMode                 = false;                                   // 是否是GTID模式\r\n    protected boolean                                parallel                   = true;                                    // 是否开启并行解析模式\r\n    protected Integer                                parallelThreadSize         = Runtime.getRuntime()\r\n                                                                                    .availableProcessors() * 60 / 100;     // 60%的能力跑解析,剩余部分处理网络\r\n    protected int                                    parallelBufferSize         = 256;                                     // 必须为2的幂\r\n    protected MultiStageCoprocessor                  multiStageCoprocessor;\r\n    protected ParserExceptionHandler                 parserExceptionHandler;\r\n    protected long                                   serverId;\r\n\r\n    protected abstract BinlogParser buildParser();\r\n\r\n    protected abstract ErosaConnection buildErosaConnection();\r\n\r\n    protected abstract MultiStageCoprocessor buildMultiStageCoprocessor();\r\n\r\n    protected abstract EntryPosition findStartPosition(ErosaConnection connection) throws IOException;\r\n\r\n    protected void preDump(ErosaConnection connection) {\r\n    }\r\n\r\n    protected boolean processTableMeta(EntryPosition position) {\r\n        return true;\r\n    }\r\n\r\n    protected void afterDump(ErosaConnection connection) {\r\n    }\r\n\r\n    public void sendAlarm(String destination, String msg) {\r\n        if (this.alarmHandler != null) {\r\n            this.alarmHandler.sendAlarm(destination, msg);\r\n        }\r\n    }\r\n\r\n    public AbstractEventParser(){\r\n        // 初始化一下\r\n        transactionBuffer = new EventTransactionBuffer(transaction -> {\r\n            boolean successed = consumeTheEventAndProfilingIfNecessary(transaction);\r\n            if (!running) {\r\n                return;\r\n            }\r\n\r\n            if (!successed) {\r\n                throw new CanalParseException(\"consume failed!\");\r\n            }\r\n\r\n            LogPosition position = buildLastTransactionPosition(transaction);\r\n            if (position != null) { // 可能position为空\r\n                logPositionManager.persistLogPosition(AbstractEventParser.this.destination, position);\r\n            }\r\n        });\r\n    }\r\n\r\n    public void start() {\r\n        super.start();\r\n        MDC.put(\"destination\", destination);\r\n        // 配置transaction buffer\r\n        // 初始化缓冲队列\r\n        transactionBuffer.setBufferSize(transactionSize);// 设置buffer大小\r\n        transactionBuffer.start();\r\n        // 构造bin log parser\r\n        binlogParser = buildParser();// 初始化一下BinLogParser\r\n        binlogParser.start();\r\n        // 启动工作线程\r\n        parseThread = new Thread(new Runnable() {\r\n\r\n            public void run() {\r\n                MDC.put(\"destination\", String.valueOf(destination));\r\n                ErosaConnection erosaConnection = null;\r\n                boolean isMariaDB = false;\r\n                while (running) {\r\n                    try {\r\n                        // 开始执行replication\r\n                        // 1. 构造Erosa连接\r\n                        erosaConnection = buildErosaConnection();\r\n\r\n                        // 2. 启动一个心跳线程\r\n                        startHeartBeat(erosaConnection);\r\n\r\n                        // 3. 执行dump前的准备工作\r\n                        preDump(erosaConnection);\r\n\r\n                        erosaConnection.connect();// 链接\r\n\r\n                        long queryServerId = erosaConnection.queryServerId();\r\n                        if (queryServerId != 0) {\r\n                            serverId = queryServerId;\r\n                        }\r\n\r\n                        if (erosaConnection instanceof MysqlConnection) {\r\n                            isMariaDB = ((MysqlConnection) erosaConnection).isMariaDB();\r\n                        }\r\n                        // 4. 获取最后的位置信息\r\n                        long start = System.currentTimeMillis();\r\n                        logger.warn(\"---> begin to find start position, it will be long time for reset or first position\");\r\n                        EntryPosition position = findStartPosition(erosaConnection);\r\n                        final EntryPosition startPosition = position;\r\n                        if (startPosition == null) {\r\n                            throw new PositionNotFoundException(\"can't find start position for \" + destination);\r\n                        }\r\n\r\n                        if (!processTableMeta(startPosition)) {\r\n                            throw new CanalParseException(\"can't find init table meta for \" + destination\r\n                                                          + \" with position : \" + startPosition);\r\n                        }\r\n                        long end = System.currentTimeMillis();\r\n                        logger.warn(\"---> find start position successfully, {}\", startPosition.toString() + \" cost : \"\r\n                                                                                 + (end - start)\r\n                                                                                 + \"ms , the next step is binlog dump\");\r\n                        // 重新链接，因为在找position过程中可能有状态，需要断开后重建\r\n                        erosaConnection.reconnect();\r\n\r\n                        final SinkFunction sinkHandler = new SinkFunction<EVENT>() {\r\n\r\n                            private LogPosition lastPosition;\r\n\r\n                            public boolean sink(EVENT event) {\r\n                                try {\r\n                                    CanalEntry.Entry entry = parseAndProfilingIfNecessary(event, false);\r\n\r\n                                    if (!running) {\r\n                                        return false;\r\n                                    }\r\n\r\n                                    if (entry != null) {\r\n                                        exception = null; // 有正常数据流过，清空exception\r\n                                        transactionBuffer.add(entry);\r\n                                        // 记录一下对应的positions\r\n                                        this.lastPosition = buildLastPosition(entry);\r\n                                        // 记录一下最后一次有数据的时间\r\n                                        lastEntryTime = System.currentTimeMillis();\r\n                                    }\r\n                                    return running;\r\n                                } catch (TableIdNotFoundException e) {\r\n                                    throw e;\r\n                                } catch (Throwable e) {\r\n                                    if (e.getCause() instanceof TableIdNotFoundException) {\r\n                                        throw (TableIdNotFoundException) e.getCause();\r\n                                    }\r\n                                    // 记录一下，出错的位点信息\r\n                                    processSinkError(e,\r\n                                        this.lastPosition,\r\n                                        startPosition.getJournalName(),\r\n                                        startPosition.getPosition());\r\n                                    throw new CanalParseException(e); // 继续抛出异常，让上层统一感知\r\n                                }\r\n                            }\r\n\r\n                        };\r\n\r\n                        // 4. 开始dump数据\r\n                        if (parallel) {\r\n                            // build stage processor\r\n                            multiStageCoprocessor = buildMultiStageCoprocessor();\r\n                            if (isGTIDMode() && StringUtils.isNotEmpty(startPosition.getGtid())) {\r\n                                // 判断所属instance是否启用GTID模式，是的话调用ErosaConnection中GTID对应方法dump数据\r\n                                GTIDSet gtidSet = parseGtidSet(startPosition.getGtid(), isMariaDB);\r\n                                ((MysqlMultiStageCoprocessor) multiStageCoprocessor).setGtidSet(gtidSet);\r\n                                multiStageCoprocessor.start();\r\n                                erosaConnection.dump(gtidSet, multiStageCoprocessor);\r\n                            } else {\r\n                                multiStageCoprocessor.start();\r\n                                if (StringUtils.isEmpty(startPosition.getJournalName())\r\n                                    && startPosition.getTimestamp() != null) {\r\n                                    erosaConnection.dump(startPosition.getTimestamp(), multiStageCoprocessor);\r\n                                } else {\r\n                                    erosaConnection.dump(startPosition.getJournalName(),\r\n                                        startPosition.getPosition(),\r\n                                        multiStageCoprocessor);\r\n                                }\r\n                            }\r\n                        } else {\r\n                            if (isGTIDMode() && StringUtils.isNotEmpty(startPosition.getGtid())) {\r\n                                // 判断所属instance是否启用GTID模式，是的话调用ErosaConnection中GTID对应方法dump数据\r\n                                erosaConnection.dump(parseGtidSet(startPosition.getGtid(), isMariaDB), sinkHandler);\r\n                            } else {\r\n                                if (StringUtils.isEmpty(startPosition.getJournalName())\r\n                                    && startPosition.getTimestamp() != null) {\r\n                                    erosaConnection.dump(startPosition.getTimestamp(), sinkHandler);\r\n                                } else {\r\n                                    erosaConnection.dump(startPosition.getJournalName(),\r\n                                        startPosition.getPosition(),\r\n                                        sinkHandler);\r\n                                }\r\n                            }\r\n                        }\r\n                    } catch (TableIdNotFoundException e) {\r\n                        exception = e;\r\n                        // 特殊处理TableIdNotFound异常,出现这样的异常，一种可能就是起始的position是一个事务当中，导致tablemap\r\n                        // Event时间没解析过\r\n                        needTransactionPosition.compareAndSet(false, true);\r\n                        logger.error(String.format(\"dump address %s has an error, retrying. caused by \",\r\n                            runningInfo.getAddress().toString()), e);\r\n                    } catch (Throwable e) {\r\n                        processDumpError(e);\r\n                        exception = e;\r\n                        if (!running) {\r\n                            if (!(e instanceof java.nio.channels.ClosedByInterruptException || e.getCause() instanceof java.nio.channels.ClosedByInterruptException)) {\r\n                                throw new CanalParseException(String.format(\"dump address %s has an error, retrying. \",\r\n                                    runningInfo.getAddress().toString()), e);\r\n                            }\r\n                        } else {\r\n                            logger.error(String.format(\"dump address %s has an error, retrying. caused by \",\r\n                                runningInfo.getAddress().toString()), e);\r\n                            sendAlarm(destination, ExceptionUtils.getFullStackTrace(e));\r\n                        }\r\n                        if (parserExceptionHandler != null) {\r\n                            parserExceptionHandler.handle(e);\r\n                        }\r\n                    } finally {\r\n                        // 重新置为中断状态\r\n                        Thread.interrupted();\r\n                        // 关闭一下链接\r\n                        afterDump(erosaConnection);\r\n                        try {\r\n                            if (erosaConnection != null) {\r\n                                erosaConnection.disconnect();\r\n                            }\r\n                        } catch (IOException e1) {\r\n                            if (!running) {\r\n                                throw new CanalParseException(String.format(\"disconnect address %s has an error, retrying. \",\r\n                                    runningInfo.getAddress().toString()),\r\n                                    e1);\r\n                            } else {\r\n                                logger.error(\"disconnect address {} has an error, retrying., caused by \",\r\n                                    runningInfo.getAddress().toString(),\r\n                                    e1);\r\n                            }\r\n                        }\r\n                    }\r\n                    // 出异常了，退出sink消费，释放一下状态\r\n                    eventSink.interrupt();\r\n                    transactionBuffer.reset();// 重置一下缓冲队列，重新记录数据\r\n                    binlogParser.reset();// 重新置位\r\n                    if (multiStageCoprocessor != null && multiStageCoprocessor.isStart()) {\r\n                        // 处理 RejectedExecutionException\r\n                        try {\r\n                            multiStageCoprocessor.stop();\r\n                        } catch (Throwable t) {\r\n                            logger.debug(\"multi processor rejected:\", t);\r\n                        }\r\n                    }\r\n\r\n                    if (running) {\r\n                        // sleep一段时间再进行重试\r\n                        try {\r\n                            Thread.sleep(10000 + RandomUtils.nextInt(10000));\r\n                        } catch (InterruptedException e) {\r\n                        }\r\n                    }\r\n                }\r\n                MDC.remove(\"destination\");\r\n            }\r\n        });\r\n\r\n        parseThread.setUncaughtExceptionHandler(handler);\r\n        parseThread.setName(String.format(\"destination = %s , address = %s , EventParser\",\r\n            destination,\r\n            runningInfo == null ? null : runningInfo.getAddress()));\r\n        parseThread.start();\r\n    }\r\n\r\n    public void stop() {\r\n        super.stop();\r\n\r\n        stopHeartBeat(); // 先停止心跳\r\n        parseThread.interrupt(); // 尝试中断\r\n        eventSink.interrupt();\r\n\r\n        if (multiStageCoprocessor != null && multiStageCoprocessor.isStart()) {\r\n            try {\r\n                multiStageCoprocessor.stop();\r\n            } catch (Throwable t) {\r\n                logger.debug(\"multi processor rejected:\", t);\r\n            }\r\n        }\r\n\r\n        try {\r\n            parseThread.join();// 等待其结束\r\n        } catch (InterruptedException e) {\r\n            // ignore\r\n        }\r\n\r\n        if (binlogParser.isStart()) {\r\n            binlogParser.stop();\r\n        }\r\n        if (transactionBuffer.isStart()) {\r\n            transactionBuffer.stop();\r\n        }\r\n    }\r\n\r\n    protected boolean consumeTheEventAndProfilingIfNecessary(List<CanalEntry.Entry> entrys) throws CanalSinkException,\r\n                                                                                           InterruptedException {\r\n        long startTs = -1;\r\n        boolean enabled = getProfilingEnabled();\r\n        if (enabled) {\r\n            startTs = System.currentTimeMillis();\r\n        }\r\n\r\n        boolean result = eventSink.sink(entrys, (runningInfo == null) ? null : runningInfo.getAddress(), destination);\r\n\r\n        if (enabled) {\r\n            this.processingInterval = System.currentTimeMillis() - startTs;\r\n        }\r\n\r\n        if (consumedEventCount.incrementAndGet() < 0) {\r\n            consumedEventCount.set(0);\r\n        }\r\n\r\n        return result;\r\n    }\r\n\r\n    protected CanalEntry.Entry parseAndProfilingIfNecessary(EVENT bod, boolean isSeek) throws Exception {\r\n        long startTs = -1;\r\n        boolean enabled = getProfilingEnabled();\r\n        if (enabled) {\r\n            startTs = System.currentTimeMillis();\r\n        }\r\n        CanalEntry.Entry event = binlogParser.parse(bod, isSeek);\r\n        if (enabled) {\r\n            this.parsingInterval = System.currentTimeMillis() - startTs;\r\n        }\r\n\r\n        if (parsedEventCount.incrementAndGet() < 0) {\r\n            parsedEventCount.set(0);\r\n        }\r\n        return event;\r\n    }\r\n\r\n    public Boolean getProfilingEnabled() {\r\n        return profilingEnabled.get();\r\n    }\r\n\r\n    protected LogPosition buildLastTransactionPosition(List<CanalEntry.Entry> entries) { // 初始化一下\r\n        for (int i = entries.size() - 1; i > 0; i--) {\r\n            CanalEntry.Entry entry = entries.get(i);\r\n            if (entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONEND) {// 尽量记录一个事务做为position\r\n                return buildLastPosition(entry);\r\n            }\r\n        }\r\n\r\n        return null;\r\n    }\r\n\r\n    protected LogPosition buildLastPosition(CanalEntry.Entry entry) { // 初始化一下\r\n        LogPosition logPosition = new LogPosition();\r\n        EntryPosition position = new EntryPosition();\r\n        position.setJournalName(entry.getHeader().getLogfileName());\r\n        position.setPosition(entry.getHeader().getLogfileOffset());\r\n        position.setTimestamp(entry.getHeader().getExecuteTime());\r\n        // add serverId at 2016-06-28\r\n        position.setServerId(entry.getHeader().getServerId());\r\n        // set gtid\r\n        position.setGtid(entry.getHeader().getGtid());\r\n\r\n        logPosition.setPostion(position);\r\n\r\n        LogIdentity identity = new LogIdentity(runningInfo.getAddress(), -1L);\r\n        logPosition.setIdentity(identity);\r\n        return logPosition;\r\n    }\r\n\r\n    protected void processSinkError(Throwable e, LogPosition lastPosition, String startBinlogFile, Long startPosition) {\r\n        if (lastPosition != null) {\r\n            logger.warn(String.format(\"ERROR ## parse this event has an error , last position : [%s]\",\r\n                lastPosition.getPostion()),\r\n                e);\r\n        } else {\r\n            logger.warn(String.format(\"ERROR ## parse this event has an error , last position : [%s,%s]\",\r\n                startBinlogFile,\r\n                startPosition), e);\r\n        }\r\n    }\r\n\r\n    protected void processDumpError(Throwable e) {\r\n        // do nothing\r\n    }\r\n\r\n    protected void startHeartBeat(ErosaConnection connection) {\r\n        lastEntryTime = 0L; // 初始化\r\n        if (timer == null) {// lazy初始化一下\r\n            String name = String.format(\"destination = %s , address = %s , HeartBeatTimeTask\",\r\n                destination,\r\n                runningInfo == null ? null : runningInfo.getAddress().toString());\r\n            synchronized (AbstractEventParser.class) {\r\n                // synchronized (MysqlEventParser.class) {\r\n                // why use MysqlEventParser.class, u know, MysqlEventParser is\r\n                // the child class 4 AbstractEventParser,\r\n                // do this is ...\r\n                if (timer == null) {\r\n                    timer = new Timer(name, true);\r\n                }\r\n            }\r\n        }\r\n\r\n        if (heartBeatTimerTask == null) {// fixed issue #56，避免重复创建heartbeat线程\r\n            heartBeatTimerTask = buildHeartBeatTimeTask(connection);\r\n            Integer interval = detectingIntervalInSeconds;\r\n            timer.schedule(heartBeatTimerTask, interval * 1000L, interval * 1000L);\r\n            logger.info(\"start heart beat.... \");\r\n        }\r\n    }\r\n\r\n    protected TimerTask buildHeartBeatTimeTask(ErosaConnection connection) {\r\n        return new TimerTask() {\r\n\r\n            public void run() {\r\n                try {\r\n                    if (exception == null || lastEntryTime > 0) {\r\n                        // 如果未出现异常，或者有第一条正常数据\r\n                        long now = System.currentTimeMillis();\r\n                        long inteval = (now - lastEntryTime) / 1000;\r\n                        if (inteval >= detectingIntervalInSeconds) {\r\n                            Header.Builder headerBuilder = Header.newBuilder();\r\n                            headerBuilder.setExecuteTime(now);\r\n                            Entry.Builder entryBuilder = Entry.newBuilder();\r\n                            entryBuilder.setHeader(headerBuilder.build());\r\n                            entryBuilder.setEntryType(EntryType.HEARTBEAT);\r\n                            Entry entry = entryBuilder.build();\r\n                            // 提交到sink中，目前不会提交到store中，会在sink中进行忽略\r\n                            consumeTheEventAndProfilingIfNecessary(Arrays.asList(entry));\r\n                        }\r\n                    }\r\n\r\n                } catch (Throwable e) {\r\n                    logger.warn(\"heartBeat run failed \", e);\r\n                }\r\n            }\r\n\r\n        };\r\n    }\r\n\r\n    protected void stopHeartBeat() {\r\n        lastEntryTime = 0L; // 初始化\r\n        if (timer != null) {\r\n            timer.cancel();\r\n            timer = null;\r\n        }\r\n        heartBeatTimerTask = null;\r\n    }\r\n    \r\n    /**\r\n     * 解析字段过滤规则\r\n     */\r\n    private Map<String, List<String>> parseFieldFilterMap(String config) {\r\n    \t\r\n    \tMap<String, List<String>> map = new HashMap<>();\r\n\t\t\r\n\t\tif (StringUtils.isNotBlank(config)) {\r\n\t\t\tfor (String filter : config.split(\",\")) {\r\n\t\t\t\tif (StringUtils.isBlank(filter)) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tString[] filterConfig = filter.split(\":\");\r\n\t\t\t\tif (filterConfig.length != 2) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tmap.put(filterConfig[0].trim().toUpperCase(), Arrays.asList(filterConfig[1].trim().toUpperCase().split(\"/\")));\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\treturn map;\r\n    }\r\n\r\n    public void setEventFilter(CanalEventFilter eventFilter) {\r\n        this.eventFilter = eventFilter;\r\n    }\r\n\r\n    public void setEventBlackFilter(CanalEventFilter eventBlackFilter) {\r\n        this.eventBlackFilter = eventBlackFilter;\r\n    }\r\n\r\n    public Long getParsedEventCount() {\r\n        return parsedEventCount.get();\r\n    }\r\n\r\n    public Long getConsumedEventCount() {\r\n        return consumedEventCount.get();\r\n    }\r\n\r\n    public void setProfilingEnabled(boolean profilingEnabled) {\r\n        this.profilingEnabled = new AtomicBoolean(profilingEnabled);\r\n    }\r\n\r\n    public long getParsingInterval() {\r\n        return parsingInterval;\r\n    }\r\n\r\n    public long getProcessingInterval() {\r\n        return processingInterval;\r\n    }\r\n\r\n    public void setEventSink(CanalEventSink<List<CanalEntry.Entry>> eventSink) {\r\n        this.eventSink = eventSink;\r\n    }\r\n\r\n    public void setDestination(String destination) {\r\n        this.destination = destination;\r\n    }\r\n\r\n    public void setBinlogParser(BinlogParser binlogParser) {\r\n        this.binlogParser = binlogParser;\r\n    }\r\n\r\n    public BinlogParser getBinlogParser() {\r\n        return binlogParser;\r\n    }\r\n\r\n    public void setAlarmHandler(CanalAlarmHandler alarmHandler) {\r\n        this.alarmHandler = alarmHandler;\r\n    }\r\n\r\n    public CanalAlarmHandler getAlarmHandler() {\r\n        return this.alarmHandler;\r\n    }\r\n\r\n    public void setLogPositionManager(CanalLogPositionManager logPositionManager) {\r\n        this.logPositionManager = logPositionManager;\r\n    }\r\n\r\n    public void setTransactionSize(int transactionSize) {\r\n        this.transactionSize = transactionSize;\r\n    }\r\n\r\n    public CanalLogPositionManager getLogPositionManager() {\r\n        return logPositionManager;\r\n    }\r\n\r\n    public void setDetectingEnable(boolean detectingEnable) {\r\n        this.detectingEnable = detectingEnable;\r\n    }\r\n\r\n    public void setDetectingIntervalInSeconds(Integer detectingIntervalInSeconds) {\r\n        this.detectingIntervalInSeconds = detectingIntervalInSeconds;\r\n    }\r\n\r\n    public Throwable getException() {\r\n        return exception;\r\n    }\r\n\r\n    public boolean isGTIDMode() {\r\n        return isGTIDMode;\r\n    }\r\n\r\n    public void setIsGTIDMode(boolean isGTIDMode) {\r\n        this.isGTIDMode = isGTIDMode;\r\n    }\r\n\r\n    public boolean isParallel() {\r\n        return parallel;\r\n    }\r\n\r\n    public void setParallel(boolean parallel) {\r\n        this.parallel = parallel;\r\n    }\r\n\r\n    public int getParallelThreadSize() {\r\n        return parallelThreadSize;\r\n    }\r\n\r\n    public void setParallelThreadSize(Integer parallelThreadSize) {\r\n        if (parallelThreadSize != null) {\r\n            this.parallelThreadSize = parallelThreadSize;\r\n        }\r\n    }\r\n\r\n    public Integer getParallelBufferSize() {\r\n        return parallelBufferSize;\r\n    }\r\n\r\n    public void setParallelBufferSize(int parallelBufferSize) {\r\n        this.parallelBufferSize = parallelBufferSize;\r\n    }\r\n\r\n    public ParserExceptionHandler getParserExceptionHandler() {\r\n        return parserExceptionHandler;\r\n    }\r\n\r\n    public void setParserExceptionHandler(ParserExceptionHandler parserExceptionHandler) {\r\n        this.parserExceptionHandler = parserExceptionHandler;\r\n    }\r\n\r\n    public long getServerId() {\r\n        return serverId;\r\n    }\r\n\r\n    public void setServerId(long serverId) {\r\n        this.serverId = serverId;\r\n    }\r\n\r\n    public String getFieldFilter() {\r\n\t\treturn fieldFilter;\r\n\t}\r\n\r\n\tpublic void setFieldFilter(String fieldFilter) {\r\n\t\tthis.fieldFilter = fieldFilter.trim();\r\n\t\tthis.fieldFilterMap = parseFieldFilterMap(fieldFilter);\r\n\t}\r\n\t\r\n\tpublic String getFieldBlackFilter() {\r\n\t\treturn fieldBlackFilter;\r\n\t}\r\n\r\n\tpublic void setFieldBlackFilter(String fieldBlackFilter) {\r\n\t\tthis.fieldBlackFilter = fieldBlackFilter;\r\n\t\tthis.fieldBlackFilterMap = parseFieldFilterMap(fieldBlackFilter);\r\n\t}\r\n\r\n\t/**\r\n\t * 获取表字段过滤规则\r\n\t * @return\r\n\t * \tkey:\tschema.tableName\r\n\t * \tvalue:\t字段列表\r\n\t */\r\n\tpublic Map<String, List<String>> getFieldFilterMap() {\r\n\t\treturn fieldFilterMap;\r\n\t}\r\n\r\n\t/**\r\n\t * 获取表字段过滤规则黑名单\r\n\t * @return\r\n\t * \tkey:\tschema.tableName\r\n\t * \tvalue:\t字段列表\r\n\t */\r\n\tpublic Map<String, List<String>> getFieldBlackFilterMap() {\r\n\t\treturn fieldBlackFilterMap;\r\n\t}\r\n}\r\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/BinlogParser.java",
    "content": "package com.alibaba.otter.canal.parse.inbound;\r\n\r\nimport com.alibaba.otter.canal.common.CanalLifeCycle;\r\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\r\nimport com.alibaba.otter.canal.protocol.CanalEntry;\r\n\r\n/**\r\n * 解析binlog的接口\r\n * \r\n * @author: yuanzu Date: 12-9-20 Time: 下午8:46\r\n */\r\npublic interface BinlogParser<T> extends CanalLifeCycle {\r\n\r\n    CanalEntry.Entry parse(T event, boolean isSeek) throws CanalParseException;\r\n\r\n    void reset();\r\n}\r\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/ErosaConnection.java",
    "content": "package com.alibaba.otter.canal.parse.inbound;\r\n\r\nimport java.io.IOException;\r\n\r\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.GTIDSet;\r\n\r\n/**\r\n * 通用的Erosa的链接接口, 用于一般化处理mysql/oracle的解析过程\r\n * \r\n * @author: yuanzu Date: 12-9-20 Time: 下午2:47\r\n */\r\npublic interface ErosaConnection {\r\n\r\n    public void connect() throws IOException;\r\n\r\n    public void reconnect() throws IOException;\r\n\r\n    public void disconnect() throws IOException;\r\n\r\n    /**\r\n     * 用于快速数据查找,和dump的区别在于，seek会只给出部分的数据\r\n     */\r\n    public void seek(String binlogfilename, Long binlogPosition, String gtid, SinkFunction func) throws IOException;\r\n\r\n    public void dump(String binlogfilename, Long binlogPosition, SinkFunction func) throws IOException;\r\n\r\n    public void dump(long timestamp, SinkFunction func) throws IOException;\r\n\r\n    /**\r\n     * 通过GTID同步binlog\r\n     */\r\n    public void dump(GTIDSet gtidSet, SinkFunction func) throws IOException;\r\n\r\n    // -------------\r\n\r\n    public void dump(String binlogfilename, Long binlogPosition, MultiStageCoprocessor coprocessor) throws IOException;\r\n\r\n    public void dump(long timestamp, MultiStageCoprocessor coprocessor) throws IOException;\r\n\r\n    public void dump(GTIDSet gtidSet, MultiStageCoprocessor coprocessor) throws IOException;\r\n\r\n    ErosaConnection fork();\r\n\r\n    public long queryServerId() throws IOException;\r\n}\r\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/EventTransactionBuffer.java",
    "content": "package com.alibaba.otter.canal.parse.inbound;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.springframework.util.Assert;\n\nimport com.alibaba.otter.canal.common.AbstractCanalLifeCycle;\nimport com.alibaba.otter.canal.protocol.CanalEntry;\nimport com.alibaba.otter.canal.protocol.CanalEntry.EventType;\nimport com.alibaba.otter.canal.store.CanalStoreException;\n\n/**\n * 缓冲event队列，提供按事务刷新数据的机制\n * \n * @author jianghang 2012-12-6 上午11:05:12\n * @version 1.0.0\n */\npublic class EventTransactionBuffer extends AbstractCanalLifeCycle {\n\n    private static final long        INIT_SQEUENCE = -1;\n    private int                      bufferSize    = 1024;\n    private int                      indexMask;\n    private CanalEntry.Entry[]       entries;\n\n    private AtomicLong               putSequence   = new AtomicLong(INIT_SQEUENCE); // 代表当前put操作最后一次写操作发生的位置\n    private AtomicLong               flushSequence = new AtomicLong(INIT_SQEUENCE); // 代表满足flush条件后最后一次数据flush的时间\n\n    private TransactionFlushCallback flushCallback;\n\n    public EventTransactionBuffer(){\n\n    }\n\n    public EventTransactionBuffer(TransactionFlushCallback flushCallback){\n        this.flushCallback = flushCallback;\n    }\n\n    public void start() throws CanalStoreException {\n        super.start();\n        if (Integer.bitCount(bufferSize) != 1) {\n            throw new IllegalArgumentException(\"bufferSize must be a power of 2\");\n        }\n\n        Assert.notNull(flushCallback, \"flush callback is null!\");\n        indexMask = bufferSize - 1;\n        entries = new CanalEntry.Entry[bufferSize];\n    }\n\n    public void stop() throws CanalStoreException {\n        putSequence.set(INIT_SQEUENCE);\n        flushSequence.set(INIT_SQEUENCE);\n\n        entries = null;\n        super.stop();\n    }\n\n    public void add(List<CanalEntry.Entry> entrys) throws InterruptedException {\n        for (CanalEntry.Entry entry : entrys) {\n            add(entry);\n        }\n    }\n\n    public void add(CanalEntry.Entry entry) throws InterruptedException {\n        switch (entry.getEntryType()) {\n            case TRANSACTIONBEGIN:\n                flush();// 刷新上一次的数据\n                put(entry);\n                break;\n            case TRANSACTIONEND:\n                put(entry);\n                flush();\n                break;\n            case ROWDATA:\n                put(entry);\n                // 针对非DML的数据，直接输出，不进行buffer控制\n                EventType eventType = entry.getHeader().getEventType();\n                if (eventType != null && !isDml(eventType)) {\n                    flush();\n                }\n                break;\n            case HEARTBEAT:\n                // master过来的heartbeat，说明binlog已经读完了，是idle状态\n                put(entry);\n                flush();\n                break;\n            default:\n                break;\n        }\n    }\n\n    public void reset() {\n        putSequence.set(INIT_SQEUENCE);\n        flushSequence.set(INIT_SQEUENCE);\n    }\n\n    private void put(CanalEntry.Entry data) throws InterruptedException {\n        // 首先检查是否有空位\n        if (checkFreeSlotAt(putSequence.get() + 1)) {\n            long current = putSequence.get();\n            long next = current + 1;\n\n            // 先写数据，再更新对应的cursor,并发度高的情况，putSequence会被get请求可见，拿出了ringbuffer中的老的Entry值\n            entries[getIndex(next)] = data;\n            putSequence.set(next);\n        } else {\n            flush();// buffer区满了，刷新一下\n            put(data);// 继续加一下新数据\n        }\n    }\n\n    private void flush() throws InterruptedException {\n        long start = this.flushSequence.get() + 1;\n        long end = this.putSequence.get();\n\n        if (start <= end) {\n            List<CanalEntry.Entry> transaction = new ArrayList<>();\n            for (long next = start; next <= end; next++) {\n                transaction.add(this.entries[getIndex(next)]);\n            }\n\n            flushCallback.flush(transaction);\n            flushSequence.set(end);// flush成功后，更新flush位置\n        }\n    }\n\n    /**\n     * 查询是否有空位\n     */\n    private boolean checkFreeSlotAt(final long sequence) {\n        final long wrapPoint = sequence - bufferSize;\n        if (wrapPoint > flushSequence.get()) { // 刚好追上一轮\n            return false;\n        } else {\n            return true;\n        }\n    }\n\n    private int getIndex(long sequcnce) {\n        return (int) sequcnce & indexMask;\n    }\n\n    private boolean isDml(EventType eventType) {\n        return eventType == EventType.INSERT || eventType == EventType.UPDATE || eventType == EventType.DELETE;\n    }\n\n    // ================ setter / getter ==================\n\n    public void setBufferSize(int bufferSize) {\n        this.bufferSize = bufferSize;\n    }\n\n    public void setFlushCallback(TransactionFlushCallback flushCallback) {\n        this.flushCallback = flushCallback;\n    }\n\n    /**\n     * 事务刷新机制\n     * \n     * @author jianghang 2012-12-6 上午11:57:38\n     * @version 1.0.0\n     */\n    public static interface TransactionFlushCallback {\n\n        public void flush(List<CanalEntry.Entry> transaction) throws InterruptedException;\n    }\n\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/HeartBeatCallback.java",
    "content": "package com.alibaba.otter.canal.parse.inbound;\n\n/**\n * 提供mysql heartBeat心跳数据的callback机制\n * \n * @author jianghang 2012-6-26 下午04:49:56\n * @version 1.0.0\n */\npublic interface HeartBeatCallback {\n\n    /**\n     * 心跳发送成功\n     */\n    public void onSuccess(long costTime);\n\n    /**\n     * 心跳发送失败\n     */\n    public void onFailed(Throwable e);\n\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/MultiStageCoprocessor.java",
    "content": "package com.alibaba.otter.canal.parse.inbound;\n\nimport com.alibaba.otter.canal.common.CanalLifeCycle;\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\n\n/**\n * 针对解析器提供一个多阶段协同的处理\n * \n * <pre>\n * 1. 网络接收 (单线程)\n * 2. 事件基本解析 (单线程，事件类型、DDL解析构造TableMeta、维护位点信息)\n * 3. 事件深度解析 (多线程, DML事件数据的完整解析)\n * 4. 投递到store (单线程)\n * </pre>\n * \n * @author agapple 2018年7月3日 下午4:54:17\n * @since 1.0.26\n */\npublic interface MultiStageCoprocessor extends CanalLifeCycle {\n\n    /**\n     * 网络数据投递\n     */\n    public boolean publish(LogBuffer buffer);\n\n    public boolean publish(LogEvent event);\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/ParserExceptionHandler.java",
    "content": "package com.alibaba.otter.canal.parse.inbound;\n\n/**\n * @author chengjin.lyf on 2018/7/20 下午3:55\n * @since 1.0.25\n */\npublic interface ParserExceptionHandler {\n\n    void handle(Throwable e);\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/SinkFunction.java",
    "content": "package com.alibaba.otter.canal.parse.inbound;\r\n\r\n/**\r\n * receive parsed bytes , 用于处理要解析的数据块\r\n * \r\n * @author: yuanzu Date: 12-9-20 Time: 下午2:50\r\n */\r\n\r\npublic interface SinkFunction<EVENT> {\r\n\r\n    public boolean sink(EVENT event);\r\n}\r\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/TableMeta.java",
    "content": "package com.alibaba.otter.canal.parse.inbound;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.apache.commons.lang.StringUtils;\n\nimport com.taobao.tddl.dbsync.binlog.event.TableMapLogEvent;\n\n/**\n * 描述数据meta对象,mysql binlog中对应的{@linkplain TableMapLogEvent}包含的信息不全\n *\n * <pre>\n * 1. 主键信息\n * 2. column name\n * 3. unsigned字段\n * </pre>\n *\n * @author jianghang 2013-1-18 下午12:24:59\n * @version 1.0.0\n */\npublic class TableMeta {\n\n    private String          schema;\n    private String          table;\n    private List<FieldMeta> fields = new ArrayList<>();\n    private String          ddl;                       // 表结构的DDL语句\n\n    public TableMeta(){\n\n    }\n\n    public TableMeta(String schema, String table, List<FieldMeta> fields){\n        this.schema = schema;\n        this.table = table;\n        this.fields = fields;\n    }\n\n    public String getFullName() {\n        return schema + \".\" + table;\n    }\n\n    public String getSchema() {\n        return schema;\n    }\n\n    public void setSchema(String schema) {\n        this.schema = schema;\n    }\n\n    public String getTable() {\n        return table;\n    }\n\n    public void setTable(String table) {\n        this.table = table;\n    }\n\n    public List<FieldMeta> getFields() {\n        return fields;\n    }\n\n    public void setFields(List<FieldMeta> fileds) {\n        this.fields = fileds;\n    }\n\n    public FieldMeta getFieldMetaByName(String name) {\n        for (FieldMeta meta : fields) {\n            if (meta.getColumnName().equalsIgnoreCase(name)) {\n                return meta;\n            }\n        }\n\n        throw new RuntimeException(\"unknow column : \" + name);\n    }\n\n    /**\n     * 尝试基于列名查找一下Filed信息,找不到时返回为null\n     * \n     * @param name\n     * @return\n     */\n    public FieldMeta tryGetFieldMetaByName(String name) {\n        for (FieldMeta meta : fields) {\n            if (meta.getColumnName().equalsIgnoreCase(name)) {\n                return meta;\n            }\n        }\n\n        return null;\n    }\n\n    public List<FieldMeta> getPrimaryFields() {\n        List<FieldMeta> primarys = new ArrayList<>();\n        for (FieldMeta meta : fields) {\n            if (meta.isKey()) {\n                primarys.add(meta);\n            }\n        }\n\n        return primarys;\n    }\n\n    public String getDdl() {\n        return ddl;\n    }\n\n    public void setDdl(String ddl) {\n        this.ddl = ddl;\n    }\n\n    public void addFieldMeta(FieldMeta fieldMeta) {\n        this.fields.add(fieldMeta);\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder data = new StringBuilder();\n        data.append(\"TableMeta [schema=\" + schema + \", table=\" + table + \", fileds=\");\n        for (FieldMeta field : fields) {\n            data.append(\"\\n\\t\").append(field.toString());\n        }\n        data.append(\"\\n]\");\n        return data.toString();\n    }\n\n    public static class FieldMeta {\n\n        public FieldMeta(){\n\n        }\n\n        public FieldMeta(String columnName, String columnType, boolean nullable, boolean key, String defaultValue){\n            this.columnName = columnName;\n            this.columnType = columnType;\n            this.nullable = nullable;\n            this.key = key;\n            this.defaultValue = defaultValue;\n        }\n\n        private String  columnName;\n        private String  columnType;\n        private boolean nullable;\n        private boolean key;\n        private String  defaultValue;\n        private String  extra;\n        private boolean unique;\n\n        public String getColumnName() {\n            return columnName;\n        }\n\n        public void setColumnName(String columnName) {\n            this.columnName = columnName;\n        }\n\n        public String getColumnType() {\n            return columnType;\n        }\n\n        public void setColumnType(String columnType) {\n            this.columnType = columnType;\n        }\n\n        public void setNullable(boolean nullable) {\n            this.nullable = nullable;\n        }\n\n        public String getDefaultValue() {\n            return defaultValue;\n        }\n\n        public void setDefaultValue(String defaultValue) {\n            this.defaultValue = defaultValue;\n        }\n\n        public boolean isUnsigned() {\n            return StringUtils.containsIgnoreCase(columnType, \"unsigned\");\n        }\n\n        public boolean isNullable() {\n            return nullable;\n        }\n\n        public boolean isKey() {\n            return key;\n        }\n\n        public void setKey(boolean key) {\n            this.key = key;\n        }\n\n        public String getExtra() {\n            return extra;\n        }\n\n        public void setExtra(String extra) {\n            this.extra = extra;\n        }\n\n        public boolean isUnique() {\n            return unique;\n        }\n\n        public void setUnique(boolean unique) {\n            this.unique = unique;\n        }\n\n        @Override\n        public String toString() {\n            return \"FieldMeta [columnName=\" + columnName + \", columnType=\" + columnType + \", nullable=\" + nullable\n                   + \", key=\" + key + \", defaultValue=\" + defaultValue + \", extra=\" + extra + \", unique=\" + unique\n                   + \"]\";\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/group/GroupEventParser.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.group;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport com.alibaba.otter.canal.common.AbstractCanalLifeCycle;\nimport com.alibaba.otter.canal.parse.CanalEventParser;\n\n/**\n * 组合多个EventParser进行合并处理，group只是做为一个delegate处理\n * \n * @author jianghang 2012-10-16 上午11:23:14\n * @version 1.0.0\n */\npublic class GroupEventParser extends AbstractCanalLifeCycle implements CanalEventParser {\n\n    private List<CanalEventParser> eventParsers = new ArrayList<>();\n\n    public void start() {\n        super.start();\n        // 统一启动\n        for (CanalEventParser eventParser : eventParsers) {\n            if (!eventParser.isStart()) {\n                eventParser.start();\n            }\n        }\n    }\n\n    public void stop() {\n        super.stop();\n        // 统一关闭\n        for (CanalEventParser eventParser : eventParsers) {\n            if (eventParser.isStart()) {\n                eventParser.stop();\n            }\n        }\n    }\n\n    public void setEventParsers(List<CanalEventParser> eventParsers) {\n        this.eventParsers = eventParsers;\n    }\n\n    public void addEventParser(CanalEventParser eventParser) {\n        if (!eventParsers.contains(eventParser)) {\n            eventParsers.add(eventParser);\n        }\n    }\n\n    public void removeEventParser(CanalEventParser eventParser) {\n        eventParsers.remove(eventParser);\n    }\n\n    public List<CanalEventParser> getEventParsers() {\n        return eventParsers;\n    }\n\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/AbstractMysqlEventParser.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql;\n\nimport java.nio.charset.Charset;\nimport java.util.Properties;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport com.alibaba.otter.canal.filter.CanalEventFilter;\nimport com.alibaba.otter.canal.filter.aviater.AviaterRegexFilter;\nimport com.alibaba.otter.canal.parse.CanalEventParser;\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\nimport com.alibaba.otter.canal.parse.inbound.AbstractEventParser;\nimport com.alibaba.otter.canal.parse.inbound.BinlogParser;\nimport com.alibaba.otter.canal.parse.inbound.MultiStageCoprocessor;\nimport com.alibaba.otter.canal.parse.inbound.mysql.dbsync.LogEventConvert;\nimport com.alibaba.otter.canal.parse.inbound.mysql.tsdb.DatabaseTableMeta;\nimport com.alibaba.otter.canal.parse.inbound.mysql.tsdb.DefaultTableMetaTSDBFactory;\nimport com.alibaba.otter.canal.parse.inbound.mysql.tsdb.TableMetaTSDB;\nimport com.alibaba.otter.canal.parse.inbound.mysql.tsdb.TableMetaTSDBFactory;\nimport com.alibaba.otter.canal.protocol.position.EntryPosition;\n\npublic abstract class AbstractMysqlEventParser extends AbstractEventParser {\n\n    protected static final long    BINLOG_START_OFFEST       = 4L;\n\n    protected TableMetaTSDBFactory tableMetaTSDBFactory      = new DefaultTableMetaTSDBFactory();\n    protected boolean              enableTsdb                = false;\n    protected String               tsdbJdbcUrl;\n    protected String               tsdbJdbcUserName;\n    protected String               tsdbJdbcPassword;\n    protected int                  tsdbSnapshotInterval      = 24;\n    protected int                  tsdbSnapshotExpire        = 360;\n    protected String               tsdbSpringXml;\n    protected TableMetaTSDB        tableMetaTSDB;\n\n    // 编码信息\n    protected Charset              connectionCharset         = Charset.forName(\"UTF-8\");\n    protected boolean              filterQueryDcl            = false;\n    protected boolean              filterQueryDml            = false;\n    protected boolean              filterQueryDdl            = false;\n    protected boolean              filterRows                = false;\n    protected boolean              filterTableError          = false;\n    protected boolean              useDruidDdlFilter         = true;\n\n    protected boolean              filterDmlInsert           = false;\n    protected boolean              filterDmlUpdate           = false;\n    protected boolean              filterDmlDelete           = false;\n    // instance received binlog bytes\n    protected final AtomicLong     receivedBinlogBytes       = new AtomicLong(0L);\n    private final AtomicLong       eventsPublishBlockingTime = new AtomicLong(0L);\n\n    protected BinlogParser buildParser() {\n        LogEventConvert convert = new LogEventConvert();\n        if (eventFilter != null && eventFilter instanceof AviaterRegexFilter) {\n            convert.setNameFilter((AviaterRegexFilter) eventFilter);\n        }\n\n        if (eventBlackFilter != null && eventBlackFilter instanceof AviaterRegexFilter) {\n            convert.setNameBlackFilter((AviaterRegexFilter) eventBlackFilter);\n        }\n\n        convert.setFieldFilterMap(getFieldFilterMap());\n        convert.setFieldBlackFilterMap(getFieldBlackFilterMap());\n\n        convert.setCharset(connectionCharset);\n        convert.setFilterQueryDcl(filterQueryDcl);\n        convert.setFilterQueryDml(filterQueryDml);\n        convert.setFilterQueryDdl(filterQueryDdl);\n        convert.setFilterRows(filterRows);\n        convert.setFilterTableError(filterTableError);\n        convert.setUseDruidDdlFilter(useDruidDdlFilter);\n        return convert;\n    }\n\n    public void setEventFilter(CanalEventFilter eventFilter) {\n        super.setEventFilter(eventFilter);\n\n        // 触发一下filter变更\n        if (eventFilter != null && eventFilter instanceof AviaterRegexFilter) {\n            if (binlogParser instanceof LogEventConvert) {\n                ((LogEventConvert) binlogParser).setNameFilter((AviaterRegexFilter) eventFilter);\n            }\n\n            if (tableMetaTSDB != null && tableMetaTSDB instanceof DatabaseTableMeta) {\n                ((DatabaseTableMeta) tableMetaTSDB).setFilter(eventFilter);\n            }\n        }\n    }\n\n    public void setEventBlackFilter(CanalEventFilter eventBlackFilter) {\n        super.setEventBlackFilter(eventBlackFilter);\n\n        // 触发一下filter变更\n        if (eventBlackFilter != null && eventBlackFilter instanceof AviaterRegexFilter) {\n            if (binlogParser instanceof LogEventConvert) {\n                ((LogEventConvert) binlogParser).setNameBlackFilter((AviaterRegexFilter) eventBlackFilter);\n            }\n\n            if (tableMetaTSDB != null && tableMetaTSDB instanceof DatabaseTableMeta) {\n                ((DatabaseTableMeta) tableMetaTSDB).setBlackFilter(eventBlackFilter);\n            }\n        }\n    }\n\n    @Override\n    public void setFieldFilter(String fieldFilter) {\n        super.setFieldFilter(fieldFilter);\n\n        // 触发一下filter变更\n        if (binlogParser instanceof LogEventConvert) {\n            ((LogEventConvert) binlogParser).setFieldFilterMap(getFieldFilterMap());\n        }\n\n        if (tableMetaTSDB != null && tableMetaTSDB instanceof DatabaseTableMeta) {\n            ((DatabaseTableMeta) tableMetaTSDB).setFieldFilterMap(getFieldFilterMap());\n        }\n    }\n\n    @Override\n    public void setFieldBlackFilter(String fieldBlackFilter) {\n        super.setFieldBlackFilter(fieldBlackFilter);\n\n        // 触发一下filter变更\n        if (binlogParser instanceof LogEventConvert) {\n            ((LogEventConvert) binlogParser).setFieldBlackFilterMap(getFieldBlackFilterMap());\n        }\n\n        if (tableMetaTSDB != null && tableMetaTSDB instanceof DatabaseTableMeta) {\n            ((DatabaseTableMeta) tableMetaTSDB).setFieldBlackFilterMap(getFieldBlackFilterMap());\n        }\n    }\n\n    /**\n     * 回滚到指定位点\n     * \n     * @param position\n     * @return\n     */\n    protected boolean processTableMeta(EntryPosition position) {\n        if (tableMetaTSDB != null) {\n            if (position.getTimestamp() == null || position.getTimestamp() <= 0) {\n                throw new CanalParseException(\"use gtid and TableMeta TSDB should be config timestamp > 0\");\n            }\n\n            return tableMetaTSDB.rollback(position);\n        }\n\n        return true;\n    }\n\n    public void start() throws CanalParseException {\n        if (enableTsdb) {\n            if (tableMetaTSDB == null) {\n                synchronized (CanalEventParser.class) {\n                    buildTableMetaTSDB(tsdbSpringXml);\n                }\n            }\n        }\n\n        super.start();\n    }\n\n    public void stop() throws CanalParseException {\n        if (enableTsdb) {\n            tableMetaTSDBFactory.destory(destination);\n            tableMetaTSDB = null;\n        }\n\n        super.stop();\n    }\n\n    protected synchronized void buildTableMetaTSDB(String tsdbSpringXml) {\n        if (tableMetaTSDB != null) {\n            return;\n        }\n\n        try {\n            // 设置当前正在加载的通道，加载spring查找文件时会用到该变量\n            System.setProperty(\"canal.instance.tsdb.url\", tsdbJdbcUrl);\n            System.setProperty(\"canal.instance.tsdb.dbUsername\", tsdbJdbcUserName);\n            System.setProperty(\"canal.instance.tsdb.dbPassword\", tsdbJdbcPassword);\n            // 初始化\n            this.tableMetaTSDB = tableMetaTSDBFactory.build(destination, tsdbSpringXml);\n        } catch (Throwable e) {\n            logger.warn(\"failed to build TableMetaTSDB \",e);\n            throw new CanalParseException(e);\n        } finally {\n            // reset\n            Properties props = System.getProperties();\n            props.remove(\"canal.instance.tsdb.url\");\n            props.remove(\"canal.instance.tsdb.dbUsername\");\n            props.remove(\"canal.instance.tsdb.dbPassword\");\n        }\n    }\n\n    protected MultiStageCoprocessor buildMultiStageCoprocessor() {\n        MysqlMultiStageCoprocessor mysqlMultiStageCoprocessor = new MysqlMultiStageCoprocessor(parallelBufferSize,\n            parallelThreadSize,\n            (LogEventConvert) binlogParser,\n            transactionBuffer,\n            destination, filterDmlInsert, filterDmlUpdate, filterDmlDelete);\n        mysqlMultiStageCoprocessor.setEventsPublishBlockingTime(eventsPublishBlockingTime);\n        return mysqlMultiStageCoprocessor;\n    }\n\n    // ============================ setter / getter =========================\n\n    public void setConnectionCharsetStd(Charset connectionCharset) {\n        this.connectionCharset = connectionCharset;\n    }\n\n    public void setConnectionCharset(String connectionCharset) {\n        if (\"UTF8MB4\".equalsIgnoreCase(connectionCharset)) {\n            connectionCharset = \"UTF-8\";\n        }\n\n        this.connectionCharset = Charset.forName(connectionCharset);\n    }\n\n    public void setFilterQueryDcl(boolean filterQueryDcl) {\n        this.filterQueryDcl = filterQueryDcl;\n    }\n\n    public void setFilterQueryDml(boolean filterQueryDml) {\n        this.filterQueryDml = filterQueryDml;\n    }\n\n    public void setFilterQueryDdl(boolean filterQueryDdl) {\n        this.filterQueryDdl = filterQueryDdl;\n    }\n\n    public void setFilterRows(boolean filterRows) {\n        this.filterRows = filterRows;\n    }\n\n    public void setFilterTableError(boolean filterTableError) {\n        this.filterTableError = filterTableError;\n    }\n\n    public boolean isUseDruidDdlFilter() {\n        return useDruidDdlFilter;\n    }\n\n    public void setUseDruidDdlFilter(boolean useDruidDdlFilter) {\n        this.useDruidDdlFilter = useDruidDdlFilter;\n    }\n\n    public boolean isFilterDmlInsert() {\n        return filterDmlInsert;\n    }\n\n    public void setFilterDmlInsert(boolean filterDmlInsert) {\n        this.filterDmlInsert = filterDmlInsert;\n    }\n\n    public boolean isFilterDmlUpdate() {\n        return filterDmlUpdate;\n    }\n\n    public void setFilterDmlUpdate(boolean filterDmlUpdate) {\n        this.filterDmlUpdate = filterDmlUpdate;\n    }\n\n    public boolean isFilterDmlDelete() {\n        return filterDmlDelete;\n    }\n\n    public void setFilterDmlDelete(boolean filterDmlDelete) {\n        this.filterDmlDelete = filterDmlDelete;\n    }\n\n    public void setEnableTsdb(boolean enableTsdb) {\n        this.enableTsdb = enableTsdb;\n    }\n\n    public void setTsdbSpringXml(String tsdbSpringXml) {\n        this.tsdbSpringXml = tsdbSpringXml;\n    }\n\n    public void setTableMetaTSDBFactory(TableMetaTSDBFactory tableMetaTSDBFactory) {\n        this.tableMetaTSDBFactory = tableMetaTSDBFactory;\n    }\n\n    public AtomicLong getEventsPublishBlockingTime() {\n        return this.eventsPublishBlockingTime;\n    }\n\n    public AtomicLong getReceivedBinlogBytes() {\n        return this.receivedBinlogBytes;\n    }\n\n    public int getTsdbSnapshotInterval() {\n        return tsdbSnapshotInterval;\n    }\n\n    public void setTsdbSnapshotInterval(int tsdbSnapshotInterval) {\n        this.tsdbSnapshotInterval = tsdbSnapshotInterval;\n    }\n\n    public int getTsdbSnapshotExpire() {\n        return tsdbSnapshotExpire;\n    }\n\n    public void setTsdbSnapshotExpire(int tsdbSnapshotExpire) {\n        this.tsdbSnapshotExpire = tsdbSnapshotExpire;\n    }\n\n    public void setTsdbJdbcUrl(String tsdbJdbcUrl) {\n        this.tsdbJdbcUrl = tsdbJdbcUrl;\n    }\n\n    public void setTsdbJdbcUserName(String tsdbJdbcUserName) {\n        this.tsdbJdbcUserName = tsdbJdbcUserName;\n    }\n\n    public void setTsdbJdbcPassword(String tsdbJdbcPassword) {\n        this.tsdbJdbcPassword = tsdbJdbcPassword;\n    }\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/DbsyncMysqlEventParser.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql;\n\npublic class DbsyncMysqlEventParser {\n\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/LocalBinLogConnection.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql;\r\n\r\nimport java.io.File;\r\nimport java.io.IOException;\r\nimport java.util.HashSet;\r\nimport java.util.List;\r\nimport java.util.Set;\r\n\r\nimport org.apache.commons.lang.NotImplementedException;\r\nimport org.apache.commons.lang.StringUtils;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\n\r\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.GTIDSet;\r\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\r\nimport com.alibaba.otter.canal.parse.exception.ServerIdNotMatchException;\r\nimport com.alibaba.otter.canal.parse.inbound.ErosaConnection;\r\nimport com.alibaba.otter.canal.parse.inbound.MultiStageCoprocessor;\r\nimport com.alibaba.otter.canal.parse.inbound.SinkFunction;\r\nimport com.alibaba.otter.canal.parse.inbound.mysql.local.BinLogFileQueue;\r\nimport com.taobao.tddl.dbsync.binlog.*;\r\nimport com.taobao.tddl.dbsync.binlog.event.QueryLogEvent;\r\n\r\n/**\r\n * local bin log connection (not real connection)\r\n *\r\n * @author yuanzu Date: 12-9-27 Time: 下午6:14\r\n */\r\npublic class LocalBinLogConnection implements ErosaConnection {\r\n\r\n    private static final Logger logger                       = LoggerFactory.getLogger(LocalBinLogConnection.class);\r\n    /** rdsOosMode 主从信息 */\r\n    private final Set<Long>     rdsOssMasterSlaveInfo        = new HashSet<>(4);\r\n    private BinLogFileQueue     binlogs                      = null;\r\n    private boolean             needWait;\r\n    private String              directory;\r\n    private int                 bufferSize                   = 16 * 1024;\r\n    private boolean             running                      = false;\r\n    private long                serverId;\r\n    /** rdsOosMode binlog 的 serverId 是两个 */\r\n    private boolean             isRdsOssMode                 = false;\r\n    private boolean             firstUpdateRdsOssMasterSlave = true;\r\n\r\n    private FileParserListener  parserListener;\r\n\r\n    public LocalBinLogConnection(){\r\n    }\r\n\r\n    public LocalBinLogConnection(String directory, boolean needWait){\r\n        this.needWait = needWait;\r\n        this.directory = directory;\r\n    }\r\n\r\n    public boolean isRdsOssMode() {\r\n        return isRdsOssMode;\r\n    }\r\n\r\n    public void setRdsOssMode(boolean rdsOssMode) {\r\n        isRdsOssMode = rdsOssMode;\r\n    }\r\n\r\n    @Override\r\n    public void connect() throws IOException {\r\n        if (this.binlogs == null) {\r\n            this.binlogs = new BinLogFileQueue(this.directory);\r\n        }\r\n        this.running = true;\r\n    }\r\n\r\n    @Override\r\n    public void reconnect() throws IOException {\r\n        disconnect();\r\n        connect();\r\n    }\r\n\r\n    @Override\r\n    public void disconnect() throws IOException {\r\n        this.running = false;\r\n        if (this.binlogs != null) {\r\n            this.binlogs.destory();\r\n        }\r\n        this.binlogs = null;\r\n        this.running = false;\r\n    }\r\n\r\n    public boolean isConnected() {\r\n        return running;\r\n    }\r\n\r\n    public void seek(String binlogfilename, Long binlogPosition, String gtid, SinkFunction func) throws IOException {\r\n    }\r\n\r\n    public void dump(String binlogfilename, Long binlogPosition, SinkFunction func) throws IOException {\r\n        File current = new File(directory, binlogfilename);\r\n\r\n        try (FileLogFetcher fetcher = new FileLogFetcher(bufferSize)) {\r\n            LogDecoder decoder = new LogDecoder(LogEvent.UNKNOWN_EVENT, LogEvent.ENUM_END_EVENT);\r\n            LogContext context = new LogContext();\r\n            fetcher.open(current, binlogPosition);\r\n            context.setLogPosition(new LogPosition(binlogfilename, binlogPosition));\r\n            while (running) {\r\n                boolean needContinue = true;\r\n                LogEvent event = null;\r\n                while (fetcher.fetch()) {\r\n                    event = decoder.decode(fetcher, context);\r\n                    if (event == null) {\r\n                        continue;\r\n                    }\r\n                    checkServerId(event);\r\n                    List<LogEvent> iterateEvents = decoder.processIterateDecode(event, context);\r\n                    if (!iterateEvents.isEmpty()) {\r\n                        // 处理compress event\r\n                        for (LogEvent itEvent : iterateEvents) {\r\n                            if (!func.sink(itEvent)) {\r\n                                needContinue = false;\r\n                                break;\r\n                            }\r\n                        }\r\n                    } else {\r\n                        if (!func.sink(event)) {\r\n                            needContinue = false;\r\n                            break;\r\n                        }\r\n                    }\r\n                }\r\n\r\n                fetcher.close(); // 关闭上一个文件\r\n                parserFinish(current.getName());\r\n                if (needContinue) {// 读取下一个\r\n                    File nextFile;\r\n                    if (needWait) {\r\n                        nextFile = binlogs.waitForNextFile(current);\r\n                    } else {\r\n                        nextFile = binlogs.getNextFile(current);\r\n                    }\r\n\r\n                    if (nextFile == null) {\r\n                        break;\r\n                    }\r\n\r\n                    current = nextFile;\r\n                    fetcher.open(current);\r\n                    context.setLogPosition(new LogPosition(nextFile.getName()));\r\n                } else {\r\n                    break;// 跳出\r\n                }\r\n            }\r\n        } catch (InterruptedException e) {\r\n            logger.warn(\"LocalBinLogConnection dump interrupted\");\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 1. 非 rdsOos 模式下需要要校验 serverId 是否一致 防止解析其他实例的 binlog <br/>\r\n     * 2. rdsOos 高可用模式下解析 binlog\r\n     * 会有两个 serverId,分别对应着主从节点 binlog解析出来的 serverId 主从的关系可能会变, 但是 serverId一直都会是这两个\r\n     * serverId\r\n     *\r\n     * @param event\r\n     */\r\n    private void checkServerId(LogEvent event) {\r\n        if (serverId != 0 && event.getServerId() != serverId) {\r\n            if (isRdsOssMode()) {\r\n                // 第一次添加主从信息\r\n                if (firstUpdateRdsOssMasterSlave) {\r\n                    firstUpdateRdsOssMasterSlave = false;\r\n                    rdsOssMasterSlaveInfo.add(event.getServerId());\r\n                } else if (!rdsOssMasterSlaveInfo.contains(event.getServerId())) {\r\n                    // 主从节点信息之外的节点信息\r\n                    throw new ServerIdNotMatchException(\"unexpected rds serverId \" + serverId + \" in binlog file !\");\r\n                }\r\n            } else {\r\n                throw new ServerIdNotMatchException(\"unexpected serverId \" + serverId + \" in binlog file !\");\r\n            }\r\n        }\r\n    }\r\n\r\n    public void dump(long timestampMills, SinkFunction func) throws IOException {\r\n        List<File> currentBinlogs = binlogs.currentBinlogs();\r\n        File current = currentBinlogs.get(currentBinlogs.size() - 1);\r\n        long timestampSeconds = timestampMills / 1000;\r\n\r\n        String binlogFilename = null;\r\n        long binlogFileOffset = 0;\r\n\r\n        FileLogFetcher fetcher = new FileLogFetcher(bufferSize);\r\n        LogDecoder decoder = new LogDecoder();\r\n        decoder.handle(LogEvent.FORMAT_DESCRIPTION_EVENT);\r\n        decoder.handle(LogEvent.QUERY_EVENT);\r\n        decoder.handle(LogEvent.XID_EVENT);\r\n        LogContext context = new LogContext();\r\n        try {\r\n            fetcher.open(current);\r\n            context.setLogPosition(new LogPosition(current.getName()));\r\n            while (running) {\r\n                boolean needContinue = true;\r\n                String lastXidLogFilename = current.getName();\r\n                long lastXidLogFileOffset = 0;\r\n\r\n                binlogFilename = lastXidLogFilename;\r\n                binlogFileOffset = lastXidLogFileOffset;\r\n                while (fetcher.fetch()) {\r\n                    LogEvent event = decoder.decode(fetcher, context);\r\n                    if (event != null) {\r\n                        checkServerId(event);\r\n\r\n                        // 闭区间，防止丢开始那一秒的数据\r\n                        if (event.getWhen() >= timestampSeconds) {\r\n                            break;\r\n                        }\r\n\r\n                        needContinue = false;\r\n                        if (LogEvent.QUERY_EVENT == event.getHeader().getType()) {\r\n                            if (StringUtils.endsWithIgnoreCase(((QueryLogEvent) event).getQuery(), \"BEGIN\")) {\r\n                                binlogFilename = lastXidLogFilename;\r\n                                binlogFileOffset = lastXidLogFileOffset;\r\n                            } else if (StringUtils.endsWithIgnoreCase(((QueryLogEvent) event).getQuery(), \"COMMIT\")) {\r\n                                lastXidLogFilename = current.getName();\r\n                                lastXidLogFileOffset = event.getLogPos();\r\n                            }\r\n                        } else if (LogEvent.XID_EVENT == event.getHeader().getType()) {\r\n                            lastXidLogFilename = current.getName();\r\n                            lastXidLogFileOffset = event.getLogPos();\r\n                        } else if (LogEvent.FORMAT_DESCRIPTION_EVENT == event.getHeader().getType()) {\r\n                            lastXidLogFilename = current.getName();\r\n                            lastXidLogFileOffset = event.getLogPos();\r\n                        }\r\n                    }\r\n                }\r\n\r\n                if (needContinue) {// 读取下一个\r\n                    fetcher.close(); // 关闭上一个文件\r\n\r\n                    File nextFile = binlogs.getBefore(current);\r\n                    if (nextFile == null) {\r\n                        break;\r\n                    }\r\n\r\n                    current = nextFile;\r\n                    fetcher.open(current);\r\n                    context.setLogPosition(new LogPosition(current.getName()));\r\n                } else {\r\n                    break;// 跳出\r\n                }\r\n            }\r\n        } finally {\r\n            if (fetcher != null) {\r\n                fetcher.close();\r\n            }\r\n        }\r\n\r\n        dump(binlogFilename, binlogFileOffset, func);\r\n    }\r\n\r\n    @Override\r\n    public void dump(GTIDSet gtidSet, SinkFunction func) throws IOException {\r\n        throw new NotImplementedException();\r\n    }\r\n\r\n    @Override\r\n    public void dump(String binlogfilename, Long binlogPosition, MultiStageCoprocessor coprocessor) throws IOException {\r\n        File current = new File(directory, binlogfilename);\r\n        if (!current.exists()) {\r\n            throw new CanalParseException(\"binlog:\" + binlogfilename + \" is not found\");\r\n        }\r\n\r\n        try (FileLogFetcher fetcher = new FileLogFetcher(bufferSize)) {\r\n            LogDecoder decoder = new LogDecoder(LogEvent.UNKNOWN_EVENT, LogEvent.ENUM_END_EVENT);\r\n            LogContext context = new LogContext();\r\n            fetcher.open(current, binlogPosition);\r\n            context.setLogPosition(new LogPosition(binlogfilename, binlogPosition));\r\n            while (running) {\r\n                boolean needContinue = true;\r\n                LogEvent event = null;\r\n                while (fetcher.fetch()) {\r\n                    event = decoder.decode(fetcher, context);\r\n                    if (event == null) {\r\n                        continue;\r\n                    }\r\n                    checkServerId(event);\r\n\r\n                    if (!coprocessor.publish(event)) {\r\n                        needContinue = false;\r\n                        break;\r\n                    }\r\n                }\r\n\r\n                fetcher.close(); // 关闭上一个文件\r\n                parserFinish(binlogfilename);\r\n                if (needContinue) {// 读取下一个\r\n                    File nextFile;\r\n                    if (needWait) {\r\n                        nextFile = binlogs.waitForNextFile(current);\r\n                    } else {\r\n                        nextFile = binlogs.getNextFile(current);\r\n                    }\r\n\r\n                    if (nextFile == null) {\r\n                        break;\r\n                    }\r\n\r\n                    current = nextFile;\r\n                    fetcher.open(current);\r\n                    binlogfilename = nextFile.getName();\r\n                } else {\r\n                    break;// 跳出\r\n                }\r\n            }\r\n        } catch (InterruptedException e) {\r\n            logger.warn(\"LocalBinLogConnection dump interrupted\");\r\n        }\r\n    }\r\n\r\n    private void parserFinish(String fileName) {\r\n        if (parserListener != null) {\r\n            parserListener.onFinish(fileName);\r\n        }\r\n    }\r\n\r\n    @Override\r\n    public void dump(long timestampMills, MultiStageCoprocessor coprocessor) throws IOException {\r\n        List<File> currentBinlogs = binlogs.currentBinlogs();\r\n        File current = currentBinlogs.get(currentBinlogs.size() - 1);\r\n        long timestampSeconds = timestampMills / 1000;\r\n\r\n        String binlogFilename = null;\r\n        long binlogFileOffset = 0;\r\n\r\n        FileLogFetcher fetcher = new FileLogFetcher(bufferSize);\r\n        LogDecoder decoder = new LogDecoder();\r\n        decoder.handle(LogEvent.FORMAT_DESCRIPTION_EVENT);\r\n        decoder.handle(LogEvent.QUERY_EVENT);\r\n        decoder.handle(LogEvent.XID_EVENT);\r\n        LogContext context = new LogContext();\r\n        try {\r\n            fetcher.open(current);\r\n            context.setLogPosition(new LogPosition(current.getName()));\r\n            while (running) {\r\n                boolean needContinue = true;\r\n                String lastXidLogFilename = current.getName();\r\n                long lastXidLogFileOffset = 0;\r\n\r\n                binlogFilename = lastXidLogFilename;\r\n                binlogFileOffset = lastXidLogFileOffset;\r\n                while (fetcher.fetch()) {\r\n                    LogEvent event = decoder.decode(fetcher, context);\r\n                    if (event != null) {\r\n                        checkServerId(event);\r\n\r\n                        if (event.getWhen() > timestampSeconds) {\r\n                            break;\r\n                        }\r\n\r\n                        needContinue = false;\r\n                        if (LogEvent.QUERY_EVENT == event.getHeader().getType()) {\r\n                            if (StringUtils.endsWithIgnoreCase(((QueryLogEvent) event).getQuery(), \"BEGIN\")) {\r\n                                binlogFilename = lastXidLogFilename;\r\n                                binlogFileOffset = lastXidLogFileOffset;\r\n                            } else if (StringUtils.endsWithIgnoreCase(((QueryLogEvent) event).getQuery(), \"COMMIT\")) {\r\n                                lastXidLogFilename = current.getName();\r\n                                lastXidLogFileOffset = event.getLogPos();\r\n                            }\r\n                        } else if (LogEvent.XID_EVENT == event.getHeader().getType()) {\r\n                            lastXidLogFilename = current.getName();\r\n                            lastXidLogFileOffset = event.getLogPos();\r\n                        } else if (LogEvent.FORMAT_DESCRIPTION_EVENT == event.getHeader().getType()) {\r\n                            lastXidLogFilename = current.getName();\r\n                            lastXidLogFileOffset = event.getLogPos();\r\n                        }\r\n                    }\r\n                }\r\n\r\n                if (needContinue) {// 读取下一个\r\n                    fetcher.close(); // 关闭上一个文件\r\n\r\n                    File nextFile = binlogs.getBefore(current);\r\n                    if (nextFile == null) {\r\n                        break;\r\n                    }\r\n\r\n                    current = nextFile;\r\n                    fetcher.open(current);\r\n                    context.setLogPosition(new LogPosition(current.getName()));\r\n                } else {\r\n                    break;// 跳出\r\n                }\r\n            }\r\n        } finally {\r\n            if (fetcher != null) {\r\n                fetcher.close();\r\n            }\r\n        }\r\n\r\n        dump(binlogFilename, binlogFileOffset, coprocessor);\r\n    }\r\n\r\n    @Override\r\n    public void dump(GTIDSet gtidSet, MultiStageCoprocessor coprocessor) throws IOException {\r\n        throw new NotImplementedException();\r\n    }\r\n\r\n    public ErosaConnection fork() {\r\n        LocalBinLogConnection connection = new LocalBinLogConnection();\r\n\r\n        connection.setBufferSize(this.bufferSize);\r\n        connection.setDirectory(this.directory);\r\n        connection.setNeedWait(this.needWait);\r\n        return connection;\r\n    }\r\n\r\n    @Override\r\n    public long queryServerId() {\r\n        return 0;\r\n    }\r\n\r\n    public boolean isNeedWait() {\r\n        return needWait;\r\n    }\r\n\r\n    public void setNeedWait(boolean needWait) {\r\n        this.needWait = needWait;\r\n    }\r\n\r\n    public String getDirectory() {\r\n        return directory;\r\n    }\r\n\r\n    public void setDirectory(String directory) {\r\n        this.directory = directory;\r\n    }\r\n\r\n    public int getBufferSize() {\r\n        return bufferSize;\r\n    }\r\n\r\n    public void setBufferSize(int bufferSize) {\r\n        this.bufferSize = bufferSize;\r\n    }\r\n\r\n    public long getServerId() {\r\n        return serverId;\r\n    }\r\n\r\n    public void setServerId(long serverId) {\r\n        this.serverId = serverId;\r\n        rdsOssMasterSlaveInfo.add(serverId);\r\n    }\r\n\r\n    public void setParserListener(FileParserListener parserListener) {\r\n        this.parserListener = parserListener;\r\n    }\r\n\r\n    public interface FileParserListener {\r\n\r\n        void onFinish(String fileName);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/LocalBinlogEventParser.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql;\n\nimport java.io.IOException;\n\nimport org.apache.commons.lang.StringUtils;\n\nimport com.alibaba.otter.canal.parse.CanalEventParser;\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\nimport com.alibaba.otter.canal.parse.inbound.ErosaConnection;\nimport com.alibaba.otter.canal.parse.inbound.mysql.dbsync.LogEventConvert;\nimport com.alibaba.otter.canal.parse.inbound.mysql.dbsync.TableMetaCache;\nimport com.alibaba.otter.canal.parse.inbound.mysql.tsdb.DatabaseTableMeta;\nimport com.alibaba.otter.canal.parse.index.CanalLogPositionManager;\nimport com.alibaba.otter.canal.parse.support.AuthenticationInfo;\nimport com.alibaba.otter.canal.protocol.position.EntryPosition;\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\n\n/**\n * 基于本地binlog文件的复制\n * \n * @author jianghang 2012-6-21 下午04:07:33\n * @version 1.0.0\n */\npublic class LocalBinlogEventParser extends AbstractMysqlEventParser implements CanalEventParser {\n\n    // 数据库信息\n    protected AuthenticationInfo masterInfo;\n    protected EntryPosition      masterPosition;        // binlog信息\n    protected MysqlConnection    metaConnection;        // 查询meta信息的链接\n    protected TableMetaCache     tableMetaCache;        // 对应meta\n\n    protected String             directory;\n    protected boolean            needWait   = false;\n    protected int                bufferSize = 16 * 1024;\n\n    public LocalBinlogEventParser(){\n        // this.runningInfo = new AuthenticationInfo();\n    }\n\n    @Override\n    protected ErosaConnection buildErosaConnection() {\n        return buildLocalBinLogConnection();\n    }\n\n    @Override\n    protected void preDump(ErosaConnection connection) {\n        metaConnection = buildMysqlConnection();\n        try {\n            metaConnection.connect();\n        } catch (IOException e) {\n            throw new CanalParseException(e);\n        }\n\n        if (tableMetaTSDB != null && tableMetaTSDB instanceof DatabaseTableMeta) {\n            ((DatabaseTableMeta) tableMetaTSDB).setConnection(metaConnection);\n            ((DatabaseTableMeta) tableMetaTSDB).setFilter(eventFilter);\n            ((DatabaseTableMeta) tableMetaTSDB).setBlackFilter(eventBlackFilter);\n            ((DatabaseTableMeta) tableMetaTSDB).setSnapshotInterval(tsdbSnapshotInterval);\n            ((DatabaseTableMeta) tableMetaTSDB).setSnapshotExpire(tsdbSnapshotExpire);\n            ((DatabaseTableMeta) tableMetaTSDB).init(destination);\n        }\n\n        tableMetaCache = new TableMetaCache(metaConnection, tableMetaTSDB);\n        ((LogEventConvert) binlogParser).setTableMetaCache(tableMetaCache);\n    }\n\n    @Override\n    protected void afterDump(ErosaConnection connection) {\n        if (metaConnection != null) {\n            try {\n                metaConnection.disconnect();\n            } catch (IOException e) {\n                logger.error(\"ERROR # disconnect meta connection for address:{}\", metaConnection.getConnector()\n                    .getAddress(), e);\n            }\n        }\n    }\n\n    public void start() throws CanalParseException {\n        if (runningInfo == null) { // 第一次链接主库\n            runningInfo = masterInfo;\n        }\n\n        super.start();\n    }\n\n    @Override\n    public void stop() {\n        if (metaConnection != null) {\n            try {\n                metaConnection.disconnect();\n            } catch (IOException e) {\n                logger.error(\"ERROR # disconnect meta connection for address:{}\", metaConnection.getConnector()\n                    .getAddress(), e);\n            }\n        }\n\n        if (tableMetaCache != null) {\n            tableMetaCache.clearTableMeta();\n        }\n\n        super.stop();\n    }\n\n    private ErosaConnection buildLocalBinLogConnection() {\n        LocalBinLogConnection connection = new LocalBinLogConnection();\n\n        connection.setBufferSize(this.bufferSize);\n        connection.setDirectory(this.directory);\n        connection.setNeedWait(this.needWait);\n\n        return connection;\n    }\n\n    private MysqlConnection buildMysqlConnection() {\n        MysqlConnection connection = new MysqlConnection(runningInfo.getAddress(),\n            runningInfo.getUsername(),\n            runningInfo.getPassword(),\n            runningInfo.getDefaultDatabaseName());\n        connection.getConnector().setReceiveBufferSize(64 * 1024);\n        connection.getConnector().setSendBufferSize(64 * 1024);\n        connection.getConnector().setSoTimeout(30 * 1000);\n        connection.setCharset(connectionCharset);\n        return connection;\n    }\n\n    @Override\n    protected EntryPosition findStartPosition(ErosaConnection connection) {\n        // 处理逻辑\n        // 1. 首先查询上一次解析成功的最后一条记录\n        // 2. 存在最后一条记录，判断一下当前记录是否发生过主备切换\n        // // a. 无机器切换，直接返回\n        // // b. 存在机器切换，按最后一条记录的stamptime进行查找\n        // 3. 不存在最后一条记录，则从默认的位置开始启动\n        LogPosition logPosition = logPositionManager.getLatestIndexBy(destination);\n        if (logPosition == null) {// 找不到历史成功记录\n            EntryPosition entryPosition = masterPosition;\n\n            // 判断一下是否需要按时间订阅\n            if (StringUtils.isEmpty(entryPosition.getJournalName())) {\n                // 如果没有指定binlogName，尝试按照timestamp进行查找\n                if (entryPosition.getTimestamp() != null) {\n                    return new EntryPosition(entryPosition.getTimestamp());\n                }\n            } else {\n                if (entryPosition.getPosition() != null) {\n                    // 如果指定binlogName + offest，直接返回\n                    return entryPosition;\n                } else {\n                    return new EntryPosition(entryPosition.getTimestamp());\n                }\n            }\n        } else {\n            return logPosition.getPostion();\n        }\n\n        return null;\n    }\n\n    // ========================= setter / getter =========================\n\n    public void setLogPositionManager(CanalLogPositionManager logPositionManager) {\n        this.logPositionManager = logPositionManager;\n    }\n\n    public void setDirectory(String directory) {\n        this.directory = directory;\n    }\n\n    public void setBufferSize(int bufferSize) {\n        this.bufferSize = bufferSize;\n    }\n\n    public void setMasterPosition(EntryPosition masterPosition) {\n        this.masterPosition = masterPosition;\n    }\n\n    public void setMasterInfo(AuthenticationInfo masterInfo) {\n        this.masterInfo = masterInfo;\n    }\n\n    public boolean isNeedWait() {\n        return needWait;\n    }\n\n    public void setNeedWait(boolean needWait) {\n        this.needWait = needWait;\n    }\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/MysqlConnection.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql;\n\nimport static com.alibaba.otter.canal.parse.driver.mysql.utils.GtidUtil.parseGtidSet;\nimport static com.alibaba.otter.canal.parse.inbound.mysql.dbsync.DirectLogFetcher.MASTER_HEARTBEAT_PERIOD_SECONDS;\n\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.net.SocketAddress;\nimport java.nio.charset.Charset;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.commons.lang.math.NumberUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.MysqlConnector;\nimport com.alibaba.otter.canal.parse.driver.mysql.MysqlQueryExecutor;\nimport com.alibaba.otter.canal.parse.driver.mysql.MysqlUpdateExecutor;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.GTIDSet;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.HeaderPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.client.BinlogDumpCommandPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.client.BinlogDumpGTIDCommandPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.client.RegisterSlaveCommandPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.client.SemiAckCommandPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.server.ErrorPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.server.ResultSetPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.ssl.SslInfo;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.PacketManager;\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\nimport com.alibaba.otter.canal.parse.inbound.ErosaConnection;\nimport com.alibaba.otter.canal.parse.inbound.MultiStageCoprocessor;\nimport com.alibaba.otter.canal.parse.inbound.SinkFunction;\nimport com.alibaba.otter.canal.parse.inbound.mysql.dbsync.DirectLogFetcher;\nimport com.alibaba.otter.canal.parse.support.AuthenticationInfo;\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.LogContext;\nimport com.taobao.tddl.dbsync.binlog.LogDecoder;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.FormatDescriptionLogEvent;\n\npublic class MysqlConnection implements ErosaConnection {\n\n    private static final Logger logger             = LoggerFactory.getLogger(MysqlConnection.class);\n\n    private MysqlConnector      connector;\n    private long                slaveId;\n    private Charset             charset            = Charset.forName(\"UTF-8\");\n    private BinlogFormat        binlogFormat;\n    private BinlogImage         binlogImage;\n\n    // tsdb releated\n    private AuthenticationInfo  authInfo;\n    protected int               connTimeout        = 5 * 1000;                                      // 5秒\n    protected int               soTimeout          = 60 * 60 * 1000;                                // 1小时\n    private int                 binlogChecksum     = LogEvent.BINLOG_CHECKSUM_ALG_OFF;\n    // dump binlog bytes, 暂不包括meta与TSDB\n    private AtomicLong          receivedBinlogBytes;\n    private boolean             compatiablePercona = false;\n\n    public MysqlConnection(){\n    }\n\n    public MysqlConnection(InetSocketAddress address, String username, String password){\n        authInfo = new AuthenticationInfo();\n        authInfo.setAddress(address);\n        authInfo.setUsername(username);\n        authInfo.setPassword(password);\n        connector = new MysqlConnector(address, username, password);\n        // 将connection里面的参数透传下\n        connector.setSoTimeout(soTimeout);\n        connector.setConnTimeout(connTimeout);\n    }\n\n    public MysqlConnection(InetSocketAddress address, String username, String password, String defaultSchema){\n        authInfo = new AuthenticationInfo();\n        authInfo.setAddress(address);\n        authInfo.setUsername(username);\n        authInfo.setPassword(password);\n        authInfo.setDefaultDatabaseName(defaultSchema);\n        connector = new MysqlConnector(address, username, password, defaultSchema);\n        // 将connection里面的参数透传下\n        connector.setSoTimeout(soTimeout);\n        connector.setConnTimeout(connTimeout);\n    }\n\n    public MysqlConnection(InetSocketAddress address, String username, String password, String defaultSchema,\n                           SslInfo sslInfo){\n        authInfo = new AuthenticationInfo();\n        authInfo.setAddress(address);\n        authInfo.setUsername(username);\n        authInfo.setPassword(password);\n        authInfo.setDefaultDatabaseName(defaultSchema);\n        authInfo.setSslInfo(sslInfo);\n        connector = new MysqlConnector(address, username, password, defaultSchema, sslInfo);\n        // 将connection里面的参数透传下\n        connector.setSoTimeout(soTimeout);\n        connector.setConnTimeout(connTimeout);\n    }\n\n    public void connect() throws IOException {\n        connector.connect();\n    }\n\n    public void reconnect() throws IOException {\n        connector.reconnect();\n    }\n\n    public void disconnect() throws IOException {\n        connector.disconnect();\n    }\n\n    public boolean isConnected() {\n        return connector.isConnected();\n    }\n\n    public ResultSetPacket query(String cmd) throws IOException {\n        MysqlQueryExecutor exector = new MysqlQueryExecutor(connector);\n        return exector.query(cmd);\n    }\n\n    public List<ResultSetPacket> queryMulti(String cmd) throws IOException {\n        MysqlQueryExecutor exector = new MysqlQueryExecutor(connector);\n        return exector.queryMulti(cmd);\n    }\n\n    public void update(String cmd) throws IOException {\n        MysqlUpdateExecutor exector = new MysqlUpdateExecutor(connector);\n        exector.update(cmd);\n    }\n\n    /**\n     * 加速主备切换时的查找速度，做一些特殊优化，比如只解析事务头或者尾\n     */\n    public void seek(String binlogfilename, Long binlogPosition, String gtid, SinkFunction func) throws IOException {\n        updateSettings();\n        loadBinlogChecksum();\n        loadVersionComment();\n        sendBinlogDump(binlogfilename, binlogPosition);\n        DirectLogFetcher fetcher = new DirectLogFetcher(connector.getReceiveBufferSize());\n        fetcher.start(connector.getChannel());\n        LogDecoder decoder = new LogDecoder();\n        decoder.handle(LogEvent.ROTATE_EVENT);\n        decoder.handle(LogEvent.FORMAT_DESCRIPTION_EVENT);\n        decoder.handle(LogEvent.QUERY_EVENT);\n        decoder.handle(LogEvent.XID_EVENT);\n        LogContext context = new LogContext();\n        // 若entry position存在gtid，则使用传入的gtid作为gtidSet\n        // 拼接的标准,否则同时开启gtid和tsdb时，会导致丢失gtid\n        // 而当源端数据库gtid 有purged时会有如下类似报错\n        // 'errno = 1236, sqlstate = HY000 errmsg = The slave is connecting\n        // using CHANGE MASTER TO MASTER_AUTO_POSITION = 1 ...\n        if (StringUtils.isNotEmpty(gtid)) {\n            GTIDSet gtidSet = parseGtidSet(gtid, isMariaDB());\n            if (isMariaDB()) {\n                decoder.handle(LogEvent.GTID_EVENT);\n                decoder.handle(LogEvent.GTID_LIST_EVENT);\n            } else {\n                decoder.handle(LogEvent.GTID_LOG_EVENT);\n            }\n            context.setGtidSet(gtidSet);\n        }\n        context.setCompatiablePercona(compatiablePercona);\n        context.setFormatDescription(new FormatDescriptionLogEvent(4, binlogChecksum));\n        while (fetcher.fetch()) {\n            accumulateReceivedBytes(fetcher.limit());\n            LogEvent event = null;\n            event = decoder.decode(fetcher, context);\n\n            if (event == null) {\n                throw new CanalParseException(\"parse failed\");\n            }\n\n            if (!func.sink(event)) {\n                break;\n            }\n        }\n    }\n\n    public void dump(String binlogfilename, Long binlogPosition, SinkFunction func) throws IOException {\n        updateSettings();\n        loadBinlogChecksum();\n        loadVersionComment();\n        sendRegisterSlave();\n        sendBinlogDump(binlogfilename, binlogPosition);\n        DirectLogFetcher fetcher = new DirectLogFetcher(connector.getReceiveBufferSize());\n        fetcher.start(connector.getChannel());\n        LogDecoder decoder = new LogDecoder(LogEvent.UNKNOWN_EVENT, LogEvent.ENUM_END_EVENT);\n        LogContext context = new LogContext();\n        context.setCompatiablePercona(compatiablePercona);\n        context.setFormatDescription(new FormatDescriptionLogEvent(4, binlogChecksum));\n        while (fetcher.fetch()) {\n            accumulateReceivedBytes(fetcher.limit());\n            LogEvent event = null;\n            event = decoder.decode(fetcher, context);\n\n            if (event == null) {\n                throw new CanalParseException(\"parse failed\");\n            }\n\n            if (!func.sink(event)) {\n                break;\n            }\n\n            if (event.getSemival() == 1) {\n                sendSemiAck(context.getLogPosition().getFileName(), context.getLogPosition().getPosition());\n            }\n        }\n    }\n\n    @Override\n    public void dump(GTIDSet gtidSet, SinkFunction func) throws IOException {\n        updateSettings();\n        loadBinlogChecksum();\n        loadVersionComment();\n        sendBinlogDumpGTID(gtidSet);\n\n        try (DirectLogFetcher fetcher = new DirectLogFetcher(connector.getReceiveBufferSize())) {\n            fetcher.start(connector.getChannel());\n            LogDecoder decoder = new LogDecoder(LogEvent.UNKNOWN_EVENT, LogEvent.ENUM_END_EVENT);\n            LogContext context = new LogContext();\n            context.setCompatiablePercona(compatiablePercona);\n            context.setFormatDescription(new FormatDescriptionLogEvent(4, binlogChecksum));\n            // fix bug: #890 将gtid传输至context中，供decode使用\n            context.setGtidSet(gtidSet);\n            while (fetcher.fetch()) {\n                accumulateReceivedBytes(fetcher.limit());\n                LogEvent event = null;\n                event = decoder.decode(fetcher, context);\n\n                if (event == null) {\n                    throw new CanalParseException(\"parse failed\");\n                }\n\n                List<LogEvent> iterateEvents = decoder.processIterateDecode(event, context);\n                if (!iterateEvents.isEmpty()) {\n                    // 处理compress event\n                    for (LogEvent itEvent : iterateEvents) {\n                        if (!func.sink(event)) {\n                            break;\n                        }\n                    }\n                } else {\n                    if (!func.sink(event)) {\n                        break;\n                    }\n                }\n            }\n        }\n    }\n\n    public void dump(long timestamp, SinkFunction func) throws IOException {\n        throw new NullPointerException(\"Not implement yet\");\n    }\n\n    @Override\n    public void dump(String binlogfilename, Long binlogPosition, MultiStageCoprocessor coprocessor) throws IOException {\n        updateSettings();\n        loadBinlogChecksum();\n        loadVersionComment();\n        sendRegisterSlave();\n        sendBinlogDump(binlogfilename, binlogPosition);\n        ((MysqlMultiStageCoprocessor) coprocessor).setConnection(this);\n        ((MysqlMultiStageCoprocessor) coprocessor).setBinlogChecksum(binlogChecksum);\n        ((MysqlMultiStageCoprocessor) coprocessor).setCompatiablePercona(compatiablePercona);\n        try (DirectLogFetcher fetcher = new DirectLogFetcher(connector.getReceiveBufferSize())) {\n            fetcher.start(connector.getChannel());\n            while (fetcher.fetch()) {\n                accumulateReceivedBytes(fetcher.limit());\n                LogBuffer buffer = fetcher.duplicate();\n                fetcher.consume(fetcher.limit());\n                if (!coprocessor.publish(buffer)) {\n                    break;\n                }\n            }\n        }\n    }\n\n    @Override\n    public void dump(long timestamp, MultiStageCoprocessor coprocessor) throws IOException {\n        throw new NullPointerException(\"Not implement yet\");\n    }\n\n    @Override\n    public void dump(GTIDSet gtidSet, MultiStageCoprocessor coprocessor) throws IOException {\n        updateSettings();\n        loadBinlogChecksum();\n        loadVersionComment();\n        sendBinlogDumpGTID(gtidSet);\n        ((MysqlMultiStageCoprocessor) coprocessor).setConnection(this);\n        ((MysqlMultiStageCoprocessor) coprocessor).setBinlogChecksum(binlogChecksum);\n        ((MysqlMultiStageCoprocessor) coprocessor).setCompatiablePercona(compatiablePercona);\n        try (DirectLogFetcher fetcher = new DirectLogFetcher(connector.getReceiveBufferSize())) {\n            fetcher.start(connector.getChannel());\n            while (fetcher.fetch()) {\n                accumulateReceivedBytes(fetcher.limit());\n                LogBuffer buffer = fetcher.duplicate();\n                fetcher.consume(fetcher.limit());\n                if (!coprocessor.publish(buffer)) {\n                    break;\n                }\n            }\n        }\n    }\n\n    private void sendRegisterSlave() throws IOException {\n        RegisterSlaveCommandPacket cmd = new RegisterSlaveCommandPacket();\n        SocketAddress socketAddress = connector.getChannel().getLocalSocketAddress();\n        if (socketAddress == null || !(socketAddress instanceof InetSocketAddress)) {\n            return;\n        }\n\n        InetSocketAddress address = (InetSocketAddress) socketAddress;\n        String host = address.getHostString();\n        int port = address.getPort();\n        cmd.reportHost = host;\n        cmd.reportPort = port;\n        cmd.reportPasswd = authInfo.getPassword();\n        cmd.reportUser = authInfo.getUsername();\n        cmd.serverId = this.slaveId;\n        byte[] cmdBody = cmd.toBytes();\n\n        logger.info(\"Register slave {}\", cmd);\n\n        HeaderPacket header = new HeaderPacket();\n        header.setPacketBodyLength(cmdBody.length);\n        header.setPacketSequenceNumber((byte) 0x00);\n        PacketManager.writePkg(connector.getChannel(), header.toBytes(), cmdBody);\n\n        header = PacketManager.readHeader(connector.getChannel(), 4);\n        byte[] body = PacketManager.readBytes(connector.getChannel(), header.getPacketBodyLength());\n        assert body != null;\n        if (body[0] < 0) {\n            if (body[0] == -1) {\n                ErrorPacket err = new ErrorPacket();\n                err.fromBytes(body);\n                throw new IOException(\"Error When doing Register slave:\" + err.toString());\n            } else {\n                throw new IOException(\"Unexpected packet with field_count=\" + body[0]);\n            }\n        }\n    }\n\n    private void sendBinlogDump(String binlogfilename, Long binlogPosition) throws IOException {\n        BinlogDumpCommandPacket binlogDumpCmd = new BinlogDumpCommandPacket();\n        binlogDumpCmd.binlogFileName = binlogfilename;\n        binlogDumpCmd.binlogPosition = binlogPosition;\n        binlogDumpCmd.slaveServerId = this.slaveId;\n        byte[] cmdBody = binlogDumpCmd.toBytes();\n\n        logger.info(\"COM_BINLOG_DUMP with position:{}\", binlogDumpCmd);\n        HeaderPacket binlogDumpHeader = new HeaderPacket();\n        binlogDumpHeader.setPacketBodyLength(cmdBody.length);\n        binlogDumpHeader.setPacketSequenceNumber((byte) 0x00);\n        PacketManager.writePkg(connector.getChannel(), binlogDumpHeader.toBytes(), cmdBody);\n        connector.setDumping(true);\n    }\n\n    public void sendSemiAck(String binlogfilename, Long binlogPosition) throws IOException {\n        SemiAckCommandPacket semiAckCmd = new SemiAckCommandPacket();\n        semiAckCmd.binlogFileName = binlogfilename;\n        semiAckCmd.binlogPosition = binlogPosition;\n\n        byte[] cmdBody = semiAckCmd.toBytes();\n\n        logger.info(\"SEMI ACK with position:{}\", semiAckCmd);\n        HeaderPacket semiAckHeader = new HeaderPacket();\n        semiAckHeader.setPacketBodyLength(cmdBody.length);\n        semiAckHeader.setPacketSequenceNumber((byte) 0x00);\n        PacketManager.writePkg(connector.getChannel(), semiAckHeader.toBytes(), cmdBody);\n    }\n\n    private void sendBinlogDumpGTID(GTIDSet gtidSet) throws IOException {\n        if (isMariaDB()) {\n            sendMariaBinlogDumpGTID(gtidSet);\n        } else {\n            sendMySQLBinlogDumpGTID(gtidSet);\n        }\n    }\n\n    private void sendMySQLBinlogDumpGTID(GTIDSet gtidSet) throws IOException {\n        BinlogDumpGTIDCommandPacket binlogDumpCmd = new BinlogDumpGTIDCommandPacket();\n        binlogDumpCmd.slaveServerId = this.slaveId;\n        binlogDumpCmd.gtidSet = gtidSet;\n        byte[] cmdBody = binlogDumpCmd.toBytes();\n\n        logger.info(\"COM_BINLOG_DUMP_GTID:{}\", binlogDumpCmd);\n        HeaderPacket binlogDumpHeader = new HeaderPacket();\n        binlogDumpHeader.setPacketBodyLength(cmdBody.length);\n        binlogDumpHeader.setPacketSequenceNumber((byte) 0x00);\n        PacketManager.writePkg(connector.getChannel(), binlogDumpHeader.toBytes(), cmdBody);\n        connector.setDumping(true);\n    }\n\n    private void sendMariaBinlogDumpGTID(GTIDSet gtidSet) throws IOException {\n        update(\"SET @slave_connect_state = '\" + new String(gtidSet.encode()) + \"'\");\n        update(\"SET @slave_gtid_strict_mode = 0\");\n        update(\"SET @slave_gtid_ignore_duplicates = 0\");\n        sendRegisterSlave();\n        sendBinlogDump(\"\", 0L);\n        connector.setDumping(true);\n    }\n\n    public MysqlConnection fork() {\n        MysqlConnection connection = new MysqlConnection();\n        connection.setCharset(getCharset());\n        connection.setSlaveId(getSlaveId());\n        connection.setConnector(connector.fork());\n        // set authInfo\n        connection.setAuthInfo(authInfo);\n        return connection;\n    }\n\n    @Override\n    public long queryServerId() throws IOException {\n        ResultSetPacket resultSetPacket = query(\"show variables like 'server_id'\");\n        List<String> fieldValues = resultSetPacket.getFieldValues();\n        if (fieldValues == null || fieldValues.size() != 2) {\n            return 0;\n        }\n        return NumberUtils.toLong(fieldValues.get(1));\n    }\n\n    // ====================== help method ====================\n\n    /**\n     * the settings that will need to be checked or set:<br>\n     * <ol>\n     * <li>wait_timeout</li>\n     * <li>net_write_timeout</li>\n     * <li>net_read_timeout</li>\n     * </ol>\n     * \n     * @throws IOException\n     */\n    private void updateSettings() throws IOException {\n        try {\n            update(\"set wait_timeout=9999999\");\n        } catch (Exception e) {\n            logger.warn(\"update wait_timeout failed\", e);\n        }\n        try {\n            update(\"set net_write_timeout=7200\");\n        } catch (Exception e) {\n            logger.warn(\"update net_write_timeout failed\", e);\n        }\n\n        try {\n            update(\"set net_read_timeout=7200\");\n        } catch (Exception e) {\n            logger.warn(\"update net_read_timeout failed\", e);\n        }\n\n        try {\n            // 设置服务端返回结果时不做编码转化，直接按照数据库的二进制编码进行发送，由客户端自己根据需求进行编码转化\n            update(\"set names 'binary'\");\n        } catch (Exception e) {\n            logger.warn(\"update names failed\", e);\n        }\n\n        try {\n            // mysql5.6针对checksum支持需要设置session变量\n            // 如果不设置会出现错误： Slave can not handle replication events with the\n            // checksum that master is configured to log\n            // 但也不能乱设置，需要和mysql server的checksum配置一致，不然RotateLogEvent会出现乱码\n            // '@@global.binlog_checksum'需要去掉单引号,在mysql 5.6.29下导致master退出\n            update(\"set @master_binlog_checksum= @@global.binlog_checksum\");\n        } catch (Exception e) {\n            if (!StringUtils.contains(e.getMessage(), \"Unknown system variable\")) {\n                logger.warn(\"update master_binlog_checksum failed\", e);\n            }\n        }\n\n        try {\n            // 参考:https://github.com/alibaba/canal/issues/284\n            // mysql5.6需要设置slave_uuid避免被server kill链接\n            update(\"set @slave_uuid=uuid()\");\n        } catch (Exception e) {\n            if (!StringUtils.contains(e.getMessage(), \"Unknown system variable\")\n                && !StringUtils.contains(e.getMessage(), \"slave_uuid can't be set\")) {\n                logger.warn(\"update slave_uuid failed\", e);\n            }\n        }\n\n        try {\n            // mariadb针对特殊的类型，需要设置session变量\n            update(\"SET @mariadb_slave_capability='\" + LogEvent.MARIA_SLAVE_CAPABILITY_MINE + \"'\");\n        } catch (Exception e) {\n            if (!StringUtils.contains(e.getMessage(), \"Unknown system variable\")) {\n                logger.warn(\"update mariadb_slave_capability failed\", e);\n            }\n        }\n\n        /**\n         * MASTER_HEARTBEAT_PERIOD sets the interval in seconds between replication\n         * heartbeats. Whenever the master's binary log is updated with an event, the\n         * waiting period for the next heartbeat is reset. interval is a decimal value\n         * having the range 0 to 4294967 seconds and a resolution in milliseconds; the\n         * smallest nonzero value is 0.001. Heartbeats are sent by the master only if\n         * there are no unsent events in the binary log file for a period longer than\n         * interval.\n         */\n        try {\n            long periodNano = TimeUnit.SECONDS.toNanos(MASTER_HEARTBEAT_PERIOD_SECONDS);\n            update(\"SET @master_heartbeat_period=\" + periodNano);\n        } catch (Exception e) {\n            logger.warn(\"update master_heartbeat_period failed\", e);\n        }\n    }\n\n    /**\n     * 获取一下binlog format格式\n     */\n    private void loadBinlogFormat() {\n        ResultSetPacket rs = null;\n        try {\n            rs = query(\"show variables like 'binlog_format'\");\n        } catch (IOException e) {\n            throw new CanalParseException(e);\n        }\n\n        List<String> columnValues = rs.getFieldValues();\n        if (columnValues == null || columnValues.size() != 2) {\n            logger.warn(\n                \"unexpected binlog format query result, this may cause unexpected result, so throw exception to request network to io shutdown.\");\n            throw new IllegalStateException(\"unexpected binlog format query result:\" + rs.getFieldValues());\n        }\n\n        binlogFormat = BinlogFormat.valuesOf(columnValues.get(1));\n        if (binlogFormat == null) {\n            throw new IllegalStateException(\"unexpected binlog format query result:\" + rs.getFieldValues());\n        }\n    }\n\n    /**\n     * 获取一下binlog image格式\n     */\n    private void loadBinlogImage() {\n        ResultSetPacket rs = null;\n        try {\n            rs = query(\"show variables like 'binlog_row_image'\");\n        } catch (IOException e) {\n            throw new CanalParseException(e);\n        }\n\n        List<String> columnValues = rs.getFieldValues();\n        if (columnValues == null || columnValues.size() != 2) {\n            // 可能历时版本没有image特性\n            binlogImage = BinlogImage.FULL;\n        } else {\n            binlogImage = BinlogImage.valuesOf(columnValues.get(1));\n        }\n\n        if (binlogFormat == null) {\n            throw new IllegalStateException(\"unexpected binlog image query result:\" + rs.getFieldValues());\n        }\n    }\n\n    /**\n     * 获取主库checksum信息\n     * \n     * <pre>\n     * mariadb区别于mysql会在binlog的第一个事件Rotate_Event里也会采用checksum逻辑,而mysql是在第二个binlog事件之后才感知是否需要处理checksum\n     * 导致maraidb只要是开启checksum就会出现binlog文件名解析乱码\n     * fixed issue : https://github.com/alibaba/canal/issues/1081\n     * </pre>\n     */\n    private void loadBinlogChecksum() {\n        ResultSetPacket rs = null;\n        try {\n            rs = query(\"select @@global.binlog_checksum\");\n            List<String> columnValues = rs.getFieldValues();\n            if (columnValues != null && columnValues.size() >= 1 && columnValues.get(0) != null\n                && columnValues.get(0).toUpperCase().equals(\"CRC32\")) {\n                binlogChecksum = LogEvent.BINLOG_CHECKSUM_ALG_CRC32;\n            } else {\n                binlogChecksum = LogEvent.BINLOG_CHECKSUM_ALG_OFF;\n            }\n        } catch (Throwable e) {\n            // logger.error(\"\", e);\n            binlogChecksum = LogEvent.BINLOG_CHECKSUM_ALG_OFF;\n        }\n    }\n\n    /**\n     * 识别下mysql的几种生态版本 (percona / mariadb / mysql)\n     */\n    private void loadVersionComment() {\n        ResultSetPacket rs = null;\n        try {\n            rs = query(\"select @@version_comment\");\n            List<String> columnValues = rs.getFieldValues();\n            if (columnValues != null && columnValues.size() >= 1 && columnValues.get(0) != null) {\n                logger.warn(\"load MySQL @@version_comment : \" + columnValues.get(0));\n                if (StringUtils.containsIgnoreCase(columnValues.get(0), \"Percona\")) {\n                    compatiablePercona = true;\n                }\n            }\n        } catch (Throwable e) {\n            compatiablePercona = false;\n        }\n    }\n\n    /**\n     * MySQL 8.4版本开始部分命令出现变化\n     * https://dev.mysql.com/doc/relnotes/mysql/8.4/en/news-8-4-0.html#mysqld-8-4-0-deprecation-removal\n     * \n     * @param major\n     * @param minor\n     * @return\n     */\n    public boolean atLeast(int major, int minor) {\n        if (isMariaDB()) {\n            return false;\n        }\n        String version = connector.getServerVersion();\n        if (StringUtils.isNotEmpty(version)) {\n            String[] parts = version.split(\"\\\\.\");\n            int majorVer = Integer.parseInt(parts[0]);\n            int minorVer = Integer.parseInt(parts[1]);\n            return (majorVer > major) || (majorVer == major && minorVer >= minor);\n        }\n        return false;\n    }\n\n    public boolean atLeastMySQL84() {\n        return atLeast(8, 4);\n    }\n\n    private void accumulateReceivedBytes(long x) {\n        if (receivedBinlogBytes != null) {\n            receivedBinlogBytes.addAndGet(x);\n        }\n    }\n\n    public static enum BinlogFormat {\n\n        STATEMENT(\"STATEMENT\"), ROW(\"ROW\"), MIXED(\"MIXED\");\n\n        public boolean isStatement() {\n            return this == STATEMENT;\n        }\n\n        public boolean isRow() {\n            return this == ROW;\n        }\n\n        public boolean isMixed() {\n            return this == MIXED;\n        }\n\n        private String value;\n\n        private BinlogFormat(String value) {\n            this.value = value;\n        }\n\n        public static BinlogFormat valuesOf(String value) {\n            BinlogFormat[] formats = values();\n            for (BinlogFormat format : formats) {\n                if (format.value.equalsIgnoreCase(value)) {\n                    return format;\n                }\n            }\n            return null;\n        }\n    }\n\n    /**\n     * http://dev.mysql.com/doc/refman/5.6/en/replication-options-binary-log.\n     * html#sysvar_binlog_row_image\n     * \n     * @author agapple 2015年6月29日 下午10:39:03\n     * @since 1.0.20\n     */\n    public static enum BinlogImage {\n\n        FULL(\"FULL\"), MINIMAL(\"MINIMAL\"), NOBLOB(\"NOBLOB\");\n\n        public boolean isFull() {\n            return this == FULL;\n        }\n\n        public boolean isMinimal() {\n            return this == MINIMAL;\n        }\n\n        public boolean isNoBlob() {\n            return this == NOBLOB;\n        }\n\n        private String value;\n\n        private BinlogImage(String value) {\n            this.value = value;\n        }\n\n        public static BinlogImage valuesOf(String value) {\n            BinlogImage[] formats = values();\n            for (BinlogImage format : formats) {\n                if (format.value.equalsIgnoreCase(value)) {\n                    return format;\n                }\n            }\n            return null;\n        }\n    }\n\n    // ================== setter / getter ===================\n\n    public Charset getCharset() {\n        return charset;\n    }\n\n    public void setCharset(Charset charset) {\n        this.charset = charset;\n    }\n\n    public long getSlaveId() {\n        return slaveId;\n    }\n\n    public void setSlaveId(long slaveId) {\n        this.slaveId = slaveId;\n    }\n\n    public MysqlConnector getConnector() {\n        return connector;\n    }\n\n    public void setConnector(MysqlConnector connector) {\n        this.connector = connector;\n    }\n\n    public BinlogFormat getBinlogFormat() {\n        if (binlogFormat == null) {\n            synchronized (this) {\n                loadBinlogFormat();\n            }\n        }\n\n        return binlogFormat;\n    }\n\n    public BinlogImage getBinlogImage() {\n        if (binlogImage == null) {\n            synchronized (this) {\n                loadBinlogImage();\n            }\n        }\n\n        return binlogImage;\n    }\n\n    public InetSocketAddress getAddress() {\n        return authInfo.getAddress();\n    }\n\n    public void setConnTimeout(int connTimeout) {\n        this.connTimeout = connTimeout;\n    }\n\n    public void setSoTimeout(int soTimeout) {\n        this.soTimeout = soTimeout;\n    }\n\n    public AuthenticationInfo getAuthInfo() {\n        return authInfo;\n    }\n\n    public void setAuthInfo(AuthenticationInfo authInfo) {\n        this.authInfo = authInfo;\n    }\n\n    public void setReceivedBinlogBytes(AtomicLong receivedBinlogBytes) {\n        this.receivedBinlogBytes = receivedBinlogBytes;\n    }\n\n    public boolean isMariaDB() {\n        return connector.getServerVersion() != null && connector.getServerVersion().toLowerCase().contains(\"mariadb\");\n    }\n\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/MysqlEventParser.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql;\n\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.net.UnknownHostException;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TimerTask;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.springframework.util.CollectionUtils;\n\nimport com.alibaba.otter.canal.common.utils.JsonUtils;\nimport com.alibaba.otter.canal.parse.CanalEventParser;\nimport com.alibaba.otter.canal.parse.CanalHASwitchable;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.server.FieldPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.server.ResultSetPacket;\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\nimport com.alibaba.otter.canal.parse.ha.CanalHAController;\nimport com.alibaba.otter.canal.parse.inbound.ErosaConnection;\nimport com.alibaba.otter.canal.parse.inbound.HeartBeatCallback;\nimport com.alibaba.otter.canal.parse.inbound.SinkFunction;\nimport com.alibaba.otter.canal.parse.inbound.mysql.MysqlConnection.BinlogFormat;\nimport com.alibaba.otter.canal.parse.inbound.mysql.MysqlConnection.BinlogImage;\nimport com.alibaba.otter.canal.parse.inbound.mysql.dbsync.LogEventConvert;\nimport com.alibaba.otter.canal.parse.inbound.mysql.dbsync.TableMetaCache;\nimport com.alibaba.otter.canal.parse.inbound.mysql.tsdb.DatabaseTableMeta;\nimport com.alibaba.otter.canal.parse.support.AuthenticationInfo;\nimport com.alibaba.otter.canal.protocol.CanalEntry;\nimport com.alibaba.otter.canal.protocol.position.EntryPosition;\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\n\n/**\n * 基于向mysql server复制binlog实现\n *\n * <pre>\n * 1. 自身不控制mysql主备切换，由ha机制来控制. 比如接入tddl/cobar/自身心跳包成功率\n * 2. 切换机制\n * </pre>\n *\n * @author jianghang 2012-6-21 下午04:06:32\n * @version 1.0.0\n */\npublic class MysqlEventParser extends AbstractMysqlEventParser implements CanalEventParser, CanalHASwitchable {\n\n    private CanalHAController    haController                      = null;\n    private int                  defaultConnectionTimeoutInSeconds = 30;\n    private int                  receiveBufferSize                 = 64 * 1024;\n    private int                  sendBufferSize                    = 64 * 1024;\n    // 数据库信息\n    protected AuthenticationInfo masterInfo;                                   // 主库\n    protected AuthenticationInfo standbyInfo;                                  // 备库\n    // binlog信息\n    protected EntryPosition      masterPosition;\n    protected EntryPosition      standbyPosition;\n    private long                 slaveId;                                      // 链接到mysql的slave\n    // 心跳检查信息\n    private String               detectingSQL;                                 // 心跳sql\n    private MysqlConnection      metaConnection;                               // 查询meta信息的链接\n    private TableMetaCache       tableMetaCache;                               // 对应meta\n    private int                  fallbackIntervalInSeconds         = 60;       // 切换回退时间\n    private BinlogFormat[]       supportBinlogFormats;                         // 支持的binlogFormat,如果设置会执行强校验\n    private BinlogImage[]        supportBinlogImages;                          // 支持的binlogImage,如果设置会执行强校验\n\n    // update by yishun.chen,特殊异常处理参数\n    private int                  dumpErrorCount                    = 0;        // binlogDump失败异常计数\n    private int                  dumpErrorCountThreshold           = 2;        // binlogDump失败异常计数阀值\n    private boolean              rdsOssMode                        = false;\n    private boolean              autoResetLatestPosMode            = false;    // binlog被删除之后，自动按最新的数据订阅\n    private boolean              multiStreamEnable;                            // support for polardbx binlog-x\n\n    protected ErosaConnection buildErosaConnection() {\n        return buildMysqlConnection(this.runningInfo);\n    }\n\n    protected void preDump(ErosaConnection connection) {\n        if (!(connection instanceof MysqlConnection)) {\n            throw new CanalParseException(\"Unsupported connection type : \" + connection.getClass().getSimpleName());\n        }\n\n        if (binlogParser != null && binlogParser instanceof LogEventConvert) {\n            metaConnection = (MysqlConnection) connection.fork();\n            try {\n                metaConnection.connect();\n            } catch (IOException e) {\n                throw new CanalParseException(e);\n            }\n\n            if (supportBinlogFormats != null && supportBinlogFormats.length > 0) {\n                BinlogFormat format = ((MysqlConnection) metaConnection).getBinlogFormat();\n                boolean found = false;\n                for (BinlogFormat supportFormat : supportBinlogFormats) {\n                    if (supportFormat != null && format == supportFormat) {\n                        found = true;\n                        break;\n                    }\n                }\n\n                if (!found) {\n                    throw new CanalParseException(\"Unsupported BinlogFormat \" + format);\n                }\n            }\n\n            if (supportBinlogImages != null && supportBinlogImages.length > 0) {\n                BinlogImage image = ((MysqlConnection) metaConnection).getBinlogImage();\n                boolean found = false;\n                for (BinlogImage supportImage : supportBinlogImages) {\n                    if (supportImage != null && image == supportImage) {\n                        found = true;\n                        break;\n                    }\n                }\n\n                if (!found) {\n                    throw new CanalParseException(\"Unsupported BinlogImage \" + image);\n                }\n            }\n\n            if (tableMetaTSDB != null && tableMetaTSDB instanceof DatabaseTableMeta) {\n                ((DatabaseTableMeta) tableMetaTSDB).setConnection(metaConnection);\n                ((DatabaseTableMeta) tableMetaTSDB).setFilter(eventFilter);\n                ((DatabaseTableMeta) tableMetaTSDB).setBlackFilter(eventBlackFilter);\n                ((DatabaseTableMeta) tableMetaTSDB).setSnapshotInterval(tsdbSnapshotInterval);\n                ((DatabaseTableMeta) tableMetaTSDB).setSnapshotExpire(tsdbSnapshotExpire);\n                ((DatabaseTableMeta) tableMetaTSDB).init(destination);\n            }\n\n            tableMetaCache = new TableMetaCache(metaConnection, tableMetaTSDB);\n            ((LogEventConvert) binlogParser).setTableMetaCache(tableMetaCache);\n        }\n    }\n\n    protected void afterDump(ErosaConnection connection) {\n        super.afterDump(connection);\n\n        if (connection == null) {\n            throw new CanalParseException(\"illegal connection is null\");\n        }\n\n        if (!(connection instanceof MysqlConnection)) {\n            throw new CanalParseException(\"Unsupported connection type : \" + connection.getClass().getSimpleName());\n        }\n\n        if (metaConnection != null) {\n            try {\n                metaConnection.disconnect();\n            } catch (IOException e) {\n                logger.error(\"ERROR # disconnect meta connection for address:{}\", metaConnection.getConnector()\n                    .getAddress(), e);\n            }\n        }\n    }\n\n    public void start() throws CanalParseException {\n        if (runningInfo == null) { // 第一次链接主库\n            runningInfo = masterInfo;\n        }\n\n        super.start();\n    }\n\n    public void stop() throws CanalParseException {\n        if (metaConnection != null) {\n            try {\n                metaConnection.disconnect();\n            } catch (IOException e) {\n                logger.error(\"ERROR # disconnect meta connection for address:{}\", metaConnection.getConnector()\n                    .getAddress(), e);\n            }\n        }\n\n        if (tableMetaCache != null) {\n            tableMetaCache.clearTableMeta();\n        }\n\n        super.stop();\n    }\n\n    protected TimerTask buildHeartBeatTimeTask(ErosaConnection connection) {\n        if (!(connection instanceof MysqlConnection)) {\n            throw new CanalParseException(\"Unsupported connection type : \" + connection.getClass().getSimpleName());\n        }\n\n        // 开始mysql心跳sql\n        if (detectingEnable && StringUtils.isNotBlank(detectingSQL)) {\n            return new MysqlDetectingTimeTask((MysqlConnection) connection.fork());\n        } else {\n            return super.buildHeartBeatTimeTask(connection);\n        }\n\n    }\n\n    protected void stopHeartBeat() {\n        TimerTask heartBeatTimerTask = this.heartBeatTimerTask;\n        super.stopHeartBeat();\n        if (heartBeatTimerTask != null && heartBeatTimerTask instanceof MysqlDetectingTimeTask) {\n            MysqlConnection mysqlConnection = ((MysqlDetectingTimeTask) heartBeatTimerTask).getMysqlConnection();\n            try {\n                mysqlConnection.disconnect();\n            } catch (IOException e) {\n                logger.error(\"ERROR # disconnect heartbeat connection for address:{}\", mysqlConnection.getConnector()\n                    .getAddress(), e);\n            }\n        }\n    }\n\n    /**\n     * 心跳信息\n     *\n     * @author jianghang 2012-7-6 下午02:50:15\n     * @version 1.0.0\n     */\n    class MysqlDetectingTimeTask extends TimerTask {\n\n        private boolean         reconnect = false;\n        private MysqlConnection mysqlConnection;\n\n        public MysqlDetectingTimeTask(MysqlConnection mysqlConnection){\n            this.mysqlConnection = mysqlConnection;\n        }\n\n        public void run() {\n            try {\n                if (reconnect) {\n                    reconnect = false;\n                    mysqlConnection.reconnect();\n                } else if (!mysqlConnection.isConnected()) {\n                    mysqlConnection.connect();\n                }\n                long startTime = System.currentTimeMillis();\n\n                // 可能心跳sql为select 1\n                if (StringUtils.startsWithIgnoreCase(detectingSQL.trim(), \"select\")\n                    || StringUtils.startsWithIgnoreCase(detectingSQL.trim(), \"show\")\n                    || StringUtils.startsWithIgnoreCase(detectingSQL.trim(), \"explain\")\n                    || StringUtils.startsWithIgnoreCase(detectingSQL.trim(), \"desc\")) {\n                    mysqlConnection.query(detectingSQL);\n                } else {\n                    mysqlConnection.update(detectingSQL);\n                }\n\n                long costTime = System.currentTimeMillis() - startTime;\n                if (haController != null && haController instanceof HeartBeatCallback) {\n                    ((HeartBeatCallback) haController).onSuccess(costTime);\n                }\n            } catch (Throwable e) {\n                if (haController != null && haController instanceof HeartBeatCallback) {\n                    ((HeartBeatCallback) haController).onFailed(e);\n                }\n                reconnect = true;\n                logger.warn(\"connect failed by \", e);\n            }\n        }\n\n        public MysqlConnection getMysqlConnection() {\n            return mysqlConnection;\n        }\n    }\n\n    // 处理主备切换的逻辑\n    public void doSwitch() {\n        AuthenticationInfo newRunningInfo = (runningInfo.equals(masterInfo) ? standbyInfo : masterInfo);\n        this.doSwitch(newRunningInfo);\n    }\n\n    public void doSwitch(AuthenticationInfo newRunningInfo) {\n        // 1. 需要停止当前正在复制的过程\n        // 2. 找到新的position点\n        // 3. 重新建立链接，开始复制数据\n        // 切换ip\n        String alarmMessage = null;\n\n        if (this.runningInfo.equals(newRunningInfo)) {\n            alarmMessage = \"same runingInfo switch again : \" + runningInfo.getAddress().toString();\n            logger.warn(alarmMessage);\n            return;\n        }\n\n        if (newRunningInfo == null) {\n            alarmMessage = \"no standby config, just do nothing, will continue try:\"\n                           + runningInfo.getAddress().toString();\n            logger.warn(alarmMessage);\n            sendAlarm(destination, alarmMessage);\n            return;\n        } else {\n            stop();\n            alarmMessage = \"try to ha switch, old:\" + runningInfo.getAddress().toString() + \", new:\"\n                           + newRunningInfo.getAddress().toString();\n            logger.warn(alarmMessage);\n            sendAlarm(destination, alarmMessage);\n            runningInfo = newRunningInfo;\n            start();\n        }\n    }\n\n    // =================== helper method =================\n\n    private MysqlConnection buildMysqlConnection(AuthenticationInfo runningInfo) {\n        MysqlConnection connection = new MysqlConnection(runningInfo.getAddress(),\n            runningInfo.getUsername(),\n            runningInfo.getPassword(),\n            runningInfo.getDefaultDatabaseName(),\n            runningInfo.getSslInfo());\n        connection.getConnector().setReceiveBufferSize(receiveBufferSize);\n        connection.getConnector().setSendBufferSize(sendBufferSize);\n        connection.getConnector().setSoTimeout(defaultConnectionTimeoutInSeconds * 1000);\n        connection.setCharset(connectionCharset);\n        connection.setReceivedBinlogBytes(receivedBinlogBytes);\n        // 随机生成slaveId\n        if (this.slaveId <= 0) {\n            this.slaveId = generateUniqueServerId();\n        }\n        connection.setSlaveId(this.slaveId);\n        return connection;\n    }\n\n    private final long generateUniqueServerId() {\n        try {\n            // a=`echo $masterip|cut -d\\. -f1`\n            // b=`echo $masterip|cut -d\\. -f2`\n            // c=`echo $masterip|cut -d\\. -f3`\n            // d=`echo $masterip|cut -d\\. -f4`\n            // #server_id=`expr $a \\* 256 \\* 256 \\* 256 + $b \\* 256 \\* 256 + $c\n            // \\* 256 + $d `\n            // #server_id=$b$c$d\n            // server_id=`expr $b \\* 256 \\* 256 + $c \\* 256 + $d `\n            InetAddress localHost = InetAddress.getLocalHost();\n            byte[] addr = localHost.getAddress();\n            int salt = (destination != null) ? destination.hashCode() : 0;\n            return ((0x7f & salt) << 24) + ((0xff & (int) addr[1]) << 16) // NL\n                   + ((0xff & (int) addr[2]) << 8) // NL\n                   + (0xff & (int) addr[3]);\n        } catch (UnknownHostException e) {\n            throw new CanalParseException(\"Unknown host\", e);\n        }\n    }\n\n    protected EntryPosition findStartPosition(ErosaConnection connection) throws IOException {\n        if (isGTIDMode()) {\n            // GTID模式下，CanalLogPositionManager里取最后的gtid，没有则取instance配置中的\n            LogPosition logPosition = getLogPositionManager().getLatestIndexBy(destination);\n            if (logPosition != null) {\n                // 如果以前是非GTID模式，后来调整为了GTID模式，那么为了保持兼容，需要判断gtid是否为空\n                if (StringUtils.isNotEmpty(logPosition.getPostion().getGtid())) {\n                    return logPosition.getPostion();\n                }\n            } else {\n                if (masterPosition != null && StringUtils.isNotEmpty(masterPosition.getGtid())) {\n                    return masterPosition;\n                }\n            }\n        }\n\n        EntryPosition startPosition = findStartPositionInternal(connection);\n        if (needTransactionPosition.get()) {\n            logger.warn(\"prepare to find last position : {}\", startPosition.toString());\n            Long preTransactionStartPosition = findTransactionBeginPosition(connection, startPosition);\n            if (!preTransactionStartPosition.equals(startPosition.getPosition())) {\n                logger.warn(\"find new start Transaction Position , old : {} , new : {}\",\n                    startPosition.getPosition(),\n                    preTransactionStartPosition);\n                startPosition.setPosition(preTransactionStartPosition);\n            }\n            needTransactionPosition.compareAndSet(true, false);\n        }\n        return startPosition;\n    }\n\n    protected EntryPosition findEndPosition(ErosaConnection connection) throws IOException {\n        MysqlConnection mysqlConnection = (MysqlConnection) connection;\n        EntryPosition endPosition = findEndPosition(mysqlConnection);\n        return endPosition;\n    }\n\n    protected EntryPosition findEndPositionWithMasterIdAndTimestamp(MysqlConnection connection) {\n        MysqlConnection mysqlConnection = (MysqlConnection) connection;\n        final EntryPosition endPosition = findEndPosition(mysqlConnection);\n        if (tableMetaTSDB != null || isGTIDMode()) {\n            long startTimestamp = System.currentTimeMillis();\n            return findAsPerTimestampInSpecificLogFile(mysqlConnection,\n                startTimestamp,\n                endPosition,\n                endPosition.getJournalName(),\n                true);\n        } else {\n            return endPosition;\n        }\n    }\n\n    protected EntryPosition findPositionWithMasterIdAndTimestamp(MysqlConnection connection, EntryPosition fixedPosition) {\n        MysqlConnection mysqlConnection = (MysqlConnection) connection;\n        if (tableMetaTSDB != null && (fixedPosition.getTimestamp() == null || fixedPosition.getTimestamp() <= 0)) {\n            // 使用一个未来极大的时间，基于位点进行定位\n            long startTimestamp = System.currentTimeMillis() + 102L * 365 * 24 * 3600 * 1000; // 当前时间的未来102年\n            EntryPosition entryPosition = findAsPerTimestampInSpecificLogFile(mysqlConnection,\n                startTimestamp,\n                fixedPosition,\n                fixedPosition.getJournalName(),\n                true);\n            if (entryPosition == null) {\n                throw new CanalParseException(\"[fixed timestamp] can't found begin/commit position before with fixed position \"\n                                              + fixedPosition.getJournalName() + \":\" + fixedPosition.getPosition());\n            }\n            return entryPosition;\n        } else {\n            return fixedPosition;\n        }\n    }\n\n    protected EntryPosition findStartPositionInternal(ErosaConnection connection) {\n        MysqlConnection mysqlConnection = (MysqlConnection) connection;\n        LogPosition logPosition = logPositionManager.getLatestIndexBy(destination);\n        if (logPosition == null) {// 找不到历史成功记录\n            EntryPosition entryPosition = null;\n            if (masterInfo != null && mysqlConnection.getConnector().getAddress().equals(masterInfo.getAddress())) {\n                entryPosition = masterPosition;\n            } else if (standbyInfo != null\n                       && mysqlConnection.getConnector().getAddress().equals(standbyInfo.getAddress())) {\n                entryPosition = standbyPosition;\n            }\n\n            if (entryPosition == null) {\n                entryPosition =\n                        findEndPositionWithMasterIdAndTimestamp(mysqlConnection); // 默认从当前最后一个位置进行消费\n            }\n\n            // 判断一下是否需要按时间订阅\n            if (StringUtils.isEmpty(entryPosition.getJournalName())) {\n                // 如果没有指定binlogName，尝试按照timestamp进行查找\n                if (entryPosition.getTimestamp() != null && entryPosition.getTimestamp() > 0L) {\n                    logger.warn(\"prepare to find start position {}:{}:{}\",\n                        new Object[] { \"\", \"\", entryPosition.getTimestamp() });\n                    return findByStartTimeStamp(mysqlConnection, entryPosition.getTimestamp());\n                } else {\n                    logger.warn(\"prepare to find start position just show master status\");\n                    return findEndPositionWithMasterIdAndTimestamp(mysqlConnection); // 默认从当前最后一个位置进行消费\n                }\n            } else {\n                if (entryPosition.getPosition() != null && entryPosition.getPosition() > 0L) {\n                    // 如果指定binlogName + offest，直接返回\n                    entryPosition = findPositionWithMasterIdAndTimestamp(mysqlConnection, entryPosition);\n                    logger.warn(\"prepare to find start position {}:{}:{}\",\n                        new Object[] { entryPosition.getJournalName(), entryPosition.getPosition(),\n                                entryPosition.getTimestamp() });\n                    return entryPosition;\n                } else {\n                    EntryPosition specificLogFilePosition = null;\n                    if (entryPosition.getTimestamp() != null && entryPosition.getTimestamp() > 0L) {\n                        // 如果指定binlogName +\n                        // timestamp，但没有指定对应的offest，尝试根据时间找一下offest\n                        EntryPosition endPosition = findEndPosition(mysqlConnection);\n                        if (endPosition != null) {\n                            logger.warn(\"prepare to find start position {}:{}:{}\",\n                                new Object[] { entryPosition.getJournalName(), \"\", entryPosition.getTimestamp() });\n                            specificLogFilePosition = findAsPerTimestampInSpecificLogFile(mysqlConnection,\n                                entryPosition.getTimestamp(),\n                                endPosition,\n                                entryPosition.getJournalName(),\n                                true);\n                        }\n                    }\n\n                    if (specificLogFilePosition == null) {\n                        if (isRdsOssMode()) {\n                            // 如果binlog位点不存在，并且属于timestamp不为空,可以返回null走到oss binlog处理\n                            return null;\n                        }\n                        // position不存在，从文件头开始\n                        entryPosition.setPosition(BINLOG_START_OFFEST);\n                        return entryPosition;\n                    } else {\n                        return specificLogFilePosition;\n                    }\n                }\n            }\n        } else {\n            if (logPosition.getIdentity().getSourceAddress().equals(mysqlConnection.getConnector().getAddress())) {\n                if (dumpErrorCountThreshold >= 0 && dumpErrorCount > dumpErrorCountThreshold) {\n                    // binlog定位位点失败,可能有两个原因:\n                    // 1. binlog位点被删除\n                    // 2.vip模式的mysql,发生了主备切换,判断一下serverId是否变化,针对这种模式可以发起一次基于时间戳查找合适的binlog位点\n                    boolean case2 = (standbyInfo == null || standbyInfo.getAddress() == null)\n                                    && logPosition.getPostion().getServerId() != null\n                                    && !logPosition.getPostion().getServerId().equals(findServerId(mysqlConnection));\n                    if (case2) {\n                        EntryPosition findPosition = fallbackFindByStartTimestamp(logPosition, mysqlConnection);\n                        dumpErrorCount = 0;\n                        return findPosition;\n                    }\n                    // 处理 binlog 位点被删除的情况，提供自动重置到当前位点的功能\n                    // 应用场景: 测试环境不稳定，位点经常被删。强烈不建议在正式环境中开启此控制参数，因为binlog\n                    // 丢失调到最新位点也即意味着数据丢失\n                    if (isAutoResetLatestPosMode()) {\n                        dumpErrorCount = 0;\n                        return findEndPosition(mysqlConnection);\n                    }\n                    Long timestamp = logPosition.getPostion().getTimestamp();\n                    if (isRdsOssMode() && (timestamp != null && timestamp > 0)) {\n                        // 如果binlog位点不存在，并且属于timestamp不为空,可以返回null走到oss binlog处理\n                        return null;\n                    }\n                } else if (StringUtils.isBlank(logPosition.getPostion().getJournalName())\n                           && logPosition.getPostion().getPosition() <= 0\n                           && logPosition.getPostion().getTimestamp() > 0) {\n                    return fallbackFindByStartTimestamp(logPosition, mysqlConnection);\n                }\n                // 其余情况\n                logger.warn(\"prepare to find start position just last position\\n {}\",\n                    JsonUtils.marshalToString(logPosition));\n                return logPosition.getPostion();\n            } else {\n                // 针对切换的情况，考虑回退时间\n                long newStartTimestamp = logPosition.getPostion().getTimestamp() - fallbackIntervalInSeconds * 1000;\n                logger.warn(\"prepare to find start position by switch {}:{}:{}\", new Object[] { \"\", \"\",\n                        logPosition.getPostion().getTimestamp() });\n                return findByStartTimeStamp(mysqlConnection, newStartTimestamp);\n            }\n        }\n    }\n\n    /**\n     * find position by timestamp with a fallback interval seconds.\n     *\n     * @param logPosition\n     * @param mysqlConnection\n     * @return\n     */\n    protected EntryPosition fallbackFindByStartTimestamp(LogPosition logPosition, MysqlConnection mysqlConnection) {\n        long timestamp = logPosition.getPostion().getTimestamp();\n        long newStartTimestamp = timestamp - fallbackIntervalInSeconds * 1000;\n        logger.warn(\"prepare to find start position by last position {}:{}:{}\", new Object[] { \"\", \"\",\n                logPosition.getPostion().getTimestamp() });\n        return findByStartTimeStamp(mysqlConnection, newStartTimestamp);\n    }\n\n    // 根据想要的position，可能这个position对应的记录为rowdata，需要找到事务头，避免丢数据\n    // 主要考虑一个事务执行时间可能会几秒种，如果仅仅按照timestamp相同，则可能会丢失事务的前半部分数据\n    private Long findTransactionBeginPosition(ErosaConnection mysqlConnection, final EntryPosition entryPosition)\n                                                                                                                 throws IOException {\n        // 针对开始的第一条为非Begin记录，需要从该binlog扫描\n        final java.util.concurrent.atomic.AtomicLong preTransactionStartPosition = new java.util.concurrent.atomic.AtomicLong(0L);\n        mysqlConnection.reconnect();\n        mysqlConnection.seek(entryPosition.getJournalName(), 4L, entryPosition.getGtid(), new SinkFunction<LogEvent>() {\n\n            private LogPosition lastPosition;\n\n            public boolean sink(LogEvent event) {\n                try {\n                    CanalEntry.Entry entry = parseAndProfilingIfNecessary(event, true);\n                    if (entry == null) {\n                        return true;\n                    }\n\n                    // 直接查询第一条业务数据，确认是否为事务Begin\n                    // 记录一下transaction begin position\n                    if (entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONBEGIN\n                        && entry.getHeader().getLogfileOffset() < entryPosition.getPosition()) {\n                        preTransactionStartPosition.set(entry.getHeader().getLogfileOffset());\n                    }\n\n                    if (entry.getHeader().getLogfileOffset() >= entryPosition.getPosition()) {\n                        return false;// 退出\n                    }\n\n                    lastPosition = buildLastPosition(entry);\n                } catch (Exception e) {\n                    processSinkError(e, lastPosition, entryPosition.getJournalName(), entryPosition.getPosition());\n                    return false;\n                }\n\n                return running;\n            }\n        });\n\n        // 判断一下找到的最接近position的事务头的位置\n        if (preTransactionStartPosition.get() > entryPosition.getPosition()) {\n            logger.error(\"preTransactionEndPosition greater than startPosition from zk or localconf, maybe lost data\");\n            throw new CanalParseException(\"preTransactionStartPosition greater than startPosition from zk or localconf, maybe lost data\");\n        }\n        return preTransactionStartPosition.get();\n    }\n\n    // 根据时间查找binlog位置\n    private EntryPosition findByStartTimeStamp(MysqlConnection mysqlConnection, Long startTimestamp) {\n        EntryPosition endPosition = findEndPosition(mysqlConnection);\n        EntryPosition startPosition = findStartPosition(mysqlConnection);\n        String maxBinlogFileName = endPosition.getJournalName();\n        String minBinlogFileName = startPosition.getJournalName();\n        logger.info(\"show master status to set search end condition:{} \", endPosition);\n        String startSearchBinlogFile = endPosition.getJournalName();\n        boolean shouldBreak = false;\n        while (running && !shouldBreak) {\n            try {\n                EntryPosition entryPosition = findAsPerTimestampInSpecificLogFile(mysqlConnection,\n                    startTimestamp,\n                    endPosition,\n                    startSearchBinlogFile,\n                    false);\n                if (entryPosition == null) {\n                    if (StringUtils.equalsIgnoreCase(minBinlogFileName, startSearchBinlogFile)) {\n                        // 已经找到最早的一个binlog，没必要往前找了\n                        shouldBreak = true;\n                        logger.warn(\"Didn't find the corresponding binlog files from {} to {}\",\n                            minBinlogFileName,\n                            maxBinlogFileName);\n                    } else {\n                        // 继续往前找\n                        int binlogSeqNum = Integer.parseInt(startSearchBinlogFile.substring(startSearchBinlogFile.indexOf(\".\") + 1));\n                        if (binlogSeqNum <= 1) {\n                            logger.warn(\"Didn't find the corresponding binlog files\");\n                            shouldBreak = true;\n                        } else {\n                            int nextBinlogSeqNum = binlogSeqNum - 1;\n                            String binlogFileNamePrefix = startSearchBinlogFile.substring(0,\n                                startSearchBinlogFile.indexOf(\".\") + 1);\n                            String binlogFileNameSuffix = String.format(\"%06d\", nextBinlogSeqNum);\n                            startSearchBinlogFile = binlogFileNamePrefix + binlogFileNameSuffix;\n                        }\n                    }\n                } else {\n                    logger.info(\"found and return:{} in findByStartTimeStamp operation.\", entryPosition);\n                    return entryPosition;\n                }\n            } catch (Exception e) {\n                logger.warn(String.format(\"the binlogfile:%s doesn't exist, to continue to search the next binlogfile , caused by\",\n                    startSearchBinlogFile),\n                    e);\n                int binlogSeqNum = Integer.parseInt(startSearchBinlogFile.substring(startSearchBinlogFile.indexOf(\".\") + 1));\n                if (binlogSeqNum <= 1) {\n                    logger.warn(\"Didn't find the corresponding binlog files\");\n                    shouldBreak = true;\n                } else {\n                    int nextBinlogSeqNum = binlogSeqNum - 1;\n                    String binlogFileNamePrefix = startSearchBinlogFile.substring(0,\n                        startSearchBinlogFile.indexOf(\".\") + 1);\n                    String binlogFileNameSuffix = String.format(\"%06d\", nextBinlogSeqNum);\n                    startSearchBinlogFile = binlogFileNamePrefix + binlogFileNameSuffix;\n                }\n            }\n        }\n        // 找不到\n        return null;\n    }\n\n    /**\n     * 查询当前db的serverId信息\n     */\n    private Long findServerId(MysqlConnection mysqlConnection) {\n        try {\n            ResultSetPacket packet = mysqlConnection.query(\"show variables like 'server_id'\");\n            List<String> fields = packet.getFieldValues();\n            if (CollectionUtils.isEmpty(fields)) {\n                throw new CanalParseException(\"command : show variables like 'server_id' has an error! pls check. you need (at least one of) the SUPER,REPLICATION CLIENT privilege(s) for this operation\");\n            }\n            return Long.valueOf(fields.get(1));\n        } catch (IOException e) {\n            throw new CanalParseException(\"command : show variables like 'server_id' has an error!\", e);\n        }\n    }\n\n    /**\n     * 查询当前的binlog位置\n     */\n    private EntryPosition findEndPosition(MysqlConnection mysqlConnection) {\n        String showSql = \"show master status\";\n        try {\n            if (mysqlConnection.atLeastMySQL84()) {\n                // 8.4新语法\n                showSql = \"show binary log status\";\n            } else if (multiStreamEnable) {\n                // 兼容polardb-x的多流binlog\n                showSql = \"show master status with \" + destination;\n            }\n            ResultSetPacket packet = mysqlConnection.query(showSql);\n            List<String> fields = packet.getFieldValues();\n            if (CollectionUtils.isEmpty(fields)) {\n                throw new CanalParseException(\n                    \"command : '\" + showSql + \"' has an error! pls check. you need (at least one of) the SUPER,REPLICATION CLIENT privilege(s) for this operation\");\n            }\n            EntryPosition endPosition = new EntryPosition(fields.get(0), Long.valueOf(fields.get(1)));\n            if (isGTIDMode() && fields.size() > 4) {\n                endPosition.setGtid(fields.get(4));\n            }\n            // MariaDB 无法通过`show master status`获取 gtid\n            if (mysqlConnection.isMariaDB() && isGTIDMode()) {\n                ResultSetPacket gtidPacket = mysqlConnection.query(\"SELECT @@global.gtid_binlog_pos\");\n                List<String> gtidFields = gtidPacket.getFieldValues();\n                if (!CollectionUtils.isEmpty(gtidFields) && gtidFields.size() > 0) {\n                    endPosition.setGtid(gtidFields.get(0));\n                }\n            }\n            return endPosition;\n        } catch (IOException e) {\n            throw new CanalParseException(\"command : '\" + showSql + \"' has an error!\", e);\n        }\n    }\n\n    /**\n     * 查询当前的binlog位置\n     */\n    private EntryPosition findStartPosition(MysqlConnection mysqlConnection) {\n        try {\n            String showSql = \"show binlog events limit 1\";\n            if (multiStreamEnable) {\n                showSql = \"show binlog events with \" + destination + \" limit 1\";\n            }\n            ResultSetPacket packet = mysqlConnection.query(showSql);\n            List<String> fields = packet.getFieldValues();\n            if (CollectionUtils.isEmpty(fields)) {\n                throw new CanalParseException(\n                        \"command : 'show binlog events limit 1' has an error! pls check. you need (at least one of) the SUPER,REPLICATION CLIENT privilege(s) for this operation\");\n            }\n            EntryPosition endPosition = new EntryPosition(fields.get(0), Long.valueOf(fields.get(1)));\n            return endPosition;\n        } catch (IOException e) {\n            throw new CanalParseException(\"command : 'show binlog events limit 1' has an error!\", e);\n        }\n\n    }\n\n    /**\n     * 查询当前的slave视图的binlog位置\n     */\n    @SuppressWarnings(\"unused\")\n    private SlaveEntryPosition findSlavePosition(MysqlConnection mysqlConnection) {\n        try {\n            String showSql = \"show slave status\";\n            if (mysqlConnection.atLeastMySQL84()) {\n                // 兼容mysql 8.4\n                showSql = \"show replica status\";\n            }\n            ResultSetPacket packet = mysqlConnection.query(showSql);\n            List<FieldPacket> names = packet.getFieldDescriptors();\n            List<String> fields = packet.getFieldValues();\n            if (CollectionUtils.isEmpty(fields)) {\n                return null;\n            }\n\n            int i = 0;\n            Map<String, String> maps = new HashMap<>(names.size(), 1f);\n            for (FieldPacket name : names) {\n                maps.put(name.getName(), fields.get(i));\n                i++;\n            }\n\n            String errno = maps.get(\"Last_Errno\");\n            String slaveIORunning = maps.get(\"Slave_IO_Running\"); // Slave_SQL_Running\n            String slaveSQLRunning = maps.get(\"Slave_SQL_Running\"); // Slave_SQL_Running\n            if ((!\"0\".equals(errno)) || (!\"Yes\".equalsIgnoreCase(slaveIORunning))\n                || (!\"Yes\".equalsIgnoreCase(slaveSQLRunning))) {\n                logger.warn(\"Ignoring failed slave: \" + mysqlConnection.getConnector().getAddress() + \", Last_Errno = \"\n                            + errno + \", Slave_IO_Running = \" + slaveIORunning + \", Slave_SQL_Running = \"\n                            + slaveSQLRunning);\n                return null;\n            }\n\n            String masterHost = maps.get(\"Master_Host\");\n            String masterPort = maps.get(\"Master_Port\");\n            String binlog = maps.get(\"Master_Log_File\");\n            String position = maps.get(\"Exec_Master_Log_Pos\");\n            return new SlaveEntryPosition(binlog, Long.valueOf(position), masterHost, masterPort);\n        } catch (IOException e) {\n            logger.error(\"find slave position error\", e);\n        }\n\n        return null;\n    }\n\n    /**\n     * 根据给定的时间戳，在指定的binlog中找到最接近于该时间戳(必须是小于时间戳)的一个事务起始位置。\n     * 针对最后一个binlog会给定endPosition，避免无尽的查询\n     */\n    private EntryPosition findAsPerTimestampInSpecificLogFile(MysqlConnection mysqlConnection,\n                                                              final Long startTimestamp,\n                                                              final EntryPosition endPosition,\n                                                              final String searchBinlogFile,\n                                                              final Boolean justForPositionTimestamp) {\n\n        final LogPosition logPosition = new LogPosition();\n        try {\n            mysqlConnection.reconnect();\n            // 开始遍历文件\n            mysqlConnection.seek(searchBinlogFile, 4L, endPosition.getGtid(), new SinkFunction<LogEvent>() {\n\n                private LogPosition lastPosition;\n\n                public boolean sink(LogEvent event) {\n                    EntryPosition entryPosition = null;\n                    try {\n                        CanalEntry.Entry entry = parseAndProfilingIfNecessary(event, true);\n                        if (justForPositionTimestamp && logPosition.getPostion() == null && event.getWhen() > 0) {\n                            // 初始位点\n                            entryPosition = new EntryPosition(searchBinlogFile,\n                                event.getLogPos() - event.getEventLen(),\n                                event.getWhen() * 1000,\n                                event.getServerId());\n                            entryPosition.setGtid(event.getHeader().getGtidSetStr());\n                            logPosition.setPostion(entryPosition);\n                        }\n\n                        // 直接用event的位点来处理,解决一个binlog文件里没有任何事件导致死循环无法退出的问题\n                        String logfilename = event.getHeader().getLogFileName();\n                        // 记录的是binlog end offest,\n                        // 因为与其对比的offest是show master status里的end offest\n                        Long logfileoffset = event.getHeader().getLogPos();\n                        Long logposTimestamp = event.getHeader().getWhen() * 1000;\n                        Long serverId = event.getHeader().getServerId();\n\n                        // 如果最小的一条记录都不满足条件，可直接退出\n                        if (logposTimestamp >= startTimestamp) {\n                            return false;\n                        }\n\n                        if (StringUtils.equals(endPosition.getJournalName(), logfilename)\n                            && endPosition.getPosition() <= logfileoffset) {\n                            return false;\n                        }\n\n                        if (entry == null) {\n                            return true;\n                        }\n\n                        // 记录一下上一个事务结束的位置，即下一个事务的position\n                        // position = current +\n                        // data.length，代表该事务的下一条offest，避免多余的事务重复\n                        if (CanalEntry.EntryType.TRANSACTIONEND.equals(entry.getEntryType())) {\n                            entryPosition = new EntryPosition(logfilename, logfileoffset, logposTimestamp, serverId);\n                            if (logger.isDebugEnabled()) {\n                                logger.debug(\"set {} to be pending start position before finding another proper one...\",\n                                    entryPosition);\n                            }\n                            logPosition.setPostion(entryPosition);\n                            entryPosition.setGtid(entry.getHeader().getGtid());\n                        } else if (CanalEntry.EntryType.TRANSACTIONBEGIN.equals(entry.getEntryType())) {\n                            // 当前事务开始位点\n                            entryPosition = new EntryPosition(logfilename, logfileoffset, logposTimestamp, serverId);\n                            if (logger.isDebugEnabled()) {\n                                logger.debug(\"set {} to be pending start position before finding another proper one...\",\n                                    entryPosition);\n                            }\n                            entryPosition.setGtid(entry.getHeader().getGtid());\n                            logPosition.setPostion(entryPosition);\n                        }\n\n                        lastPosition = buildLastPosition(entry);\n                    } catch (Throwable e) {\n                        processSinkError(e, lastPosition, searchBinlogFile, 4L);\n                    }\n\n                    return running;\n                }\n            });\n\n        } catch (IOException e) {\n            logger.error(\"ERROR ## findAsPerTimestampInSpecificLogFile has an error\", e);\n        }\n\n        if (logPosition.getPostion() != null) {\n            return logPosition.getPostion();\n        } else {\n            return null;\n        }\n    }\n\n    @Override\n    protected void processDumpError(Throwable e) {\n        if (e instanceof IOException) {\n            String message = e.getMessage();\n            if (StringUtils.contains(message, \"errno = 1236\")) {\n                // 1236 errorCode代表ER_MASTER_FATAL_ERROR_READING_BINLOG\n                dumpErrorCount++;\n            }\n        }\n\n        super.processDumpError(e);\n    }\n\n    public void setSupportBinlogFormats(String formatStrs) {\n        String[] formats = StringUtils.split(formatStrs, ',');\n        if (formats != null) {\n            BinlogFormat[] supportBinlogFormats = new BinlogFormat[formats.length];\n            int i = 0;\n            for (String format : formats) {\n                supportBinlogFormats[i++] = BinlogFormat.valuesOf(format);\n            }\n\n            this.supportBinlogFormats = supportBinlogFormats;\n        }\n    }\n\n    public void setSupportBinlogImages(String imageStrs) {\n        String[] images = StringUtils.split(imageStrs, ',');\n        if (images != null) {\n            BinlogImage[] supportBinlogImages = new BinlogImage[images.length];\n            int i = 0;\n            for (String image : images) {\n                supportBinlogImages[i++] = BinlogImage.valuesOf(image);\n            }\n\n            this.supportBinlogImages = supportBinlogImages;\n        }\n    }\n\n    // ===================== setter / getter ========================\n\n    public void setDefaultConnectionTimeoutInSeconds(int defaultConnectionTimeoutInSeconds) {\n        this.defaultConnectionTimeoutInSeconds = defaultConnectionTimeoutInSeconds;\n    }\n\n    public void setReceiveBufferSize(int receiveBufferSize) {\n        this.receiveBufferSize = receiveBufferSize;\n    }\n\n    public void setSendBufferSize(int sendBufferSize) {\n        this.sendBufferSize = sendBufferSize;\n    }\n\n    public void setMasterInfo(AuthenticationInfo masterInfo) {\n        this.masterInfo = masterInfo;\n    }\n\n    public void setStandbyInfo(AuthenticationInfo standbyInfo) {\n        this.standbyInfo = standbyInfo;\n    }\n\n    public void setMasterPosition(EntryPosition masterPosition) {\n        this.masterPosition = masterPosition;\n    }\n\n    public void setStandbyPosition(EntryPosition standbyPosition) {\n        this.standbyPosition = standbyPosition;\n    }\n\n    public void setSlaveId(long slaveId) {\n        this.slaveId = slaveId;\n    }\n\n    public void setDetectingSQL(String detectingSQL) {\n        this.detectingSQL = detectingSQL;\n    }\n\n    public void setDetectingIntervalInSeconds(Integer detectingIntervalInSeconds) {\n        this.detectingIntervalInSeconds = detectingIntervalInSeconds;\n    }\n\n    public void setDetectingEnable(boolean detectingEnable) {\n        this.detectingEnable = detectingEnable;\n    }\n\n    public void setFallbackIntervalInSeconds(int fallbackIntervalInSeconds) {\n        this.fallbackIntervalInSeconds = fallbackIntervalInSeconds;\n    }\n\n    public CanalHAController getHaController() {\n        return haController;\n    }\n\n    public void setHaController(CanalHAController haController) {\n        this.haController = haController;\n    }\n\n    public void setDumpErrorCountThreshold(int dumpErrorCountThreshold) {\n        this.dumpErrorCountThreshold = dumpErrorCountThreshold;\n    }\n\n    public boolean isRdsOssMode() {\n        return rdsOssMode;\n    }\n\n    public void setRdsOssMode(boolean rdsOssMode) {\n        this.rdsOssMode = rdsOssMode;\n    }\n\n    public void setDumpErrorCount(int dumpErrorCount) {\n        this.dumpErrorCount = dumpErrorCount;\n    }\n\n    public boolean isAutoResetLatestPosMode() {\n        return autoResetLatestPosMode;\n    }\n\n    public void setAutoResetLatestPosMode(boolean autoResetLatestPosMode) {\n        this.autoResetLatestPosMode = autoResetLatestPosMode;\n    }\n\n    public void setMultiStreamEnable(boolean multiStreamEnable) {\n        this.multiStreamEnable = multiStreamEnable;\n    }\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/MysqlMultiStageCoprocessor.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql;\n\nimport java.util.List;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.concurrent.locks.LockSupport;\n\nimport org.apache.commons.compress.utils.Lists;\n\nimport com.alibaba.otter.canal.common.AbstractCanalLifeCycle;\nimport com.alibaba.otter.canal.common.utils.NamedThreadFactory;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.GTIDSet;\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\nimport com.alibaba.otter.canal.parse.inbound.ErosaConnection;\nimport com.alibaba.otter.canal.parse.inbound.EventTransactionBuffer;\nimport com.alibaba.otter.canal.parse.inbound.MultiStageCoprocessor;\nimport com.alibaba.otter.canal.parse.inbound.TableMeta;\nimport com.alibaba.otter.canal.parse.inbound.mysql.dbsync.LogEventConvert;\nimport com.alibaba.otter.canal.protocol.CanalEntry;\nimport com.lmax.disruptor.*;\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.LogContext;\nimport com.taobao.tddl.dbsync.binlog.LogDecoder;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.*;\n\n/**\n * 针对解析器提供一个多阶段协同的处理\n * \n * <pre>\n * 1. 网络接收 (单线程)\n * 2. 事件基本解析 (单线程，事件类型、DDL解析构造TableMeta、维护位点信息)\n * 3. 事件深度解析 (多线程, DML事件数据的完整解析)\n * 4. 投递到store (单线程)\n * </pre>\n * \n * @author agapple 2018年7月3日 下午4:54:17\n * @since 1.0.26\n */\npublic class MysqlMultiStageCoprocessor extends AbstractCanalLifeCycle implements MultiStageCoprocessor {\n\n    private static final int                  maxFullTimes    = 10;\n    private LogEventConvert                   logEventConvert;\n    private EventTransactionBuffer            transactionBuffer;\n    private ErosaConnection                   connection;\n\n    private int                               parserThreadCount;\n    private int                               ringBufferSize;\n    private RingBuffer<MessageEvent>          disruptorMsgBuffer;\n    private ExecutorService                   parserExecutor;\n    private ExecutorService                   stageExecutor;\n    private String                            destination;\n    private volatile CanalParseException      exception;\n    private AtomicLong                        eventsPublishBlockingTime;\n    private GTIDSet                           gtidSet;\n    private WorkerPool<MessageEvent>          workerPool;\n    private BatchEventProcessor<MessageEvent> simpleParserStage;\n    private BatchEventProcessor<MessageEvent> sinkStoreStage;\n    private LogContext                        logContext;\n    protected boolean                         filterDmlInsert = false;\n    protected boolean                         filterDmlUpdate = false;\n    protected boolean                         filterDmlDelete = false;\n\n    public MysqlMultiStageCoprocessor(int ringBufferSize, int parserThreadCount, LogEventConvert logEventConvert,\n                                      EventTransactionBuffer transactionBuffer, String destination,\n                                      boolean filterDmlInsert, boolean filterDmlUpdate, boolean filterDmlDelete){\n        this.ringBufferSize = ringBufferSize;\n        this.parserThreadCount = parserThreadCount;\n        this.logEventConvert = logEventConvert;\n        this.transactionBuffer = transactionBuffer;\n        this.destination = destination;\n        this.filterDmlInsert = filterDmlInsert;\n        this.filterDmlUpdate = filterDmlUpdate;\n        this.filterDmlDelete = filterDmlDelete;\n    }\n\n    @Override\n    public void start() {\n        super.start();\n        this.exception = null;\n        this.disruptorMsgBuffer = RingBuffer.createSingleProducer(new MessageEventFactory(),\n            ringBufferSize,\n            new BlockingWaitStrategy());\n        int tc = parserThreadCount > 0 ? parserThreadCount : 1;\n        this.parserExecutor = Executors.newFixedThreadPool(tc, new NamedThreadFactory(\"MultiStageCoprocessor-Parser-\"\n                                                                                      + destination));\n\n        this.stageExecutor = Executors.newFixedThreadPool(2, new NamedThreadFactory(\"MultiStageCoprocessor-other-\"\n                                                                                    + destination));\n        SequenceBarrier sequenceBarrier = disruptorMsgBuffer.newBarrier();\n        ExceptionHandler exceptionHandler = new SimpleFatalExceptionHandler();\n        // stage 2\n        this.logContext = new LogContext();\n        simpleParserStage = new BatchEventProcessor<>(disruptorMsgBuffer,\n            sequenceBarrier,\n            new SimpleParserStage(logContext));\n        simpleParserStage.setExceptionHandler(exceptionHandler);\n        disruptorMsgBuffer.addGatingSequences(simpleParserStage.getSequence());\n\n        // stage 3\n        SequenceBarrier dmlParserSequenceBarrier = disruptorMsgBuffer.newBarrier(simpleParserStage.getSequence());\n        WorkHandler<MessageEvent>[] workHandlers = new DmlParserStage[tc];\n        for (int i = 0; i < tc; i++) {\n            workHandlers[i] = new DmlParserStage();\n        }\n        workerPool = new WorkerPool<MessageEvent>(disruptorMsgBuffer,\n            dmlParserSequenceBarrier,\n            exceptionHandler,\n            workHandlers);\n        Sequence[] sequence = workerPool.getWorkerSequences();\n        disruptorMsgBuffer.addGatingSequences(sequence);\n\n        // stage 4\n        SequenceBarrier sinkSequenceBarrier = disruptorMsgBuffer.newBarrier(sequence);\n        sinkStoreStage = new BatchEventProcessor<>(disruptorMsgBuffer, sinkSequenceBarrier, new SinkStoreStage());\n        sinkStoreStage.setExceptionHandler(exceptionHandler);\n        disruptorMsgBuffer.addGatingSequences(sinkStoreStage.getSequence());\n\n        // start work\n        stageExecutor.submit(simpleParserStage);\n        stageExecutor.submit(sinkStoreStage);\n        workerPool.start(parserExecutor);\n    }\n\n    public void setBinlogChecksum(int binlogChecksum) {\n        if (binlogChecksum != LogEvent.BINLOG_CHECKSUM_ALG_OFF) {\n            logContext.setFormatDescription(new FormatDescriptionLogEvent(4, binlogChecksum));\n        }\n    }\n\n    public void setCompatiablePercona(boolean compatiablePercona) {\n        logContext.setCompatiablePercona(compatiablePercona);\n    }\n\n    @Override\n    public void stop() {\n        // fix bug #968，对于pool与\n        workerPool.halt();\n        simpleParserStage.halt();\n        sinkStoreStage.halt();\n        try {\n            parserExecutor.shutdownNow();\n            while (!parserExecutor.awaitTermination(1, TimeUnit.SECONDS)) {\n                if (parserExecutor.isShutdown() || parserExecutor.isTerminated()) {\n                    break;\n                }\n\n                parserExecutor.shutdownNow();\n            }\n        } catch (Throwable e) {\n            // ignore\n        }\n\n        try {\n            stageExecutor.shutdownNow();\n            while (!stageExecutor.awaitTermination(1, TimeUnit.SECONDS)) {\n                if (stageExecutor.isShutdown() || stageExecutor.isTerminated()) {\n                    break;\n                }\n\n                stageExecutor.shutdownNow();\n            }\n        } catch (Throwable e) {\n            // ignore\n        }\n        super.stop();\n    }\n\n    public boolean publish(LogBuffer buffer) {\n        return this.publish(buffer, null);\n    }\n\n    /**\n     * 网络数据投递\n     */\n    public boolean publish(LogEvent event) {\n        return this.publish(null, event);\n    }\n\n    private boolean publish(LogBuffer buffer, LogEvent event) {\n        if (!isStart()) {\n            if (exception != null) {\n                throw exception;\n            }\n            return false;\n        }\n\n        boolean interupted = false;\n        long blockingStart = 0L;\n        int fullTimes = 0;\n        do {\n            /**\n             * 由于改为processor仅终止自身stage而不是stop，那么需要由incident标识coprocessor是否正常工作。\n             * 让dump线程能够及时感知\n             */\n            if (exception != null) {\n                throw exception;\n            }\n            try {\n                long next = disruptorMsgBuffer.tryNext();\n                MessageEvent data = disruptorMsgBuffer.get(next);\n                if (buffer != null) {\n                    data.setBuffer(buffer);\n                } else {\n                    data.setEvent(event);\n                }\n                disruptorMsgBuffer.publish(next);\n                if (fullTimes > 0) {\n                    eventsPublishBlockingTime.addAndGet(System.nanoTime() - blockingStart);\n                }\n                break;\n            } catch (InsufficientCapacityException e) {\n                if (fullTimes == 0) {\n                    blockingStart = System.nanoTime();\n                }\n                // park\n                // LockSupport.parkNanos(1L);\n                applyWait(++fullTimes);\n                interupted = Thread.interrupted();\n                if (fullTimes % 1000 == 0) {\n                    long nextStart = System.nanoTime();\n                    eventsPublishBlockingTime.addAndGet(nextStart - blockingStart);\n                    blockingStart = nextStart;\n                }\n            }\n        } while (!interupted && isStart());\n        return isStart();\n    }\n\n    // 处理无数据的情况，避免空循环挂死\n    private void applyWait(int fullTimes) {\n        int newFullTimes = fullTimes > maxFullTimes ? maxFullTimes : fullTimes;\n        if (fullTimes <= 3) { // 3次以内\n            Thread.yield();\n        } else { // 超过3次，最多只sleep 1ms\n            LockSupport.parkNanos(100 * 1000L * newFullTimes);\n        }\n\n    }\n\n    private class SimpleParserStage implements EventHandler<MessageEvent>, LifecycleAware {\n\n        private LogDecoder decoder;\n        private LogContext context;\n\n        public SimpleParserStage(LogContext context){\n            decoder = new LogDecoder(LogEvent.UNKNOWN_EVENT, LogEvent.ENUM_END_EVENT);\n            this.context = context;\n            if (gtidSet != null) {\n                context.setGtidSet(gtidSet);\n            }\n        }\n\n        public void onEvent(MessageEvent event, long sequence, boolean endOfBatch) throws Exception {\n            try {\n                LogEvent logEvent = event.getEvent();\n                if (logEvent == null) {\n                    LogBuffer buffer = event.getBuffer();\n                    logEvent = decoder.decode(buffer, context);\n                    event.setEvent(logEvent);\n                }\n\n                int eventType = logEvent.getHeader().getType();\n                boolean needIterate = false;\n\n                if (eventType == LogEvent.TRANSACTION_PAYLOAD_EVENT) {\n                    // https://github.com/alibaba/canal/issues/4388\n                    List<LogEvent> deLogEvents = decoder.processIterateDecode(logEvent, context);\n                    List<TableMeta> tableMetas = Lists.newArrayList();\n                    event.setNeedIterate(true);\n                    for (LogEvent deLogEvent : deLogEvents) {\n                        TableMeta table = processEvent(deLogEvent, event);\n                        tableMetas.add(table);\n                    }\n                    event.setIterateEvents(deLogEvents);\n                    event.setIterateTables(tableMetas);\n                } else {\n                    TableMeta table = processEvent(logEvent, event);\n                    event.setTable(table);\n                }\n            } catch (Throwable e) {\n                exception = new CanalParseException(e);\n                throw exception;\n            }\n        }\n\n        private TableMeta processEvent(LogEvent logEvent, MessageEvent event) {\n            TableMeta tableMeta = null;\n            boolean needDmlParse = false;\n            int eventType = logEvent.getHeader().getType();\n            switch (eventType) {\n                case LogEvent.WRITE_ROWS_EVENT_V1:\n                case LogEvent.WRITE_ROWS_EVENT:\n                    if (!filterDmlInsert) {\n                        tableMeta = logEventConvert.parseRowsEventForTableMeta((WriteRowsLogEvent) logEvent);\n                        needDmlParse = true;\n                    }\n                    break;\n                case LogEvent.UPDATE_ROWS_EVENT_V1:\n                case LogEvent.PARTIAL_UPDATE_ROWS_EVENT:\n                case LogEvent.UPDATE_ROWS_EVENT:\n                    if (!filterDmlUpdate) {\n                        tableMeta = logEventConvert.parseRowsEventForTableMeta((UpdateRowsLogEvent) logEvent);\n                        needDmlParse = true;\n                    }\n                    break;\n                case LogEvent.DELETE_ROWS_EVENT_V1:\n                case LogEvent.DELETE_ROWS_EVENT:\n                    if (!filterDmlDelete) {\n                        tableMeta = logEventConvert.parseRowsEventForTableMeta((DeleteRowsLogEvent) logEvent);\n                        needDmlParse = true;\n                    }\n                    break;\n                case LogEvent.ROWS_QUERY_LOG_EVENT:\n                    needDmlParse = true;\n                    break;\n                default:\n                    CanalEntry.Entry entry = logEventConvert.parse(event.getEvent(), false);\n                    event.setEntry(entry);\n            }\n\n            // 记录一下DML的表结构\n            if (needDmlParse && !event.isNeedDmlParse()) {\n                event.setNeedDmlParse(true);\n            }\n            return tableMeta;\n        }\n\n        @Override\n        public void onStart() {\n\n        }\n\n        @Override\n        public void onShutdown() {\n\n        }\n    }\n\n    private class DmlParserStage implements WorkHandler<MessageEvent>, LifecycleAware {\n\n        @Override\n        public void onEvent(MessageEvent event) throws Exception {\n            try {\n                if (event.isNeedDmlParse()) {\n                    if (event.isNeedIterate()) {\n                        // compress binlog\n                        List<CanalEntry.Entry> entrys = Lists.newArrayList();\n                        for (int index = 0; index < event.getIterateEvents().size(); index++) {\n                            CanalEntry.Entry entry = processEvent(event.getIterateEvents().get(index),\n                                event.getIterateTables().get(index));\n                            if (entry != null) {\n                                entrys.add(entry);\n                            }\n                        }\n                        event.setIterateEntrys(entrys);\n                    } else {\n                        CanalEntry.Entry entry = processEvent(event.getEvent(), event.getTable());\n                        event.setEntry(entry);\n                    }\n                }\n            } catch (Throwable e) {\n                exception = new CanalParseException(e);\n                throw exception;\n            }\n        }\n\n        private CanalEntry.Entry processEvent(LogEvent logEvent, TableMeta table) {\n            int eventType = logEvent.getHeader().getType();\n            CanalEntry.Entry entry = null;\n            switch (eventType) {\n                case LogEvent.WRITE_ROWS_EVENT_V1:\n                case LogEvent.WRITE_ROWS_EVENT:\n                case LogEvent.UPDATE_ROWS_EVENT_V1:\n                case LogEvent.PARTIAL_UPDATE_ROWS_EVENT:\n                case LogEvent.UPDATE_ROWS_EVENT:\n                case LogEvent.DELETE_ROWS_EVENT_V1:\n                case LogEvent.DELETE_ROWS_EVENT:\n                    // 单独解析dml事件\n                    entry = logEventConvert.parseRowsEvent((RowsLogEvent) logEvent, table);\n                    break;\n                default:\n                    // 如果出现compress binlog,会出现其他的event type类型\n                    entry = logEventConvert.parse(logEvent, false);\n                    break;\n            }\n\n            return entry;\n        }\n\n        @Override\n        public void onStart() {\n\n        }\n\n        @Override\n        public void onShutdown() {\n\n        }\n    }\n\n    private class SinkStoreStage implements EventHandler<MessageEvent>, LifecycleAware {\n\n        public void onEvent(MessageEvent event, long sequence, boolean endOfBatch) throws Exception {\n            try {\n                if (event.isNeedIterate()) {\n                    // compress binlog\n                    for (CanalEntry.Entry entry : event.getIterateEntrys()) {\n                        transactionBuffer.add(entry);\n                    }\n                } else {\n                    if (event.getEntry() != null) {\n                        transactionBuffer.add(event.getEntry());\n                    }\n                }\n\n                LogEvent logEvent = event.getEvent();\n                if (connection instanceof MysqlConnection && logEvent.getSemival() == 1) {\n                    // semi ack回报\n                    ((MysqlConnection) connection).sendSemiAck(logEvent.getHeader().getLogFileName(),\n                        logEvent.getHeader().getLogPos());\n                }\n\n                // clear for gc\n                event.setBuffer(null);\n                event.setEvent(null);\n                event.setTable(null);\n                event.setEntry(null);\n                // clear compress binlog events\n                event.setNeedDmlParse(false);\n                event.setNeedIterate(false);\n                event.setIterateEntrys(null);\n                event.setIterateTables(null);\n                event.setIterateEvents(null);\n            } catch (Throwable e) {\n                exception = new CanalParseException(e);\n                throw exception;\n            }\n        }\n\n        @Override\n        public void onStart() {\n\n        }\n\n        @Override\n        public void onShutdown() {\n\n        }\n    }\n\n    static class MessageEvent {\n\n        private LogBuffer        buffer;\n        private CanalEntry.Entry entry;\n        private boolean          needDmlParse = false;\n        private TableMeta        table;\n        private LogEvent         event;\n        private boolean                needIterate  = false;\n        // compress binlog\n        private List<LogEvent>         iterateEvents;\n        private List<TableMeta>        iterateTables;\n        private List<CanalEntry.Entry> iterateEntrys;\n\n        public LogBuffer getBuffer() {\n            return buffer;\n        }\n\n        public void setBuffer(LogBuffer buffer) {\n            this.buffer = buffer;\n        }\n\n        public LogEvent getEvent() {\n            return event;\n        }\n\n        public void setEvent(LogEvent event) {\n            this.event = event;\n        }\n\n        public CanalEntry.Entry getEntry() {\n            return entry;\n        }\n\n        public void setEntry(CanalEntry.Entry entry) {\n            this.entry = entry;\n        }\n\n        public boolean isNeedDmlParse() {\n            return needDmlParse;\n        }\n\n        public void setNeedDmlParse(boolean needDmlParse) {\n            this.needDmlParse = needDmlParse;\n        }\n\n        public TableMeta getTable() {\n            return table;\n        }\n\n        public void setTable(TableMeta table) {\n            this.table = table;\n        }\n\n        public boolean isNeedIterate() {\n            return needIterate;\n        }\n\n        public void setNeedIterate(boolean needIterate) {\n            this.needIterate = needIterate;\n        }\n\n        public List<LogEvent> getIterateEvents() {\n            return iterateEvents;\n        }\n\n        public List<TableMeta> getIterateTables() {\n            return iterateTables;\n        }\n\n        public void setIterateEvents(List<LogEvent> iterateEvents) {\n            this.iterateEvents = iterateEvents;\n        }\n\n        public void setIterateTables(List<TableMeta> iterateTables) {\n            this.iterateTables = iterateTables;\n        }\n\n        public List<CanalEntry.Entry> getIterateEntrys() {\n            return iterateEntrys;\n        }\n\n        public void setIterateEntrys(List<CanalEntry.Entry> iterateEntrys) {\n            this.iterateEntrys = iterateEntrys;\n        }\n    }\n\n    static class SimpleFatalExceptionHandler implements ExceptionHandler {\n\n        @Override\n        public void handleEventException(final Throwable ex, final long sequence, final Object event) {\n            // 异常上抛，否则processEvents的逻辑会默认会mark为成功执行，有丢数据风险\n            throw new CanalParseException(ex);\n        }\n\n        @Override\n        public void handleOnStartException(final Throwable ex) {\n        }\n\n        @Override\n        public void handleOnShutdownException(final Throwable ex) {\n        }\n    }\n\n    static class MessageEventFactory implements EventFactory<MessageEvent> {\n\n        public MessageEvent newInstance() {\n            return new MessageEvent();\n        }\n    }\n\n    public void setLogEventConvert(LogEventConvert logEventConvert) {\n        this.logEventConvert = logEventConvert;\n    }\n\n    public void setTransactionBuffer(EventTransactionBuffer transactionBuffer) {\n        this.transactionBuffer = transactionBuffer;\n    }\n\n    public void setConnection(ErosaConnection connection) {\n        this.connection = connection;\n    }\n\n    public void setEventsPublishBlockingTime(AtomicLong eventsPublishBlockingTime) {\n        this.eventsPublishBlockingTime = eventsPublishBlockingTime;\n    }\n\n    public void setGtidSet(GTIDSet gtidSet) {\n        this.gtidSet = gtidSet;\n    }\n\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/SlaveEntryPosition.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql;\n\nimport com.alibaba.otter.canal.protocol.position.EntryPosition;\n\n/**\n * slave status状态的信息\n * \n * @author jianghang 2013-1-23 下午09:42:18\n * @version 1.0.0\n */\npublic class SlaveEntryPosition extends EntryPosition {\n\n    private static final long serialVersionUID = 5271424551446372093L;\n    private final String      masterHost;\n    private final String      masterPort;\n\n    public SlaveEntryPosition(String fileName, long position, String masterHost, String masterPort){\n        super(fileName, position);\n\n        this.masterHost = masterHost;\n        this.masterPort = masterPort;\n    }\n\n    public String getMasterHost() {\n        return masterHost;\n    }\n\n    public String getMasterPort() {\n        return masterPort;\n    }\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/dbsync/DirectLogFetcher.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.dbsync;\n\nimport java.io.IOException;\nimport java.io.InterruptedIOException;\nimport java.net.SocketTimeoutException;\nimport java.nio.channels.ClosedByInterruptException;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.socket.SocketChannel;\nimport com.alibaba.otter.canal.parse.exception.ServerLogPurgedException;\nimport com.taobao.tddl.dbsync.binlog.LogFetcher;\n\n/**\n * 基于socket的logEvent实现\n * \n * @author jianghang 2013-1-14 下午07:39:30\n * @version 1.0.0\n */\npublic class DirectLogFetcher extends LogFetcher {\n\n    protected static final Logger logger                          = LoggerFactory.getLogger(DirectLogFetcher.class);\n\n    // Master heartbeat interval\n    public static final int       MASTER_HEARTBEAT_PERIOD_SECONDS = 15;\n    // +10s 确保 timeout > heartbeat interval\n    private static final int      READ_TIMEOUT_MILLISECONDS       = (MASTER_HEARTBEAT_PERIOD_SECONDS + 10) * 1000;\n\n    /** Command to dump binlog */\n    public static final byte      COM_BINLOG_DUMP                 = 18;\n\n    /** Packet header sizes */\n    public static final int       NET_HEADER_SIZE                 = 4;\n    public static final int       SQLSTATE_LENGTH                 = 5;\n\n    /** Packet offsets */\n    public static final int       PACKET_LEN_OFFSET               = 0;\n    public static final int       PACKET_SEQ_OFFSET               = 3;\n\n    /** Maximum packet length */\n    public static final int       MAX_PACKET_LENGTH               = (256 * 256 * 256 - 1);\n\n    private SocketChannel         channel;\n\n    private boolean               issemi                          = false;\n\n    // private BufferedInputStream input;\n\n    public DirectLogFetcher(){\n        super(DEFAULT_INITIAL_CAPACITY, DEFAULT_GROWTH_FACTOR);\n    }\n\n    public DirectLogFetcher(final int initialCapacity){\n        super(initialCapacity, DEFAULT_GROWTH_FACTOR);\n    }\n\n    public DirectLogFetcher(final int initialCapacity, final float growthFactor){\n        super(initialCapacity, growthFactor);\n    }\n\n    public void start(SocketChannel channel) throws IOException {\n        this.channel = channel;\n        String dbsemi = System.getProperty(\"db.semi\");\n        if (\"1\".equals(dbsemi)) {\n            issemi = true;\n        }\n    }\n\n    /**\n     * {@inheritDoc}\n     * \n     * @see com.taobao.tddl.dbsync.binlog.LogFetcher#fetch()\n     */\n    public boolean fetch() throws IOException {\n        try {\n            // Fetching packet header from input.\n            if (!fetch0(0, NET_HEADER_SIZE)) {\n                logger.warn(\"Reached end of input stream while fetching header\");\n                return false;\n            }\n\n            // Fetching the first packet(may a multi-packet).\n            int netlen = getUint24(PACKET_LEN_OFFSET);\n            int netnum = getUint8(PACKET_SEQ_OFFSET);\n            if (!fetch0(NET_HEADER_SIZE, netlen)) {\n                logger.warn(\"Reached end of input stream: packet #\" + netnum + \", len = \" + netlen);\n                return false;\n            }\n\n            // Detecting error code.\n            final int mark = getUint8(NET_HEADER_SIZE);\n            if (mark != 0) {\n                if (mark == 255) // error from master\n                {\n                    // Indicates an error, for example trying to fetch from\n                    // wrong\n                    // binlog position.\n                    position = NET_HEADER_SIZE + 1;\n                    final int errno = getInt16();\n                    String sqlstate = forward(1).getFixString(SQLSTATE_LENGTH);\n                    String errmsg = getFixString(limit - position);\n                    if (StringUtils.containsIgnoreCase(errmsg, \"not find first log file name\")\n                        || StringUtils.containsIgnoreCase(errmsg, \"purged binary logs\")) {\n                        // 开始 dump 后，server 位点过期，DUMP 和 DUMP_GTID 两种错误信息\n                        throw new ServerLogPurgedException(\n                            \" errno = \" + errno + \", sqlstate = \" + sqlstate + \" errmsg = \" + errmsg);\n                    }\n\n                    throw new IOException(\"Received error packet:\" + \" errno = \" + errno + \", sqlstate = \" + sqlstate\n                                          + \" errmsg = \" + errmsg);\n                } else if (mark == 254) {\n                    // Indicates end of stream. It's not clear when this would\n                    // be sent.\n                    logger.warn(\"Received EOF packet from server, apparent\"\n                                + \" master disconnected. It's may be duplicate slaveId , check instance config\");\n                    return false;\n                } else {\n                    // Should not happen.\n                    throw new IOException(\"Unexpected response \" + mark + \" while fetching binlog: packet #\" + netnum\n                                          + \", len = \" + netlen);\n                }\n            }\n\n            // if mysql is in semi mode\n            if (issemi) {\n                // parse semi mark\n                int semimark = getUint8(NET_HEADER_SIZE + 1);\n                int semival = getUint8(NET_HEADER_SIZE + 2);\n                this.semival = semival;\n            }\n\n            // The first packet is a multi-packet, concatenate the packets.\n            while (netlen == MAX_PACKET_LENGTH) {\n                if (!fetch0(0, NET_HEADER_SIZE)) {\n                    logger.warn(\"Reached end of input stream while fetching header\");\n                    return false;\n                }\n\n                netlen = getUint24(PACKET_LEN_OFFSET);\n                netnum = getUint8(PACKET_SEQ_OFFSET);\n                if (!fetch0(limit, netlen)) {\n                    logger.warn(\"Reached end of input stream: packet #\" + netnum + \", len = \" + netlen);\n                    return false;\n                }\n            }\n\n            // Preparing buffer variables to decoding.\n            if (issemi) {\n                origin = NET_HEADER_SIZE + 3;\n            } else {\n                origin = NET_HEADER_SIZE + 1;\n            }\n            position = origin;\n            limit -= origin;\n            return true;\n        } catch (SocketTimeoutException e) {\n            close(); /* Do cleanup */\n            logger.error(\"Socket timeout expired, closing connection\", e);\n            throw e;\n        } catch (InterruptedIOException | ClosedByInterruptException e) {\n            close(); /* Do cleanup */\n            logger.info(\"I/O interrupted while reading from client socket\", e);\n            throw e;\n        } catch (IOException e) {\n            close(); /* Do cleanup */\n            logger.error(\"I/O error while reading from client socket\", e);\n            throw e;\n        }\n    }\n\n    private final boolean fetch0(final int off, final int len) throws IOException {\n        ensureCapacity(off + len);\n\n        // byte[] read = channel.read(len, READ_TIMEOUT_MILLISECONDS);\n        // System.arraycopy(read, 0, this.buffer, off, len);\n\n        channel.read(buffer, off, len, READ_TIMEOUT_MILLISECONDS);\n        if (limit < off + len) {\n            limit = off + len;\n        }\n        return true;\n    }\n\n    /**\n     * {@inheritDoc}\n     * \n     * @see com.taobao.tddl.dbsync.binlog.LogFetcher#close()\n     */\n    public void close() throws IOException {\n        // do nothing\n    }\n\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/dbsync/LogEventConvert.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.dbsync;\n\nimport java.io.Serializable;\nimport java.io.UnsupportedEncodingException;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.nio.charset.Charset;\nimport java.sql.Types;\nimport java.util.Arrays;\nimport java.util.BitSet;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.taobao.tddl.dbsync.binlog.event.*;\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.commons.lang.exception.ExceptionUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.common.AbstractCanalLifeCycle;\nimport com.alibaba.otter.canal.filter.aviater.AviaterRegexFilter;\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\nimport com.alibaba.otter.canal.parse.inbound.BinlogParser;\nimport com.alibaba.otter.canal.parse.inbound.TableMeta;\nimport com.alibaba.otter.canal.parse.inbound.TableMeta.FieldMeta;\nimport com.alibaba.otter.canal.parse.inbound.mysql.ddl.DdlResult;\nimport com.alibaba.otter.canal.parse.inbound.mysql.ddl.DruidDdlParser;\nimport com.alibaba.otter.canal.parse.inbound.mysql.ddl.SimpleDdlParser;\nimport com.alibaba.otter.canal.protocol.CanalEntry.Column;\nimport com.alibaba.otter.canal.protocol.CanalEntry.Entry;\nimport com.alibaba.otter.canal.protocol.CanalEntry.EntryType;\nimport com.alibaba.otter.canal.protocol.CanalEntry.EventType;\nimport com.alibaba.otter.canal.protocol.CanalEntry.Header;\nimport com.alibaba.otter.canal.protocol.CanalEntry.Pair;\nimport com.alibaba.otter.canal.protocol.CanalEntry.RowChange;\nimport com.alibaba.otter.canal.protocol.CanalEntry.RowData;\nimport com.alibaba.otter.canal.protocol.CanalEntry.TransactionBegin;\nimport com.alibaba.otter.canal.protocol.CanalEntry.TransactionEnd;\nimport com.alibaba.otter.canal.protocol.CanalEntry.Type;\nimport com.alibaba.otter.canal.protocol.position.EntryPosition;\nimport com.google.protobuf.ByteString;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.TableMapLogEvent.ColumnInfo;\nimport com.taobao.tddl.dbsync.binlog.event.mariadb.AnnotateRowsEvent;\nimport com.taobao.tddl.dbsync.binlog.event.mariadb.MariaGtidListLogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.mariadb.MariaGtidLogEvent;\nimport com.taobao.tddl.dbsync.binlog.exception.TableIdNotFoundException;\n\n/**\n * 基于{@linkplain LogEvent}转化为Entry对象的处理\n * \n * @author jianghang 2013-1-17 下午02:41:14\n * @version 1.0.0\n */\npublic class LogEventConvert extends AbstractCanalLifeCycle implements BinlogParser<LogEvent> {\n\n    public static final String          XA_XID              = \"XA_XID\";\n    public static final String          XA_TYPE             = \"XA_TYPE\";\n    public static final String          XA_START            = \"XA START\";\n    public static final String          XA_END              = \"XA END\";\n    public static final String          XA_COMMIT           = \"XA COMMIT\";\n    public static final String          XA_ROLLBACK         = \"XA ROLLBACK\";\n    public static final String          ISO_8859_1          = \"ISO-8859-1\";\n    public static final String          UTF_8               = \"UTF-8\";\n    public static final int             TINYINT_MAX_VALUE   = 256;\n    public static final int             SMALLINT_MAX_VALUE  = 65536;\n    public static final int             MEDIUMINT_MAX_VALUE = 16777216;\n    public static final long            INTEGER_MAX_VALUE   = 4294967296L;\n    public static final BigInteger      BIGINT_MAX_VALUE    = new BigInteger(\"18446744073709551616\");\n    public static final int             version             = 1;\n    public static final String          BEGIN               = \"BEGIN\";\n    public static final String          COMMIT              = \"COMMIT\";\n    public static final Logger          logger              = LoggerFactory.getLogger(LogEventConvert.class);\n\n    private volatile AviaterRegexFilter nameFilter;                                                          // 运行时引用可能会有变化，比如规则发生变化时\n    private volatile AviaterRegexFilter nameBlackFilter;\n    private Map<String, List<String>>   fieldFilterMap      = new HashMap<>();\n    private Map<String, List<String>>   fieldBlackFilterMap = new HashMap<>();\n\n    private TableMetaCache              tableMetaCache;\n    private Charset                     charset             = Charset.defaultCharset();\n    private boolean                     filterQueryDcl      = false;\n    private boolean                     filterQueryDml      = false;\n    private boolean                     filterQueryDdl      = false;\n    // 是否跳过table相关的解析异常,比如表不存在或者列数量不匹配,issue 92\n    private boolean                     filterTableError    = false;\n    // 新增rows过滤，用于仅订阅除rows以外的数据\n    private boolean                     filterRows          = false;\n    private boolean                     useDruidDdlFilter   = true;\n\n    public LogEventConvert(){\n\n    }\n\n    @Override\n    public Entry parse(LogEvent logEvent, boolean isSeek) throws CanalParseException {\n        if (logEvent == null || logEvent instanceof UnknownLogEvent) {\n            return null;\n        }\n\n        int eventType = logEvent.getHeader().getType();\n        switch (eventType) {\n            case LogEvent.QUERY_EVENT:\n                return parseQueryEvent((QueryLogEvent) logEvent, isSeek);\n            case LogEvent.XID_EVENT:\n                return parseXidEvent((XidLogEvent) logEvent);\n            case LogEvent.TABLE_MAP_EVENT:\n                parseTableMapEvent((TableMapLogEvent) logEvent);\n                break;\n            case LogEvent.WRITE_ROWS_EVENT_V1:\n            case LogEvent.WRITE_ROWS_EVENT:\n                return parseRowsEvent((WriteRowsLogEvent) logEvent);\n            case LogEvent.UPDATE_ROWS_EVENT_V1:\n            case LogEvent.PARTIAL_UPDATE_ROWS_EVENT:\n            case LogEvent.UPDATE_ROWS_EVENT:\n                return parseRowsEvent((UpdateRowsLogEvent) logEvent);\n            case LogEvent.DELETE_ROWS_EVENT_V1:\n            case LogEvent.DELETE_ROWS_EVENT:\n                return parseRowsEvent((DeleteRowsLogEvent) logEvent);\n            case LogEvent.ROWS_QUERY_LOG_EVENT:\n                return parseRowsQueryEvent((RowsQueryLogEvent) logEvent);\n            case LogEvent.ANNOTATE_ROWS_EVENT:\n                return parseAnnotateRowsEvent((AnnotateRowsEvent) logEvent);\n            case LogEvent.USER_VAR_EVENT:\n                return parseUserVarLogEvent((UserVarLogEvent) logEvent);\n            case LogEvent.INTVAR_EVENT:\n                return parseIntrvarLogEvent((IntvarLogEvent) logEvent);\n            case LogEvent.RAND_EVENT:\n                return parseRandLogEvent((RandLogEvent) logEvent);\n            case LogEvent.GTID_LOG_EVENT:\n                return parseGTIDLogEvent((GtidLogEvent) logEvent);\n            case LogEvent.HEARTBEAT_LOG_EVENT:\n                return parseHeartbeatLogEvent((HeartbeatLogEvent) logEvent);\n            case LogEvent.HEARTBEAT_LOG_EVENT_V2:\n                return parseHeartbeatV2LogEvent((HeartbeatV2LogEvent) logEvent);\n            case LogEvent.GTID_EVENT:\n            case LogEvent.GTID_LIST_EVENT:\n                return parseMariaGTIDLogEvent(logEvent);\n            default:\n                break;\n        }\n\n        return null;\n    }\n\n    public void reset() {\n        // do nothing\n        if (tableMetaCache != null) {\n            tableMetaCache.clearTableMeta();\n        }\n    }\n\n    private Entry parseHeartbeatLogEvent(HeartbeatLogEvent logEvent) {\n        Header.Builder headerBuilder = Header.newBuilder();\n        headerBuilder.setEventType(EventType.MHEARTBEAT);\n        Entry.Builder entryBuilder = Entry.newBuilder();\n        entryBuilder.setHeader(headerBuilder.build());\n        entryBuilder.setEntryType(EntryType.HEARTBEAT);\n        return entryBuilder.build();\n    }\n\n    private Entry parseHeartbeatV2LogEvent(HeartbeatV2LogEvent logEvent) {\n        Header.Builder headerBuilder = Header.newBuilder();\n        headerBuilder.setEventType(EventType.MHEARTBEAT);\n        Entry.Builder entryBuilder = Entry.newBuilder();\n        entryBuilder.setHeader(headerBuilder.build());\n        entryBuilder.setEntryType(EntryType.HEARTBEAT);\n        return entryBuilder.build();\n    }\n\n    private Entry parseGTIDLogEvent(GtidLogEvent logEvent) {\n        LogHeader logHeader = logEvent.getHeader();\n        Pair.Builder builder = Pair.newBuilder();\n        builder.setKey(\"gtid\");\n        builder.setValue(logEvent.getGtidStr());\n\n        if (logEvent.getLastCommitted() != -1) {\n            builder.setKey(\"lastCommitted\");\n            builder.setValue(String.valueOf(logEvent.getLastCommitted()));\n            builder.setKey(\"sequenceNumber\");\n            builder.setValue(String.valueOf(logEvent.getSequenceNumber()));\n        }\n\n        Header header = createHeader(logHeader, \"\", \"\", EventType.GTID);\n        return createEntry(header, EntryType.GTIDLOG, builder.build().toByteString());\n    }\n\n    private Entry parseMariaGTIDLogEvent(LogEvent logEvent) {\n        LogHeader logHeader = logEvent.getHeader();\n        Pair.Builder builder = Pair.newBuilder();\n        builder.setKey(\"gtid\");\n        if (logEvent instanceof MariaGtidLogEvent) {\n            builder.setValue(((MariaGtidLogEvent) logEvent).getGtidStr());\n        } else if (logEvent instanceof MariaGtidListLogEvent) {\n            builder.setValue(((MariaGtidListLogEvent) logEvent).getGtidStr());\n        }\n        Header header = createHeader(logHeader, \"\", \"\", EventType.GTID);\n        return createEntry(header, EntryType.GTIDLOG, builder.build().toByteString());\n    }\n\n    private Entry parseQueryEvent(QueryLogEvent event, boolean isSeek) {\n        String queryString = event.getQuery();\n        if (StringUtils.startsWithIgnoreCase(queryString, XA_START)) {\n            // xa start use TransactionBegin\n            TransactionBegin.Builder beginBuilder = TransactionBegin.newBuilder();\n            beginBuilder.setThreadId(event.getSessionId());\n            beginBuilder.addProps(createSpecialPair(XA_TYPE, XA_START));\n            beginBuilder.addProps(createSpecialPair(XA_XID, getXaXid(queryString, XA_START)));\n            TransactionBegin transactionBegin = beginBuilder.build();\n            Header header = createHeader(event.getHeader(), \"\", \"\", null);\n            return createEntry(header, EntryType.TRANSACTIONBEGIN, transactionBegin.toByteString());\n        } else if (StringUtils.startsWithIgnoreCase(queryString, XA_END)) {\n            // xa start use TransactionEnd\n            TransactionEnd.Builder endBuilder = TransactionEnd.newBuilder();\n            endBuilder.setTransactionId(String.valueOf(0L));\n            endBuilder.addProps(createSpecialPair(XA_TYPE, XA_END));\n            endBuilder.addProps(createSpecialPair(XA_XID, getXaXid(queryString, XA_END)));\n            TransactionEnd transactionEnd = endBuilder.build();\n            Header header = createHeader(event.getHeader(), \"\", \"\", null);\n            return createEntry(header, EntryType.TRANSACTIONEND, transactionEnd.toByteString());\n        } else if (StringUtils.startsWithIgnoreCase(queryString, XA_COMMIT)) {\n            // xa commit\n            Header header = createHeader(event.getHeader(), \"\", \"\", EventType.XACOMMIT);\n            RowChange.Builder rowChangeBuider = RowChange.newBuilder();\n            rowChangeBuider.setSql(queryString);\n            rowChangeBuider.addProps(createSpecialPair(XA_TYPE, XA_COMMIT));\n            rowChangeBuider.addProps(createSpecialPair(XA_XID, getXaXid(queryString, XA_COMMIT)));\n            rowChangeBuider.setEventType(EventType.XACOMMIT);\n            return createEntry(header, EntryType.ROWDATA, rowChangeBuider.build().toByteString());\n        } else if (StringUtils.startsWithIgnoreCase(queryString, XA_ROLLBACK)) {\n            // xa rollback\n            Header header = createHeader(event.getHeader(), \"\", \"\", EventType.XAROLLBACK);\n            RowChange.Builder rowChangeBuider = RowChange.newBuilder();\n            rowChangeBuider.setSql(queryString);\n            rowChangeBuider.addProps(createSpecialPair(XA_TYPE, XA_ROLLBACK));\n            rowChangeBuider.addProps(createSpecialPair(XA_XID, getXaXid(queryString, XA_ROLLBACK)));\n            rowChangeBuider.setEventType(EventType.XAROLLBACK);\n            return createEntry(header, EntryType.ROWDATA, rowChangeBuider.build().toByteString());\n        } else if (StringUtils.endsWithIgnoreCase(queryString, BEGIN)) {\n            TransactionBegin transactionBegin = createTransactionBegin(event.getSessionId());\n            Header header = createHeader(event.getHeader(), \"\", \"\", null);\n            return createEntry(header, EntryType.TRANSACTIONBEGIN, transactionBegin.toByteString());\n        } else if (StringUtils.endsWithIgnoreCase(queryString, COMMIT)) {\n            TransactionEnd transactionEnd = createTransactionEnd(0L); // MyISAM可能不会有xid事件\n            Header header = createHeader(event.getHeader(), \"\", \"\", null);\n            return createEntry(header, EntryType.TRANSACTIONEND, transactionEnd.toByteString());\n        } else {\n            boolean notFilter = false;\n            EventType type = EventType.QUERY;\n            String tableName = null;\n            String schemaName = null;\n            if (useDruidDdlFilter) {\n                List<DdlResult> results = DruidDdlParser.parse(queryString, event.getDbName());\n                for (DdlResult result : results) {\n                    if (!processFilter(queryString, result)) {\n                        // 只要有一个数据不进行过滤\n                        notFilter = true;\n                    }\n                }\n                if (results.size() > 0) {\n                    // 如果针对多行的DDL,只能取第一条\n                    type = results.get(0).getType();\n                    schemaName = results.get(0).getSchemaName();\n                    tableName = results.get(0).getTableName();\n                }\n            } else {\n                DdlResult result = SimpleDdlParser.parse(queryString, event.getDbName());\n                if (!processFilter(queryString, result)) {\n                    notFilter = true;\n                }\n\n                type = result.getType();\n                schemaName = result.getSchemaName();\n                tableName = result.getTableName();\n            }\n\n            if (!notFilter) {\n                // 如果是过滤的数据就不处理了\n                return null;\n            }\n\n            boolean isDml = (type == EventType.INSERT || type == EventType.UPDATE || type == EventType.DELETE);\n\n            // filterQueryDdl=true的情况下,也得更新tablemeta\n            if (!isSeek && !isDml) {\n                // 使用新的表结构元数据管理方式\n                EntryPosition position = createPosition(event.getHeader());\n                tableMetaCache.apply(position, event.getDbName(), queryString, null);\n            }\n\n            if (filterQueryDdl) {\n                // 全部DDL过滤,那就忽略事件生成\n                return null;\n            }\n\n            Header header = createHeader(event.getHeader(), schemaName, tableName, type);\n            RowChange.Builder rowChangeBuilder = RowChange.newBuilder();\n            rowChangeBuilder.setIsDdl(!isDml);\n            rowChangeBuilder.setSql(queryString);\n            if (StringUtils.isNotEmpty(event.getDbName())) {// 可能为空\n                rowChangeBuilder.setDdlSchemaName(event.getDbName());\n            }\n            rowChangeBuilder.setEventType(type);\n            return createEntry(header, EntryType.ROWDATA, rowChangeBuilder.build().toByteString());\n        }\n    }\n\n    private String getXaXid(String queryString, String type) {\n        return StringUtils.substringAfter(queryString, type);\n    }\n\n    private boolean processFilter(String queryString, DdlResult result) {\n        String schemaName = result.getSchemaName();\n        String tableName = result.getTableName();\n        // fixed issue https://github.com/alibaba/canal/issues/58\n        // 更新下table meta cache\n        if (tableMetaCache != null\n            && (result.getType() == EventType.ALTER || result.getType() == EventType.ERASE || result.getType() == EventType.RENAME)) {\n            // 对外返回，保证兼容，还是返回QUERY类型，这里暂不解析tableName，所以无法支持过滤\n            for (DdlResult renameResult = result; renameResult != null; renameResult = renameResult.getRenameTableResult()) {\n                String schemaName0 = renameResult.getSchemaName();\n                String tableName0 = renameResult.getTableName();\n                if (StringUtils.isNotEmpty(tableName0)) {\n                    // 如果解析到了正确的表信息，则根据全名进行清除\n                    tableMetaCache.clearTableMeta(schemaName0, tableName0);\n                } else {\n                    // 如果无法解析正确的表信息，则根据schema进行清除\n                    tableMetaCache.clearTableMetaWithSchemaName(schemaName0);\n                }\n            }\n        }\n\n        // fixed issue https://github.com/alibaba/canal/issues/58\n        if (result.getType() == EventType.ALTER || result.getType() == EventType.ERASE\n            || result.getType() == EventType.CREATE || result.getType() == EventType.TRUNCATE\n            || result.getType() == EventType.RENAME || result.getType() == EventType.CINDEX\n            || result.getType() == EventType.DINDEX) { // 针对DDL类型\n\n            if (!filterQueryDdl && (StringUtils.isEmpty(tableName)\n                || (result.getType() == EventType.RENAME && StringUtils.isEmpty(result.getOriTableName())))) {\n                // 如果解析不出tableName,记录一下日志，方便bugfix，目前直接抛出异常，中断解析\n                throw new CanalParseException(\"SimpleDdlParser process query failed. pls submit issue with this queryString: \"\n                                              + queryString + \" , and DdlResult: \" + result.toString());\n                // return null;\n            } else {\n                // check name filter\n                String name = schemaName + \".\" + tableName;\n                if (nameFilter != null && !nameFilter.filter(name)) {\n                    if (result.getType() == EventType.RENAME) {\n                        // rename校验只要源和目标满足一个就进行操作\n                        if (nameFilter != null\n                            && !nameFilter.filter(result.getOriSchemaName() + \".\" + result.getOriTableName())) {\n                            return true;\n                        }\n                    } else {\n                        // 其他情况返回null\n                        return true;\n                    }\n                }\n\n                if (nameBlackFilter != null && nameBlackFilter.filter(name)) {\n                    if (result.getType() == EventType.RENAME) {\n                        // rename校验只要源和目标满足一个就进行操作\n                        if (nameBlackFilter != null\n                            && nameBlackFilter.filter(result.getOriSchemaName() + \".\" + result.getOriTableName())) {\n                            return true;\n                        }\n                    } else {\n                        // 其他情况返回null\n                        return true;\n                    }\n                }\n            }\n        } else if (result.getType() == EventType.INSERT || result.getType() == EventType.UPDATE\n                   || result.getType() == EventType.DELETE) {\n            // 对外返回，保证兼容，还是返回QUERY类型，这里暂不解析tableName，所以无法支持过滤\n            if (filterQueryDml) {\n                return true;\n            }\n        } else if (filterQueryDcl) {\n            return true;\n        }\n\n        return false;\n    }\n\n    private Entry parseRowsQueryEvent(RowsQueryLogEvent event) {\n        if (filterQueryDml) {\n            return null;\n        }\n        // mysql5.6支持，需要设置binlog-rows-query-log-events=1，可详细打印原始DML语句\n        String queryString = null;\n        try {\n            queryString = new String(event.getRowsQuery().getBytes(ISO_8859_1), charset);\n            String tableName = null;\n            if (useDruidDdlFilter) {\n                List<DdlResult> results = DruidDdlParser.parse(queryString, null);\n                if (results.size() > 0) {\n                    tableName = results.get(0).getTableName();\n                }\n            }\n\n            return buildQueryEntry(queryString, event.getHeader(), tableName);\n        } catch (UnsupportedEncodingException e) {\n            throw new CanalParseException(e);\n        }\n    }\n\n    private Entry parseAnnotateRowsEvent(AnnotateRowsEvent event) {\n        if (filterQueryDml) {\n            return null;\n        }\n        // mariaDb支持，需要设置binlog_annotate_row_events=true，可详细打印原始DML语句\n        String queryString = null;\n        try {\n            queryString = new String(event.getRowsQuery().getBytes(ISO_8859_1), charset);\n            return buildQueryEntry(queryString, event.getHeader());\n        } catch (UnsupportedEncodingException e) {\n            throw new CanalParseException(e);\n        }\n    }\n\n    private Entry parseUserVarLogEvent(UserVarLogEvent event) {\n        if (filterQueryDml) {\n            return null;\n        }\n\n        return buildQueryEntry(event.getQuery(), event.getHeader());\n    }\n\n    private Entry parseIntrvarLogEvent(IntvarLogEvent event) {\n        if (filterQueryDml) {\n            return null;\n        }\n\n        return buildQueryEntry(event.getQuery(), event.getHeader());\n    }\n\n    private Entry parseRandLogEvent(RandLogEvent event) {\n        if (filterQueryDml) {\n            return null;\n        }\n\n        return buildQueryEntry(event.getQuery(), event.getHeader());\n    }\n\n    private Entry parseXidEvent(XidLogEvent event) {\n        TransactionEnd transactionEnd = createTransactionEnd(event.getXid());\n        Header header = createHeader(event.getHeader(), \"\", \"\", null);\n        return createEntry(header, EntryType.TRANSACTIONEND, transactionEnd.toByteString());\n    }\n\n    public TableMeta parseRowsEventForTableMeta(RowsLogEvent event) {\n        TableMapLogEvent table = event.getTable();\n        if (table == null) {\n            // tableId对应的记录不存在\n            throw new TableIdNotFoundException(\"not found tableId:\" + event.getTableId());\n        }\n\n        boolean isHeartBeat = isAliSQLHeartBeat(table.getDbName(), table.getTableName());\n        boolean isRDSHeartBeat = tableMetaCache.isOnRDS() && isRDSHeartBeat(table.getDbName(), table.getTableName());\n\n        String fullname = table.getDbName() + \".\" + table.getTableName();\n        // check name filter\n        if (nameFilter != null && !nameFilter.filter(fullname)) {\n            return null;\n        }\n        if (nameBlackFilter != null && nameBlackFilter.filter(fullname)) {\n            return null;\n        }\n\n        // if (isHeartBeat || isRDSHeartBeat) {\n        // // 忽略rds模式的mysql.ha_health_check心跳数据\n        // return null;\n        // }\n        TableMeta tableMeta = null;\n        if (isRDSHeartBeat) {\n            // 处理rds模式的mysql.ha_health_check心跳数据\n            // 主要RDS的心跳表基本无权限,需要mock一个tableMeta\n            FieldMeta idMeta = new FieldMeta(\"id\", \"bigint(20)\", true, false, \"0\");\n            FieldMeta typeMeta = new FieldMeta(\"type\", \"char(1)\", false, true, \"0\");\n            tableMeta = new TableMeta(table.getDbName(), table.getTableName(), Arrays.asList(idMeta, typeMeta));\n        } else if (isHeartBeat) {\n            // 处理alisql模式的test.heartbeat心跳数据\n            // 心跳表基本无权限,需要mock一个tableMeta\n            FieldMeta idMeta = new FieldMeta(\"id\", \"smallint(6)\", false, true, null);\n            FieldMeta typeMeta = new FieldMeta(\"ts\", \"int(11)\", true, false, null);\n            tableMeta = new TableMeta(table.getDbName(), table.getTableName(), Arrays.asList(idMeta, typeMeta));\n        }\n\n        EntryPosition position = createPosition(event.getHeader());\n        if (tableMetaCache != null && tableMeta == null) {// 入错存在table meta\n            tableMeta = getTableMeta(table.getDbName(), table.getTableName(), true, position);\n            if (tableMeta == null) {\n                if (!filterTableError) {\n                    throw new CanalParseException(\"not found [\" + fullname + \"] in db , pls check!\");\n                }\n            }\n        }\n\n        return tableMeta;\n    }\n\n    public Entry parseRowsEvent(RowsLogEvent event) {\n        return parseRowsEvent(event, null);\n    }\n\n    public void parseTableMapEvent(TableMapLogEvent event) {\n        try {\n            String charsetDbName = new String(event.getDbName().getBytes(ISO_8859_1), charset);\n            event.setDbname(charsetDbName);\n\n            String charsetTbName = new String(event.getTableName().getBytes(ISO_8859_1), charset);\n            event.setTblname(charsetTbName);\n        } catch (UnsupportedEncodingException e) {\n            throw new CanalParseException(e);\n        }\n    }\n\n    public Entry parseRowsEvent(RowsLogEvent event, TableMeta tableMeta) {\n        if (filterRows) {\n            return null;\n        }\n        try {\n            if (tableMeta == null) { // 如果没有外部指定\n                tableMeta = parseRowsEventForTableMeta(event);\n            }\n\n            if (tableMeta == null) {\n                // 拿不到表结构,执行忽略\n                return null;\n            }\n\n            EventType eventType = null;\n            int type = event.getHeader().getType();\n            if (LogEvent.WRITE_ROWS_EVENT_V1 == type || LogEvent.WRITE_ROWS_EVENT == type) {\n                eventType = EventType.INSERT;\n            } else if (LogEvent.UPDATE_ROWS_EVENT_V1 == type || LogEvent.UPDATE_ROWS_EVENT == type\n                       || LogEvent.PARTIAL_UPDATE_ROWS_EVENT == type) {\n                eventType = EventType.UPDATE;\n            } else if (LogEvent.DELETE_ROWS_EVENT_V1 == type || LogEvent.DELETE_ROWS_EVENT == type) {\n                eventType = EventType.DELETE;\n            } else {\n                throw new CanalParseException(\"unsupport event type :\" + event.getHeader().getType());\n            }\n\n            RowChange.Builder rowChangeBuider = RowChange.newBuilder();\n            rowChangeBuider.setTableId(event.getTableId());\n            rowChangeBuider.setIsDdl(false);\n\n            rowChangeBuider.setEventType(eventType);\n            RowsLogBuffer buffer = event.getRowsBuf(charset);\n            BitSet columns = event.getColumns();\n            BitSet changeColumns = event.getChangeColumns();\n\n            boolean tableError = false;\n            int rowsCount = 0;\n            while (buffer.nextOneRow(columns, false)) {\n                // 处理row记录\n                RowData.Builder rowDataBuilder = RowData.newBuilder();\n                if (EventType.INSERT == eventType) {\n                    // insert的记录放在before字段中\n                    tableError |= parseOneRow(rowDataBuilder, event, buffer, columns, true, tableMeta);\n                } else if (EventType.DELETE == eventType) {\n                    // delete的记录放在before字段中\n                    tableError |= parseOneRow(rowDataBuilder, event, buffer, columns, false, tableMeta);\n                } else {\n                    // update需要处理before/after\n                    tableError |= parseOneRow(rowDataBuilder, event, buffer, columns, false, tableMeta);\n                    if (!buffer.nextOneRow(changeColumns, true)) {\n                        rowChangeBuider.addRowDatas(rowDataBuilder.build());\n                        break;\n                    }\n\n                    tableError |= parseOneRow(rowDataBuilder, event, buffer, changeColumns, true, tableMeta);\n                }\n\n                rowsCount++;\n                rowChangeBuider.addRowDatas(rowDataBuilder.build());\n            }\n            TableMapLogEvent table = event.getTable();\n            Header header = createHeader(event.getHeader(),\n                table.getDbName(),\n                table.getTableName(),\n                eventType,\n                rowsCount);\n\n            RowChange rowChange = rowChangeBuider.build();\n            if (tableError) {\n                Entry entry = createEntry(header, EntryType.ROWDATA, ByteString.EMPTY);\n                logger.warn(\"table parser error : {}storeValue: {}\", entry.toString(), rowChange.toString());\n                return null;\n            } else {\n                Entry entry = createEntry(header, EntryType.ROWDATA, rowChange.toByteString());\n                return entry;\n            }\n        } catch (Exception e) {\n            throw new CanalParseException(\"parse row data failed.\", e);\n        }\n    }\n\n    private EntryPosition createPosition(LogHeader logHeader) {\n        return new EntryPosition(logHeader.getLogFileName(), logHeader.getLogPos() - logHeader.getEventLen(), // startPos\n            logHeader.getWhen() * 1000L,\n            logHeader.getServerId()); // 记录到秒\n    }\n\n    private boolean parseOneRow(RowData.Builder rowDataBuilder, RowsLogEvent event, RowsLogBuffer buffer, BitSet cols,\n                                boolean isAfter, TableMeta tableMeta) throws UnsupportedEncodingException {\n        int columnCnt = event.getTable().getColumnCnt();\n        ColumnInfo[] columnInfo = event.getTable().getColumnInfo();\n        // mysql8.0针对set @@global.binlog_row_metadata='FULL' 可以记录部分的metadata信息\n        boolean existOptionalMetaData = event.getTable().isExistOptionalMetaData();\n        boolean tableError = false;\n        // check table fileds count，只能处理加字段\n        boolean existRDSNoPrimaryKey = false;\n        // 获取字段过滤条件\n        List<String> fieldList = null;\n        List<String> blackFieldList = null;\n\n        if (tableMeta != null) {\n            fieldList = fieldFilterMap.get(tableMeta.getFullName().toUpperCase());\n            blackFieldList = fieldBlackFilterMap.get(tableMeta.getFullName().toUpperCase());\n        }\n\n        if (tableMeta != null && columnInfo.length > tableMeta.getFields().size()) {\n            if (tableMetaCache.isOnRDS() || tableMetaCache.isOnPolarX()) {\n                // 特殊处理下RDS的场景\n                List<FieldMeta> primaryKeys = tableMeta.getPrimaryFields();\n                if (primaryKeys == null || primaryKeys.isEmpty()) {\n                    if (columnInfo.length == tableMeta.getFields().size() + 1\n                        && columnInfo[columnInfo.length - 1].type == LogEvent.MYSQL_TYPE_LONGLONG) {\n                        existRDSNoPrimaryKey = true;\n                    }\n                }\n            }\n\n            EntryPosition position = createPosition(event.getHeader());\n            if (!existRDSNoPrimaryKey) {\n                // online ddl增加字段操作步骤：\n                // 1. 新增一张临时表，将需要做ddl表的数据全量导入\n                // 2. 在老表上建立I/U/D的trigger，增量的将数据插入到临时表\n                // 3. 锁住应用请求，将临时表rename为老表的名字，完成增加字段的操作\n                // 尝试做一次reload，可能因为ddl没有正确解析，或者使用了类似online ddl的操作\n                // 因为online ddl没有对应表名的alter语法，所以不会有clear cache的操作\n                tableMeta = getTableMeta(event.getTable().getDbName(), event.getTable().getTableName(), false, position);// 强制重新获取一次\n                if (tableMeta == null) {\n                    tableError = true;\n                    if (!filterTableError) {\n                        throw new CanalParseException(\"not found [\" + event.getTable().getDbName() + \".\"\n                                                      + event.getTable().getTableName() + \"] in db , pls check!\");\n                    }\n                }\n\n                // 在做一次判断\n                if (tableMeta != null && columnInfo.length > tableMeta.getFields().size()) {\n                    tableError = true;\n                    if (!filterTableError) {\n                        throw new CanalParseException(\"column size is not match for table:\" + tableMeta.getFullName()\n                                                      + \",\" + columnInfo.length + \" vs \" + tableMeta.getFields().size());\n                    }\n                }\n                // } else {\n                // logger.warn(\"[\" + event.getTable().getDbName() + \".\" +\n                // event.getTable().getTableName()\n                // + \"] is no primary key , skip alibaba_rds_row_id column\");\n            }\n        }\n\n        for (int i = 0; i < columnCnt; i++) {\n            ColumnInfo info = columnInfo[i];\n            // mysql 5.6开始支持nolob/mininal类型,并不一定记录所有的列,需要进行判断\n            if (!cols.get(i)) {\n                continue;\n            }\n\n            if (existRDSNoPrimaryKey && i == columnCnt - 1 && info.type == LogEvent.MYSQL_TYPE_LONGLONG) {\n                // 不解析最后一列\n                String rdsRowIdColumnName = \"__#alibaba_rds_row_id#__\";\n                if (tableMetaCache.isOnPolarX()) {\n                    rdsRowIdColumnName = \"_drds_implicit_id_\";\n                }\n                buffer.nextValue(rdsRowIdColumnName, i, info.type, info.meta, false);\n                Column.Builder columnBuilder = Column.newBuilder();\n                columnBuilder.setName(rdsRowIdColumnName);\n                columnBuilder.setIsKey(true);\n                columnBuilder.setMysqlType(\"bigint\");\n                columnBuilder.setIndex(i);\n                columnBuilder.setIsNull(false);\n                Serializable value = buffer.getValue();\n                columnBuilder.setValue(value.toString());\n                columnBuilder.setSqlType(Types.BIGINT);\n                columnBuilder.setUpdated(false);\n\n                if (needField(fieldList, blackFieldList, columnBuilder.getName())) {\n                    if (isAfter) {\n                        rowDataBuilder.addAfterColumns(columnBuilder.build());\n                    } else {\n                        rowDataBuilder.addBeforeColumns(columnBuilder.build());\n                    }\n                }\n                continue;\n            }\n\n            FieldMeta fieldMeta = null;\n            if (tableMeta != null && !tableError) {\n                // 处理file meta\n                fieldMeta = tableMeta.getFields().get(i);\n            }\n\n            if (fieldMeta != null && existOptionalMetaData && tableMetaCache.isOnTSDB()) {\n                // check column info\n                boolean check = StringUtils.equalsIgnoreCase(fieldMeta.getColumnName(), info.name);\n                check &= (fieldMeta.isUnsigned() == info.unsigned);\n                check &= (fieldMeta.isNullable() == info.nullable);\n\n                if (!check) {\n                    throw new CanalParseException(\"MySQL8.0 unmatch column metadata & pls submit issue , table : \"\n                                                  + tableMeta.getFullName() + \", db fieldMeta : \"\n                                                  + fieldMeta.toString() + \" , binlog fieldMeta : \" + info.toString()\n                                                  + \" , on : \" + event.getHeader().getLogFileName() + \":\"\n                                                  + (event.getHeader().getLogPos() - event.getHeader().getEventLen()));\n                }\n            }\n\n            Column.Builder columnBuilder = Column.newBuilder();\n            if (fieldMeta != null) {\n                columnBuilder.setName(fieldMeta.getColumnName());\n                columnBuilder.setIsKey(fieldMeta.isKey());\n                // 增加mysql type类型,issue 73\n                columnBuilder.setMysqlType(fieldMeta.getColumnType());\n            } else if (existOptionalMetaData) {\n                columnBuilder.setName(info.name);\n                columnBuilder.setIsKey(info.pk);\n                // mysql8.0里没有mysql type类型\n                // columnBuilder.setMysqlType(fieldMeta.getColumnType());\n            }\n            columnBuilder.setIndex(i);\n            columnBuilder.setIsNull(false);\n\n            // fixed issue\n            // https://github.com/alibaba/canal/issues/66，特殊处理binary/varbinary，不能做编码处理\n            boolean isBinary = false;\n            if (fieldMeta != null) {\n                if (StringUtils.containsIgnoreCase(fieldMeta.getColumnType(), \"VARBINARY\")) {\n                    isBinary = true;\n                } else if (StringUtils.containsIgnoreCase(fieldMeta.getColumnType(), \"BINARY\")) {\n                    isBinary = true;\n                }\n            }\n\n            buffer.nextValue(columnBuilder.getName(), i, info.type, info.meta, isBinary);\n            int javaType = buffer.getJavaType();\n            if (buffer.isNull()) {\n                columnBuilder.setIsNull(true);\n                \n                // 处理各种类型\n                switch (javaType) {\n                    case Types.BINARY:\n                    case Types.VARBINARY:\n                    case Types.LONGVARBINARY:\n\n                        // https://github.com/alibaba/canal/issues/4652\n                        // mysql binlog中blob/text都处理为blob类型，需要反查table\n                        // meta，按编码解析text\n                        if (fieldMeta != null && isText(fieldMeta.getColumnType())) {\n                            javaType = Types.CLOB;\n                        } else {\n                            javaType = Types.BLOB;\n                        }\n                        break;\n                }\n            } else {\n                final Serializable value = buffer.getValue();\n                // 处理各种类型\n                switch (javaType) {\n                    case Types.INTEGER:\n                    case Types.TINYINT:\n                    case Types.SMALLINT:\n                    case Types.BIGINT:\n                        // 处理unsigned类型\n                        Number number = (Number) value;\n                        boolean isUnsigned = (fieldMeta != null ? fieldMeta.isUnsigned() : (existOptionalMetaData ? info.unsigned : false));\n                        if (isUnsigned && number.longValue() < 0) {\n                            switch (buffer.getLength()) {\n                                case 1: /* MYSQL_TYPE_TINY */\n                                    columnBuilder.setValue(String.valueOf(Integer.valueOf(TINYINT_MAX_VALUE\n                                                                                          + number.intValue())));\n                                    javaType = Types.SMALLINT; // 往上加一个量级\n                                    break;\n\n                                case 2: /* MYSQL_TYPE_SHORT */\n                                    columnBuilder.setValue(String.valueOf(Integer.valueOf(SMALLINT_MAX_VALUE\n                                                                                          + number.intValue())));\n                                    javaType = Types.INTEGER; // 往上加一个量级\n                                    break;\n\n                                case 3: /* MYSQL_TYPE_INT24 */\n                                    columnBuilder.setValue(String.valueOf(Integer.valueOf(MEDIUMINT_MAX_VALUE\n                                                                                          + number.intValue())));\n                                    javaType = Types.INTEGER; // 往上加一个量级\n                                    break;\n\n                                case 4: /* MYSQL_TYPE_LONG */\n                                    columnBuilder.setValue(String.valueOf(Long.valueOf(INTEGER_MAX_VALUE\n                                                                                       + number.longValue())));\n                                    javaType = Types.BIGINT; // 往上加一个量级\n                                    break;\n\n                                case 8: /* MYSQL_TYPE_LONGLONG */\n                                    columnBuilder.setValue(BIGINT_MAX_VALUE.add(BigInteger.valueOf(number.longValue()))\n                                        .toString());\n                                    javaType = Types.DECIMAL; // 往上加一个量级，避免执行出错\n                                    break;\n                            }\n                        } else {\n                            // 对象为number类型，直接valueof即可\n                            columnBuilder.setValue(String.valueOf(value));\n                        }\n                        break;\n                    case Types.REAL: // float\n                    case Types.DOUBLE: // double\n                        // 对象为number类型，直接valueof即可\n                        columnBuilder.setValue(String.valueOf(value));\n                        break;\n                    case Types.BIT:// bit\n                        // 对象为number类型\n                        columnBuilder.setValue(String.valueOf(value));\n                        break;\n                    case Types.DECIMAL:\n                        columnBuilder.setValue(((BigDecimal) value).toPlainString());\n                        break;\n                    case Types.TIMESTAMP:\n                        // 修复时间边界值\n                        // String v = value.toString();\n                        // v = v.substring(0, v.length() - 2);\n                        // columnBuilder.setValue(v);\n                        // break;\n                    case Types.TIME:\n                    case Types.DATE:\n                        // 需要处理year\n                        columnBuilder.setValue(value.toString());\n                        break;\n                    case Types.BINARY:\n                    case Types.VARBINARY:\n                    case Types.LONGVARBINARY:\n                        // fixed text encoding\n                        // https://github.com/AlibabaTech/canal/issues/18\n                        // mysql binlog中blob/text都处理为blob类型，需要反查table\n                        // meta，按编码解析text\n                        if (fieldMeta != null && isText(fieldMeta.getColumnType())) {\n                            columnBuilder.setValue(new String((byte[]) value, charset));\n                            javaType = Types.CLOB;\n                        } else {\n                            // byte数组，直接使用iso-8859-1保留对应编码，浪费内存\n                            columnBuilder.setValue(new String((byte[]) value, ISO_8859_1));\n                            // columnBuilder.setValueBytes(ByteString.copyFrom((byte[])\n                            // value));\n                            javaType = Types.BLOB;\n                        }\n                        break;\n                    case Types.CHAR:\n                    case Types.VARCHAR:\n                        columnBuilder.setValue(value.toString());\n                        break;\n                    default:\n                        columnBuilder.setValue(value.toString());\n                }\n            }\n\n            columnBuilder.setSqlType(javaType);\n            // 设置是否update的标记位\n            columnBuilder.setUpdated(isAfter\n                                     && isUpdate(rowDataBuilder.getBeforeColumnsList(),\n                                         columnBuilder.getIsNull() ? null : columnBuilder.getValue(),\n                                         i));\n            if (needField(fieldList, blackFieldList, columnBuilder.getName())) {\n                if (isAfter) {\n                    rowDataBuilder.addAfterColumns(columnBuilder.build());\n                } else {\n                    rowDataBuilder.addBeforeColumns(columnBuilder.build());\n                }\n            }\n        }\n\n        return tableError;\n\n    }\n\n    private Entry buildQueryEntry(String queryString, LogHeader logHeader, String tableName) {\n        Header header = createHeader(logHeader, \"\", tableName, EventType.QUERY);\n        RowChange.Builder rowChangeBuider = RowChange.newBuilder();\n        rowChangeBuider.setSql(queryString);\n        rowChangeBuider.setEventType(EventType.QUERY);\n        return createEntry(header, EntryType.ROWDATA, rowChangeBuider.build().toByteString());\n    }\n\n    private Entry buildQueryEntry(String queryString, LogHeader logHeader) {\n        Header header = createHeader(logHeader, \"\", \"\", EventType.QUERY);\n        RowChange.Builder rowChangeBuider = RowChange.newBuilder();\n        rowChangeBuider.setSql(queryString);\n        rowChangeBuider.setEventType(EventType.QUERY);\n        return createEntry(header, EntryType.ROWDATA, rowChangeBuider.build().toByteString());\n    }\n\n    private Header createHeader(LogHeader logHeader, String schemaName, String tableName, EventType eventType) {\n        return createHeader(logHeader, schemaName, tableName, eventType, -1);\n    }\n\n    private Header createHeader(LogHeader logHeader, String schemaName, String tableName, EventType eventType,\n                                Integer rowsCount) {\n        // header会做信息冗余,方便以后做检索或者过滤\n        Header.Builder headerBuilder = Header.newBuilder();\n        headerBuilder.setVersion(version);\n        headerBuilder.setLogfileName(logHeader.getLogFileName());\n        // 记录的是该binlog的start offest\n        headerBuilder.setLogfileOffset(logHeader.getLogPos() - logHeader.getEventLen());\n        headerBuilder.setServerId(logHeader.getServerId());\n        headerBuilder.setServerenCode(UTF_8);// 经过java输出后所有的编码为unicode\n        headerBuilder.setExecuteTime(logHeader.getWhen() * 1000L);\n        headerBuilder.setSourceType(Type.MYSQL);\n        if (eventType != null) {\n            headerBuilder.setEventType(eventType);\n        }\n        if (schemaName != null) {\n            headerBuilder.setSchemaName(schemaName);\n        }\n        if (tableName != null) {\n            headerBuilder.setTableName(tableName);\n        }\n        headerBuilder.setEventLength(logHeader.getEventLen());\n        // enable gtid position\n        if (StringUtils.isNotEmpty(logHeader.getGtidSetStr())) {\n            headerBuilder.setGtid(logHeader.getGtidSetStr());\n        }\n        // add current gtid\n        if (StringUtils.isNotEmpty(logHeader.getCurrentGtid())) {\n            Pair pair = createSpecialPair(\"curtGtid\", logHeader.getCurrentGtid());\n            headerBuilder.addProps(pair);\n        }\n        // add current gtid sequence no\n        if (StringUtils.isNotEmpty(logHeader.getCurrentGtidSn())) {\n            Pair pair = createSpecialPair(\"curtGtidSn\", logHeader.getCurrentGtidSn());\n            headerBuilder.addProps(pair);\n        }\n\n        // add current gtid last committed\n        if (StringUtils.isNotEmpty(logHeader.getCurrentGtidLastCommit())) {\n            Pair pair = createSpecialPair(\"curtGtidLct\", logHeader.getCurrentGtidLastCommit());\n            headerBuilder.addProps(pair);\n        }\n\n        // add rowsCount suppport\n        if (rowsCount > 0) {\n            Pair pair = createSpecialPair(\"rowsCount\", String.valueOf(rowsCount));\n            headerBuilder.addProps(pair);\n        }\n        return headerBuilder.build();\n    }\n\n    private boolean isUpdate(List<Column> bfColumns, String newValue, int index) {\n        if (bfColumns == null) {\n            throw new CanalParseException(\"ERROR ## the bfColumns is null\");\n        }\n\n        if (index < 0) {\n            return false;\n        }\n\n        for (Column column : bfColumns) {\n            if (column.getIndex() == index) {// 比较before / after的column index\n                if (column.getIsNull() && newValue == null) {\n                    // 如果全是null\n                    return false;\n                } else if (newValue != null && (!column.getIsNull() && column.getValue().equals(newValue))) {\n                    // fixed issue #135, old column is Null\n                    // 如果不为null，并且相等\n                    return false;\n                }\n            }\n        }\n\n        // 比如nolob/minial模式下,可能找不到before记录,认为是有变化\n        return true;\n    }\n\n    private TableMeta getTableMeta(String dbName, String tbName, boolean useCache, EntryPosition position) {\n        try {\n            return tableMetaCache.getTableMeta(dbName, tbName, useCache, position);\n        } catch (Throwable e) {\n            String message = ExceptionUtils.getRootCauseMessage(e);\n            if (filterTableError) {\n                if (StringUtils.contains(message, \"errorNumber=1146\") && StringUtils.contains(message, \"doesn't exist\")) {\n                    return null;\n                } else if (StringUtils.contains(message, \"errorNumber=1142\")\n                           && StringUtils.contains(message, \"command denied\")) {\n                    return null;\n                }\n            }\n\n            throw new CanalParseException(e);\n        }\n    }\n\n    private boolean isText(String columnType) {\n        return \"LONGTEXT\".equalsIgnoreCase(columnType) || \"MEDIUMTEXT\".equalsIgnoreCase(columnType)\n               || \"TEXT\".equalsIgnoreCase(columnType) || \"TINYTEXT\".equalsIgnoreCase(columnType);\n    }\n\n    private boolean isAliSQLHeartBeat(String schema, String table) {\n        return \"test\".equalsIgnoreCase(schema) && \"heartbeat\".equalsIgnoreCase(table);\n    }\n\n    private boolean isRDSHeartBeat(String schema, String table) {\n        return \"mysql\".equalsIgnoreCase(schema) && \"ha_health_check\".equalsIgnoreCase(table);\n    }\n\n    /**\n     * 字段过滤判断\n     */\n    private boolean needField(List<String> fieldList, List<String> blackFieldList, String columnName) {\n        if (fieldList == null || fieldList.isEmpty()) {\n            return blackFieldList == null || blackFieldList.isEmpty()\n                   || !blackFieldList.contains(columnName.toUpperCase());\n        } else {\n            return fieldList.contains(columnName.toUpperCase());\n        }\n    }\n\n    public static TransactionBegin createTransactionBegin(long threadId) {\n        TransactionBegin.Builder beginBuilder = TransactionBegin.newBuilder();\n        beginBuilder.setThreadId(threadId);\n        return beginBuilder.build();\n    }\n\n    public static TransactionEnd createTransactionEnd(long transactionId) {\n        TransactionEnd.Builder endBuilder = TransactionEnd.newBuilder();\n        endBuilder.setTransactionId(String.valueOf(transactionId));\n        return endBuilder.build();\n    }\n\n    public static Pair createSpecialPair(String key, String value) {\n        Pair.Builder pairBuilder = Pair.newBuilder();\n        pairBuilder.setKey(key);\n        pairBuilder.setValue(value);\n        return pairBuilder.build();\n    }\n\n    public static Entry createEntry(Header header, EntryType entryType, ByteString storeValue) {\n        Entry.Builder entryBuilder = Entry.newBuilder();\n        entryBuilder.setHeader(header);\n        entryBuilder.setEntryType(entryType);\n        entryBuilder.setStoreValue(storeValue);\n        return entryBuilder.build();\n    }\n\n    public void setCharset(Charset charset) {\n        this.charset = charset;\n    }\n\n    public void setNameFilter(AviaterRegexFilter nameFilter) {\n        this.nameFilter = nameFilter;\n        logger.warn(\"--> init table filter : \" + nameFilter.toString());\n    }\n\n    public void setNameBlackFilter(AviaterRegexFilter nameBlackFilter) {\n        this.nameBlackFilter = nameBlackFilter;\n        logger.warn(\"--> init table black filter : \" + nameBlackFilter.toString());\n    }\n\n    public void setFieldFilterMap(Map<String, List<String>> fieldFilterMap) {\n        if (fieldFilterMap != null) {\n            this.fieldFilterMap = fieldFilterMap;\n        } else {\n            this.fieldFilterMap = new HashMap<>();\n        }\n\n        for (Map.Entry<String, List<String>> entry : this.fieldFilterMap.entrySet()) {\n            logger.warn(\"--> init field filter : \" + entry.getKey() + \"->\" + entry.getValue());\n        }\n    }\n\n    public void setFieldBlackFilterMap(Map<String, List<String>> fieldBlackFilterMap) {\n        if (fieldBlackFilterMap != null) {\n            this.fieldBlackFilterMap = fieldBlackFilterMap;\n        } else {\n            this.fieldBlackFilterMap = new HashMap<>();\n        }\n\n        for (Map.Entry<String, List<String>> entry : this.fieldBlackFilterMap.entrySet()) {\n            logger.warn(\"--> init field black filter : \" + entry.getKey() + \"->\" + entry.getValue());\n        }\n    }\n\n    public void setTableMetaCache(TableMetaCache tableMetaCache) {\n        this.tableMetaCache = tableMetaCache;\n    }\n\n    public void setFilterQueryDcl(boolean filterQueryDcl) {\n        this.filterQueryDcl = filterQueryDcl;\n    }\n\n    public void setFilterQueryDml(boolean filterQueryDml) {\n        this.filterQueryDml = filterQueryDml;\n    }\n\n    public void setFilterQueryDdl(boolean filterQueryDdl) {\n        this.filterQueryDdl = filterQueryDdl;\n    }\n\n    public void setFilterTableError(boolean filterTableError) {\n        this.filterTableError = filterTableError;\n    }\n\n    public void setFilterRows(boolean filterRows) {\n        this.filterRows = filterRows;\n    }\n\n    public void setUseDruidDdlFilter(boolean useDruidDdlFilter) {\n        this.useDruidDdlFilter = useDruidDdlFilter;\n    }\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/dbsync/TableMetaCache.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.dbsync;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentMap;\n\nimport org.apache.commons.lang.StringUtils;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.server.FieldPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.server.ResultSetPacket;\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\nimport com.alibaba.otter.canal.parse.inbound.TableMeta;\nimport com.alibaba.otter.canal.parse.inbound.TableMeta.FieldMeta;\nimport com.alibaba.otter.canal.parse.inbound.mysql.MysqlConnection;\nimport com.alibaba.otter.canal.parse.inbound.mysql.ddl.DruidDdlParser;\nimport com.alibaba.otter.canal.parse.inbound.mysql.tsdb.DatabaseTableMeta;\nimport com.alibaba.otter.canal.parse.inbound.mysql.tsdb.MemoryTableMeta;\nimport com.alibaba.otter.canal.parse.inbound.mysql.tsdb.TableMetaTSDB;\nimport com.alibaba.otter.canal.protocol.position.EntryPosition;\nimport com.google.common.cache.CacheBuilder;\nimport com.google.common.cache.CacheLoader;\nimport com.google.common.cache.LoadingCache;\n\n/**\n * 处理table meta解析和缓存\n *\n * @author jianghang 2013-1-17 下午10:15:16\n * @version 1.0.0\n */\npublic class TableMetaCache {\n\n    public static final String              COLUMN_NAME    = \"field\";\n    public static final String              COLUMN_TYPE    = \"type\";\n    public static final String              IS_NULLABLE    = \"null\";\n    public static final String              COLUMN_KEY     = \"key\";\n    public static final String              COLUMN_DEFAULT = \"default\";\n    public static final String              EXTRA          = \"extra\";\n    private MysqlConnection                 connection;\n    private boolean                         isOnRDS        = false;\n    private boolean                         isOnPolarX     = false;\n    private boolean                         isOnTSDB       = false;\n\n    private TableMetaTSDB                   tableMetaTSDB;\n\n    // 第一层tableId,第二层schema.table,解决tableId重复，对应多张表\n    private LoadingCache<String, TableMeta> tableMetaCache;\n\n    public TableMetaCache(MysqlConnection con, TableMetaTSDB tableMetaTSDB){\n        this.connection = con;\n        this.tableMetaTSDB = tableMetaTSDB;\n        // 如果持久存储的表结构为空，从db里面获取下\n        if (tableMetaTSDB == null) {\n            this.tableMetaCache = createLocalCache();\n        } else {\n            isOnTSDB = true;\n        }\n        try {\n            ResultSetPacket packet = connection.query(\"show global variables  like 'rds\\\\_%'\");\n            // if (packet.getFieldValues().size() > 0) {\n            isOnRDS = packet.getFieldValues().size() > 0;\n            // }\n        } catch (IOException e) {\n        }\n        try {\n            ResultSetPacket packet = connection.query(\"show global variables  like 'polarx\\\\_%'\");\n            // if (packet.getFieldValues().size() > 0) {\n            isOnPolarX = packet.getFieldValues().size() > 0;\n            // }\n        } catch (IOException e) {\n        }\n    }\n\n    public static List<FieldMeta> parseTableMeta(String schema, String table, ResultSetPacket packet) {\n        if (packet.getFieldValues().size() > 1) {\n            String createDDL = packet.getFieldValues().get(1);\n            MemoryTableMeta memoryTableMeta = new MemoryTableMeta();\n            memoryTableMeta.apply(DatabaseTableMeta.INIT_POSITION, schema, createDDL, null);\n            TableMeta tableMeta = memoryTableMeta.find(schema, table);\n            return tableMeta.getFields();\n        } else {\n            return new ArrayList<>();\n        }\n    }\n\n    /**\n     * 处理desc table的结果\n     */\n    public static List<FieldMeta> parseTableMetaByDesc(ResultSetPacket packet) {\n        List<FieldPacket> fieldPackets = packet.getFieldDescriptors();\n        int size = fieldPackets.size();\n        Map<String, Integer> nameMaps = new HashMap<>(size);\n        int index = 0;\n        for (FieldPacket fieldPacket : fieldPackets) {\n            nameMaps.put(StringUtils.lowerCase(fieldPacket.getName()), index++);\n        }\n\n        List<String> fieldValues = packet.getFieldValues();\n        int count = fieldValues.size() / size;\n        List<FieldMeta> result = new ArrayList<>(count);\n        for (int i = 0; i < count; i++) {\n            FieldMeta meta = new FieldMeta();\n            // 做一个优化，使用String.intern()，共享String对象，减少内存使用\n            meta.setColumnName(fieldValues.get(nameMaps.get(COLUMN_NAME) + i * size).intern());\n            meta.setColumnType(fieldValues.get(nameMaps.get(COLUMN_TYPE) + i * size));\n            meta.setNullable(\n                StringUtils.equalsIgnoreCase(fieldValues.get(nameMaps.get(IS_NULLABLE) + i * size), \"YES\"));\n            meta.setKey(\"PRI\".equalsIgnoreCase(fieldValues.get(nameMaps.get(COLUMN_KEY) + i * size)));\n            meta.setUnique(\"UNI\".equalsIgnoreCase(fieldValues.get(nameMaps.get(COLUMN_KEY) + i * size)));\n            // 特殊处理引号\n            meta.setDefaultValue(\n                DruidDdlParser.unescapeQuotaName(fieldValues.get(nameMaps.get(COLUMN_DEFAULT) + i * size)));\n            meta.setExtra(fieldValues.get(nameMaps.get(EXTRA) + i * size));\n            result.add(meta);\n        }\n        return result;\n    }\n\n    private LoadingCache<String, TableMeta> createLocalCache() {\n        return CacheBuilder.newBuilder().build(new CacheLoader<String, TableMeta>() {\n\n            @Override\n            public TableMeta load(String name) throws Exception {\n                try {\n                    return getTableMetaByDB(name);\n                } catch (Throwable e) {\n                    // 尝试做一次retry操作\n                    try {\n                        connection.reconnect();\n                        return getTableMetaByDB(name);\n                    } catch (IOException e1) {\n                        throw new CanalParseException(\"fetch table meta failed. table: \" + name, e1);\n                    }\n                }\n            }\n        });\n    }\n\n    private TableMeta getTableMetaByDB(String fullname) throws IOException {\n        boolean showCreateTable = true;\n        ResultSetPacket packet = null;\n        synchronized (this) {\n            try {\n                packet = connection.query(\"show create table \" + fullname);\n            } catch (Exception ex) {\n                showCreateTable = false;\n                packet = connection.query(\"desc \" + fullname);\n            }\n        }\n        String[] names = StringUtils.split(fullname, \"`.`\");\n        String schema = names[0];\n        String table = names[1].substring(0, names[1].length());\n        List<FieldMeta> fieldMetas = showCreateTable ? parseTableMeta(schema, table, packet) : parseTableMetaByDesc(\n            packet);\n        return new TableMeta(schema, table, fieldMetas);\n    }\n\n    // This method is unused\n    public TableMeta getTableMeta(String schema, String table) {\n        return getTableMeta(schema, table, true);\n    }\n\n    // This method is unused\n    public TableMeta getTableMeta(String schema, String table, boolean useCache) {\n        String fullName = getFullName(schema, table);\n        if (!useCache) {\n            // tableMetaCache.invalidate(getFullName(schema, table));\n            tableMetaCache.invalidate(fullName);\n        }\n        // return tableMetaCache.getUnchecked(getFullName(schema, table));\n        return tableMetaCache.getUnchecked(fullName);\n    }\n\n    // This method is unused\n    public TableMeta getTableMeta(String schema, String table, EntryPosition position) {\n        return getTableMeta(schema, table, true, position);\n    }\n\n    public TableMeta getTableMeta(String schema, String table, boolean useCache, EntryPosition position) {\n        TableMeta tableMeta = null;\n        if (tableMetaTSDB != null) {\n            tableMeta = tableMetaTSDB.find(schema, table);\n            if (tableMeta == null) {\n                // 因为条件变化，可能第一次的tableMeta没取到，需要从db获取一次，并记录到snapshot中\n                String fullName = getFullName(schema, table);\n                try {\n                    synchronized (this) {\n                        tableMeta = tableMetaTSDB.find(schema, table);\n                        if (tableMeta != null) {\n                            return tableMeta;\n                        }\n\n                        ResultSetPacket packet = null;\n                        try {\n                            packet = connection.query(\"show create table \" + fullName);\n                        } catch (Exception e) {\n                            // 尝试做一次retry操作\n                            connection.reconnect();\n                            packet = connection.query(\"show create table \" + fullName);\n                        }\n\n                        String createDDL = null;\n                        if (packet.getFieldValues().size() > 0) {\n                            createDDL = packet.getFieldValues().get(1);\n                        }\n                        // 强制覆盖掉内存值\n                        tableMetaTSDB.apply(position, schema, createDDL, \"first\");\n                        tableMeta = tableMetaTSDB.find(schema, table);\n                    }\n                } catch (IOException e) {\n                    throw new CanalParseException(\"fetch failed by table meta:\" + fullName, e);\n                }\n            }\n            return tableMeta;\n        } else {\n            String fullName = getFullName(schema, table);\n            if (!useCache) {\n                // tableMetaCache.invalidate(getFullName(schema, table));\n                tableMetaCache.invalidate(fullName);\n            }\n            // return tableMetaCache.getUnchecked(getFullName(schema, table));\n            return tableMetaCache.getUnchecked(fullName);\n        }\n    }\n\n    public void clearTableMeta(String schema, String table) {\n        if (tableMetaTSDB != null) {\n            // tsdb不需要做,会基于ddl sql自动清理\n        } else {\n            tableMetaCache.invalidate(getFullName(schema, table));\n        }\n    }\n\n    public void clearTableMetaWithSchemaName(String schema) {\n        if (tableMetaTSDB != null) {\n            // tsdb不需要做,会基于ddl sql自动清理\n        } else {\n            ConcurrentMap<String, TableMeta> map = tableMetaCache.asMap();\n            if (!map.isEmpty()) {\n                for (String name : map.keySet()) {\n                    if (StringUtils.startsWithIgnoreCase(name, schema + \".\")) {\n                        // removeNames.add(name);\n                        tableMetaCache.invalidate(name);\n                    }\n                }\n            }\n        }\n    }\n\n    public void clearTableMeta() {\n        if (tableMetaTSDB != null) {\n            // tsdb不需要做,会基于ddl sql自动清理\n        } else {\n            tableMetaCache.invalidateAll();\n        }\n    }\n\n    /**\n     * 更新一下本地的表结构内存\n     *\n     * @param position\n     * @param schema\n     * @param ddl\n     * @return\n     */\n    public boolean apply(EntryPosition position, String schema, String ddl, String extra) {\n        if (tableMetaTSDB != null) {\n            return tableMetaTSDB.apply(position, schema, ddl, extra);\n        } else {\n            // ignore\n            return true;\n        }\n    }\n\n    private String getFullName(String schema, String table) {\n        StringBuilder builder = new StringBuilder(64);\n        return builder.append('`')\n            .append(schema)\n            .append('`')\n            .append('.')\n            .append('`')\n            .append(StringUtils.replace(table, \"`\", \"``\"))\n            .append('`')\n            .toString();\n    }\n\n    public boolean isOnTSDB() {\n        return isOnTSDB;\n    }\n\n    public void setOnTSDB(boolean isOnTSDB) {\n        this.isOnTSDB = isOnTSDB;\n    }\n\n    public boolean isOnRDS() {\n        return isOnRDS;\n    }\n\n    public void setOnRDS(boolean isOnRDS) {\n        this.isOnRDS = isOnRDS;\n    }\n\n    public boolean isOnPolarX() {\n        return isOnPolarX;\n    }\n\n    public void setOnPolarX(boolean isOnPolarX) {\n        this.isOnPolarX = isOnPolarX;\n    }\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/ddl/DdlResult.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.ddl;\n\nimport com.alibaba.otter.canal.protocol.CanalEntry.EventType;\n\n/**\n * @author agapple 2017年8月1日 下午7:30:42\n * @since 3.2.5\n */\npublic class DdlResult {\n\n    private String    schemaName;\n    private String    tableName;\n    private String    oriSchemaName;    // rename ddl中的源表\n    private String    oriTableName;     // rename ddl中的目标表\n    private EventType type;\n    private DdlResult renameTableResult; // 多个rename table的存储\n\n    /*\n     * RENAME TABLE tbl_name TO new_tbl_name [, tbl_name2 TO new_tbl_name2] ...\n     */\n\n    public DdlResult(){\n    }\n\n    public DdlResult(String schemaName){\n        this.schemaName = schemaName;\n    }\n\n    public DdlResult(String schemaName, String tableName){\n        this.schemaName = schemaName;\n        this.tableName = tableName;\n    }\n\n    public DdlResult(String schemaName, String tableName, String oriSchemaName, String oriTableName){\n        this.schemaName = schemaName;\n        this.tableName = tableName;\n        this.oriSchemaName = oriSchemaName;\n        this.oriTableName = oriTableName;\n    }\n\n    public String getSchemaName() {\n        return schemaName;\n    }\n\n    public void setSchemaName(String schemaName) {\n        this.schemaName = schemaName;\n    }\n\n    public String getTableName() {\n        return tableName;\n    }\n\n    public void setTableName(String tableName) {\n        this.tableName = tableName;\n    }\n\n    public EventType getType() {\n        return type;\n    }\n\n    public void setType(EventType type) {\n        this.type = type;\n    }\n\n    public String getOriSchemaName() {\n        return oriSchemaName;\n    }\n\n    public void setOriSchemaName(String oriSchemaName) {\n        this.oriSchemaName = oriSchemaName;\n    }\n\n    public String getOriTableName() {\n        return oriTableName;\n    }\n\n    public void setOriTableName(String oriTableName) {\n        this.oriTableName = oriTableName;\n    }\n\n    public DdlResult getRenameTableResult() {\n        return renameTableResult;\n    }\n\n    public void setRenameTableResult(DdlResult renameTableResult) {\n        this.renameTableResult = renameTableResult;\n    }\n\n    @Override\n    public DdlResult clone() {\n        DdlResult result = new DdlResult();\n        result.setOriSchemaName(oriSchemaName);\n        result.setOriTableName(oriTableName);\n        result.setSchemaName(schemaName);\n        result.setTableName(tableName);\n        // result.setType(type);\n        return result;\n    }\n\n    @Override\n    public String toString() {\n        DdlResult ddlResult = this;\n        StringBuilder sb = new StringBuilder();\n        do {\n            sb.append(String.format(\"DdlResult [schemaName=%s , tableName=%s , oriSchemaName=%s , oriTableName=%s , type=%s ];\",\n                ddlResult.schemaName,\n                ddlResult.tableName,\n                ddlResult.oriSchemaName,\n                ddlResult.oriTableName,\n                ddlResult.type));\n            ddlResult = ddlResult.renameTableResult;\n        } while (ddlResult != null);\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/ddl/DruidDdlParser.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.ddl;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport com.alibaba.polardbx.druid.sql.SQLUtils;\nimport com.alibaba.polardbx.druid.sql.ast.SQLExpr;\nimport com.alibaba.polardbx.druid.sql.ast.SQLStatement;\nimport com.alibaba.polardbx.druid.sql.ast.expr.SQLIdentifierExpr;\nimport com.alibaba.polardbx.druid.sql.ast.expr.SQLPropertyExpr;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLAlterTableAddConstraint;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLAlterTableAddIndex;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLAlterTableDropConstraint;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLAlterTableDropIndex;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLAlterTableDropKey;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLAlterTableItem;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLAlterTableRename;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLAlterTableStatement;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLConstraint;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLCreateDatabaseStatement;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLCreateIndexStatement;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLCreateTableStatement;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLDeleteStatement;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLDropDatabaseStatement;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLDropIndexStatement;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLDropTableStatement;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLExprTableSource;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLInsertStatement;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLTableSource;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLTruncateStatement;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLUnique;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLUpdateStatement;\nimport com.alibaba.polardbx.druid.sql.dialect.mysql.ast.statement.MySqlRenameTableStatement;\nimport com.alibaba.polardbx.druid.sql.parser.ParserException;\nimport com.alibaba.polardbx.druid.util.JdbcConstants;\nimport org.apache.commons.lang.StringUtils;\n\nimport com.alibaba.otter.canal.protocol.CanalEntry.EventType;\n\n/**\n * @author agapple 2017年7月27日 下午4:05:34\n * @since 1.0.25\n */\npublic class DruidDdlParser {\n\n    public static List<DdlResult> parse(String queryString, String schmeaName) {\n        List<SQLStatement> stmtList = null;\n        try {\n            stmtList = SQLUtils.parseStatements(queryString, JdbcConstants.MYSQL, false);\n        } catch (ParserException e) {\n            // 可能存在一些SQL是不支持的，比如存储过程\n            DdlResult ddlResult = new DdlResult();\n            ddlResult.setType(EventType.QUERY);\n            return Arrays.asList(ddlResult);\n        }\n\n        List<DdlResult> ddlResults = new ArrayList<>();\n        for (SQLStatement statement : stmtList) {\n            if (statement instanceof SQLCreateTableStatement) {\n                DdlResult ddlResult = new DdlResult();\n                SQLCreateTableStatement createTable = (SQLCreateTableStatement) statement;\n                processName(ddlResult, schmeaName, createTable.getName(), false);\n                ddlResult.setType(EventType.CREATE);\n                ddlResults.add(ddlResult);\n            } else if (statement instanceof SQLAlterTableStatement) {\n                SQLAlterTableStatement alterTable = (SQLAlterTableStatement) statement;\n                if (alterTable.getTableOptions().size() > 0) {\n                    DdlResult ddlResult = new DdlResult();\n                    processName(ddlResult, schmeaName, alterTable.getName(), false);\n                    ddlResult.setType(EventType.ALTER);\n                    ddlResults.add(ddlResult);\n                }\n                for (SQLAlterTableItem item : alterTable.getItems()) {\n                    if (item instanceof SQLAlterTableRename) {\n                        DdlResult ddlResult = new DdlResult();\n                        processName(ddlResult, schmeaName, alterTable.getName(), true);\n                        processName(ddlResult, schmeaName, ((SQLAlterTableRename) item).getToName(), false);\n                        ddlResult.setType(EventType.RENAME);\n                        ddlResults.add(ddlResult);\n                    } else if (item instanceof SQLAlterTableAddIndex) {\n                        DdlResult ddlResult = new DdlResult();\n                        processName(ddlResult, schmeaName, alterTable.getName(), false);\n                        ddlResult.setType(EventType.CINDEX);\n                        ddlResults.add(ddlResult);\n                    } else if (item instanceof SQLAlterTableDropIndex || item instanceof SQLAlterTableDropKey) {\n                        DdlResult ddlResult = new DdlResult();\n                        processName(ddlResult, schmeaName, alterTable.getName(), false);\n                        ddlResult.setType(EventType.DINDEX);\n                        ddlResults.add(ddlResult);\n                    } else if (item instanceof SQLAlterTableAddConstraint) {\n                        DdlResult ddlResult = new DdlResult();\n                        processName(ddlResult, schmeaName, alterTable.getName(), false);\n                        SQLConstraint constraint = ((SQLAlterTableAddConstraint) item).getConstraint();\n                        if (constraint instanceof SQLUnique) {\n                            ddlResult.setType(EventType.CINDEX);\n                            ddlResults.add(ddlResult);\n                        }\n                    } else if (item instanceof SQLAlterTableDropConstraint) {\n                        DdlResult ddlResult = new DdlResult();\n                        processName(ddlResult, schmeaName, alterTable.getName(), false);\n                        ddlResult.setType(EventType.DINDEX);\n                        ddlResults.add(ddlResult);\n                    } else {\n                        DdlResult ddlResult = new DdlResult();\n                        processName(ddlResult, schmeaName, alterTable.getName(), false);\n                        ddlResult.setType(EventType.ALTER);\n                        ddlResults.add(ddlResult);\n                    }\n                }\n            } else if (statement instanceof SQLDropTableStatement) {\n                SQLDropTableStatement dropTable = (SQLDropTableStatement) statement;\n                for (SQLExprTableSource tableSource : dropTable.getTableSources()) {\n                    DdlResult ddlResult = new DdlResult();\n                    processName(ddlResult, schmeaName, tableSource.getExpr(), false);\n                    ddlResult.setType(EventType.ERASE);\n                    ddlResults.add(ddlResult);\n                }\n            } else if (statement instanceof SQLCreateIndexStatement) {\n                SQLCreateIndexStatement createIndex = (SQLCreateIndexStatement) statement;\n                SQLTableSource tableSource = createIndex.getTable();\n                DdlResult ddlResult = new DdlResult();\n                processName(ddlResult, schmeaName, ((SQLExprTableSource) tableSource).getExpr(), false);\n                ddlResult.setType(EventType.CINDEX);\n                ddlResults.add(ddlResult);\n            } else if (statement instanceof SQLDropIndexStatement) {\n                SQLDropIndexStatement dropIndex = (SQLDropIndexStatement) statement;\n                SQLExprTableSource tableSource = dropIndex.getTableName();\n                DdlResult ddlResult = new DdlResult();\n                processName(ddlResult, schmeaName, tableSource.getExpr(), false);\n                ddlResult.setType(EventType.DINDEX);\n                ddlResults.add(ddlResult);\n            } else if (statement instanceof SQLTruncateStatement) {\n                SQLTruncateStatement truncate = (SQLTruncateStatement) statement;\n                for (SQLExprTableSource tableSource : truncate.getTableSources()) {\n                    DdlResult ddlResult = new DdlResult();\n                    processName(ddlResult, schmeaName, tableSource.getExpr(), false);\n                    ddlResult.setType(EventType.TRUNCATE);\n                    ddlResults.add(ddlResult);\n                }\n            } else if (statement instanceof MySqlRenameTableStatement) {\n                MySqlRenameTableStatement rename = (MySqlRenameTableStatement) statement;\n                for (MySqlRenameTableStatement.Item item : rename.getItems()) {\n                    DdlResult ddlResult = new DdlResult();\n                    processName(ddlResult, schmeaName, item.getName(), true);\n                    processName(ddlResult, schmeaName, item.getTo(), false);\n                    ddlResult.setType(EventType.RENAME);\n                    ddlResults.add(ddlResult);\n                }\n            } else if (statement instanceof SQLInsertStatement) {\n                DdlResult ddlResult = new DdlResult();\n                SQLInsertStatement insert = (SQLInsertStatement) statement;\n                processName(ddlResult, schmeaName, insert.getTableName(), false);\n                ddlResult.setType(EventType.INSERT);\n                ddlResults.add(ddlResult);\n            } else if (statement instanceof SQLUpdateStatement) {\n                DdlResult ddlResult = new DdlResult();\n                SQLUpdateStatement update = (SQLUpdateStatement) statement;\n                // 拿到的表名可能为null,比如update a,b set a.id=x\n                processName(ddlResult, schmeaName, update.getTableName(), false);\n                ddlResult.setType(EventType.UPDATE);\n                ddlResults.add(ddlResult);\n            } else if (statement instanceof SQLDeleteStatement) {\n                DdlResult ddlResult = new DdlResult();\n                SQLDeleteStatement delete = (SQLDeleteStatement) statement;\n                // 拿到的表名可能为null,比如delete a,b from a where a.id = b.id\n                processName(ddlResult, schmeaName, delete.getTableName(), false);\n                ddlResult.setType(EventType.DELETE);\n                ddlResults.add(ddlResult);\n            } else if (statement instanceof SQLCreateDatabaseStatement) {\n                SQLCreateDatabaseStatement create = (SQLCreateDatabaseStatement) statement;\n                DdlResult ddlResult = new DdlResult();\n                ddlResult.setType(EventType.QUERY);\n                processName(ddlResult, create.getDatabaseName(), null, false);\n                ddlResults.add(ddlResult);\n            } else if (statement instanceof SQLDropDatabaseStatement) {\n                SQLDropDatabaseStatement drop = (SQLDropDatabaseStatement) statement;\n                DdlResult ddlResult = new DdlResult();\n                ddlResult.setType(EventType.QUERY);\n                processName(ddlResult, drop.getDatabaseName(), null, false);\n                ddlResults.add(ddlResult);\n            }\n        }\n\n        return ddlResults;\n    }\n\n    private static void processName(DdlResult ddlResult, String schema, SQLExpr sqlName, boolean isOri) {\n        if (sqlName == null) {\n            if (StringUtils.isNotBlank(schema)) {\n                ddlResult.setSchemaName(schema);\n            }\n            return;\n        }\n\n        String table = null;\n        if (sqlName instanceof SQLPropertyExpr) {\n            SQLIdentifierExpr owner = (SQLIdentifierExpr) ((SQLPropertyExpr) sqlName).getOwner();\n            schema = unescapeName(owner.getName());\n            table = unescapeName(((SQLPropertyExpr) sqlName).getName());\n        } else if (sqlName instanceof SQLIdentifierExpr) {\n            table = unescapeName(((SQLIdentifierExpr) sqlName).getName());\n        }\n\n        if (isOri) {\n            ddlResult.setOriSchemaName(schema);\n            ddlResult.setOriTableName(table);\n        } else {\n            ddlResult.setSchemaName(schema);\n            ddlResult.setTableName(table);\n        }\n    }\n\n    public static String unescapeName(String name) {\n        if (name != null && name.length() > 2) {\n            char c0 = name.charAt(0);\n            char x0 = name.charAt(name.length() - 1);\n            if ((c0 == '\"' && x0 == '\"') || (c0 == '`' && x0 == '`')) {\n                return name.substring(1, name.length() - 1);\n            }\n        }\n\n        return name;\n    }\n\n    public static String unescapeQuotaName(String name) {\n        if (name != null && name.length() > 2) {\n            char c0 = name.charAt(0);\n            char x0 = name.charAt(name.length() - 1);\n            if (c0 == '\\'' && x0 == '\\'') {\n                return name.substring(1, name.length() - 1);\n            }\n        }\n\n        return name;\n    }\n\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/ddl/SimpleDdlParser.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.ddl;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.oro.text.regex.Perl5Matcher;\n\nimport com.alibaba.otter.canal.filter.PatternUtils;\nimport com.alibaba.otter.canal.protocol.CanalEntry.EventType;\n\n/**\n * 简单的ddl解析工具类，后续可使用cobar/druid的SqlParser进行语法树解析\n * \n * <pre>\n * 解析支持：\n * a. 带schema: retl.retl_mark\n * b. 带引号` :  `retl.retl_mark`\n * c. 存在换行符： create table \\n `retl.retl_mark`\n * </pre>\n * \n * http://dev.mysql.com/doc/refman/5.6/en/sql-syntax-data-definition.html\n * \n * @author jianghang 2013-1-22 下午10:03:22\n * @version 1.0.0\n */\npublic class SimpleDdlParser {\n\n    public static final String CREATE_PATTERN         = \"^\\\\s*CREATE\\\\s*(TEMPORARY)?\\\\s*TABLE\\\\s*(.*)$\";\n    public static final String DROP_PATTERN           = \"^\\\\s*DROP\\\\s*(TEMPORARY)?\\\\s*TABLE\\\\s*(.*)$\";\n    public static final String ALERT_PATTERN          = \"^\\\\s*ALTER\\\\s*(IGNORE)?\\\\s*TABLE\\\\s*(.*)$\";\n    public static final String TRUNCATE_PATTERN       = \"^\\\\s*TRUNCATE\\\\s*(TABLE)?\\\\s*(.*)$\";\n    public static final String TABLE_PATTERN          = \"^(IF\\\\s*NOT\\\\s*EXISTS\\\\s*)?(IF\\\\s*EXISTS\\\\s*)?(`?.+?`?[;\\\\(\\\\s]+?)?.*$\";         // 采用非贪婪模式\n    public static final String INSERT_PATTERN         = \"^\\\\s*(INSERT|MERGE|REPLACE)(.*)$\";\n    public static final String UPDATE_PATTERN         = \"^\\\\s*UPDATE(.*)$\";\n    public static final String DELETE_PATTERN         = \"^\\\\s*DELETE(.*)$\";\n    public static final String RENAME_PATTERN         = \"^\\\\s*RENAME\\\\s+TABLE\\\\s+(.+?)\\\\s+TO\\\\s+(.+?)$\";\n    public static final String RENAME_REMNANT_PATTERN = \"^\\\\s*(.+?)\\\\s+TO\\\\s+(.+?)$\";\n\n    /**\n     * <pre>\n     * CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name\n     *         [index_type]\n     *         ON tbl_name (index_col_name,...)\n     *         [algorithm_option | lock_option] ...\n     *         \n     * http://dev.mysql.com/doc/refman/5.6/en/create-index.html\n     * </pre>\n     */\n    public static final String CREATE_INDEX_PATTERN   = \"^\\\\s*CREATE\\\\s*(UNIQUE)?(FULLTEXT)?(SPATIAL)?\\\\s*INDEX\\\\s*(.*?)\\\\s+ON\\\\s+(.*?)$\";\n    public static final String DROP_INDEX_PATTERN     = \"^\\\\s*DROP\\\\s*INDEX\\\\s*(.*?)\\\\s+ON\\\\s+(.*?)$\";\n\n    public static DdlResult parse(String queryString, String schmeaName) {\n        queryString = removeComment(queryString); // 去除/* */的sql注释内容\n        DdlResult result = parseDdl(queryString, schmeaName, ALERT_PATTERN, 2);\n        if (result != null) {\n            result.setType(EventType.ALTER);\n            return result;\n        }\n\n        result = parseDdl(queryString, schmeaName, CREATE_PATTERN, 2);\n        if (result != null) {\n            result.setType(EventType.CREATE);\n            return result;\n        }\n\n        result = parseDdl(queryString, schmeaName, DROP_PATTERN, 2);\n        if (result != null) {\n            result.setType(EventType.ERASE);\n            return result;\n        }\n\n        result = parseDdl(queryString, schmeaName, TRUNCATE_PATTERN, 2);\n        if (result != null) {\n            result.setType(EventType.TRUNCATE);\n            return result;\n        }\n\n        result = parseRename(queryString, schmeaName, RENAME_PATTERN);\n        if (result != null) {\n            result.setType(EventType.RENAME);\n\n            String[] renameStrings = queryString.split(\",\");\n            if (renameStrings.length > 1) {\n                DdlResult lastResult = result;\n                for (int i = 1; i < renameStrings.length; i++) {\n                    DdlResult ddlResult = parseRename(renameStrings[i], schmeaName, RENAME_REMNANT_PATTERN);\n                    ddlResult.setType(EventType.RENAME);\n                    lastResult.setRenameTableResult(ddlResult);\n                    lastResult = ddlResult;\n                }\n            }\n\n            return result;\n        }\n\n        result = parseDdl(queryString, schmeaName, CREATE_INDEX_PATTERN, 5);\n        if (result != null) {\n            result.setType(EventType.CINDEX);\n            return result;\n        }\n\n        result = parseDdl(queryString, schmeaName, DROP_INDEX_PATTERN, 2);\n        if (result != null) {\n            result.setType(EventType.DINDEX);\n            return result;\n        }\n\n        result = new DdlResult(schmeaName);\n        if (isDml(queryString, INSERT_PATTERN)) {\n            result.setType(EventType.INSERT);\n            return result;\n        }\n\n        if (isDml(queryString, UPDATE_PATTERN)) {\n            result.setType(EventType.UPDATE);\n            return result;\n        }\n\n        if (isDml(queryString, DELETE_PATTERN)) {\n            result.setType(EventType.DELETE);\n            return result;\n        }\n\n        result.setType(EventType.QUERY);\n        return result;\n    }\n\n    private static DdlResult parseDdl(String queryString, String schmeaName, String pattern, int index) {\n        Perl5Matcher matcher = new Perl5Matcher();\n        if (matcher.matches(queryString, PatternUtils.getPattern(pattern))) {\n            DdlResult result = parseTableName(matcher.getMatch().group(index), schmeaName);\n            return result != null ? result : new DdlResult(schmeaName); // 无法解析时，直接返回schmea，进行兼容处理\n        }\n\n        return null;\n    }\n\n    private static boolean isDml(String queryString, String pattern) {\n        Perl5Matcher matcher = new Perl5Matcher();\n        if (matcher.matches(queryString, PatternUtils.getPattern(pattern))) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    private static DdlResult parseRename(String queryString, String schmeaName, String pattern) {\n        Perl5Matcher matcher = new Perl5Matcher();\n        if (matcher.matches(queryString, PatternUtils.getPattern(pattern))) {\n            DdlResult orign = parseTableName(matcher.getMatch().group(1), schmeaName);\n            DdlResult target = parseTableName(matcher.getMatch().group(2), schmeaName);\n            if (orign != null && target != null) {\n                return new DdlResult(target.getSchemaName(),\n                    target.getTableName(),\n                    orign.getSchemaName(),\n                    orign.getTableName());\n            }\n        }\n\n        return null;\n    }\n\n    private static DdlResult parseTableName(String matchString, String schmeaName) {\n        Perl5Matcher tableMatcher = new Perl5Matcher();\n        matchString = matchString + \" \";\n        if (tableMatcher.matches(matchString, PatternUtils.getPattern(TABLE_PATTERN))) {\n            String tableString = tableMatcher.getMatch().group(3);\n            if (StringUtils.isEmpty(tableString)) {\n                return null;\n            }\n\n            tableString = StringUtils.removeEnd(tableString, \";\");\n            tableString = StringUtils.removeEnd(tableString, \"(\");\n            tableString = StringUtils.trim(tableString);\n            // 特殊处理引号`\n            tableString = removeEscape(tableString);\n            // 处理schema.table的写法\n            String names[] = StringUtils.split(tableString, \".\");\n            if (names.length == 0) {\n                return null;\n            }\n\n            if (names != null && names.length > 1) {\n                return new DdlResult(removeEscape(names[0]), removeEscape(names[1]));\n            } else {\n                return new DdlResult(schmeaName, removeEscape(names[0]));\n            }\n        }\n\n        return null;\n    }\n\n    private static String removeEscape(String str) {\n        String result = StringUtils.removeEnd(str, \"`\");\n        result = StringUtils.removeStart(result, \"`\");\n        return result;\n    }\n\n    private static String removeComment(String sql) {\n        if (sql == null) {\n            return null;\n        }\n\n        String start = \"/*\";\n        String end = \"*/\";\n        while (true) {\n            // 循环找到所有的注释\n            int index0 = sql.indexOf(start);\n            if (index0 == -1) {\n                return sql;\n            }\n            int index1 = sql.indexOf(end, index0);\n            if (index1 == -1) {\n                return sql;\n            }\n            StringBuilder sb = new StringBuilder();\n            sb.append(sql.substring(0, index0));\n            sb.append(\" \");\n            sb.append(sql.substring(index1 + end.length()));\n            sql = sb.toString();\n        }\n    }\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/local/BinLogFileQueue.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.local;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Timer;\nimport java.util.TimerTask;\nimport java.util.concurrent.locks.Condition;\nimport java.util.concurrent.locks.ReentrantLock;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.apache.commons.io.FileUtils;\nimport org.apache.commons.io.filefilter.IOFileFilter;\n\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\n\n/**\n * 维护binlog文件列表\n *\n * @author jianghang 2012-7-7 下午03:48:05\n * @version 1.0.0\n */\npublic class BinLogFileQueue {\n\n    private String              baseName       = \"mysql-bin.\";\n    private List<File>          binlogs        = new ArrayList<>();\n    private Pattern binLogPattern = Pattern.compile(baseName + \"\\\\d+$\");\n    private File                directory;\n    private ReentrantLock       lock           = new ReentrantLock();\n    private Condition           nextCondition  = lock.newCondition();\n    private Timer               timer          = new Timer(true);\n    private long                reloadInterval = 10 * 1000L;           // 10秒\n    private CanalParseException exception      = null;\n\n    public BinLogFileQueue(String directory){\n        this(new File(directory));\n    }\n\n    public BinLogFileQueue(File directory){\n        this.directory = directory;\n\n        if (!directory.canRead()) {\n            throw new CanalParseException(\"Binlog index missing or unreadable;  \" + directory.getAbsolutePath());\n        }\n\n        List<File> files = listBinlogFiles();\n        for (File file : files) {\n            offer(file);\n        }\n\n        timer.scheduleAtFixedRate(new TimerTask() {\n\n            public void run() {\n                try {\n                    // File errorFile = new File(BinLogFileQueue.this.directory,\n                    // errorFileName);\n                    // if (errorFile.isFile() && errorFile.exists()) {\n                    // String text = StringUtils.join(IOUtils.readLines(new\n                    // FileInputStream(errorFile)), \"\\n\");\n                    // exception = new CanalParseException(text);\n                    // }\n                    List<File> files = listBinlogFiles();\n                    for (File file : files) {\n                        offer(file);\n                    }\n                } catch (Throwable e) {\n                    exception = new CanalParseException(e);\n                }\n\n                if (exception != null) {\n                    offer(null);\n                }\n            }\n        }, reloadInterval, reloadInterval);\n    }\n\n    /**\n     * 根据前一个文件，获取符合条件的下一个binlog文件\n     *\n     * @param pre\n     * @return\n     */\n    public File getNextFile(File pre) {\n        try {\n            lock.lockInterruptibly();\n            if (exception != null) {\n                throw exception;\n            }\n\n            if (binlogs.size() == 0) {\n                return null;\n            } else {\n                if (pre == null) {// 第一次\n                    return binlogs.get(0);\n                } else {\n                    int index = seek(pre);\n                    if (index < binlogs.size() - 1) {\n                        return binlogs.get(index + 1);\n                    } else {\n                        return null;\n                    }\n                }\n            }\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            return null;\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    public File getBefore(File file) {\n        try {\n            lock.lockInterruptibly();\n            if (exception != null) {\n                throw exception;\n            }\n\n            if (binlogs.size() == 0) {\n                return null;\n            } else {\n                if (file == null) {// 第一次\n                    return binlogs.get(binlogs.size() - 1);\n                } else {\n                    int index = seek(file);\n                    if (index > 0) {\n                        return binlogs.get(index - 1);\n                    } else {\n                        return null;\n                    }\n                }\n            }\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            return null;\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    /**\n     * 根据前一个文件，获取符合条件的下一个binlog文件\n     *\n     * @param pre\n     * @return\n     * @throws InterruptedException\n     */\n    public File waitForNextFile(File pre) throws InterruptedException {\n        try {\n            lock.lockInterruptibly();\n            if (binlogs.size() == 0) {\n                nextCondition.await();// 等待新文件\n            }\n\n            if (exception != null) {\n                throw exception;\n            }\n            if (pre == null) {// 第一次\n                return binlogs.get(0);\n            } else {\n                int index = seek(pre);\n                if (index < binlogs.size() - 1) {\n                    return binlogs.get(index + 1);\n                } else {\n                    nextCondition.await();// 等待新文件\n                    return waitForNextFile(pre);// 唤醒之后递归调用一下\n                }\n            }\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    /**\n     * 获取当前所有binlog文件\n     */\n    public List<File> currentBinlogs() {\n        return new ArrayList<>(binlogs);\n    }\n\n    public void destory() {\n        try {\n            lock.lockInterruptibly();\n            timer.cancel();\n            binlogs.clear();\n\n            nextCondition.signalAll();// 唤醒线程，通知退出\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    private boolean offer(File file) {\n        try {\n            lock.lockInterruptibly();\n            if (file != null) {\n                if (!binlogs.contains(file)) {\n                    binlogs.add(file);\n                    nextCondition.signalAll();// 唤醒\n                    return true;\n                }\n            }\n\n            nextCondition.signalAll();// 唤醒\n            return false;\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            return false;\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    private List<File> listBinlogFiles() {\n        List<File> files = new ArrayList<>();\n        files.addAll(FileUtils.listFiles(directory, new IOFileFilter() {\n\n            public boolean accept(File file) {\n                Matcher matcher = binLogPattern.matcher(file.getName());\n                return matcher.find();\n            }\n\n            public boolean accept(File dir, String name) {\n                return true;\n            }\n        }, null));\n        // 排一下序列\n        files.sort(Comparator.comparing(File::getName));\n        return files;\n    }\n\n    private int seek(File file) {\n        for (int i = 0; i < binlogs.size(); i++) {\n            File binlog = binlogs.get(i);\n            if (binlog.getName().equals(file.getName())) {\n                return i;\n            }\n        }\n\n        return -1;\n    }\n\n    // ================== setter / getter ===================\n\n    public void setBaseName(String baseName) {\n        this.baseName = baseName;\n    }\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/local/BufferedFileDataInput.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.local;\n\nimport java.io.BufferedInputStream;\nimport java.io.DataInputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.nio.channels.ClosedByInterruptException;\nimport java.nio.channels.FileChannel;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * @author jianghang 2012-7-7 下午03:10:47\n * @version 1.0.0\n */\npublic class BufferedFileDataInput {\n\n    private static final Logger logger = LoggerFactory.getLogger(BufferedFileDataInput.class);\n    // Read parameters.\n    private File                file;\n    private int                 size;\n\n    // Variables to control reading.\n    private FileInputStream     fileInput;\n    private BufferedInputStream bufferedInput;\n    private DataInputStream     dataInput;\n    private long                offset;\n    private FileChannel         fileChannel;\n\n    public BufferedFileDataInput(File file, int size) throws FileNotFoundException, IOException, InterruptedException{\n        this.file = file;\n        this.size = size;\n    }\n\n    public BufferedFileDataInput(File file) throws FileNotFoundException, IOException, InterruptedException{\n        this(file, 1024);\n    }\n\n    public long available() throws IOException {\n        return fileChannel.size() - offset;\n    }\n\n    public long skip(long bytes) throws IOException {\n        long bytesSkipped = bufferedInput.skip(bytes);\n        offset += bytesSkipped;\n        return bytesSkipped;\n    }\n\n    public void seek(long seekBytes) throws FileNotFoundException, IOException, InterruptedException {\n        fileInput = new FileInputStream(file);\n        fileChannel = fileInput.getChannel();\n\n        try {\n            fileChannel.position(seekBytes);\n        } catch (ClosedByInterruptException e) {\n            throw new InterruptedException();\n        }\n        bufferedInput = new BufferedInputStream(fileInput, size);\n        dataInput = new DataInputStream(bufferedInput);\n        offset = seekBytes;\n    }\n\n    public void readFully(byte[] bytes) throws IOException {\n        readFully(bytes, 0, bytes.length);\n    }\n\n    public void readFully(byte[] bytes, int start, int len) throws IOException {\n        dataInput.readFully(bytes, start, len);\n        offset += len;\n    }\n\n    public void close() {\n        try {\n            if (fileChannel != null) {\n                fileChannel.close();\n                fileInput.close();\n            }\n        } catch (IOException e) {\n            logger.warn(\"Unable to close buffered file reader: file=\" + file.getName() + \" exception=\" + e.getMessage());\n        }\n\n        fileChannel = null;\n        fileInput = null;\n        bufferedInput = null;\n        dataInput = null;\n        offset = -1;\n    }\n\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/rds/BinlogDownloadQueue.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.rds;\n\nimport java.io.*;\nimport java.util.Comparator;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.locks.LockSupport;\n\nimport javax.net.ssl.SSLContext;\n\nimport org.apache.commons.compress.archivers.tar.TarArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveInputStream;\nimport org.apache.commons.io.FileUtils;\nimport org.apache.commons.io.IOUtils;\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.http.Header;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.client.config.RequestConfig;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.config.RegistryBuilder;\nimport org.apache.http.conn.socket.ConnectionSocketFactory;\nimport org.apache.http.conn.socket.PlainConnectionSocketFactory;\nimport org.apache.http.conn.ssl.NoopHostnameVerifier;\nimport org.apache.http.conn.ssl.SSLConnectionSocketFactory;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.HttpClientBuilder;\nimport org.apache.http.impl.conn.PoolingHttpClientConnectionManager;\nimport org.apache.http.ssl.SSLContextBuilder;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\nimport com.alibaba.otter.canal.parse.inbound.mysql.rds.data.BinlogFile;\n\nimport io.netty.handler.codec.http.HttpResponseStatus;\n\n/**\n * @author chengjin.lyf on 2018/8/7 下午3:10\n * @since 1.0.25\n */\npublic class BinlogDownloadQueue {\n\n    private static final Logger             logger        = LoggerFactory.getLogger(BinlogDownloadQueue.class);\n    private static final int                TIMEOUT       = 10000;\n\n    private LinkedBlockingQueue<BinlogFile> downloadQueue = new LinkedBlockingQueue<>();\n    private LinkedBlockingQueue<Runnable>   taskQueue     = new LinkedBlockingQueue<>();\n    private LinkedList<BinlogFile>          binlogList;\n    private final int                       batchFileSize;\n    private Thread                          downloadThread;\n    public boolean                          running       = true;\n    private final String                    destDir;\n    private String                          hostId;\n    private int                             currentSize;\n    private String                          lastDownload;\n\n    public BinlogDownloadQueue(List<BinlogFile> downloadQueue, int batchFileSize, String destDir) throws IOException{\n        this.binlogList = new LinkedList(downloadQueue);\n        this.batchFileSize = batchFileSize;\n        this.destDir = destDir;\n        this.currentSize = 0;\n        prepareBinlogList();\n        cleanDir();\n    }\n\n    private void prepareBinlogList() {\n        for (BinlogFile binlog : this.binlogList) {\n            String fileName = StringUtils.substringBetween(binlog.getDownloadLink(), \"mysql-bin.\", \"?\");\n            binlog.setFileName(fileName);\n        }\n        this.binlogList.sort(Comparator.comparing(BinlogFile::getFileName));\n    }\n\n    public void cleanDir() throws IOException {\n        File destDirFile = new File(destDir);\n        FileUtils.forceMkdir(destDirFile);\n        FileUtils.cleanDirectory(destDirFile);\n    }\n\n    public void silenceDownload() {\n        if (downloadThread != null) {\n            return;\n        }\n        downloadThread = new Thread(new DownloadThread(), \"download-\" + destDir);\n        downloadThread.setDaemon(true);\n        downloadThread.start();\n    }\n\n    public BinlogFile tryOne() throws Throwable {\n        BinlogFile binlogFile = binlogList.poll();\n        if (binlogFile == null) {\n            throw new CanalParseException(\"download binlog is null\");\n        }\n        download(binlogFile);\n        hostId = binlogFile.getHostInstanceID();\n        this.currentSize++;\n        return binlogFile;\n    }\n\n    public void notifyNotMatch() {\n        this.currentSize--;\n        filter(hostId);\n    }\n\n    private void filter(String hostInstanceId) {\n        Iterator<BinlogFile> it = binlogList.iterator();\n        while (it.hasNext()) {\n            BinlogFile bf = it.next();\n            if (bf.getHostInstanceID().equalsIgnoreCase(hostInstanceId)) {\n                it.remove();\n            } else {\n                hostId = bf.getHostInstanceID();\n            }\n        }\n    }\n\n    public boolean isLastFile(String fileName) {\n        String needCompareName = lastDownload;\n        if (StringUtils.isNotEmpty(needCompareName) && StringUtils.endsWith(needCompareName, \"tar\")) {\n            needCompareName = needCompareName.substring(0, needCompareName.lastIndexOf(\".\"));\n        }\n        return (needCompareName == null || fileName.equalsIgnoreCase(needCompareName)) && binlogList.isEmpty();\n    }\n\n    public void prepare() throws InterruptedException {\n        for (int i = this.currentSize; i < batchFileSize && !binlogList.isEmpty(); i++) {\n            BinlogFile binlogFile = null;\n            while (!binlogList.isEmpty()) {\n                binlogFile = binlogList.poll();\n                if (!binlogFile.getHostInstanceID().equalsIgnoreCase(hostId)) {\n                    continue;\n                }\n                break;\n            }\n            if (binlogFile == null) {\n                break;\n            }\n            this.downloadQueue.put(binlogFile);\n            this.lastDownload = \"mysql-bin.\" + binlogFile.getFileName();\n            this.currentSize++;\n        }\n    }\n\n    public void downOne() {\n        this.currentSize--;\n    }\n\n    public void release() {\n        running = false;\n        this.currentSize = 0;\n        binlogList.clear();\n        downloadQueue.clear();\n        try {\n            downloadThread.interrupt();\n            downloadThread.join();// 等待其结束\n        } catch (InterruptedException e) {\n            // ignore\n        } finally {\n            downloadThread = null;\n        }\n    }\n\n    private void download(BinlogFile binlogFile) throws Throwable {\n        String downloadLink = binlogFile.getDownloadLink();\n        String fileName = binlogFile.getFileName();\n\n        downloadLink = downloadLink.trim();\n        CloseableHttpClient httpClient = null;\n        if (downloadLink.startsWith(\"https\")) {\n            HttpClientBuilder builder = HttpClientBuilder.create();\n            builder.setMaxConnPerRoute(50);\n            builder.setMaxConnTotal(100);\n            // 创建支持忽略证书的https\n            final SSLContext sslContext = new SSLContextBuilder()\n                    .loadTrustMaterial(null, (x509Certificates, s) -> true)\n                    .build();\n\n            httpClient = HttpClientBuilder.create()\n                .setSSLContext(sslContext)\n                .setConnectionManager(new PoolingHttpClientConnectionManager(RegistryBuilder.<ConnectionSocketFactory> create()\n                    .register(\"http\", PlainConnectionSocketFactory.INSTANCE)\n                    .register(\"https\", new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE))\n                    .build()))\n                .build();\n        } else {\n            httpClient = HttpClientBuilder.create().setMaxConnPerRoute(50).setMaxConnTotal(100).build();\n        }\n\n        HttpGet httpGet = new HttpGet(downloadLink);\n        RequestConfig requestConfig = RequestConfig.custom()\n            .setConnectTimeout(TIMEOUT)\n            .setConnectionRequestTimeout(TIMEOUT)\n            .setSocketTimeout(TIMEOUT)\n            .build();\n        httpGet.setConfig(requestConfig);\n        HttpResponse response = httpClient.execute(httpGet);\n        int statusCode = response.getStatusLine().getStatusCode();\n        if (statusCode != HttpResponseStatus.OK.code()) {\n            throw new RuntimeException(\"download failed , url:\" + downloadLink + \" , statusCode:\" + statusCode);\n        }\n        saveFile(new File(destDir), \"mysql-bin.\" + fileName, response);\n    }\n\n    private static void saveFile(File parentFile, String fileName, HttpResponse response) throws IOException {\n        InputStream is = response.getEntity().getContent();\n        boolean isChunked = response.getEntity().isChunked();\n        Header contentLengthHeader = response.getFirstHeader(\"Content-Length\");\n        long totalSize = (isChunked || contentLengthHeader == null) ? 0 : Long.parseLong(contentLengthHeader.getValue());\n        if (response.getFirstHeader(\"Content-Disposition\") != null) {\n            fileName = response.getFirstHeader(\"Content-Disposition\").getValue();\n            fileName = StringUtils.substringAfter(fileName, \"filename=\");\n        }\n        boolean isTar = StringUtils.endsWith(fileName, \".tar\");\n        FileUtils.forceMkdir(parentFile);\n        FileOutputStream fos = null;\n        try {\n            if (isTar) {\n                TarArchiveInputStream tais = new TarArchiveInputStream(is);\n                TarArchiveEntry tarArchiveEntry = null;\n                while ((tarArchiveEntry = tais.getNextTarEntry()) != null) {\n                    String name = tarArchiveEntry.getName();\n                    File tarFile = new File(parentFile, name + \".tmp\");\n                    logger.info(\"start to download file \" + tarFile.getName());\n                    if (tarFile.exists()) {\n                        tarFile.delete();\n                    }\n                    BufferedOutputStream bos = null;\n                    try {\n                        bos = new BufferedOutputStream(new FileOutputStream(tarFile));\n                        int read = -1;\n                        byte[] buffer = new byte[1024];\n                        while ((read = tais.read(buffer)) != -1) {\n                            bos.write(buffer, 0, read);\n                        }\n                        logger.info(\"download file \" + tarFile.getName() + \" end!\");\n                        tarFile.renameTo(new File(parentFile, name));\n                    } finally {\n                        IOUtils.closeQuietly(bos);\n                    }\n                }\n                tais.close();\n            } else {\n                File file = new File(parentFile, fileName + \".tmp\");\n                if (file.exists()) {\n                    file.delete();\n                }\n\n                if (!file.isFile()) {\n                    file.createNewFile();\n                }\n                try {\n                    fos = new FileOutputStream(file);\n                    byte[] buffer = new byte[1024];\n                    int len;\n                    long copySize = 0;\n                    long nextPrintProgress = 0;\n                    logger.info(\"start to download file \" + file.getName());\n                    while ((len = is.read(buffer)) != -1) {\n                        fos.write(buffer, 0, len);\n                        copySize += len;\n                        if (totalSize > 0){\n                            long progress = copySize * 100 / totalSize;\n                            if (progress >= nextPrintProgress) {\n                                logger.info(\"download \" + file.getName() + \" progress : \" + progress\n                                        + \"% , download size : \" + copySize + \", total size : \" + totalSize);\n                                nextPrintProgress += 10;\n                            }\n                        }\n                    }\n                    logger.info(\"download file \" + file.getName() + \" end!\");\n                    fos.flush();\n                } finally {\n                    IOUtils.closeQuietly(fos);\n                }\n                file.renameTo(new File(parentFile, fileName));\n            }\n        } finally {\n            IOUtils.closeQuietly(fos);\n        }\n    }\n\n    public void execute(Runnable runnable) throws InterruptedException {\n        taskQueue.put(runnable);\n    }\n\n    private class DownloadThread implements Runnable {\n\n        @Override\n        public void run() {\n            while (running) {\n                BinlogFile binlogFile = null;\n                try {\n                    binlogFile = downloadQueue.poll(5000, TimeUnit.MILLISECONDS);\n                    if (binlogFile != null) {\n                        int retry = 1;\n                        while (true) {\n                            try {\n                                download(binlogFile);\n                                break;\n                            } catch (Throwable e) {\n                                if (retry % 10 == 0) {\n                                    retry = retry + 1;\n                                    try {\n                                        logger.warn(\"download failed + \" + binlogFile.toString() + \"], retry : \"\n                                                    + retry, e);\n                                        // File errorFile = new File(destDir,\n                                        // \"error.txt\");\n                                        // FileWriter writer = new\n                                        // FileWriter(errorFile);\n                                        // writer.write(ExceptionUtils.getFullStackTrace(e));\n                                        // writer.flush();\n                                        // IOUtils.closeQuietly(writer);\n                                        LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(100 * retry));\n                                    } catch (Throwable e1) {\n                                        logger.error(\"write error failed\", e1);\n                                    }\n                                } else {\n                                    retry = retry + 1;\n                                }\n                            }\n                        }\n                    }\n\n                    Runnable runnable = taskQueue.poll(5000, TimeUnit.MILLISECONDS);\n                    if (runnable != null) {\n                        runnable.run();\n                    }\n                } catch (Throwable e) {\n                    logger.error(\"task process failed\", e);\n                }\n            }\n\n        }\n    }\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/rds/HttpHelper.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.rds;\n\nimport static org.apache.http.client.config.RequestConfig.custom;\n\nimport java.io.IOException;\nimport java.net.URI;\nimport java.nio.charset.Charset;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.net.ssl.SSLContext;\n\nimport org.apache.http.HttpStatus;\nimport org.apache.http.NameValuePair;\nimport org.apache.http.client.CookieStore;\nimport org.apache.http.client.config.RequestConfig;\nimport org.apache.http.client.entity.UrlEncodedFormEntity;\nimport org.apache.http.client.methods.CloseableHttpResponse;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.client.methods.HttpPost;\nimport org.apache.http.client.protocol.HttpClientContext;\nimport org.apache.http.client.utils.URIBuilder;\nimport org.apache.http.config.RegistryBuilder;\nimport org.apache.http.conn.socket.ConnectionSocketFactory;\nimport org.apache.http.conn.socket.PlainConnectionSocketFactory;\nimport org.apache.http.conn.ssl.NoopHostnameVerifier;\nimport org.apache.http.conn.ssl.SSLConnectionSocketFactory;\nimport org.apache.http.cookie.Cookie;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.HttpClientBuilder;\nimport org.apache.http.impl.conn.PoolingHttpClientConnectionManager;\nimport org.apache.http.message.BasicNameValuePair;\nimport org.apache.http.ssl.SSLContextBuilder;\nimport org.apache.http.util.EntityUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.google.common.collect.Lists;\n\npublic class HttpHelper {\n\n    protected static final Logger logger = LoggerFactory.getLogger(HttpHelper.class);\n\n    public static byte[] getBytes(String url, int timeout) throws Exception {\n        long start = System.currentTimeMillis();\n        HttpClientBuilder builder = HttpClientBuilder.create();\n        builder.setMaxConnPerRoute(50);\n        builder.setMaxConnTotal(100);\n        CloseableHttpClient httpclient = builder.build();\n        URI uri = new URIBuilder(url).build();\n        RequestConfig config = custom().setConnectTimeout(timeout)\n            .setConnectionRequestTimeout(timeout)\n            .setSocketTimeout(timeout)\n            .build();\n        HttpGet httpGet = new HttpGet(uri);\n        HttpClientContext context = HttpClientContext.create();\n        context.setRequestConfig(config);\n        try (CloseableHttpResponse response = httpclient.execute(httpGet, context)) {\n            int statusCode = response.getStatusLine().getStatusCode();\n            long end = System.currentTimeMillis();\n            long cost = end - start;\n            if (logger.isWarnEnabled()) {\n                logger.warn(\"post \" + url + \", cost : \" + cost);\n            }\n            if (statusCode == HttpStatus.SC_OK) {\n                return EntityUtils.toByteArray(response.getEntity());\n            } else {\n                String errorMsg = EntityUtils.toString(response.getEntity());\n                throw new RuntimeException(\"requestGet remote error, url=\" + uri.toString() + \", code=\" + statusCode\n                        + \", error msg=\" + errorMsg);\n            }\n        } finally {\n            httpGet.releaseConnection();\n        }\n    }\n\n    public static String get(String url, int timeout) {\n        // logger.info(\"get url is :\" + url);\n        // 支持采用https协议，忽略证书\n        url = url.trim();\n        if (url.startsWith(\"https\")) {\n            return getIgnoreCerf(url, null, null, timeout);\n        }\n        long start = System.currentTimeMillis();\n        HttpClientBuilder builder = HttpClientBuilder.create();\n        builder.setMaxConnPerRoute(50);\n        builder.setMaxConnTotal(100);\n        CloseableHttpClient httpclient = builder.build();\n        CloseableHttpResponse response = null;\n        HttpGet httpGet = null;\n        try {\n            URI uri = new URIBuilder(url).build();\n            RequestConfig config = custom().setConnectTimeout(timeout)\n                .setConnectionRequestTimeout(timeout)\n                .setSocketTimeout(timeout)\n                .build();\n            httpGet = new HttpGet(uri);\n            HttpClientContext context = HttpClientContext.create();\n            context.setRequestConfig(config);\n            response = httpclient.execute(httpGet, context);\n            int statusCode = response.getStatusLine().getStatusCode();\n            if (statusCode == HttpStatus.SC_OK) {\n                return EntityUtils.toString(response.getEntity());\n            } else {\n                String errorMsg = EntityUtils.toString(response.getEntity());\n                throw new RuntimeException(\"requestGet remote error, url=\" + uri.toString() + \", code=\" + statusCode\n                                           + \", error msg=\" + errorMsg);\n            }\n        } catch (Throwable t) {\n            long end = System.currentTimeMillis();\n            long cost = end - start;\n            String curlRequest = getCurlRequest(url, null, null, cost);\n            throw new RuntimeException(\"requestGet remote error, request : \" + curlRequest, t);\n        } finally {\n            long end = System.currentTimeMillis();\n            long cost = end - start;\n            printCurlRequest(url, null, null, cost);\n            if (response != null) {\n                try {\n                    response.close();\n                } catch (IOException e) {\n                }\n            }\n            httpGet.releaseConnection();\n        }\n    }\n\n    private static String getIgnoreCerf(String url, CookieStore cookieStore, Map<String, String> params, int timeout) {\n        long start = System.currentTimeMillis();\n        HttpClientBuilder builder = HttpClientBuilder.create();\n        builder.setMaxConnPerRoute(50);\n        builder.setMaxConnTotal(100);\n        HttpGet httpGet = null;\n        CloseableHttpResponse response = null;\n        try {\n            // 创建支持忽略证书的https\n            final SSLContext sslContext = new SSLContextBuilder()\n                    .loadTrustMaterial(null, (x509Certificates, s) -> true)\n                    .build();\n\n            CloseableHttpClient httpClient = HttpClientBuilder.create()\n                .setSSLContext(sslContext)\n                .setConnectionManager(new PoolingHttpClientConnectionManager(RegistryBuilder.<ConnectionSocketFactory> create()\n                    .register(\"http\", PlainConnectionSocketFactory.INSTANCE)\n                    .register(\"https\", new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE))\n                    .build()))\n                .build();\n\n            // ---------------- 创建支持https 的client成功---------\n\n            URI uri = new URIBuilder(url).build();\n            RequestConfig config = custom().setConnectTimeout(timeout)\n                .setConnectionRequestTimeout(timeout)\n                .setSocketTimeout(timeout)\n                .build();\n            httpGet = new HttpGet(uri);\n            HttpClientContext context = HttpClientContext.create();\n            context.setRequestConfig(config);\n            response = httpClient.execute(httpGet, context);\n            int statusCode = response.getStatusLine().getStatusCode();\n            if (statusCode == HttpStatus.SC_OK) {\n                return EntityUtils.toString(response.getEntity());\n            } else {\n                String errorMsg = EntityUtils.toString(response.getEntity());\n                throw new RuntimeException(\"requestGet remote error, url=\" + uri.toString() + \", code=\" + statusCode\n                                           + \", error msg=\" + errorMsg);\n            }\n        } catch (Throwable t) {\n            long end = System.currentTimeMillis();\n            long cost = end - start;\n            String curlRequest = getCurlRequest(url, cookieStore, params, cost);\n            throw new RuntimeException(\"requestPost(Https) remote error, request : \" + curlRequest, t);\n        } finally {\n            long end = System.currentTimeMillis();\n            long cost = end - start;\n            printCurlRequest(url, null, null, cost);\n            if (response != null) {\n                try {\n                    response.close();\n                } catch (IOException e) {\n                }\n            }\n            if (httpGet != null) {\n                httpGet.releaseConnection();\n            }\n        }\n    }\n\n    private static String postIgnoreCerf(String url, CookieStore cookieStore, Map<String, String> params, int timeout) {\n        long start = System.currentTimeMillis();\n        HttpClientBuilder builder = HttpClientBuilder.create();\n        builder.setMaxConnPerRoute(50);\n        builder.setMaxConnTotal(100);\n        HttpPost httpPost = null;\n        CloseableHttpResponse response = null;\n        try {\n            // 创建支持忽略证书的https\n            final SSLContext sslContext = new SSLContextBuilder()\n                    .loadTrustMaterial(null, (x509Certificates, s) -> true)\n                    .build();\n\n            CloseableHttpClient httpClient = HttpClientBuilder.create()\n                .setSSLContext(sslContext)\n                .setConnectionManager(new PoolingHttpClientConnectionManager(RegistryBuilder.<ConnectionSocketFactory> create()\n                    .register(\"http\", PlainConnectionSocketFactory.INSTANCE)\n                    .register(\"https\", new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE))\n                    .build()))\n                .build();\n            // ---------------- 创建支持https 的client成功---------\n\n            URI uri = new URIBuilder(url).build();\n            RequestConfig config = custom().setConnectTimeout(timeout)\n                .setConnectionRequestTimeout(timeout)\n                .setSocketTimeout(timeout)\n                .build();\n            httpPost = new HttpPost(uri);\n            List<NameValuePair> parameters = Lists.newArrayList();\n            for (String key : params.keySet()) {\n                NameValuePair nameValuePair = new BasicNameValuePair(key, params.get(key));\n                parameters.add(nameValuePair);\n            }\n            httpPost.setEntity(new UrlEncodedFormEntity(parameters, Charset.forName(\"UTF-8\")));\n            HttpClientContext context = HttpClientContext.create();\n            context.setRequestConfig(config);\n            context.setCookieStore(cookieStore);\n\n            response = httpClient.execute(httpPost, context);\n            int statusCode = response.getStatusLine().getStatusCode();\n            if (statusCode == HttpStatus.SC_OK) {\n                long end = System.currentTimeMillis();\n                long cost = end - start;\n                printCurlRequest(url, cookieStore, params, cost);\n                return EntityUtils.toString(response.getEntity());\n            } else {\n                long end = System.currentTimeMillis();\n                long cost = end - start;\n                String curlRequest = getCurlRequest(url, cookieStore, params, cost);\n                throw new RuntimeException(\"requestPost(Https) remote error, request : \" + curlRequest\n                                           + \", statusCode=\" + statusCode + \"\");\n            }\n        } catch (Throwable t) {\n            long end = System.currentTimeMillis();\n            long cost = end - start;\n            String curlRequest = getCurlRequest(url, cookieStore, params, cost);\n            throw new RuntimeException(\"requestPost(Https) remote error, request : \" + curlRequest, t);\n        } finally {\n            if (response != null) {\n                try {\n                    response.close();\n                } catch (IOException e) {\n                }\n            }\n            if (httpPost != null) {\n                httpPost.releaseConnection();\n            }\n        }\n    }\n\n    public static String post(String url, CookieStore cookieStore, Map<String, String> params, int timeout) {\n        url = url.trim();\n        // 支持采用https协议，忽略证书\n        if (url.startsWith(\"https\")) {\n            return postIgnoreCerf(url, cookieStore, params, timeout);\n        }\n        long start = System.currentTimeMillis();\n        HttpClientBuilder builder = HttpClientBuilder.create();\n        builder.setMaxConnPerRoute(50);\n        builder.setMaxConnTotal(100);\n        HttpPost httpPost = null;\n        CloseableHttpResponse response = null;\n        try {\n            CloseableHttpClient httpclient = builder.build();\n            URI uri = new URIBuilder(url).build();\n            RequestConfig config = custom().setConnectTimeout(timeout)\n                .setConnectionRequestTimeout(timeout)\n                .setSocketTimeout(timeout)\n                .build();\n            httpPost = new HttpPost(uri);\n            List<NameValuePair> parameters = Lists.newArrayList();\n            for (String key : params.keySet()) {\n                NameValuePair nameValuePair = new BasicNameValuePair(key, params.get(key));\n                parameters.add(nameValuePair);\n            }\n            httpPost.setEntity(new UrlEncodedFormEntity(parameters, Charset.forName(\"UTF-8\")));\n            HttpClientContext context = HttpClientContext.create();\n            context.setRequestConfig(config);\n            context.setCookieStore(cookieStore);\n\n            response = httpclient.execute(httpPost, context);\n            int statusCode = response.getStatusLine().getStatusCode();\n            if (statusCode == HttpStatus.SC_OK) {\n                long end = System.currentTimeMillis();\n                long cost = end - start;\n                printCurlRequest(url, cookieStore, params, cost);\n                return EntityUtils.toString(response.getEntity());\n            } else {\n                long end = System.currentTimeMillis();\n                long cost = end - start;\n                String curlRequest = getCurlRequest(url, cookieStore, params, cost);\n                throw new RuntimeException(\"requestPost remote error, request : \" + curlRequest + \", statusCode=\"\n                                           + statusCode + \";\" + EntityUtils.toString(response.getEntity()));\n            }\n        } catch (Throwable t) {\n            long end = System.currentTimeMillis();\n            long cost = end - start;\n            String curlRequest = getCurlRequest(url, cookieStore, params, cost);\n            throw new RuntimeException(\"requestPost remote error, request : \" + curlRequest, t);\n        } finally {\n            if (response != null) {\n                try {\n                    response.close();\n                } catch (IOException e) {\n                }\n            }\n            if (httpPost != null) {\n                httpPost.releaseConnection();\n            }\n        }\n    }\n\n    public static void printCurlRequest(String url, CookieStore cookieStore, Map<String, String> params, long cost) {\n        logger.warn(getCurlRequest(url, cookieStore, params, cost));\n    }\n\n    private static String getCurlRequest(String url, CookieStore cookieStore, Map<String, String> params, long cost) {\n        if (params == null) {\n            return \"curl '\" + url + \"'\\ncost : \" + cost;\n        } else {\n            StringBuilder paramsStr = new StringBuilder();\n            Iterator<Map.Entry<String, String>> iterator = params.entrySet().iterator();\n            while (iterator.hasNext()) {\n                Map.Entry<String, String> entry = iterator.next();\n                paramsStr.append(entry.getKey() + \"=\" + entry.getValue());\n                if (iterator.hasNext()) {\n                    paramsStr.append(\"&\");\n                }\n            }\n            if (cookieStore == null) {\n                return \"curl '\" + url + \"' -d '\" + paramsStr.toString() + \"'\\ncost : \" + cost;\n            } else {\n                StringBuilder cookieStr = new StringBuilder();\n                List<Cookie> cookies = cookieStore.getCookies();\n                Iterator<Cookie> iteratorCookie = cookies.iterator();\n                while (iteratorCookie.hasNext()) {\n                    Cookie cookie = iteratorCookie.next();\n                    cookieStr.append(cookie.getName() + \"=\" + cookie.getValue());\n                    if (iteratorCookie.hasNext()) {\n                        cookieStr.append(\";\");\n                    }\n                }\n                return \"curl '\" + url + \"' -b '\" + cookieStr + \"' -d '\" + paramsStr.toString() + \"'\\ncost : \" + cost;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/rds/RdsBinlogEventParserProxy.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.rds;\n\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport org.apache.commons.lang.StringUtils;\n\nimport com.alibaba.otter.canal.parse.exception.PositionNotFoundException;\nimport com.alibaba.otter.canal.parse.exception.ServerLogPurgedException;\nimport com.alibaba.otter.canal.parse.inbound.ParserExceptionHandler;\nimport com.alibaba.otter.canal.parse.inbound.mysql.MysqlEventParser;\n\n/**\n * aliyun rds的binlog parser支持\n *\n * <pre>\n * 注意点：aliyun的binlog会有定期清理并备份到oss上, 这里实现了一份自动下载oss+rds binlog的机制\n * </pre>\n *\n * @author chengjin.lyf on 2018/7/20 上午10:52\n * @since 1.0.25\n */\npublic class RdsBinlogEventParserProxy extends MysqlEventParser {\n\n    private String                    rdsOpenApiUrl             = \"https://rds.aliyuncs.com/\"; // openapi地址\n    private String                    accesskey;                                              // 云账号的ak\n    private String                    secretkey;                                              // 云账号sk\n    private String                    instanceId;                                             // rds实例id\n    private String                    directory;                                              // binlog目录\n    private int                       batchFileSize             = 4;                          // 最多下载的binlog文件数量\n\n    private RdsLocalBinlogEventParser rdsLocalBinlogEventParser = null;\n    private ExecutorService           executorService           = Executors.newSingleThreadExecutor(r -> {\n                                                                        Thread t = new Thread(r,\n                                                                            \"rds-binlog-daemon-thread\");\n                                                                        t.setDaemon(true);\n                                                                        return t;\n                                                                    });\n\n    @Override\n    public void start() {\n        if (rdsLocalBinlogEventParser == null && StringUtils.isNotEmpty(accesskey) && StringUtils.isNotEmpty(secretkey)\n            && StringUtils.isNotEmpty(instanceId)) {\n            rdsLocalBinlogEventParser = new RdsLocalBinlogEventParser();\n            // rds oss mode\n            setRdsOssMode(true);\n            final ParserExceptionHandler targetHandler = this.getParserExceptionHandler();\n            if (directory == null) {\n                directory = System.getProperty(\"java.io.tmpdir\", \"/tmp\") + \"/\" + destination;\n            }\n            rdsLocalBinlogEventParser.setLogPositionManager(this.getLogPositionManager());\n            rdsLocalBinlogEventParser.setDestination(destination);\n            rdsLocalBinlogEventParser.setAlarmHandler(this.getAlarmHandler());\n            rdsLocalBinlogEventParser.setConnectionCharsetStd(this.connectionCharset);\n            rdsLocalBinlogEventParser.setEnableTsdb(this.enableTsdb);\n            rdsLocalBinlogEventParser.setEventBlackFilter(this.eventBlackFilter);\n            rdsLocalBinlogEventParser.setFilterQueryDcl(this.filterQueryDcl);\n            rdsLocalBinlogEventParser.setFilterQueryDdl(this.filterQueryDdl);\n            rdsLocalBinlogEventParser.setFilterQueryDml(this.filterQueryDml);\n            rdsLocalBinlogEventParser.setFilterRows(this.filterRows);\n            rdsLocalBinlogEventParser.setFilterTableError(this.filterTableError);\n            // rdsLocalBinlogEventParser.setIsGTIDMode(this.isGTIDMode);\n            rdsLocalBinlogEventParser.setMasterInfo(this.masterInfo);\n            rdsLocalBinlogEventParser.setEventFilter(this.eventFilter);\n            rdsLocalBinlogEventParser.setMasterPosition(this.masterPosition);\n            rdsLocalBinlogEventParser.setTransactionSize(this.transactionSize);\n            rdsLocalBinlogEventParser.setUrl(this.rdsOpenApiUrl);\n            rdsLocalBinlogEventParser.setAccesskey(this.accesskey);\n            rdsLocalBinlogEventParser.setSecretkey(this.secretkey);\n            rdsLocalBinlogEventParser.setInstanceId(this.instanceId);\n            rdsLocalBinlogEventParser.setEventSink(eventSink);\n            rdsLocalBinlogEventParser.setDirectory(directory);\n            rdsLocalBinlogEventParser.setBatchFileSize(batchFileSize);\n            rdsLocalBinlogEventParser.setParallel(this.parallel);\n            rdsLocalBinlogEventParser.setParallelBufferSize(this.parallelBufferSize);\n            rdsLocalBinlogEventParser.setParallelThreadSize(this.parallelThreadSize);\n            rdsLocalBinlogEventParser.setFinishListener(() -> executorService.execute(() -> {\n                rdsLocalBinlogEventParser.stop();\n                // empty the dump error count,or will go into local binlog mode again,with error\n                // position,never get out,fixed by bucketli\n                RdsBinlogEventParserProxy.this.setDumpErrorCount(0);\n                RdsBinlogEventParserProxy.this.start();\n            }));\n            this.setParserExceptionHandler(e -> {\n                handleMysqlParserException(e);\n                if (targetHandler != null) {\n                    targetHandler.handle(e);\n                }\n            });\n        }\n\n        super.start();\n    }\n\n    private void handleMysqlParserException(Throwable throwable) {\n        if (throwable instanceof PositionNotFoundException || throwable instanceof ServerLogPurgedException) {\n            logger.info(\"remove rds not found position, try download rds binlog!\");\n            executorService.execute(() -> {\n                try {\n                    logger.info(\"stop mysql parser!\");\n                    RdsBinlogEventParserProxy rdsBinlogEventParserProxy = RdsBinlogEventParserProxy.this;\n                    long serverId = rdsBinlogEventParserProxy.getServerId();\n                    rdsLocalBinlogEventParser.setServerId(serverId);\n                    rdsBinlogEventParserProxy.stop();\n                } catch (Throwable e) {\n                    logger.info(\"handle exception failed\", e);\n                }\n\n                try {\n                    logger.info(\"start rds mysql binlog parser!\");\n                    rdsLocalBinlogEventParser.start();\n                } catch (Throwable e) {\n                    logger.info(\"handle exception failed\", e);\n                    rdsLocalBinlogEventParser.stop();\n                    RdsBinlogEventParserProxy rdsBinlogEventParserProxy = RdsBinlogEventParserProxy.this;\n                    rdsBinlogEventParserProxy.start();// 继续重试\n                }\n            });\n        }\n    }\n\n    @Override\n    public void stop() {\n        super.stop();\n    }\n\n    @Override\n    public boolean isStart() {\n        return super.isStart();\n    }\n\n    public void setRdsOpenApiUrl(String rdsOpenApiUrl) {\n        this.rdsOpenApiUrl = rdsOpenApiUrl;\n    }\n\n    public void setAccesskey(String accesskey) {\n        this.accesskey = accesskey;\n    }\n\n    public void setSecretkey(String secretkey) {\n        this.secretkey = secretkey;\n    }\n\n    public void setInstanceId(String instanceId) {\n        this.instanceId = instanceId;\n    }\n\n    public void setDirectory(String directory) {\n        this.directory = directory;\n    }\n\n    public void setBatchFileSize(int batchFileSize) {\n        this.batchFileSize = batchFileSize;\n    }\n\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/rds/RdsBinlogOpenApi.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.rds;\n\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.List;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.parse.inbound.mysql.rds.data.BinlogFile;\nimport com.alibaba.otter.canal.parse.inbound.mysql.rds.data.DescribeBinlogFileResult;\nimport com.alibaba.otter.canal.parse.inbound.mysql.rds.data.RdsBackupPolicy;\nimport com.alibaba.otter.canal.parse.inbound.mysql.rds.data.RdsItem;\nimport com.alibaba.otter.canal.parse.inbound.mysql.rds.request.DescribeBackupPolicyRequest;\nimport com.alibaba.otter.canal.parse.inbound.mysql.rds.request.DescribeBinlogFilesRequest;\n\n/**\n * @author agapple 2017年10月14日 下午1:53:52\n * @since 1.0.25\n */\npublic class RdsBinlogOpenApi {\n\n    protected static final Logger logger = LoggerFactory.getLogger(RdsBinlogOpenApi.class);\n\n    public static List<BinlogFile> listBinlogFiles(String url, String ak, String sk, String dbInstanceId,\n                                                   Date startTime, Date endTime) {\n        DescribeBinlogFilesRequest request = new DescribeBinlogFilesRequest();\n        if (StringUtils.isNotEmpty(url)) {\n            try {\n                URI uri = new URI(url);\n                request.setEndPoint(uri.getHost());\n            } catch (URISyntaxException e) {\n                logger.error(\"resolve url host failed, will use default rds endpoint!\");\n            }\n        }\n        request.setStartDate(startTime);\n        request.setEndDate(endTime);\n        request.setPageNumber(1);\n        request.setPageSize(100);\n        request.setRdsInstanceId(dbInstanceId);\n        request.setAccessKeyId(ak);\n        request.setAccessKeySecret(sk);\n        DescribeBinlogFileResult result = null;\n        int retryTime = 3;\n        while (true) {\n            try {\n                result = request.doAction();\n                break;\n            } catch (Exception e) {\n                if (retryTime-- <= 0) {\n                    throw new RuntimeException(e);\n                }\n                try {\n                    Thread.sleep(100L);\n                } catch (InterruptedException e1) {\n                }\n            }\n        }\n        if (result == null) {\n            return Collections.EMPTY_LIST;\n        }\n        RdsItem rdsItem = result.getItems();\n        if (rdsItem != null) {\n            return rdsItem.getBinLogFile();\n        }\n        return Collections.EMPTY_LIST;\n    }\n\n    public static RdsBackupPolicy queryBinlogBackupPolicy(String url, String ak, String sk, String dbInstanceId) {\n        DescribeBackupPolicyRequest request = new DescribeBackupPolicyRequest();\n        if (StringUtils.isNotEmpty(url)) {\n            try {\n                URI uri = new URI(url);\n                request.setEndPoint(uri.getHost());\n            } catch (URISyntaxException e) {\n                logger.error(\"resolve url host failed, will use default rds endpoint!\");\n            }\n        }\n        request.setRdsInstanceId(dbInstanceId);\n        request.setAccessKeyId(ak);\n        request.setAccessKeySecret(sk);\n        int retryTime = 3;\n        while (true) {\n            try {\n                return request.doAction();\n            } catch (Exception e) {\n                if (retryTime-- <= 0) {\n                    throw new RuntimeException(e);\n                }\n                try {\n                    Thread.sleep(100L);\n                } catch (InterruptedException e1) {\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/rds/RdsLocalBinlogEventParser.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.rds;\n\nimport java.io.File;\nimport java.util.Date;\nimport java.util.List;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.commons.lang.math.NumberUtils;\nimport org.springframework.util.Assert;\n\nimport com.alibaba.otter.canal.parse.CanalEventParser;\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\nimport com.alibaba.otter.canal.parse.exception.PositionNotFoundException;\nimport com.alibaba.otter.canal.parse.exception.ServerIdNotMatchException;\nimport com.alibaba.otter.canal.parse.inbound.ErosaConnection;\nimport com.alibaba.otter.canal.parse.inbound.mysql.LocalBinLogConnection;\nimport com.alibaba.otter.canal.parse.inbound.mysql.LocalBinlogEventParser;\nimport com.alibaba.otter.canal.parse.inbound.mysql.rds.data.BinlogFile;\nimport com.alibaba.otter.canal.protocol.position.EntryPosition;\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\n\n/**\n * 基于rds binlog备份文件的复制\n *\n * @author agapple 2017年10月15日 下午1:27:36\n * @since 1.0.25\n */\npublic class RdsLocalBinlogEventParser extends LocalBinlogEventParser implements CanalEventParser, LocalBinLogConnection.FileParserListener {\n\n    private String              url;                // openapi地址\n    private String              accesskey;          // 云账号的ak\n    private String              secretkey;          // 云账号sk\n    private String              instanceId;         // rds实例id\n    private Long                startTime;\n    private Long                endTime;\n    private BinlogDownloadQueue binlogDownloadQueue;\n    private ParseFinishListener finishListener;\n    private int                 batchFileSize;\n\n    public RdsLocalBinlogEventParser(){\n    }\n\n    public void start() throws CanalParseException {\n        try {\n            Assert.notNull(accesskey);\n            Assert.notNull(secretkey);\n            Assert.notNull(instanceId);\n            Assert.notNull(url);\n            Assert.notNull(directory);\n\n            if (endTime == null) {\n                endTime = System.currentTimeMillis();\n            }\n\n            EntryPosition entryPosition = findStartPosition(null);\n            if (entryPosition == null) {\n                throw new PositionNotFoundException(\"position not found!\");\n            }\n            Long startTimeInMill = entryPosition.getTimestamp();\n            if (startTimeInMill == null || startTimeInMill <= 0) {\n                throw new PositionNotFoundException(\"position timestamp is empty!\");\n            }\n\n            startTime = startTimeInMill;\n            List<BinlogFile> binlogFiles = RdsBinlogOpenApi.listBinlogFiles(url,\n                accesskey,\n                secretkey,\n                instanceId,\n                new Date(startTime),\n                new Date(endTime));\n            if (binlogFiles.isEmpty()) {\n                throw new CanalParseException(\"start timestamp : \" + startTimeInMill + \" binlog files is empty\");\n            }\n\n            binlogDownloadQueue = new BinlogDownloadQueue(binlogFiles, batchFileSize, directory);\n            binlogDownloadQueue.silenceDownload();\n            needWait = true;\n            // try to download one file,use to test server id\n            binlogDownloadQueue.tryOne();\n        } catch (Throwable e) {\n            logger.error(\"download binlog failed\", e);\n            throw new CanalParseException(e);\n        }\n        setParserExceptionHandler(this::handleMysqlParserException);\n        super.start();\n    }\n\n    private void handleMysqlParserException(Throwable throwable) {\n        if (throwable instanceof ServerIdNotMatchException) {\n            logger.error(\"server id not match, try download another rds binlog!\");\n            binlogDownloadQueue.notifyNotMatch();\n            try {\n                binlogDownloadQueue.cleanDir();\n                binlogDownloadQueue.tryOne();\n                binlogDownloadQueue.prepare();\n            } catch (Throwable e) {\n                throw new RuntimeException(e);\n            }\n\n            try {\n                binlogDownloadQueue.execute(() -> {\n                    RdsLocalBinlogEventParser.super.stop();\n                    RdsLocalBinlogEventParser.super.start();\n                });\n            } catch (InterruptedException e) {\n                throw new RuntimeException(e);\n            }\n\n        }\n    }\n\n    @Override\n    protected ErosaConnection buildErosaConnection() {\n        ErosaConnection connection = super.buildErosaConnection();\n        if (connection instanceof LocalBinLogConnection) {\n            LocalBinLogConnection localBinLogConnection = (LocalBinLogConnection) connection;\n            localBinLogConnection.setNeedWait(true);\n            localBinLogConnection.setServerId(serverId);\n            localBinLogConnection.setParserListener(this);\n            localBinLogConnection.setRdsOssMode(true);\n        }\n        return connection;\n    }\n\n    public String getUrl() {\n        return url;\n    }\n\n    public void setUrl(String url) {\n        if (StringUtils.isNotEmpty(url)) {\n            this.url = url;\n        }\n    }\n\n    public void setAccesskey(String accesskey) {\n        this.accesskey = accesskey;\n    }\n\n    public void setSecretkey(String secretkey) {\n        this.secretkey = secretkey;\n    }\n\n    public void setInstanceId(String instanceId) {\n        this.instanceId = instanceId;\n    }\n\n    public void setStartTime(Long startTime) {\n        this.startTime = startTime;\n    }\n\n    public void setEndTime(Long endTime) {\n        this.endTime = endTime;\n    }\n\n    @Override\n    public void onFinish(String fileName) {\n        try {\n            binlogDownloadQueue.downOne();\n            File needDeleteFile = new File(directory + File.separator + fileName);\n            if (needDeleteFile.exists()) {\n                needDeleteFile.delete();\n            }\n            // 处理下logManager位点问题\n            LogPosition logPosition = logPositionManager.getLatestIndexBy(destination);\n            Long timestamp = 0L;\n            if (logPosition != null && logPosition.getPostion() != null) {\n                timestamp = logPosition.getPostion().getTimestamp();\n                EntryPosition position = logPosition.getPostion();\n                LogPosition newLogPosition = new LogPosition();\n                String journalName = position.getJournalName();\n                int sepIdx = journalName.indexOf(\".\");\n                String fileIndex = journalName.substring(sepIdx + 1);\n                int index = NumberUtils.toInt(fileIndex) + 1;\n                String newJournalName = journalName.substring(0, sepIdx) + \".\"\n                                        + StringUtils.leftPad(String.valueOf(index), fileIndex.length(), \"0\");\n                newLogPosition.setPostion(new EntryPosition(newJournalName,\n                    4L,\n                    position.getTimestamp(),\n                    position.getServerId()));\n                newLogPosition.setIdentity(logPosition.getIdentity());\n                logPositionManager.persistLogPosition(destination, newLogPosition);\n            }\n\n            if (binlogDownloadQueue.isLastFile(fileName)) {\n                logger.warn(\"last file : \" + fileName + \" , timestamp : \" + timestamp\n                            + \" , all file parse complete, switch to mysql parser!\");\n                finishListener.onFinish();\n                return;\n            } else {\n                logger.warn(\"parse local binlog file : \" + fileName + \" , timestamp : \" + timestamp\n                            + \" , try the next binlog !\");\n            }\n            binlogDownloadQueue.prepare();\n        } catch (Exception e) {\n            logger.error(\"prepare download binlog file failed!\", e);\n            throw new RuntimeException(e);\n        }\n    }\n\n    @Override\n    public void stop() {\n        this.binlogDownloadQueue.release();\n        super.stop();\n    }\n\n    public void setFinishListener(ParseFinishListener finishListener) {\n        this.finishListener = finishListener;\n    }\n\n    public interface ParseFinishListener {\n\n        void onFinish();\n    }\n\n    public void setBatchFileSize(int batchFileSize) {\n        this.batchFileSize = batchFileSize;\n    }\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/rds/data/BinlogFile.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.rds.data;\n\n/**\n * @author chengjin.lyf on 2018/8/7 下午2:26\n * @since 1.0.25\n */\npublic class BinlogFile {\n\n    private Long   FileSize;\n    private String LogBeginTime;\n    private String LogEndTime;\n    private String DownloadLink;\n    private String HostInstanceID;\n    private String LinkExpiredTime;\n    private String fileName;\n\n    public Long getFileSize() {\n        return FileSize;\n    }\n\n    public void setFileSize(Long fileSize) {\n        FileSize = fileSize;\n    }\n\n    public String getLogBeginTime() {\n        return LogBeginTime;\n    }\n\n    public void setLogBeginTime(String logBeginTime) {\n        LogBeginTime = logBeginTime;\n    }\n\n    public String getLogEndTime() {\n        return LogEndTime;\n    }\n\n    public void setLogEndTime(String logEndTime) {\n        LogEndTime = logEndTime;\n    }\n\n    public String getDownloadLink() {\n        return DownloadLink;\n    }\n\n    public void setDownloadLink(String downloadLink) {\n        DownloadLink = downloadLink;\n    }\n\n    public String getHostInstanceID() {\n        return HostInstanceID;\n    }\n\n    public void setHostInstanceID(String hostInstanceID) {\n        HostInstanceID = hostInstanceID;\n    }\n\n    public String getLinkExpiredTime() {\n        return LinkExpiredTime;\n    }\n\n    public void setLinkExpiredTime(String linkExpiredTime) {\n        LinkExpiredTime = linkExpiredTime;\n    }\n\n    public String getFileName() {\n        return fileName;\n    }\n\n    public void setFileName(String fileName) {\n        this.fileName = fileName;\n    }\n\n    @Override\n    public String toString() {\n        return \"BinlogFile [FileSize=\" + FileSize + \", LogBeginTime=\" + LogBeginTime + \", LogEndTime=\" + LogEndTime\n               + \", DownloadLink=\" + DownloadLink + \", HostInstanceID=\" + HostInstanceID + \", LinkExpiredTime=\"\n               + LinkExpiredTime + \", fileName=\" + fileName + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/rds/data/DescribeBinlogFileResult.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.rds.data;\n\n/**\n * @author chengjin.lyf on 2018/8/7 下午2:26\n * @since 1.0.25\n */\npublic class DescribeBinlogFileResult {\n\n    private RdsItem Items;\n    private long    PageNumber;\n    private long    TotalRecordCount;\n    private long    TotalFileSize;\n    private String  RequestId;\n    private long    PageRecordCount;\n\n    public RdsItem getItems() {\n        return Items;\n    }\n\n    public void setItems(RdsItem items) {\n        Items = items;\n    }\n\n    public long getPageNumber() {\n        return PageNumber;\n    }\n\n    public void setPageNumber(long pageNumber) {\n        PageNumber = pageNumber;\n    }\n\n    public long getTotalRecordCount() {\n        return TotalRecordCount;\n    }\n\n    public void setTotalRecordCount(long totalRecordCount) {\n        TotalRecordCount = totalRecordCount;\n    }\n\n    public long getTotalFileSize() {\n        return TotalFileSize;\n    }\n\n    public void setTotalFileSize(long totalFileSize) {\n        TotalFileSize = totalFileSize;\n    }\n\n    public String getRequestId() {\n        return RequestId;\n    }\n\n    public void setRequestId(String requestId) {\n        RequestId = requestId;\n    }\n\n    public long getPageRecordCount() {\n        return PageRecordCount;\n    }\n\n    public void setPageRecordCount(long pageRecordCount) {\n        PageRecordCount = pageRecordCount;\n    }\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/rds/data/RdsBackupPolicy.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.rds.data;\n\n/**\n * @author chengjin.lyf on 2018/8/7 下午2:26\n * @since 1.0.25\n */\npublic class RdsBackupPolicy {\n\n    /**\n     * 数据备份保留天数（7到730天）。\n     */\n    private String  BackupRetentionPeriod;\n    /**\n     * 数据备份时间，格式：HH:mmZ- HH:mm Z。\n     */\n    private String  PreferredBackupTime;\n    /**\n     * 数据备份周期。Monday：周一；Tuesday：周二；Wednesday：周三；Thursday：周四；Friday：周五；Saturday：\n     * 周六；Sunday：周日。\n     */\n    private String  PreferredBackupPeriod;\n    /**\n     * 日志备份状态。Enable：开启；Disabled：关闭。\n     */\n    private boolean BackupLog;\n    /**\n     * 日志备份保留天数（7到730天）。\n     */\n    private int     LogBackupRetentionPeriod;\n\n    public String getBackupRetentionPeriod() {\n        return BackupRetentionPeriod;\n    }\n\n    public void setBackupRetentionPeriod(String backupRetentionPeriod) {\n        BackupRetentionPeriod = backupRetentionPeriod;\n    }\n\n    public String getPreferredBackupTime() {\n        return PreferredBackupTime;\n    }\n\n    public void setPreferredBackupTime(String preferredBackupTime) {\n        PreferredBackupTime = preferredBackupTime;\n    }\n\n    public String getPreferredBackupPeriod() {\n        return PreferredBackupPeriod;\n    }\n\n    public void setPreferredBackupPeriod(String preferredBackupPeriod) {\n        PreferredBackupPeriod = preferredBackupPeriod;\n    }\n\n    public boolean isBackupLog() {\n        return BackupLog;\n    }\n\n    public void setBackupLog(boolean backupLog) {\n        BackupLog = backupLog;\n    }\n\n    public int getLogBackupRetentionPeriod() {\n        return LogBackupRetentionPeriod;\n    }\n\n    public void setLogBackupRetentionPeriod(int logBackupRetentionPeriod) {\n        LogBackupRetentionPeriod = logBackupRetentionPeriod;\n    }\n\n    @Override\n    public String toString() {\n        return \"RdsBackupPolicy [BackupRetentionPeriod=\" + BackupRetentionPeriod + \", PreferredBackupTime=\"\n               + PreferredBackupTime + \", PreferredBackupPeriod=\" + PreferredBackupPeriod + \", BackupLog=\" + BackupLog\n               + \", LogBackupRetentionPeriod=\" + LogBackupRetentionPeriod + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/rds/data/RdsItem.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.rds.data;\n\nimport java.util.List;\n\n/**\n * @author chengjin.lyf on 2018/8/7 下午2:26\n * @since 1.0.25\n */\npublic class RdsItem {\n\n    private List<BinlogFile> BinLogFile;\n\n    public List<BinlogFile> getBinLogFile() {\n        return BinLogFile;\n    }\n\n    public void setBinLogFile(List<BinlogFile> binLogFile) {\n        BinLogFile = binLogFile;\n    }\n\n    @Override\n    public String toString() {\n        return \"RdsItem [BinLogFile=\" + BinLogFile + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/rds/request/AbstractRequest.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.rds.request;\n\nimport io.netty.handler.codec.http.HttpResponseStatus;\n\nimport java.io.IOException;\nimport java.io.UnsupportedEncodingException;\nimport java.net.URLEncoder;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.Map;\nimport java.util.TimeZone;\nimport java.util.TreeMap;\nimport java.util.UUID;\nimport java.util.concurrent.TimeUnit;\n\nimport javax.crypto.Mac;\nimport javax.crypto.SecretKey;\nimport javax.crypto.spec.SecretKeySpec;\nimport javax.net.ssl.SSLContext;\n\nimport org.apache.commons.codec.binary.Base64;\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.HttpStatus;\nimport org.apache.http.client.config.RequestConfig;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.config.Registry;\nimport org.apache.http.config.RegistryBuilder;\nimport org.apache.http.conn.HttpClientConnectionManager;\nimport org.apache.http.conn.socket.PlainConnectionSocketFactory;\nimport org.apache.http.conn.ssl.SSLConnectionSocketFactory;\nimport org.apache.http.conn.ssl.TrustStrategy;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.HttpClientBuilder;\nimport org.apache.http.impl.conn.PoolingHttpClientConnectionManager;\nimport org.apache.http.ssl.SSLContexts;\nimport org.apache.http.util.EntityUtils;\n\n/**\n * @author chengjin.lyf on 2018/8/7 下午2:26\n * @since 1.0.25\n */\npublic abstract class AbstractRequest<T> {\n\n    /**\n     * 要求的编码格式\n     */\n    private static final String ENCODING = \"UTF-8\";\n    /**\n     * 要求的sign签名算法\n     */\n    private static final String MAC_NAME = \"HmacSHA1\";\n\n    private String              accessKeyId;\n\n    private String              accessKeySecret;\n\n    /**\n     * api 版本\n     */\n    private String              version;\n\n    private String              endPoint = \"rds.aliyuncs.com\";\n\n    private String              protocol = \"http\";\n\n    public void setProtocol(String protocol) {\n        this.protocol = protocol;\n    }\n\n    private int                 timeout = (int) TimeUnit.MINUTES.toMillis(1);\n\n    private Map<String, String> treeMap = new TreeMap();\n\n    public void putQueryString(String name, String value) {\n        if (StringUtils.isBlank(name) || StringUtils.isBlank(value)) {\n            return;\n        }\n        treeMap.put(name, value);\n    }\n\n    public void setVersion(String version) {\n        this.version = version;\n    }\n\n    public void setEndPoint(String endPoint) {\n        this.endPoint = endPoint;\n    }\n\n    public void setAccessKeyId(String accessKeyId) {\n        this.accessKeyId = accessKeyId;\n    }\n\n    public void setAccessKeySecret(String accessKeySecret) {\n        this.accessKeySecret = accessKeySecret;\n    }\n\n    /**\n     * 使用 HMAC-SHA1 签名方法对对encryptText进行签名\n     *\n     * @param encryptText 被签名的字符串\n     * @param encryptKey 密钥\n     * @return\n     * @throws Exception\n     */\n    private byte[] HmacSHA1Encrypt(String encryptText, String encryptKey) throws Exception {\n        byte[] data = encryptKey.getBytes(ENCODING);\n        // 根据给定的字节数组构造一个密钥,第二参数指定一个密钥算法的名称\n        SecretKey secretKey = new SecretKeySpec(data, MAC_NAME);\n        // 生成一个指定 Mac 算法 的 Mac 对象\n        Mac mac = Mac.getInstance(MAC_NAME);\n        // 用给定密钥初始化 Mac 对象\n        mac.init(secretKey);\n\n        byte[] text = encryptText.getBytes(ENCODING);\n        // 完成 Mac 操作\n        return mac.doFinal(text);\n    }\n\n    private String base64(byte input[]) throws UnsupportedEncodingException {\n        return new String(Base64.encodeBase64(input), ENCODING);\n    }\n\n    private String concatQueryString(Map<String, String> parameters) throws UnsupportedEncodingException {\n        if (null == parameters) {\n            return null;\n        }\n        StringBuilder urlBuilder = new StringBuilder(\"\");\n        for (Map.Entry<String, String> entry : parameters.entrySet()) {\n            String key = entry.getKey();\n            String val = entry.getValue();\n            urlBuilder.append(encode(key));\n            if (val != null) {\n                urlBuilder.append(\"=\").append(encode(val));\n            }\n            urlBuilder.append(\"&\");\n        }\n        int strIndex = urlBuilder.length();\n        if (parameters.size() > 0) {\n            urlBuilder.deleteCharAt(strIndex - 1);\n        }\n        return urlBuilder.toString();\n    }\n\n    private String encode(String value) throws UnsupportedEncodingException {\n        return URLEncoder.encode(value, \"UTF-8\");\n    }\n\n    private String makeSignature(TreeMap<String, String> paramMap) throws Exception {\n        String cqs = concatQueryString(paramMap);\n        cqs = encode(cqs);\n        cqs = cqs.replaceAll(\"\\\\+\", \"%20\");\n        cqs = cqs.replaceAll(\"\\\\*\", \"%2A\");\n        cqs = cqs.replaceAll(\"%7E\", \"~\");\n        StringBuilder stringBuilder = new StringBuilder();\n        stringBuilder.append(\"GET\").append(\"&\").append(encode(\"/\")).append(\"&\").append(cqs);\n        return base64(HmacSHA1Encrypt(stringBuilder.toString(), accessKeySecret + \"&\"));\n    }\n\n    public final String formatUTCTZ(Date date) {\n        SimpleDateFormat sdf = new SimpleDateFormat(\"yyyy-MM-dd'T'HH:mm:ss'Z'\");\n        sdf.setTimeZone(TimeZone.getTimeZone(\"UTC\"));\n        return sdf.format(date);\n    }\n\n    private void fillCommonParam(Map<String, String> p) {\n        p.put(\"Format\", \"JSON\");\n        p.put(\"Version\", version);\n        p.put(\"AccessKeyId\", accessKeyId);\n        p.put(\"SignatureMethod\", \"HMAC-SHA1\"); // 此处不能用变量 MAC_NAME\n        p.put(\"Timestamp\", formatUTCTZ(new Date()));\n        p.put(\"SignatureVersion\", \"1.0\");\n        p.put(\"SignatureNonce\", UUID.randomUUID().toString());\n    }\n\n    private String makeRequestString(Map<String, String> param) throws Exception {\n        fillCommonParam(param);\n        String sign = makeSignature(new TreeMap<>(param));\n        StringBuilder builder = new StringBuilder();\n        for (Map.Entry<String, String> entry : param.entrySet()) {\n            builder.append(encode(entry.getKey())).append(\"=\").append(encode(entry.getValue())).append(\"&\");\n        }\n        builder.append(\"Signature\").append(\"=\").append(sign);\n        return builder.toString();\n    }\n\n    /**\n     * 执行http请求\n     *\n     * @param getMethod\n     * @return\n     * @throws IOException\n     */\n    @SuppressWarnings(\"deprecation\")\n    private final HttpResponse executeHttpRequest(HttpGet getMethod, String host) throws Exception {\n        SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, (TrustStrategy) (arg0, arg1) -> true).build();\n        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext,\n            new String[] { \"TLSv1.2\" },\n            null,\n            SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);\n        Registry registry = RegistryBuilder.create()\n            .register(\"http\", PlainConnectionSocketFactory.INSTANCE)\n            .register(\"https\", sslsf)\n            .build();\n        HttpClientConnectionManager httpClientConnectionManager = new PoolingHttpClientConnectionManager(registry);\n        CloseableHttpClient httpClient = HttpClientBuilder.create()\n            .setMaxConnPerRoute(50)\n            .setMaxConnTotal(100)\n            .setConnectionManager(httpClientConnectionManager)\n            .build();\n        RequestConfig requestConfig = RequestConfig.custom()\n            .setConnectTimeout(timeout)\n            .setConnectionRequestTimeout(timeout)\n            .setSocketTimeout(timeout)\n            .build();\n        getMethod.setConfig(requestConfig);\n        HttpResponse response = httpClient.execute(getMethod);\n        int statusCode = response.getStatusLine().getStatusCode();\n        if (statusCode != HttpResponseStatus.OK.code() && statusCode != HttpResponseStatus.PARTIAL_CONTENT.code()) {\n            String result = EntityUtils.toString(response.getEntity());\n            throw new RuntimeException(\"return error !\" + response.getStatusLine().getReasonPhrase() + \", \" + result);\n        }\n        return response;\n    }\n\n    protected abstract T processResult(HttpResponse response) throws Exception;\n\n    protected void processBefore() {\n\n    }\n\n    public final T doAction() throws Exception {\n        processBefore();\n        String requestStr = makeRequestString(treeMap);\n        HttpGet httpGet = new HttpGet(protocol + \"://\" + endPoint + \"?\" + requestStr);\n        HttpResponse response = executeHttpRequest(httpGet, endPoint);\n        if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {\n            String result = EntityUtils.toString(response.getEntity());\n            throw new RuntimeException(\"http request failed! \" + result);\n        }\n        return processResult(response);\n    }\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/rds/request/DescribeBackupPolicyRequest.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.rds.request;\n\nimport org.apache.http.HttpResponse;\nimport org.apache.http.util.EntityUtils;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.JSONObject;\nimport com.alibaba.otter.canal.parse.inbound.mysql.rds.data.RdsBackupPolicy;\n\n/**\n * rds 备份策略查询\n * \n * @author chengjin.lyf on 2018/8/7 下午3:41\n * @since 1.0.25\n */\npublic class DescribeBackupPolicyRequest extends AbstractRequest<RdsBackupPolicy> {\n\n    public DescribeBackupPolicyRequest(){\n        setVersion(\"2014-08-15\");\n        putQueryString(\"Action\", \"DescribeBackupPolicy\");\n\n    }\n\n    public void setRdsInstanceId(String rdsInstanceId) {\n        putQueryString(\"DBInstanceId\", rdsInstanceId);\n    }\n\n    @Override\n    protected RdsBackupPolicy processResult(HttpResponse response) throws Exception {\n        String result = EntityUtils.toString(response.getEntity());\n        JSONObject jsonObj = JSON.parseObject(result);\n        RdsBackupPolicy policy = new RdsBackupPolicy();\n        policy.setBackupRetentionPeriod(jsonObj.getString(\"BackupRetentionPeriod\"));\n        policy.setBackupLog(jsonObj.getString(\"BackupLog\").equalsIgnoreCase(\"Enable\"));\n        policy.setLogBackupRetentionPeriod(jsonObj.getIntValue(\"LogBackupRetentionPeriod\"));\n        policy.setPreferredBackupPeriod(jsonObj.getString(\"PreferredBackupPeriod\"));\n        policy.setPreferredBackupTime(jsonObj.getString(\"PreferredBackupTime\"));\n        return policy;\n    }\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/rds/request/DescribeBinlogFilesRequest.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.rds.request;\n\nimport java.util.Date;\n\nimport com.alibaba.fastjson2.JSON;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.util.EntityUtils;\n\nimport com.alibaba.fastjson2.TypeReference;\nimport com.alibaba.otter.canal.parse.inbound.mysql.rds.data.DescribeBinlogFileResult;\n\n/**\n * @author chengjin.lyf on 2018/8/7 下午3:41\n * @since 1.0.25\n */\npublic class DescribeBinlogFilesRequest extends AbstractRequest<DescribeBinlogFileResult> {\n\n    public DescribeBinlogFilesRequest(){\n        setVersion(\"2014-08-15\");\n        putQueryString(\"Action\", \"DescribeBinlogFiles\");\n    }\n\n    public void setRdsInstanceId(String rdsInstanceId) {\n        putQueryString(\"DBInstanceId\", rdsInstanceId);\n    }\n\n    public void setPageSize(int pageSize) {\n        putQueryString(\"PageSize\", String.valueOf(pageSize));\n    }\n\n    public void setPageNumber(int pageNumber) {\n        putQueryString(\"PageNumber\", String.valueOf(pageNumber));\n    }\n\n    public void setStartDate(Date startDate) {\n        putQueryString(\"StartTime\", formatUTCTZ(startDate));\n    }\n\n    public void setEndDate(Date endDate) {\n        putQueryString(\"EndTime\", formatUTCTZ(endDate));\n    }\n\n    public void setResourceOwnerId(Long resourceOwnerId) {\n        putQueryString(\"ResourceOwnerId\", String.valueOf(resourceOwnerId));\n    }\n\n    @Override\n    protected DescribeBinlogFileResult processResult(HttpResponse response) throws Exception {\n        String result = EntityUtils.toString(response.getEntity());\n        DescribeBinlogFileResult describeBinlogFileResult = JSON.parseObject(result,\n            new TypeReference<DescribeBinlogFileResult>() {\n            });\n        return describeBinlogFileResult;\n    }\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/tsdb/DatabaseTableMeta.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.tsdb;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.locks.ReadWriteLock;\nimport java.util.concurrent.locks.ReentrantReadWriteLock;\nimport java.util.regex.Pattern;\n\nimport org.apache.commons.lang.ObjectUtils;\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.slf4j.MDC;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.JSONObject;\nimport com.alibaba.fastjson2.JSONWriter;\nimport com.alibaba.otter.canal.filter.CanalEventFilter;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.server.FieldPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.server.ResultSetPacket;\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\nimport com.alibaba.otter.canal.parse.inbound.TableMeta;\nimport com.alibaba.otter.canal.parse.inbound.TableMeta.FieldMeta;\nimport com.alibaba.otter.canal.parse.inbound.mysql.MysqlConnection;\nimport com.alibaba.otter.canal.parse.inbound.mysql.dbsync.TableMetaCache;\nimport com.alibaba.otter.canal.parse.inbound.mysql.ddl.DdlResult;\nimport com.alibaba.otter.canal.parse.inbound.mysql.ddl.DruidDdlParser;\nimport com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao.MetaHistoryDAO;\nimport com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao.MetaHistoryDO;\nimport com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao.MetaSnapshotDAO;\nimport com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao.MetaSnapshotDO;\nimport com.alibaba.otter.canal.protocol.position.EntryPosition;\nimport com.alibaba.polardbx.druid.sql.repository.Schema;\n\n/**\n * 基于db远程管理 see internal class: CanalTableMeta , ConsoleTableMetaTSDB\n *\n * @author agapple 2017年7月27日 下午10:47:55\n * @since 3.2.5\n */\npublic class DatabaseTableMeta implements TableMetaTSDB {\n\n    public static final EntryPosition       INIT_POSITION       = new EntryPosition(\"0\", 0L, -2L, -1L);\n    private static Logger                   logger              = LoggerFactory.getLogger(DatabaseTableMeta.class);\n    private static Pattern                  pattern             = Pattern.compile(\"Duplicate entry '.*' for key '*'\");\n    private static Pattern                  h2Pattern           = Pattern\n        .compile(\"Unique index or primary key violation\");\n    private static ScheduledExecutorService scheduler           = Executors.newSingleThreadScheduledExecutor(r -> {\n                                                                    Thread thread = new Thread(r,\n                                                                        \"[scheduler-table-meta-snapshot]\");\n                                                                    thread.setDaemon(true);\n                                                                    return thread;\n                                                                });\n    private ReadWriteLock                   lock                = new ReentrantReadWriteLock();\n    private AtomicBoolean                   initialized         = new AtomicBoolean(false);\n    private String                          destination;\n    private MemoryTableMeta                 memoryTableMeta;\n    private volatile MysqlConnection        connection;                                                               // 查询meta信息的链接\n    private CanalEventFilter                filter;\n    private CanalEventFilter                blackFilter;\n    private Map<String, List<String>>       fieldFilterMap      = new HashMap<>();\n    private Map<String, List<String>>       fieldBlackFilterMap = new HashMap<>();\n    private EntryPosition                   lastPosition;\n    private boolean                         hasNewDdl;\n    private MetaHistoryDAO                  metaHistoryDAO;\n    private MetaSnapshotDAO                 metaSnapshotDAO;\n    private int                             snapshotInterval    = 24;\n    private int                             snapshotExpire      = 360;\n    private ScheduledFuture<?>              scheduleSnapshotFuture;\n\n    public DatabaseTableMeta(){\n\n    }\n\n    public static boolean compareTableMeta(TableMeta source, TableMeta target) {\n        if (!StringUtils.equalsIgnoreCase(source.getSchema(), target.getSchema())) {\n            return false;\n        }\n\n        if (!StringUtils.equalsIgnoreCase(source.getTable(), target.getTable())) {\n            return false;\n        }\n\n        List<FieldMeta> sourceFields = source.getFields();\n        List<FieldMeta> targetFields = target.getFields();\n        if (sourceFields.size() != targetFields.size()) {\n            return false;\n        }\n\n        /**\n         * MySQL DDL的一些默认行为:\n         *\n         * <pre>\n         * 1. Timestamp类型的列在第一次添加时，未指定默认值会默认为CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP\n         * 2. Timestamp类型的列在第二次时，必须指定默认值\n         * 3. BLOB和TEXT类型不存在NULL、NOT NULL属性\n         * 4. 部分数据类型是synonyms，实际show create table时会转成对应类型\n         * 5. 非BLOB和TEXT类型在默认未指定NULL、NOT NULL时，默认default null\n         * 6. 在列变更时，不仅变更列名数据类型，同时各个约束中列名也会变更，同时如果约束中包含key length，则变更后的数据类型不应违背key length的约束（有长度的应大于key length；BLOB、TEXT应有key length；可以在存在key length情况下变更为无key length的数据类型，约束中key length忽略；等等）\n         * 7. 字符集每列（char类、eumn、set）默认保存，指定使用指定的，未指定使用表默认的，不受修改表默认字符集而改变，同表默认时，字符集显示省略\n         * 8. 新建表默认innodb引擎，latin1字符集\n         * 9. BLOB、TEXT会根据给定长度自动转换为对应的TINY、MEDIUM，LONG类型，长度和字符集也有关\n         * 10. unique约束在没有指定索引名是非幂等的，会自动以约束索引第一个列名称命名，同时以_2,_3这种形式添加后缀\n         * </pre>\n         */\n\n        for (int i = 0; i < sourceFields.size(); i++) {\n            FieldMeta sourceField = sourceFields.get(i);\n            FieldMeta targetField = targetFields.get(i);\n            if (!StringUtils.equalsIgnoreCase(sourceField.getColumnName(), targetField.getColumnName())) {\n                return false;\n            }\n\n            // if (!StringUtils.equalsIgnoreCase(sourceField.getColumnType(),\n            // targetField.getColumnType())) {\n            // return false;\n            // }\n\n            // https://github.com/alibaba/canal/issues/1100\n            // 支持一下 int vs int(10)\n            if ((sourceField.isUnsigned() && !targetField.isUnsigned())\n                || (!sourceField.isUnsigned() && targetField.isUnsigned())) {\n                return false;\n            }\n\n            String sourceColumnType = StringUtils.removeEndIgnoreCase(sourceField.getColumnType(), \"zerofill\").trim();\n            String targetColumnType = StringUtils.removeEndIgnoreCase(targetField.getColumnType(), \"zerofill\").trim();\n\n            String sign = sourceField.isUnsigned() ? \"unsigned\" : \"signed\";\n            sourceColumnType = StringUtils.removeEndIgnoreCase(sourceColumnType, sign).trim();\n            targetColumnType = StringUtils.removeEndIgnoreCase(targetColumnType, sign).trim();\n\n            boolean columnTypeCompare = false;\n            columnTypeCompare |= StringUtils.containsIgnoreCase(sourceColumnType, targetColumnType);\n            columnTypeCompare |= StringUtils.containsIgnoreCase(targetColumnType, sourceColumnType);\n            if (!columnTypeCompare) {\n                // 去掉精度参数再对比一次\n                sourceColumnType = synonymsType(StringUtils.substringBefore(sourceColumnType, \"(\")).trim();\n                targetColumnType = synonymsType(StringUtils.substringBefore(targetColumnType, \"(\")).trim();\n                columnTypeCompare |= StringUtils.containsIgnoreCase(sourceColumnType, targetColumnType);\n                columnTypeCompare |= StringUtils.containsIgnoreCase(targetColumnType, sourceColumnType);\n                if (!columnTypeCompare) {\n                    return false;\n                }\n            }\n\n            // if (!StringUtils.equalsIgnoreCase(sourceField.getDefaultValue(),\n            // targetField.getDefaultValue())) {\n            // return false;\n            // }\n\n            // BLOB, TEXT, GEOMETRY or JSON默认都是nullable，可以忽略比较，但比较了也是对齐\n            if (StringUtils.containsIgnoreCase(sourceColumnType, \"timestamp\")\n                || StringUtils.containsIgnoreCase(targetColumnType, \"timestamp\")) {\n                // timestamp可能会加default current_timestamp默认值,忽略对比nullable\n            } else {\n                if (sourceField.isNullable() != targetField.isNullable()) {\n                    return false;\n                }\n            }\n\n            // mysql会有一种处理,针对show create只有uk没有pk时，会在desc默认将uk当做pk\n            boolean isSourcePkOrUk = sourceField.isKey() || sourceField.isUnique();\n            boolean isTargetPkOrUk = targetField.isKey() || targetField.isUnique();\n            if (isSourcePkOrUk != isTargetPkOrUk) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * <pre>\n     * synonyms处理\n     * 1. BOOL/BOOLEAN => TINYINT\n     * 2. DEC/NUMERIC/FIXED => DECIMAL\n     * 3. INTEGER => INT\n     * </pre>\n     *\n     * @param originType\n     * @return\n     */\n    private static String synonymsType(String originType) {\n        if (StringUtils.equalsIgnoreCase(originType, \"bool\") || StringUtils.equalsIgnoreCase(originType, \"boolean\")) {\n            return \"tinyint\";\n        } else\n            if (StringUtils.equalsIgnoreCase(originType, \"dec\") || StringUtils.equalsIgnoreCase(originType, \"numeric\")\n                || StringUtils.equalsIgnoreCase(originType, \"fixed\")) {\n                    return \"decimal\";\n                } else if (StringUtils.equalsIgnoreCase(originType, \"integer\")) {\n                    return \"int\";\n                } else if (StringUtils.equalsIgnoreCase(originType, \"real\")\n                           || StringUtils.equalsIgnoreCase(originType, \"double precision\")) {\n                               return \"double\";\n                           }\n\n        // BLOB、TEXT会根据给定长度自动转换为对应的TINY、MEDIUM，LONG类型，长度和字符集也有关，统一按照blob对比\n        if (StringUtils.equalsIgnoreCase(originType, \"tinyblob\")\n            || StringUtils.equalsIgnoreCase(originType, \"mediumblob\")\n            || StringUtils.equalsIgnoreCase(originType, \"longblob\")) {\n            return \"blob\";\n        } else if (StringUtils.equalsIgnoreCase(originType, \"tinytext\")\n                   || StringUtils.equalsIgnoreCase(originType, \"mediumtext\")\n                   || StringUtils.equalsIgnoreCase(originType, \"longtext\")) {\n                       return \"text\";\n                   }\n\n        return originType;\n    }\n\n    @Override\n    public boolean init(final String destination) {\n        if (initialized.compareAndSet(false, true)) {\n            this.destination = destination;\n            this.memoryTableMeta = new MemoryTableMeta();\n\n            // 24小时生成一份snapshot\n            if (snapshotInterval > 0) {\n                scheduleSnapshotFuture = scheduler.scheduleWithFixedDelay(() -> {\n                    boolean applyResult = false;\n                    try {\n                        MDC.put(\"destination\", destination);\n                        applyResult = applySnapshotToDB(lastPosition, false);\n                    } catch (Throwable e) {\n                        logger.error(\"scheudle applySnapshotToDB faield\", e);\n                    }\n\n                    try {\n                        MDC.put(\"destination\", destination);\n                        if (applyResult) {\n                            snapshotExpire((int) TimeUnit.HOURS.toSeconds(snapshotExpire));\n                        }\n                    } catch (Throwable e) {\n                        logger.error(\"scheudle snapshotExpire faield\", e);\n                    }\n                }, snapshotInterval, snapshotInterval, TimeUnit.HOURS);\n            }\n        }\n        return true;\n    }\n\n    @Override\n    public void destory() {\n        if (memoryTableMeta != null) {\n            memoryTableMeta.destory();\n        }\n\n        if (connection != null) {\n            try {\n                connection.disconnect();\n            } catch (IOException e) {\n                logger.error(\"ERROR # disconnect meta connection for address:{}\",\n                    connection.getConnector().getAddress(),\n                    e);\n            }\n        }\n\n        if (scheduleSnapshotFuture != null) {\n            scheduleSnapshotFuture.cancel(false);\n        }\n    }\n\n    @Override\n    public TableMeta find(String schema, String table) {\n        lock.readLock().lock();\n        try {\n            return memoryTableMeta.find(schema, table);\n        } finally {\n            lock.readLock().unlock();\n        }\n    }\n\n    @Override\n    public boolean apply(EntryPosition position, String schema, String ddl, String extra) {\n        // 首先记录到内存结构\n        lock.writeLock().lock();\n        try {\n            if (memoryTableMeta.apply(position, schema, ddl, extra)) {\n                this.lastPosition = position;\n                this.hasNewDdl = true;\n                // 同步每次变更给远程做历史记录\n                return applyHistoryToDB(position, schema, ddl, extra);\n            } else {\n                throw new RuntimeException(\"apply to memory is failed\");\n            }\n        } finally {\n            lock.writeLock().unlock();\n        }\n    }\n\n    @Override\n    public boolean rollback(EntryPosition position) {\n        // 每次rollback需要重新构建一次memory data\n        // FIXME The global MemoryTableMeta may cause OOM when it store too many tables\n        this.memoryTableMeta = new MemoryTableMeta();\n        boolean flag = false;\n        EntryPosition snapshotPosition = buildMemFromSnapshot(position);\n        if (snapshotPosition != null) {\n            applyHistoryOnMemory(snapshotPosition, position);\n            flag = true;\n        }\n\n        if (!flag) {\n            // 如果没有任何数据，则为初始化状态，全量dump一份关注的表\n            if (dumpTableMeta(connection, filter)) {\n                // 记录一下snapshot结果,方便快速恢复\n                flag = applySnapshotToDB(INIT_POSITION, true);\n            }\n        }\n\n        return flag;\n    }\n\n    @Override\n    public Map<String, String> snapshot() {\n        return memoryTableMeta.snapshot();\n    }\n\n    /**\n     * 初始化的时候dump一下表结构\n     */\n    private boolean dumpTableMeta(MysqlConnection connection, final CanalEventFilter filter) {\n        try {\n            ResultSetPacket packet = connection.query(\"show databases\");\n            int columnSize = packet.getFieldDescriptors().size();\n            int columnIndex = 0;\n            for (; columnIndex < columnSize; columnIndex++) {\n                FieldPacket value = packet.getFieldDescriptors().get(columnIndex);\n                if (StringUtils.equalsIgnoreCase(value.getName(), \"Database\")) {\n                    break;\n                }\n            }\n\n            List<String> schemas = new ArrayList<>();\n            for (int line = 0; line < packet.getFieldValues().size() / columnSize; line++) {\n                String schema = packet.getFieldValues().get(line * columnSize + columnIndex);\n                schemas.add(schema);\n            }\n\n            for (String schema : schemas) {\n                // 如果schema命中黑名单，直接跳过\n                // 解决部分数据库可以看到database，但实际表级别无权限的情况\n                if (blackFilter != null && blackFilter.filter(schema + \".%\")) {\n                    continue;\n                }\n                // filter views\n                packet = connection.query(\"show full tables from `\" + schema + \"` where Table_type = 'BASE TABLE'\");\n                columnSize = packet.getFieldDescriptors().size();\n                int tableNameColumnIndex = 0; // default index is 0\n                List<String> tables = new ArrayList<>();\n                for (int line = 0; line < packet.getFieldValues().size() / columnSize; line++) {\n                    String table = packet.getFieldValues().get(line * columnSize + tableNameColumnIndex);\n                    String fullName = schema + \".\" + table;\n                    if (blackFilter == null || !blackFilter.filter(fullName)) {\n                        if (filter == null || filter.filter(fullName)) {\n                            tables.add(table);\n                        }\n                    }\n                }\n\n                if (tables.isEmpty()) {\n                    continue;\n                }\n\n                StringBuilder sql = new StringBuilder();\n                for (String table : tables) {\n                    sql.append(\"show create table `\" + schema + \"`.`\" + StringUtils.replace(table, \"`\", \"``\") + \"`;\");\n                }\n\n                List<ResultSetPacket> packets = connection.queryMulti(sql.toString());\n                for (ResultSetPacket onePacket : packets) {\n                    if (onePacket.getFieldValues().size() > 1) {\n                        String oneTableCreateSql = onePacket.getFieldValues().get(1);\n                        memoryTableMeta.apply(INIT_POSITION, schema, oneTableCreateSql, null);\n                    }\n                }\n            }\n\n            return true;\n        } catch (IOException e) {\n            throw new CanalParseException(e);\n        }\n    }\n\n    private boolean applyHistoryToDB(EntryPosition position, String schema, String ddl, String extra) {\n        // Map<String, String> content = new HashMap<>();\n        // content.put(\"destination\", destination);\n        // content.put(\"binlogFile\", position.getJournalName());\n        // content.put(\"binlogOffest\", String.valueOf(position.getPosition()));\n        // content.put(\"binlogMasterId\", String.valueOf(position.getServerId()));\n        // content.put(\"binlogTimestamp\", String.valueOf(position.getTimestamp()));\n        // content.put(\"useSchema\", schema);\n        //\n        // if (content.isEmpty()) {\n        // throw new RuntimeException(\"apply failed caused by content is empty in\n        // applyHistoryToDB\");\n        // }\n        // // 待补充\n        // List<DdlResult> ddlResults = DruidDdlParser.parse(ddl, schema);\n        // if (ddlResults.size() > 0) {\n        // DdlResult ddlResult = ddlResults.get(0);\n        // content.put(\"sqlSchema\", ddlResult.getSchemaName());\n        // content.put(\"sqlTable\", ddlResult.getTableName());\n        // content.put(\"sqlType\", ddlResult.getType().name());\n        // content.put(\"sqlText\", ddl);\n        // content.put(\"extra\", extra);\n        // }\n        // BeanUtils.populate(metaDO, content);\n\n        MetaHistoryDO metaDO = new MetaHistoryDO();\n        metaDO.setDestination(destination);\n        metaDO.setBinlogFile(position.getJournalName());\n        metaDO.setBinlogOffest(position.getPosition());\n        metaDO.setBinlogMasterId(String.valueOf(position.getServerId()));\n        metaDO.setBinlogTimestamp(position.getTimestamp());\n        metaDO.setUseSchema(schema);\n        List<DdlResult> ddlResults = DruidDdlParser.parse(ddl, schema);\n        if (ddlResults.size() > 0) {\n            DdlResult ddlResult = ddlResults.get(0);\n            metaDO.setSqlSchema(ddlResult.getSchemaName());\n            metaDO.setSqlTable(ddlResult.getTableName());\n            metaDO.setSqlType(ddlResult.getType().name());\n            metaDO.setSqlText(ddl);\n            metaDO.setExtra(extra);\n        }\n        try {\n            // 会建立唯一约束,解决:\n            // 1. 重复的binlog file+offest\n            // 2. 重复的masterId+timestamp\n            metaHistoryDAO.insert(metaDO);\n        } catch (Throwable e) {\n            if (isUkDuplicateException(e)) {\n                // 忽略掉重复的位点\n                logger.warn(\"dup apply for sql : \" + ddl);\n            } else {\n                throw new CanalParseException(\"apply history to db failed caused by : \" + e.getMessage(), e);\n            }\n\n        }\n        return true;\n    }\n\n    /**\n     * 发布数据到console上\n     */\n    private boolean applySnapshotToDB(EntryPosition position, boolean init) {\n        // 获取一份快照\n        Map<String, String> schemaDdls = null;\n        lock.readLock().lock();\n        try {\n            if (!init && !hasNewDdl) {\n                // 如果是持续构建,则识别一下是否有DDL变更过,如果没有就忽略了\n                return false;\n            }\n            this.hasNewDdl = false;\n            schemaDdls = memoryTableMeta.snapshot();\n        } finally {\n            lock.readLock().unlock();\n        }\n\n        MemoryTableMeta tmpMemoryTableMeta = new MemoryTableMeta();\n        for (Map.Entry<String, String> entry : schemaDdls.entrySet()) {\n            tmpMemoryTableMeta.apply(position, entry.getKey(), entry.getValue(), null);\n        }\n\n        // 基于临时内存对象进行对比\n        boolean compareAll = true;\n        for (Schema schema : tmpMemoryTableMeta.getRepository().getSchemas()) {\n            for (String table : schema.showTables()) {\n                String fullName = schema.getName() + \".\" + table;\n                if (blackFilter == null || !blackFilter.filter(fullName)) {\n                    if (filter == null || filter.filter(fullName)) {\n                        // issue : https://github.com/alibaba/canal/issues/1168\n                        // 在生成snapshot时重新过滤一遍\n                        if (!compareTableMetaDbAndMemory(connection, tmpMemoryTableMeta, schema.getName(), table)) {\n                            compareAll = false;\n                        }\n                    }\n                }\n            }\n        }\n\n        if (compareAll) {\n            // Map<String, String> content = new HashMap<>();\n            // content.put(\"destination\", destination);\n            // content.put(\"binlogFile\", position.getJournalName());\n            // content.put(\"binlogOffest\", String.valueOf(position.getPosition()));\n            // content.put(\"binlogMasterId\", String.valueOf(position.getServerId()));\n            // content.put(\"binlogTimestamp\", String.valueOf(position.getTimestamp()));\n            // content.put(\"data\", JSON.toJSONString(schemaDdls));\n            // if (content.isEmpty()) {\n            // throw new RuntimeException(\"apply failed caused by content is empty in\n            // applySnapshotToDB\");\n            // }\n            // BeanUtils.populate(snapshotDO, content);\n\n            MetaSnapshotDO snapshotDO = new MetaSnapshotDO();\n            snapshotDO.setDestination(destination);\n            snapshotDO.setBinlogFile(position.getJournalName());\n            snapshotDO.setBinlogOffest(position.getPosition());\n            snapshotDO.setBinlogMasterId(String.valueOf(position.getServerId()));\n            snapshotDO.setBinlogTimestamp(position.getTimestamp());\n            snapshotDO.setData(JSON.toJSONString(schemaDdls, JSONWriter.Feature.LargeObject));\n            try {\n                metaSnapshotDAO.insert(snapshotDO);\n            } catch (Throwable e) {\n                if (isUkDuplicateException(e)) {\n                    // 忽略掉重复的位点\n                    logger.info(\"dup apply snapshot use position : \" + position + \" , just ignore\");\n                } else {\n                    throw new CanalParseException(\"apply failed caused by : \" + e.getMessage(), e);\n                }\n            }\n            return true;\n        } else {\n            logger.error(\"compare failed , check log\");\n        }\n        return false;\n    }\n\n    private boolean compareTableMetaDbAndMemory(MysqlConnection connection, MemoryTableMeta memoryTableMeta,\n                                                final String schema, final String table) {\n        TableMeta tableMetaFromMem = memoryTableMeta.find(schema, table);\n\n        TableMeta tableMetaFromDB = new TableMeta();\n        tableMetaFromDB.setSchema(schema);\n        tableMetaFromDB.setTable(table);\n        String createDDL = null;\n        try {\n            ResultSetPacket packet = connection.query(\"show create table \" + getFullName(schema, table));\n            if (packet.getFieldValues().size() > 1) {\n                createDDL = packet.getFieldValues().get(1);\n                tableMetaFromDB.setFields(TableMetaCache.parseTableMeta(schema, table, packet));\n            }\n        } catch (Throwable e) {\n            try {\n                // retry for broke pipe, see:\n                // https://github.com/alibaba/canal/issues/724\n                connection.reconnect();\n                ResultSetPacket packet = connection.query(\"show create table \" + getFullName(schema, table));\n                if (packet.getFieldValues().size() > 1) {\n                    createDDL = packet.getFieldValues().get(1);\n                    tableMetaFromDB.setFields(TableMetaCache.parseTableMeta(schema, table, packet));\n                }\n            } catch (IOException e1) {\n                if (e.getMessage().contains(\"errorNumber=1146\")) {\n                    logger.error(\"table not exist in db , pls check :\" + getFullName(schema, table) + \" , mem : \"\n                                 + tableMetaFromMem);\n                    return false;\n                }\n                throw new CanalParseException(e);\n            }\n        }\n\n        boolean result = compareTableMeta(tableMetaFromMem, tableMetaFromDB);\n        if (!result) {\n            logger.error(\"pls submit github issue, show create table ddl:\" + createDDL + \" , compare failed . \\n db : \"\n                         + tableMetaFromDB + \" \\n mem : \" + tableMetaFromMem);\n        }\n        return result;\n    }\n\n    private EntryPosition buildMemFromSnapshot(EntryPosition position) {\n        try {\n            MetaSnapshotDO snapshotDO = metaSnapshotDAO.findByTimestamp(destination, position.getTimestamp());\n            if (snapshotDO == null) {\n                return null;\n            }\n            String binlogFile = snapshotDO.getBinlogFile();\n            Long binlogOffest = snapshotDO.getBinlogOffest();\n            String binlogMasterId = snapshotDO.getBinlogMasterId();\n            Long binlogTimestamp = snapshotDO.getBinlogTimestamp();\n\n            EntryPosition snapshotPosition = new EntryPosition(binlogFile,\n                binlogOffest == null ? 0l : binlogOffest,\n                binlogTimestamp == null ? 0l : binlogTimestamp,\n                Long.valueOf(binlogMasterId == null ? \"-2\" : binlogMasterId));\n            // data存储为Map<String,String>，每个分库一套建表\n            String sqlData = snapshotDO.getData();\n            JSONObject jsonObj = JSON.parseObject(sqlData);\n            for (Map.Entry entry : jsonObj.entrySet()) {\n                // 记录到内存\n                if (!memoryTableMeta.apply(snapshotPosition,\n                    ObjectUtils.toString(entry.getKey()),\n                    ObjectUtils.toString(entry.getValue()),\n                    null)) {\n                    return null;\n                }\n            }\n\n            return snapshotPosition;\n        } catch (Throwable e) {\n            throw new CanalParseException(\"apply failed caused by : \" + e.getMessage(), e);\n        }\n    }\n\n    private boolean applyHistoryOnMemory(EntryPosition position, EntryPosition rollbackPosition) {\n        try {\n            List<MetaHistoryDO> metaHistoryDOList = metaHistoryDAO\n                .findByTimestamp(destination, position.getTimestamp(), rollbackPosition.getTimestamp());\n            if (metaHistoryDOList == null) {\n                return true;\n            }\n\n            for (MetaHistoryDO metaHistoryDO : metaHistoryDOList) {\n                String binlogFile = metaHistoryDO.getBinlogFile();\n                Long binlogOffest = metaHistoryDO.getBinlogOffest();\n                String binlogMasterId = metaHistoryDO.getBinlogMasterId();\n                Long binlogTimestamp = metaHistoryDO.getBinlogTimestamp();\n                String useSchema = metaHistoryDO.getUseSchema();\n                String sqlData = metaHistoryDO.getSqlText();\n                EntryPosition snapshotPosition = new EntryPosition(binlogFile,\n                    binlogOffest == null ? 0L : binlogOffest,\n                    binlogTimestamp == null ? 0L : binlogTimestamp,\n                    Long.valueOf(binlogMasterId == null ? \"-2\" : binlogMasterId));\n\n                // 如果是同一秒内,对比一下history的位点，如果比期望的位点要大，忽略之\n                if (snapshotPosition.getTimestamp() > rollbackPosition.getTimestamp()) {\n                    continue;\n                } else if (rollbackPosition.getServerId().equals(snapshotPosition.getServerId())\n                           && snapshotPosition.compareTo(rollbackPosition) > 0) {\n                               continue;\n                           }\n\n                // 记录到内存\n                if (!memoryTableMeta.apply(snapshotPosition, useSchema, sqlData, null)) {\n                    return false;\n                }\n\n            }\n\n            return metaHistoryDOList.size() > 0;\n        } catch (Throwable e) {\n            throw new CanalParseException(\"apply failed\", e);\n        }\n    }\n\n    private String structureSchema(String schema) {\n        if (schema.startsWith(\"`\") && schema.endsWith(\"`\")) {\n            return schema;\n        }\n        return \"`\" + schema + \"`\";\n    }\n\n    private String getFullName(String schema, String table) {\n        StringBuilder builder = new StringBuilder();\n        return builder.append(structureSchema(schema))\n            .append('.')\n            .append('`')\n            .append(StringUtils.replace(table, \"`\", \"``\"))\n            .append('`')\n            .toString();\n    }\n\n    private int snapshotExpire(int expireTimestamp) {\n        return metaSnapshotDAO.deleteByTimestamp(destination, expireTimestamp);\n    }\n\n    public void setFilter(CanalEventFilter filter) {\n        this.filter = filter;\n    }\n\n    public MetaHistoryDAO getMetaHistoryDAO() {\n        return metaHistoryDAO;\n    }\n\n    public void setMetaHistoryDAO(MetaHistoryDAO metaHistoryDAO) {\n        this.metaHistoryDAO = metaHistoryDAO;\n    }\n\n    public MetaSnapshotDAO getMetaSnapshotDAO() {\n        return metaSnapshotDAO;\n    }\n\n    public void setMetaSnapshotDAO(MetaSnapshotDAO metaSnapshotDAO) {\n        this.metaSnapshotDAO = metaSnapshotDAO;\n    }\n\n    public void setBlackFilter(CanalEventFilter blackFilter) {\n        this.blackFilter = blackFilter;\n    }\n\n    public Map<String, List<String>> getFieldFilterMap() {\n        return fieldFilterMap;\n    }\n\n    public void setFieldFilterMap(Map<String, List<String>> fieldFilterMap) {\n        this.fieldFilterMap = fieldFilterMap;\n    }\n\n    public Map<String, List<String>> getFieldBlackFilterMap() {\n        return fieldBlackFilterMap;\n    }\n\n    public void setFieldBlackFilterMap(Map<String, List<String>> fieldBlackFilterMap) {\n        this.fieldBlackFilterMap = fieldBlackFilterMap;\n    }\n\n    public int getSnapshotInterval() {\n        return snapshotInterval;\n    }\n\n    public void setSnapshotInterval(int snapshotInterval) {\n        this.snapshotInterval = snapshotInterval;\n    }\n\n    public int getSnapshotExpire() {\n        return snapshotExpire;\n    }\n\n    public void setSnapshotExpire(int snapshotExpire) {\n        this.snapshotExpire = snapshotExpire;\n    }\n\n    public MysqlConnection getConnection() {\n        return connection;\n    }\n\n    public void setConnection(MysqlConnection connection) {\n        this.connection = connection;\n    }\n\n    public boolean isUkDuplicateException(Throwable t) {\n        if (pattern.matcher(t.getMessage()).find() || h2Pattern.matcher(t.getMessage()).find()) {\n            // 违反外键约束时也抛出这种异常，所以这里还要判断包含字符串Duplicate entry\n            return true;\n        }\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/tsdb/DefaultTableMetaTSDBFactory.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.tsdb;\n\n/**\n * @author agapple 2017年10月11日 下午8:45:40\n * @since 1.0.25\n */\npublic class DefaultTableMetaTSDBFactory implements TableMetaTSDBFactory {\n\n    /**\n     * 代理一下tableMetaTSDB的获取,使用隔离的spring定义\n     */\n    public TableMetaTSDB build(String destination, String springXml) {\n        return TableMetaTSDBBuilder.build(destination, springXml);\n    }\n\n    public void destory(String destination) {\n        TableMetaTSDBBuilder.destory(destination);\n    }\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/tsdb/MemoryTableMeta.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.tsdb;\n\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport com.alibaba.polardbx.druid.DbType;\nimport com.alibaba.polardbx.druid.sql.SQLUtils;\nimport com.alibaba.polardbx.druid.sql.ast.SQLDataType;\nimport com.alibaba.polardbx.druid.sql.ast.SQLDataTypeImpl;\nimport com.alibaba.polardbx.druid.sql.ast.SQLExpr;\nimport com.alibaba.polardbx.druid.sql.ast.SQLStatement;\nimport com.alibaba.polardbx.druid.sql.ast.expr.SQLCharExpr;\nimport com.alibaba.polardbx.druid.sql.ast.expr.SQLIdentifierExpr;\nimport com.alibaba.polardbx.druid.sql.ast.expr.SQLMethodInvokeExpr;\nimport com.alibaba.polardbx.druid.sql.ast.expr.SQLNullExpr;\nimport com.alibaba.polardbx.druid.sql.ast.expr.SQLPropertyExpr;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLColumnConstraint;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLColumnDefinition;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLColumnPrimaryKey;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLColumnUniqueKey;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLCreateTableStatement;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLNotNullConstraint;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLNullConstraint;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLSelectOrderByItem;\nimport com.alibaba.polardbx.druid.sql.ast.statement.SQLTableElement;\nimport com.alibaba.polardbx.druid.sql.dialect.mysql.ast.MySqlPrimaryKey;\nimport com.alibaba.polardbx.druid.sql.dialect.mysql.ast.MySqlUnique;\nimport com.alibaba.polardbx.druid.sql.dialect.mysql.ast.expr.MySqlOrderingExpr;\nimport com.alibaba.polardbx.druid.sql.repository.Schema;\nimport com.alibaba.polardbx.druid.sql.repository.SchemaObject;\nimport com.alibaba.polardbx.druid.sql.repository.SchemaRepository;\nimport com.alibaba.polardbx.druid.sql.visitor.SQLASTOutputVisitor;\nimport com.alibaba.polardbx.druid.sql.visitor.VisitorFeature;\nimport com.alibaba.polardbx.druid.util.JdbcConstants;\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport com.alibaba.otter.canal.parse.inbound.TableMeta;\nimport com.alibaba.otter.canal.parse.inbound.TableMeta.FieldMeta;\nimport com.alibaba.otter.canal.parse.inbound.mysql.ddl.DruidDdlParser;\nimport com.alibaba.otter.canal.protocol.position.EntryPosition;\n\n/**\n * 基于DDL维护的内存表结构\n *\n * @author agapple 2017年7月27日 下午4:19:40\n * @since 3.2.5\n */\npublic class MemoryTableMeta implements TableMetaTSDB {\n\n    private Logger                       logger     = LoggerFactory.getLogger(MemoryTableMeta.class);\n    private Map<List<String>, TableMeta> tableMetas = new ConcurrentHashMap<>();\n    private SchemaRepository repository;\n\n    public MemoryTableMeta(){\n        repository = new SchemaRepository(JdbcConstants.MYSQL);\n    }\n\n    @Override\n    public boolean init(String destination) {\n        return true;\n    }\n\n    @Override\n    public void destory() {\n        tableMetas.clear();\n    }\n\n    public boolean apply(EntryPosition position, String schema, String ddl, String extra) {\n        tableMetas.clear();\n        synchronized (this) {\n            if (StringUtils.isNotEmpty(schema)) {\n                repository.setDefaultSchema(structureSchema(schema));\n            }\n\n            try {\n                // druid暂时flush privileges语法解析有问题\n                if (!StringUtils.startsWithIgnoreCase(StringUtils.trim(ddl), \"flush\")\n                    && !StringUtils.startsWithIgnoreCase(StringUtils.trim(ddl), \"grant\")\n                    && !StringUtils.startsWithIgnoreCase(StringUtils.trim(ddl), \"revoke\")\n                    && !StringUtils.startsWithIgnoreCase(StringUtils.trim(ddl), \"create user\")\n                    && !StringUtils.startsWithIgnoreCase(StringUtils.trim(ddl), \"alter user\")\n                    && !StringUtils.startsWithIgnoreCase(StringUtils.trim(ddl), \"drop user\")\n                    && !StringUtils.startsWithIgnoreCase(StringUtils.trim(ddl), \"create database\")\n                    && !StringUtils.startsWithIgnoreCase(StringUtils.trim(ddl), \"alter schema\")) {\n                    repository.console(ddl);\n                }\n            } catch (Throwable e) {\n                logger.warn(\"parse faield : \" + ddl, e);\n            }\n        }\n\n        // TableMeta meta = find(\"tddl5_00\", \"ab\");\n        // if (meta != null) {\n        // repository.setDefaultSchema(\"tddl5_00\");\n        // System.out.println(repository.console(\"show create table tddl5_00.ab\"));\n        // System.out.println(repository.console(\"show columns from tddl5_00.ab\"));\n        // }\n        return true;\n    }\n\n    @Override\n    public TableMeta find(String schema, String table) {\n        List<String> keys = Arrays.asList(schema, table);\n        TableMeta tableMeta = tableMetas.get(keys);\n        if (tableMeta == null) {\n            synchronized (this) {\n                tableMeta = tableMetas.get(keys);\n                if (tableMeta == null) {\n                    Schema schemaRep = repository.findSchema(schema);\n                    if (schemaRep == null) {\n                        return null;\n                    }\n                    SchemaObject data = schemaRep.findTable(table);\n                    if (data == null) {\n                        return null;\n                    }\n                    SQLStatement statement = data.getStatement();\n                    if (statement == null) {\n                        return null;\n                    }\n                    if (statement instanceof SQLCreateTableStatement) {\n                        tableMeta = parse((SQLCreateTableStatement) statement);\n                    }\n                    if (tableMeta != null) {\n                        if (table != null) {\n                            tableMeta.setTable(table);\n                        }\n                        if (schema != null) {\n                            tableMeta.setSchema(schema);\n                        }\n\n                        tableMetas.put(keys, tableMeta);\n                    }\n                }\n            }\n        }\n\n        return tableMeta;\n    }\n\n    @Override\n    public boolean rollback(EntryPosition position) {\n        throw new RuntimeException(\"not support for memory\");\n    }\n\n    public Map<String, String> snapshot() {\n        Map<String, String> schemaDdls = new HashMap<>();\n        for (Schema schema : repository.getSchemas()) {\n            StringBuilder data = new StringBuilder(4 * 1024);\n            for (String table : schema.showTables()) {\n                SchemaObject schemaObject = schema.findTable(table);\n                // fixed issue #4899\n                // snapshot输出的DDL语句未正确处理mysql keyword\n                // 导致canal重启回滚时会出现ddl解析失败的问题\n                // schemaObject.getStatement().output(data);\n                SQLASTOutputVisitor visitor = SQLUtils.createOutputVisitor(data, DbType.mysql);\n                visitor.config(VisitorFeature.OutputNameQuote, true);\n                schemaObject.getStatement().accept(visitor);\n\n                data.append(\"; \\n\");\n            }\n            schemaDdls.put(schema.getName(), data.toString());\n        }\n\n        return schemaDdls;\n    }\n\n    private String structureSchema(String schema) {\n        if (schema.startsWith(\"`\") && schema.endsWith(\"`\")) {\n            return schema;\n        }\n        return \"`\" + schema + \"`\";\n    }\n\n    private TableMeta parse(SQLCreateTableStatement statement) {\n        int size = statement.getTableElementList().size();\n        if (size > 0) {\n            TableMeta tableMeta = new TableMeta();\n            for (int i = 0; i < size; ++i) {\n                SQLTableElement element = statement.getTableElementList().get(i);\n                processTableElement(element, tableMeta);\n            }\n            return tableMeta;\n        }\n\n        return null;\n    }\n\n    private void processTableElement(SQLTableElement element, TableMeta tableMeta) {\n        if (element instanceof SQLColumnDefinition) {\n            FieldMeta fieldMeta = new FieldMeta();\n            SQLColumnDefinition column = (SQLColumnDefinition) element;\n            String name = getSqlName(column.getName());\n            // String charset = getSqlName(column.getCharsetExpr());\n            SQLDataType dataType = column.getDataType();\n            String dataTypStr = dataType.getName();\n            if (StringUtils.equalsIgnoreCase(dataTypStr, \"float\")) {\n                if (dataType.getArguments().size() == 1) {\n                    int num = Integer.valueOf(dataType.getArguments().get(0).toString());\n                    if (num > 24) {\n                        dataTypStr = \"double\";\n                    }\n                }\n            }\n\n            if (dataType.getArguments().size() > 0) {\n                dataTypStr += \"(\";\n                for (int i = 0; i < column.getDataType().getArguments().size(); i++) {\n                    if (i != 0) {\n                        dataTypStr += \",\";\n                    }\n                    SQLExpr arg = column.getDataType().getArguments().get(i);\n                    dataTypStr += arg.toString();\n                }\n                dataTypStr += \")\";\n            }\n\n            if (dataType instanceof SQLDataTypeImpl) {\n                SQLDataTypeImpl dataTypeImpl = (SQLDataTypeImpl) dataType;\n                if (dataTypeImpl.isUnsigned()) {\n                    dataTypStr += \" unsigned\";\n                }\n\n                if (dataTypeImpl.isZerofill()) {\n                    // mysql default behaiver\n                    // 如果设置了zerofill，自动给列添加unsigned属性\n                    if (!dataTypeImpl.isUnsigned()) {\n                        dataTypStr += \" unsigned\";\n                    }\n\n                    dataTypStr += \" zerofill\";\n                }\n            }\n\n            if (column.getDefaultExpr() == null || column.getDefaultExpr() instanceof SQLNullExpr) {\n                fieldMeta.setDefaultValue(null);\n            } else {\n                fieldMeta.setDefaultValue(DruidDdlParser.unescapeQuotaName(getSqlName(column.getDefaultExpr())));\n            }\n\n            fieldMeta.setColumnName(name);\n            fieldMeta.setColumnType(dataTypStr);\n            fieldMeta.setNullable(true);\n            List<SQLColumnConstraint> constraints = column.getConstraints();\n            for (SQLColumnConstraint constraint : constraints) {\n                if (constraint instanceof SQLNotNullConstraint) {\n                    fieldMeta.setNullable(false);\n                } else if (constraint instanceof SQLNullConstraint) {\n                    fieldMeta.setNullable(true);\n                } else if (constraint instanceof SQLColumnPrimaryKey) {\n                    fieldMeta.setKey(true);\n                    fieldMeta.setNullable(false);\n                } else if (constraint instanceof SQLColumnUniqueKey) {\n                    fieldMeta.setUnique(true);\n                }\n            }\n            tableMeta.addFieldMeta(fieldMeta);\n        } else if (element instanceof MySqlPrimaryKey) {\n            MySqlPrimaryKey column = (MySqlPrimaryKey) element;\n            List<SQLSelectOrderByItem> pks = column.getColumns();\n            for (SQLSelectOrderByItem pk : pks) {\n                String name = getSqlName(pk.getExpr());\n                FieldMeta field = tableMeta.getFieldMetaByName(name);\n                field.setKey(true);\n                field.setNullable(false);\n            }\n        } else if (element instanceof MySqlUnique) {\n            MySqlUnique column = (MySqlUnique) element;\n            List<SQLSelectOrderByItem> uks = column.getColumns();\n            // https://github.com/alibaba/canal/issues/5094\n            // 处理一下函数索引\n            List<String> columnNames = new ArrayList<String>();\n            for (SQLSelectOrderByItem uk : uks) {\n                SQLExpr sqlName = uk.getExpr();\n                columnNames.addAll(getIndexColumnNames(sqlName));\n            }\n            // uniqe打标\n            for (String name : columnNames) {\n                FieldMeta field = tableMeta.tryGetFieldMetaByName(name);\n                if (field != null) {\n                    field.setUnique(true);\n                }\n            }\n        }\n    }\n\n    private List<String> getIndexColumnNames(SQLExpr expr) {\n        if (expr instanceof SQLMethodInvokeExpr) {\n            // 需要递归处理下函数索引, 尽可能收集一下列名\n            // 常见的case:\n            // 1. upper(col)\n            // 2. left(upper(col) , 10)\n            // 3. col(10)\n            List<SQLExpr> indexExpres = ((SQLMethodInvokeExpr) expr).getArguments();\n            List<String> columnNames = new ArrayList<String>();\n            // 加上当前列\n            columnNames.add(getSqlName(expr));\n            // 处理函数索引列\n            for (SQLExpr exArgs : indexExpres) {\n                if (exArgs instanceof SQLMethodInvokeExpr) {\n                    // 加上当前列\n                    columnNames.add(getSqlName(exArgs));\n                    columnNames.addAll(getIndexColumnNames(exArgs));\n                } else {\n                    String columnName = getSqlName(exArgs);\n                    columnNames.add(columnName);\n                }\n            }\n\n            return columnNames;\n        } else {\n            String columnName = getSqlName(expr);\n            return Arrays.asList(columnName);\n        }\n    }\n\n    private String getSqlName(SQLExpr sqlName) {\n        if (sqlName == null) {\n            return null;\n        }\n\n        if (sqlName instanceof SQLPropertyExpr) {\n            SQLIdentifierExpr owner = (SQLIdentifierExpr) ((SQLPropertyExpr) sqlName).getOwner();\n            return DruidDdlParser.unescapeName(owner.getName()) + \".\"\n                   + DruidDdlParser.unescapeName(((SQLPropertyExpr) sqlName).getName());\n        } else if (sqlName instanceof SQLIdentifierExpr) {\n            return DruidDdlParser.unescapeName(((SQLIdentifierExpr) sqlName).getName());\n        } else if (sqlName instanceof SQLCharExpr) {\n            return ((SQLCharExpr) sqlName).getText();\n        } else if (sqlName instanceof SQLMethodInvokeExpr) {\n            return DruidDdlParser.unescapeName(((SQLMethodInvokeExpr) sqlName).getMethodName());\n        } else if (sqlName instanceof MySqlOrderingExpr) {\n            return getSqlName(((MySqlOrderingExpr) sqlName).getExpr());\n        } else {\n            return sqlName.toString();\n        }\n    }\n\n    public SchemaRepository getRepository() {\n        return repository;\n    }\n\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/tsdb/TableMetaTSDB.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.tsdb;\n\nimport java.util.Map;\n\nimport com.alibaba.otter.canal.parse.inbound.TableMeta;\nimport com.alibaba.otter.canal.protocol.position.EntryPosition;\n\n/**\n * 表结构的时间序列存储\n *\n * @author agapple 2017年7月27日 下午4:06:30\n * @since 1.0.25\n */\npublic interface TableMetaTSDB {\n\n    /**\n     * 初始化\n     */\n    public boolean init(String destination);\n\n    /**\n     * 销毁资源\n     */\n    public void destory();\n\n    /**\n     * 获取当前的表结构\n     */\n    public TableMeta find(String schema, String table);\n\n    /**\n     * 添加ddl到时间序列库中\n     */\n    public boolean apply(EntryPosition position, String schema, String ddl, String extra);\n\n    /**\n     * 回滚到指定位点的表结构\n     */\n    public boolean rollback(EntryPosition position);\n\n    /**\n     * 生成快照内容\n     */\n    public Map<String/* schema */, String> snapshot();\n\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/tsdb/TableMetaTSDBBuilder.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.tsdb;\n\nimport java.util.concurrent.ConcurrentMap;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.context.support.ClassPathXmlApplicationContext;\n\nimport com.google.common.collect.Maps;\n\n/**\n * tableMeta构造器\n * \n * @author agapple 2018年8月8日 上午11:01:08\n * @since 1.0.25\n */\n\npublic class TableMetaTSDBBuilder {\n\n    protected final static Logger                                        logger   = LoggerFactory.getLogger(DefaultTableMetaTSDBFactory.class);\n    private static ConcurrentMap<String, ClassPathXmlApplicationContext> contexts = Maps.newConcurrentMap();\n\n    /**\n     * 代理一下tableMetaTSDB的获取,使用隔离的spring定义\n     */\n    public static TableMetaTSDB build(String destination, String springXml) {\n        if (StringUtils.isNotEmpty(springXml)) {\n            ClassPathXmlApplicationContext applicationContext = contexts.get(destination);\n            if (applicationContext == null) {\n                synchronized (contexts) {\n                    if (applicationContext == null) {\n                        if (!StringUtils.startsWithIgnoreCase(springXml, \"classpath:\")) {\n                            springXml = \"classpath:\" + springXml;\n                        }\n                        applicationContext = new ClassPathXmlApplicationContext(springXml);\n                        contexts.put(destination, applicationContext);\n                    }\n                }\n            }\n            TableMetaTSDB tableMetaTSDB = (TableMetaTSDB) applicationContext.getBean(\"tableMetaTSDB\");\n            logger.info(\"{} init TableMetaTSDB with {}\", destination, springXml);\n            return tableMetaTSDB;\n        } else {\n            return null;\n        }\n    }\n\n    public static void destory(String destination) {\n        ClassPathXmlApplicationContext context = contexts.remove(destination);\n        if (context != null) {\n            logger.info(\"{} destory TableMetaTSDB\", destination);\n            context.close();\n        }\n    }\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/tsdb/TableMetaTSDBFactory.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.tsdb;\n\n/**\n * tableMeta构造器,允许重载实现\n * \n * @author agapple 2018年8月8日 上午11:01:08\n * @since 1.0.26\n */\n\npublic interface TableMetaTSDBFactory {\n\n    /**\n     * 代理一下tableMetaTSDB的获取,使用隔离的spring定义\n     */\n    public TableMetaTSDB build(String destination, String springXml);\n\n    public void destory(String destination);\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/tsdb/dao/MetaBaseDAO.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao;\n\nimport java.io.InputStream;\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.sql.Statement;\n\nimport javax.sql.DataSource;\n\nimport org.apache.commons.io.IOUtils;\nimport org.apache.commons.lang.StringUtils;\nimport org.mybatis.spring.support.SqlSessionDaoSupport;\n\n/**\n * @author agapple 2017年10月14日 上午1:05:22\n * @since 1.0.25\n */\n@SuppressWarnings(\"deprecation\")\npublic class MetaBaseDAO extends SqlSessionDaoSupport {\n\n    protected boolean isH2 = false;\n\n    protected void initTable(String tableName) throws Exception {\n        Connection conn = null;\n        InputStream input = null;\n        try {\n            DataSource dataSource = getSqlSessionFactory().getConfiguration().getEnvironment().getDataSource();\n            conn = dataSource.getConnection();\n            String name = \"mysql\";\n            isH2 = isH2(conn);\n            if (isH2) {\n                name = \"h2\";\n            }\n            input = Thread.currentThread()\n                .getContextClassLoader()\n                .getResourceAsStream(\"ddl/\" + name + \"/\" + tableName + \".sql\");\n            if (input == null) {\n                return;\n            }\n\n            String sql = StringUtils.join(IOUtils.readLines(input), \"\\n\");\n            Statement stmt = conn.createStatement();\n            stmt.execute(sql);\n            stmt.close();\n        } catch (Throwable e) {\n            logger.warn(\"init \" + tableName + \" failed\", e);\n        } finally {\n            IOUtils.closeQuietly(input);\n            if (conn != null) {\n                conn.close();\n            }\n        }\n    }\n\n    private boolean isH2(Connection conn) throws SQLException {\n        String product = conn.getMetaData().getDatabaseProductName();\n        return StringUtils.containsIgnoreCase(product, \"H2\");\n    }\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/tsdb/dao/MetaHistoryDAO.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao;\n\nimport java.util.HashMap;\nimport java.util.List;\n\nimport com.google.common.collect.Maps;\n\n/**\n * canal数据的存储\n *\n * @author wanshao 2017年7月27日 下午10:51:55\n * @since 3.2.5\n */\n@SuppressWarnings(\"deprecation\")\npublic class MetaHistoryDAO extends MetaBaseDAO {\n\n    public Long insert(MetaHistoryDO metaDO) {\n        return getSqlSession().getMapper(MetaHistoryMapper.class).insert(metaDO);\n    }\n\n    public List<MetaHistoryDO> findByTimestamp(String destination, Long snapshotTimestamp, Long timestamp) {\n        HashMap params = Maps.newHashMapWithExpectedSize(2);\n        params.put(\"destination\", destination);\n        params.put(\"snapshotTimestamp\", snapshotTimestamp == null ? 0L : snapshotTimestamp);\n        params.put(\"timestamp\", timestamp == null ? 0L : timestamp);\n        return getSqlSession().getMapper(MetaHistoryMapper.class).findByTimestamp(params);\n    }\n\n    public Integer deleteByName(String destination) {\n        HashMap params = Maps.newHashMapWithExpectedSize(2);\n        params.put(\"destination\", destination);\n        return getSqlSession().getMapper(MetaHistoryMapper.class).deleteByName(params);\n    }\n\n    /**\n     * 删除interval秒之前的数据\n     */\n    public Integer deleteByTimestamp(String destination, int interval) {\n        HashMap params = Maps.newHashMapWithExpectedSize(2);\n        long timestamp = System.currentTimeMillis() - interval * 1000;\n        params.put(\"timestamp\", timestamp);\n        params.put(\"destination\", destination);\n        return getSqlSession().getMapper(MetaHistoryMapper.class).deleteByTimestamp(params);\n    }\n\n    protected void initDao() throws Exception {\n        initTable(\"meta_history\");\n    }\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/tsdb/dao/MetaHistoryDO.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao;\n\nimport java.util.Date;\n\n/**\n * @author agapple 2017年7月27日 下午11:09:41\n * @since 1.0.25\n */\npublic class MetaHistoryDO {\n\n    private Long   id;\n    private Date   gmtCreate;\n    private Date   gmtModified;\n    private String destination;\n    private String binlogFile;\n    private Long   binlogOffest;\n    private String binlogMasterId;\n    private Long   binlogTimestamp;\n    private String useSchema;\n    private String sqlSchema;\n    private String sqlTable;\n    private String sqlText;\n    private String sqlType;\n    private String extra;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public Date getGmtCreate() {\n        return gmtCreate;\n    }\n\n    public void setGmtCreate(Date gmtCreate) {\n        this.gmtCreate = gmtCreate;\n    }\n\n    public Date getGmtModified() {\n        return gmtModified;\n    }\n\n    public void setGmtModified(Date gmtModified) {\n        this.gmtModified = gmtModified;\n    }\n\n    public String getBinlogFile() {\n        return binlogFile;\n    }\n\n    public void setBinlogFile(String binlogFile) {\n        this.binlogFile = binlogFile;\n    }\n\n    public Long getBinlogOffest() {\n        return binlogOffest;\n    }\n\n    public void setBinlogOffest(Long binlogOffest) {\n        this.binlogOffest = binlogOffest;\n    }\n\n    public String getBinlogMasterId() {\n        return binlogMasterId;\n    }\n\n    public void setBinlogMasterId(String binlogMasterId) {\n        this.binlogMasterId = binlogMasterId;\n    }\n\n    public Long getBinlogTimestamp() {\n        return binlogTimestamp;\n    }\n\n    public void setBinlogTimestamp(Long binlogTimestamp) {\n        this.binlogTimestamp = binlogTimestamp;\n    }\n\n    public String getUseSchema() {\n        return useSchema;\n    }\n\n    public void setUseSchema(String useSchema) {\n        this.useSchema = useSchema;\n    }\n\n    public String getExtra() {\n        return extra;\n    }\n\n    public void setExtra(String extra) {\n        this.extra = extra;\n    }\n\n    public String getDestination() {\n        return destination;\n    }\n\n    public void setDestination(String destination) {\n        this.destination = destination;\n    }\n\n    public String getSqlSchema() {\n        return sqlSchema;\n    }\n\n    public void setSqlSchema(String sqlSchema) {\n        this.sqlSchema = sqlSchema;\n    }\n\n    public String getSqlTable() {\n        return sqlTable;\n    }\n\n    public void setSqlTable(String sqlTable) {\n        this.sqlTable = sqlTable;\n    }\n\n    public String getSqlText() {\n        return sqlText;\n    }\n\n    public void setSqlText(String sqlText) {\n        this.sqlText = sqlText;\n    }\n\n    public String getSqlType() {\n        return sqlType;\n    }\n\n    public void setSqlType(String sqlType) {\n        this.sqlType = sqlType;\n    }\n\n    @Override\n    public String toString() {\n        return \"MetaHistoryDO [id=\" + id + \", gmtCreate=\" + gmtCreate + \", gmtModified=\" + gmtModified\n               + \", destination=\" + destination + \", binlogFile=\" + binlogFile + \", binlogOffest=\" + binlogOffest\n               + \", binlogMasterId=\" + binlogMasterId + \", binlogTimestamp=\" + binlogTimestamp + \", useSchema=\"\n               + useSchema + \", sqlSchema=\" + sqlSchema + \", sqlTable=\" + sqlTable + \", sqlText=\" + sqlText\n               + \", sqlType=\" + sqlType + \", extra=\" + extra + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/tsdb/dao/MetaHistoryMapper.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao;\n\nimport java.util.List;\nimport java.util.Map;\n\npublic interface MetaHistoryMapper {\n\n    List<MetaHistoryDO> findByTimestamp(Map<String, Object> map);\n\n    long insert(MetaHistoryDO metaHistoryDO);\n\n    int deleteByName(Map<String, Object> map);\n\n    int deleteByTimestamp(Map<String, Object> map);\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/tsdb/dao/MetaSnapshotDAO.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao;\n\nimport java.util.HashMap;\n\nimport com.google.common.collect.Maps;\n\n/**\n * canal数据的存储\n *\n * @author wanshao 2017年7月27日 下午10:51:55\n * @since 3.2.5\n */\n@SuppressWarnings(\"deprecation\")\npublic class MetaSnapshotDAO extends MetaBaseDAO {\n\n    public Long insert(MetaSnapshotDO snapshotDO) {\n        return getSqlSession().getMapper(MetaSnapshotMapper.class).insert(snapshotDO);\n    }\n\n    public Long update(MetaSnapshotDO snapshotDO) {\n        return getSqlSession().getMapper(MetaSnapshotMapper.class).update(snapshotDO);\n    }\n\n    public MetaSnapshotDO findByTimestamp(String destination, Long timestamp) {\n        HashMap params = Maps.newHashMapWithExpectedSize(2);\n        params.put(\"timestamp\", timestamp == null ? 0L : timestamp);\n        params.put(\"destination\", destination);\n        return getSqlSession().getMapper(MetaSnapshotMapper.class).findByTimestamp(params);\n    }\n\n    public Integer deleteByName(String destination) {\n        HashMap params = Maps.newHashMapWithExpectedSize(2);\n        params.put(\"destination\", destination);\n        return getSqlSession().getMapper(MetaSnapshotMapper.class).deleteByName(params);\n    }\n\n    /**\n     * 删除interval秒之前的数据\n     */\n    public Integer deleteByTimestamp(String destination, int interval) {\n        HashMap params = Maps.newHashMapWithExpectedSize(2);\n        long timestamp = System.currentTimeMillis() - interval * 1000;\n        params.put(\"timestamp\", timestamp);\n        params.put(\"destination\", destination);\n        return getSqlSession().getMapper(MetaSnapshotMapper.class).deleteByTimestamp(params);\n    }\n\n    protected void initDao() throws Exception {\n        initTable(\"meta_snapshot\");\n    }\n\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/tsdb/dao/MetaSnapshotDO.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao;\n\nimport java.util.Date;\n\n/**\n * @author agapple 2017年7月27日 下午11:09:41\n * @since 1.0.25\n */\npublic class MetaSnapshotDO {\n\n    private Long   id;\n    private Date   gmtCreate;\n    private Date   gmtModified;\n    private String destination;\n    private String binlogFile;\n    private Long   binlogOffest;\n    private String binlogMasterId;\n    private Long   binlogTimestamp;\n    private String data;\n    private String extra;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public Date getGmtCreate() {\n        return gmtCreate;\n    }\n\n    public void setGmtCreate(Date gmtCreate) {\n        this.gmtCreate = gmtCreate;\n    }\n\n    public Date getGmtModified() {\n        return gmtModified;\n    }\n\n    public void setGmtModified(Date gmtModified) {\n        this.gmtModified = gmtModified;\n    }\n\n    public String getBinlogFile() {\n        return binlogFile;\n    }\n\n    public void setBinlogFile(String binlogFile) {\n        this.binlogFile = binlogFile;\n    }\n\n    public Long getBinlogOffest() {\n        return binlogOffest;\n    }\n\n    public void setBinlogOffest(Long binlogOffest) {\n        this.binlogOffest = binlogOffest;\n    }\n\n    public String getBinlogMasterId() {\n        return binlogMasterId;\n    }\n\n    public void setBinlogMasterId(String binlogMasterId) {\n        this.binlogMasterId = binlogMasterId;\n    }\n\n    public Long getBinlogTimestamp() {\n        return binlogTimestamp;\n    }\n\n    public void setBinlogTimestamp(Long binlogTimestamp) {\n        this.binlogTimestamp = binlogTimestamp;\n    }\n\n    public String getData() {\n        return data;\n    }\n\n    public void setData(String data) {\n        this.data = data;\n    }\n\n    public String getExtra() {\n        return extra;\n    }\n\n    public void setExtra(String extra) {\n        this.extra = extra;\n    }\n\n    public String getDestination() {\n        return destination;\n    }\n\n    public void setDestination(String destination) {\n        this.destination = destination;\n    }\n\n    @Override\n    public String toString() {\n        return \"MetaSnapshotDO [id=\" + id + \", gmtCreate=\" + gmtCreate + \", gmtModified=\" + gmtModified\n               + \", destination=\" + destination + \", binlogFile=\" + binlogFile + \", binlogOffest=\" + binlogOffest\n               + \", binlogMasterId=\" + binlogMasterId + \", binlogTimestamp=\" + binlogTimestamp + \", data=\" + data\n               + \", extra=\" + extra + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/tsdb/dao/MetaSnapshotMapper.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao;\n\nimport java.util.Map;\n\npublic interface MetaSnapshotMapper {\n\n    MetaSnapshotDO findByTimestamp(Map<String, Object> map);\n\n    long insert(MetaSnapshotDO metaSnapshotDO);\n\n    long update(MetaSnapshotDO metaSnapshotDO);\n\n    int deleteByName(Map<String, Object> map);\n\n    int deleteByTimestamp(Map<String, Object> map);\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/index/AbstractLogPositionManager.java",
    "content": "package com.alibaba.otter.canal.parse.index;\n\nimport com.alibaba.otter.canal.common.AbstractCanalLifeCycle;\n\n/**\n * Created by yinxiu on 17/3/17. Email: marklin.hz@gmail.com\n */\npublic abstract class AbstractLogPositionManager extends AbstractCanalLifeCycle implements CanalLogPositionManager {\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/index/CanalLogPositionManager.java",
    "content": "package com.alibaba.otter.canal.parse.index;\n\nimport com.alibaba.otter.canal.common.CanalLifeCycle;\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\n\n/**\n * Created by yinxiu on 17/3/17. Email: marklin.hz@gmail.com\n */\npublic interface CanalLogPositionManager extends CanalLifeCycle {\n\n    LogPosition getLatestIndexBy(String destination);\n\n    void persistLogPosition(String destination, LogPosition logPosition) throws CanalParseException;\n\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/index/FailbackLogPositionManager.java",
    "content": "package com.alibaba.otter.canal.parse.index;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\n\n/**\n * Created by yinxiu on 17/3/18. Email: marklin.hz@gmail.com\n * 实现基于failover查找的机制完成meta的操作\n *\n * <pre>\n * 应用场景：比如针对内存buffer，出现HA切换，先尝试从内存buffer区中找到lastest position，如果不存在才尝试找一下meta里消费的信息\n * </pre>\n */\npublic class FailbackLogPositionManager extends AbstractLogPositionManager {\n\n    private final static Logger           logger = LoggerFactory.getLogger(FailbackLogPositionManager.class);\n\n    private final CanalLogPositionManager primary;\n    private final CanalLogPositionManager secondary;\n\n    public FailbackLogPositionManager(CanalLogPositionManager primary, CanalLogPositionManager secondary){\n        if (primary == null) {\n            throw new NullPointerException(\"nul primary LogPositionManager\");\n        }\n        if (secondary == null) {\n            throw new NullPointerException(\"nul secondary LogPositionManager\");\n        }\n\n        this.primary = primary;\n        this.secondary = secondary;\n    }\n\n    @Override\n    public void start() {\n        super.start();\n\n        if (!primary.isStart()) {\n            primary.start();\n        }\n\n        if (!secondary.isStart()) {\n            secondary.start();\n        }\n    }\n\n    @Override\n    public void stop() {\n        super.stop();\n\n        if (secondary.isStart()) {\n            secondary.stop();\n        }\n\n        if (primary.isStart()) {\n            primary.stop();\n        }\n    }\n\n    @Override\n    public LogPosition getLatestIndexBy(String destination) {\n        LogPosition logPosition = primary.getLatestIndexBy(destination);\n        if (logPosition != null) {\n            return logPosition;\n        }\n        return secondary.getLatestIndexBy(destination);\n    }\n\n    @Override\n    public void persistLogPosition(String destination, LogPosition logPosition) throws CanalParseException {\n        try {\n            primary.persistLogPosition(destination, logPosition);\n        } catch (CanalParseException e) {\n            logger.warn(\"persistLogPosition use primary log position manager exception. destination: {}, logPosition: {}\",\n                destination,\n                logPosition,\n                e);\n            secondary.persistLogPosition(destination, logPosition);\n        }\n    }\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/index/FileMixedLogPositionManager.java",
    "content": "package com.alibaba.otter.canal.parse.index;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.charset.Charset;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.commons.io.FileUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.common.utils.JsonUtils;\nimport com.alibaba.otter.canal.meta.exception.CanalMetaManagerException;\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\nimport com.google.common.collect.MigrateMap;\n\n/**\n * Created by yinxiu on 17/3/18. Email: marklin.hz@gmail.com 基于文件刷新的log\n * position实现\n *\n * <pre>\n * 策略：\n * 1. 先写内存，然后定时刷新数据到File\n * 2. 数据采取overwrite模式(只保留最后一次)\n * </pre>\n */\npublic class FileMixedLogPositionManager extends AbstractLogPositionManager {\n\n    private final static Logger      logger       = LoggerFactory.getLogger(FileMixedLogPositionManager.class);\n    private final static Charset     charset      = Charset.forName(\"UTF-8\");\n\n    private File                     dataDir;\n\n    private Map<String, File>        dataFileCaches;\n\n    private ScheduledExecutorService executorService;\n\n    @SuppressWarnings(\"serial\")\n    private final LogPosition        nullPosition = new LogPosition() {\n                                                  };\n\n    private MemoryLogPositionManager memoryLogPositionManager;\n\n    private long                     period;\n    private Set<String>              persistTasks;\n\n    public FileMixedLogPositionManager(File dataDir, long period, MemoryLogPositionManager memoryLogPositionManager){\n        if (dataDir == null) {\n            throw new NullPointerException(\"null dataDir\");\n        }\n        if (period <= 0) {\n            throw new IllegalArgumentException(\"period must be positive, given: \" + period);\n        }\n        if (memoryLogPositionManager == null) {\n            throw new NullPointerException(\"null memoryLogPositionManager\");\n        }\n        this.dataDir = dataDir;\n        this.period = period;\n        this.memoryLogPositionManager = memoryLogPositionManager;\n\n        this.dataFileCaches = MigrateMap.makeComputingMap(this::getDataFile);\n\n        this.executorService = Executors.newScheduledThreadPool(1);\n        this.persistTasks = Collections.synchronizedSet(new HashSet<>());\n    }\n\n    @Override\n    public void start() {\n        super.start();\n\n        if (!dataDir.exists()) {\n            try {\n                FileUtils.forceMkdir(dataDir);\n            } catch (IOException e) {\n                throw new CanalMetaManagerException(e);\n            }\n        }\n\n        if (!dataDir.canRead() || !dataDir.canWrite()) {\n            throw new CanalMetaManagerException(\"dir[\" + dataDir.getPath() + \"] can not read/write\");\n        }\n\n        if (!memoryLogPositionManager.isStart()) {\n            memoryLogPositionManager.start();\n        }\n\n        // 启动定时工作任务\n        executorService.scheduleAtFixedRate(() -> {\n            List<String> tasks = new ArrayList<>(persistTasks);\n            for (String destination : tasks) {\n                try {\n                    // 定时将内存中的最新值刷到file中，多次变更只刷一次\n                    flushDataToFile(destination);\n                    persistTasks.remove(destination);\n                } catch (Throwable e) {\n                    // ignore\n                    logger.error(\"period update\" + destination + \" curosr failed!\", e);\n                }\n            }\n        }, period, period, TimeUnit.MILLISECONDS);\n\n    }\n\n    @Override\n    public void stop() {\n        super.stop();\n\n        flushDataToFile();\n        executorService.shutdown();\n        memoryLogPositionManager.stop();\n    }\n\n    @Override\n    public LogPosition getLatestIndexBy(String destination) {\n        LogPosition logPosition = memoryLogPositionManager.getLatestIndexBy(destination);\n        if (logPosition != null) {\n            return logPosition;\n        }\n        logPosition = loadDataFromFile(dataFileCaches.get(destination));\n        if (logPosition == null) {\n            return nullPosition;\n        }\n        return logPosition;\n    }\n\n    @Override\n    public void persistLogPosition(String destination, LogPosition logPosition) throws CanalParseException {\n        persistTasks.add(destination);\n        memoryLogPositionManager.persistLogPosition(destination, logPosition);\n    }\n\n    // ============================ helper method ======================\n\n    private File getDataFile(String destination) {\n        File destinationMetaDir = new File(dataDir, destination);\n        if (!destinationMetaDir.exists()) {\n            try {\n                FileUtils.forceMkdir(destinationMetaDir);\n            } catch (IOException e) {\n                throw new CanalMetaManagerException(e);\n            }\n        }\n\n        String dataFileName = \"parse.dat\";\n        return new File(destinationMetaDir, dataFileName);\n    }\n\n    private void flushDataToFile() {\n        for (String destination : memoryLogPositionManager.destinations()) {\n            flushDataToFile(destination);\n        }\n    }\n\n    private void flushDataToFile(String destination) {\n        flushDataToFile(destination, dataFileCaches.get(destination));\n    }\n\n    private void flushDataToFile(String destination, File dataFile) {\n        LogPosition position = memoryLogPositionManager.getLatestIndexBy(destination);\n        if (position != null && position != nullPosition) {\n            String json = JsonUtils.marshalToString(position);\n            try {\n                FileUtils.writeStringToFile(dataFile, json);\n            } catch (IOException e) {\n                throw new CanalMetaManagerException(e);\n            }\n        }\n    }\n\n    private LogPosition loadDataFromFile(File dataFile) {\n        try {\n            if (!dataFile.exists()) {\n                return null;\n            }\n\n            String json = FileUtils.readFileToString(dataFile, charset);\n            return JsonUtils.unmarshalFromString(json, LogPosition.class);\n        } catch (IOException e) {\n            throw new CanalMetaManagerException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/index/MemoryLogPositionManager.java",
    "content": "package com.alibaba.otter.canal.parse.index;\n\nimport java.util.Map;\nimport java.util.Set;\n\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\nimport com.google.common.collect.MapMaker;\n\n/**\n * Created by yinxiu on 17/3/17. Email: marklin.hz@gmail.com\n */\npublic class MemoryLogPositionManager extends AbstractLogPositionManager {\n\n    private Map<String, LogPosition> positions;\n\n    @Override\n    public void start() {\n        super.start();\n        positions = new MapMaker().makeMap();\n    }\n\n    @Override\n    public void stop() {\n        super.stop();\n        positions.clear();\n    }\n\n    @Override\n    public LogPosition getLatestIndexBy(String destination) {\n        return positions.get(destination);\n    }\n\n    @Override\n    public void persistLogPosition(String destination, LogPosition logPosition) throws CanalParseException {\n        positions.put(destination, logPosition);\n    }\n\n    public Set<String> destinations() {\n        return positions.keySet();\n    }\n\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/index/MetaLogPositionManager.java",
    "content": "package com.alibaba.otter.canal.parse.index;\n\nimport java.util.List;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.util.CollectionUtils;\n\nimport com.alibaba.otter.canal.meta.CanalMetaManager;\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\nimport com.alibaba.otter.canal.protocol.ClientIdentity;\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\nimport com.alibaba.otter.canal.store.helper.CanalEventUtils;\n\n/**\n * Created by yinxiu on 17/3/18. Email: marklin.hz@gmail.com\n */\npublic class MetaLogPositionManager extends AbstractLogPositionManager {\n\n    private final static Logger    logger = LoggerFactory.getLogger(MetaLogPositionManager.class);\n\n    private final CanalMetaManager metaManager;\n\n    public MetaLogPositionManager(CanalMetaManager metaManager){\n        if (metaManager == null) {\n            throw new NullPointerException(\"null metaManager\");\n        }\n\n        this.metaManager = metaManager;\n    }\n\n    @Override\n    public void stop() {\n        super.stop();\n\n        if (metaManager.isStart()) {\n            metaManager.stop();\n        }\n    }\n\n    @Override\n    public void start() {\n        super.start();\n\n        if (!metaManager.isStart()) {\n            metaManager.start();\n        }\n    }\n\n    @Override\n    public LogPosition getLatestIndexBy(String destination) {\n        List<ClientIdentity> clientIdentities = metaManager.listAllSubscribeInfo(destination);\n        LogPosition result = null;\n        if (!CollectionUtils.isEmpty(clientIdentities)) {\n            // 尝试找到一个最小的logPosition\n            for (ClientIdentity clientIdentity : clientIdentities) {\n                LogPosition position = (LogPosition) metaManager.getCursor(clientIdentity);\n                if (position == null) {\n                    continue;\n                }\n\n                if (result == null) {\n                    result = position;\n                } else {\n                    result = CanalEventUtils.min(result, position);\n                }\n            }\n        }\n\n        return result;\n    }\n\n    @Override\n    public void persistLogPosition(String destination, LogPosition logPosition) throws CanalParseException {\n        // do nothing\n        logger.info(\"destination [{}] persist LogPosition:{}\", destination, logPosition);\n    }\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/index/MixedLogPositionManager.java",
    "content": "package com.alibaba.otter.canal.parse.index;\n\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.common.zookeeper.ZkClientx;\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\n\n/**\n * Created by yinxiu on 17/3/17. Email: marklin.hz@gmail.com Memory first.\n * Asynchronous commit position info to ZK.\n */\npublic class MixedLogPositionManager extends AbstractLogPositionManager {\n\n    private final Logger                      logger = LoggerFactory.getLogger(MixedLogPositionManager.class);\n\n    private final MemoryLogPositionManager    memoryLogPositionManager;\n    private final ZooKeeperLogPositionManager zooKeeperLogPositionManager;\n\n    private final ExecutorService             executor;\n\n    public MixedLogPositionManager(ZkClientx zkClient){\n        if (zkClient == null) {\n            throw new NullPointerException(\"null zkClient\");\n        }\n\n        this.memoryLogPositionManager = new MemoryLogPositionManager();\n        this.zooKeeperLogPositionManager = new ZooKeeperLogPositionManager(zkClient);\n\n        this.executor = Executors.newFixedThreadPool(1);\n    }\n\n    @Override\n    public void start() {\n        super.start();\n\n        if (!memoryLogPositionManager.isStart()) {\n            memoryLogPositionManager.start();\n        }\n\n        if (!zooKeeperLogPositionManager.isStart()) {\n            zooKeeperLogPositionManager.start();\n        }\n    }\n\n    @Override\n    public void stop() {\n        super.stop();\n\n        executor.shutdown();\n        zooKeeperLogPositionManager.stop();\n        memoryLogPositionManager.stop();\n    }\n\n    @Override\n    public LogPosition getLatestIndexBy(String destination) {\n        LogPosition logPosition = memoryLogPositionManager.getLatestIndexBy(destination);\n        if (logPosition != null) {\n            return logPosition;\n        }\n        logPosition = zooKeeperLogPositionManager.getLatestIndexBy(destination);\n        // 这里保持和重构前的逻辑一致,重新添加到Memory中\n        if (logPosition != null) {\n            memoryLogPositionManager.persistLogPosition(destination, logPosition);\n        }\n        return logPosition;\n    }\n\n    @Override\n    public void persistLogPosition(final String destination, final LogPosition logPosition) throws CanalParseException {\n        memoryLogPositionManager.persistLogPosition(destination, logPosition);\n        executor.submit(() -> {\n            try {\n                zooKeeperLogPositionManager.persistLogPosition(destination, logPosition);\n            } catch (Exception e) {\n                logger.error(\"ERROR # persist to zookeeper has an error\", e);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/index/PeriodMixedLogPositionManager.java",
    "content": "package com.alibaba.otter.canal.parse.index;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\n\n/**\n * Created by yinxiu on 17/3/18. Email: marklin.hz@gmail.com\n */\npublic class PeriodMixedLogPositionManager extends AbstractLogPositionManager {\n\n    private static final Logger         logger       = LoggerFactory.getLogger(PeriodMixedLogPositionManager.class);\n\n    private MemoryLogPositionManager    memoryLogPositionManager;\n    private ZooKeeperLogPositionManager zooKeeperLogPositionManager;\n    private ScheduledExecutorService    executorService;\n\n    private long                        period;\n    private Set<String>                 persistTasks;\n\n    @SuppressWarnings(\"serial\")\n    private final LogPosition           nullPosition = new LogPosition() {\n                                                     };\n\n    public PeriodMixedLogPositionManager(MemoryLogPositionManager memoryLogPositionManager,\n                                         ZooKeeperLogPositionManager zooKeeperLogPositionManager, long period){\n        if (memoryLogPositionManager == null) {\n            throw new NullPointerException(\"null memoryLogPositionManager\");\n        }\n\n        if (zooKeeperLogPositionManager == null) {\n            throw new NullPointerException(\"null zooKeeperLogPositionManager\");\n        }\n\n        if (period <= 0) {\n            throw new IllegalArgumentException(\"period must be positive, given: \" + period);\n        }\n\n        this.memoryLogPositionManager = memoryLogPositionManager;\n        this.zooKeeperLogPositionManager = zooKeeperLogPositionManager;\n        this.period = period;\n        this.persistTasks = Collections.synchronizedSet(new HashSet<>());\n        this.executorService = Executors.newScheduledThreadPool(1);\n    }\n\n    @Override\n    public void stop() {\n        super.stop();\n\n        if (zooKeeperLogPositionManager.isStart()) {\n            zooKeeperLogPositionManager.stop();\n        }\n\n        if (memoryLogPositionManager.isStart()) {\n            memoryLogPositionManager.stop();\n        }\n\n        executorService.shutdown();\n    }\n\n    @Override\n    public void start() {\n        super.start();\n\n        if (!memoryLogPositionManager.isStart()) {\n            memoryLogPositionManager.start();\n        }\n\n        if (!zooKeeperLogPositionManager.isStart()) {\n            zooKeeperLogPositionManager.start();\n        }\n\n        // 启动定时工作任务\n        executorService.scheduleAtFixedRate(() -> {\n            List<String> tasks = new ArrayList<>(persistTasks);\n            for (String destination : tasks) {\n                try {\n                    // 定时将内存中的最新值刷到zookeeper中，多次变更只刷一次\n                    zooKeeperLogPositionManager.persistLogPosition(destination, getLatestIndexBy(destination));\n                    persistTasks.remove(destination);\n                } catch (Throwable e) {\n                    // ignore\n                    logger.error(\"period update\" + destination + \" curosr failed!\", e);\n                }\n            }\n        }, period, period, TimeUnit.MILLISECONDS);\n    }\n\n    @Override\n    public LogPosition getLatestIndexBy(String destination) {\n        LogPosition logPosition = memoryLogPositionManager.getLatestIndexBy(destination);\n        if (logPosition == nullPosition) {\n            return null;\n        } else {\n            return logPosition;\n        }\n    }\n\n    @Override\n    public void persistLogPosition(String destination, LogPosition logPosition) throws CanalParseException {\n        persistTasks.add(destination);\n        memoryLogPositionManager.persistLogPosition(destination, logPosition);\n    }\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/index/ZooKeeperLogPositionManager.java",
    "content": "package com.alibaba.otter.canal.parse.index;\n\nimport org.I0Itec.zkclient.exception.ZkNoNodeException;\n\nimport com.alibaba.otter.canal.common.utils.JsonUtils;\nimport com.alibaba.otter.canal.common.zookeeper.ZkClientx;\nimport com.alibaba.otter.canal.common.zookeeper.ZookeeperPathUtils;\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\n\n/**\n * Created by yinxiu on 17/3/17. Email: marklin.hz@gmail.com\n */\npublic class ZooKeeperLogPositionManager extends AbstractLogPositionManager {\n\n    private final ZkClientx zkClientx;\n\n    public ZooKeeperLogPositionManager(ZkClientx zkClient){\n        if (zkClient == null) {\n            throw new NullPointerException(\"null zkClient\");\n        }\n\n        this.zkClientx = zkClient;\n    }\n\n    @Override\n    public LogPosition getLatestIndexBy(String destination) {\n        String path = ZookeeperPathUtils.getParsePath(destination);\n        byte[] data = zkClientx.readData(path, true);\n        if (data == null || data.length == 0) {\n            return null;\n        }\n\n        return JsonUtils.unmarshalFromByte(data, LogPosition.class);\n    }\n\n    @Override\n    public void persistLogPosition(String destination, LogPosition logPosition) throws CanalParseException {\n        String path = ZookeeperPathUtils.getParsePath(destination);\n        byte[] data = JsonUtils.marshalToByte(logPosition);\n        try {\n            zkClientx.writeData(path, data);\n        } catch (ZkNoNodeException e) {\n            zkClientx.createPersistent(path, data, true);\n        }\n    }\n\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/support/AuthenticationInfo.java",
    "content": "package com.alibaba.otter.canal.parse.support;\n\nimport java.net.InetSocketAddress;\n\nimport org.apache.commons.lang.builder.ToStringBuilder;\nimport org.apache.commons.lang.builder.ToStringStyle;\n\nimport com.alibaba.otter.canal.common.utils.CommonUtils;\nimport com.alibaba.otter.canal.parse.driver.mysql.ssl.SslInfo;\n\n/**\n * 数据库认证信息\n *\n * @author jianghang 2012-7-11 上午11:22:19\n * @version 1.0.0\n */\npublic class AuthenticationInfo {\n\n    private InetSocketAddress address;            // 主库信息\n    private String            username;           // 帐号\n    private String            password;           // 密码\n    private String            defaultDatabaseName;// 默认链接的数据库\n    private String            pwdPublicKey;       // 公钥\n    private boolean           enableDruid;        // 是否使用druid加密解密数据库密码\n    private SslInfo           sslInfo;\n\n    public void initPwd() throws Exception {\n        if (enableDruid) {\n            this.password = CommonUtils.decryptDruidPassword(pwdPublicKey, password);\n        }\n    }\n\n    public AuthenticationInfo(){\n        super();\n    }\n\n    public AuthenticationInfo(InetSocketAddress address, String username, String password){\n        this(address, username, password, \"\");\n    }\n\n    private AuthenticationInfo(InetSocketAddress address, String username, String password, String defaultDatabaseName){\n        this.address = address;\n        this.username = username;\n        this.password = password;\n        this.defaultDatabaseName = defaultDatabaseName;\n    }\n\n    public AuthenticationInfo(InetSocketAddress address, String username, String password, String defaultDatabaseName,\n                              SslInfo sslInfo){\n        this(address, username, password, defaultDatabaseName);\n        this.sslInfo = sslInfo;\n    }\n\n    public InetSocketAddress getAddress() {\n        return address;\n    }\n\n    public void setAddress(InetSocketAddress address) {\n        this.address = address;\n    }\n\n    public String getUsername() {\n        return username;\n    }\n\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    public String getDefaultDatabaseName() {\n        return defaultDatabaseName;\n    }\n\n    public void setDefaultDatabaseName(String defaultDatabaseName) {\n        this.defaultDatabaseName = defaultDatabaseName;\n    }\n\n    public String getPwdPublicKey() {\n        return pwdPublicKey;\n    }\n\n    public void setPwdPublicKey(String pwdPublicKey) {\n        this.pwdPublicKey = pwdPublicKey;\n    }\n\n    public boolean isEnableDruid() {\n        return enableDruid;\n    }\n\n    public void setEnableDruid(boolean enableDruid) {\n        this.enableDruid = enableDruid;\n    }\n\n    public SslInfo getSslInfo() {\n        return sslInfo;\n    }\n\n    public void setSslInfo(SslInfo sslInfo) {\n        this.sslInfo = sslInfo;\n    }\n\n    @Override\n    public String toString() {\n        return ToStringBuilder.reflectionToString(this, ToStringStyle.DEFAULT_STYLE);\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + ((address == null) ? 0 : address.hashCode());\n        result = prime * result + ((defaultDatabaseName == null) ? 0 : defaultDatabaseName.hashCode());\n        result = prime * result + ((password == null) ? 0 : password.hashCode());\n        result = prime * result + ((username == null) ? 0 : username.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (!(obj instanceof AuthenticationInfo)) {\n            return false;\n        }\n        AuthenticationInfo other = (AuthenticationInfo) obj;\n        if (address == null) {\n            if (other.address != null) {\n                return false;\n            }\n        } else if (!address.equals(other.address)) {\n            return false;\n        }\n        if (defaultDatabaseName == null) {\n            if (other.defaultDatabaseName != null) {\n                return false;\n            }\n        } else if (!defaultDatabaseName.equals(other.defaultDatabaseName)) {\n            return false;\n        }\n        if (password == null) {\n            if (other.password != null) {\n                return false;\n            }\n        } else if (!password.equals(other.password)) {\n            return false;\n        }\n        if (username == null) {\n            if (other.username != null) {\n                return false;\n            }\n        } else if (!username.equals(other.username)) {\n            return false;\n        }\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "parse/src/main/java/com/alibaba/otter/canal/parse/support/HaAuthenticationInfo.java",
    "content": "package com.alibaba.otter.canal.parse.support;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\n\n/**\n * @author zebin.xuzb 2012-9-26 下午3:08:11\n * @version 1.0.0\n */\npublic class HaAuthenticationInfo {\n\n    private AuthenticationInfo       master;\n    private List<AuthenticationInfo> slavers = new ArrayList<>();\n\n    public AuthenticationInfo getMaster() {\n        return master;\n    }\n\n    public void setMaster(AuthenticationInfo master) {\n        this.master = master;\n    }\n\n    public List<AuthenticationInfo> getSlavers() {\n        return slavers;\n    }\n\n    public void addSlaver(AuthenticationInfo slaver) {\n        this.slavers.add(slaver);\n    }\n\n    public void addSlavers(Collection<AuthenticationInfo> slavers) {\n        this.slavers.addAll(slavers);\n    }\n\n}\n"
  },
  {
    "path": "parse/src/main/resources/ddl/derby/meta_history.sql",
    "content": "CREATE TABLE meta_history (\n  id bigint GENERATED ALWAYS AS IDENTITY NOT NULL,\n  gmt_create timestamp NOT NULL,\n  gmt_modified timestamp NOT NULL,\n  destination varchar(128) DEFAULT NULL,\n  binlog_file varchar(64) DEFAULT NULL,\n  binlog_offest bigint DEFAULT NULL,\n  binlog_master_id varchar(64) DEFAULT NULL,\n  binlog_timestamp bigint DEFAULT NULL,\n  use_schema varchar(1024) DEFAULT NULL,\n  sql_schema varchar(1024) DEFAULT NULL,\n  sql_table varchar(1024) DEFAULT NULL,\n  sql_text clob(16 M) DEFAULT NULL,\n  sql_type varchar(1024) DEFAULT NULL,\n  extra varchar(512) DEFAULT NULL,\n  PRIMARY KEY (id),\n  CONSTRAINT meta_history_binlog_file_offest UNIQUE (destination,binlog_master_id,binlog_file,binlog_offest)\n);\n\ncreate index meta_history_destination on meta_history(destination);\ncreate index meta_history_destination_timestamp on meta_history(destination,binlog_timestamp);\ncreate index meta_history_gmt_modified on meta_history(gmt_modified);"
  },
  {
    "path": "parse/src/main/resources/ddl/derby/meta_snapshot.sql",
    "content": "CREATE TABLE meta_snapshot (\n  id bigint GENERATED ALWAYS AS IDENTITY NOT NULL,\n  gmt_create timestamp NOT NULL,\n  gmt_modified timestamp NOT NULL,\n  destination varchar(128) DEFAULT NULL,\n  binlog_file varchar(64) DEFAULT NULL,\n  binlog_offest bigint DEFAULT NULL,\n  binlog_master_id varchar(64) DEFAULT NULL,\n  binlog_timestamp bigint DEFAULT NULL,\n  data clob(16 M) DEFAULT NULL,\n  extra varchar(512) DEFAULT NULL,\n  PRIMARY KEY (id),\n  CONSTRAINT meta_snapshot_binlog_file_offest UNIQUE (destination,binlog_master_id,binlog_file,binlog_offest)\n);\n\ncreate index meta_snapshot_destination on meta_snapshot(destination);\ncreate index meta_snapshot_destination_timestamp on meta_snapshot(destination,binlog_timestamp);\ncreate index meta_snapshot_gmt_modified on meta_snapshot(gmt_modified);"
  },
  {
    "path": "parse/src/main/resources/ddl/h2/meta_history.sql",
    "content": "CREATE TABLE IF NOT EXISTS `meta_history` (\n  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',\n  `gmt_create` datetime NOT NULL COMMENT '创建时间',\n  `gmt_modified` datetime NOT NULL COMMENT '修改时间',\n  `destination` varchar(128) DEFAULT NULL COMMENT '通道名称',\n  `binlog_file` varchar(64) DEFAULT NULL COMMENT 'binlog文件名',\n  `binlog_offest` bigint(20) DEFAULT NULL COMMENT 'binlog偏移量',\n  `binlog_master_id` varchar(64) DEFAULT NULL COMMENT 'binlog节点id',\n  `binlog_timestamp` bigint(20) DEFAULT NULL COMMENT 'binlog应用的时间戳',\n  `use_schema` varchar(1024) DEFAULT NULL COMMENT '执行sql时对应的schema',\n  `sql_schema` varchar(1024) DEFAULT NULL COMMENT '对应的schema',\n  `sql_table` varchar(1024) DEFAULT NULL COMMENT '对应的table',\n  `sql_text` CLOB DEFAULT NULL COMMENT '执行的sql',\n  `sql_type` varchar(256) DEFAULT NULL COMMENT 'sql类型',\n  `extra` text DEFAULT NULL COMMENT '额外的扩展信息',\n  PRIMARY KEY (`id`),\n  UNIQUE KEY meta_history_binlog_file_offest(`destination`,`binlog_master_id`,`binlog_file`,`binlog_offest`),\n  KEY `meta_history_destination` (`destination`),\n  KEY `meta_history_destination_timestamp` (`destination`,`binlog_timestamp`),\n  KEY `meta_history_gmt_modified` (`gmt_modified`)\n);"
  },
  {
    "path": "parse/src/main/resources/ddl/h2/meta_snapshot.sql",
    "content": "CREATE TABLE IF NOT EXISTS `meta_snapshot` (\n  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',\n  `gmt_create` datetime NOT NULL COMMENT '创建时间',\n  `gmt_modified` datetime NOT NULL COMMENT '修改时间',\n  `destination` varchar(128) DEFAULT NULL COMMENT '通道名称',\n  `binlog_file` varchar(64) DEFAULT NULL COMMENT 'binlog文件名',\n  `binlog_offest` bigint(20) DEFAULT NULL COMMENT 'binlog偏移量',\n  `binlog_master_id` varchar(64) DEFAULT NULL COMMENT 'binlog节点id',\n  `binlog_timestamp` bigint(20) DEFAULT NULL COMMENT 'binlog应用的时间戳',\n  `data` CLOB DEFAULT NULL COMMENT '表结构数据',\n  `extra` text DEFAULT NULL COMMENT '额外的扩展信息',\n  PRIMARY KEY (`id`),\n  UNIQUE KEY meta_snapshot_binlog_file_offest(`destination`,`binlog_master_id`,`binlog_file`,`binlog_offest`),\n  KEY `meta_snapshot_destination` (`destination`),\n  KEY `meta_snapshot_destination_timestamp` (`destination`,`binlog_timestamp`),\n  KEY `meta_snapshot_gmt_modified` (`gmt_modified`)\n);"
  },
  {
    "path": "parse/src/main/resources/ddl/mysql/meta_history.sql",
    "content": "CREATE TABLE IF NOT EXISTS `meta_history` (\n  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',\n  `gmt_create` datetime NOT NULL COMMENT '创建时间',\n  `gmt_modified` datetime NOT NULL COMMENT '修改时间',\n  `destination` varchar(128) DEFAULT NULL COMMENT '通道名称',\n  `binlog_file` varchar(64) DEFAULT NULL COMMENT 'binlog文件名',\n  `binlog_offest` bigint(20) DEFAULT NULL COMMENT 'binlog偏移量',\n  `binlog_master_id` varchar(64) DEFAULT NULL COMMENT 'binlog节点id',\n  `binlog_timestamp` bigint(20) DEFAULT NULL COMMENT 'binlog应用的时间戳',\n  `use_schema` varchar(1024) DEFAULT NULL COMMENT '执行sql时对应的schema',\n  `sql_schema` varchar(1024) DEFAULT NULL COMMENT '对应的schema',\n  `sql_table` varchar(1024) DEFAULT NULL COMMENT '对应的table',\n  `sql_text` longtext DEFAULT NULL COMMENT '执行的sql',\n  `sql_type` varchar(256) DEFAULT NULL COMMENT 'sql类型',\n  `extra` text DEFAULT NULL COMMENT '额外的扩展信息',\n  PRIMARY KEY (`id`),\n  UNIQUE KEY binlog_file_offest(`destination`,`binlog_master_id`,`binlog_file`,`binlog_offest`),\n  KEY `destination` (`destination`),\n  KEY `destination_timestamp` (`destination`,`binlog_timestamp`),\n  KEY `gmt_modified` (`gmt_modified`)\n) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='表结构变化明细表';"
  },
  {
    "path": "parse/src/main/resources/ddl/mysql/meta_snapshot.sql",
    "content": "CREATE TABLE IF NOT EXISTS `meta_snapshot` (\n  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',\n  `gmt_create` datetime NOT NULL COMMENT '创建时间',\n  `gmt_modified` datetime NOT NULL COMMENT '修改时间',\n  `destination` varchar(128) DEFAULT NULL COMMENT '通道名称',\n  `binlog_file` varchar(64) DEFAULT NULL COMMENT 'binlog文件名',\n  `binlog_offest` bigint(20) DEFAULT NULL COMMENT 'binlog偏移量',\n  `binlog_master_id` varchar(64) DEFAULT NULL COMMENT 'binlog节点id',\n  `binlog_timestamp` bigint(20) DEFAULT NULL COMMENT 'binlog应用的时间戳',\n  `data` longtext DEFAULT NULL COMMENT '表结构数据',\n  `extra` text DEFAULT NULL COMMENT '额外的扩展信息',\n  PRIMARY KEY (`id`),\n  UNIQUE KEY binlog_file_offest(`destination`,`binlog_master_id`,`binlog_file`,`binlog_offest`),\n  KEY `destination` (`destination`),\n  KEY `destination_timestamp` (`destination`,`binlog_timestamp`),\n  KEY `gmt_modified` (`gmt_modified`)\n) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='表结构记录表快照表';"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/DirectLogFetcherTest.java",
    "content": "package com.alibaba.otter.canal.parse;\n\nimport static com.alibaba.otter.canal.parse.inbound.mysql.dbsync.DirectLogFetcher.MASTER_HEARTBEAT_PERIOD_SECONDS;\n\nimport java.io.IOException;\nimport java.io.Serializable;\nimport java.io.UnsupportedEncodingException;\nimport java.net.InetSocketAddress;\nimport java.nio.charset.Charset;\nimport java.util.BitSet;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.junit.Assert;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.MysqlConnector;\nimport com.alibaba.otter.canal.parse.driver.mysql.MysqlQueryExecutor;\nimport com.alibaba.otter.canal.parse.driver.mysql.MysqlUpdateExecutor;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.HeaderPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.client.BinlogDumpCommandPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.client.RegisterSlaveCommandPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.server.ErrorPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.server.ResultSetPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.PacketManager;\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\nimport com.alibaba.otter.canal.parse.inbound.mysql.dbsync.DirectLogFetcher;\nimport com.taobao.tddl.dbsync.binlog.LogContext;\nimport com.taobao.tddl.dbsync.binlog.LogDecoder;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.*;\nimport com.taobao.tddl.dbsync.binlog.event.TableMapLogEvent.ColumnInfo;\nimport com.taobao.tddl.dbsync.binlog.event.mariadb.AnnotateRowsEvent;\nimport com.taobao.tddl.dbsync.binlog.event.mariadb.BinlogCheckPointLogEvent;\n\n@Ignore\npublic class DirectLogFetcherTest {\n\n    protected final Logger logger         = LoggerFactory.getLogger(this.getClass());\n    protected String       binlogFileName = \"mysql-bin.000001\";\n    protected Charset      charset        = Charset.forName(\"utf-8\");\n    private int            binlogChecksum;\n\n    @Test\n    public void testSimple() {\n        DirectLogFetcher fetcher = new DirectLogFetcher();\n        try {\n            MysqlConnector connector = new MysqlConnector(new InetSocketAddress(\"127.0.0.1\", 3306), \"canal\", \"canal\");\n            connector.connect();\n            updateSettings(connector);\n            loadBinlogChecksum(connector);\n            sendRegisterSlave(connector, 3);\n            sendBinlogDump(connector, \"mysql-bin.000002\", 4L, 3);\n\n            fetcher.start(connector.getChannel());\n\n            LogDecoder decoder = new LogDecoder(LogEvent.UNKNOWN_EVENT, LogEvent.ENUM_END_EVENT);\n            LogContext context = new LogContext();\n            context.setFormatDescription(new FormatDescriptionLogEvent(4, binlogChecksum));\n\n            while (fetcher.fetch()) {\n                LogEvent event = null;\n                event = decoder.decode(fetcher, context);\n\n                if (event == null) {\n                    throw new RuntimeException(\"parse failed\");\n                }\n                processEvent(event, decoder, context);\n            }\n        } catch (Throwable e) {\n            e.printStackTrace();\n            Assert.fail(e.getMessage());\n        } finally {\n            try {\n                fetcher.close();\n            } catch (IOException e) {\n                Assert.fail(e.getMessage());\n            }\n        }\n\n    }\n\n    private void processEvent(LogEvent event, LogDecoder decoder, LogContext context) throws Throwable {\n        int eventType = event.getHeader().getType();\n        switch (eventType) {\n            case LogEvent.ROTATE_EVENT:\n                // binlogFileName = ((RotateLogEvent)\n                // event).getFilename();\n                System.out.println(\"RotateLogEvent : \" + ((RotateLogEvent) event).getFilename());\n                break;\n            case LogEvent.BINLOG_CHECKPOINT_EVENT:\n                // binlogFileName = ((BinlogCheckPointLogEvent)\n                // event).getFilename();\n                System.out.println(\"BinlogCheckPointLogEvent : \" + ((BinlogCheckPointLogEvent) event).getFilename());\n                break;\n            case LogEvent.TABLE_MAP_EVENT:\n                parseTableMapEvent((TableMapLogEvent) event);\n                break;\n            case LogEvent.WRITE_ROWS_EVENT_V1:\n            case LogEvent.WRITE_ROWS_EVENT:\n                parseRowsEvent((WriteRowsLogEvent) event);\n                break;\n            case LogEvent.UPDATE_ROWS_EVENT_V1:\n            case LogEvent.PARTIAL_UPDATE_ROWS_EVENT:\n            case LogEvent.UPDATE_ROWS_EVENT:\n                parseRowsEvent((UpdateRowsLogEvent) event);\n                break;\n            case LogEvent.DELETE_ROWS_EVENT_V1:\n            case LogEvent.DELETE_ROWS_EVENT:\n                parseRowsEvent((DeleteRowsLogEvent) event);\n                break;\n            case LogEvent.QUERY_EVENT:\n                parseQueryEvent((QueryLogEvent) event);\n                break;\n            case LogEvent.ROWS_QUERY_LOG_EVENT:\n                parseRowsQueryEvent((RowsQueryLogEvent) event);\n                break;\n            case LogEvent.ANNOTATE_ROWS_EVENT:\n                break;\n            case LogEvent.XID_EVENT:\n                break;\n            case LogEvent.TRANSACTION_PAYLOAD_EVENT:\n                List<LogEvent> events = decoder.processIterateDecode(event, context);\n                for (LogEvent deEvent : events) {\n                    processEvent(deEvent, decoder, context);\n                }\n                break;\n            default:\n                break;\n        }\n    }\n\n    private void sendRegisterSlave(MysqlConnector connector, int slaveId) throws IOException {\n        RegisterSlaveCommandPacket cmd = new RegisterSlaveCommandPacket();\n        cmd.reportHost = connector.getAddress().getAddress().getHostAddress();\n        cmd.reportPasswd = connector.getPassword();\n        cmd.reportUser = connector.getUsername();\n        cmd.serverId = slaveId;\n        byte[] cmdBody = cmd.toBytes();\n\n        HeaderPacket header = new HeaderPacket();\n        header.setPacketBodyLength(cmdBody.length);\n        header.setPacketSequenceNumber((byte) 0x00);\n        PacketManager.writePkg(connector.getChannel(), header.toBytes(), cmdBody);\n\n        header = PacketManager.readHeader(connector.getChannel(), 4);\n        byte[] body = PacketManager.readBytes(connector.getChannel(), header.getPacketBodyLength());\n        assert body != null;\n        if (body[0] < 0) {\n            if (body[0] == -1) {\n                ErrorPacket err = new ErrorPacket();\n                err.fromBytes(body);\n                throw new IOException(\"Error When doing Register slave:\" + err.toString());\n            } else {\n                throw new IOException(\"Unexpected packet with field_count=\" + body[0]);\n            }\n        }\n    }\n\n    private void sendBinlogDump(MysqlConnector connector, String binlogfilename, Long binlogPosition, int slaveId)\n                                                                                                                  throws IOException {\n        BinlogDumpCommandPacket binlogDumpCmd = new BinlogDumpCommandPacket();\n        binlogDumpCmd.binlogFileName = binlogfilename;\n        binlogDumpCmd.binlogPosition = binlogPosition;\n        binlogDumpCmd.slaveServerId = slaveId;\n        byte[] cmdBody = binlogDumpCmd.toBytes();\n\n        HeaderPacket binlogDumpHeader = new HeaderPacket();\n        binlogDumpHeader.setPacketBodyLength(cmdBody.length);\n        binlogDumpHeader.setPacketSequenceNumber((byte) 0x00);\n        PacketManager.writePkg(connector.getChannel(), binlogDumpHeader.toBytes(), cmdBody);\n    }\n\n    private void updateSettings(MysqlConnector connector) throws IOException {\n        try {\n            update(\"set wait_timeout=9999999\", connector);\n        } catch (Exception e) {\n            logger.warn(\"update wait_timeout failed\", e);\n        }\n        try {\n            update(\"set net_write_timeout=7200\", connector);\n        } catch (Exception e) {\n            logger.warn(\"update net_write_timeout failed\", e);\n        }\n\n        try {\n            update(\"set net_read_timeout=7200\", connector);\n        } catch (Exception e) {\n            logger.warn(\"update net_read_timeout failed\", e);\n        }\n\n        try {\n            // 设置服务端返回结果时不做编码转化，直接按照数据库的二进制编码进行发送，由客户端自己根据需求进行编码转化\n            update(\"set names 'binary'\", connector);\n        } catch (Exception e) {\n            logger.warn(\"update names failed\", e);\n        }\n\n        try {\n            // mysql5.6针对checksum支持需要设置session变量\n            // 如果不设置会出现错误： Slave can not handle replication events with the\n            // checksum that master is configured to log\n            // 但也不能乱设置，需要和mysql server的checksum配置一致，不然RotateLogEvent会出现乱码\n            update(\"set @master_binlog_checksum= @@global.binlog_checksum\", connector);\n        } catch (Exception e) {\n            logger.warn(\"update master_binlog_checksum failed\", e);\n        }\n\n        try {\n            // 参考:https://github.com/alibaba/canal/issues/284\n            // mysql5.6需要设置slave_uuid避免被server kill链接\n            update(\"set @slave_uuid=uuid()\", connector);\n        } catch (Exception e) {\n            if (!StringUtils.contains(e.getMessage(), \"Unknown system variable\")\n                && !StringUtils.contains(e.getMessage(), \"slave_uuid can't be set\")) {\n                logger.warn(\"update slave_uuid failed\", e);\n            }\n        }\n\n        try {\n            // mariadb针对特殊的类型，需要设置session变量\n            update(\"SET @mariadb_slave_capability='\" + LogEvent.MARIA_SLAVE_CAPABILITY_MINE + \"'\", connector);\n        } catch (Exception e) {\n            logger.warn(\"update mariadb_slave_capability failed\", e);\n        }\n\n        try {\n            long period = TimeUnit.SECONDS.toNanos(MASTER_HEARTBEAT_PERIOD_SECONDS);\n            update(\"SET @master_heartbeat_period=\" + period, connector);\n        } catch (Exception e) {\n            logger.warn(\"update master_heartbeat_period failed\", e);\n        }\n    }\n\n    private void loadBinlogChecksum(MysqlConnector connector) {\n        ResultSetPacket rs = null;\n        try {\n            rs = query(\"select @@global.binlog_checksum\", connector);\n        } catch (IOException e) {\n            throw new CanalParseException(e);\n        }\n\n        List<String> columnValues = rs.getFieldValues();\n        if (columnValues != null && columnValues.size() >= 1 && columnValues.get(0).toUpperCase().equals(\"CRC32\")) {\n            binlogChecksum = LogEvent.BINLOG_CHECKSUM_ALG_CRC32;\n        } else {\n            binlogChecksum = LogEvent.BINLOG_CHECKSUM_ALG_OFF;\n        }\n    }\n\n    public ResultSetPacket query(String cmd, MysqlConnector connector) throws IOException {\n        MysqlQueryExecutor exector = new MysqlQueryExecutor(connector);\n        return exector.query(cmd);\n    }\n\n    public void update(String cmd, MysqlConnector connector) throws IOException {\n        MysqlUpdateExecutor exector = new MysqlUpdateExecutor(connector);\n        exector.update(cmd);\n    }\n\n    protected void parseQueryEvent(QueryLogEvent event) {\n        System.out.println(String.format(\"================> binlog[%s:%s] , name[%s]\",\n            binlogFileName,\n            event.getHeader().getLogPos() - event.getHeader().getEventLen(),\n            event.getCatalog()));\n        System.out.println(\"sql : \" + event.getQuery());\n    }\n\n    protected void parseRowsQueryEvent(RowsQueryLogEvent event) throws Exception {\n        System.out.println(String.format(\"================> binlog[%s:%s]\", binlogFileName, event.getHeader()\n            .getLogPos() - event.getHeader().getEventLen()));\n        System.out.println(\"sql : \" + new String(event.getRowsQuery().getBytes(\"ISO-8859-1\"), charset.name()));\n    }\n\n    protected void parseAnnotateRowsEvent(AnnotateRowsEvent event) throws Exception {\n        System.out.println(String.format(\"================> binlog[%s:%s]\", binlogFileName, event.getHeader()\n            .getLogPos() - event.getHeader().getEventLen()));\n        System.out.println(\"sql : \" + new String(event.getRowsQuery().getBytes(\"ISO-8859-1\"), charset.name()));\n    }\n\n    public void parseTableMapEvent(TableMapLogEvent event) {\n        try {\n            String charsetDbName = new String(event.getDbName().getBytes(\"ISO-8859-1\"), charset.name());\n            event.setDbname(charsetDbName);\n\n            String charsetTbName = new String(event.getTableName().getBytes(\"ISO-8859-1\"), charset.name());\n            event.setTblname(charsetTbName);\n        } catch (UnsupportedEncodingException e) {\n            throw new CanalParseException(e);\n        }\n    }\n\n    protected void parseXidEvent(XidLogEvent event) throws Exception {\n        System.out.println(String.format(\"================> binlog[%s:%s]\", binlogFileName, event.getHeader()\n            .getLogPos() - event.getHeader().getEventLen()));\n        System.out.println(\"xid : \" + event.getXid());\n    }\n\n    protected void parseRowsEvent(RowsLogEvent event) {\n        try {\n            System.out.println(String.format(\"================> binlog[%s:%s] , name[%s,%s]\",\n                binlogFileName,\n                event.getHeader().getLogPos() - event.getHeader().getEventLen(),\n                event.getTable().getDbName(),\n                event.getTable().getTableName()));\n            RowsLogBuffer buffer = event.getRowsBuf(charset);\n            BitSet columns = event.getColumns();\n            BitSet changeColumns = event.getChangeColumns();\n            while (buffer.nextOneRow(columns)) {\n                // 处理row记录\n                int type = event.getHeader().getType();\n                if (LogEvent.WRITE_ROWS_EVENT_V1 == type || LogEvent.WRITE_ROWS_EVENT == type) {\n                    // insert的记录放在before字段中\n                    parseOneRow(event, buffer, columns, true);\n                } else if (LogEvent.DELETE_ROWS_EVENT_V1 == type || LogEvent.DELETE_ROWS_EVENT == type) {\n                    // delete的记录放在before字段中\n                    parseOneRow(event, buffer, columns, false);\n                } else {\n                    // update需要处理before/after\n                    System.out.println(\"-------> before\");\n                    parseOneRow(event, buffer, columns, false);\n                    if (!buffer.nextOneRow(changeColumns, true)) {\n                        break;\n                    }\n                    System.out.println(\"-------> after\");\n                    parseOneRow(event, buffer, changeColumns, true);\n                }\n\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(\"parse row data failed.\", e);\n        }\n    }\n\n    protected void parseOneRow(RowsLogEvent event, RowsLogBuffer buffer, BitSet cols, boolean isAfter)\n                                                                                                      throws UnsupportedEncodingException {\n        TableMapLogEvent map = event.getTable();\n        if (map == null) {\n            throw new RuntimeException(\"not found TableMap with tid=\" + event.getTableId());\n        }\n\n        final int columnCnt = map.getColumnCnt();\n        final ColumnInfo[] columnInfo = map.getColumnInfo();\n\n        for (int i = 0; i < columnCnt; i++) {\n            if (!cols.get(i)) {\n                continue;\n            }\n\n            ColumnInfo info = columnInfo[i];\n            buffer.nextValue(null, i, info.type, info.meta);\n\n            if (buffer.isNull()) {\n                //\n            } else {\n                final Serializable value = buffer.getValue();\n                if (value instanceof byte[]) {\n                    System.out.println(new String((byte[]) value));\n                } else {\n                    System.out.println(value);\n                }\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/MysqlBinlogDumpPerformanceTest.java",
    "content": "package com.alibaba.otter.canal.parse;\n\nimport java.net.InetSocketAddress;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.junit.Ignore;\n\nimport com.alibaba.otter.canal.common.AbstractCanalLifeCycle;\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\nimport com.alibaba.otter.canal.parse.inbound.mysql.MysqlEventParser;\nimport com.alibaba.otter.canal.parse.index.AbstractLogPositionManager;\nimport com.alibaba.otter.canal.parse.support.AuthenticationInfo;\nimport com.alibaba.otter.canal.protocol.CanalEntry;\nimport com.alibaba.otter.canal.protocol.position.EntryPosition;\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\nimport com.alibaba.otter.canal.sink.CanalEventSink;\nimport com.alibaba.otter.canal.sink.exception.CanalSinkException;\n\n@Ignore\npublic class MysqlBinlogDumpPerformanceTest {\n\n    public static void main(String args[]) {\n        final MysqlEventParser controller = new MysqlEventParser();\n        final EntryPosition startPosition = new EntryPosition(\"binlog.000002\", 4L, 100L);\n        controller.setConnectionCharset(\"UTF-8\");\n        controller.setSlaveId(3344L);\n        controller.setDetectingEnable(false);\n        controller.setFilterQueryDml(true);\n        controller.setMasterInfo(new AuthenticationInfo(new InetSocketAddress(\"127.0.0.1\", 3306), \"canal\", \"canal\"));\n        controller.setMasterPosition(startPosition);\n        controller.setEnableTsdb(false);\n        controller.setDestination(\"example\");\n        controller.setTsdbSpringXml(\"classpath:spring/tsdb/h2-tsdb.xml\");\n        // controller.setEventFilter(new AviaterRegexFilter(\"test\\\\..*\"));\n        // controller.setEventBlackFilter(new\n        // AviaterRegexFilter(\"canal_tsdb\\\\..*\"));\n        controller.setParallel(true);\n        controller.setParallelBufferSize(256);\n        controller.setParallelThreadSize(16);\n        controller.setIsGTIDMode(false);\n        final AtomicLong sum = new AtomicLong(0);\n        final AtomicLong last = new AtomicLong(0);\n        final AtomicLong start = new AtomicLong(System.currentTimeMillis());\n        final AtomicLong end = new AtomicLong(0);\n        controller.setEventSink(new AbstractCanalEventSinkTest<List<CanalEntry.Entry>>() {\n\n            public boolean sink(List<CanalEntry.Entry> entrys, InetSocketAddress remoteAddress, String destination)\n                                                                                                                   throws CanalSinkException,\n                                                                                                                   InterruptedException {\n\n                sum.addAndGet(entrys.size());\n                long current = sum.get();\n                if (current - last.get() >= 100000) {\n                    end.set(System.currentTimeMillis());\n                    long tps = ((current - last.get()) * 1000) / (end.get() - start.get());\n                    System.out.println(\" total : \" + sum + \" , cost : \" + (end.get() - start.get()) + \" , tps : \" + tps);\n                    last.set(current);\n                    start.set(end.get());\n                }\n                return true;\n            }\n\n        });\n        controller.setLogPositionManager(new AbstractLogPositionManager() {\n\n            @Override\n            public LogPosition getLatestIndexBy(String destination) {\n                return null;\n            }\n\n            @Override\n            public void persistLogPosition(String destination, LogPosition logPosition) throws CanalParseException {\n            }\n        });\n\n        controller.start();\n\n        try {\n            Thread.sleep(100 * 1000 * 1000L);\n        } catch (InterruptedException e) {\n        }\n        controller.stop();\n    }\n\n    public static abstract class AbstractCanalEventSinkTest<T> extends AbstractCanalLifeCycle implements CanalEventSink<T> {\n\n        public void interrupt() {\n        }\n    }\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/MysqlBinlogEventPerformanceTest.java",
    "content": "package com.alibaba.otter.canal.parse;\n\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.nio.charset.Charset;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.MysqlConnector;\nimport com.alibaba.otter.canal.parse.driver.mysql.MysqlUpdateExecutor;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.HeaderPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.client.BinlogDumpCommandPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.PacketManager;\nimport com.alibaba.otter.canal.parse.inbound.mysql.dbsync.DirectLogFetcher;\nimport com.taobao.tddl.dbsync.binlog.LogContext;\nimport com.taobao.tddl.dbsync.binlog.LogDecoder;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\nimport org.junit.Ignore;\n\n@Ignore\npublic class MysqlBinlogEventPerformanceTest {\n\n    protected static Charset charset = Charset.forName(\"utf-8\");\n\n    public static void main(String args[]) {\n        try (DirectLogFetcher fetcher = new DirectLogFetcher()) {\n            MysqlConnector connector = new MysqlConnector(new InetSocketAddress(\"127.0.0.1\", 3306), \"root\", \"hello\");\n            connector.connect();\n            updateSettings(connector);\n            sendBinlogDump(connector, \"mysql-bin.000006\", 120L, 3);\n            fetcher.start(connector.getChannel());\n            LogDecoder decoder = new LogDecoder(LogEvent.UNKNOWN_EVENT, LogEvent.ENUM_END_EVENT);\n            LogContext context = new LogContext();\n            AtomicLong sum = new AtomicLong(0);\n            long start = System.currentTimeMillis();\n            long last = 0;\n            long end = 0;\n            while (fetcher.fetch()) {\n                decoder.decode(fetcher, context);\n                sum.incrementAndGet();\n                long current = sum.get();\n                if (current - last >= 100000) {\n                    end = System.currentTimeMillis();\n                    long tps = ((current - last) * 1000) / (end - start);\n                    System.out.println(\" total : \" + sum + \" , cost : \" + (end - start) + \" , tps : \" + tps);\n                    last = current;\n                    start = end;\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    private static void sendBinlogDump(MysqlConnector connector, String binlogfilename, Long binlogPosition, int slaveId)\n                                                                                                                         throws IOException {\n        BinlogDumpCommandPacket binlogDumpCmd = new BinlogDumpCommandPacket();\n        binlogDumpCmd.binlogFileName = binlogfilename;\n        binlogDumpCmd.binlogPosition = binlogPosition;\n        binlogDumpCmd.slaveServerId = slaveId;\n        byte[] cmdBody = binlogDumpCmd.toBytes();\n\n        HeaderPacket binlogDumpHeader = new HeaderPacket();\n        binlogDumpHeader.setPacketBodyLength(cmdBody.length);\n        binlogDumpHeader.setPacketSequenceNumber((byte) 0x00);\n        PacketManager.writePkg(connector.getChannel(), binlogDumpHeader.toBytes(), cmdBody);\n    }\n\n    private static void updateSettings(MysqlConnector connector) throws IOException {\n        update(\"set @master_binlog_checksum= '@@global.binlog_checksum'\", connector);\n        update(\"SET @mariadb_slave_capability='\" + LogEvent.MARIA_SLAVE_CAPABILITY_MINE + \"'\", connector);\n    }\n\n    public static void update(String cmd, MysqlConnector connector) throws IOException {\n        MysqlUpdateExecutor exector = new MysqlUpdateExecutor(connector);\n        exector.update(cmd);\n    }\n\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/MysqlBinlogParsePerformanceTest.java",
    "content": "package com.alibaba.otter.canal.parse;\n\nimport java.io.IOException;\nimport java.io.UnsupportedEncodingException;\nimport java.net.InetSocketAddress;\nimport java.nio.charset.Charset;\nimport java.util.BitSet;\nimport java.util.List;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.junit.Ignore;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.MysqlConnector;\nimport com.alibaba.otter.canal.parse.driver.mysql.MysqlUpdateExecutor;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.HeaderPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.client.BinlogDumpCommandPacket;\nimport com.alibaba.otter.canal.parse.driver.mysql.utils.PacketManager;\nimport com.alibaba.otter.canal.parse.inbound.mysql.dbsync.DirectLogFetcher;\nimport com.taobao.tddl.dbsync.binlog.LogBuffer;\nimport com.taobao.tddl.dbsync.binlog.LogContext;\nimport com.taobao.tddl.dbsync.binlog.LogDecoder;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\nimport com.taobao.tddl.dbsync.binlog.event.*;\nimport com.taobao.tddl.dbsync.binlog.event.TableMapLogEvent.ColumnInfo;\n\n@Ignore\npublic class MysqlBinlogParsePerformanceTest {\n\n    protected static Charset charset = Charset.forName(\"utf-8\");\n\n    public static void main(String args[]) {\n        try (DirectLogFetcher fetcher = new DirectLogFetcher()) {\n            MysqlConnector connector = new MysqlConnector(new InetSocketAddress(\"127.0.0.1\", 3306), \"root\", \"hello\");\n            connector.connect();\n            updateSettings(connector);\n            sendBinlogDump(connector, \"mysql-bin.000006\", 120L, 3);\n            fetcher.start(connector.getChannel());\n            final BlockingQueue<LogBuffer> buffer = new ArrayBlockingQueue<>(1024);\n            Thread thread = new Thread(() -> {\n                try {\n                    consumer(buffer);\n                } catch (Throwable e) {\n                    e.printStackTrace();\n                }\n            });\n            thread.start();\n\n            while (fetcher.fetch()) {\n                buffer.put(fetcher.duplicate());\n                fetcher.consume(fetcher.limit());\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    public static void consumer(BlockingQueue<LogBuffer> buffer) throws Throwable {\n        LogDecoder decoder = new LogDecoder(LogEvent.UNKNOWN_EVENT, LogEvent.ENUM_END_EVENT);\n        LogContext context = new LogContext();\n\n        AtomicLong sum = new AtomicLong(0);\n        long start = System.currentTimeMillis();\n        long last = 0;\n        long end = 0;\n        while (true) {\n            LogEvent event = null;\n            event = decoder.decode(buffer.take(), context);\n            processEvent(event, decoder, context, sum);\n            long current = sum.get();\n            if (current - last >= 100000) {\n                end = System.currentTimeMillis();\n                long tps = ((current - last) * 1000) / (end - start);\n                System.out.println(\" total : \" + sum + \" , cost : \" + (end - start) + \" , tps : \" + tps);\n                last = current;\n                start = end;\n            }\n        }\n    }\n\n    private static void processEvent(LogEvent event, LogDecoder decoder, LogContext context, AtomicLong sum) throws Throwable {\n        int eventType = event.getHeader().getType();\n        switch (eventType) {\n            case LogEvent.ROTATE_EVENT:\n                break;\n            case LogEvent.WRITE_ROWS_EVENT_V1:\n            case LogEvent.WRITE_ROWS_EVENT:\n                parseRowsEvent((WriteRowsLogEvent) event, sum);\n                break;\n            case LogEvent.UPDATE_ROWS_EVENT_V1:\n            case LogEvent.PARTIAL_UPDATE_ROWS_EVENT:\n            case LogEvent.UPDATE_ROWS_EVENT:\n                parseRowsEvent((UpdateRowsLogEvent) event, sum);\n                break;\n            case LogEvent.DELETE_ROWS_EVENT_V1:\n            case LogEvent.DELETE_ROWS_EVENT:\n                parseRowsEvent((DeleteRowsLogEvent) event, sum);\n                break;\n            case LogEvent.XID_EVENT:\n                sum.incrementAndGet();\n                break;\n            case LogEvent.QUERY_EVENT:\n                sum.incrementAndGet();\n                break;\n            case LogEvent.TRANSACTION_PAYLOAD_EVENT:\n                List<LogEvent> events = decoder.processIterateDecode(event, context);\n                for (LogEvent deEvent : events) {\n                    processEvent(deEvent, decoder, context, sum);\n                }\n                break;\n            default:\n                break;\n        }\n    }\n\n    private static void sendBinlogDump(MysqlConnector connector, String binlogfilename, Long binlogPosition, int slaveId)\n                                                                                                                         throws IOException {\n        BinlogDumpCommandPacket binlogDumpCmd = new BinlogDumpCommandPacket();\n        binlogDumpCmd.binlogFileName = binlogfilename;\n        binlogDumpCmd.binlogPosition = binlogPosition;\n        binlogDumpCmd.slaveServerId = slaveId;\n        byte[] cmdBody = binlogDumpCmd.toBytes();\n\n        HeaderPacket binlogDumpHeader = new HeaderPacket();\n        binlogDumpHeader.setPacketBodyLength(cmdBody.length);\n        binlogDumpHeader.setPacketSequenceNumber((byte) 0x00);\n        PacketManager.writePkg(connector.getChannel(), binlogDumpHeader.toBytes(), cmdBody);\n    }\n\n    private static void updateSettings(MysqlConnector connector) throws IOException {\n        update(\"set @master_binlog_checksum= '@@global.binlog_checksum'\", connector);\n        update(\"SET @mariadb_slave_capability='\" + LogEvent.MARIA_SLAVE_CAPABILITY_MINE + \"'\", connector);\n    }\n\n    public static void update(String cmd, MysqlConnector connector) throws IOException {\n        MysqlUpdateExecutor exector = new MysqlUpdateExecutor(connector);\n        exector.update(cmd);\n    }\n\n    public static void parseRowsEvent(RowsLogEvent event, AtomicLong sum) {\n        try {\n            RowsLogBuffer buffer = event.getRowsBuf(charset);\n            BitSet columns = event.getColumns();\n            BitSet changeColumns = event.getChangeColumns();\n            while (buffer.nextOneRow(columns)) {\n                int type = event.getHeader().getType();\n                if (LogEvent.WRITE_ROWS_EVENT_V1 == type || LogEvent.WRITE_ROWS_EVENT == type) {\n                    parseOneRow(event, buffer, columns, true);\n                } else if (LogEvent.DELETE_ROWS_EVENT_V1 == type || LogEvent.DELETE_ROWS_EVENT == type) {\n                    parseOneRow(event, buffer, columns, false);\n                } else {\n                    parseOneRow(event, buffer, columns, false);\n                    if (!buffer.nextOneRow(changeColumns, true)) {\n                        break;\n                    }\n                    parseOneRow(event, buffer, changeColumns, true);\n                }\n\n                sum.incrementAndGet();\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(\"parse row data failed.\", e);\n        }\n    }\n\n    public static void parseOneRow(RowsLogEvent event, RowsLogBuffer buffer, BitSet cols, boolean isAfter)\n                                                                                                          throws UnsupportedEncodingException {\n        TableMapLogEvent map = event.getTable();\n        if (map == null) {\n            throw new RuntimeException(\"not found TableMap with tid=\" + event.getTableId());\n        }\n\n        final int columnCnt = map.getColumnCnt();\n        final ColumnInfo[] columnInfo = map.getColumnInfo();\n        for (int i = 0; i < columnCnt; i++) {\n            if (!cols.get(i)) {\n                continue;\n            }\n\n            ColumnInfo info = columnInfo[i];\n            buffer.nextValue(null, i, info.type, info.meta);\n            if (buffer.isNull()) {\n            } else {\n                buffer.getValue();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/helper/TimeoutChecker.java",
    "content": "package com.alibaba.otter.canal.parse.helper;\r\n\r\n/**\r\n * 用于检查超时, 主要用于启动服务以后，如果在指定的时间内没有响应，则自动退出\r\n * \r\n * @author: yuanzu Date: 12-9-26 Time: 上午10:55\r\n */\r\npublic class TimeoutChecker {\r\n\r\n    /**\r\n     * 最后一次动作的时间\r\n     */\r\n    private long              lastTouch;\r\n    /**\r\n     * 超时时间\r\n     */\r\n    private long              timeoutMillis;\r\n\r\n    /**\r\n     * 运行标志\r\n     */\r\n    private boolean           running                = true;\r\n\r\n    /**\r\n     * default 3s\r\n     */\r\n    private static final long DEFAULT_TIMEOUT_MILLIS = 3 * 1000;\r\n\r\n    public TimeoutChecker(long timeoutMillis){\r\n        this.timeoutMillis = timeoutMillis;\r\n        touch();\r\n    }\r\n\r\n    public TimeoutChecker(){\r\n        this(DEFAULT_TIMEOUT_MILLIS);\r\n    }\r\n\r\n    /**\r\n     * 更新\r\n     */\r\n    public void touch() {\r\n        this.lastTouch = System.currentTimeMillis();\r\n    }\r\n\r\n    /**\r\n     * 等待空闲\r\n     * \r\n     * @throws InterruptedException\r\n     */\r\n    public void waitForIdle() throws InterruptedException {\r\n        while (this.running && (System.currentTimeMillis() - this.lastTouch) < this.timeoutMillis) {\r\n            Thread.sleep(50);\r\n        }\r\n    }\r\n\r\n    public void stop() {\r\n        this.running = false;\r\n    }\r\n}\r\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/inbound/EventTransactionBufferTest.java",
    "content": "package com.alibaba.otter.canal.parse.inbound;\n\nimport java.text.MessageFormat;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.protocol.CanalEntry.Entry;\nimport com.alibaba.otter.canal.protocol.CanalEntry.EntryType;\nimport com.alibaba.otter.canal.protocol.CanalEntry.Header;\n\npublic class EventTransactionBufferTest {\n\n    private static final String DATE_FORMAT = \"yyyy-MM-dd HH:mm:ss\";\n    private static final String messgae     = \"{0} [{1}:{2}:{3}] {4}.{5}\";\n\n    @Test\n    public void testTransactionFlush() {\n        final int bufferSize = 64;\n        final int transactionSize = 5;\n        EventTransactionBuffer buffer = new EventTransactionBuffer();\n        buffer.setBufferSize(bufferSize);\n        buffer.setFlushCallback(transaction -> {\n            Assert.assertEquals(transactionSize, transaction.size());\n            System.out.println(\"\\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\");\n            for (Entry data : transaction) {\n\n                Header header = data.getHeader();\n                Date date = new Date(header.getExecuteTime());\n                SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT);\n                if (data.getEntryType() == EntryType.TRANSACTIONBEGIN\n                    || data.getEntryType() == EntryType.TRANSACTIONEND) {\n                    System.out.println(data.getEntryType());\n\n                } else {\n                    System.out.println(MessageFormat.format(messgae, new Object[] {\n                            Thread.currentThread().getName(), header.getLogfileName(), header.getLogfileOffset(),\n                            format.format(date), header.getSchemaName(), header.getTableName() }));\n                }\n\n            }\n            System.out.println(\"<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\\n\");\n        });\n        buffer.start();\n\n        try {\n            for (int i = 0; i < transactionSize * 10; i++) {\n                if (i % transactionSize == 0) {\n                    buffer.add(buildEntry(\"1\", 1L + i, 40L + i, EntryType.TRANSACTIONBEGIN));\n                } else if ((i + 1) % transactionSize == 0) {\n                    buffer.add(buildEntry(\"1\", 1L + i, 40L + i, EntryType.TRANSACTIONEND));\n                } else {\n                    buffer.add(buildEntry(\"1\", 1L + i, 40L + i));\n                }\n            }\n        } catch (InterruptedException e) {\n            Assert.fail(e.getMessage());\n        }\n\n        buffer.stop();\n    }\n\n    @Test\n    public void testForceFlush() {\n        final int bufferSize = 64;\n        EventTransactionBuffer buffer = new EventTransactionBuffer();\n        buffer.setBufferSize(bufferSize);\n        buffer.setFlushCallback(transaction -> {\n            Assert.assertEquals(bufferSize, transaction.size());\n            System.out.println(\"\\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\");\n            for (Entry data : transaction) {\n\n                Header header = data.getHeader();\n                Date date = new Date(header.getExecuteTime());\n                SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT);\n                if (data.getEntryType() == EntryType.TRANSACTIONBEGIN\n                    || data.getEntryType() == EntryType.TRANSACTIONEND) {\n                    // System.out.println(MessageFormat.format(messgae, new\n                    // Object[] {\n                    // Thread.currentThread().getName(),\n                    // header.getLogfilename(), header.getLogfileoffset(),\n                    // format.format(date),\n                    // data.getEntry().getEntryType(), \"\" }));\n                    System.out.println(data.getEntryType());\n\n                } else {\n                    System.out.println(MessageFormat.format(messgae, new Object[] {\n                            Thread.currentThread().getName(), header.getLogfileName(), header.getLogfileOffset(),\n                            format.format(date), header.getSchemaName(), header.getTableName() }));\n                }\n\n            }\n            System.out.println(\"<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\\n\");\n        });\n        buffer.start();\n\n        try {\n            for (int i = 0; i < bufferSize * 2 + 1; i++) {\n                buffer.add(buildEntry(\"1\", 1L + i, 40L + i));\n            }\n        } catch (InterruptedException e) {\n            Assert.fail(e.getMessage());\n        }\n\n        buffer.stop();\n    }\n\n    private static Entry buildEntry(String binlogFile, long offset, long timestamp) {\n        Header.Builder headerBuilder = Header.newBuilder();\n        headerBuilder.setLogfileName(binlogFile);\n        headerBuilder.setLogfileOffset(offset);\n        headerBuilder.setExecuteTime(timestamp);\n        Entry.Builder entryBuilder = Entry.newBuilder();\n        entryBuilder.setHeader(headerBuilder.build());\n        return entryBuilder.build();\n    }\n\n    private static Entry buildEntry(String binlogFile, long offset, long timestamp, EntryType type) {\n        Header.Builder headerBuilder = Header.newBuilder();\n        headerBuilder.setLogfileName(binlogFile);\n        headerBuilder.setLogfileOffset(offset);\n        headerBuilder.setExecuteTime(timestamp);\n        Entry.Builder entryBuilder = Entry.newBuilder();\n        entryBuilder.setHeader(headerBuilder.build());\n        entryBuilder.setEntryType(type);\n        return entryBuilder.build();\n    }\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/inbound/TableMetaCacheTest.java",
    "content": "package com.alibaba.otter.canal.parse.inbound;\n\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.util.List;\n\nimport org.junit.Assert;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.parse.driver.mysql.packets.server.ResultSetPacket;\nimport com.alibaba.otter.canal.parse.inbound.mysql.MysqlConnection;\n@Ignore\npublic class TableMetaCacheTest {\n\n    @Test\n    public void testSimple() throws IOException {\n        MysqlConnection connection = new MysqlConnection(new InetSocketAddress(\"127.0.0.1\", 3306), \"root\", \"hello\");\n        try {\n            connection.connect();\n        } catch (IOException e) {\n            Assert.fail(e.getMessage());\n        }\n\n        List<ResultSetPacket> packets = connection.queryMulti(\"show create table test.ljh_test\");\n        String createDDL = null;\n        if (packets.get(0).getFieldValues().size() > 0) {\n            createDDL = packets.get(0).getFieldValues().get(1);\n        }\n\n        System.out.println(createDDL);\n\n        // TableMetaCache cache = new TableMetaCache(connection);\n        // TableMeta meta = cache.getTableMeta(\"otter1\", \"otter_stability1\");\n        // Assert.assertNotNull(meta);\n        // for (FieldMeta field : meta.getFields()) {\n        // System.out.println(\"filed :\" + field.getColumnName() + \" , isKey : \"\n        // + field.isKey() + \" , isNull : \"\n        // + field.isNullable());\n        // }\n    }\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/inbound/group/DummyEventStore.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.group;\n\nimport java.text.MessageFormat;\nimport java.text.SimpleDateFormat;\nimport java.util.Arrays;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport com.alibaba.otter.canal.protocol.CanalEntry.EntryType;\nimport com.alibaba.otter.canal.protocol.position.Position;\nimport com.alibaba.otter.canal.store.CanalEventStore;\nimport com.alibaba.otter.canal.store.CanalStoreException;\nimport com.alibaba.otter.canal.store.model.Event;\nimport com.alibaba.otter.canal.store.model.Events;\n\npublic class DummyEventStore implements CanalEventStore<Event> {\n\n    private static final String DATE_FORMAT = \"yyyy-MM-dd HH:mm:ss\";\n    private static final String messgae     = \"{0} [{1}:{2}:{3}]\";\n\n    public void ack(Position position) throws CanalStoreException {\n\n    }\n\n    public void ack(Position position, Long seqId) throws CanalStoreException {\n\n    }\n\n    public Events get(Position start, int batchSize) throws InterruptedException, CanalStoreException {\n        return null;\n    }\n\n    public Events get(Position start, int batchSize, long timeout, TimeUnit unit) throws InterruptedException,\n                                                                                 CanalStoreException {\n        return null;\n    }\n\n    public Position getFirstPosition() throws CanalStoreException {\n        return null;\n    }\n\n    public Position getLatestPosition() throws CanalStoreException {\n        return null;\n    }\n\n    public void rollback() throws CanalStoreException {\n\n    }\n\n    public Events tryGet(Position start, int batchSize) throws CanalStoreException {\n        return null;\n    }\n\n    public boolean isStart() {\n        return false;\n    }\n\n    public void start() {\n\n    }\n\n    public void stop() {\n\n    }\n\n    public void cleanAll() throws CanalStoreException {\n    }\n\n    public void cleanUntil(Position position) throws CanalStoreException {\n\n    }\n\n    public void put(Event data) throws InterruptedException, CanalStoreException {\n        put(Arrays.asList(data));\n    }\n\n    public boolean put(Event data, long timeout, TimeUnit unit) throws InterruptedException, CanalStoreException {\n        return put(Arrays.asList(data), timeout, unit);\n    }\n\n    public boolean tryPut(Event data) throws CanalStoreException {\n        return tryPut(Arrays.asList(data));\n    }\n\n    public void put(List<Event> datas) throws InterruptedException, CanalStoreException {\n        for (Event data : datas) {\n            Date date = new Date(data.getExecuteTime());\n            SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT);\n            if (data.getEntryType() == EntryType.TRANSACTIONBEGIN || data.getEntryType() == EntryType.TRANSACTIONEND) {\n                // System.out.println(MessageFormat.format(messgae, new Object[]\n                // { Thread.currentThread().getName(),\n                // header.getLogfilename(), header.getLogfileoffset(),\n                // format.format(date),\n                // data.getEntry().getEntryType(), \"\" }));\n                System.out.println(data.getEntryType());\n\n            } else {\n                System.out.println(MessageFormat.format(messgae,\n                    new Object[] { Thread.currentThread().getName(), data.getJournalName(),\n                            String.valueOf(data.getPosition()), format.format(date) }));\n            }\n        }\n    }\n\n    public boolean put(List<Event> datas, long timeout, TimeUnit unit) throws InterruptedException, CanalStoreException {\n        for (Event data : datas) {\n            Date date = new Date(data.getExecuteTime());\n            SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT);\n            if (data.getEntryType() == EntryType.TRANSACTIONBEGIN || data.getEntryType() == EntryType.TRANSACTIONEND) {\n                // System.out.println(MessageFormat.format(messgae, new Object[]\n                // { Thread.currentThread().getName(),\n                // header.getLogfilename(), header.getLogfileoffset(),\n                // format.format(date),\n                // data.getEntry().getEntryType(), \"\" }));\n                System.out.println(data.getEntryType());\n\n            } else {\n                System.out.println(MessageFormat.format(messgae,\n                    new Object[] { Thread.currentThread().getName(), data.getJournalName(),\n                            String.valueOf(data.getPosition()), format.format(date) }));\n            }\n        }\n        return true;\n    }\n\n    public boolean tryPut(List<Event> datas) throws CanalStoreException {\n        System.out.println(\"\\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\");\n        for (Event data : datas) {\n\n            Date date = new Date(data.getExecuteTime());\n            SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT);\n            if (data.getEntryType() == EntryType.TRANSACTIONBEGIN || data.getEntryType() == EntryType.TRANSACTIONEND) {\n                // System.out.println(MessageFormat.format(messgae, new Object[]\n                // { Thread.currentThread().getName(),\n                // header.getLogfilename(), header.getLogfileoffset(),\n                // format.format(date),\n                // data.getEntry().getEntryType(), \"\" }));\n                System.out.println(data.getEntryType());\n\n            } else {\n                System.out.println(MessageFormat.format(messgae,\n                    new Object[] { Thread.currentThread().getName(), data.getJournalName(),\n                            String.valueOf(data.getPosition()), format.format(date) }));\n            }\n\n        }\n        System.out.println(\"<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\\n\");\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/inbound/group/GroupEventPaserTest.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.group;\n\nimport java.net.InetSocketAddress;\n\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\nimport com.alibaba.otter.canal.parse.inbound.AbstractBinlogParser;\nimport com.alibaba.otter.canal.parse.inbound.BinlogParser;\nimport com.alibaba.otter.canal.parse.inbound.mysql.MysqlEventParser;\nimport com.alibaba.otter.canal.parse.index.AbstractLogPositionManager;\nimport com.alibaba.otter.canal.parse.support.AuthenticationInfo;\nimport com.alibaba.otter.canal.protocol.CanalEntry.Entry;\nimport com.alibaba.otter.canal.protocol.position.EntryPosition;\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\nimport com.alibaba.otter.canal.sink.entry.EntryEventSink;\nimport com.alibaba.otter.canal.sink.entry.group.GroupEventSink;\nimport com.taobao.tddl.dbsync.binlog.LogEvent;\n\npublic class GroupEventPaserTest {\n\n    private static final String DETECTING_SQL = \"insert into retl.xdual values(1,now()) on duplicate key update x=now()\";\n    private static final String MYSQL_ADDRESS = \"127.0.0.1\";\n    private static final String USERNAME      = \"xxxxx\";\n    private static final String PASSWORD      = \"xxxxx\";\n    @Ignore\n    @Test\n    public void testMysqlWithMysql() {\n        // MemoryEventStoreWithBuffer eventStore = new\n        // MemoryEventStoreWithBuffer();\n        // eventStore.setBufferSize(8196);\n\n        GroupEventSink eventSink = new GroupEventSink(3);\n        eventSink.setFilterTransactionEntry(false);\n        eventSink.setEventStore(new DummyEventStore());\n        eventSink.start();\n\n        // 构造第一个mysql\n        MysqlEventParser mysqlEventPaser1 = buildEventParser(3344);\n        mysqlEventPaser1.setEventSink(eventSink);\n        // 构造第二个mysql\n        MysqlEventParser mysqlEventPaser2 = buildEventParser(3345);\n        mysqlEventPaser2.setEventSink(eventSink);\n        // 构造第二个mysql\n        MysqlEventParser mysqlEventPaser3 = buildEventParser(3346);\n        mysqlEventPaser3.setEventSink(eventSink);\n        // 启动\n        mysqlEventPaser1.start();\n        mysqlEventPaser2.start();\n        mysqlEventPaser3.start();\n\n        try {\n            Thread.sleep(30 * 10 * 1000L);\n        } catch (InterruptedException e) {\n        }\n\n        mysqlEventPaser1.stop();\n        mysqlEventPaser2.stop();\n        mysqlEventPaser3.stop();\n    }\n\n    private MysqlEventParser buildEventParser(int slaveId) {\n        MysqlEventParser mysqlEventPaser = new MysqlEventParser();\n        EntryPosition defaultPosition = buildPosition(\"mysql-bin.000001\", 6163L, 1322803601000L);\n        mysqlEventPaser.setDestination(\"group-\" + slaveId);\n        mysqlEventPaser.setSlaveId(slaveId);\n        mysqlEventPaser.setDetectingEnable(false);\n        mysqlEventPaser.setDetectingSQL(DETECTING_SQL);\n        mysqlEventPaser.setMasterInfo(buildAuthentication());\n        mysqlEventPaser.setMasterPosition(defaultPosition);\n        mysqlEventPaser.setBinlogParser(buildParser(buildAuthentication()));\n        mysqlEventPaser.setEventSink(new EntryEventSink());\n        mysqlEventPaser.setLogPositionManager(new AbstractLogPositionManager() {\n\n            @Override\n            public LogPosition getLatestIndexBy(String destination) {\n                return null;\n            }\n\n            @Override\n            public void persistLogPosition(String destination, LogPosition logPosition) throws CanalParseException {\n                System.out.println(logPosition);\n            }\n        });\n        return mysqlEventPaser;\n    }\n\n    private BinlogParser buildParser(AuthenticationInfo info) {\n        return new AbstractBinlogParser<LogEvent>() {\n\n            @Override\n            public Entry parse(LogEvent event, boolean isSeek) throws CanalParseException {\n                return null;\n            }\n        };\n    }\n\n    private EntryPosition buildPosition(String binlogFile, Long offest, Long timestamp) {\n        return new EntryPosition(binlogFile, offest, timestamp);\n    }\n\n    private AuthenticationInfo buildAuthentication() {\n        return new AuthenticationInfo(new InetSocketAddress(MYSQL_ADDRESS, 3306), USERNAME, PASSWORD);\n    }\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/inbound/mysql/DruidDdlParserTest.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.parse.inbound.mysql.ddl.DdlResult;\nimport com.alibaba.otter.canal.parse.inbound.mysql.ddl.DruidDdlParser;\nimport com.alibaba.otter.canal.parse.inbound.mysql.ddl.SimpleDdlParser;\nimport com.alibaba.otter.canal.protocol.CanalEntry.EventType;\n\npublic class DruidDdlParserTest {\n\n    @Test\n    public void testCreate() {\n        String queryString = \"CREATE TABLE retl_mark ( `ID` int(11) )\";\n        DdlResult result = DruidDdlParser.parse(queryString, \"retl\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        queryString = \"CREATE TABLE IF NOT EXISTS retl.retl_mark ( `ID` int(11) )\";\n        result = DruidDdlParser.parse(queryString, \"retl\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        queryString = \"CREATE TABLE IF NOT EXISTS `retl_mark` ( `ID` int(11) )\";\n        result = DruidDdlParser.parse(queryString, \"retl\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        queryString = \"CREATE TABLE  `retl`.`retl_mark` (\\n  `ID` int(10) unsigned NOT NULL )\";\n        result = DruidDdlParser.parse(queryString, \"retl\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        queryString = \"CREATE TABLE  `retl`.`retl_mark`(\\n  `ID` int(10) unsigned NOT NULL )\";\n        result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        queryString = \"CREATE table `bak591`.`j_order_log_back_201309` like j_order_log\";\n        result = DruidDdlParser.parse(queryString, \"bak\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"bak591\", result.getSchemaName());\n        Assert.assertEquals(\"j_order_log_back_201309\", result.getTableName());\n\n        queryString = \"CREATE DEFINER=sco*erce@% PROCEDURE SC_CPN_CODES_SAVE_ACTION(IN cosmosPassportId CHAR(32), IN orderId CHAR(32), IN codeIds TEXT) BEGIN SET @orderId = orderId; SET @timeNow = NOW(); START TRANSACTION; DELETE FROMsc_ord_couponWHEREORDER_ID= @orderId; SET @i=1; SET @numbers = FN_GET_ELEMENTS_COUNT(codeIds, '|'); WHILE @i <= @numbers DO SET @codeId = FN_FIND_ELEMENT_BYINDEX(codeIds, '|', @i); SET @orderCodeId = UUID32(); INSERT INTOsc_ord_coupon(ID,CREATE_BY,CREATE_TIME,UPDATE_BY,UPDATE_TIME,ORDER_ID,CODE_ID`) VALUES(@orderCodeId, cosmosPassportId, @timeNow, cosmosPassportId, @timeNow, @orderId, @codeId); SET @i = @i + 1; END WHILE; COMMIT; END\";\n        result = DruidDdlParser.parse(queryString, \"bak\").get(0);\n        Assert.assertEquals(EventType.QUERY, result.getType());\n\n        queryString = \"CREATE TABLE performance_schema.cond_instances(`ID` int(10) unsigned NOT NULL ) \";\n        result = DruidDdlParser.parse(queryString, \"retl\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"performance_schema\", result.getSchemaName());\n        Assert.assertEquals(\"cond_instances\", result.getTableName());\n    }\n\n    @Test\n    public void testDrop() {\n        String queryString = \"DROP TABLE retl_mark\";\n        DdlResult result = DruidDdlParser.parse(queryString, \"retl\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        queryString = \"DROP TABLE IF EXISTS test.retl_mark;\";\n        result = DruidDdlParser.parse(queryString, \"retl\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"test\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        queryString = \"DROP TABLE IF EXISTS \\n \\\"test\\\".`retl_mark`;\";\n        result = DruidDdlParser.parse(queryString, \"retl\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"test\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        queryString = \"DROP TABLE IF EXISTS \\n retl.retl_mark , retl_test\";\n        result = DruidDdlParser.parse(queryString, \"test\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n        result = DruidDdlParser.parse(queryString, \"test\").get(1);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"test\", result.getSchemaName());\n        Assert.assertEquals(\"retl_test\", result.getTableName());\n\n        queryString = \"DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `temp_bond_keys`.`temp_bond_key_id`;\";\n        result = DruidDdlParser.parse(queryString, \"retl\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"temp_bond_keys\", result.getSchemaName());\n        Assert.assertEquals(\"temp_bond_key_id\", result.getTableName());\n    }\n\n    @Test\n    public void testAlert() {\n        String queryString = \"alter table retl_mark drop index emp_name\";\n        DdlResult result = DruidDdlParser.parse(queryString, \"retl\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        queryString = \"alter table retl.retl_mark drop index emp_name\";\n        result = DruidDdlParser.parse(queryString, \"retl\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        queryString = \"alter table \\n retl.`retl_mark` drop index emp_name;\";\n        result = DruidDdlParser.parse(queryString, \"retl\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        queryString = \"alter table retl.retl_mark drop index emp_name , add index emp_name(id)\";\n        result = DruidDdlParser.parse(queryString, \"retl\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n        Assert.assertEquals(EventType.DINDEX, result.getType());\n\n        result = DruidDdlParser.parse(queryString, \"retl\").get(1);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n        Assert.assertEquals(EventType.CINDEX, result.getType());\n    }\n\n    @Test\n    public void testTruncate() {\n        String queryString = \"truncate table retl_mark\";\n        DdlResult result = DruidDdlParser.parse(queryString, \"retl\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        queryString = \"truncate table retl.retl_mark\";\n        result = DruidDdlParser.parse(queryString, \"retl\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        queryString = \"truncate \\n  retl.`retl_mark` \";\n        result = DruidDdlParser.parse(queryString, \"retl\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        queryString = \"truncate \\n  retl.retl_mark , retl_test \";\n        result = DruidDdlParser.parse(queryString, \"retl\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n        result = DruidDdlParser.parse(queryString, \"retl\").get(1);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl_test\", result.getTableName());\n    }\n\n    @Test\n    public void testRename() {\n        String queryString = \"rename table retl_mark to retl_mark2\";\n        DdlResult result = DruidDdlParser.parse(queryString, \"retl\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getOriSchemaName());\n        Assert.assertEquals(\"retl\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getOriTableName());\n        Assert.assertEquals(\"retl_mark2\", result.getTableName());\n\n        queryString = \"rename table retl.retl_mark to retl2.retl_mark2\";\n        result = DruidDdlParser.parse(queryString, \"retl\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getOriSchemaName());\n        Assert.assertEquals(\"retl2\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getOriTableName());\n        Assert.assertEquals(\"retl_mark2\", result.getTableName());\n\n        queryString = \"rename \\n table \\n `retl`.`retl_mark` to `retl2`.`retl_mark2`;\";\n        result = DruidDdlParser.parse(queryString, \"retl\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getOriSchemaName());\n        Assert.assertEquals(\"retl2\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getOriTableName());\n        Assert.assertEquals(\"retl_mark2\", result.getTableName());\n\n        queryString = \"rename \\n table \\n `retl`.`retl_mark` to `retl2`.`retl_mark2` , `retl1`.`retl_mark1` to `retl3`.`retl_mark3`;\";\n        result = DruidDdlParser.parse(queryString, \"retl\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getOriSchemaName());\n        Assert.assertEquals(\"retl2\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getOriTableName());\n        Assert.assertEquals(\"retl_mark2\", result.getTableName());\n        result = DruidDdlParser.parse(queryString, \"retl\").get(1);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl1\", result.getOriSchemaName());\n        Assert.assertEquals(\"retl3\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark1\", result.getOriTableName());\n        Assert.assertEquals(\"retl_mark3\", result.getTableName());\n\n        // 正则匹配test case\n\n        queryString = \"rename table totl_mark to totl_mark2\";\n        result = DruidDdlParser.parse(queryString, \"retl\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getOriSchemaName());\n        Assert.assertEquals(\"retl\", result.getSchemaName());\n        Assert.assertEquals(\"totl_mark\", result.getOriTableName());\n        Assert.assertEquals(\"totl_mark2\", result.getTableName());\n\n        queryString = \"rename table totl.retl_mark to totl2.retl_mark2\";\n        result = DruidDdlParser.parse(queryString, \"retl\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"totl\", result.getOriSchemaName());\n        Assert.assertEquals(\"totl2\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getOriTableName());\n        Assert.assertEquals(\"retl_mark2\", result.getTableName());\n\n        queryString = \"rename \\n table \\n `totl`.`retl_mark` to `totl2`.`retl_mark2`;\";\n        result = DruidDdlParser.parse(queryString, \"retl\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"totl\", result.getOriSchemaName());\n        Assert.assertEquals(\"totl2\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getOriTableName());\n        Assert.assertEquals(\"retl_mark2\", result.getTableName());\n\n        queryString = \"rename \\n table \\n `totl`.`retl_mark` to `totl2`.`retl_mark2` , `totl1`.`retl_mark1` to `totl3`.`retl_mark3`;\";\n        result = DruidDdlParser.parse(queryString, \"retl\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"totl\", result.getOriSchemaName());\n        Assert.assertEquals(\"totl2\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getOriTableName());\n        Assert.assertEquals(\"retl_mark2\", result.getTableName());\n        result = DruidDdlParser.parse(queryString, \"retl\").get(1);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"totl1\", result.getOriSchemaName());\n        Assert.assertEquals(\"totl3\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark1\", result.getOriTableName());\n        Assert.assertEquals(\"retl_mark3\", result.getTableName());\n\n    }\n\n    @Test\n    public void testIndex() {\n        String queryString = \"CREATE UNIQUE INDEX index_1 ON retl_mark(id,x)\";\n        DdlResult result = DruidDdlParser.parse(queryString, \"retl\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        queryString = \"create index idx_qca_cid_mcid on q_contract_account (contract_id,main_contract_id)\";\n        result = DruidDdlParser.parse(queryString, \"retl\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getSchemaName());\n        Assert.assertEquals(\"q_contract_account\", result.getTableName());\n\n        queryString = \"DROP INDEX index_str ON retl_mark\";\n        result = DruidDdlParser.parse(queryString, \"retl\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n    }\n\n    @Test\n    public void testDb() {\n        String queryString = \"create database db1\";\n        DdlResult result = DruidDdlParser.parse(queryString, \"db0\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"db1\", result.getSchemaName());\n\n        queryString = \"drop database db1\";\n        result = DruidDdlParser.parse(queryString, \"retl\").get(0);\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"db1\", result.getSchemaName());\n    }\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/inbound/mysql/LocalBinlogDumpTest.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql;\n\nimport java.net.InetSocketAddress;\nimport java.nio.charset.Charset;\nimport java.util.List;\n\nimport org.junit.Assert;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\nimport com.alibaba.otter.canal.parse.index.AbstractLogPositionManager;\nimport com.alibaba.otter.canal.parse.stub.AbstractCanalEventSinkTest;\nimport com.alibaba.otter.canal.parse.support.AuthenticationInfo;\nimport com.alibaba.otter.canal.protocol.CanalEntry.Column;\nimport com.alibaba.otter.canal.protocol.CanalEntry.Entry;\nimport com.alibaba.otter.canal.protocol.CanalEntry.EntryType;\nimport com.alibaba.otter.canal.protocol.CanalEntry.EventType;\nimport com.alibaba.otter.canal.protocol.CanalEntry.RowChange;\nimport com.alibaba.otter.canal.protocol.CanalEntry.RowData;\nimport com.alibaba.otter.canal.protocol.position.EntryPosition;\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\nimport com.alibaba.otter.canal.sink.exception.CanalSinkException;\n@Ignore\npublic class LocalBinlogDumpTest {\n\n    @Test\n    public void testSimple() {\n        String directory = \"/Users/wanshao/projects/canal/parse/src/test/resources/binlog/tsdb\";\n        final LocalBinlogEventParser controller = new LocalBinlogEventParser();\n        final EntryPosition startPosition = new EntryPosition(\"mysql-bin.000003\", 123L);\n\n        controller.setMasterInfo(new AuthenticationInfo(new InetSocketAddress(\"127.0.0.1\", 3306), \"canal\", \"canal\"));\n        controller.setConnectionCharsetStd(Charset.forName(\"UTF-8\"));\n        controller.setDirectory(directory);\n        controller.setMasterPosition(startPosition);\n        controller.setEventSink(new AbstractCanalEventSinkTest<List<Entry>>() {\n\n            public boolean sink(List<Entry> entrys, InetSocketAddress remoteAddress, String destination)\n                                                                                                        throws CanalSinkException,\n                                                                                                        InterruptedException {\n\n                for (Entry entry : entrys) {\n                    if (entry.getEntryType() == EntryType.TRANSACTIONBEGIN\n                        || entry.getEntryType() == EntryType.TRANSACTIONEND) {\n                        continue;\n                    }\n\n                    if (entry.getEntryType() == EntryType.ROWDATA) {\n                        RowChange rowChange = null;\n                        try {\n                            rowChange = RowChange.parseFrom(entry.getStoreValue());\n                        } catch (Exception e) {\n                            throw new RuntimeException(\"ERROR ## parser of eromanga-event has an error , data:\"\n                                                       + entry.toString(), e);\n                        }\n\n                        EventType eventType = rowChange.getEventType();\n                        System.out.println(String.format(\"================> binlog[%s:%s] , name[%s,%s] , eventType : %s\",\n                            entry.getHeader().getLogfileName(),\n                            entry.getHeader().getLogfileOffset(),\n                            entry.getHeader().getSchemaName(),\n                            entry.getHeader().getTableName(),\n                            eventType));\n\n                        for (RowData rowData : rowChange.getRowDatasList()) {\n                            if (eventType == EventType.DELETE) {\n                                print(rowData.getBeforeColumnsList());\n                            } else if (eventType == EventType.INSERT) {\n                                print(rowData.getAfterColumnsList());\n                            } else {\n                                System.out.println(\"-------> before\");\n                                print(rowData.getBeforeColumnsList());\n                                System.out.println(\"-------> after\");\n                                print(rowData.getAfterColumnsList());\n                            }\n                        }\n                    }\n                }\n\n                return true;\n            }\n\n        });\n        controller.setLogPositionManager(new AbstractLogPositionManager() {\n\n            @Override\n            public LogPosition getLatestIndexBy(String destination) {\n                return null;\n            }\n\n            @Override\n            public void persistLogPosition(String destination, LogPosition logPosition) throws CanalParseException {\n                System.out.println(logPosition);\n            }\n        });\n\n        controller.start();\n\n        try {\n            Thread.sleep(100 * 1000L);\n        } catch (InterruptedException e) {\n            Assert.fail(e.getMessage());\n        }\n        controller.stop();\n    }\n\n    private void print(List<Column> columns) {\n        for (Column column : columns) {\n            System.out.println(column.getName() + \" : \" + column.getValue() + \"    update=\" + column.getUpdated());\n        }\n    }\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/inbound/mysql/LocalBinlogEventParserTest.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql;\n\nimport java.io.File;\nimport java.net.InetSocketAddress;\nimport java.net.URL;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.parse.helper.TimeoutChecker;\nimport com.alibaba.otter.canal.parse.index.AbstractLogPositionManager;\nimport com.alibaba.otter.canal.parse.stub.AbstractCanalEventSinkTest;\nimport com.alibaba.otter.canal.parse.support.AuthenticationInfo;\nimport com.alibaba.otter.canal.protocol.CanalEntry.Entry;\nimport com.alibaba.otter.canal.protocol.position.EntryPosition;\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\nimport com.alibaba.otter.canal.sink.exception.CanalSinkException;\n@Ignore\npublic class LocalBinlogEventParserTest {\n\n    private static final String MYSQL_ADDRESS = \"127.0.0.1\";\n    private static final String USERNAME      = \"canal\";\n    private static final String PASSWORD      = \"canal\";\n    private String              directory;\n\n    @Before\n    public void setUp() {\n        URL url = Thread.currentThread().getContextClassLoader().getResource(\"dummy.txt\");\n        File dummyFile = new File(url.getFile());\n        directory = new File(dummyFile + \"/binlog/tsdb\").getPath();\n    }\n\n    @Test\n    public void test_position() throws InterruptedException {\n        final TimeoutChecker timeoutChecker = new TimeoutChecker();\n        final AtomicLong entryCount = new AtomicLong(0);\n        final EntryPosition entryPosition = new EntryPosition();\n\n        final EntryPosition defaultPosition = buildPosition(\"mysql-bin.000003\", 219L, 1505467103000L);\n        final LocalBinlogEventParser controller = new LocalBinlogEventParser();\n        controller.setMasterPosition(defaultPosition);\n        controller.setMasterInfo(buildAuthentication());\n        controller.setDirectory(directory);\n        controller.setEventSink(new AbstractCanalEventSinkTest<List<Entry>>() {\n\n            public boolean sink(List<Entry> entrys, InetSocketAddress remoteAddress, String destination)\n                                                                                                        throws CanalSinkException {\n                entryCount.incrementAndGet();\n\n                for (Entry entry : entrys) {\n                    String logfilename = entry.getHeader().getLogfileName();\n                    long logfileoffset = entry.getHeader().getLogfileOffset();\n                    long executeTime = entry.getHeader().getExecuteTime();\n\n                    entryPosition.setJournalName(logfilename);\n                    entryPosition.setPosition(logfileoffset);\n                    entryPosition.setTimestamp(executeTime);\n                    break;\n                }\n\n                controller.stop();\n                timeoutChecker.stop();\n                timeoutChecker.touch();\n                return true;\n            }\n\n        });\n\n        controller.setLogPositionManager(new AbstractLogPositionManager() {\n\n            public void persistLogPosition(String destination, LogPosition logPosition) {\n                System.out.println(logPosition);\n            }\n\n            @Override\n            public LogPosition getLatestIndexBy(String destination) {\n                return null;\n            }\n        });\n\n        controller.start();\n\n        timeoutChecker.waitForIdle();\n\n        if (controller.isStart()) {\n            controller.stop();\n        }\n\n        // check\n        Assert.assertTrue(entryCount.get() > 0);\n\n        // 对比第一条数据和起始的position相同\n        Assert.assertEquals(entryPosition, defaultPosition);\n    }\n\n    @Test\n    public void test_timestamp() throws InterruptedException {\n        final TimeoutChecker timeoutChecker = new TimeoutChecker(300 * 1000);\n        final AtomicLong entryCount = new AtomicLong(0);\n        final EntryPosition entryPosition = new EntryPosition();\n\n        final EntryPosition defaultPosition = buildPosition(\"mysql-bin.000003\", null, 1505467103000L);\n        final LocalBinlogEventParser controller = new LocalBinlogEventParser();\n        controller.setMasterPosition(defaultPosition);\n        controller.setMasterInfo(buildAuthentication());\n        controller.setDirectory(directory);\n        controller.setEventSink(new AbstractCanalEventSinkTest<List<Entry>>() {\n\n            @Override\n            public boolean sink(List<Entry> entrys, InetSocketAddress remoteAddress, String destination)\n                                                                                                        throws CanalSinkException {\n                for (Entry entry : entrys) {\n                    entryCount.incrementAndGet();\n\n                    String logfilename = entry.getHeader().getLogfileName();\n                    long logfileoffset = entry.getHeader().getLogfileOffset();\n                    long executeTime = entry.getHeader().getExecuteTime();\n\n                    entryPosition.setJournalName(logfilename);\n                    entryPosition.setPosition(logfileoffset);\n                    entryPosition.setTimestamp(executeTime);\n                    break;\n                }\n\n                controller.stop();\n                timeoutChecker.stop();\n                timeoutChecker.touch();\n                return true;\n            }\n        });\n\n        controller.setLogPositionManager(new AbstractLogPositionManager() {\n\n            public void persistLogPosition(String destination, LogPosition logPosition) {\n                System.out.println(logPosition);\n            }\n\n            @Override\n            public LogPosition getLatestIndexBy(String destination) {\n                return null;\n            }\n        });\n\n        controller.start();\n        timeoutChecker.waitForIdle();\n\n        if (controller.isStart()) {\n            controller.stop();\n        }\n\n        // check\n        Assert.assertTrue(entryCount.get() > 0);\n\n        // 对比第一条数据和起始的position相同\n        Assert.assertEquals(entryPosition.getJournalName(), \"mysql-bin.000003\");\n        Assert.assertTrue(entryPosition.getPosition() <= 300L);\n        Assert.assertTrue(entryPosition.getTimestamp() <= defaultPosition.getTimestamp());\n    }\n\n    @Test\n    public void test_no_position() throws InterruptedException {\n        final TimeoutChecker timeoutChecker = new TimeoutChecker(3 * 1000);\n        final EntryPosition defaultPosition = buildPosition(\"mysql-bin.000003\",\n            null,\n            new Date().getTime() + 1000 * 1000L);\n        final AtomicLong entryCount = new AtomicLong(0);\n        final EntryPosition entryPosition = new EntryPosition();\n\n        final LocalBinlogEventParser controller = new LocalBinlogEventParser();\n        controller.setMasterPosition(defaultPosition);\n        controller.setMasterInfo(buildAuthentication());\n        controller.setDirectory(directory);\n        controller.setEventSink(new AbstractCanalEventSinkTest<List<Entry>>() {\n\n            public boolean sink(List<Entry> entrys, InetSocketAddress remoteAddress, String destination)\n                                                                                                        throws CanalSinkException {\n                for (Entry entry : entrys) {\n                    entryCount.incrementAndGet();\n\n                    String logfilename = entry.getHeader().getLogfileName();\n                    long logfileoffset = entry.getHeader().getLogfileOffset();\n                    long executeTime = entry.getHeader().getExecuteTime();\n\n                    entryPosition.setJournalName(logfilename);\n                    entryPosition.setPosition(logfileoffset);\n                    entryPosition.setTimestamp(executeTime);\n                    break;\n                }\n\n                controller.stop();\n                timeoutChecker.stop();\n                timeoutChecker.touch();\n                return true;\n            }\n        });\n\n        controller.setLogPositionManager(new AbstractLogPositionManager() {\n\n            public void persistLogPosition(String destination, LogPosition logPosition) {\n                System.out.println(logPosition);\n            }\n\n            @Override\n            public LogPosition getLatestIndexBy(String destination) {\n                return null;\n            }\n        });\n\n        controller.start();\n\n        timeoutChecker.waitForIdle();\n\n        if (controller.isStart()) {\n            controller.stop();\n        }\n\n        // check\n        Assert.assertTrue(entryCount.get() > 0);\n\n        // 对比第一条数据和起始的position相同\n        // assertEquals(entryPosition.getJournalName(), \"mysql-bin.000002\");\n        Assert.assertTrue(entryPosition.getTimestamp() <= defaultPosition.getTimestamp());\n    }\n\n    private EntryPosition buildPosition(String binlogFile, Long offest, Long timestamp) {\n        return new EntryPosition(binlogFile, offest, timestamp);\n    }\n\n    private AuthenticationInfo buildAuthentication() {\n        return new AuthenticationInfo(new InetSocketAddress(MYSQL_ADDRESS, 3306), USERNAME, PASSWORD);\n    }\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/inbound/mysql/MysqlDumpTest.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql;\n\nimport java.net.InetSocketAddress;\nimport java.nio.charset.Charset;\nimport java.util.List;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.junit.Assert;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.filter.aviater.AviaterRegexFilter;\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\nimport com.alibaba.otter.canal.parse.index.AbstractLogPositionManager;\nimport com.alibaba.otter.canal.parse.stub.AbstractCanalEventSinkTest;\nimport com.alibaba.otter.canal.parse.support.AuthenticationInfo;\nimport com.alibaba.otter.canal.protocol.CanalEntry.Column;\nimport com.alibaba.otter.canal.protocol.CanalEntry.Entry;\nimport com.alibaba.otter.canal.protocol.CanalEntry.EntryType;\nimport com.alibaba.otter.canal.protocol.CanalEntry.EventType;\nimport com.alibaba.otter.canal.protocol.CanalEntry.Pair;\nimport com.alibaba.otter.canal.protocol.CanalEntry.RowChange;\nimport com.alibaba.otter.canal.protocol.CanalEntry.RowData;\nimport com.alibaba.otter.canal.protocol.position.EntryPosition;\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\nimport com.alibaba.otter.canal.sink.exception.CanalSinkException;\n@Ignore\npublic class MysqlDumpTest {\n\n    @Test\n    public void testSimple() {\n        final MysqlEventParser controller = new MysqlEventParser();\n        final EntryPosition startPosition = new EntryPosition(\"mysql-bin.000001\", 4L);\n        // startPosition.setGtid(\"f1ceb61a-a5d5-11e7-bdee-107c3dbcf8a7:1-17\");\n        controller.setConnectionCharsetStd(Charset.forName(\"UTF-8\"));\n        controller.setSlaveId(3344L);\n        controller.setDetectingEnable(false);\n        controller.setMasterInfo(new AuthenticationInfo(new InetSocketAddress(\"127.0.0.1\", 3306), \"root\", \"hello\"));\n        controller.setMasterPosition(startPosition);\n        controller.setEnableTsdb(true);\n        controller.setDestination(\"example\");\n        controller.setTsdbSpringXml(\"classpath:tsdb/h2-tsdb.xml\");\n        controller.setEventFilter(new AviaterRegexFilter(\"test\\\\..*\"));\n        controller.setEventBlackFilter(new AviaterRegexFilter(\"canal_tsdb\\\\..*\"));\n        controller.setParallel(true);\n        controller.setParallelBufferSize(256);\n        controller.setParallelThreadSize(2);\n        controller.setIsGTIDMode(false);\n        controller.setEventSink(new AbstractCanalEventSinkTest<List<Entry>>() {\n\n            public boolean sink(List<Entry> entrys, InetSocketAddress remoteAddress, String destination)\n                                                                                                        throws CanalSinkException,\n                                                                                                        InterruptedException {\n\n                for (Entry entry : entrys) {\n                    if (entry.getEntryType() == EntryType.TRANSACTIONBEGIN\n                        || entry.getEntryType() == EntryType.TRANSACTIONEND\n                        || entry.getEntryType() == EntryType.HEARTBEAT) {\n                        continue;\n                    }\n\n                    RowChange rowChange = null;\n                    try {\n                        rowChange = RowChange.parseFrom(entry.getStoreValue());\n                    } catch (Exception e) {\n                        throw new RuntimeException(\"ERROR ## parser of eromanga-event has an error , data:\"\n                                                   + entry.toString(), e);\n                    }\n\n                    EventType eventType = rowChange.getEventType();\n                    System.out.println(String.format(\"================> binlog[%s:%s] , name[%s,%s] , eventType : %s\",\n                        entry.getHeader().getLogfileName(),\n                        entry.getHeader().getLogfileOffset(),\n                        entry.getHeader().getSchemaName(),\n                        entry.getHeader().getTableName(),\n                        eventType));\n\n                    if (eventType == EventType.QUERY || rowChange.getIsDdl()) {\n                        System.out.println(\" sql ----> \" + rowChange.getSql());\n                    }\n\n                    printXAInfo(rowChange.getPropsList());\n                    for (RowData rowData : rowChange.getRowDatasList()) {\n                        if (eventType == EventType.DELETE) {\n                            print(rowData.getBeforeColumnsList());\n                        } else if (eventType == EventType.INSERT) {\n                            print(rowData.getAfterColumnsList());\n                        } else {\n                            System.out.println(\"-------> before\");\n                            print(rowData.getBeforeColumnsList());\n                            System.out.println(\"-------> after\");\n                            print(rowData.getAfterColumnsList());\n                        }\n                    }\n                }\n\n                return true;\n            }\n\n        });\n        controller.setLogPositionManager(new AbstractLogPositionManager() {\n\n            @Override\n            public LogPosition getLatestIndexBy(String destination) {\n                return null;\n            }\n\n            @Override\n            public void persistLogPosition(String destination, LogPosition logPosition) throws CanalParseException {\n                System.out.println(logPosition);\n            }\n        });\n\n        controller.start();\n\n        try {\n            Thread.sleep(100 * 1000 * 1000L);\n        } catch (InterruptedException e) {\n            Assert.fail(e.getMessage());\n        }\n        controller.stop();\n    }\n\n    private void print(List<Column> columns) {\n        for (Column column : columns) {\n            System.out.println(column.getName() + \" : \" + column.getValue() + \"    update=\" + column.getUpdated());\n        }\n    }\n\n    private void printXAInfo(List<Pair> pairs) {\n        if (pairs == null) {\n            return;\n        }\n\n        String xaType = null;\n        String xaXid = null;\n        for (Pair pair : pairs) {\n            String key = pair.getKey();\n            if (StringUtils.endsWithIgnoreCase(key, \"XA_TYPE\")) {\n                xaType = pair.getValue();\n            } else if (StringUtils.endsWithIgnoreCase(key, \"XA_XID\")) {\n                xaXid = pair.getValue();\n            }\n        }\n\n        if (xaType != null && xaXid != null) {\n            System.out.println(\" ------> \" + xaType + \" \" + xaXid);\n        }\n    }\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/inbound/mysql/MysqlEventParserTest.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql;\n\nimport java.net.InetSocketAddress;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.junit.Assert;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\nimport com.alibaba.otter.canal.parse.helper.TimeoutChecker;\nimport com.alibaba.otter.canal.parse.index.AbstractLogPositionManager;\nimport com.alibaba.otter.canal.parse.stub.AbstractCanalEventSinkTest;\nimport com.alibaba.otter.canal.parse.support.AuthenticationInfo;\nimport com.alibaba.otter.canal.protocol.CanalEntry.Entry;\nimport com.alibaba.otter.canal.protocol.CanalEntry.EntryType;\nimport com.alibaba.otter.canal.protocol.position.EntryPosition;\nimport com.alibaba.otter.canal.protocol.position.LogIdentity;\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\nimport com.alibaba.otter.canal.sink.exception.CanalSinkException;\n@Ignore\npublic class MysqlEventParserTest {\n\n    private static final String DETECTING_SQL = \"insert into retl.xdual values(1,now()) on duplicate key update x=now()\";\n    private static final String MYSQL_ADDRESS = \"127.0.0.1\";\n    private static final String USERNAME      = \"canal\";\n    private static final String PASSWORD      = \"canal\";\n\n    @Test\n    public void test_position() throws InterruptedException {\n        final TimeoutChecker timeoutChecker = new TimeoutChecker();\n        final AtomicLong entryCount = new AtomicLong(0);\n        final EntryPosition entryPosition = new EntryPosition();\n\n        final MysqlEventParser controller = new MysqlEventParser();\n        final EntryPosition defaultPosition = buildPosition(\"mysql-bin.000003\", 4690L, 1505481064000L);\n\n        controller.setSlaveId(3344L);\n        controller.setDetectingEnable(true);\n        controller.setDetectingSQL(DETECTING_SQL);\n        controller.setMasterPosition(defaultPosition);\n        controller.setMasterInfo(buildAuthentication());\n        controller.setEventSink(new AbstractCanalEventSinkTest<List<Entry>>() {\n\n            @Override\n            public boolean sink(List<Entry> entrys, InetSocketAddress remoteAddress, String destination)\n                                                                                                        throws CanalSinkException {\n                for (Entry entry : entrys) {\n                    if (entry.getEntryType() != EntryType.HEARTBEAT) {\n                        entryCount.incrementAndGet();\n                        String logfilename = entry.getHeader().getLogfileName();\n                        long logfileoffset = entry.getHeader().getLogfileOffset();\n                        long executeTime = entry.getHeader().getExecuteTime();\n                        entryPosition.setJournalName(logfilename);\n                        entryPosition.setPosition(logfileoffset);\n                        entryPosition.setTimestamp(executeTime);\n                        break;\n                    }\n                }\n\n                if (entryCount.get() > 0) {\n                    controller.stop();\n                    timeoutChecker.stop();\n                    timeoutChecker.touch();\n                }\n                return true;\n            }\n        });\n\n        controller.setLogPositionManager(new AbstractLogPositionManager() {\n\n            @Override\n            public LogPosition getLatestIndexBy(String destination) {\n                return null;\n            }\n\n            @Override\n            public void persistLogPosition(String destination, LogPosition logPosition) throws CanalParseException {\n                System.out.println(logPosition);\n            }\n        });\n\n        controller.start();\n\n        timeoutChecker.waitForIdle();\n\n        if (controller.isStart()) {\n            controller.stop();\n        }\n\n        // check\n        Assert.assertTrue(entryCount.get() > 0);\n\n        // 对比第一条数据和起始的position相同\n        Assert.assertEquals(entryPosition, defaultPosition);\n    }\n\n    @Test\n    public void test_timestamp() throws InterruptedException {\n        final TimeoutChecker timeoutChecker = new TimeoutChecker(3000 * 1000);\n        final AtomicLong entryCount = new AtomicLong(0);\n        final EntryPosition entryPosition = new EntryPosition();\n\n        final MysqlEventParser controller = new MysqlEventParser();\n        final EntryPosition defaultPosition = buildPosition(null, null, 1475116855000L);\n        controller.setSlaveId(3344L);\n        controller.setDetectingEnable(false);\n        controller.setDetectingSQL(DETECTING_SQL);\n        controller.setMasterInfo(buildAuthentication());\n        controller.setMasterPosition(defaultPosition);\n        controller.setEventSink(new AbstractCanalEventSinkTest<List<Entry>>() {\n\n            @Override\n            public boolean sink(List<Entry> entrys, InetSocketAddress remoteAddress, String destination)\n                                                                                                        throws CanalSinkException {\n                for (Entry entry : entrys) {\n                    if (entry.getEntryType() != EntryType.HEARTBEAT) {\n                        entryCount.incrementAndGet();\n\n                        String logfilename = entry.getHeader().getLogfileName();\n                        long logfileoffset = entry.getHeader().getLogfileOffset();\n                        long executeTime = entry.getHeader().getExecuteTime();\n\n                        entryPosition.setJournalName(logfilename);\n                        entryPosition.setPosition(logfileoffset);\n                        entryPosition.setTimestamp(executeTime);\n                        break;\n                    }\n                }\n\n                if (entryCount.get() > 0) {\n                    controller.stop();\n                    timeoutChecker.stop();\n                    timeoutChecker.touch();\n                }\n                return true;\n            }\n        });\n\n        controller.setLogPositionManager(new AbstractLogPositionManager() {\n\n            public void persistLogPosition(String destination, LogPosition logPosition) {\n                System.out.println(logPosition);\n            }\n\n            public LogPosition getLatestIndexBy(String destination) {\n                return null;\n            }\n        });\n\n        controller.start();\n        timeoutChecker.waitForIdle();\n\n        if (controller.isStart()) {\n            controller.stop();\n        }\n\n        // check\n        Assert.assertTrue(entryCount.get() > 0);\n\n        // 对比第一条数据和起始的position相同\n        Assert.assertEquals(entryPosition.getJournalName(), \"mysql-bin.000001\");\n        Assert.assertTrue(entryPosition.getPosition() <= 6163L);\n        Assert.assertTrue(entryPosition.getTimestamp() <= defaultPosition.getTimestamp());\n    }\n\n    @Test\n    public void test_ha() throws InterruptedException {\n        final TimeoutChecker timeoutChecker = new TimeoutChecker(30 * 1000);\n        final AtomicLong entryCount = new AtomicLong(0);\n        final EntryPosition entryPosition = new EntryPosition();\n\n        final MysqlEventParser controller = new MysqlEventParser();\n        final EntryPosition defaultPosition = buildPosition(\"mysql-bin.000001\", 6163L, 1322803601000L);\n        controller.setSlaveId(3344L);\n        controller.setDetectingEnable(false);\n        controller.setMasterInfo(buildAuthentication());\n        controller.setMasterPosition(defaultPosition);\n        controller.setEventSink(new AbstractCanalEventSinkTest<List<Entry>>() {\n\n            @Override\n            public boolean sink(List<Entry> entrys, InetSocketAddress remoteAddress, String destination)\n                                                                                                        throws CanalSinkException {\n                for (Entry entry : entrys) {\n                    if (entry.getEntryType() != EntryType.HEARTBEAT) {\n\n                        entryCount.incrementAndGet();\n\n                        String logfilename = entry.getHeader().getLogfileName();\n                        long logfileoffset = entry.getHeader().getLogfileOffset();\n                        long executeTime = entry.getHeader().getExecuteTime();\n\n                        entryPosition.setJournalName(logfilename);\n                        entryPosition.setPosition(logfileoffset);\n                        entryPosition.setTimestamp(executeTime);\n                        break;\n                    }\n                }\n\n                if (entryCount.get() > 0) {\n                    controller.stop();\n                    timeoutChecker.stop();\n                    timeoutChecker.touch();\n                }\n                return true;\n            }\n        });\n\n        controller.setLogPositionManager(new AbstractLogPositionManager() {\n\n            public void persistLogPosition(String destination, LogPosition logPosition) {\n                System.out.println(logPosition);\n            }\n\n            public LogPosition getLatestIndexBy(String destination) {\n                LogPosition masterLogPosition = new LogPosition();\n                masterLogPosition.setIdentity(new LogIdentity(new InetSocketAddress(\"127.0.0.1\", 3306), 1234L));\n                masterLogPosition.setPostion(new EntryPosition(1322803601000L));\n                return masterLogPosition;\n            }\n        });\n\n        controller.start();\n        timeoutChecker.waitForIdle();\n\n        if (controller.isStart()) {\n            controller.stop();\n        }\n\n        // check\n        Assert.assertTrue(entryCount.get() > 0);\n\n        // 对比第一条数据和起始的position相同\n        Assert.assertEquals(entryPosition.getJournalName(), \"mysql-bin.000001\");\n        Assert.assertTrue(entryPosition.getPosition() <= 6163L);\n        Assert.assertTrue(entryPosition.getTimestamp() <= defaultPosition.getTimestamp());\n    }\n\n    @Test\n    public void test_no_position() throws InterruptedException { // 在某个文件下，找不到对应的timestamp数据，会使用106L\n                                                                 // position进行数据抓取\n        final TimeoutChecker timeoutChecker = new TimeoutChecker(3 * 60 * 1000);\n        final AtomicLong entryCount = new AtomicLong(0);\n        final EntryPosition entryPosition = new EntryPosition();\n\n        final MysqlEventParser controller = new MysqlEventParser();\n        final EntryPosition defaultPosition = buildPosition(\"mysql-bin.000001\",\n            null,\n            new Date().getTime() + 1000 * 1000L);\n        controller.setSlaveId(3344L);\n        controller.setDetectingEnable(false);\n        controller.setMasterInfo(buildAuthentication());\n        controller.setMasterPosition(defaultPosition);\n        controller.setEventSink(new AbstractCanalEventSinkTest<List<Entry>>() {\n\n            @Override\n            public boolean sink(List<Entry> entrys, InetSocketAddress remoteAddress, String destination)\n                                                                                                        throws CanalSinkException {\n                for (Entry entry : entrys) {\n                    if (entry.getEntryType() != EntryType.HEARTBEAT) {\n                        entryCount.incrementAndGet();\n\n                        // String logfilename =\n                        // entry.getHeader().getLogfileName();\n                        // long logfileoffset =\n                        // entry.getHeader().getLogfileOffset();\n                        long executeTime = entry.getHeader().getExecuteTime();\n\n                        // entryPosition.setJournalName(logfilename);\n                        // entryPosition.setPosition(logfileoffset);\n                        entryPosition.setTimestamp(executeTime);\n                        break;\n                    }\n                }\n\n                if (entryCount.get() > 0) {\n                    controller.stop();\n                    timeoutChecker.stop();\n                    timeoutChecker.touch();\n                }\n                return true;\n            }\n        });\n\n        controller.setLogPositionManager(new AbstractLogPositionManager() {\n\n            public void persistLogPosition(String destination, LogPosition logPosition) {\n                System.out.println(logPosition);\n            }\n\n            @Override\n            public LogPosition getLatestIndexBy(String destination) {\n                return null;\n            }\n        });\n\n        controller.start();\n        timeoutChecker.waitForIdle();\n\n        if (controller.isStart()) {\n            controller.stop();\n        }\n\n        // check\n        Assert.assertTrue(entryCount.get() > 0);\n\n        // 对比第一条数据和起始的position相同\n        // Assert.assertEquals(logfilename, \"mysql-bin.000001\");\n        // Assert.assertEquals(106L, logfileoffset);\n        Assert.assertTrue(entryPosition.getTimestamp() < defaultPosition.getTimestamp());\n    }\n\n    // ======================== helper method =======================\n\n    private EntryPosition buildPosition(String binlogFile, Long offest, Long timestamp) {\n        return new EntryPosition(binlogFile, offest, timestamp);\n    }\n\n    private AuthenticationInfo buildAuthentication() {\n        return new AuthenticationInfo(new InetSocketAddress(MYSQL_ADDRESS, 3306), USERNAME, PASSWORD);\n    }\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/inbound/mysql/RdsBinlogEventParserProxyTest.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql;\n\nimport java.net.InetSocketAddress;\nimport java.util.Calendar;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.junit.Assert;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.filter.aviater.AviaterRegexFilter;\nimport com.alibaba.otter.canal.parse.helper.TimeoutChecker;\nimport com.alibaba.otter.canal.parse.inbound.mysql.rds.RdsBinlogEventParserProxy;\nimport com.alibaba.otter.canal.parse.index.AbstractLogPositionManager;\nimport com.alibaba.otter.canal.parse.stub.AbstractCanalEventSinkTest;\nimport com.alibaba.otter.canal.parse.support.AuthenticationInfo;\nimport com.alibaba.otter.canal.protocol.CanalEntry;\nimport com.alibaba.otter.canal.protocol.position.EntryPosition;\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\nimport com.alibaba.otter.canal.sink.exception.CanalSinkException;\n\n/**\n * @author chengjin.lyf on 2018/7/21 下午5:24\n * @since 1.0.25\n */\n@Ignore\npublic class RdsBinlogEventParserProxyTest {\n\n    private static final String DETECTING_SQL = \"insert into retl.xdual values(1,now()) on duplicate key update x=now()\";\n    private static final String MYSQL_ADDRESS = \"\";\n    private static final String USERNAME      = \"\";\n    private static final String PASSWORD      = \"\";\n    public static final String  DBNAME        = \"\";\n    public static final String  TBNAME        = \"\";\n    public static final String  DDL           = \"\";\n\n    @Test\n    public void test_timestamp() throws InterruptedException {\n        final TimeoutChecker timeoutChecker = new TimeoutChecker(3000 * 1000);\n        final AtomicLong entryCount = new AtomicLong(0);\n        final EntryPosition entryPosition = new EntryPosition();\n\n        final RdsBinlogEventParserProxy controller = new RdsBinlogEventParserProxy();\n        Calendar calendar = Calendar.getInstance();\n        calendar.add(Calendar.HOUR_OF_DAY, -24 * 4);\n        final EntryPosition defaultPosition = buildPosition(null, null, calendar.getTimeInMillis());\n        controller.setSlaveId(3344L);\n        controller.setDetectingEnable(false);\n        controller.setDetectingSQL(DETECTING_SQL);\n        controller.setMasterInfo(buildAuthentication());\n        controller.setMasterPosition(defaultPosition);\n        controller.setInstanceId(\"\");\n        controller.setAccesskey(\"\");\n        controller.setSecretkey(\"\");\n        controller.setDirectory(\"/tmp/binlog\");\n        controller.setEventBlackFilter(new AviaterRegexFilter(\"mysql\\\\.*\"));\n        controller.setFilterTableError(true);\n        controller.setBatchFileSize(4);\n        controller.setEventSink(new AbstractCanalEventSinkTest<List<CanalEntry.Entry>>() {\n\n            @Override\n            public boolean sink(List<CanalEntry.Entry> entrys, InetSocketAddress remoteAddress, String destination)\n                                                                                                                   throws CanalSinkException {\n                for (CanalEntry.Entry entry : entrys) {\n                    if (entry.getEntryType() != CanalEntry.EntryType.HEARTBEAT) {\n                        entryCount.incrementAndGet();\n\n                        String logfilename = entry.getHeader().getLogfileName();\n                        long logfileoffset = entry.getHeader().getLogfileOffset();\n                        long executeTime = entry.getHeader().getExecuteTime();\n\n                        entryPosition.setJournalName(logfilename);\n                        entryPosition.setPosition(logfileoffset);\n                        entryPosition.setTimestamp(executeTime);\n                        break;\n                    }\n                }\n                return true;\n            }\n        });\n\n        controller.setLogPositionManager(new AbstractLogPositionManager() {\n\n            private LogPosition logPosition;\n\n            public void persistLogPosition(String destination, LogPosition logPosition) {\n                this.logPosition = logPosition;\n            }\n\n            public LogPosition getLatestIndexBy(String destination) {\n                return logPosition;\n            }\n        });\n\n        controller.start();\n        timeoutChecker.waitForIdle();\n\n        if (controller.isStart()) {\n            controller.stop();\n        }\n\n        // check\n        Assert.assertTrue(entryCount.get() > 0);\n\n        // 对比第一条数据和起始的position相同\n        Assert.assertEquals(entryPosition.getJournalName(), \"mysql-bin.000001\");\n        Assert.assertTrue(entryPosition.getPosition() <= 6163L);\n        Assert.assertTrue(entryPosition.getTimestamp() <= defaultPosition.getTimestamp());\n    }\n\n    // ======================== helper method =======================\n\n    private EntryPosition buildPosition(String binlogFile, Long offest, Long timestamp) {\n        return new EntryPosition(binlogFile, offest, timestamp);\n    }\n\n    private AuthenticationInfo buildAuthentication() {\n        return new AuthenticationInfo(new InetSocketAddress(MYSQL_ADDRESS, 3306), USERNAME, PASSWORD);\n    }\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/inbound/mysql/RdsBinlogOpenApiTest.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql;\n\nimport java.util.Date;\nimport java.util.List;\n\nimport org.apache.commons.lang.time.DateUtils;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.parse.inbound.mysql.rds.RdsBinlogOpenApi;\nimport com.alibaba.otter.canal.parse.inbound.mysql.rds.data.BinlogFile;\nimport com.alibaba.otter.canal.parse.inbound.mysql.rds.data.RdsBackupPolicy;\n\n/**\n * @author agapple 2017年10月15日 下午2:14:34\n * @since 1.0.25\n */\n@Ignore\npublic class RdsBinlogOpenApiTest {\n\n    @Test\n    public void testSimple() throws Throwable {\n        Date startTime = DateUtils.parseDate(\"2018-08-10 12:00:00\", new String[] { \"yyyy-MM-dd HH:mm:ss\" });\n        Date endTime = DateUtils.parseDate(\"2018-08-11 12:00:00\", new String[] { \"yyyy-MM-dd HH:mm:ss\" });\n        String url = \"https://rds.aliyuncs.com/\";\n        String ak = \"\";\n        String sk = \"\";\n        String dbInstanceId = \"\";\n\n        RdsBackupPolicy backupPolicy = RdsBinlogOpenApi.queryBinlogBackupPolicy(url, ak, sk, dbInstanceId);\n        System.out.println(backupPolicy);\n\n        List<BinlogFile> binlogFiles = RdsBinlogOpenApi.listBinlogFiles(url, ak, sk, dbInstanceId, startTime, endTime);\n        System.out.println(binlogFiles);\n    }\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/inbound/mysql/RdsLocalBinlogDumpTest.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql;\n\nimport java.net.InetSocketAddress;\nimport java.nio.charset.Charset;\nimport java.util.List;\n\nimport org.junit.Assert;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.parse.exception.CanalParseException;\nimport com.alibaba.otter.canal.parse.inbound.mysql.rds.RdsLocalBinlogEventParser;\nimport com.alibaba.otter.canal.parse.index.AbstractLogPositionManager;\nimport com.alibaba.otter.canal.parse.stub.AbstractCanalEventSinkTest;\nimport com.alibaba.otter.canal.parse.support.AuthenticationInfo;\nimport com.alibaba.otter.canal.protocol.CanalEntry.Column;\nimport com.alibaba.otter.canal.protocol.CanalEntry.Entry;\nimport com.alibaba.otter.canal.protocol.CanalEntry.EntryType;\nimport com.alibaba.otter.canal.protocol.CanalEntry.EventType;\nimport com.alibaba.otter.canal.protocol.CanalEntry.RowChange;\nimport com.alibaba.otter.canal.protocol.CanalEntry.RowData;\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\nimport com.alibaba.otter.canal.sink.exception.CanalSinkException;\n\n/**\n * @author agapple 2017年10月15日 下午2:16:58\n * @since 1.0.25\n */\n@Ignore\npublic class RdsLocalBinlogDumpTest {\n\n    @Test\n    public void testSimple() {\n        String directory = \"/tmp/rds\";\n        final RdsLocalBinlogEventParser controller = new RdsLocalBinlogEventParser();\n        controller.setMasterInfo(new AuthenticationInfo(new InetSocketAddress(\"127.0.0.1\", 3306), \"root\", \"hello\"));\n        controller.setConnectionCharsetStd(Charset.forName(\"UTF-8\"));\n        controller.setDirectory(directory);\n        controller.setAccesskey(\"\");\n        controller.setSecretkey(\"\");\n        controller.setInstanceId(\"\");\n        controller.setStartTime(1507860498350L);\n        controller.setEventSink(new AbstractCanalEventSinkTest<List<Entry>>() {\n\n            public boolean sink(List<Entry> entrys, InetSocketAddress remoteAddress, String destination)\n                                                                                                        throws CanalSinkException,\n                                                                                                        InterruptedException {\n\n                for (Entry entry : entrys) {\n                    if (entry.getEntryType() == EntryType.TRANSACTIONBEGIN\n                        || entry.getEntryType() == EntryType.TRANSACTIONEND) {\n                        continue;\n                    }\n\n                    if (entry.getEntryType() == EntryType.ROWDATA) {\n                        RowChange rowChange = null;\n                        try {\n                            rowChange = RowChange.parseFrom(entry.getStoreValue());\n                        } catch (Exception e) {\n                            throw new RuntimeException(\"ERROR ## parser of eromanga-event has an error , data:\"\n                                                       + entry.toString(), e);\n                        }\n\n                        EventType eventType = rowChange.getEventType();\n                        System.out.println(String.format(\"================> binlog[%s:%s] , name[%s,%s] , eventType : %s\",\n                            entry.getHeader().getLogfileName(),\n                            entry.getHeader().getLogfileOffset(),\n                            entry.getHeader().getSchemaName(),\n                            entry.getHeader().getTableName(),\n                            eventType));\n\n                        for (RowData rowData : rowChange.getRowDatasList()) {\n                            if (eventType == EventType.DELETE) {\n                                print(rowData.getBeforeColumnsList());\n                            } else if (eventType == EventType.INSERT) {\n                                print(rowData.getAfterColumnsList());\n                            } else {\n                                System.out.println(\"-------> before\");\n                                print(rowData.getBeforeColumnsList());\n                                System.out.println(\"-------> after\");\n                                print(rowData.getAfterColumnsList());\n                            }\n                        }\n                    }\n                }\n\n                return true;\n            }\n\n        });\n        controller.setLogPositionManager(new AbstractLogPositionManager() {\n\n            @Override\n            public LogPosition getLatestIndexBy(String destination) {\n                return null;\n            }\n\n            @Override\n            public void persistLogPosition(String destination, LogPosition logPosition) throws CanalParseException {\n                System.out.println(logPosition);\n            }\n        });\n\n        controller.start();\n\n        try {\n            Thread.sleep(100 * 1000 * 1000L);\n        } catch (InterruptedException e) {\n            Assert.fail(e.getMessage());\n        }\n        controller.stop();\n    }\n\n    private void print(List<Column> columns) {\n        for (Column column : columns) {\n            System.out.println(column.getName() + \" : \" + column.getValue() + \"    update=\" + column.getUpdated());\n        }\n    }\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/inbound/mysql/SimpleDdlParserTest.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql;\n\nimport org.junit.Assert;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.parse.inbound.mysql.ddl.DdlResult;\nimport com.alibaba.otter.canal.parse.inbound.mysql.ddl.SimpleDdlParser;\nimport com.alibaba.otter.canal.protocol.CanalEntry.EventType;\n@Ignore\npublic class SimpleDdlParserTest {\n\n    @Test\n    public void testCreate() {\n        String queryString = \"CREATE TABLE retl_mark ( `ID` int(11)\";\n        DdlResult result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        queryString = \"CREATE TABLE IF NOT EXISTS retl.retl_mark ( `ID` int(11)\";\n        result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        queryString = \"CREATE TABLE IF NOT EXISTS `retl_mark` ( `ID` int(11)\";\n        result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        queryString = \"CREATE TABLE IF NOT EXISTS `retl.retl_mark` ( `ID` int(11)\";\n        result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        queryString = \"CREATE TABLE  `retl`.`retl_mark` (\\n  `ID` int(10) unsigned NOT NULL\";\n        result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        queryString = \"CREATE TABLE  `retl`.`retl_mark`(\\n  `ID` int(10) unsigned NOT NULL\";\n        result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        queryString = \"CREATE table `bak591`.`j_order_log_back_201309` like j_order_log\";\n        result = SimpleDdlParser.parse(queryString, \"bak\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"bak591\", result.getSchemaName());\n        Assert.assertEquals(\"j_order_log_back_201309\", result.getTableName());\n\n        queryString = \"CREATE DEFINER=sco*erce@% PROCEDURE SC_CPN_CODES_SAVE_ACTION(IN cosmosPassportId CHAR(32), IN orderId CHAR(32), IN codeIds TEXT) BEGIN SET @orderId = orderId; SET @timeNow = NOW(); START TRANSACTION; DELETE FROMsc_ord_couponWHEREORDER_ID= @orderId; SET @i=1; SET @numbers = FN_GET_ELEMENTS_COUNT(codeIds, '|'); WHILE @i <= @numbers DO SET @codeId = FN_FIND_ELEMENT_BYINDEX(codeIds, '|', @i); SET @orderCodeId = UUID32(); INSERT INTOsc_ord_coupon(ID,CREATE_BY,CREATE_TIME,UPDATE_BY,UPDATE_TIME,ORDER_ID,CODE_ID`) VALUES(@orderCodeId, cosmosPassportId, @timeNow, cosmosPassportId, @timeNow, @orderId, @codeId); SET @i = @i + 1; END WHILE; COMMIT; END\";\n        result = SimpleDdlParser.parse(queryString, \"bak\");\n        Assert.assertEquals(EventType.QUERY, result.getType());\n    }\n\n    @Test\n    public void testDrop() {\n        String queryString = \"DROP TABLE retl_mark\";\n        DdlResult result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        queryString = \"DROP TABLE IF EXISTS retl.retl_mark;\";\n        result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        queryString = \"DROP TABLE IF EXISTS \\n `retl.retl_mark` /;\";\n        result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        queryString = \"DROP /*!40005 TEMPORARY */  /*!40005 TEMPORARY */ TABLE IF EXISTS `temp_bond_keys`.`temp_bond_key_id`;\";\n        result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"temp_bond_keys\", result.getSchemaName());\n        Assert.assertEquals(\"temp_bond_key_id\", result.getTableName());\n\n        queryString = \"CREATE TABLE performance_schema.cond_instances(NAME \";\n        result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"performance_schema\", result.getSchemaName());\n        Assert.assertEquals(\"cond_instances\", result.getTableName());\n    }\n\n    @Test\n    public void testAlert() {\n        String queryString = \"alter table retl_mark drop index emp_name\";\n        DdlResult result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        queryString = \"alter table retl.retl_mark drop index emp_name\";\n        result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        queryString = \"alter table \\n `retl.retl_mark` drop index emp_name;\";\n        result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n    }\n\n    @Test\n    public void testTruncate() {\n        String queryString = \"truncate table retl_mark\";\n        DdlResult result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        queryString = \"truncate table retl.retl_mark\";\n        result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        queryString = \"truncate \\n  `retl.retl_mark` \";\n        result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n    }\n\n    @Test\n    public void testRename() {\n        String queryString = \"rename table retl_mark to retl_mark2\";\n        DdlResult result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getOriSchemaName());\n        Assert.assertEquals(\"retl\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getOriTableName());\n        Assert.assertEquals(\"retl_mark2\", result.getTableName());\n\n        queryString = \"rename table retl.retl_mark to retl2.retl_mark2\";\n        result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getOriSchemaName());\n        Assert.assertEquals(\"retl2\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getOriTableName());\n        Assert.assertEquals(\"retl_mark2\", result.getTableName());\n\n        queryString = \"rename \\n table \\n `retl`.`retl_mark` to `retl2.retl_mark2`;\";\n        result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getOriSchemaName());\n        Assert.assertEquals(\"retl2\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getOriTableName());\n        Assert.assertEquals(\"retl_mark2\", result.getTableName());\n\n        queryString = \"rename \\n table \\n `retl`.`retl_mark` to `retl2.retl_mark2` , `retl1`.`retl_mark1` to `retl3.retl_mark3`;\";\n        result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getOriSchemaName());\n        Assert.assertEquals(\"retl2\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getOriTableName());\n        Assert.assertEquals(\"retl_mark2\", result.getTableName());\n        result = result.getRenameTableResult();\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl1\", result.getOriSchemaName());\n        Assert.assertEquals(\"retl3\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark1\", result.getOriTableName());\n        Assert.assertEquals(\"retl_mark3\", result.getTableName());\n\n        // 正则匹配test case\n\n        queryString = \"rename table totl_mark to totl_mark2\";\n        result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getOriSchemaName());\n        Assert.assertEquals(\"retl\", result.getSchemaName());\n        Assert.assertEquals(\"totl_mark\", result.getOriTableName());\n        Assert.assertEquals(\"totl_mark2\", result.getTableName());\n\n        queryString = \"rename table totl.retl_mark to totl2.retl_mark2\";\n        result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"totl\", result.getOriSchemaName());\n        Assert.assertEquals(\"totl2\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getOriTableName());\n        Assert.assertEquals(\"retl_mark2\", result.getTableName());\n\n        queryString = \"rename \\n table \\n `totl`.`retl_mark` to `totl2.retl_mark2`;\";\n        result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"totl\", result.getOriSchemaName());\n        Assert.assertEquals(\"totl2\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getOriTableName());\n        Assert.assertEquals(\"retl_mark2\", result.getTableName());\n\n        queryString = \"rename \\n table \\n `totl`.`retl_mark` to `totl2.retl_mark2` , `totl1`.`retl_mark1` to `totl3.retl_mark3`;\";\n        result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"totl\", result.getOriSchemaName());\n        Assert.assertEquals(\"totl2\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getOriTableName());\n        Assert.assertEquals(\"retl_mark2\", result.getTableName());\n        result = result.getRenameTableResult();\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"totl1\", result.getOriSchemaName());\n        Assert.assertEquals(\"totl3\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark1\", result.getOriTableName());\n        Assert.assertEquals(\"retl_mark3\", result.getTableName());\n\n    }\n\n    @Test\n    public void testIndex() {\n        String queryString = \"CREATE UNIQUE INDEX index_1 ON retl_mark(id,x)\";\n        DdlResult result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        queryString = \"create index idx_qca_cid_mcid on q_contract_account (contract_id,main_contract_id)\";\n        result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getSchemaName());\n        Assert.assertEquals(\"q_contract_account\", result.getTableName());\n\n        queryString = \"DROP INDEX index_str ON retl_mark\";\n        result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getSchemaName());\n        Assert.assertEquals(\"retl_mark\", result.getTableName());\n\n        // test index name contains 'on' -- version\n        queryString = \"create index schema_new_index_version_s_idx on q_contract_account (contract_id,main_contract_id)\";\n        result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getSchemaName());\n        Assert.assertEquals(\"q_contract_account\", result.getTableName());\n\n        queryString = \"drop index schema_new_index_version_s_idx on q_contract_account\";\n        result = SimpleDdlParser.parse(queryString, \"retl\");\n        Assert.assertNotNull(result);\n        Assert.assertEquals(\"retl\", result.getSchemaName());\n        Assert.assertEquals(\"q_contract_account\", result.getTableName());\n\n    }\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/inbound/mysql/ddl/DdlResultTest.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.ddl;\n\nimport com.alibaba.otter.canal.parse.inbound.mysql.ddl.DdlResult;\nimport com.alibaba.otter.canal.protocol.CanalEntry.EventType;\nimport org.junit.Assert;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.junit.rules.ExpectedException;\nimport org.junit.rules.Timeout;\n\nimport java.lang.reflect.InvocationTargetException;\n\npublic class DdlResultTest {\n\n  @Rule public final ExpectedException thrown = ExpectedException.none();\n\n  @Rule public final Timeout globalTimeout = new Timeout(10000);\n\n  /* testedClasses: DdlResult */\n  // Test written by Diffblue Cover.\n  @Test\n  public void cloneOutputNotNull() {\n\n    // Arrange\n    final DdlResult objectUnderTest = new DdlResult();\n\n    // Act\n    final DdlResult actual = objectUnderTest.clone();\n\n    // Assert result\n    Assert.assertNotNull(actual);\n    Assert.assertNull(actual.getSchemaName());\n    Assert.assertNull(actual.getType());\n    Assert.assertNull(actual.getOriSchemaName());\n    Assert.assertNull(actual.getTableName());\n    Assert.assertNull(actual.getRenameTableResult());\n    Assert.assertNull(actual.getOriTableName());\n  }\n\n  // Test written by Diffblue Cover.\n\n  @Test\n  public void constructorInputNotNullNotNullNotNullNotNullOutputVoid() {\n\n    // Arrange\n    final String schemaName = \"foo\";\n    final String tableName = \"\\'\";\n    final String oriSchemaName = \"1a 2b 3c\";\n    final String oriTableName = \"BAZ\";\n\n    // Act, creating object to test constructor\n    final DdlResult objectUnderTest =\n        new DdlResult(schemaName, tableName, oriSchemaName, oriTableName);\n\n    // Assert side effects\n    Assert.assertEquals(\"foo\", objectUnderTest.getSchemaName());\n    Assert.assertEquals(\"1a 2b 3c\", objectUnderTest.getOriSchemaName());\n    Assert.assertEquals(\"\\'\", objectUnderTest.getTableName());\n    Assert.assertEquals(\"BAZ\", objectUnderTest.getOriTableName());\n  }\n\n  // Test written by Diffblue Cover.\n\n  @Test\n  public void constructorInputNotNullNotNullOutputVoid() {\n\n    // Arrange\n    final String schemaName = \",\";\n    final String tableName = \"BAZ\";\n\n    // Act, creating object to test constructor\n    final DdlResult objectUnderTest = new DdlResult(schemaName, tableName);\n\n    // Assert side effects\n    Assert.assertEquals(\",\", objectUnderTest.getSchemaName());\n    Assert.assertEquals(\"BAZ\", objectUnderTest.getTableName());\n  }\n\n  // Test written by Diffblue Cover.\n\n  @Test\n  public void constructorInputNotNullOutputVoid() {\n\n    // Arrange\n    final String schemaName = \"3\";\n\n    // Act, creating object to test constructor\n    final DdlResult objectUnderTest = new DdlResult(schemaName);\n\n    // Assert side effects\n    Assert.assertEquals(\"3\", objectUnderTest.getSchemaName());\n  }\n\n  // Test written by Diffblue Cover.\n  @Test\n  public void getOriSchemaNameOutputNull() {\n\n    // Arrange\n    final DdlResult objectUnderTest = new DdlResult();\n\n    // Act\n    final String actual = objectUnderTest.getOriSchemaName();\n\n    // Assert result\n    Assert.assertNull(actual);\n  }\n\n  // Test written by Diffblue Cover.\n  @Test\n  public void getOriTableNameOutputNull() {\n\n    // Arrange\n    final DdlResult objectUnderTest = new DdlResult();\n\n    // Act\n    final String actual = objectUnderTest.getOriTableName();\n\n    // Assert result\n    Assert.assertNull(actual);\n  }\n\n  // Test written by Diffblue Cover.\n  @Test\n  public void getRenameTableResultOutputNull() {\n\n    // Arrange\n    final DdlResult objectUnderTest = new DdlResult();\n\n    // Act\n    final DdlResult actual = objectUnderTest.getRenameTableResult();\n\n    // Assert result\n    Assert.assertNull(actual);\n  }\n\n  // Test written by Diffblue Cover.\n  @Test\n  public void getSchemaNameOutputNull() {\n\n    // Arrange\n    final DdlResult objectUnderTest = new DdlResult();\n\n    // Act\n    final String actual = objectUnderTest.getSchemaName();\n\n    // Assert result\n    Assert.assertNull(actual);\n  }\n\n  // Test written by Diffblue Cover.\n  @Test\n  public void getTableNameOutputNull() {\n\n    // Arrange\n    final DdlResult objectUnderTest = new DdlResult();\n\n    // Act\n    final String actual = objectUnderTest.getTableName();\n\n    // Assert result\n    Assert.assertNull(actual);\n  }\n\n  // Test written by Diffblue Cover.\n  @Test\n  public void getTypeOutputNull() {\n\n    // Arrange\n    final DdlResult objectUnderTest = new DdlResult();\n\n    // Act\n    final EventType actual = objectUnderTest.getType();\n\n    // Assert result\n    Assert.assertNull(actual);\n  }\n\n  // Test written by Diffblue Cover.\n  @Test\n  public void setOriSchemaNameInputNotNullOutputVoid() {\n\n    // Arrange\n    final DdlResult objectUnderTest = new DdlResult();\n    final String oriSchemaName = \"3\";\n\n    // Act\n    objectUnderTest.setOriSchemaName(oriSchemaName);\n\n    // Assert side effects\n    Assert.assertEquals(\"3\", objectUnderTest.getOriSchemaName());\n  }\n\n  // Test written by Diffblue Cover.\n  @Test\n  public void setOriTableNameInputNotNullOutputVoid() {\n\n    // Arrange\n    final DdlResult objectUnderTest = new DdlResult();\n    final String oriTableName = \"3\";\n\n    // Act\n    objectUnderTest.setOriTableName(oriTableName);\n\n    // Assert side effects\n    Assert.assertEquals(\"3\", objectUnderTest.getOriTableName());\n  }\n\n  // Test written by Diffblue Cover.\n  @Test\n  public void setSchemaNameInputNotNullOutputVoid() {\n\n    // Arrange\n    final DdlResult objectUnderTest = new DdlResult();\n    final String schemaName = \"3\";\n\n    // Act\n    objectUnderTest.setSchemaName(schemaName);\n\n    // Assert side effects\n    Assert.assertEquals(\"3\", objectUnderTest.getSchemaName());\n  }\n\n  // Test written by Diffblue Cover.\n  @Test\n  public void setTableNameInputNotNullOutputVoid() {\n\n    // Arrange\n    final DdlResult objectUnderTest = new DdlResult();\n    final String tableName = \"3\";\n\n    // Act\n    objectUnderTest.setTableName(tableName);\n\n    // Assert side effects\n    Assert.assertEquals(\"3\", objectUnderTest.getTableName());\n  }\n\n  // Test written by Diffblue Cover.\n  @Test\n  public void toStringOutputNotNull() {\n\n    // Arrange\n    final DdlResult objectUnderTest = new DdlResult();\n\n    // Act\n    final String actual = objectUnderTest.toString();\n\n    // Assert result\n    Assert.assertEquals(\n        \"DdlResult [schemaName=null , tableName=null , oriSchemaName=null , oriTableName=null , type=null ];\",\n        actual);\n  }\n\n  // Test written by Diffblue Cover.\n\n  @Test\n  public void toStringOutputNotNull2() throws InvocationTargetException {\n\n    // Arrange\n    final DdlResult objectUnderTest = new DdlResult();\n    objectUnderTest.setSchemaName(null);\n    objectUnderTest.setType(null);\n    objectUnderTest.setOriSchemaName(null);\n    objectUnderTest.setTableName(\",\");\n    final DdlResult ddlResult = new DdlResult();\n    objectUnderTest.setRenameTableResult(ddlResult);\n    objectUnderTest.setOriTableName(\"2\");\n\n    // Act\n    final String actual = objectUnderTest.toString();\n\n    // Assert result\n    Assert.assertEquals(\n        \"DdlResult [schemaName=null , tableName=, , oriSchemaName=null , oriTableName=2 , type=null ];DdlResult [schemaName=null , tableName=null , oriSchemaName=null , oriTableName=null , type=null ];\",\n        actual);\n  }\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/inbound/mysql/tsdb/FastsqlSchemaTest.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.tsdb;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport com.alibaba.polardbx.druid.DbType;\nimport com.alibaba.polardbx.druid.sql.SQLUtils;\nimport com.alibaba.polardbx.druid.sql.repository.Schema;\nimport com.alibaba.polardbx.druid.sql.repository.SchemaObject;\nimport com.alibaba.polardbx.druid.sql.repository.SchemaRepository;\nimport com.alibaba.polardbx.druid.sql.visitor.SQLASTOutputVisitor;\nimport com.alibaba.polardbx.druid.sql.visitor.VisitorFeature;\nimport com.alibaba.polardbx.druid.util.JdbcConstants;\n\npublic class FastsqlSchemaTest {\n\n    @Test\n    public void testSimple() throws Throwable {\n        SchemaRepository repository = new SchemaRepository(JdbcConstants.MYSQL);\n        String sql1 = \"CREATE TABLE `table_x1` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, \"\n                      + \"`key1` longtext NOT NULL COMMENT 'key1', `value1` longtext NOT NULL COMMENT 'value1', PRIMARY KEY (`id`) )\"\n                      + \"ENGINE=InnoDB DEFAULT CHARSET=utf8mb4\";\n        repository.console(sql1);\n        repository.setDefaultSchema(\"test\");\n        SchemaObject table = repository.findTable(\"table_x1\");\n        System.out.println(table.getStatement().toString());\n        Assert.assertTrue(table.findColumn(\"value1\") != null);\n    }\n\n    @Test\n    public void test_block_format() throws Throwable {\n        SchemaRepository repository = new SchemaRepository(JdbcConstants.MYSQL);\n        String sql = \" CREATE TABLE `parent` (`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,\"\n                     + \"`created_at` timestamp NULL DEFAULT NULL, \" + \"PRIMARY KEY (`id`)\"\n                     + \") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 BLOCK_FORMAT=ENCRYPTED\";\n        repository.console(sql);\n        repository.setDefaultSchema(\"test\");\n        SchemaObject table = repository.findTable(\"parent\");\n        System.out.println(table.getStatement().toString());\n        Assert.assertTrue(table.findColumn(\"id\") != null);\n    }\n\n    @Test\n    public void test_json_index() throws Throwable {\n        SchemaRepository repository = new SchemaRepository(JdbcConstants.MYSQL);\n        String sql = \" CREATE TABLE `articles` ( `article_id` bigint NOT NULL AUTO_INCREMENT,\"\n                     + \" `tags` json DEFAULT NULL, PRIMARY KEY (`article_id`),\"\n                     + \" KEY `articles_tags` ((cast(json_extract(`tags`,_utf8mb4'$[*]') as char(40))))\"\n                     + \") ENGINE=InnoDB AUTO_INCREMENT=1054 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci\";\n        repository.console(sql);\n        repository.setDefaultSchema(\"test\");\n        SchemaObject table = repository.findTable(\"articles\");\n        System.out.println(table.getStatement().toString());\n        Assert.assertTrue(table.findColumn(\"article_id\") != null);\n    }\n\n    @Test\n    public void test_invisible() throws Throwable {\n        SchemaRepository repository = new SchemaRepository(JdbcConstants.MYSQL);\n        String sql = \" CREATE TABLE `proposal_order_info` (`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,\"\n                     + \"`created_at` timestamp NULL DEFAULT NULL, \" + \"PRIMARY KEY (`id`) , \"\n                     + \"KEY `idx_create_time` (`created_at`)\"\n                     + \") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 BLOCK_FORMAT=ENCRYPTED\";\n        repository.console(sql);\n        repository.setDefaultSchema(\"test\");\n        SchemaObject table = repository.findTable(\"proposal_order_info\");\n        System.out.println(table.getStatement().toString());\n        Assert.assertTrue(table.findColumn(\"id\") != null);\n    }\n\n    @Test\n    public void test_persistent() throws Throwable {\n        SchemaRepository repository = new SchemaRepository(JdbcConstants.MYSQL);\n        String sql = \" create table example_vc_tbl( c1 int not null auto_increment primary key,\"\n                     + \"c2 varchar(70), vc1 int as (length(c2)) virtual,\"\n                     + \"DIM_SUM varchar(128) AS (MD5(UPPER(CONCAT(c2, c1)))) STORED)\";\n        repository.console(sql);\n        repository.setDefaultSchema(\"test\");\n        SchemaObject table = repository.findTable(\"example_vc_tbl\");\n        System.out.println(table.getStatement().toString());\n        Assert.assertTrue(table.findColumn(\"c1\") != null);\n    }\n\n    @Test\n    public void test_primaryKey() throws Throwable {\n        SchemaRepository repository = new SchemaRepository(JdbcConstants.MYSQL);\n        {\n            String sql1 = \"CREATE TABLE test ( id NOT NULL, name varchar(32) ) ENGINE=InnoDB; \";\n            String sql2 = \" ALTER TABLE test add primary key(id);\";\n            repository.console(sql1);\n            String rs = repository.console(sql2);\n            System.out.println(rs);\n            repository.setDefaultSchema(\"test\");\n            SchemaObject table = repository.findTable(\"test\");\n            Assert.assertTrue(table.findColumn(\"id\").isOnlyPrimaryKey());\n        }\n\n        {\n            String sql1 = \"CREATE TABLE test ( id NOT NULL, name varchar(32) ) ENGINE=InnoDB; \";\n            String sql2 = \"ALTER TABLE test MODIFY id bigint AUTO_INCREMENT PRIMARY KEY; \";\n            repository.console(sql1);\n            repository.console(sql2);\n            repository.setDefaultSchema(\"test\");\n            SchemaObject table = repository.findTable(\"test\");\n            Assert.assertTrue(table.findColumn(\"id\").isOnlyPrimaryKey());\n            Assert.assertTrue(table.findColumn(\"id\").isAutoIncrement());\n        }\n    }\n\n    @Test\n    public void test_partition_table() throws Throwable {\n        SchemaRepository repository = new SchemaRepository(JdbcConstants.MYSQL);\n        String sql1 = \"create table test (\\n\" + \" id int not null AUTO_INCREMENT primary key,\\n\"\n                      + \" name varchar(32) \\n\" + \" )\\n\" + \" partition by range(id) (\\n\"\n                      + \" partition p1 values less than (10),\\n\" + \" partition px values less than MAXVALUE\\n\"\n                      + \" );\";\n        String sql2 = \"alter table test add partition ( partition p2 VALUES LESS THAN (738552) ENGINE = InnoDB, PARTITION pmax VALUES LESS THAN MAXVALUE ENGINE = InnoDB)\";\n        repository.console(sql1);\n        repository.console(sql2);\n        repository.setDefaultSchema(\"test\");\n        SchemaObject table = repository.findTable(\"test\");\n        Assert.assertTrue(table != null);\n    }\n\n    @Test\n    public void test_mariadb_aria() throws Throwable {\n        SchemaRepository repository = new SchemaRepository(JdbcConstants.MYSQL);\n        String sql1 = \"CREATE TABLE test (\\n\" + \"db_name varchar(64) COLLATE utf8_bin NOT NULL,\\n\"\n                      + \"table_name varchar(64) COLLATE utf8_bin NOT NULL,\\n\"\n                      + \"column_name varchar(64) COLLATE utf8_bin NOT NULL,\\n\"\n                      + \"min_value varbinary(255) DEFAULT NULL,\\n\" + \"max_value varbinary(255) DEFAULT NULL,\\n\"\n                      + \"nulls_ratio decimal(12,4) DEFAULT NULL,\\n\" + \"avg_length decimal(12,4) DEFAULT NULL,\\n\"\n                      + \"avg_frequency decimal(12,4) DEFAULT NULL,\\n\" + \"hist_size tinyint(3) unsigned DEFAULT NULL,\\n\"\n                      + \"hist_type enum('SINGLE_PREC_HB','DOUBLE_PREC_HB') COLLATE utf8_bin DEFAULT NULL,\\n\"\n                      + \"histogram varbinary(255) DEFAULT NULL,\\n\" + \"PRIMARY KEY (db_name,table_name,column_name)\\n\"\n                      + \") ENGINE=Aria DEFAULT CHARSET=utf8 COLLATE=utf8_bin\";\n        repository.console(sql1);\n        repository.setDefaultSchema(\"test\");\n        SchemaObject table = repository.findTable(\"test\");\n        Assert.assertTrue(table != null);\n    }\n\n    @Test\n    public void test_polardb_x() throws Throwable {\n        SchemaRepository repository = new SchemaRepository(JdbcConstants.MYSQL);\n        repository.setDefaultSchema(\"test\");\n\n        String sql1 = \"CREATE TABLE `test1` (\\n\" + \"  `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,\\n\"\n                      + \"  `serialNo` varchar(64) CHARACTER SET utf8mb4 NOT NULL DEFAULT '',\\n\"\n                      + \"  `user_id` int(11) DEFAULT NULL COMMENT '用户id',\\n\" + \"  PRIMARY KEY (`id`)\\n\"\n                      + \") ENGINE = InnoDB  PARTITION BY KEY(`tenant_id`,`id`)\\n\" + \"PARTITIONS 21 tablegroup = `tg_p_msg`\";\n        repository.console(sql1);\n        SchemaObject table = repository.findTable(\"test1\");\n        Assert.assertTrue(table != null);\n\n\n        String sql2 = \"CREATE TABLE `test2` (\\n\" + \"  `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,\\n\"\n                      + \"  `serialNo` varchar(64) CHARACTER SET utf8mb4 NOT NULL DEFAULT '',\\n\"\n                      + \"  `user_id` int(11) DEFAULT NULL COMMENT '用户id',\\n\" + \"  PRIMARY KEY (`id`)\\n\"\n                      + \") ENGINE = InnoDB single\";\n        repository.console(sql2);\n        table = repository.findTable(\"test2\");\n        Assert.assertTrue(table != null);\n\n\n        String sql3 = \"CREATE TABLE `test3` (\\n\" + \"  `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,\\n\"\n                      + \"  `serialNo` varchar(64) CHARACTER SET utf8mb4 NOT NULL DEFAULT '',\\n\"\n                      + \"  `user_id` int(11) DEFAULT NULL COMMENT '用户id',\\n\" + \"  PRIMARY KEY (`id`)\\n\"\n                      + \") ENGINE = InnoDB locality = 'dn=polardbx-ng28-dn-1,polardbx-ng28-dn-2'\";\n        repository.console(sql3);\n        table = repository.findTable(\"test3\");\n        Assert.assertTrue(table != null);\n\n        String sql4 = \"CREATE TABLE test4(\\n\" + \" order_id int AUTO_INCREMENT primary key,\\n\"\n                      + \" customer_id int,\\n\" + \" country varchar(64),\\n\" + \" city varchar(64),\\n\"\n                      + \" order_time datetime not null)\\n\" + \"PARTITION BY LIST COLUMNS(country,city)\\n\" + \"(\\n\"\n                      + \"  PARTITION p1 VALUES IN (('China','Shanghai')) LOCALITY = 'dn=polardbx-ng28-dn-2',\\n\"\n                      + \"  PARTITION p2 VALUES IN (('China','Beijing')) LOCALITY = 'dn=polardbx-ng28-dn-2',\\n\"\n                      + \"  PARTITION p3 VALUES IN (('China','Hangzhou')) ,\\n\"\n                      + \"  PARTITION p4 VALUES IN (('China','Nanjing')) ,\\n\"\n                      + \"  PARTITION p5 VALUES IN (('China','Guangzhou')) ,\\n\"\n                      + \"  PARTITION p6 VALUES IN (('China','Shenzhen')) ,\\n\"\n                      + \"  PARTITION p7 VALUES IN (('China','Wuhan')) ,\\n\"\n                      + \"  PARTITION p8 VALUES IN (('America','New York'))\\n\"\n                      + \") LOCALITY = 'dn=polardbx-ng28-dn-0,polardbx-ng28-dn-1';\";\n        repository.console(sql4);\n        table = repository.findTable(\"test4\");\n        Assert.assertTrue(table != null);\n\n        String sql5 = \"CREATE TABLE `test5` (\\n\" + \"\\t`Id` varchar(32) NOT NULL COMMENT '',\\n\"\n                      + \"\\t`ExitId` varchar(32) NOT NULL COMMENT '',\\n\"\n                      + \"\\t`CreateTime` datetime NOT NULL COMMENT '创建时间',\\n\"\n                      + \"\\t`archive_date` datetime NOT NULL DEFAULT '2099-01-01 00:00:00',\\n\"\n                      + \"\\tPRIMARY KEY (`Id`, `archive_date`),\\n\"\n                      + \"\\tGLOBAL INDEX `g_i_id` (`id`) COVERING (`ExitId`) \\n\" + \"\\t\\tPARTITION BY KEY(`Id`)\\n\"\n                      + \"\\t\\tPARTITIONS 16,\\n\" + \"\\tKEY `ExitId` USING BTREE (`ExitId`),\\n\"\n                      + \"\\tKEY `CreateTime` (`CreateTime`),\\n\" + \"\\tKEY `i_id_ExitId` USING BTREE (`Id`, `ExitId`),\\n\"\n                      + \"\\tKEY `auto_shard_key_ExitId_id` USING BTREE (`ExitId`, `Id`)\\n\"\n                      + \") ENGINE = InnoDB DEFAULT CHARSET = utf8\\n\" + \"PARTITION BY KEY(`ExitId`,`Id`)\\n\"\n                      + \"PARTITIONS 16\\n\" + \"LOCAL PARTITION BY RANGE (archive_date)\\n\" + \"INTERVAL 1 MONTH\\n\"\n                      + \"EXPIRE AFTER 27\\n\" + \"PRE ALLOCATE 2\\n\" + \"PIVOTDATE NOW()\";\n        repository.console(sql5);\n        table = repository.findTable(\"test5\");\n        Assert.assertTrue(table != null);\n    }\n\n    @Test\n    public void test_escapse_sql() {\n        SchemaRepository repository = new SchemaRepository(JdbcConstants.MYSQL);\n        repository.setDefaultSchema(\"test\");\n        String sql = \"CREATE TABLE test1 (\\n\" + \"\\tid int(11) NOT NULL AUTO_INCREMENT,\\n\"\n                     + \"\\tcluster_id int(11) NOT NULL COMMENT '集群id',\\n\"\n                     + \"\\tcomponent_id int(11) NOT NULL COMMENT '组件id',\\n\"\n                     + \"\\tcomponent_type_code tinyint(1) NOT NULL COMMENT '组件类型',\\n\"\n                     + \"\\ttype varchar(128) COLLATE utf8_bin NOT NULL COMMENT '配置类型',\\n\"\n                     + \"\\trequired tinyint(1) NOT NULL COMMENT 'true/false',\\n\"\n                     + \"\\t`key` varchar(256) COLLATE utf8_bin NOT NULL COMMENT '配置键',\\n\"\n                     + \"\\t`value` text COLLATE utf8_bin COMMENT '默认配置项',\\n\"\n                     + \"\\t`values` varchar(512) COLLATE utf8_bin DEFAULT NULL COMMENT '可配置项',\\n\"\n                     + \"\\tdependencyKey varchar(256) COLLATE utf8_bin DEFAULT NULL COMMENT '依赖键',\\n\"\n                     + \"\\tdependencyValue varchar(256) COLLATE utf8_bin DEFAULT NULL COMMENT '依赖值',\\n\"\n                     + \"\\t`desc` varchar(512) COLLATE utf8_bin DEFAULT NULL COMMENT '描述',\\n\"\n                     + \"\\tgmt_create datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\\n\"\n                     + \"\\tgmt_modified datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',\\n\"\n                     + \"\\tis_deleted tinyint(1) NOT NULL DEFAULT '0' COMMENT '0正常 1逻辑删除',\\n\" + \"\\tPRIMARY KEY (id),\\n\"\n                     + \"\\tKEY index_cluster_id (cluster_id),\\n\" + \"\\tKEY index_componentId (component_id)\\n\"\n                     + \") ENGINE = InnoDB AUTO_INCREMENT = 1140 CHARSET = utf8 COLLATE = utf8_bin;\";\n        repository.console(sql);\n        SchemaObject table = repository.findTable(\"test1\");\n        Assert.assertTrue(table != null);\n        // 应用到新的schema\n        Schema schema = repository.findSchema(\"test\");\n        StringBuilder data = new StringBuilder(4 * 1024);\n        for (String tableIn : schema.showTables()) {\n            SchemaObject schemaObject = schema.findTable(tableIn);\n\n            SQLASTOutputVisitor visitor = SQLUtils.createOutputVisitor(data, DbType.mysql);\n            visitor.config(VisitorFeature.OutputNameQuote, true);\n\n            schemaObject.getStatement().accept(visitor);\n            data.append(\"; \\n\");\n        }\n\n        repository.setDefaultSchema(\"test_new\");\n        repository.console(data.toString());\n        table = repository.findTable(\"test1\");\n        Assert.assertTrue(table != null);\n\n        // 打印新的schema的内容\n        schema = repository.findSchema(\"test_new\");\n        data = new StringBuilder(4 * 1024);\n        for (String tableIn : schema.showTables()) {\n            SchemaObject schemaObject = schema.findTable(tableIn);\n\n            SQLASTOutputVisitor visitor = SQLUtils.createOutputVisitor(data, DbType.mysql);\n            visitor.config(VisitorFeature.OutputNameQuote, true);\n\n            schemaObject.getStatement().accept(visitor);\n            data.append(\"; \\n\");\n        }\n\n        System.out.println(data.toString());\n    }\n\n\n    @Test\n    public void test_escapse_sql2() {\n        SchemaRepository repository = new SchemaRepository(JdbcConstants.MYSQL);\n        repository.setDefaultSchema(\"test\");\n        String sql = \"CREATE TABLE test1 (\\n\" + \"id int(11) NOT NULL AUTO_INCREMENT,\\n\"\n                     + \"uid int(11) NOT NULL DEFAULT '0' COMMENT '用户ID',\\n\"\n                     + \"`from` tinyint(3) NOT NULL DEFAULT '0' COMMENT '来源 1QQ 2微信 3微博',\\n\"\n                     + \"access_code varchar(20) NOT NULL DEFAULT '' COMMENT '临时code',\\n\"\n                     + \"access_token varchar(200) NOT NULL DEFAULT '' COMMENT '授权token',\\n\"\n                     + \"expires_in int(11) NOT NULL DEFAULT '0' COMMENT '过期时间',\\n\"\n                     + \"refresh_token varchar(200) NOT NULL DEFAULT '' COMMENT '刷新token',\\n\"\n                     + \"openid varchar(255) NOT NULL DEFAULT '' COMMENT '授权用户唯一标识',\\n\"\n                     + \"scope varchar(60) NOT NULL COMMENT '授权范围',\\n\"\n                     + \"status tinyint(3) NOT NULL DEFAULT '1' COMMENT '1 ',\\n\"\n                     + \"json_info text NOT NULL COMMENT '个人信息',\\n\"\n                     + \"create_time timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '创建时间',\\n\"\n                     + \"unionid varchar(128) NOT NULL DEFAULT '' COMMENT 'UnionID',\\n\"\n                     + \"session_key varchar(128) NOT NULL DEFAULT '' COMMENT '小程序session_key',\\n\"\n                     + \"PRIMARY KEY (id),\\n\" + \"KEY uid (uid),\\n\"\n                     + \"KEY idx_openid_from_status (openid, `from`, status),\\n\" + \"KEY idx_access_token (access_token),\\n\"\n                     + \"KEY idx_uid_from_status (uid, `from`, status),\\n\"\n                     + \"KEY idx_unionid_from_status (unionid, `from`, status)\\n\"\n                     + \") ENGINE = InnoDB AUTO_INCREMENT = 7831300 CHARSET = utf8 COMMENT '用户第三方登录表'\";\n        repository.console(sql);\n        SchemaObject table = repository.findTable(\"test1\");\n        Assert.assertTrue(table != null);\n\n        // 应用到新的schema\n        Schema schema = repository.findSchema(\"test\");\n        StringBuilder data = new StringBuilder(4 * 1024);\n        for (String tableIn : schema.showTables()) {\n            SchemaObject schemaObject = schema.findTable(tableIn);\n\n            SQLASTOutputVisitor visitor = SQLUtils.createOutputVisitor(data, DbType.mysql);\n            visitor.config(VisitorFeature.OutputNameQuote, true);\n\n            schemaObject.getStatement().accept(visitor);\n            data.append(\"; \\n\");\n        }\n\n        repository.setDefaultSchema(\"test_new\");\n        repository.console(data.toString());\n        table = repository.findTable(\"test1\");\n        Assert.assertTrue(table != null);\n\n        // 打印新的schema的内容\n        schema = repository.findSchema(\"test_new\");\n        data = new StringBuilder(4 * 1024);\n        for (String tableIn : schema.showTables()) {\n            SchemaObject schemaObject = schema.findTable(tableIn);\n\n            SQLASTOutputVisitor visitor = SQLUtils.createOutputVisitor(data, DbType.mysql);\n            visitor.config(VisitorFeature.OutputNameQuote, true);\n\n            schemaObject.getStatement().accept(visitor);\n            data.append(\"; \\n\");\n        }\n\n        System.out.println(data.toString());\n    }\n\n\n    @Test\n    public void test_function_index () throws Throwable {\n        SchemaRepository repository = new SchemaRepository(JdbcConstants.MYSQL);\n        repository.setDefaultSchema(\"test\");\n        String sql = \"CREATE TABLE test1 (\\n\" + \"    id INT AUTO_INCREMENT PRIMARY KEY,\\n\"\n                     + \"    owner_id INT NOT NULL,\\n\" + \"    code VARCHAR(100) NOT NULL,\\n\"\n                     + \"    UNIQUE KEY uk_owner_id_upper_code (owner_id, (upper(code)))\\n\" + \");\";\n        repository.console(sql);\n        SchemaObject table = repository.findTable(\"test1\");\n        Assert.assertTrue(table != null);\n    }\n\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/inbound/mysql/tsdb/MemoryTableMetaTest.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.tsdb;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.net.URL;\n\nimport org.apache.commons.io.IOUtils;\nimport org.apache.commons.lang.StringUtils;\nimport org.junit.Assert;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\nimport com.alibaba.otter.canal.parse.inbound.TableMeta;\n\n/**\n * @author agapple 2017年8月1日 下午7:15:54\n */\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(locations = { \"/tsdb/mysql-tsdb.xml\" })\n@Ignore\npublic class MemoryTableMetaTest {\n\n    @Test\n    public void testSimple() throws Throwable {\n        MemoryTableMeta memoryTableMeta = new MemoryTableMeta();\n        URL url = Thread.currentThread().getContextClassLoader().getResource(\"dummy.txt\");\n        File dummyFile = new File(url.getFile());\n        File create = new File(dummyFile.getParent() + \"/ddl\", \"create.sql\");\n        String sql = StringUtils.join(IOUtils.readLines(new FileInputStream(create)), \"\\n\");\n        memoryTableMeta.apply(null, \"test\", sql, null);\n\n        TableMeta meta = memoryTableMeta.find(\"test\", \"test\");\n        System.out.println(meta);\n        Assert.assertTrue(meta.getFieldMetaByName(\"ID\").isKey());\n    }\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/inbound/mysql/tsdb/MemoryTableMeta_DDL_Test.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.tsdb;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.apache.commons.io.IOUtils;\nimport org.apache.commons.lang.StringUtils;\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\nimport com.alibaba.polardbx.druid.sql.repository.Schema;\nimport com.alibaba.otter.canal.parse.inbound.TableMeta;\n\n/**\n * @author agapple 2017年8月1日 下午7:15:54\n */\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(locations = { \"/tsdb/h2-tsdb.xml\" })\npublic class MemoryTableMeta_DDL_Test {\n\n    @Test\n    public void test1() throws Throwable {\n        MemoryTableMeta memoryTableMeta = new MemoryTableMeta();\n        URL url = Thread.currentThread().getContextClassLoader().getResource(\"dummy.txt\");\n        File dummyFile = new File(url.getFile());\n        File create = new File(dummyFile.getParent() + \"/ddl\", \"ddl_test1.sql\");\n        String sql = StringUtils.join(IOUtils.readLines(new FileInputStream(create)), \"\\n\");\n        memoryTableMeta.apply(null, \"test\", sql, null);\n\n        TableMeta meta = memoryTableMeta.find(\"yushitai_test\", \"card_record\");\n        System.out.println(meta);\n        Assert.assertNotNull(meta.getFieldMetaByName(\"customization_id\"));\n\n        meta = memoryTableMeta.find(\"yushitai_test\", \"_card_record_gho\");\n        Assert.assertNull(meta);\n    }\n\n    @Test\n    public void test2() throws Throwable {\n        MemoryTableMeta memoryTableMeta = new MemoryTableMeta();\n        URL url = Thread.currentThread().getContextClassLoader().getResource(\"dummy.txt\");\n        File dummyFile = new File(url.getFile());\n        File create = new File(dummyFile.getParent() + \"/ddl\", \"ddl_test2.sql\");\n        String sql = StringUtils.join(IOUtils.readLines(new FileInputStream(create)), \"\\n\");\n        memoryTableMeta.apply(null, \"test\", sql, null);\n\n        TableMeta meta = memoryTableMeta.find(\"yushitai_test\", \"card_record\");\n        System.out.println(meta);\n        Assert.assertEquals(meta.getFieldMetaByName(\"id\").isKey(), true);\n        Assert.assertEquals(meta.getFieldMetaByName(\"name\").isUnique(), true);\n    }\n\n    @Test\n    public void test3() throws Throwable {\n        MemoryTableMeta memoryTableMeta = new MemoryTableMeta();\n        URL url = Thread.currentThread().getContextClassLoader().getResource(\"dummy.txt\");\n        File dummyFile = new File(url.getFile());\n        File create = new File(dummyFile.getParent() + \"/ddl\", \"ddl_test3.sql\");\n        String sql = StringUtils.join(IOUtils.readLines(new FileInputStream(create)), \"\\n\");\n        memoryTableMeta.apply(null, \"test\", sql, null);\n\n        TableMeta meta = memoryTableMeta.find(\"test\", \"quniya4\");\n        System.out.println(meta);\n        Assert.assertTrue(meta.getFields().get(0).getColumnName().equalsIgnoreCase(\"id\"));\n    }\n\n    @Test\n    public void test_any() throws Throwable {\n        MemoryTableMeta memoryTableMeta = new MemoryTableMeta();\n        URL url = Thread.currentThread().getContextClassLoader().getResource(\"dummy.txt\");\n        File dummyFile = new File(url.getFile());\n        File create = new File(dummyFile.getParent() + \"/ddl\", \"ddl_any.sql\");\n        String sql = StringUtils.join(IOUtils.readLines(new FileInputStream(create)), \"\\n\");\n        memoryTableMeta.apply(null, \"test\", sql, null);\n\n        List<String> tableNames = new ArrayList<>();\n        for (Schema schema : memoryTableMeta.getRepository().getSchemas()) {\n            tableNames.addAll(schema.showTables());\n        }\n\n        for (String table : tableNames) {\n            TableMeta sourceMeta = memoryTableMeta.find(\"test\", table);\n            System.out.println(sourceMeta.toString());\n        }\n    }\n\n    @Test\n    public void test_create_if_not_exist() throws Throwable {\n        MemoryTableMeta memoryTableMeta = new MemoryTableMeta();\n        URL url = Thread.currentThread().getContextClassLoader().getResource(\"dummy.txt\");\n        File dummyFile = new File(url.getFile());\n        File create = new File(dummyFile.getParent() + \"/ddl\", \"ddl_create_if_not_exist.sql\");\n        String sql = StringUtils.join(IOUtils.readLines(new FileInputStream(create)), \"\\n\");\n        memoryTableMeta.apply(null, \"test\", sql, null);\n\n        List<String> tableNames = new ArrayList<>();\n        for (Schema schema : memoryTableMeta.getRepository().getSchemas()) {\n            tableNames.addAll(schema.showTables());\n        }\n\n        for (String table : tableNames) {\n            TableMeta sourceMeta = memoryTableMeta.find(\"test\", table);\n            System.out.println(sourceMeta.toString());\n        }\n    }\n\n    @Test\n    public void test_function_index () throws Throwable {\n        MemoryTableMeta memoryTableMeta = new MemoryTableMeta();\n        URL url = Thread.currentThread().getContextClassLoader().getResource(\"dummy.txt\");\n        File dummyFile = new File(url.getFile());\n        File create = new File(dummyFile.getParent() + \"/ddl\", \"ddl_create_function_index.sql\");\n        String sql = StringUtils.join(IOUtils.readLines(new FileInputStream(create)), \"\\n\");\n        memoryTableMeta.apply(null, \"test\", sql, null);\n\n        List<String> tableNames = new ArrayList<>();\n        for (Schema schema : memoryTableMeta.getRepository().getSchemas()) {\n            tableNames.addAll(schema.showTables());\n        }\n\n        for (String table : tableNames) {\n            TableMeta sourceMeta = memoryTableMeta.find(\"test\", table);\n            TableMeta.FieldMeta field = sourceMeta.getFieldMetaByName(\"code\");\n            System.out.println(sourceMeta.toString());\n            Assert.assertTrue(field.isUnique());\n        }\n    }\n\n    @Test\n    public void test_polardbx_columnar_index () throws Throwable {\n        MemoryTableMeta memoryTableMeta = new MemoryTableMeta();\n        URL url = Thread.currentThread().getContextClassLoader().getResource(\"dummy.txt\");\n        File dummyFile = new File(url.getFile());\n        File create = new File(dummyFile.getParent() + \"/ddl\", \"ddl_test4.sql\");\n        String sql = StringUtils.join(IOUtils.readLines(new FileInputStream(create)), \"\\n\");\n        memoryTableMeta.apply(null, \"test\", sql, null);\n\n        List<String> tableNames = new ArrayList<>();\n        for (Schema schema : memoryTableMeta.getRepository().getSchemas()) {\n            tableNames.addAll(schema.showTables());\n        }\n\n        for (String table : tableNames) {\n            TableMeta sourceMeta = memoryTableMeta.find(\"test\", table);\n            TableMeta.FieldMeta field = sourceMeta.getFieldMetaByName(\"address\");\n            System.out.println(sourceMeta.toString());\n            Assert.assertTrue(field.isUnique());\n        }\n    }\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/inbound/mysql/tsdb/MemoryTableMeta_Random_DDL_Test.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.tsdb;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.apache.commons.io.IOUtils;\nimport org.apache.commons.lang.StringUtils;\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\nimport com.alibaba.polardbx.druid.sql.repository.Schema;\nimport com.alibaba.otter.canal.parse.inbound.TableMeta;\n\n/**\n * @author agapple 2017年8月1日 下午7:15:54\n */\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(locations = { \"/tsdb/h2-tsdb.xml\" })\npublic class MemoryTableMeta_Random_DDL_Test {\n\n    @Test\n    public void test_database() throws Throwable {\n        URL url = Thread.currentThread().getContextClassLoader().getResource(\"dummy.txt\");\n        File dummyFile = new File(url.getFile());\n        int number = 39;\n        for (int i = 1; i <= number; i++) {\n            File sourceFile = new File(dummyFile.getParent() + \"/ddl/table\", \"test_\" + i + \".sql\");\n            String sourceSql = StringUtils.join(IOUtils.readLines(new FileInputStream(sourceFile)), \"\\n\");\n            MemoryTableMeta source = new MemoryTableMeta();\n            source.apply(null, \"test\", sourceSql, null);\n\n            File targetFile = new File(dummyFile.getParent() + \"/ddl/table\", \"mysql_\" + i + \".sql\");\n            String targetSql = StringUtils.join(IOUtils.readLines(new FileInputStream(targetFile)), \"\\n\");\n            MemoryTableMeta target = new MemoryTableMeta();\n            target.apply(null, \"test\", targetSql, null);\n\n            compareTableMeta(i, source, target);\n        }\n    }\n\n    @Test\n    public void test_table() throws Throwable {\n        URL url = Thread.currentThread().getContextClassLoader().getResource(\"dummy.txt\");\n        File dummyFile = new File(url.getFile());\n        int number = 80;\n        for (int i = 1; i <= number; i++) {\n            try {\n                File sourceFile = new File(dummyFile.getParent() + \"/ddl/alter\", \"test_\" + i + \".sql\");\n                String sourceSql = StringUtils.join(IOUtils.readLines(new FileInputStream(sourceFile)), \"\\n\");\n                MemoryTableMeta source = new MemoryTableMeta();\n                source.apply(null, \"test\", sourceSql, null);\n\n                File targetFile = new File(dummyFile.getParent() + \"/ddl/alter\", \"mysql_\" + i + \".sql\");\n                String targetSql = StringUtils.join(IOUtils.readLines(new FileInputStream(targetFile)), \"\\n\");\n                MemoryTableMeta target = new MemoryTableMeta();\n                target.apply(null, \"test\", targetSql, null);\n\n                compareTableMeta(i, source, target);\n            } catch (Throwable e) {\n                Assert.fail(\"case : \" + i + \" failed by : \" + e.getMessage());\n            }\n        }\n    }\n\n    private void compareTableMeta(int num, MemoryTableMeta source, MemoryTableMeta target) {\n        List<String> tableNames = new ArrayList<>();\n        for (Schema schema : source.getRepository().getSchemas()) {\n            tableNames.addAll(schema.showTables());\n        }\n\n        for (String table : tableNames) {\n            TableMeta sourceMeta = source.find(\"test\", table);\n            TableMeta targetMeta = target.find(\"test\", table);\n            boolean result = DatabaseTableMeta.compareTableMeta(sourceMeta, targetMeta);\n            if (!result) {\n                Assert.fail(sourceMeta.toString() + \" vs \" + targetMeta.toString());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/inbound/mysql/tsdb/MetaHistoryDAOTest.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.tsdb;\n\nimport java.util.List;\n\nimport javax.annotation.Resource;\n\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\nimport com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao.MetaHistoryDAO;\nimport com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao.MetaHistoryDO;\n\n/**\n * Created by wanshao Date: 2017/9/20 Time: 下午5:00\n **/\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(locations = { \"/tsdb/h2-tsdb.xml\" })\n@Ignore\npublic class MetaHistoryDAOTest {\n\n    @Resource\n    MetaHistoryDAO metaHistoryDAO;\n\n    @Test\n    public void testSimple() {\n        MetaHistoryDO historyDO = new MetaHistoryDO();\n        historyDO.setDestination(\"test\");\n        historyDO.setBinlogFile(\"000001\");\n        historyDO.setBinlogOffest(4L);\n        historyDO.setBinlogMasterId(\"1\");\n        historyDO.setBinlogTimestamp(System.currentTimeMillis() - 7300 * 1000);\n        historyDO.setSqlSchema(\"test\");\n        historyDO.setUseSchema(\"test\");\n        historyDO.setSqlTable(\"testTable\");\n        historyDO.setSqlTable(\"drop table testTable\");\n        metaHistoryDAO.insert(historyDO);\n\n        int count = metaHistoryDAO.deleteByTimestamp(\"test\", 7200);\n        System.out.println(count);\n\n        List<MetaHistoryDO> metaHistoryDOList = metaHistoryDAO.findByTimestamp(\"test\", 0L, System.currentTimeMillis());\n        for (MetaHistoryDO metaHistoryDO : metaHistoryDOList) {\n            System.out.println(metaHistoryDO.getId());\n        }\n    }\n\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/inbound/mysql/tsdb/MetaSnapshotDAOTest.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.tsdb;\n\nimport javax.annotation.Resource;\n\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\nimport com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao.MetaSnapshotDAO;\nimport com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao.MetaSnapshotDO;\n\n/**\n * Created by wanshao Date: 2017/9/20 Time: 下午5:00\n **/\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(locations = { \"/tsdb/h2-tsdb.xml\" })\npublic class MetaSnapshotDAOTest {\n\n    @Resource\n    MetaSnapshotDAO metaSnapshotDAO;\n\n    @Ignore\n    @Test\n    public void testSimple() {\n        MetaSnapshotDO metaSnapshotDO = new MetaSnapshotDO();\n        metaSnapshotDO.setDestination(\"test\");\n        metaSnapshotDO.setBinlogFile(\"000001\");\n        metaSnapshotDO.setBinlogOffest(4L);\n        metaSnapshotDO.setBinlogMasterId(\"1\");\n        metaSnapshotDO.setBinlogTimestamp(System.currentTimeMillis() - 7300 * 1000);\n        metaSnapshotDO.setData(\"test\");\n        metaSnapshotDAO.insert(metaSnapshotDO);\n\n        MetaSnapshotDO snapshotDO = metaSnapshotDAO.findByTimestamp(\"test\", System.currentTimeMillis());\n        System.out.println(snapshotDO);\n\n        int count = metaSnapshotDAO.deleteByTimestamp(\"test\", 7200);\n        System.out.println(count);\n    }\n\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/inbound/mysql/tsdb/TableMetaManagerBuilderTest.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.tsdb;\n\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.springframework.util.Assert;\n\n/**\n * @author agapple 2017年10月12日 上午10:50:00\n * @since 1.0.25\n */\npublic class TableMetaManagerBuilderTest {\n\n    @Ignore\n    @Test\n    public void testSimple() {\n        TableMetaTSDB tableMetaTSDB = TableMetaTSDBBuilder.build(\"test\", \"classpath:tsdb/mysql-tsdb.xml\");\n        Assert.notNull(tableMetaTSDB);\n        TableMetaTSDBBuilder.destory(\"test\");\n    }\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/inbound/mysql/tsdb/TableMetaManagerTest.java",
    "content": "package com.alibaba.otter.canal.parse.inbound.mysql.tsdb;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.net.URL;\n\nimport javax.annotation.Resource;\n\nimport org.apache.commons.io.IOUtils;\nimport org.apache.commons.lang.StringUtils;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\nimport com.alibaba.otter.canal.protocol.position.EntryPosition;\n\n/**\n * @author wanshao 2017年8月2日 下午4:11:45\n * @since 3.2.5\n */\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(locations = { \"/tsdb/h2-tsdb.xml\" })\n@Ignore\npublic class TableMetaManagerTest {\n\n    @Resource\n    DatabaseTableMeta tableMetaManager;\n\n    @Test\n    public void testSimple() throws FileNotFoundException, IOException {\n        tableMetaManager.init(\"test\");\n\n        URL url = Thread.currentThread().getContextClassLoader().getResource(\"dummy.txt\");\n        File dummyFile = new File(url.getFile());\n        File create = new File(dummyFile.getParent() + \"/ddl\", \"create.sql\");\n        EntryPosition position = new EntryPosition(\"mysql-bin.001115\", 139177334L, 3065927853L, 1501660815000L);\n        String createSql = StringUtils.join(IOUtils.readLines(new FileInputStream(create)), \"\\n\");\n        tableMetaManager.apply(position, \"tddl5_00\", createSql, null);\n\n        String alterSql = \"alter table `test` add column name varchar(32) after c_varchar\";\n        position = new EntryPosition(\"mysql-bin.001115\", 139177334L, 3065927854L, 1501660815000L);\n        tableMetaManager.apply(position, \"tddl5_00\", alterSql, null);\n    }\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/index/AbstractLogPositionManagerTest.java",
    "content": "package com.alibaba.otter.canal.parse.index;\n\nimport java.net.InetSocketAddress;\nimport java.util.Date;\n\nimport org.junit.Assert;\n\nimport com.alibaba.otter.canal.protocol.position.EntryPosition;\nimport com.alibaba.otter.canal.protocol.position.LogIdentity;\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\nimport org.junit.Ignore;\n\n@Ignore\npublic class AbstractLogPositionManagerTest extends AbstractZkTest {\n\n    private static final String MYSQL_ADDRESS = \"127.0.0.1\";\n\n    public LogPosition doTest(CanalLogPositionManager logPositionManager) {\n        LogPosition getPosition = logPositionManager.getLatestIndexBy(destination);\n        Assert.assertNull(getPosition);\n\n        LogPosition postion1 = buildPosition(1);\n        logPositionManager.persistLogPosition(destination, postion1);\n        LogPosition getPosition1 = logPositionManager.getLatestIndexBy(destination);\n        Assert.assertEquals(postion1, getPosition1);\n\n        LogPosition postion2 = buildPosition(2);\n        logPositionManager.persistLogPosition(destination, postion2);\n        LogPosition getPosition2 = logPositionManager.getLatestIndexBy(destination);\n        Assert.assertEquals(postion2, getPosition2);\n        return postion2;\n    }\n\n    protected LogPosition buildPosition(int number) {\n        LogPosition position = new LogPosition();\n        position.setIdentity(new LogIdentity(new InetSocketAddress(MYSQL_ADDRESS, 3306), 1234L));\n        position.setPostion(new EntryPosition(\"mysql-bin.000000\" + number, 106L, new Date().getTime()));\n        return position;\n    }\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/index/AbstractZkTest.java",
    "content": "package com.alibaba.otter.canal.parse.index;\n\nimport org.junit.Assert;\n\npublic class AbstractZkTest {\n\n    protected String destination = \"ljhtest1\";\n    protected String cluster1    = \"127.0.0.1:2188\";\n    protected String cluster2    = \"127.0.0.1:2188,127.0.0.1:2188\";\n\n    public void sleep(long time) {\n        try {\n            Thread.sleep(time);\n        } catch (InterruptedException e) {\n            Assert.fail(e.getMessage());\n        }\n    }\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/index/FileMixedLogPositionManagerTest.java",
    "content": "package com.alibaba.otter.canal.parse.index;\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport org.apache.commons.io.FileUtils;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\n@Ignore\npublic class FileMixedLogPositionManagerTest extends AbstractLogPositionManagerTest {\n\n    private static final String tmp     = System.getProperty(\"java.io.tmpdir\", \"/tmp\");\n    private static final File   dataDir = new File(tmp, \"canal\");\n\n    @Before\n    public void setUp() {\n        try {\n            FileUtils.deleteDirectory(dataDir);\n        } catch (IOException e) {\n            Assert.fail(e.getMessage());\n        }\n    }\n\n    @Test\n    public void testAll() {\n        MemoryLogPositionManager memoryLogPositionManager = new MemoryLogPositionManager();\n\n        FileMixedLogPositionManager logPositionManager = new FileMixedLogPositionManager(dataDir,\n            1000,\n            memoryLogPositionManager);\n        logPositionManager.start();\n\n        LogPosition position2 = doTest(logPositionManager);\n        sleep(1500);\n\n        FileMixedLogPositionManager logPositionManager2 = new FileMixedLogPositionManager(dataDir,\n            1000,\n            memoryLogPositionManager);\n        logPositionManager2.start();\n\n        LogPosition getPosition2 = logPositionManager2.getLatestIndexBy(destination);\n        Assert.assertEquals(position2, getPosition2);\n\n        logPositionManager.stop();\n        logPositionManager2.stop();\n    }\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/index/MemoryLogPositionManagerTest.java",
    "content": "package com.alibaba.otter.canal.parse.index;\n\nimport org.junit.Ignore;\nimport org.junit.Test;\n@Ignore\npublic class MemoryLogPositionManagerTest extends AbstractLogPositionManagerTest {\n\n    @Test\n    public void testAll() {\n        MemoryLogPositionManager logPositionManager = new MemoryLogPositionManager();\n        logPositionManager.start();\n        doTest(logPositionManager);\n        logPositionManager.stop();\n    }\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/index/MetaLogPositionManagerTest.java",
    "content": "package com.alibaba.otter.canal.parse.index;\n\nimport java.net.InetSocketAddress;\nimport java.util.Date;\n\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.common.zookeeper.ZkClientx;\nimport com.alibaba.otter.canal.common.zookeeper.ZookeeperPathUtils;\nimport com.alibaba.otter.canal.meta.MixedMetaManager;\nimport com.alibaba.otter.canal.meta.ZooKeeperMetaManager;\nimport com.alibaba.otter.canal.protocol.ClientIdentity;\nimport com.alibaba.otter.canal.protocol.position.EntryPosition;\nimport com.alibaba.otter.canal.protocol.position.LogIdentity;\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\nimport com.alibaba.otter.canal.protocol.position.PositionRange;\n@Ignore\npublic class MetaLogPositionManagerTest extends AbstractLogPositionManagerTest {\n\n    private static final String MYSQL_ADDRESS = \"127.0.0.1\";\n    private ZkClientx           zkclientx     = new ZkClientx(cluster1 + \";\" + cluster2);\n\n    @Before\n    public void setUp() {\n        String path = ZookeeperPathUtils.getDestinationPath(destination);\n        zkclientx.deleteRecursive(path);\n    }\n\n    @After\n    public void tearDown() {\n        String path = ZookeeperPathUtils.getDestinationPath(destination);\n        zkclientx.deleteRecursive(path);\n    }\n\n    @Test\n    public void testAll() {\n        MixedMetaManager metaManager = new MixedMetaManager();\n\n        ZooKeeperMetaManager zooKeeperMetaManager = new ZooKeeperMetaManager();\n        zooKeeperMetaManager.setZkClientx(zkclientx);\n\n        metaManager.setZooKeeperMetaManager(zooKeeperMetaManager);\n        metaManager.start();\n\n        MetaLogPositionManager logPositionManager = new MetaLogPositionManager(metaManager);\n        logPositionManager.start();\n        // 构建meta信息\n        ClientIdentity client1 = new ClientIdentity(destination, (short) 1);\n        metaManager.subscribe(client1);\n\n        PositionRange range1 = buildRange(1);\n        metaManager.updateCursor(client1, range1.getEnd());\n\n        PositionRange range2 = buildRange(2);\n        metaManager.updateCursor(client1, range2.getEnd());\n\n        ClientIdentity client2 = new ClientIdentity(destination, (short) 2);\n        metaManager.subscribe(client2);\n\n        PositionRange range3 = buildRange(3);\n        metaManager.updateCursor(client2, range3.getEnd());\n\n        PositionRange range4 = buildRange(4);\n        metaManager.updateCursor(client2, range4.getEnd());\n\n        LogPosition logPosition = logPositionManager.getLatestIndexBy(destination);\n        Assert.assertEquals(range2.getEnd(), logPosition);\n\n        metaManager.stop();\n        logPositionManager.stop();\n    }\n\n    private PositionRange<LogPosition> buildRange(int number) {\n        LogPosition start = new LogPosition();\n        start.setIdentity(new LogIdentity(new InetSocketAddress(MYSQL_ADDRESS, 3306), 1234L));\n        start.setPostion(new EntryPosition(\"mysql-bin.000000\" + number, 106L, new Date().getTime()));\n\n        LogPosition end = new LogPosition();\n        end.setIdentity(new LogIdentity(new InetSocketAddress(MYSQL_ADDRESS, 3306), 1234L));\n        end.setPostion(new EntryPosition(\"mysql-bin.000000\" + (number + 1), 106L, (new Date().getTime()) + 1000 * 1000L));\n        return new PositionRange<>(start, end);\n    }\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/index/MixedLogPositionManagerTest.java",
    "content": "package com.alibaba.otter.canal.parse.index;\n\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.common.zookeeper.ZkClientx;\nimport com.alibaba.otter.canal.common.zookeeper.ZookeeperPathUtils;\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\n@Ignore\npublic class MixedLogPositionManagerTest extends AbstractLogPositionManagerTest {\n\n    private ZkClientx zkclientx = new ZkClientx(cluster1 + \";\" + cluster2);\n\n    @Before\n    public void setUp() {\n        String path = ZookeeperPathUtils.getDestinationPath(destination);\n        zkclientx.deleteRecursive(path);\n    }\n\n    @After\n    public void tearDown() {\n        String path = ZookeeperPathUtils.getDestinationPath(destination);\n        zkclientx.deleteRecursive(path);\n    }\n\n    @Test\n    public void testAll() {\n        MemoryLogPositionManager memoryLogPositionManager = new MemoryLogPositionManager();\n        ZooKeeperLogPositionManager zookeeperLogPositionManager = new ZooKeeperLogPositionManager(zkclientx);\n\n        MixedLogPositionManager logPositionManager = new MixedLogPositionManager(zkclientx);\n        logPositionManager.start();\n\n        LogPosition position2 = doTest(logPositionManager);\n        sleep(1000);\n\n        MixedLogPositionManager logPositionManager2 = new MixedLogPositionManager(zkclientx);\n        logPositionManager2.start();\n\n        LogPosition getPosition2 = logPositionManager2.getLatestIndexBy(destination);\n        Assert.assertEquals(position2, getPosition2);\n\n        logPositionManager.stop();\n        logPositionManager2.stop();\n    }\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/index/PeriodMixedLogPositionManagerTest.java",
    "content": "package com.alibaba.otter.canal.parse.index;\n\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.common.zookeeper.ZkClientx;\nimport com.alibaba.otter.canal.common.zookeeper.ZookeeperPathUtils;\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\n@Ignore\npublic class PeriodMixedLogPositionManagerTest extends AbstractLogPositionManagerTest {\n\n    private ZkClientx zkclientx = new ZkClientx(cluster1 + \";\" + cluster2);\n\n    @Before\n    public void setUp() {\n        String path = ZookeeperPathUtils.getDestinationPath(destination);\n        zkclientx.deleteRecursive(path);\n    }\n\n    @After\n    public void tearDown() {\n        String path = ZookeeperPathUtils.getDestinationPath(destination);\n        zkclientx.deleteRecursive(path);\n    }\n\n    @Test\n    public void testAll() {\n        MemoryLogPositionManager memoryLogPositionManager = new MemoryLogPositionManager();\n        ZooKeeperLogPositionManager zookeeperLogPositionManager = new ZooKeeperLogPositionManager(zkclientx);\n\n        PeriodMixedLogPositionManager logPositionManager = new PeriodMixedLogPositionManager(memoryLogPositionManager,\n            zookeeperLogPositionManager,\n            1000L);\n\n        logPositionManager.start();\n\n        LogPosition position2 = doTest(logPositionManager);\n        sleep(1500);\n\n        PeriodMixedLogPositionManager logPositionManager2 = new PeriodMixedLogPositionManager(memoryLogPositionManager,\n            zookeeperLogPositionManager,\n            1000L);\n        logPositionManager2.start();\n\n        LogPosition getPosition2 = logPositionManager2.getLatestIndexBy(destination);\n        Assert.assertEquals(position2, getPosition2);\n\n        logPositionManager.stop();\n        logPositionManager2.stop();\n    }\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/index/ZooKeeperLogPositionManagerTest.java",
    "content": "package com.alibaba.otter.canal.parse.index;\n\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.common.zookeeper.ZkClientx;\nimport com.alibaba.otter.canal.common.zookeeper.ZookeeperPathUtils;\n\npublic class ZooKeeperLogPositionManagerTest extends AbstractLogPositionManagerTest {\n\n    private ZkClientx zkclientx = new ZkClientx(cluster1 + \";\" + cluster2);\n\n    @Before\n    public void setUp() {\n        String path = ZookeeperPathUtils.getDestinationPath(destination);\n        zkclientx.deleteRecursive(path);\n    }\n    @After\n    public void tearDown() {\n        String path = ZookeeperPathUtils.getDestinationPath(destination);\n        zkclientx.deleteRecursive(path);\n    }\n\n    @Ignore\n    @Test\n    public void testAll() {\n        ZooKeeperLogPositionManager logPositionManager = new ZooKeeperLogPositionManager(zkclientx);\n        logPositionManager.start();\n\n        doTest(logPositionManager);\n        logPositionManager.stop();\n    }\n}\n"
  },
  {
    "path": "parse/src/test/java/com/alibaba/otter/canal/parse/stub/AbstractCanalEventSinkTest.java",
    "content": "package com.alibaba.otter.canal.parse.stub;\n\nimport com.alibaba.otter.canal.common.AbstractCanalLifeCycle;\nimport com.alibaba.otter.canal.sink.CanalEventSink;\n\npublic abstract class AbstractCanalEventSinkTest<T> extends AbstractCanalLifeCycle implements CanalEventSink<T> {\n\n    public void interrupt() {\n        // do nothing\n    }\n}\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_1.sql",
    "content": "CREATE TABLE `tb_rpwzfoyxgb` (\n  `col_mpjirrklef` longtext CHARACTER SET utf8mb4\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_10.sql",
    "content": "CREATE TABLE `tb_ubziprstga` (\n  `col_bjmlsboygo` text CHARACTER SET utf8\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_11.sql",
    "content": "CREATE TABLE `tb_ytaiteijaz` (\n  `col_lxtrjmhpmr` year(4) DEFAULT NULL,\n  `col_wvvanapjlz` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n  `col_xnljwkzjad` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT 'enum_or_set_0',\n  `col_kajgusvxkq` smallint(75) DEFAULT NULL,\n  `col_pwojmgycov` bigint(20) unsigned zerofill DEFAULT NULL,\n  UNIQUE KEY `uk_pffwfanush` (`col_wvvanapjlz`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_12.sql",
    "content": "CREATE TABLE `tb_jhqwojqbtj` (\n  `col_flcxltquqr` longtext,\n  `col_ksprsgkzrb` longtext CHARACTER SET utf8mb4,\n  `col_ndohgxbgox` float DEFAULT '1',\n  `col_egszzxhsvf` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') NOT NULL,\n  `col_cuzojqplje` year(4) DEFAULT '2019',\n  `col_sexypgjnak` date DEFAULT '2019-07-04'\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_13.sql",
    "content": "CREATE TABLE `tb_yfhnotrnrt` (\n  `col_vexgpiotuy` binary(1) DEFAULT NULL,\n  `col_qslraszfyz` longtext CHARACTER SET utf8mb4,\n  `col_dyphdacvvd` tinytext CHARACTER SET utf8mb4,\n  `col_xgueitftmx` float(247,18),\n  `col_ormwjqfbxi` int(193) unsigned zerofill DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_14.sql",
    "content": "CREATE TABLE `tb_cmzqttalvi` (\n  `col_lnqceyzqyi` mediumint(9) DEFAULT '1',\n  `col_rorzwqbqzc` varbinary(190) DEFAULT NULL,\n  `col_qfegkgeaal` tinyint(3) unsigned DEFAULT '1',\n  UNIQUE KEY `uk_nvoltofkla` (`col_rorzwqbqzc`(15))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_xnqicybdlo` (\n  `col_jzysxyqbvv` binary(91),\n  UNIQUE KEY `col_jzysxyqbvv` (`col_jzysxyqbvv`(31))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_15.sql",
    "content": "CREATE TABLE `tb_hgbecqwvnf` (\n  `col_qppnejcxiu` binary(137) DEFAULT NULL,\n  `col_nyrvlflfiz` mediumblob,\n  `col_zfwcescosm` bit(1) DEFAULT NULL,\n  `col_dqpoxmoyzl` bigint(111) unsigned DEFAULT '1',\n  `col_rfnetihhhs` decimal(15,0) NOT NULL,\n  `col_jhaqzczhxe` mediumblob,\n  `col_gfdmpyoigq` time(1) DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\nCREATE TABLE `tb_dqeiczpcpp` (\n  `col_zfwcescosm` bit(1) DEFAULT NULL,\n  `col_gvrsiekgpu` mediumint(9) DEFAULT NULL,\n  `col_luknerkzbg` year(4) DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_16.sql",
    "content": "CREATE TABLE `tb_nxbyklxowd` (\n  `col_kcwxoovscx` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8,\n  `col_dbtkzzfxoi` varbinary(22) NOT NULL,\n  `col_zkfycwevvo` time DEFAULT NULL,\n  `col_ememhbgtcx` bit(1) DEFAULT b'0',\n  `col_zrrfkkosvo` char(203) DEFAULT NULL,\n  `col_fpafdojbdn` decimal(9,9) DEFAULT NULL,\n  `col_qhgfympzxa` longtext CHARACTER SET utf8,\n  `col_tymlykugck` int(83) unsigned zerofill DEFAULT NULL,\n  `col_awkvpagorc` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT 'enum_or_set_0',\n  `col_crrxfxfdzs` datetime DEFAULT NULL,\n  `col_cgdxdxesyd` decimal(10,0) NOT NULL,\n  `col_iiqainhxkc` smallint(81) unsigned zerofill,\n  `col_kbnueyzmpm` tinyblob,\n  `col_zixjkfdybk` binary(1) NOT NULL,\n  PRIMARY KEY (`col_dbtkzzfxoi`(10)),\n  UNIQUE KEY `col_fpfpelfmso` (`col_dbtkzzfxoi`),\n  UNIQUE KEY `col_dbtkzzfxoi` (`col_dbtkzzfxoi`(2))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\nCREATE TABLE `tb_dlnhztodao` (\n  `col_rryluiawnq` varchar(24) DEFAULT '',\n  `col_bdlbhtissa` year(4) DEFAULT NULL,\n  `col_kfawipagkn` tinyblob\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_17.sql",
    "content": "CREATE TABLE `tb_ygyyvdctrs` (\n  `col_hirzxaomit` varbinary(145) NOT NULL,\n  `col_rpxmbgbwos` longblob,\n  `col_emexlkeymz` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 DEFAULT 'enum_or_set_0',\n  `col_ibmogxgtyp` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET latin1 DEFAULT 'enum_or_set_0',\n  `col_yzbwkjwzqw` int(10) unsigned zerofill NOT NULL,\n  `col_dmdpojzsct` varbinary(166) DEFAULT NULL,\n  `col_oxgbfbgzov` double(112,2) DEFAULT NULL,\n  `col_zkdwjtabnw` smallint(5) unsigned NOT NULL,\n  `col_dxgsghrizm` tinyblob,\n  `col_bowjbzwvyw` date DEFAULT NULL,\n  `col_inneappfsm` varchar(112) CHARACTER SET utf8mb4 DEFAULT NULL,\n  UNIQUE KEY `col_emexlkeymz` (`col_emexlkeymz`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_18.sql",
    "content": "CREATE TABLE `tb_jhkrixchju` (\n  `col_prrcfbnwew` longtext,\n  `col_peqguxwzcy` smallint(202) NOT NULL DEFAULT '1',\n  `col_nhdlxtgtvs` char(1) CHARACTER SET utf8 DEFAULT NULL,\n  `col_vyizooodsa` longblob,\n  `col_hwmrzghead` longtext,\n  `col_adgnavqmhq` longtext,\n  `col_adwetrnlyu` bit(41) DEFAULT NULL,\n  `col_ypyzwlctxm` varbinary(86) DEFAULT '\\0',\n  `col_rmjdxsrzry` char(159) DEFAULT NULL,\n  `col_mcjrxquwtj` binary(1) DEFAULT NULL,\n  `col_ilcapoaext` mediumblob,\n  `col_dvcgmijmcd` smallint(246) unsigned NOT NULL DEFAULT '1',\n  `col_avjufpxxft` timestamp NULL DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_19.sql",
    "content": "CREATE TABLE `tb_hefguylckk` (\n  `col_qzehomawzl` int(11) DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_2.sql",
    "content": "CREATE TABLE `tb_gcqyhapjeh` (\n  `col_hctgmkmyxs` datetime DEFAULT '2019-07-04 00:00:00',\n  `col_kkvhrfifbo` longtext,\n  `col_mqfdtybcrt` longtext,\n  `col_ddgcxloigt` bit(6) DEFAULT NULL,\n  `col_icjiguudiw` bigint(20) unsigned zerofill,\n  UNIQUE KEY `col_kkvhrfifbo` (`col_kkvhrfifbo`(31))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_20.sql",
    "content": "CREATE TABLE `tb_wxywfqcvkr` (\n  `col_oftatmlkzc` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') NOT NULL,\n  `col_vjvhvsxmoi` bigint(20) unsigned zerofill DEFAULT NULL,\n  `col_figelwsuqt` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT 'enum_or_set_0',\n  `col_whowxgsfzl` longblob,\n  `col_mzdqafxiqx` bigint(161) unsigned DEFAULT '1'\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_21.sql",
    "content": "CREATE TABLE `tb_mjvfhaqskb` (\n  `col_snmdnyljqk` varbinary(47) DEFAULT '\\0'\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_22.sql",
    "content": "CREATE TABLE `tb_sxbbqclsgf` (\n  `col_ukcpwepvny` timestamp(1) NOT NULL DEFAULT CURRENT_TIMESTAMP(1),\n  `col_avzjcdfkfv` year(4) NOT NULL DEFAULT '2019',\n  `col_kgfprqgdwt` mediumtext CHARACTER SET latin1,\n  `col_wctphwmxin` smallint(103) unsigned zerofill DEFAULT NULL,\n  `col_tekylcrmef` bit(17) DEFAULT b'0',\n  UNIQUE KEY `col_kgfprqgdwt` (`col_kgfprqgdwt`(6))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_btqvbuxdyv` (\n  `col_zknooyoueg` time NOT NULL DEFAULT '00:00:00',\n  `col_xavytdfgxu` mediumtext,\n  `col_mgwiohebft` mediumtext,\n  `col_bejzwcvfmz` date DEFAULT '2019-07-04',\n  UNIQUE KEY `uk_cryfvwxbvx` (`col_zknooyoueg`,`col_xavytdfgxu`(9))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_23.sql",
    "content": "CREATE TABLE `tb_caahynuejc` (\n  `col_ceosnfriqs` int(11) DEFAULT NULL,\n  `col_aklqoixrun` year(4) DEFAULT NULL,\n  `col_noipbutgvd` char(1) CHARACTER SET utf8mb4 DEFAULT NULL,\n  `col_eyefseknmn` time,\n  `col_tlcpasbobp` bigint(20) unsigned zerofill DEFAULT NULL,\n  UNIQUE KEY `col_ceosnfriqs` (`col_ceosnfriqs`),\n  UNIQUE KEY `uk_gekdmzrybz` (`col_aklqoixrun`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_xbsrcfksox` (\n  `col_qsljaaxbrj` datetime DEFAULT '2019-07-04 00:00:00',\n  `col_vusitjjcdx` char(1) DEFAULT NULL,\n  `col_ufwmvwjonj` int(10) unsigned NOT NULL,\n  UNIQUE KEY `uk_henpwhqovc` (`col_ufwmvwjonj`),\n  UNIQUE KEY `col_vusitjjcdx` (`col_vusitjjcdx`,`col_ufwmvwjonj`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_ydbfvvwhvi` (\n  `col_aipblmdcsw` double NOT NULL,\n  `col_sklhosmnvr` bigint(20) unsigned zerofill NOT NULL,\n  `col_skwdbrxmlc` mediumblob,\n  UNIQUE KEY `col_aipblmdcsw` (`col_aipblmdcsw`,`col_sklhosmnvr`),\n  UNIQUE KEY `uk_inmzvqrjoq` (`col_sklhosmnvr`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_24.sql",
    "content": "CREATE TABLE `tb_fywhebwffn` (\n  `col_ukjlmzjcdn` tinyint(91) unsigned DEFAULT '1',\n  UNIQUE KEY `uk_xedljqlhxo` (`col_ukjlmzjcdn`),\n  UNIQUE KEY `uk_keugblaszl` (`col_ukjlmzjcdn`),\n  UNIQUE KEY `col_ctzpiugxrl_2` (`col_ukjlmzjcdn`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_25.sql",
    "content": "CREATE TABLE `tb_aafdasghga` (\n  `col_uayhwfkoln` longtext CHARACTER SET utf8mb4,\n  `col_qskwbkbegb` decimal(16,0) DEFAULT NULL,\n  `col_fxicikwsct` float NOT NULL,\n  `col_ygghjheerk` text CHARACTER SET utf8,\n  `col_zbenqlvted` binary(1) DEFAULT NULL,\n  `col_ixseptopfk` date DEFAULT '2019-07-04',\n  `col_iafihazdod` char(1) NOT NULL,\n  UNIQUE KEY `col_fxicikwsct` (`col_fxicikwsct`),\n  UNIQUE KEY `col_zbenqlvted` (`col_zbenqlvted`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_26.sql",
    "content": "CREATE TABLE `tb_keyyesvarm` (\n  `col_zixordgmdc` decimal(3,1) DEFAULT NULL,\n  `col_victdeyala` decimal(48,7) DEFAULT NULL,\n  `col_lqkravajqi` longtext\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_27.sql",
    "content": "CREATE TABLE `tb_flnycxasap` (\n  `col_rqtzrkfarg` timestamp NULL DEFAULT CURRENT_TIMESTAMP\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_28.sql",
    "content": "CREATE TABLE `tb_cvpyawneqw` (\n  `col_nnggkdrfej` mediumint(9) DEFAULT '1',\n  `col_gxyxiafdwy` tinyblob,\n  `col_jrdtjutkna` int(10) unsigned DEFAULT NULL,\n  UNIQUE KEY `col_sowlpsmtck` (`col_nnggkdrfej`),\n  UNIQUE KEY `uk_ameijmmzqx` (`col_nnggkdrfej`),\n  UNIQUE KEY `col_gxyxiafdwy` (`col_gxyxiafdwy`(28))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_29.sql",
    "content": "CREATE TABLE `tb_lfxvmboyfq` (\n  `col_omyyogfmwf` varbinary(117) DEFAULT NULL,\n  `col_ziqdcvhqaa` longblob,\n  `col_osxbsknpgd` varchar(183) CHARACTER SET utf8mb4 DEFAULT NULL,\n  `col_idrqfoikzf` float(151,12) NOT NULL,\n  `col_whrxkkdwrk` tinytext,\n  `col_yxfqfnhsex` bit(43) DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_3.sql",
    "content": "CREATE TABLE `tb_ntoztqvpgu` (\n  `col_pszlqmpajg` mediumint(8) unsigned NOT NULL,\n  `col_gsplwknfrh` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n  `col_ytfasfxidt` mediumtext CHARACTER SET utf8mb4,\n  `col_guxaslfjra` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET latin1 DEFAULT 'enum_or_set_0',\n  `col_hzazyxoqhs` int(240) unsigned DEFAULT '1',\n  `col_yrswgxnlhe` mediumtext,\n  `col_bogirlzjnd` float DEFAULT NULL,\n  `col_kcynrqhwrh` tinyblob,\n  `col_guruxuyivx` char(1) CHARACTER SET utf8mb4 DEFAULT NULL,\n  `col_aklhemsftu` datetime DEFAULT '2019-07-04 00:00:00',\n  `col_bpigfcahks` longblob,\n  `col_xzbtbplmxx` float(173,30) DEFAULT NULL,\n  `col_abtzsnchmp` time(3) DEFAULT NULL,\n  `col_xrqqlwdmuo` datetime NOT NULL,\n  `col_yesjtrmdcm` smallint(5) unsigned DEFAULT '1',\n  `col_szbvvxlxpk` mediumtext CHARACTER SET latin1,\n  `col_qbvmzghubk` longblob,\n  `col_zvbkjkirrz` mediumint(68) unsigned DEFAULT '1'\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_30.sql",
    "content": "CREATE TABLE `tb_ruvaoezmwl` (\n  `col_gdnftbskks` datetime(4) DEFAULT NULL,\n  `col_crzzjsyeyk` tinyblob,\n  UNIQUE KEY `uk_splpaskbbf` (`col_gdnftbskks`),\n  UNIQUE KEY `uk_gcdkboipfa` (`col_gdnftbskks`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_pfzgcmldfg` (\n  `col_gdnftbskks` datetime(4) DEFAULT NULL,\n  `col_duzzugyump` smallint(74) unsigned zerofill DEFAULT NULL,\n  UNIQUE KEY `uk_gcdkboipfa` (`col_gdnftbskks`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_31.sql",
    "content": "CREATE TABLE `tb_djhsoeomxx` (\n  `col_fpegtdbbro` varchar(10) CHARACTER SET latin1 NOT NULL DEFAULT '',\n  UNIQUE KEY `uk_bbhokusgkq` (`col_fpegtdbbro`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_32.sql",
    "content": "CREATE TABLE `tb_ybgjvtnrkt` (\n  `col_vhszikunhu` int(95) unsigned zerofill DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_33.sql",
    "content": "CREATE TABLE `tb_ocwsozgwid` (\n  `col_cuctvlzqvd` decimal(63,14),\n  UNIQUE KEY `col_jerxhroyff_2` (`col_cuctvlzqvd`),\n  UNIQUE KEY `col_jerxhroyff_4` (`col_cuctvlzqvd`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_34.sql",
    "content": "CREATE TABLE `tb_qlkjrjqnps` (\n  `col_eoeroydtse` smallint(32) DEFAULT '1',\n  `col_cbcrcayfoe` longblob,\n  `col_vkcmtobywn` binary(1) NOT NULL,\n  `col_mywjrvfxmw` tinyblob,\n  `col_hkwgwwaxoy` text,\n  `col_zuhebeqqrq` decimal(4,0) DEFAULT NULL,\n  `col_oilsudgyas` smallint(39) unsigned zerofill DEFAULT NULL,\n  `col_wgsnbmgdbz` int(10) unsigned zerofill,\n  `col_opbtiidusc` tinyint(3) unsigned zerofill DEFAULT NULL,\n  `col_wcpdsgpcip` longblob,\n  `col_fidmrllusm` varchar(132) DEFAULT NULL,\n  `col_qxsokmevlv` int(10) unsigned zerofill NOT NULL,\n  PRIMARY KEY (`col_vkcmtobywn`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_jnhvwsafrh` (\n  `col_ktdqdryygn` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') NOT NULL DEFAULT 'enum_or_set_0',\n  `col_cbcrcayfoe` longblob\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_ygcnpvqeez` (\n  `col_ktdqdryygn` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') NOT NULL DEFAULT 'enum_or_set_0',\n  `col_cbcrcayfoe` longblob\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_35.sql",
    "content": "CREATE TABLE `tb_eegcnsbywv` (\n  `col_rwmjknctzl` datetime(6) NOT NULL,\n  `col_seknewafqd` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n  `col_jophiowutg` longtext CHARACTER SET latin1,\n  `col_iedptbbtmp` double DEFAULT NULL,\n  `col_pnotecfjsi` decimal(10,0) DEFAULT NULL,\n  `col_eawvokgzvi` year(4) NOT NULL,\n  `col_orlvhbnaer` longtext CHARACTER SET utf8mb4,\n  `col_krlfmduttq` longtext CHARACTER SET latin1,\n  `col_jobdxewixt` bigint(173) DEFAULT NULL,\n  `col_ufdhvspoka` float DEFAULT '1',\n  `col_qqdcbaucve` date DEFAULT NULL,\n  `col_uuexgtwrse` double(172,2) NOT NULL,\n  `col_hzixmjzrzg` tinyint(195) unsigned zerofill NOT NULL,\n  `col_bfsjjimztp` datetime(1) NOT NULL,\n  `col_hfrmqomgva` date DEFAULT NULL,\n  `col_mepqygbcxa` text CHARACTER SET utf8mb4,\n  `col_xmubzkmxzy` mediumblob,\n  PRIMARY KEY (`col_rwmjknctzl`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_qlvbveqzna` (\n  `col_ytfnmhhaoa` int(10) unsigned DEFAULT NULL,\n  `col_vimtlabyrl` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 DEFAULT NULL,\n  UNIQUE KEY `col_ytfnmhhaoa` (`col_ytfnmhhaoa`),\n  UNIQUE KEY `col_vimtlabyrl` (`col_vimtlabyrl`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_36.sql",
    "content": "CREATE TABLE `tb_putsugoooc` (\n  `col_ynpynwnkjv` mediumtext,\n  UNIQUE KEY `col_ufqdyzbxyc_2` (`col_ynpynwnkjv`(18))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_37.sql",
    "content": "CREATE TABLE `tb_cdbrmxbknb` (\n  `col_amvugezhpd` blob,\n  UNIQUE KEY `uk_yvoxkgeget` (`col_amvugezhpd`(6)),\n  UNIQUE KEY `uk_ozxqwxureo` (`col_amvugezhpd`(10))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_38.sql",
    "content": "CREATE TABLE `tb_oxwwculmvu` (\n  `col_szncpsegwq` time DEFAULT '00:00:00',\n  `col_wxqxqueihr` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT NULL,\n  `col_hyhtklzrvn` varchar(147) NOT NULL DEFAULT '',\n  `col_umxbmdtpxs` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') NOT NULL,\n  `col_bewssrhuze` tinytext CHARACTER SET utf8 COLLATE utf8_unicode_ci,\n  `col_yyixefgbqi` year(4) DEFAULT NULL,\n  UNIQUE KEY `uk_vrydxlndik` (`col_yyixefgbqi`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_39.sql",
    "content": "CREATE TABLE `tb_aidhgjhqzp` (\n  `col_wtsgpcyuec` time(6) DEFAULT NULL,\n  `col_ouqqfnoijf` tinyint(142) unsigned DEFAULT '1',\n  `col_jsjfylwbsu` time(3) NOT NULL,\n  `col_wcosqedhbh` tinytext,\n  `col_cvzuqkfnnp` tinytext CHARACTER SET latin1,\n  `col_dpnzvoemce` smallint(146) unsigned zerofill DEFAULT NULL,\n  `col_wisgyhivgt` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT 'enum_or_set_0'\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_4.sql",
    "content": "CREATE TABLE `tb_ljqwtifhmg` (\n  `col_lifsfguaso` bigint(20) unsigned zerofill NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_40.sql",
    "content": "CREATE TABLE `tb_imabeghgmt` (\n  `col_wvmxgyajnm` longblob,\n  UNIQUE KEY `uk_ppyrqytsgk` (`col_wvmxgyajnm`(12)),\n  UNIQUE KEY `uk_znvsdkastd` (`col_wvmxgyajnm`(17))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_41.sql",
    "content": "CREATE TABLE `tb_mqghelxirz` (\n  `col_ixaybtquqz` smallint(215) unsigned DEFAULT '1',\n  `col_gseshvltxd` tinytext CHARACTER SET latin1,\n  `col_otuwjnlrtt` decimal(10,0) DEFAULT NULL,\n  `col_gwwjlquinc` mediumint(9) NOT NULL,\n  `col_ibdwyzxgxi` varchar(134) CHARACTER SET latin1 DEFAULT NULL,\n  `col_vtkwyvoqkp` varbinary(121) DEFAULT NULL,\n  `col_gubjakxnpz` char(1) CHARACTER SET latin1 DEFAULT NULL,\n  `col_hawbrmwxzw` longblob,\n  `col_kgokeficzq` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET latin1 DEFAULT 'enum_or_set_0',\n  `col_xltpnadrcs` bigint(20) unsigned zerofill NOT NULL,\n  `col_rikplgqsve` tinyint(146) unsigned zerofill DEFAULT NULL,\n  `col_ukmsekjycj` tinyblob,\n  `col_zonuplyzdz` tinyblob,\n  `col_snvmotcqtx` mediumtext CHARACTER SET latin1,\n  PRIMARY KEY (`col_gwwjlquinc`),\n  UNIQUE KEY `col_otuwjnlrtt` (`col_otuwjnlrtt`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_42.sql",
    "content": "CREATE TABLE `tb_hkehwyglax` (\n  `col_dcnadmyyfb` binary(1) DEFAULT NULL,\n  `col_zvcpajjdrr` int(26) unsigned zerofill DEFAULT NULL,\n  `col_aftchdhhpb` int(10) unsigned DEFAULT NULL,\n  `col_fdyhioyktq` tinytext CHARACTER SET utf8mb4,\n  `col_iqohbjwihd` text CHARACTER SET utf8mb4,\n  `col_yxsvpkijew` double NOT NULL,\n  UNIQUE KEY `col_tymnumzsjd_2` (`col_aftchdhhpb`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_43.sql",
    "content": "CREATE TABLE `tb_uoquelzmdk` (\n  `col_wcdxzaykzl` smallint(5) unsigned DEFAULT '1',\n  `col_njhhehxbdq` mediumtext,\n  `col_wwdicmbkug` longblob\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_44.sql",
    "content": "CREATE TABLE `tb_faqsxuetwm` (\n  `col_qcgurbenzo` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT NULL,\n  UNIQUE KEY `uk_vidzaimrjm` (`col_qcgurbenzo`),\n  UNIQUE KEY `uk_zgssrxjpck` (`col_qcgurbenzo`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_45.sql",
    "content": "CREATE TABLE `tb_voanuixent` (\n  `col_xgykdmygaw` tinyblob\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_znqepghruj` (\n  `col_xgykdmygaw` tinyblob,\n  UNIQUE KEY `col_xgykdmygaw` (`col_xgykdmygaw`(21))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_46.sql",
    "content": "CREATE TABLE `tb_mlsrpqwnhf` (\n  `col_kdvvwclils` year(4) DEFAULT '2019'\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_47.sql",
    "content": "CREATE TABLE `tb_odwnejztgw` (\n  `col_ouwtrbmtli` varbinary(39) DEFAULT '\\0',\n  `col_ikgmyfugbh` time(3) DEFAULT NULL,\n  `col_grrazuxsmj` tinyint(108) unsigned zerofill DEFAULT NULL,\n  `col_dqxacqwdav` year(4) DEFAULT NULL,\n  `col_afisennniu` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET latin1 NOT NULL DEFAULT 'enum_or_set_0',\n  `col_hsbiyreflo` mediumblob,\n  `col_pmcsqydybm` bit(59) DEFAULT NULL,\n  `col_caewwurnsu` mediumblob,\n  `col_vumeeppqkm` int(62) unsigned zerofill DEFAULT NULL,\n  `col_hxgvemyiam` tinytext,\n  PRIMARY KEY (`col_afisennniu`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_48.sql",
    "content": "CREATE TABLE `tb_fzlrvzctbr` (\n  `col_fcxqhwmcni` longblob,\n  `col_kswnnckixx` tinytext,\n  `col_hpqddjdxxz` longblob,\n  `col_xnreiiwrcm` mediumint(225) unsigned DEFAULT '1',\n  UNIQUE KEY `uk_cvkkrimfqi` (`col_kswnnckixx`(2),`col_hpqddjdxxz`(29))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_tmasbkkzbt` (\n  `col_gvdetvdvvm` longtext,\n  UNIQUE KEY `uk_dvgbfwphsv` (`col_gvdetvdvvm`(27))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_vnbuhzbwvw` (\n  `col_gttrfjbbyi` varchar(161) NOT NULL,\n  `col_ksvxcquzhp` longtext CHARACTER SET utf8 COLLATE utf8_unicode_ci,\n  `col_ibahzyeiod` year(4) NOT NULL,\n  PRIMARY KEY (`col_gttrfjbbyi`(8)),\n  UNIQUE KEY `col_ksvxcquzhp` (`col_ksvxcquzhp`(16),`col_ibahzyeiod`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_49.sql",
    "content": "CREATE TABLE `tb_yzmdpoldbu` (\n  `col_cmeqnxgnwo` int(11) DEFAULT '1',\n  `col_qdzrqnbwug` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT 'enum_or_set_0',\n  `col_pabufpjxkv` tinytext,\n  `col_hvdglgtlxp` longblob,\n  `col_pbngzmfduy` varchar(225) NOT NULL,\n  `col_fefjkkdwwg` tinytext,\n  `col_kloxucvkgw` bigint(200) unsigned DEFAULT '1',\n  UNIQUE KEY `uk_bmkecbeunv` (`col_fefjkkdwwg`(12))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_oxrpkkhlpd` (\n  `col_qyxegyfxhd` binary(1) NOT NULL,\n  `col_fhrwjmkunp` time DEFAULT '00:00:00',\n  `col_ebdpffnuvl` longblob,\n  `col_ivfpfrbagk` decimal(48,0) DEFAULT NULL,\n  PRIMARY KEY (`col_qyxegyfxhd`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_5.sql",
    "content": "CREATE TABLE `tb_ahefjpyxqu` (\n  `col_cqrrpavzlu` tinyint(14) DEFAULT '1'\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_50.sql",
    "content": "CREATE TABLE `tb_cfnewnjqhr` (\n  `col_cdwqlqfwox` int(10) unsigned DEFAULT '1'\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_naclwnujgs` (\n  `col_qqccessygq` year(4) NOT NULL,\n  PRIMARY KEY (`col_qqccessygq`),\n  UNIQUE KEY `uk_mffeuwunua` (`col_qqccessygq`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_51.sql",
    "content": "CREATE TABLE `tb_krsikytrbw` (\n  `col_lliihnoyoo` int(145) NOT NULL DEFAULT '1',\n  `col_qkgtxzzfie` tinyblob,\n  `col_lfbganjgad` timestamp(4) NULL DEFAULT NULL,\n  `col_cqjptjcgyb` binary(1) NOT NULL,\n  `col_lfptlilmsv` int(230) unsigned zerofill NOT NULL,\n  `col_omxbpiulnd` year(4) DEFAULT '2019',\n  PRIMARY KEY (`col_cqjptjcgyb`),\n  UNIQUE KEY `col_cqjptjcgyb` (`col_cqjptjcgyb`,`col_lliihnoyoo`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_52.sql",
    "content": "CREATE TABLE `tb_udrucjftxw` (\n  `col_tustciiwwp` datetime(2) DEFAULT NULL,\n  `col_xhjeuttrui` longtext CHARACTER SET utf8mb4,\n  `col_gzwherugvm` decimal(35,10) DEFAULT NULL,\n  `col_fwooxfmvvs` tinytext,\n  UNIQUE KEY `uk_kllnpcqqzt` (`col_xhjeuttrui`(30)),\n  UNIQUE KEY `uk_omzcuexdxr` (`col_xhjeuttrui`(8),`col_gzwherugvm`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_syxeibzqzx` (\n  `col_shntqukbsk` datetime DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_53.sql",
    "content": "CREATE TABLE `tb_gcekkribdm` (\n  `col_xpuntwyhls` int(253) unsigned zerofill DEFAULT NULL,\n  `col_doacvjtxfj` text CHARACTER SET utf8,\n  `col_vbxxcedehr` varbinary(72) DEFAULT '\\0',\n  `col_spnkzcnaaj` tinyint(221) unsigned zerofill DEFAULT NULL,\n  `col_lctlnulyqs` varchar(141) CHARACTER SET utf8 DEFAULT '',\n  `col_vdafmpnlcj` timestamp NULL DEFAULT NULL,\n  `col_pwwnuhvonf` bit(1) DEFAULT NULL,\n  `col_wpdnfgwkmm` float(253,19) NOT NULL,\n  `col_hmbydpntpk` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 DEFAULT 'enum_or_set_0',\n  `col_kahmeuqzzo` mediumtext,\n  `col_mrruauiuzg` mediumblob,\n  `col_cxafkgwrzu` varbinary(36) DEFAULT NULL,\n  `col_ooxuaiyuqa` mediumint(107) unsigned zerofill DEFAULT NULL,\n  `col_mxpgmnrigf` decimal(10,0) DEFAULT NULL,\n  `col_sgjbftdxrq` mediumtext CHARACTER SET utf8,\n  `col_zboghrfujc` char(34) DEFAULT NULL,\n  `col_xpwlcesvfx` int(73) DEFAULT NULL,\n  `col_ysqvnorogf` int(10) unsigned DEFAULT '1',\n  `col_dznwcqadnc` mediumtext CHARACTER SET utf8\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_54.sql",
    "content": "CREATE TABLE `tb_fijiqnymmp` (\n  `col_tcroqoomon` tinyblob\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_55.sql",
    "content": "CREATE TABLE `tb_epubreeayc` (\n  `col_embnqthyuu` double NOT NULL,\n  `col_shqnxczemy` binary(149) DEFAULT NULL,\n  `col_gyjfdfpemu` longtext CHARACTER SET utf8,\n  PRIMARY KEY (`col_embnqthyuu`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\nCREATE TABLE `tb_uafierhjhg` (\n  `col_rvdpillohr` smallint(51) unsigned NOT NULL,\n  `col_wjvgjpqbgz` smallint(5) unsigned zerofill DEFAULT NULL,\n  PRIMARY KEY (`col_rvdpillohr`),\n  UNIQUE KEY `uk_aqetlmillq` (`col_wjvgjpqbgz`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_56.sql",
    "content": "CREATE TABLE `tb_hjqdntirzd` (\n  `col_dtiogubkiw` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT 'enum_or_set_0',\n  `col_okjyevogvl` int(11) DEFAULT '1',\n  `col_cawkxhaucp` tinyblob,\n  UNIQUE KEY `col_mwlpdcpegm` (`col_dtiogubkiw`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_57.sql",
    "content": "CREATE TABLE `tb_xmvawoekwx` (\n  `col_gsqeppbqjg` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_58.sql",
    "content": "CREATE TABLE `tb_wsxpqlbxhr` (\n  `col_kkdtlacxiy` char(1) NOT NULL,\n  `col_koftcyrhcl` int(233) DEFAULT '1',\n  `col_nacwazcyzi` varbinary(12) DEFAULT NULL,\n  `col_nnckvjhnnd` tinytext CHARACTER SET utf8 COLLATE utf8_unicode_ci,\n  `col_sxwmoaghtk` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT 'enum_or_set_0',\n  `col_btyjfvfohb` double(18,12) DEFAULT NULL,\n  `col_qpusrblupw` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT 'enum_or_set_0',\n  PRIMARY KEY (`col_kkdtlacxiy`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_59.sql",
    "content": "CREATE TABLE `tb_hbheuprskb` (\n  `col_mqqxkezdux` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 NOT NULL,\n  UNIQUE KEY `col_mqqxkezdux` (`col_mqqxkezdux`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_6.sql",
    "content": "CREATE TABLE `tb_yzcwyrztvj` (\n  `col_ubxpjfudbv` timestamp(5) NOT NULL DEFAULT CURRENT_TIMESTAMP(5),\n  PRIMARY KEY (`col_ubxpjfudbv`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_60.sql",
    "content": "CREATE TABLE `tb_idttivasrc` (\n  `col_vqskztkwqb` longblob,\n  `col_naimzyvtyy` mediumint(8) unsigned DEFAULT NULL,\n  `col_ngqfbkxgkw` tinyblob,\n  `col_slxxarfdmi` binary(243) DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\nCREATE TABLE `tb_rjdimmicei` (\n  `col_aszmqpjfka` decimal(49,0) DEFAULT NULL,\n  `col_qmwcrinzvf` time NOT NULL,\n  `col_xgwavsjbcg` longblob,\n  UNIQUE KEY `col_xgwavsjbcg` (`col_xgwavsjbcg`(22))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_61.sql",
    "content": "CREATE TABLE `tb_sbjgtoodpq` (\n  `col_npydnongql` decimal(45,0) NOT NULL,\n  `col_pfssvgbbli` bigint(20) unsigned zerofill DEFAULT NULL,\n  `col_qqyenpblbe` binary(1),\n  `col_mkayxjoxkl` binary(229) DEFAULT NULL,\n  `col_zlrfenamiz` double\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_62.sql",
    "content": "CREATE TABLE `tb_mvpbukrobp` (\n  `col_hkfndsohtj` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') NOT NULL,\n  `col_gepoechcst` char(1) DEFAULT NULL,\n  `col_hgaiklgzif` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT NULL,\n  `col_ndfdyxpuhz` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n  `col_vrsytgjrfw` date DEFAULT '2019-07-04',\n  `col_vlgjlismyz` text,\n  `col_jbqfyecqez` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_63.sql",
    "content": "CREATE TABLE `tb_txslclddib` (\n  `col_fflqfgfdyt` varchar(26) CHARACTER SET utf8mb4 NOT NULL DEFAULT '',\n  `col_yvgymfxalr` year(4) DEFAULT '2019',\n  `col_vkgmvcluzx` bigint(20) unsigned zerofill DEFAULT NULL,\n  `col_mnviktcwsx` blob\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_64.sql",
    "content": "CREATE TABLE `tb_vyhepkdocw` (\n  `col_yqmzdxesrj` timestamp NULL DEFAULT NULL,\n  `col_slupqsxneh` decimal(14,0) DEFAULT NULL,\n  `col_chvhleyulg` tinytext,\n  `col_getqnnhjry` date DEFAULT NULL,\n  `col_ahjuyzjbhk` bit(1) DEFAULT NULL,\n  `col_daemlskcfa` double DEFAULT NULL,\n  UNIQUE KEY `col_slupqsxneh` (`col_slupqsxneh`),\n  UNIQUE KEY `col_onhyboljxa` (`col_slupqsxneh`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_65.sql",
    "content": "CREATE TABLE `tb_ambgylvzkp` (\n  `col_smbnzspzed` date DEFAULT NULL,\n  `col_ebfnpjymeg` tinytext CHARACTER SET utf8mb4,\n  `col_llpqomujks` varchar(24) CHARACTER SET latin1 NOT NULL DEFAULT '',\n  `col_eeieaubbdp` decimal(12,0) DEFAULT NULL,\n  `col_evvhlyienk` char(172) CHARACTER SET utf8mb4 DEFAULT NULL,\n  PRIMARY KEY (`col_llpqomujks`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_rnradhkfon` (\n  `col_sbuommslma` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),\n  `col_corovzewna` date DEFAULT '2019-07-04',\n  UNIQUE KEY `col_sbuommslma` (`col_sbuommslma`),\n  UNIQUE KEY `col_sbuommslma_2` (`col_sbuommslma`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_66.sql",
    "content": "CREATE TABLE `tb_gnbqbndsaw` (\n  `col_pqnfhpfywv` datetime DEFAULT '2019-07-04 00:00:00'\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_67.sql",
    "content": "CREATE TABLE `tb_wzvjzesyqu` (\n  `col_zlboqlzvrz` binary(0) NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_68.sql",
    "content": "CREATE TABLE `tb_vmghxdnngw` (\n  `col_cuofmwfcxy` tinytext\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_69.sql",
    "content": "CREATE TABLE `tb_tilukdjjhc` (\n  `col_kxelvjyosf` int(150) DEFAULT NULL,\n  `col_loxvzbzvge` char(1) CHARACTER SET utf8 DEFAULT NULL,\n  `col_laleouwpiw` int(11) NOT NULL DEFAULT '1',\n  `col_fgidnnqvqm` year(4) NOT NULL,\n  `col_pmqkhijpcr` varbinary(71) DEFAULT '\\0',\n  `col_uzxvkpgggz` mediumblob,\n  `col_jtyftybbku` decimal(13,5) NOT NULL,\n  `col_olnmovdyfw` bit(3) DEFAULT b'0',\n  `col_kcysycgbek` longblob,\n  `col_idhlrzdwud` char(1) CHARACTER SET utf8 NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_7.sql",
    "content": "CREATE TABLE `tb_nuprsugtcj` (\n  `col_qwsjkklpfs` set('enum_or_set_0','enum_or_set_1','enum_or_set_2')\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_70.sql",
    "content": "CREATE TABLE `tb_wqthgwmnob` (\n  `col_enozfpzijr` date DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_71.sql",
    "content": "CREATE TABLE `tb_sfwkwlflbi` (\n  `col_wryzwhfdap` mediumtext CHARACTER SET utf8 COLLATE utf8_unicode_ci\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_72.sql",
    "content": "CREATE TABLE `tb_cugzkpefkt` (\n  `col_xnhktpwgoy` tinyblob,\n  UNIQUE KEY `uk_anpzhhtomg` (`col_xnhktpwgoy`(16))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_73.sql",
    "content": "CREATE TABLE `tb_upzbnfzylo` (\n  `col_dppomywdgn` tinyblob,\n  `col_hybjpvnihc` mediumblob,\n  `col_nvqsfunmve` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT 'enum_or_set_0',\n  `col_rvwyvmeidf` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') NOT NULL DEFAULT 'enum_or_set_0',\n  PRIMARY KEY (`col_rvwyvmeidf`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_rmmpcdzkft` (\n  `col_dppomywdgn` tinyblob,\n  `col_hybjpvnihc` mediumblob,\n  `col_nvqsfunmve` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT 'enum_or_set_0',\n  `col_rvwyvmeidf` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') NOT NULL DEFAULT 'enum_or_set_0',\n  PRIMARY KEY (`col_rvwyvmeidf`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_zixkylluol` (\n  `col_psutzipcit` int(29) unsigned zerofill\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_74.sql",
    "content": "CREATE TABLE `tb_tazkjnlgrx` (\n  `col_ewzdxvnlrs` bit(1) NOT NULL DEFAULT b'0',\n  `col_trhadxfbfi` decimal(10,0) DEFAULT NULL,\n  `col_jxosxbunsc` double(179,7) DEFAULT NULL,\n  `col_jijmncnsoa` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT 'enum_or_set_0',\n  `col_gxpgglefyh` char(40) CHARACTER SET utf8mb4 DEFAULT NULL,\n  `col_pgtqyvckbi` time DEFAULT NULL,\n  `col_vbsyfqxqng` mediumblob,\n  PRIMARY KEY (`col_ewzdxvnlrs`),\n  UNIQUE KEY `uk_ygarqhlsva` (`col_jxosxbunsc`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_75.sql",
    "content": "CREATE TABLE `tb_mpjfjmkbwn` (\n  `col_lyrrpdesag` bigint(20) unsigned zerofill DEFAULT NULL,\n  `col_eyzpohpkcl` int(10) unsigned zerofill NOT NULL,\n  `col_fehlmkpxfq` char(1) CHARACTER SET latin1 DEFAULT NULL,\n  `col_oqfdewvoin` bigint(20) unsigned DEFAULT NULL,\n  UNIQUE KEY `uk_odozsruufn` (`col_fehlmkpxfq`),\n  UNIQUE KEY `col_lyrrpdesag` (`col_lyrrpdesag`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_76.sql",
    "content": "CREATE TABLE `tb_bxtlrumrtn` (\n  `col_uttbttlgkx` smallint(181) unsigned DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\nCREATE TABLE `tb_irclltefag` (\n  `col_iabzixqyhm` tinyblob,\n  `col_otoxjlwatj` date DEFAULT '2019-07-04',\n  UNIQUE KEY `col_otoxjlwatj` (`col_otoxjlwatj`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_77.sql",
    "content": "CREATE TABLE `tb_igmuoxapjx` (\n  `col_cvsykxnvpf` varchar(24) DEFAULT ''\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_wmwynbzgyg` (\n  `col_iupsnmieyl` smallint(5) unsigned DEFAULT NULL,\n  `col_gnkgsewitj` decimal(10,0) DEFAULT '1',\n  `col_cvsykxnvpf` varchar(24) DEFAULT '',\n  `col_xailqzhuwy` blob\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_78.sql",
    "content": "CREATE TABLE `tb_cockfzvkou` (\n  `col_atkczpjiqk` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') NOT NULL,\n  UNIQUE KEY `uk_cxmeeaqnza` (`col_atkczpjiqk`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_79.sql",
    "content": "CREATE TABLE `tb_zwzsaathnd` (\n  `col_rqumywduzu` time DEFAULT NULL,\n  `col_jzcpwtvvhi` decimal(10,0) NOT NULL DEFAULT '1',\n  `col_vcejogynpm` time DEFAULT NULL,\n  `col_dseumehqur` tinyblob,\n  `col_xxmdywhgie` mediumint(9) DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_8.sql",
    "content": "CREATE TABLE `tb_hmfoniytbf` (\n  `col_urfoabrjor` bit(15) NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_80.sql",
    "content": "CREATE TABLE `tb_tmotlxzrja` (\n  `col_uesfklwmsk` date DEFAULT '2019-07-04',\n  `col_zskjzqcxkk` varbinary(218) DEFAULT '\\0',\n  `col_rvztkthbca` time(6) DEFAULT NULL,\n  `col_mpmkktdhop` mediumblob,\n  `col_tgjhdvpopd` year(4) DEFAULT NULL,\n  `col_erywvwybme` int(13) DEFAULT '1',\n  `col_glrqptmjgp` varbinary(172) DEFAULT NULL,\n  `col_soiyoovkol` char(1) CHARACTER SET utf8mb4 DEFAULT NULL,\n  `col_wppxtgrjdz` tinyblob\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_amkojtlotu` (\n  `col_zzhxpptdgq` longblob,\n  UNIQUE KEY `uk_voojzaxmwk` (`col_zzhxpptdgq`(21))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/mysql_9.sql",
    "content": "CREATE TABLE `tb_sqndbrgkvj` (\n  `col_mueqvldinf` int(10) unsigned DEFAULT '1',\n  `col_rtbkufevvv` smallint(5) unsigned zerofill DEFAULT NULL,\n  `col_xuafealoty` float DEFAULT NULL,\n  `col_plylqkvjll` time(5) DEFAULT NULL,\n  `col_pymdrmukax` double DEFAULT NULL,\n  `col_prvruzvlqp` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,\n  UNIQUE KEY `col_plylqkvjll` (`col_plylqkvjll`,`col_pymdrmukax`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_1.sql",
    "content": "CREATE TABLE `tb_ijlfoushao` (\n  `col_ldgkfndhbx` tinytext CHARACTER SET utf8,\n  `col_bgzuestpsr` bit(47) DEFAULT b'0'\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_ijlfoushao` TO `tb_fmmsfdptfj`;\nRENAME TABLE `tb_fmmsfdptfj` TO `tb_bthnyesbdu`;\nRENAME TABLE `tb_bthnyesbdu` TO `tb_rpwzfoyxgb`;\nALTER TABLE `tb_rpwzfoyxgb` ADD COLUMN `col_mpjirrklef` text(161554088) CHARACTER SET utf8mb4;\nALTER TABLE `tb_rpwzfoyxgb` ADD COLUMN `col_ymhswmzvva` time NULL FIRST;\nALTER TABLE `tb_rpwzfoyxgb` ADD `col_hxpgdeuejv` blob;\nALTER TABLE `tb_rpwzfoyxgb` ADD (`col_uuvxfsqeat` tinyint NOT NULL DEFAULT '1', `col_hvwlhidvlq` int(166) NULL);\nALTER TABLE `tb_rpwzfoyxgb` ADD CONSTRAINT PRIMARY KEY (`col_uuvxfsqeat`);\nALTER TABLE `tb_rpwzfoyxgb` CHANGE COLUMN `col_ymhswmzvva` `col_cuhqbcsmob` smallint(198) unsigned DEFAULT '1';\nALTER TABLE `tb_rpwzfoyxgb` DROP COLUMN `col_bgzuestpsr`, DROP COLUMN `col_hxpgdeuejv`;\nALTER TABLE `tb_rpwzfoyxgb` DROP `col_cuhqbcsmob`, DROP `col_hvwlhidvlq`;\nALTER TABLE `tb_rpwzfoyxgb` DROP COLUMN `col_uuvxfsqeat`, DROP COLUMN `col_ldgkfndhbx`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_10.sql",
    "content": "CREATE TABLE `tb_xckrjwodah` (\n  `col_pspaxkzovq` decimal,\n  UNIQUE KEY `col_pspaxkzovq` (`col_pspaxkzovq`),\n  UNIQUE INDEX `uk_vkwgrmlfqc` (`col_pspaxkzovq`)\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_xckrjwodah` TO `tb_ivkfbysugn`;\nRENAME TABLE `tb_ivkfbysugn` TO `tb_suvmojlodk`;\nRENAME TABLE `tb_suvmojlodk` TO `tb_ubziprstga`;\nALTER TABLE `tb_ubziprstga` ADD `col_bjmlsboygo` text AFTER `col_pspaxkzovq`;\nALTER TABLE `tb_ubziprstga` ADD COLUMN (`col_ayuqjzbbwg` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT 'enum_or_set_0', `col_fjhnhxlfmc` decimal(29,23));\nALTER TABLE `tb_ubziprstga` CHARACTER SET utf8mb4;\nALTER TABLE `tb_ubziprstga` CHANGE COLUMN `col_ayuqjzbbwg` `col_slcmuapykg` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 DEFAULT 'enum_or_set_0' FIRST;\nALTER TABLE `tb_ubziprstga` CHANGE `col_pspaxkzovq` `col_mlpyhxlthp` bit NOT NULL;\nALTER TABLE `tb_ubziprstga` DROP `col_mlpyhxlthp`;\nALTER TABLE `tb_ubziprstga` DROP COLUMN `col_fjhnhxlfmc`;\nALTER TABLE `tb_ubziprstga` DROP COLUMN `col_slcmuapykg`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_11.sql",
    "content": "CREATE TABLE `tb_urvrplctvm` (\n  `col_nhgbwyjskp` timestamp(3) NULL,\n  `col_tafveczsvk` datetime(5),\n  `col_kzrjsjtgnj` bigint(192) zerofill,\n  UNIQUE INDEX `col_nhgbwyjskp` (`col_nhgbwyjskp`),\n  UNIQUE `uk_zizxxnbpva` (`col_nhgbwyjskp`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_ugiidczptx` (\n  `col_fklmphgxdx` mediumtext CHARACTER SET utf8,\n  UNIQUE KEY `col_fklmphgxdx` (`col_fklmphgxdx`(1))\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_ehakozpvcb` LIKE `tb_ugiidczptx`;\nRENAME TABLE `tb_ehakozpvcb` TO `tb_qgeelwokgc`;\nDROP TABLE tb_ugiidczptx, tb_qgeelwokgc;\nDROP TABLE tb_urvrplctvm;\nCREATE TABLE `tb_ytaiteijaz` (\n  `col_tudnbijtqu` time NULL,\n  `col_lxtrjmhpmr` year,\n  `col_wvvanapjlz` timestamp NOT NULL,\n  PRIMARY KEY (`col_wvvanapjlz`),\n  UNIQUE `uk_pffwfanush` (`col_wvvanapjlz`)\n) DEFAULT CHARSET=utf8;\nALTER TABLE `tb_ytaiteijaz` ADD (`col_rjguymssfi` tinyint(83) unsigned DEFAULT '1', `col_vapswtjoqo` smallint unsigned zerofill NOT NULL);\nALTER TABLE `tb_ytaiteijaz` ADD COLUMN (`col_xnljwkzjad` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT 'enum_or_set_0', `col_kajgusvxkq` smallint(75));\nALTER TABLE `tb_ytaiteijaz` ADD COLUMN `col_adlsfkuaee` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') AFTER `col_vapswtjoqo`;\nALTER TABLE `tb_ytaiteijaz` ADD `col_ohppccpxlg` datetime NOT NULL DEFAULT '2019-07-04 00:00:00';\nALTER TABLE `tb_ytaiteijaz` ADD `col_wougwncovl` decimal(28,22) NULL;\nALTER TABLE `tb_ytaiteijaz` ADD COLUMN (`col_qdhtjqsfti` mediumblob, `col_ryjkfjtwvk` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2'));\nALTER TABLE `tb_ytaiteijaz` ADD COLUMN `col_gcahrhoadr` tinyblob;\nALTER TABLE `tb_ytaiteijaz` ADD `col_ihtpuurapz` bit(28) AFTER `col_vapswtjoqo`;\nALTER TABLE `tb_ytaiteijaz` ADD COLUMN `col_agolscsuau` char(106) NULL;\nALTER TABLE `tb_ytaiteijaz` ADD UNIQUE KEY `col_kajgusvxkq`(`col_kajgusvxkq`,`col_wougwncovl`);\nALTER TABLE `tb_ytaiteijaz` ADD UNIQUE (`col_vapswtjoqo`);\nALTER TABLE `tb_ytaiteijaz` ALTER `col_wougwncovl` DROP DEFAULT;\nALTER TABLE `tb_ytaiteijaz` CHANGE COLUMN `col_gcahrhoadr` `col_huflgowphp` mediumint unsigned zerofill AFTER `col_tudnbijtqu`;\nALTER TABLE `tb_ytaiteijaz` CHANGE COLUMN `col_huflgowphp` `col_wghwzcsnsa` text CHARACTER SET utf8mb4 FIRST;\nALTER TABLE `tb_ytaiteijaz` CHANGE `col_tudnbijtqu` `col_pwojmgycov` bigint unsigned zerofill NULL AFTER `col_ohppccpxlg`;\nALTER TABLE `tb_ytaiteijaz` DROP `col_qdhtjqsfti`;\nALTER TABLE `tb_ytaiteijaz` DROP COLUMN `col_ohppccpxlg`;\nALTER TABLE `tb_ytaiteijaz` DROP COLUMN `col_wghwzcsnsa`;\nALTER TABLE `tb_ytaiteijaz` DROP COLUMN `col_adlsfkuaee`, DROP COLUMN `col_agolscsuau`;\nALTER TABLE `tb_ytaiteijaz` DROP COLUMN `col_ihtpuurapz`, DROP COLUMN `col_vapswtjoqo`;\nALTER TABLE `tb_ytaiteijaz` DROP COLUMN `col_ryjkfjtwvk`;\nALTER TABLE `tb_ytaiteijaz` DROP COLUMN `col_wougwncovl`, DROP COLUMN `col_rjguymssfi`;\nALTER TABLE `tb_ytaiteijaz` DROP PRIMARY KEY;\nALTER TABLE `tb_ytaiteijaz` DROP KEY `col_kajgusvxkq`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_12.sql",
    "content": "CREATE TABLE `tb_izihmqlvrc` (\n  `col_niyefsuvyu` time NOT NULL,\n  `col_wtkibsyxum` blob(2345255919),\n  `col_cdltiwnbvu` bigint,\n  `col_prrfzwipjb` datetime(0) NULL,\n  CONSTRAINT symb_fjxbkxuxip PRIMARY KEY (`col_niyefsuvyu`),\n  UNIQUE KEY `uk_gdipvvuekw` (`col_cdltiwnbvu`),\n  UNIQUE INDEX `uk_ksyxhyhtqd` (`col_wtkibsyxum`(22),`col_cdltiwnbvu`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_fnxaykfskl` (\n  `col_rqdbfezzoe` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 COLLATE utf8_unicode_ci,\n  UNIQUE `uk_lvhtqnyvmw` (`col_rqdbfezzoe`),\n  UNIQUE INDEX `col_rqdbfezzoe` (`col_rqdbfezzoe`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_xyumhtxajs` (\n  `col_vfmmubhple` datetime NULL,\n  `col_dedkqeyizw` int unsigned NULL DEFAULT '1',\n  `col_imfsauznol` longtext CHARACTER SET utf8mb4,\n  `col_jqxasrchdv` double(240,6) NOT NULL,\n  PRIMARY KEY (`col_jqxasrchdv`)\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_xyumhtxajs` TO `tb_dwdawlyulx`, `tb_izihmqlvrc` TO `tb_tqqjgqvlty`;\nRENAME TABLE `tb_tqqjgqvlty` TO `tb_vltiykvgrd`;\nRENAME TABLE `tb_vltiykvgrd` TO `tb_fswsddbzby`;\nDROP TABLE tb_dwdawlyulx;\nDROP TABLE tb_fnxaykfskl, tb_fswsddbzby;\nCREATE TABLE `tb_jhqwojqbtj` (\n  `col_byfkvdrjfx` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4,\n  `col_unzkrhvwzx` integer unsigned zerofill,\n  `col_nnvyxvtluu` int(255) unsigned DEFAULT '1',\n  `col_flcxltquqr` longtext CHARACTER SET latin1\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nALTER TABLE `tb_jhqwojqbtj` ADD COLUMN (`col_tbaacjfxyz` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') NOT NULL, `col_xswcrnwfit` mediumblob);\nALTER TABLE `tb_jhqwojqbtj` ADD COLUMN `col_ksprsgkzrb` text(912789829) CHARACTER SET utf8mb4;\nALTER TABLE `tb_jhqwojqbtj` ADD COLUMN (`col_yhizzxtwet` integer unsigned, `col_mcyfebamvx` smallint(85) DEFAULT '1');\nALTER TABLE `tb_jhqwojqbtj` ADD (`col_bsjtvoujom` bit(55) NOT NULL DEFAULT b'0', `col_ndohgxbgox` float DEFAULT '1');\nALTER TABLE `tb_jhqwojqbtj` ADD (`col_egszzxhsvf` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') NOT NULL DEFAULT 'enum_or_set_0', `col_kycviiihvh` date);\nALTER TABLE `tb_jhqwojqbtj` ADD (`col_bqcpudnbtu` integer(189) NULL DEFAULT '1', `col_sexypgjnak` date DEFAULT '2019-07-04');\nALTER TABLE `tb_jhqwojqbtj` ADD `col_hemnlexcdd` int zerofill FIRST;\nALTER TABLE `tb_jhqwojqbtj` ADD (`col_pntvqnccno` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NOT NULL, `col_vedygstsxf` timestamp(0) NULL DEFAULT CURRENT_TIMESTAMP(0));\nALTER TABLE `tb_jhqwojqbtj` ADD COLUMN (`col_qabskemxzo` tinyint(23) unsigned zerofill, `col_tnkspeksfi` tinytext);\nALTER TABLE `tb_jhqwojqbtj` ADD PRIMARY KEY (`col_tbaacjfxyz`);\nALTER TABLE `tb_jhqwojqbtj` ALTER `col_egszzxhsvf` DROP DEFAULT;\nALTER TABLE `tb_jhqwojqbtj` CHANGE `col_unzkrhvwzx` `col_gwajcvodth` year(4) NOT NULL DEFAULT '2019';\nALTER TABLE `tb_jhqwojqbtj` CHANGE COLUMN `col_bqcpudnbtu` `col_cuzojqplje` year DEFAULT '2019';\nALTER TABLE `tb_jhqwojqbtj` DROP `col_qabskemxzo`, DROP `col_vedygstsxf`;\nALTER TABLE `tb_jhqwojqbtj` DROP `col_byfkvdrjfx`;\nALTER TABLE `tb_jhqwojqbtj` DROP `col_tbaacjfxyz`, DROP `col_kycviiihvh`;\nALTER TABLE `tb_jhqwojqbtj` DROP `col_mcyfebamvx`;\nALTER TABLE `tb_jhqwojqbtj` DROP COLUMN `col_yhizzxtwet`, DROP COLUMN `col_bsjtvoujom`;\nALTER TABLE `tb_jhqwojqbtj` DROP `col_tnkspeksfi`, DROP `col_xswcrnwfit`;\nALTER TABLE `tb_jhqwojqbtj` DROP `col_nnvyxvtluu`;\nALTER TABLE `tb_jhqwojqbtj` DROP `col_pntvqnccno`, DROP `col_hemnlexcdd`;\nALTER TABLE `tb_jhqwojqbtj` DROP `col_gwajcvodth`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_13.sql",
    "content": "CREATE TABLE `tb_tmeujebigu` (\n  `col_vexgpiotuy` binary,\n  `col_uouidnfxfe` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_tmeujebigu` TO `tb_vqlldbakax`;\nRENAME TABLE `tb_vqlldbakax` TO `tb_xduxzgfsux`;\nRENAME TABLE `tb_xduxzgfsux` TO `tb_yfhnotrnrt`;\nALTER TABLE `tb_yfhnotrnrt` ADD COLUMN (`col_cueciidhfy` timestamp(1) NULL DEFAULT CURRENT_TIMESTAMP(1), `col_xebqcglpvr` char);\nALTER TABLE `tb_yfhnotrnrt` ADD (`col_cvhurmqyru` tinyint(52) zerofill NOT NULL, `col_gdsggqabpa` mediumblob);\nALTER TABLE `tb_yfhnotrnrt` ADD (`col_mstusvmhpu` tinytext CHARACTER SET utf8mb4, `col_dyphdacvvd` tinytext CHARACTER SET utf8mb4);\nALTER TABLE `tb_yfhnotrnrt` ADD COLUMN (`col_ulwbtrmfes` smallint unsigned DEFAULT '1', `col_xgueitftmx` float(247,18));\nALTER TABLE `tb_yfhnotrnrt` ADD (`col_spogbqhjrx` date NOT NULL, `col_ormwjqfbxi` int(193) unsigned zerofill NULL);\nALTER TABLE `tb_yfhnotrnrt` ADD COLUMN `col_iruzsjhmbm` varbinary(83) DEFAULT '\\0';\nALTER TABLE `tb_yfhnotrnrt` CHARACTER SET utf8;\nALTER TABLE `tb_yfhnotrnrt` ALTER COLUMN `col_iruzsjhmbm` DROP DEFAULT;\nALTER TABLE `tb_yfhnotrnrt` ALTER COLUMN `col_ormwjqfbxi` SET DEFAULT NULL;\nALTER TABLE `tb_yfhnotrnrt` ALTER COLUMN `col_xgueitftmx` DROP DEFAULT;\nALTER TABLE `tb_yfhnotrnrt` CHANGE `col_ulwbtrmfes` `col_kednlljjiu` date NOT NULL DEFAULT '2019-07-04' AFTER `col_gdsggqabpa`;\nALTER TABLE `tb_yfhnotrnrt` CHANGE `col_xebqcglpvr` `col_qslraszfyz` longtext CHARACTER SET utf8mb4;\nALTER TABLE `tb_yfhnotrnrt` CHANGE `col_kednlljjiu` `col_irqdemfadw` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 DEFAULT 'enum_or_set_0';\nALTER TABLE `tb_yfhnotrnrt` DROP `col_gdsggqabpa`;\nALTER TABLE `tb_yfhnotrnrt` DROP COLUMN `col_uouidnfxfe`;\nALTER TABLE `tb_yfhnotrnrt` DROP COLUMN `col_irqdemfadw`;\nALTER TABLE `tb_yfhnotrnrt` DROP `col_cueciidhfy`, DROP `col_mstusvmhpu`;\nALTER TABLE `tb_yfhnotrnrt` DROP COLUMN `col_spogbqhjrx`;\nALTER TABLE `tb_yfhnotrnrt` DROP `col_iruzsjhmbm`, DROP `col_cvhurmqyru`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_14.sql",
    "content": "CREATE TABLE `tb_mzhjgiljck` (\n  `col_lnqceyzqyi` mediumint DEFAULT '1',\n  `col_rorzwqbqzc` varbinary(190) NULL,\n  `col_qfegkgeaal` tinyint unsigned DEFAULT '1',\n  UNIQUE `uk_nvoltofkla` (`col_rorzwqbqzc`(15))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_jwpndmdumd` (\n  `col_vpupwhoacr` bit(52) DEFAULT b'0',\n  UNIQUE `uk_ghdynafkbb` (`col_vpupwhoacr`),\n  UNIQUE `uk_pdhqnqgdnh` (`col_vpupwhoacr`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_jwpndmdumd` TO `tb_xnqicybdlo`, `tb_mzhjgiljck` TO `tb_cmzqttalvi`;\nALTER TABLE `tb_xnqicybdlo` ADD COLUMN `col_jzysxyqbvv` binary(91) NULL;\nALTER TABLE `tb_xnqicybdlo` ADD `col_ldvvuuqjus` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT 'enum_or_set_0' FIRST;\nALTER TABLE `tb_xnqicybdlo` ADD (`col_drciitekzb` longblob, `col_ocncfebity` numeric(32,27));\nALTER TABLE `tb_xnqicybdlo` ADD `col_uzoealeegi` binary;\nALTER TABLE `tb_xnqicybdlo` ADD COLUMN (`col_qnchccpalx` binary(157) NULL, `col_daawnfezqe` datetime(1) NULL);\nALTER TABLE `tb_xnqicybdlo` ADD UNIQUE INDEX (`col_jzysxyqbvv`(31),`col_uzoealeegi`);\nALTER TABLE `tb_xnqicybdlo` ADD UNIQUE `uk_spjmyismss` (`col_ldvvuuqjus`);\nALTER TABLE `tb_xnqicybdlo` ALTER COLUMN `col_uzoealeegi` SET DEFAULT NULL;\nALTER TABLE `tb_xnqicybdlo` ALTER COLUMN `col_jzysxyqbvv` DROP DEFAULT;\nALTER TABLE `tb_xnqicybdlo` ALTER COLUMN `col_qnchccpalx` DROP DEFAULT;\nALTER TABLE `tb_xnqicybdlo` DROP `col_vpupwhoacr`;\nALTER TABLE `tb_xnqicybdlo` DROP COLUMN `col_daawnfezqe`, DROP COLUMN `col_uzoealeegi`;\nALTER TABLE `tb_xnqicybdlo` DROP `col_ocncfebity`, DROP `col_ldvvuuqjus`;\nALTER TABLE `tb_xnqicybdlo` DROP `col_qnchccpalx`;\nALTER TABLE `tb_xnqicybdlo` DROP `col_drciitekzb`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_15.sql",
    "content": "CREATE TABLE `tb_odalwcctzo` (\n  `col_zfwcescosm` bit,\n  `col_gvrsiekgpu` mediumint NULL,\n  `col_luknerkzbg` year\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_ypebrnimav` LIKE `tb_odalwcctzo`;\nRENAME TABLE `tb_odalwcctzo` TO `tb_hgbecqwvnf`, `tb_ypebrnimav` TO `tb_dqeiczpcpp`;\nALTER TABLE `tb_hgbecqwvnf` ADD COLUMN (`col_iomejxwfzh` timestamp, `col_dqpoxmoyzl` bigint(111) unsigned NULL DEFAULT '1');\nALTER TABLE `tb_hgbecqwvnf` ADD COLUMN (`col_ocmmfdzihr` tinytext, `col_thbfgmggyp` blob);\nALTER TABLE `tb_hgbecqwvnf` ADD COLUMN `col_nyrvlflfiz` mediumblob FIRST;\nALTER TABLE `tb_hgbecqwvnf` ADD COLUMN `col_cdafuglmqd` mediumblob AFTER `col_ocmmfdzihr`;\nALTER TABLE `tb_hgbecqwvnf` ADD (`col_ibpfuqwtka` integer(152) zerofill NOT NULL, `col_mfbftkexwt` time(4) NULL);\nALTER TABLE `tb_hgbecqwvnf` ADD `col_rfnetihhhs` numeric(15) NOT NULL AFTER `col_ibpfuqwtka`;\nALTER TABLE `tb_hgbecqwvnf` ADD `col_shfhtlxxhg` bigint unsigned zerofill;\nALTER TABLE `tb_hgbecqwvnf` ADD (`col_jhaqzczhxe` mediumblob, `col_gfdmpyoigq` time(1));\nALTER TABLE `tb_hgbecqwvnf` CHARACTER SET = utf8mb4;\nALTER TABLE `tb_hgbecqwvnf` ADD CONSTRAINT symb_vxlhuityyt PRIMARY KEY (`col_iomejxwfzh`);\nALTER TABLE `tb_hgbecqwvnf` ADD UNIQUE `uk_lsuitvpjev` (`col_iomejxwfzh`,`col_dqpoxmoyzl`);\nALTER TABLE `tb_hgbecqwvnf` ADD UNIQUE `col_luknerkzbg`(`col_luknerkzbg`,`col_dqpoxmoyzl`);\nALTER TABLE `tb_hgbecqwvnf` ALTER `col_rfnetihhhs` DROP DEFAULT;\nALTER TABLE `tb_hgbecqwvnf` ALTER COLUMN `col_dqpoxmoyzl` SET DEFAULT '1';\nALTER TABLE `tb_hgbecqwvnf` CHANGE `col_luknerkzbg` `col_ulsyzrcnlh` float(35) NULL;\nALTER TABLE `tb_hgbecqwvnf` CHANGE `col_ulsyzrcnlh` `col_qppnejcxiu` binary(137) FIRST;\nALTER TABLE `tb_hgbecqwvnf` DROP COLUMN `col_shfhtlxxhg`;\nALTER TABLE `tb_hgbecqwvnf` DROP COLUMN `col_iomejxwfzh`, DROP COLUMN `col_cdafuglmqd`;\nALTER TABLE `tb_hgbecqwvnf` DROP COLUMN `col_thbfgmggyp`, DROP COLUMN `col_mfbftkexwt`;\nALTER TABLE `tb_hgbecqwvnf` DROP COLUMN `col_ibpfuqwtka`, DROP COLUMN `col_ocmmfdzihr`;\nALTER TABLE `tb_hgbecqwvnf` DROP COLUMN `col_gvrsiekgpu`;\nALTER TABLE `tb_hgbecqwvnf` DROP KEY `uk_lsuitvpjev`;\nALTER TABLE `tb_hgbecqwvnf` DROP INDEX `col_luknerkzbg`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_16.sql",
    "content": "CREATE TABLE `tb_baxubvrijb` (\n  `col_kcwxoovscx` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 DEFAULT 'enum_or_set_0',\n  `col_fpfpelfmso` float(57,8) NULL,\n  `col_dbtkzzfxoi` varbinary(22) NOT NULL,\n  CONSTRAINT symb_hrwhbxnbts PRIMARY KEY (`col_dbtkzzfxoi`(10)),\n  UNIQUE `col_dbtkzzfxoi` (`col_dbtkzzfxoi`(2)),\n  UNIQUE KEY `col_fpfpelfmso` (`col_fpfpelfmso`,`col_dbtkzzfxoi`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_ddzfshecwo` (\n  `col_rryluiawnq` varchar(24) CHARACTER SET latin1 DEFAULT '',\n  `col_bdlbhtissa` year(4) NULL,\n  `col_kfawipagkn` tinyblob\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_ddzfshecwo` TO `tb_bcsetyvuul`, `tb_baxubvrijb` TO `tb_nxbyklxowd`;\nRENAME TABLE `tb_bcsetyvuul` TO `tb_dlnhztodao`;\nALTER TABLE `tb_nxbyklxowd` ADD `col_zkfycwevvo` time;\nALTER TABLE `tb_nxbyklxowd` ADD COLUMN (`col_ememhbgtcx` bit NULL DEFAULT b'0', `col_zrrfkkosvo` char(203) CHARACTER SET utf8mb4);\nALTER TABLE `tb_nxbyklxowd` ADD (`col_fpafdojbdn` decimal(9,9) NULL, `col_juolcidyaj` datetime DEFAULT '2019-07-04 00:00:00');\nALTER TABLE `tb_nxbyklxowd` ADD `col_qhgfympzxa` longtext;\nALTER TABLE `tb_nxbyklxowd` ADD COLUMN (`col_tymlykugck` integer(83) zerofill, `col_awkvpagorc` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT 'enum_or_set_0');\nALTER TABLE `tb_nxbyklxowd` ADD COLUMN `col_crrxfxfdzs` datetime(0);\nALTER TABLE `tb_nxbyklxowd` ADD COLUMN (`col_cgdxdxesyd` decimal NOT NULL, `col_pjkofcyiht` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 DEFAULT 'enum_or_set_0');\nALTER TABLE `tb_nxbyklxowd` ADD COLUMN `col_iiqainhxkc` smallint(81) zerofill NULL;\nALTER TABLE `tb_nxbyklxowd` ADD (`col_kbnueyzmpm` tinyblob, `col_zixjkfdybk` binary NOT NULL);\nALTER TABLE `tb_nxbyklxowd` CHARACTER SET = utf8mb4;\nALTER TABLE `tb_nxbyklxowd` ADD UNIQUE `col_cgdxdxesyd`(`col_cgdxdxesyd`,`col_iiqainhxkc`);\nALTER TABLE `tb_nxbyklxowd` ADD UNIQUE KEY `uk_regnlkocpv` (`col_zrrfkkosvo`(16),`col_fpafdojbdn`);\nALTER TABLE `tb_nxbyklxowd` ALTER `col_dbtkzzfxoi` DROP DEFAULT;\nALTER TABLE `tb_nxbyklxowd` ALTER `col_iiqainhxkc` DROP DEFAULT;\nALTER TABLE `tb_nxbyklxowd` ALTER `col_kcwxoovscx` DROP DEFAULT;\nALTER TABLE `tb_nxbyklxowd` CHANGE COLUMN `col_fpfpelfmso` `col_xkzfmyvfvv` smallint DEFAULT '1' FIRST;\nALTER TABLE `tb_nxbyklxowd` DROP `col_juolcidyaj`, DROP `col_pjkofcyiht`;\nALTER TABLE `tb_nxbyklxowd` DROP COLUMN `col_xkzfmyvfvv`;\nALTER TABLE `tb_nxbyklxowd` DROP INDEX `col_cgdxdxesyd`;\nALTER TABLE `tb_nxbyklxowd` DROP INDEX `uk_regnlkocpv`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_17.sql",
    "content": "CREATE TABLE `tb_aaxiqmpjjd` (\n  `col_psfdpvpotp` integer(136) unsigned\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_axknhurptj` (\n  `col_ezolqkylrw` bigint DEFAULT '1',\n  `col_itrckjigax` tinyint zerofill,\n  `col_vywhhgaozj` year,\n  `col_xdrbsjifvv` datetime(1)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_ciqhkflcci` (\n  `col_dgkncfpqja` bit(46) DEFAULT b'0',\n  UNIQUE `col_dgkncfpqja` (`col_dgkncfpqja`),\n  UNIQUE `uk_kcnspithfv` (`col_dgkncfpqja`)\n) DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_axknhurptj` TO `tb_iilujirnjb`;\nRENAME TABLE `tb_iilujirnjb` TO `tb_aftfwefuwe`;\nDROP TABLE tb_aaxiqmpjjd;\nDROP TABLE tb_ciqhkflcci, tb_aftfwefuwe;\nCREATE TABLE `tb_ygyyvdctrs` (\n  `col_emexlkeymz` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 DEFAULT 'enum_or_set_0',\n  UNIQUE KEY `uk_kcmgrgarnq` (`col_emexlkeymz`),\n  UNIQUE `col_emexlkeymz` (`col_emexlkeymz`)\n) DEFAULT CHARSET=latin1;\nALTER TABLE `tb_ygyyvdctrs` ADD COLUMN `col_ljhqsygrcc` mediumtext FIRST;\nALTER TABLE `tb_ygyyvdctrs` ADD COLUMN (`col_ibmogxgtyp` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT 'enum_or_set_0', `col_lqozcajhii` tinyblob);\nALTER TABLE `tb_ygyyvdctrs` ADD (`col_yzbwkjwzqw` int zerofill NOT NULL, `col_dmdpojzsct` varbinary(166));\nALTER TABLE `tb_ygyyvdctrs` ADD `col_oxgbfbgzov` double(112,2);\nALTER TABLE `tb_ygyyvdctrs` ADD COLUMN `col_hirzxaomit` varbinary(145) NOT NULL FIRST;\nALTER TABLE `tb_ygyyvdctrs` ADD COLUMN `col_dxgsghrizm` tinyblob;\nALTER TABLE `tb_ygyyvdctrs` ADD `col_zkdwjtabnw` smallint unsigned NOT NULL AFTER `col_oxgbfbgzov`;\nALTER TABLE `tb_ygyyvdctrs` ADD COLUMN (`col_bowjbzwvyw` date, `col_inneappfsm` varchar(112) CHARACTER SET utf8mb4);\nALTER TABLE `tb_ygyyvdctrs` CHARACTER SET utf8;\nALTER TABLE `tb_ygyyvdctrs` ADD CONSTRAINT PRIMARY KEY (`col_hirzxaomit`(25));\nALTER TABLE `tb_ygyyvdctrs` ALTER COLUMN `col_ibmogxgtyp` DROP DEFAULT;\nALTER TABLE `tb_ygyyvdctrs` ALTER COLUMN `col_hirzxaomit` DROP DEFAULT;\nALTER TABLE `tb_ygyyvdctrs` ALTER COLUMN `col_ibmogxgtyp` SET DEFAULT 'enum_or_set_0';\nALTER TABLE `tb_ygyyvdctrs` CHANGE COLUMN `col_ljhqsygrcc` `col_rpxmbgbwos` longblob;\nALTER TABLE `tb_ygyyvdctrs` CHANGE `col_lqozcajhii` `col_qdbxvykcyv` tinytext CHARACTER SET utf8 COLLATE utf8_unicode_ci;\nALTER TABLE `tb_ygyyvdctrs` DROP COLUMN `col_qdbxvykcyv`;\nALTER TABLE `tb_ygyyvdctrs` DROP PRIMARY KEY;\nALTER TABLE `tb_ygyyvdctrs` DROP KEY `uk_kcmgrgarnq`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_18.sql",
    "content": "CREATE TABLE `tb_pnracjzmkp` (\n  `col_zoovnitdls` float(13,13),\n  `col_prrcfbnwew` longtext CHARACTER SET utf8mb4,\n  `col_peqguxwzcy` smallint(202) NOT NULL DEFAULT '1'\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_qwbjzchejk` LIKE `tb_pnracjzmkp`;\nRENAME TABLE `tb_qwbjzchejk` TO `tb_ezxnrjkvwu`, `tb_pnracjzmkp` TO `tb_jhkrixchju`;\nRENAME TABLE `tb_ezxnrjkvwu` TO `tb_nxqxynvjvx`;\nDROP TABLE tb_nxqxynvjvx;\nALTER TABLE `tb_jhkrixchju` ADD COLUMN (`col_fpmvnrnoxw` varchar(18) NOT NULL, `col_hrcqpnxnrn` text(1490675533));\nALTER TABLE `tb_jhkrixchju` ADD COLUMN (`col_iguvbfennm` year(4) NOT NULL, `col_nhdlxtgtvs` char NULL);\nALTER TABLE `tb_jhkrixchju` ADD `col_vyizooodsa` longblob AFTER `col_nhdlxtgtvs`;\nALTER TABLE `tb_jhkrixchju` ADD (`col_hwmrzghead` longtext CHARACTER SET utf8mb4, `col_adgnavqmhq` longtext CHARACTER SET utf8mb4);\nALTER TABLE `tb_jhkrixchju` ADD (`col_adwetrnlyu` bit(41), `col_ypyzwlctxm` varbinary(86) DEFAULT '\\0');\nALTER TABLE `tb_jhkrixchju` ADD (`col_lkdcwbjkis` varbinary(61), `col_rmjdxsrzry` char(159) CHARACTER SET utf8mb4);\nALTER TABLE `tb_jhkrixchju` ADD (`col_sfmloqjxwi` decimal(33,29) NOT NULL, `col_mcjrxquwtj` binary);\nALTER TABLE `tb_jhkrixchju` ADD COLUMN (`col_fxxexsgvmq` int(11) unsigned NOT NULL, `col_ilcapoaext` mediumblob);\nALTER TABLE `tb_jhkrixchju` ADD (`col_dvcgmijmcd` smallint(246) unsigned NOT NULL DEFAULT '1', `col_avjufpxxft` timestamp NULL);\nALTER TABLE `tb_jhkrixchju` DEFAULT CHARACTER SET = utf8mb4;\nALTER TABLE `tb_jhkrixchju` DROP `col_fxxexsgvmq`, DROP `col_iguvbfennm`;\nALTER TABLE `tb_jhkrixchju` DROP `col_zoovnitdls`, DROP `col_lkdcwbjkis`;\nALTER TABLE `tb_jhkrixchju` DROP COLUMN `col_fpmvnrnoxw`;\nALTER TABLE `tb_jhkrixchju` DROP `col_sfmloqjxwi`, DROP `col_hrcqpnxnrn`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_19.sql",
    "content": "CREATE TABLE `tb_gbdjlupmhj` (\n  `col_zciuwofqxv` float(151,15)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_yubjqntjhv` LIKE `tb_gbdjlupmhj`;\nRENAME TABLE `tb_yubjqntjhv` TO `tb_obmtwwzsar`, `tb_gbdjlupmhj` TO `tb_acbpixrigq`;\nRENAME TABLE `tb_obmtwwzsar` TO `tb_hefguylckk`, `tb_acbpixrigq` TO `tb_nfcvlzwedu`;\nDROP TABLE tb_nfcvlzwedu;\nALTER TABLE `tb_hefguylckk` ADD `col_hjucxhsncd` mediumint(206) unsigned zerofill;\nALTER TABLE `tb_hefguylckk` ADD (`col_bblhcpxxju` tinyblob, `col_fcmfyfomtk` tinyblob);\nALTER TABLE `tb_hefguylckk` DEFAULT CHARACTER SET = utf8mb4;\nALTER TABLE `tb_hefguylckk` ADD UNIQUE `uk_qgxgwlyozf` (`col_fcmfyfomtk`(14));\nALTER TABLE `tb_hefguylckk` ADD UNIQUE INDEX (`col_bblhcpxxju`(25));\nALTER TABLE `tb_hefguylckk` CHANGE `col_zciuwofqxv` `col_oidtfumfdm` tinyblob;\nALTER TABLE `tb_hefguylckk` CHANGE `col_oidtfumfdm` `col_qzehomawzl` integer NULL;\nALTER TABLE `tb_hefguylckk` DROP COLUMN `col_fcmfyfomtk`, DROP COLUMN `col_hjucxhsncd`;\nALTER TABLE `tb_hefguylckk` DROP COLUMN `col_bblhcpxxju`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_2.sql",
    "content": "CREATE TABLE `tb_kyvyqhwcpi` (\n  `col_pesoyggsjl` mediumblob,\n  `col_hctgmkmyxs` datetime DEFAULT '2019-07-04 00:00:00',\n  `col_kkvhrfifbo` longtext CHARACTER SET utf8,\n  `col_ewyzkapekq` longblob,\n  UNIQUE KEY `uk_jvoonsdsfr` (`col_pesoyggsjl`(32)),\n  UNIQUE INDEX `col_kkvhrfifbo` (`col_kkvhrfifbo`(31))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_kyvyqhwcpi` TO `tb_zyynbdsyib`;\nRENAME TABLE `tb_zyynbdsyib` TO `tb_gcqyhapjeh`;\nALTER TABLE `tb_gcqyhapjeh` ADD `col_mlfdocnxzd` text CHARACTER SET utf8 FIRST;\nALTER TABLE `tb_gcqyhapjeh` ADD COLUMN (`col_yxhhhxgwjz` datetime(5) NOT NULL, `col_mqfdtybcrt` longtext);\nALTER TABLE `tb_gcqyhapjeh` ADD (`col_dszxjztuni` varbinary(68) NOT NULL DEFAULT '\\0', `col_sukknvclub` longblob);\nALTER TABLE `tb_gcqyhapjeh` ADD COLUMN (`col_zhvifnzhjr` tinyint(107) zerofill, `col_fscylalync` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8);\nALTER TABLE `tb_gcqyhapjeh` ADD `col_ddgcxloigt` bit(6) NULL;\nALTER TABLE `tb_gcqyhapjeh` ADD (`col_ihidhmecqm` tinytext, `col_icjiguudiw` bigint zerofill);\nALTER TABLE `tb_gcqyhapjeh` ADD COLUMN `col_hxvzygxblr` binary;\nALTER TABLE `tb_gcqyhapjeh` ADD (`col_xiszwdtbgk` tinyint zerofill NOT NULL, `col_cdyttfqwra` longblob);\nALTER TABLE `tb_gcqyhapjeh` ADD `col_jzhdjycrpd` longtext AFTER `col_ewyzkapekq`;\nALTER TABLE `tb_gcqyhapjeh` ADD UNIQUE (`col_cdyttfqwra`(29));\nALTER TABLE `tb_gcqyhapjeh` ALTER COLUMN `col_icjiguudiw` DROP DEFAULT;\nALTER TABLE `tb_gcqyhapjeh` DROP `col_cdyttfqwra`;\nALTER TABLE `tb_gcqyhapjeh` DROP COLUMN `col_pesoyggsjl`, DROP COLUMN `col_sukknvclub`;\nALTER TABLE `tb_gcqyhapjeh` DROP `col_dszxjztuni`, DROP `col_xiszwdtbgk`;\nALTER TABLE `tb_gcqyhapjeh` DROP `col_ewyzkapekq`;\nALTER TABLE `tb_gcqyhapjeh` DROP COLUMN `col_mlfdocnxzd`, DROP COLUMN `col_zhvifnzhjr`;\nALTER TABLE `tb_gcqyhapjeh` DROP `col_jzhdjycrpd`;\nALTER TABLE `tb_gcqyhapjeh` DROP COLUMN `col_ihidhmecqm`, DROP COLUMN `col_yxhhhxgwjz`;\nALTER TABLE `tb_gcqyhapjeh` DROP `col_fscylalync`, DROP `col_hxvzygxblr`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_20.sql",
    "content": "CREATE TABLE `tb_zjdvakwwwv` (\n  `col_bytftanpdh` mediumint(56) unsigned DEFAULT '1',\n  `col_zwyhucxxkr` year(4) NOT NULL,\n  `col_desbhtchpe` text(3076914288) CHARACTER SET latin1,\n  `col_figelwsuqt` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET latin1 DEFAULT 'enum_or_set_0',\n  UNIQUE `col_desbhtchpe` (`col_desbhtchpe`(5)),\n  UNIQUE `col_bytftanpdh` (`col_bytftanpdh`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_zjdvakwwwv` TO `tb_unztlaanoa`;\nRENAME TABLE `tb_unztlaanoa` TO `tb_wxywfqcvkr`;\nALTER TABLE `tb_wxywfqcvkr` ADD COLUMN (`col_hikfliwljt` varchar(14), `col_vrnocgbjsc` mediumtext CHARACTER SET utf8);\nALTER TABLE `tb_wxywfqcvkr` ADD COLUMN (`col_gudluixdai` char, `col_adpuaqjrtd` numeric(22,2) NOT NULL);\nALTER TABLE `tb_wxywfqcvkr` ADD COLUMN `col_vjvhvsxmoi` bigint zerofill AFTER `col_desbhtchpe`;\nALTER TABLE `tb_wxywfqcvkr` ADD COLUMN (`col_whowxgsfzl` blob(1844532465), `col_mzdqafxiqx` bigint(161) unsigned DEFAULT '1');\nALTER TABLE `tb_wxywfqcvkr` ADD `col_spyfsutunk` bit DEFAULT b'0' AFTER `col_zwyhucxxkr`;\nALTER TABLE `tb_wxywfqcvkr` ADD `col_iqugcuomsl` numeric(9) NOT NULL;\nALTER TABLE `tb_wxywfqcvkr` ADD PRIMARY KEY (`col_zwyhucxxkr`,`col_adpuaqjrtd`);\nALTER TABLE `tb_wxywfqcvkr` CHANGE `col_zwyhucxxkr` `col_sixmujutpp` smallint zerofill NOT NULL AFTER `col_hikfliwljt`;\nALTER TABLE `tb_wxywfqcvkr` CHANGE COLUMN `col_hikfliwljt` `col_oftatmlkzc` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') NOT NULL FIRST;\nALTER TABLE `tb_wxywfqcvkr` CHANGE COLUMN `col_spyfsutunk` `col_wwaeohiyto` timestamp FIRST;\nALTER TABLE `tb_wxywfqcvkr` DROP `col_adpuaqjrtd`;\nALTER TABLE `tb_wxywfqcvkr` DROP `col_iqugcuomsl`, DROP `col_sixmujutpp`;\nALTER TABLE `tb_wxywfqcvkr` DROP `col_vrnocgbjsc`;\nALTER TABLE `tb_wxywfqcvkr` DROP `col_wwaeohiyto`;\nALTER TABLE `tb_wxywfqcvkr` DROP `col_bytftanpdh`;\nALTER TABLE `tb_wxywfqcvkr` DROP `col_desbhtchpe`;\nALTER TABLE `tb_wxywfqcvkr` DROP COLUMN `col_gudluixdai`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_21.sql",
    "content": "CREATE TABLE `tb_kcqprbgueu` (\n  `col_bkngorvqcs` blob(236574804),\n  `col_zzurkpmmun` year(4) DEFAULT '2019',\n  `col_ysfndnoaxw` varchar(53) CHARACTER SET utf8 NOT NULL DEFAULT '',\n  PRIMARY KEY (`col_ysfndnoaxw`(25)),\n  UNIQUE `col_bkngorvqcs` (`col_bkngorvqcs`(26),`col_zzurkpmmun`),\n  UNIQUE `uk_gjdewbtjjb` (`col_zzurkpmmun`)\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_kcqprbgueu` TO `tb_vsurmlbmno`;\nRENAME TABLE `tb_vsurmlbmno` TO `tb_aaholafery`;\nRENAME TABLE `tb_aaholafery` TO `tb_mjvfhaqskb`;\nALTER TABLE `tb_mjvfhaqskb` ADD `col_njoaqbbtxv` bit(26) DEFAULT b'0';\nALTER TABLE `tb_mjvfhaqskb` ADD COLUMN `col_mipvhqbjat` mediumtext CHARACTER SET utf8 AFTER `col_zzurkpmmun`;\nALTER TABLE `tb_mjvfhaqskb` ADD COLUMN `col_bjzwkjcmer` decimal(17,10) FIRST;\nALTER TABLE `tb_mjvfhaqskb` ADD COLUMN (`col_qnkieomtxh` datetime(5), `col_olvjbrfhvy` char NULL);\nALTER TABLE `tb_mjvfhaqskb` ADD `col_bnupaoxxfv` blob(1570619016) AFTER `col_qnkieomtxh`;\nALTER TABLE `tb_mjvfhaqskb` ADD UNIQUE `uk_sidczmsazr` (`col_bkngorvqcs`(6),`col_mipvhqbjat`(25));\nALTER TABLE `tb_mjvfhaqskb` ALTER COLUMN `col_zzurkpmmun` DROP DEFAULT;\nALTER TABLE `tb_mjvfhaqskb` CHANGE COLUMN `col_bkngorvqcs` `col_kxxtstiztr` mediumblob;\nALTER TABLE `tb_mjvfhaqskb` CHANGE COLUMN `col_njoaqbbtxv` `col_snmdnyljqk` varbinary(47) DEFAULT '\\0' FIRST;\nALTER TABLE `tb_mjvfhaqskb` CHANGE `col_kxxtstiztr` `col_bfmjyipktn` mediumtext FIRST;\nALTER TABLE `tb_mjvfhaqskb` DROP `col_bfmjyipktn`;\nALTER TABLE `tb_mjvfhaqskb` DROP COLUMN `col_zzurkpmmun`, DROP COLUMN `col_ysfndnoaxw`;\nALTER TABLE `tb_mjvfhaqskb` DROP COLUMN `col_qnkieomtxh`;\nALTER TABLE `tb_mjvfhaqskb` DROP COLUMN `col_bjzwkjcmer`;\nALTER TABLE `tb_mjvfhaqskb` DROP `col_mipvhqbjat`, DROP `col_olvjbrfhvy`;\nALTER TABLE `tb_mjvfhaqskb` DROP `col_bnupaoxxfv`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_22.sql",
    "content": "CREATE TABLE `tb_sxbbqclsgf` (\n  `col_avzjcdfkfv` year(4) NOT NULL DEFAULT '2019',\n  `col_kgfprqgdwt` mediumtext CHARACTER SET latin1,\n  CONSTRAINT PRIMARY KEY (`col_avzjcdfkfv`),\n  UNIQUE `col_kgfprqgdwt` (`col_kgfprqgdwt`(6))\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_uakpdqzysm` (\n  `col_zknooyoueg` time NOT NULL DEFAULT '00:00:00',\n  `col_xavytdfgxu` mediumtext CHARACTER SET utf8,\n  `col_mgwiohebft` mediumtext CHARACTER SET utf8,\n  `col_bejzwcvfmz` date DEFAULT '2019-07-04',\n  UNIQUE `uk_cryfvwxbvx` (`col_zknooyoueg`,`col_xavytdfgxu`(9))\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_vktpftxscc` (\n  `col_wqtdmdoyoo` longblob\n) DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_uakpdqzysm` TO `tb_btqvbuxdyv`, `tb_vktpftxscc` TO `tb_fficunfgca`;\nDROP TABLE tb_fficunfgca;\nALTER TABLE `tb_sxbbqclsgf` ADD `col_glgspzmrxu` mediumint zerofill NOT NULL AFTER `col_avzjcdfkfv`;\nALTER TABLE `tb_sxbbqclsgf` ADD COLUMN (`col_rezszlbpen` mediumtext, `col_nmxcrltjbv` binary);\nALTER TABLE `tb_sxbbqclsgf` ADD (`col_wctphwmxin` smallint(103) unsigned zerofill NULL, `col_yadwowaswm` mediumint(118) unsigned zerofill NOT NULL);\nALTER TABLE `tb_sxbbqclsgf` ADD COLUMN `col_tekylcrmef` bit(17) NULL DEFAULT b'0';\nALTER TABLE `tb_sxbbqclsgf` ADD COLUMN `col_ukcpwepvny` timestamp(1) DEFAULT CURRENT_TIMESTAMP(1) FIRST;\nALTER TABLE `tb_sxbbqclsgf` DEFAULT CHARACTER SET utf8;\nALTER TABLE `tb_sxbbqclsgf` ADD UNIQUE `uk_htumixicdh` (`col_avzjcdfkfv`,`col_kgfprqgdwt`(28));\nALTER TABLE `tb_sxbbqclsgf` ALTER COLUMN `col_nmxcrltjbv` SET DEFAULT NULL;\nALTER TABLE `tb_sxbbqclsgf` CHANGE `col_yadwowaswm` `col_tappjfodgm` date NULL;\nALTER TABLE `tb_sxbbqclsgf` CHANGE COLUMN `col_nmxcrltjbv` `col_raprmikjbo` date;\nALTER TABLE `tb_sxbbqclsgf` DROP COLUMN `col_tappjfodgm`, DROP COLUMN `col_glgspzmrxu`;\nALTER TABLE `tb_sxbbqclsgf` DROP COLUMN `col_rezszlbpen`, DROP COLUMN `col_raprmikjbo`;\nALTER TABLE `tb_sxbbqclsgf` DROP PRIMARY KEY;\nALTER TABLE `tb_sxbbqclsgf` DROP KEY `uk_htumixicdh`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_23.sql",
    "content": "CREATE TABLE `tb_caahynuejc` (\n  `col_ceosnfriqs` integer,\n  `col_aklqoixrun` year(4),\n  UNIQUE INDEX `col_ceosnfriqs` (`col_ceosnfriqs`),\n  UNIQUE `uk_gekdmzrybz` (`col_aklqoixrun`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_xbsrcfksox` (\n  `col_qsljaaxbrj` datetime DEFAULT '2019-07-04 00:00:00',\n  `col_vusitjjcdx` char CHARACTER SET latin1,\n  `col_ufwmvwjonj` integer unsigned NOT NULL,\n  UNIQUE KEY `uk_henpwhqovc` (`col_ufwmvwjonj`),\n  UNIQUE INDEX `col_vusitjjcdx` (`col_vusitjjcdx`,`col_ufwmvwjonj`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_eroteuzada` (\n  `col_aipblmdcsw` float(32) NOT NULL,\n  `col_sklhosmnvr` bigint unsigned zerofill NOT NULL,\n  `col_skwdbrxmlc` mediumblob,\n  UNIQUE INDEX `col_aipblmdcsw` (`col_aipblmdcsw`,`col_sklhosmnvr`),\n  UNIQUE INDEX `uk_inmzvqrjoq` (`col_sklhosmnvr`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_eroteuzada` TO `tb_thlwjjfpcg`;\nRENAME TABLE `tb_thlwjjfpcg` TO `tb_ydbfvvwhvi`;\nALTER TABLE `tb_caahynuejc` ADD COLUMN `col_noipbutgvd` char CHARACTER SET utf8mb4 NULL;\nALTER TABLE `tb_caahynuejc` ADD (`col_eyefseknmn` time DEFAULT '00:00:00', `col_nxbdoexmux` bigint(139) zerofill NULL);\nALTER TABLE `tb_caahynuejc` ADD `col_aulqirvfec` tinyblob;\nALTER TABLE `tb_caahynuejc` ADD COLUMN (`col_tlcpasbobp` bigint zerofill NULL, `col_fyktzflvgx` tinytext CHARACTER SET utf8);\nALTER TABLE `tb_caahynuejc` ADD (`col_bufdgcwxci` time DEFAULT '00:00:00', `col_snfugvbwkh` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 NULL);\nALTER TABLE `tb_caahynuejc` ADD (`col_hcvfpfsxxl` longblob, `col_tnpnwxtkvp` longblob);\nALTER TABLE `tb_caahynuejc` DEFAULT CHARACTER SET utf8;\nALTER TABLE `tb_caahynuejc` ADD UNIQUE KEY `uk_kvrvlewpkc` (`col_bufdgcwxci`);\nALTER TABLE `tb_caahynuejc` ALTER `col_eyefseknmn` DROP DEFAULT;\nALTER TABLE `tb_caahynuejc` CHANGE `col_fyktzflvgx` `col_dijbniwgme` decimal(20,1) NULL;\nALTER TABLE `tb_caahynuejc` CHANGE `col_aulqirvfec` `col_wpzatdhhyw` datetime NOT NULL DEFAULT '2019-07-04 00:00:00';\nALTER TABLE `tb_caahynuejc` DROP COLUMN `col_bufdgcwxci`;\nALTER TABLE `tb_caahynuejc` DROP COLUMN `col_snfugvbwkh`;\nALTER TABLE `tb_caahynuejc` DROP COLUMN `col_tnpnwxtkvp`;\nALTER TABLE `tb_caahynuejc` DROP `col_nxbdoexmux`, DROP `col_hcvfpfsxxl`;\nALTER TABLE `tb_caahynuejc` DROP COLUMN `col_dijbniwgme`;\nALTER TABLE `tb_caahynuejc` DROP COLUMN `col_wpzatdhhyw`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_24.sql",
    "content": "CREATE TABLE `tb_joiefnrthx` (\n  `col_ctzpiugxrl` binary(180),\n  UNIQUE INDEX `col_ctzpiugxrl` (`col_ctzpiugxrl`(6)),\n  UNIQUE KEY `uk_xedljqlhxo` (`col_ctzpiugxrl`(18))\n) DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_joiefnrthx` TO `tb_bubrykvvkb`;\nRENAME TABLE `tb_bubrykvvkb` TO `tb_fywhebwffn`;\nALTER TABLE `tb_fywhebwffn` DEFAULT CHARACTER SET utf8mb4;\nALTER TABLE `tb_fywhebwffn` ADD UNIQUE KEY `uk_keugblaszl` (`col_ctzpiugxrl`(8));\nALTER TABLE `tb_fywhebwffn` ADD UNIQUE (`col_ctzpiugxrl`(13));\nALTER TABLE `tb_fywhebwffn` CHANGE `col_ctzpiugxrl` `col_ukjlmzjcdn` tinyint(91) unsigned DEFAULT '1';\nALTER TABLE `tb_fywhebwffn` DROP KEY `col_ctzpiugxrl`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_25.sql",
    "content": "CREATE TABLE `tb_kvzhyqqpam` (\n  `col_lyptirnsfn` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NOT NULL,\n  `col_cqxknjvdgb` blob,\n  `col_xavhqavxqo` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET latin1 NOT NULL DEFAULT 'enum_or_set_0',\n  `col_lmxzibarzh` mediumblob,\n  CONSTRAINT symb_kvlbvjhbln PRIMARY KEY (`col_lyptirnsfn`),\n  UNIQUE KEY `col_lyptirnsfn` (`col_lyptirnsfn`,`col_xavhqavxqo`)\n) DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_kvzhyqqpam` TO `tb_tspkdvcnhl`;\nRENAME TABLE `tb_tspkdvcnhl` TO `tb_wqjpnnzouv`;\nRENAME TABLE `tb_wqjpnnzouv` TO `tb_aafdasghga`;\nALTER TABLE `tb_aafdasghga` ADD (`col_uayhwfkoln` longtext CHARACTER SET utf8mb4, `col_qskwbkbegb` decimal(16));\nALTER TABLE `tb_aafdasghga` ADD COLUMN (`col_wnhexsbjnb` decimal(9) NULL, `col_fxicikwsct` float(24) NOT NULL);\nALTER TABLE `tb_aafdasghga` ADD COLUMN (`col_spzdmnayxy` char(190), `col_wmxfqcqztv` time NOT NULL DEFAULT '00:00:00');\nALTER TABLE `tb_aafdasghga` ADD COLUMN (`col_ygghjheerk` text CHARACTER SET utf8, `col_zbenqlvted` binary NULL);\nALTER TABLE `tb_aafdasghga` ADD `col_ixseptopfk` date DEFAULT '2019-07-04';\nALTER TABLE `tb_aafdasghga` ADD `col_pslvsvljbg` longblob;\nALTER TABLE `tb_aafdasghga` ADD COLUMN `col_ispobmxiik` year;\nALTER TABLE `tb_aafdasghga` ADD (`col_iafihazdod` char NOT NULL, `col_tfuomyukus` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT 'enum_or_set_0');\nALTER TABLE `tb_aafdasghga` ADD UNIQUE (`col_fxicikwsct`,`col_spzdmnayxy`(21));\nALTER TABLE `tb_aafdasghga` ADD UNIQUE (`col_zbenqlvted`,`col_pslvsvljbg`(10));\nALTER TABLE `tb_aafdasghga` CHANGE COLUMN `col_cqxknjvdgb` `col_rasjhueqqp` mediumint zerofill NOT NULL;\nALTER TABLE `tb_aafdasghga` DROP `col_lmxzibarzh`, DROP `col_rasjhueqqp`;\nALTER TABLE `tb_aafdasghga` DROP `col_wmxfqcqztv`;\nALTER TABLE `tb_aafdasghga` DROP `col_spzdmnayxy`, DROP `col_pslvsvljbg`;\nALTER TABLE `tb_aafdasghga` DROP `col_ispobmxiik`;\nALTER TABLE `tb_aafdasghga` DROP COLUMN `col_wnhexsbjnb`;\nALTER TABLE `tb_aafdasghga` DROP COLUMN `col_lyptirnsfn`;\nALTER TABLE `tb_aafdasghga` DROP COLUMN `col_tfuomyukus`;\nALTER TABLE `tb_aafdasghga` DROP COLUMN `col_xavhqavxqo`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_26.sql",
    "content": "CREATE TABLE `tb_rvyjlenqnq` (\n  `col_bvvlapfogy` tinyint zerofill,\n  `col_bkqxmqavul` decimal(63,16) NOT NULL,\n  `col_apojimldou` timestamp NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_epfxexadow` (\n  `col_fuowyuxzjz` tinyint(117) unsigned DEFAULT '1',\n  `col_tkevazcpbc` numeric(36,23)\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_rvyjlenqnq` TO `tb_keyyesvarm`, `tb_epfxexadow` TO `tb_pbwzafanju`;\nDROP TABLE tb_pbwzafanju;\nALTER TABLE `tb_keyyesvarm` ADD `col_liorapkbnd` mediumint(65) zerofill NOT NULL;\nALTER TABLE `tb_keyyesvarm` ADD `col_zixordgmdc` decimal(3,1);\nALTER TABLE `tb_keyyesvarm` ADD COLUMN `col_muylgrtcdh` varchar(79) CHARACTER SET utf8mb4;\nALTER TABLE `tb_keyyesvarm` ADD `col_xxwqoepjpj` char AFTER `col_bvvlapfogy`;\nALTER TABLE `tb_keyyesvarm` ADD COLUMN (`col_qttxalrego` blob(3354084938), `col_ycfogbjylp` binary(106));\nALTER TABLE `tb_keyyesvarm` ADD COLUMN (`col_anvpdwbfbo` smallint zerofill, `col_victdeyala` decimal(48,7));\nALTER TABLE `tb_keyyesvarm` ADD (`col_ftspfhlmkw` tinyblob, `col_uvxqqmoipg` char CHARACTER SET utf8);\nALTER TABLE `tb_keyyesvarm` ADD (`col_zfowehmbto` bit NULL DEFAULT b'0', `col_lqkravajqi` longtext);\nALTER TABLE `tb_keyyesvarm` ADD COLUMN `col_kyzsjpzdyk` numeric(41);\nALTER TABLE `tb_keyyesvarm` ADD UNIQUE INDEX (`col_apojimldou`,`col_liorapkbnd`);\nALTER TABLE `tb_keyyesvarm` ALTER COLUMN `col_uvxqqmoipg` DROP DEFAULT;\nALTER TABLE `tb_keyyesvarm` ALTER `col_victdeyala` SET DEFAULT NULL;\nALTER TABLE `tb_keyyesvarm` DROP `col_uvxqqmoipg`;\nALTER TABLE `tb_keyyesvarm` DROP COLUMN `col_muylgrtcdh`, DROP COLUMN `col_anvpdwbfbo`;\nALTER TABLE `tb_keyyesvarm` DROP COLUMN `col_bkqxmqavul`;\nALTER TABLE `tb_keyyesvarm` DROP COLUMN `col_ycfogbjylp`, DROP COLUMN `col_zfowehmbto`;\nALTER TABLE `tb_keyyesvarm` DROP `col_xxwqoepjpj`, DROP `col_apojimldou`;\nALTER TABLE `tb_keyyesvarm` DROP `col_liorapkbnd`;\nALTER TABLE `tb_keyyesvarm` DROP `col_ftspfhlmkw`, DROP `col_kyzsjpzdyk`;\nALTER TABLE `tb_keyyesvarm` DROP COLUMN `col_bvvlapfogy`, DROP COLUMN `col_qttxalrego`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_27.sql",
    "content": "CREATE TABLE `tb_ffitzbfcdd` (\n  `col_nfqelngymy` varchar(119) CHARACTER SET utf8 DEFAULT '',\n  `col_icgtjlsqcx` year(4) NULL DEFAULT '2019',\n  `col_wkerqargxk` numeric(63),\n  UNIQUE `col_nfqelngymy` (`col_nfqelngymy`(6))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_ffitzbfcdd` TO `tb_yvjscngtbt`;\nRENAME TABLE `tb_yvjscngtbt` TO `tb_cnbkkspjcl`;\nRENAME TABLE `tb_cnbkkspjcl` TO `tb_flnycxasap`;\nALTER TABLE `tb_flnycxasap` ADD COLUMN (`col_ctczxnvezz` timestamp(4) DEFAULT CURRENT_TIMESTAMP(4), `col_sfeoecazoa` tinyint zerofill);\nALTER TABLE `tb_flnycxasap` ADD (`col_tthopazpvp` longblob, `col_icevwmryve` mediumtext);\nALTER TABLE `tb_flnycxasap` ADD (`col_hygoqydgxc` bit, `col_rqtzrkfarg` timestamp(0) NULL DEFAULT CURRENT_TIMESTAMP(0));\nALTER TABLE `tb_flnycxasap` ADD `col_olqpjxyqbq` mediumint unsigned zerofill NOT NULL FIRST;\nALTER TABLE `tb_flnycxasap` ADD PRIMARY KEY (`col_olqpjxyqbq`);\nALTER TABLE `tb_flnycxasap` ADD UNIQUE (`col_sfeoecazoa`,`col_hygoqydgxc`);\nALTER TABLE `tb_flnycxasap` ALTER COLUMN `col_hygoqydgxc` SET DEFAULT NULL;\nALTER TABLE `tb_flnycxasap` CHANGE `col_wkerqargxk` `col_uqaobxqnuc` blob;\nALTER TABLE `tb_flnycxasap` CHANGE `col_sfeoecazoa` `col_tqseiopsqa` datetime(4) NOT NULL;\nALTER TABLE `tb_flnycxasap` CHANGE COLUMN `col_icevwmryve` `col_udrxovnqce` longtext;\nALTER TABLE `tb_flnycxasap` DROP COLUMN `col_uqaobxqnuc`;\nALTER TABLE `tb_flnycxasap` DROP `col_ctczxnvezz`, DROP `col_olqpjxyqbq`;\nALTER TABLE `tb_flnycxasap` DROP COLUMN `col_udrxovnqce`;\nALTER TABLE `tb_flnycxasap` DROP `col_tqseiopsqa`;\nALTER TABLE `tb_flnycxasap` DROP COLUMN `col_tthopazpvp`;\nALTER TABLE `tb_flnycxasap` DROP COLUMN `col_hygoqydgxc`;\nALTER TABLE `tb_flnycxasap` DROP COLUMN `col_nfqelngymy`, DROP COLUMN `col_icgtjlsqcx`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_28.sql",
    "content": "CREATE TABLE `tb_fyextrfwrp` (\n  `col_dkfamtasnd` bigint(86) unsigned DEFAULT '1',\n  `col_yzwppisdla` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET latin1,\n  `col_sowlpsmtck` tinyblob,\n  `col_nnggkdrfej` mediumint NULL DEFAULT '1',\n  UNIQUE `col_sowlpsmtck` (`col_sowlpsmtck`(1),`col_nnggkdrfej`)\n) DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_fyextrfwrp` TO `tb_mdvjbvmscg`;\nRENAME TABLE `tb_mdvjbvmscg` TO `tb_kzznkaskgu`;\nRENAME TABLE `tb_kzznkaskgu` TO `tb_cvpyawneqw`;\nALTER TABLE `tb_cvpyawneqw` ADD (`col_klkrbtckkp` varchar(114) NULL, `col_yfpelqlubr` bigint(252) unsigned zerofill NULL);\nALTER TABLE `tb_cvpyawneqw` ADD `col_gxyxiafdwy` tinyblob;\nALTER TABLE `tb_cvpyawneqw` ADD COLUMN (`col_spugbpzyyf` double NOT NULL, `col_wbsqhinkwg` text);\nALTER TABLE `tb_cvpyawneqw` ADD COLUMN `col_npeyxvumaf` numeric(23) NULL AFTER `col_klkrbtckkp`;\nALTER TABLE `tb_cvpyawneqw` ADD COLUMN (`col_jrdtjutkna` int unsigned, `col_geplpeokit` smallint);\nALTER TABLE `tb_cvpyawneqw` ADD UNIQUE `uk_ameijmmzqx` (`col_sowlpsmtck`(21),`col_nnggkdrfej`);\nALTER TABLE `tb_cvpyawneqw` ADD UNIQUE (`col_gxyxiafdwy`(28),`col_spugbpzyyf`);\nALTER TABLE `tb_cvpyawneqw` ALTER `col_yzwppisdla` SET DEFAULT 'enum_or_set_0';\nALTER TABLE `tb_cvpyawneqw` CHANGE COLUMN `col_sowlpsmtck` `col_hjhuktoxjb` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 NULL DEFAULT 'enum_or_set_0' FIRST;\nALTER TABLE `tb_cvpyawneqw` CHANGE COLUMN `col_yfpelqlubr` `col_gumhdzmptr` longblob AFTER `col_jrdtjutkna`;\nALTER TABLE `tb_cvpyawneqw` DROP COLUMN `col_npeyxvumaf`, DROP COLUMN `col_dkfamtasnd`;\nALTER TABLE `tb_cvpyawneqw` DROP COLUMN `col_spugbpzyyf`, DROP COLUMN `col_geplpeokit`;\nALTER TABLE `tb_cvpyawneqw` DROP `col_yzwppisdla`;\nALTER TABLE `tb_cvpyawneqw` DROP `col_klkrbtckkp`, DROP `col_hjhuktoxjb`;\nALTER TABLE `tb_cvpyawneqw` DROP `col_gumhdzmptr`, DROP `col_wbsqhinkwg`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_29.sql",
    "content": "CREATE TABLE `tb_spegvrpfiz` (\n  `col_zphkdkfyfk` year(4) DEFAULT '2019',\n  `col_omyyogfmwf` varbinary(117),\n  `col_ziqdcvhqaa` longblob,\n  `col_nygklhdofu` time(3),\n  UNIQUE `col_zphkdkfyfk` (`col_zphkdkfyfk`)\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_spegvrpfiz` TO `tb_lfxvmboyfq`;\nALTER TABLE `tb_lfxvmboyfq` ADD `col_ngeiottgyu` year(4);\nALTER TABLE `tb_lfxvmboyfq` ADD COLUMN `col_bvvikzmudl` bit(61);\nALTER TABLE `tb_lfxvmboyfq` ADD (`col_ozthytmepu` mediumtext CHARACTER SET utf8mb4, `col_osxbsknpgd` varchar(183) CHARACTER SET utf8mb4);\nALTER TABLE `tb_lfxvmboyfq` ADD COLUMN (`col_qkgcfgdjqf` text(932341768) CHARACTER SET utf8mb4, `col_idrqfoikzf` float(151,12) NOT NULL);\nALTER TABLE `tb_lfxvmboyfq` ADD (`col_ixxhxsglwg` bigint(92) zerofill, `col_fpciekbati` tinyint DEFAULT '1');\nALTER TABLE `tb_lfxvmboyfq` ADD `col_whrxkkdwrk` tinytext;\nALTER TABLE `tb_lfxvmboyfq` ADD COLUMN `col_ymcntbqrwg` int zerofill FIRST;\nALTER TABLE `tb_lfxvmboyfq` ADD (`col_yxfqfnhsex` bit(43), `col_vvuposukex` numeric NOT NULL DEFAULT '1');\nALTER TABLE `tb_lfxvmboyfq` ADD PRIMARY KEY (`col_idrqfoikzf`);\nALTER TABLE `tb_lfxvmboyfq` ADD UNIQUE KEY (`col_ymcntbqrwg`);\nALTER TABLE `tb_lfxvmboyfq` ALTER `col_vvuposukex` SET DEFAULT '1';\nALTER TABLE `tb_lfxvmboyfq` DROP COLUMN `col_bvvikzmudl`;\nALTER TABLE `tb_lfxvmboyfq` DROP COLUMN `col_ngeiottgyu`, DROP COLUMN `col_ymcntbqrwg`;\nALTER TABLE `tb_lfxvmboyfq` DROP `col_qkgcfgdjqf`;\nALTER TABLE `tb_lfxvmboyfq` DROP COLUMN `col_nygklhdofu`;\nALTER TABLE `tb_lfxvmboyfq` DROP COLUMN `col_fpciekbati`, DROP COLUMN `col_zphkdkfyfk`;\nALTER TABLE `tb_lfxvmboyfq` DROP `col_vvuposukex`;\nALTER TABLE `tb_lfxvmboyfq` DROP `col_ixxhxsglwg`, DROP `col_ozthytmepu`;\nALTER TABLE `tb_lfxvmboyfq` DROP PRIMARY KEY;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_3.sql",
    "content": "CREATE TABLE `tb_rbpnonwcoi` (\n  `col_efmpbyjrdf` year NULL,\n  UNIQUE `col_efmpbyjrdf` (`col_efmpbyjrdf`),\n  UNIQUE `col_efmpbyjrdf_2` (`col_efmpbyjrdf`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_meinmfimcf` (\n  `col_xfazfienqr` datetime DEFAULT '2019-07-04 00:00:00',\n  `col_vwufqrmckr` date NOT NULL,\n  PRIMARY KEY (`col_vwufqrmckr`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_nnvqjcjwfg` LIKE `tb_rbpnonwcoi`;\nRENAME TABLE `tb_nnvqjcjwfg` TO `tb_forjngzrrh`, `tb_meinmfimcf` TO `tb_mbjktaoecs`;\nRENAME TABLE `tb_mbjktaoecs` TO `tb_trprduwltr`, `tb_forjngzrrh` TO `tb_sdpdmvgtcg`;\nDROP TABLE tb_rbpnonwcoi, tb_sdpdmvgtcg;\nDROP TABLE tb_trprduwltr;\nCREATE TABLE `tb_ntoztqvpgu` (\n  `col_pszlqmpajg` mediumint unsigned NOT NULL,\n  `col_gsplwknfrh` timestamp,\n  UNIQUE `uk_tjprvpapej` (`col_pszlqmpajg`,`col_gsplwknfrh`),\n  UNIQUE INDEX `uk_bkvacomalw` (`col_pszlqmpajg`)\n) DEFAULT CHARSET=latin1;\nALTER TABLE `tb_ntoztqvpgu` ADD COLUMN (`col_xzoqslbemg` int DEFAULT '1', `col_ytfasfxidt` mediumtext CHARACTER SET utf8mb4);\nALTER TABLE `tb_ntoztqvpgu` ADD COLUMN (`col_guxaslfjra` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT 'enum_or_set_0', `col_hzazyxoqhs` int(240) unsigned DEFAULT '1');\nALTER TABLE `tb_ntoztqvpgu` ADD `col_yrswgxnlhe` mediumtext CHARACTER SET utf8;\nALTER TABLE `tb_ntoztqvpgu` ADD COLUMN (`col_kcynrqhwrh` tinyblob, `col_guruxuyivx` char CHARACTER SET utf8mb4);\nALTER TABLE `tb_ntoztqvpgu` ADD COLUMN (`col_bpigfcahks` longblob, `col_xzbtbplmxx` float(173,30) NULL);\nALTER TABLE `tb_ntoztqvpgu` ADD `col_aklhemsftu` datetime DEFAULT '2019-07-04 00:00:00' AFTER `col_guruxuyivx`;\nALTER TABLE `tb_ntoztqvpgu` ADD (`col_abtzsnchmp` time(3) NULL, `col_xrqqlwdmuo` datetime NOT NULL);\nALTER TABLE `tb_ntoztqvpgu` ADD COLUMN (`col_yesjtrmdcm` smallint unsigned DEFAULT '1', `col_szbvvxlxpk` mediumtext);\nALTER TABLE `tb_ntoztqvpgu` ADD (`col_qbvmzghubk` longblob, `col_zvbkjkirrz` mediumint(68) unsigned DEFAULT '1');\nALTER TABLE `tb_ntoztqvpgu` CHARACTER SET = utf8;\nALTER TABLE `tb_ntoztqvpgu` CHANGE `col_xzoqslbemg` `col_bogirlzjnd` float AFTER `col_yrswgxnlhe`;\nALTER TABLE `tb_ntoztqvpgu` DROP INDEX `uk_tjprvpapej`;\nALTER TABLE `tb_ntoztqvpgu` DROP INDEX `uk_bkvacomalw`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_30.sql",
    "content": "CREATE TABLE `tb_tmxzhiadaj` (\n  `col_gdnftbskks` datetime(4) NULL,\n  `col_crzzjsyeyk` tinyblob,\n  UNIQUE KEY `uk_splpaskbbf` (`col_gdnftbskks`),\n  UNIQUE KEY `uk_gcdkboipfa` (`col_gdnftbskks`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_jmcsxwqpdc` (\n  `col_kfjyiiexjd` timestamp,\n  CONSTRAINT symb_cbacpsgnkl PRIMARY KEY (`col_kfjyiiexjd`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_pfzgcmldfg` LIKE `tb_tmxzhiadaj`;\nRENAME TABLE `tb_tmxzhiadaj` TO `tb_ruvaoezmwl`;\nRENAME TABLE `tb_jmcsxwqpdc` TO `tb_jchakrwydf`;\nDROP TABLE tb_jchakrwydf;\nALTER TABLE `tb_pfzgcmldfg` ADD `col_zgrykqfrec` tinytext CHARACTER SET utf8 COLLATE utf8_unicode_ci;\nALTER TABLE `tb_pfzgcmldfg` ADD COLUMN `col_fpwqjmseog` numeric(12) NULL;\nALTER TABLE `tb_pfzgcmldfg` ADD (`col_sqfwaxyktx` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') NULL DEFAULT 'enum_or_set_0', `col_duzzugyump` smallint(74) unsigned zerofill NULL);\nALTER TABLE `tb_pfzgcmldfg` ADD (`col_gmbaiqhote` varbinary(140) NOT NULL, `col_nntmqziejp` text);\nALTER TABLE `tb_pfzgcmldfg` ADD (`col_hqjdekphma` date NULL, `col_lbikfetujc` timestamp(6) DEFAULT CURRENT_TIMESTAMP(6));\nALTER TABLE `tb_pfzgcmldfg` ADD (`col_enjwbyuifx` longblob, `col_btttknjcig` tinyblob);\nALTER TABLE `tb_pfzgcmldfg` ADD COLUMN (`col_rtstrcujvm` bigint unsigned NOT NULL, `col_qpjwuqjymd` varchar(209) NOT NULL DEFAULT '');\nALTER TABLE `tb_pfzgcmldfg` CHARACTER SET utf8;\nALTER TABLE `tb_pfzgcmldfg` ADD PRIMARY KEY (`col_gmbaiqhote`(13),`col_lbikfetujc`);\nALTER TABLE `tb_pfzgcmldfg` ADD UNIQUE KEY (`col_enjwbyuifx`(20),`col_btttknjcig`(1));\nALTER TABLE `tb_pfzgcmldfg` ADD UNIQUE `uk_tkfeqlqmie` (`col_sqfwaxyktx`,`col_gmbaiqhote`(2));\nALTER TABLE `tb_pfzgcmldfg` ALTER `col_qpjwuqjymd` DROP DEFAULT;\nALTER TABLE `tb_pfzgcmldfg` DROP `col_fpwqjmseog`, DROP `col_qpjwuqjymd`;\nALTER TABLE `tb_pfzgcmldfg` DROP `col_gmbaiqhote`, DROP `col_zgrykqfrec`;\nALTER TABLE `tb_pfzgcmldfg` DROP `col_rtstrcujvm`, DROP `col_crzzjsyeyk`;\nALTER TABLE `tb_pfzgcmldfg` DROP `col_sqfwaxyktx`;\nALTER TABLE `tb_pfzgcmldfg` DROP COLUMN `col_lbikfetujc`;\nALTER TABLE `tb_pfzgcmldfg` DROP `col_btttknjcig`;\nALTER TABLE `tb_pfzgcmldfg` DROP `col_enjwbyuifx`;\nALTER TABLE `tb_pfzgcmldfg` DROP `col_hqjdekphma`, DROP `col_nntmqziejp`;\nALTER TABLE `tb_pfzgcmldfg` DROP INDEX `uk_splpaskbbf`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_31.sql",
    "content": "CREATE TABLE `tb_oyptksgbxm` (\n  `col_gdmzqziedn` mediumint(192) NULL DEFAULT '1',\n  `col_iesufjnkzg` double(60,2) NOT NULL,\n  `col_fpegtdbbro` varchar(10) CHARACTER SET latin1 NOT NULL DEFAULT '',\n  CONSTRAINT symb_hwjsmtmrol PRIMARY KEY (`col_iesufjnkzg`),\n  UNIQUE `uk_bbhokusgkq` (`col_gdmzqziedn`,`col_fpegtdbbro`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_oyptksgbxm` TO `tb_djhsoeomxx`;\nALTER TABLE `tb_djhsoeomxx` ADD COLUMN (`col_yuemiunaby` mediumtext, `col_ogwamnrrff` mediumint(37) DEFAULT '1');\nALTER TABLE `tb_djhsoeomxx` ADD `col_pvgwkvvphj` text(2345284065) CHARACTER SET utf8;\nALTER TABLE `tb_djhsoeomxx` CHARACTER SET = utf8mb4;\nALTER TABLE `tb_djhsoeomxx` ADD UNIQUE (`col_gdmzqziedn`);\nALTER TABLE `tb_djhsoeomxx` ADD UNIQUE INDEX `uk_pmearqrlzv` (`col_gdmzqziedn`,`col_yuemiunaby`(31));\nALTER TABLE `tb_djhsoeomxx` CHANGE COLUMN `col_gdmzqziedn` `col_mgdrjdeyro` char NOT NULL;\nALTER TABLE `tb_djhsoeomxx` DROP COLUMN `col_pvgwkvvphj`;\nALTER TABLE `tb_djhsoeomxx` DROP `col_ogwamnrrff`, DROP `col_iesufjnkzg`;\nALTER TABLE `tb_djhsoeomxx` DROP COLUMN `col_yuemiunaby`;\nALTER TABLE `tb_djhsoeomxx` DROP COLUMN `col_mgdrjdeyro`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_32.sql",
    "content": "CREATE TABLE `tb_nnxufbaqsg` (\n  `col_kytprnpyhw` decimal(15,15),\n  `col_vhszikunhu` integer(95) unsigned zerofill,\n  `col_llqqqlblzs` timestamp NOT NULL,\n  `col_zlezapwnhv` double,\n  UNIQUE `col_zlezapwnhv` (`col_zlezapwnhv`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_nnxufbaqsg` TO `tb_diurzhsdsd`;\nRENAME TABLE `tb_diurzhsdsd` TO `tb_uhdpyibqnh`;\nRENAME TABLE `tb_uhdpyibqnh` TO `tb_ybgjvtnrkt`;\nALTER TABLE `tb_ybgjvtnrkt` ADD COLUMN (`col_uuoufewntu` tinytext, `col_obvzxvrpac` year);\nALTER TABLE `tb_ybgjvtnrkt` ADD COLUMN (`col_qvxcdustin` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL, `col_qlfphmrfqo` longblob);\nALTER TABLE `tb_ybgjvtnrkt` ADD PRIMARY KEY (`col_llqqqlblzs`);\nALTER TABLE `tb_ybgjvtnrkt` ADD UNIQUE (`col_kytprnpyhw`);\nALTER TABLE `tb_ybgjvtnrkt` ADD UNIQUE INDEX `uk_flumuisvnj` (`col_qlfphmrfqo`(28));\nALTER TABLE `tb_ybgjvtnrkt` CHANGE `col_kytprnpyhw` `col_lcuznlvglo` time(4) AFTER `col_vhszikunhu`;\nALTER TABLE `tb_ybgjvtnrkt` DROP `col_obvzxvrpac`, DROP `col_qlfphmrfqo`;\nALTER TABLE `tb_ybgjvtnrkt` DROP `col_zlezapwnhv`;\nALTER TABLE `tb_ybgjvtnrkt` DROP COLUMN `col_qvxcdustin`, DROP COLUMN `col_uuoufewntu`;\nALTER TABLE `tb_ybgjvtnrkt` DROP COLUMN `col_lcuznlvglo`, DROP COLUMN `col_llqqqlblzs`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_33.sql",
    "content": "CREATE TABLE `tb_yajpbebdke` (\n  `col_jerxhroyff` mediumtext CHARACTER SET utf8 COLLATE utf8_unicode_ci,\n  `col_cuctvlzqvd` numeric(63,14),\n  UNIQUE `col_jerxhroyff` (`col_jerxhroyff`(29)),\n  UNIQUE INDEX `col_jerxhroyff_2` (`col_jerxhroyff`(15),`col_cuctvlzqvd`)\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_yajpbebdke` TO `tb_nenripsjcu`;\nRENAME TABLE `tb_nenripsjcu` TO `tb_ocwsozgwid`;\nALTER TABLE `tb_ocwsozgwid` ADD UNIQUE INDEX (`col_jerxhroyff`(28));\nALTER TABLE `tb_ocwsozgwid` ADD UNIQUE KEY (`col_jerxhroyff`(19),`col_cuctvlzqvd`);\nALTER TABLE `tb_ocwsozgwid` ALTER `col_cuctvlzqvd` DROP DEFAULT;\nALTER TABLE `tb_ocwsozgwid` DROP COLUMN `col_jerxhroyff`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_34.sql",
    "content": "CREATE TABLE `tb_qlkjrjqnps` (\n  `col_ktdqdryygn` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 NOT NULL DEFAULT 'enum_or_set_0',\n  `col_cbcrcayfoe` blob(3373722532)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_whplqdohkv` LIKE `tb_qlkjrjqnps`;\nCREATE TABLE `tb_ygcnpvqeez` LIKE `tb_whplqdohkv`;\nRENAME TABLE `tb_whplqdohkv` TO `tb_jnhvwsafrh`;\nALTER TABLE `tb_qlkjrjqnps` ADD COLUMN `col_vkcmtobywn` binary NOT NULL;\nALTER TABLE `tb_qlkjrjqnps` ADD (`col_eblttrbrlq` varbinary(35) NULL DEFAULT '\\0', `col_rygyddsstu` tinytext CHARACTER SET utf8mb4);\nALTER TABLE `tb_qlkjrjqnps` ADD `col_hkwgwwaxoy` text AFTER `col_eblttrbrlq`;\nALTER TABLE `tb_qlkjrjqnps` ADD COLUMN (`col_oilsudgyas` smallint(39) unsigned zerofill, `col_wgsnbmgdbz` int unsigned zerofill);\nALTER TABLE `tb_qlkjrjqnps` ADD COLUMN `col_opbtiidusc` tinyint zerofill NULL;\nALTER TABLE `tb_qlkjrjqnps` ADD (`col_ecaramctpw` varbinary(185) NOT NULL, `col_wcpdsgpcip` longblob);\nALTER TABLE `tb_qlkjrjqnps` ADD COLUMN (`col_fidmrllusm` varchar(132) CHARACTER SET utf8 NULL, `col_qxsokmevlv` integer zerofill NOT NULL);\nALTER TABLE `tb_qlkjrjqnps` ADD COLUMN `col_eoeroydtse` smallint(32) DEFAULT '1' FIRST;\nALTER TABLE `tb_qlkjrjqnps` ADD CONSTRAINT symb_rvaqwhjyyk PRIMARY KEY (`col_ktdqdryygn`,`col_vkcmtobywn`);\nALTER TABLE `tb_qlkjrjqnps` ALTER COLUMN `col_opbtiidusc` SET DEFAULT NULL;\nALTER TABLE `tb_qlkjrjqnps` ALTER `col_wgsnbmgdbz` DROP DEFAULT;\nALTER TABLE `tb_qlkjrjqnps` CHANGE COLUMN `col_eblttrbrlq` `col_mywjrvfxmw` tinyblob;\nALTER TABLE `tb_qlkjrjqnps` CHANGE COLUMN `col_rygyddsstu` `col_zuhebeqqrq` numeric(4,0);\nALTER TABLE `tb_qlkjrjqnps` DROP COLUMN `col_ecaramctpw`, DROP COLUMN `col_ktdqdryygn`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_35.sql",
    "content": "CREATE TABLE `tb_yntgfjruqk` (\n  `col_bxnkhgjjdz` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 DEFAULT 'enum_or_set_0',\n  `col_rwmjknctzl` datetime(6) NOT NULL,\n  `col_seknewafqd` timestamp,\n  PRIMARY KEY (`col_rwmjknctzl`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_ajxoovpkvw` (\n  `col_ytfnmhhaoa` int unsigned,\n  `col_vimtlabyrl` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NULL,\n  UNIQUE `col_ytfnmhhaoa` (`col_ytfnmhhaoa`),\n  UNIQUE KEY `col_vimtlabyrl` (`col_vimtlabyrl`)\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_ajxoovpkvw` TO `tb_qlvbveqzna`, `tb_yntgfjruqk` TO `tb_eegcnsbywv`;\nALTER TABLE `tb_eegcnsbywv` ADD (`col_jophiowutg` longtext, `col_pnotecfjsi` decimal);\nALTER TABLE `tb_eegcnsbywv` ADD `col_eawvokgzvi` year(4) NOT NULL DEFAULT '2019';\nALTER TABLE `tb_eegcnsbywv` ADD `col_orlvhbnaer` longtext CHARACTER SET utf8mb4;\nALTER TABLE `tb_eegcnsbywv` ADD COLUMN (`col_krlfmduttq` longtext, `col_jobdxewixt` bigint(173));\nALTER TABLE `tb_eegcnsbywv` ADD (`col_ufdhvspoka` float DEFAULT '1', `col_qqdcbaucve` date);\nALTER TABLE `tb_eegcnsbywv` ADD COLUMN (`col_uuexgtwrse` double(172,2) NOT NULL, `col_bfsjjimztp` datetime(1) NOT NULL);\nALTER TABLE `tb_eegcnsbywv` ADD `col_trrvagfhxb` longblob AFTER `col_uuexgtwrse`;\nALTER TABLE `tb_eegcnsbywv` ADD (`col_hfrmqomgva` date, `col_mepqygbcxa` text CHARACTER SET utf8mb4);\nALTER TABLE `tb_eegcnsbywv` ADD `col_xmubzkmxzy` mediumblob;\nALTER TABLE `tb_eegcnsbywv` DEFAULT CHARACTER SET = utf8;\nALTER TABLE `tb_eegcnsbywv` ADD UNIQUE INDEX `col_jophiowutg`(`col_jophiowutg`(2),`col_pnotecfjsi`);\nALTER TABLE `tb_eegcnsbywv` ADD UNIQUE `col_trrvagfhxb`(`col_trrvagfhxb`(20),`col_hfrmqomgva`);\nALTER TABLE `tb_eegcnsbywv` ALTER COLUMN `col_eawvokgzvi` DROP DEFAULT;\nALTER TABLE `tb_eegcnsbywv` CHANGE COLUMN `col_bxnkhgjjdz` `col_iedptbbtmp` float(41) AFTER `col_jophiowutg`;\nALTER TABLE `tb_eegcnsbywv` CHANGE `col_trrvagfhxb` `col_hzixmjzrzg` tinyint(195) unsigned zerofill NOT NULL;\nALTER TABLE `tb_eegcnsbywv` DROP INDEX `col_jophiowutg`;\nALTER TABLE `tb_eegcnsbywv` DROP KEY `col_trrvagfhxb`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_36.sql",
    "content": "CREATE TABLE `tb_teqnorpcun` (\n  `col_ufqdyzbxyc` longtext CHARACTER SET utf8mb4,\n  UNIQUE KEY `col_ufqdyzbxyc` (`col_ufqdyzbxyc`(19)),\n  UNIQUE KEY `col_ufqdyzbxyc_2` (`col_ufqdyzbxyc`(18))\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_teqnorpcun` TO `tb_plmerlrvqm`;\nRENAME TABLE `tb_plmerlrvqm` TO `tb_putsugoooc`;\nALTER TABLE `tb_putsugoooc` ADD `col_eykecckmna` float(240,27) FIRST;\nALTER TABLE `tb_putsugoooc` ADD `col_anwqmnbtnq` char CHARACTER SET utf8 FIRST;\nALTER TABLE `tb_putsugoooc` ADD `col_zqtvmwyqye` tinyblob AFTER `col_ufqdyzbxyc`;\nALTER TABLE `tb_putsugoooc` ADD (`col_ptbaaugrfk` timestamp NULL, `col_nzheqbovze` longtext CHARACTER SET utf8mb4);\nALTER TABLE `tb_putsugoooc` ADD COLUMN `col_ewavlcwcvf` bigint(210) unsigned zerofill NOT NULL FIRST;\nALTER TABLE `tb_putsugoooc` ADD (`col_kxxvdiusoj` tinyblob, `col_gkjiivrixs` double(212,20) NULL);\nALTER TABLE `tb_putsugoooc` CHARACTER SET utf8mb4;\nALTER TABLE `tb_putsugoooc` ADD PRIMARY KEY (`col_ewavlcwcvf`);\nALTER TABLE `tb_putsugoooc` CHANGE COLUMN `col_nzheqbovze` `col_hwjcbrppgw` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 DEFAULT 'enum_or_set_0' FIRST;\nALTER TABLE `tb_putsugoooc` CHANGE `col_ufqdyzbxyc` `col_ynpynwnkjv` mediumtext CHARACTER SET utf8mb4 FIRST;\nALTER TABLE `tb_putsugoooc` DROP `col_anwqmnbtnq`;\nALTER TABLE `tb_putsugoooc` DROP `col_gkjiivrixs`, DROP `col_kxxvdiusoj`;\nALTER TABLE `tb_putsugoooc` DROP COLUMN `col_zqtvmwyqye`;\nALTER TABLE `tb_putsugoooc` DROP `col_hwjcbrppgw`, DROP `col_ptbaaugrfk`;\nALTER TABLE `tb_putsugoooc` DROP `col_eykecckmna`;\nALTER TABLE `tb_putsugoooc` DROP COLUMN `col_ewavlcwcvf`;\nALTER TABLE `tb_putsugoooc` DROP INDEX `col_ufqdyzbxyc`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_37.sql",
    "content": "CREATE TABLE `tb_qxifuytosb` (\n  `col_xxcylzlczf` blob(2724000156),\n  `col_sanwlcnfin` time NULL,\n  `col_qxmjojclfy` bit(56) NULL,\n  `col_uzjeazqmyh` mediumblob,\n  UNIQUE `col_xxcylzlczf` (`col_xxcylzlczf`(10)),\n  UNIQUE `col_xxcylzlczf_2` (`col_xxcylzlczf`(4),`col_uzjeazqmyh`(4))\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_jiijqyzrrm` (\n  `col_xmaniyllht` year(4) NULL,\n  UNIQUE KEY `col_xmaniyllht` (`col_xmaniyllht`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_qxifuytosb` TO `tb_pxjfszwfyt`;\nDROP TABLE tb_jiijqyzrrm, tb_pxjfszwfyt;\nCREATE TABLE `tb_cdbrmxbknb` (\n  `col_rsqdthkvva` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 NULL,\n  `col_amvugezhpd` blob,\n  UNIQUE INDEX `uk_yvoxkgeget` (`col_amvugezhpd`(6)),\n  UNIQUE `uk_ozxqwxureo` (`col_rsqdthkvva`,`col_amvugezhpd`(10))\n) DEFAULT CHARSET=latin1;\nALTER TABLE `tb_cdbrmxbknb` ADD COLUMN (`col_cybpuhkzzb` datetime(6) NULL, `col_fssjphbkbw` mediumtext CHARACTER SET utf8 COLLATE utf8_unicode_ci);\nALTER TABLE `tb_cdbrmxbknb` DEFAULT CHARACTER SET = utf8;\nALTER TABLE `tb_cdbrmxbknb` ADD UNIQUE (`col_fssjphbkbw`(1));\nALTER TABLE `tb_cdbrmxbknb` ALTER `col_cybpuhkzzb` DROP DEFAULT;\nALTER TABLE `tb_cdbrmxbknb` CHANGE COLUMN `col_cybpuhkzzb` `col_lxbevqcyyv` bigint(33) zerofill NULL FIRST;\nALTER TABLE `tb_cdbrmxbknb` CHANGE COLUMN `col_fssjphbkbw` `col_vobywwqdrd` datetime DEFAULT '2019-07-04 00:00:00';\nALTER TABLE `tb_cdbrmxbknb` DROP COLUMN `col_lxbevqcyyv`, DROP COLUMN `col_vobywwqdrd`;\nALTER TABLE `tb_cdbrmxbknb` DROP `col_rsqdthkvva`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_38.sql",
    "content": "CREATE TABLE `tb_axmikqwoki` (\n  `col_emfohlohwo` bit NULL,\n  `col_ubwarukvbl` tinyint(141) unsigned zerofill NOT NULL,\n  `col_amwzbhvmje` numeric NOT NULL DEFAULT '1',\n  `col_qrklyrbbgp` time(6) NOT NULL,\n  UNIQUE `uk_bbaanqoyjv` (`col_qrklyrbbgp`),\n  UNIQUE KEY `col_amwzbhvmje` (`col_amwzbhvmje`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_qiuxoamkjv` (\n  `col_sahfvmjolk` tinyblob,\n  `col_facdiejxet` mediumtext CHARACTER SET utf8,\n  UNIQUE `col_facdiejxet` (`col_facdiejxet`(6))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_jtxcznanun` (\n  `col_qkjsktvtdg` decimal(9,7) NOT NULL,\n  UNIQUE `uk_qwtaypasqp` (`col_qkjsktvtdg`),\n  UNIQUE INDEX `col_qkjsktvtdg` (`col_qkjsktvtdg`)\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_jtxcznanun` TO `tb_djmwhfbubf`, `tb_axmikqwoki` TO `tb_unuzjkojlt`;\nDROP TABLE tb_unuzjkojlt, tb_djmwhfbubf;\nDROP TABLE tb_qiuxoamkjv;\nCREATE TABLE `tb_oxwwculmvu` (\n  `col_msksigujbh` text CHARACTER SET utf8,\n  `col_qfmpogxwgh` mediumtext CHARACTER SET utf8,\n  UNIQUE `uk_qfabuzevew` (`col_msksigujbh`(16))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nALTER TABLE `tb_oxwwculmvu` ADD COLUMN (`col_kesjpzxctq` datetime(6), `col_szncpsegwq` time NULL DEFAULT '00:00:00');\nALTER TABLE `tb_oxwwculmvu` ADD (`col_wxqxqueihr` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') NULL, `col_hyhtklzrvn` varchar(147) CHARACTER SET utf8 NOT NULL DEFAULT '');\nALTER TABLE `tb_oxwwculmvu` ADD (`col_zrjuysqdco` smallint(247) unsigned, `col_umxbmdtpxs` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') NOT NULL DEFAULT 'enum_or_set_0');\nALTER TABLE `tb_oxwwculmvu` ADD COLUMN `col_bewssrhuze` tinytext CHARACTER SET utf8 COLLATE utf8_unicode_ci;\nALTER TABLE `tb_oxwwculmvu` ADD `col_jnwlatgrgv` mediumblob FIRST;\nALTER TABLE `tb_oxwwculmvu` ADD COLUMN `col_xemgprlpmx` double(138,3) FIRST;\nALTER TABLE `tb_oxwwculmvu` ADD COLUMN (`col_yyixefgbqi` year(4), `col_kixpfwoyyq` tinytext CHARACTER SET utf8);\nALTER TABLE `tb_oxwwculmvu` ADD `col_wsgiswplbj` decimal(7,4);\nALTER TABLE `tb_oxwwculmvu` ADD UNIQUE `uk_vrydxlndik` (`col_zrjuysqdco`,`col_yyixefgbqi`);\nALTER TABLE `tb_oxwwculmvu` ADD UNIQUE (`col_wsgiswplbj`);\nALTER TABLE `tb_oxwwculmvu` ALTER COLUMN `col_kesjpzxctq` DROP DEFAULT;\nALTER TABLE `tb_oxwwculmvu` ALTER `col_umxbmdtpxs` DROP DEFAULT;\nALTER TABLE `tb_oxwwculmvu` ALTER COLUMN `col_wsgiswplbj` DROP DEFAULT;\nALTER TABLE `tb_oxwwculmvu` CHANGE COLUMN `col_wsgiswplbj` `col_qxmxrwuujo` integer(209) unsigned zerofill NOT NULL FIRST;\nALTER TABLE `tb_oxwwculmvu` CHANGE `col_kesjpzxctq` `col_gspziyqoeg` blob;\nALTER TABLE `tb_oxwwculmvu` DROP COLUMN `col_xemgprlpmx`;\nALTER TABLE `tb_oxwwculmvu` DROP COLUMN `col_jnwlatgrgv`, DROP COLUMN `col_gspziyqoeg`;\nALTER TABLE `tb_oxwwculmvu` DROP COLUMN `col_zrjuysqdco`, DROP COLUMN `col_msksigujbh`;\nALTER TABLE `tb_oxwwculmvu` DROP COLUMN `col_qxmxrwuujo`;\nALTER TABLE `tb_oxwwculmvu` DROP COLUMN `col_qfmpogxwgh`, DROP COLUMN `col_kixpfwoyyq`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_39.sql",
    "content": "CREATE TABLE `tb_owgbdhiwmn` (\n  `col_nhjtnryfsu` decimal(13,0),\n  `col_dmrqgaovxi` longblob,\n  `col_gvwexllvhe` decimal(35) NULL\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_xlwzxxkunf` LIKE `tb_owgbdhiwmn`;\nCREATE TABLE `tb_aidhgjhqzp` (\n  `col_ouqqfnoijf` tinyint(142) unsigned DEFAULT '1',\n  `col_wzzrzavmqu` int unsigned zerofill,\n  UNIQUE KEY `col_ouqqfnoijf` (`col_ouqqfnoijf`)\n) DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_owgbdhiwmn` TO `tb_vpcgqeykeh`, `tb_xlwzxxkunf` TO `tb_xyniefhewz`;\nDROP TABLE tb_vpcgqeykeh, tb_xyniefhewz;\nALTER TABLE `tb_aidhgjhqzp` ADD COLUMN (`col_cvjkhkkerl` datetime(1) NULL, `col_cvzuqkfnnp` tinytext);\nALTER TABLE `tb_aidhgjhqzp` ADD COLUMN (`col_dpnzvoemce` smallint(146) zerofill, `col_wisgyhivgt` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 DEFAULT 'enum_or_set_0');\nALTER TABLE `tb_aidhgjhqzp` ADD COLUMN `col_jsjfylwbsu` time(3) NOT NULL AFTER `col_ouqqfnoijf`;\nALTER TABLE `tb_aidhgjhqzp` CHARACTER SET = utf8mb4;\nALTER TABLE `tb_aidhgjhqzp` CHANGE `col_wzzrzavmqu` `col_wcosqedhbh` tinytext CHARACTER SET utf8mb4 AFTER `col_cvjkhkkerl`;\nALTER TABLE `tb_aidhgjhqzp` CHANGE COLUMN `col_cvjkhkkerl` `col_zcmworbhql` double NOT NULL FIRST;\nALTER TABLE `tb_aidhgjhqzp` CHANGE COLUMN `col_zcmworbhql` `col_wtsgpcyuec` time(6) NULL FIRST;\nALTER TABLE `tb_aidhgjhqzp` DROP INDEX `col_ouqqfnoijf`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_4.sql",
    "content": "CREATE TABLE `tb_srnygbtlet` (\n  `col_lifsfguaso` bigint unsigned zerofill NOT NULL,\n  `col_jfqoynkdul` int(85) zerofill NOT NULL,\n  `col_xtdeqhkius` int unsigned zerofill\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_sykueansru` (\n  `col_tvoyslqfaz` char(165) CHARACTER SET utf8 NOT NULL,\n  `col_kcqzudwksh` int(74) zerofill,\n  CONSTRAINT PRIMARY KEY (`col_tvoyslqfaz`(15)),\n  UNIQUE `uk_jusgrekcyt` (`col_tvoyslqfaz`(10))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_ljqwtifhmg` LIKE `tb_srnygbtlet`;\nRENAME TABLE `tb_srnygbtlet` TO `tb_cvldhcmtfi`;\nRENAME TABLE `tb_sykueansru` TO `tb_yizqtrqbqn`;\nRENAME TABLE `tb_cvldhcmtfi` TO `tb_vloxpqyomb`;\nDROP TABLE tb_yizqtrqbqn, tb_vloxpqyomb;\nALTER TABLE `tb_ljqwtifhmg` ADD (`col_jskeqnympm` mediumblob, `col_reyjvzjrca` mediumtext);\nALTER TABLE `tb_ljqwtifhmg` ADD `col_vqkcruulcb` numeric NOT NULL DEFAULT '1' AFTER `col_xtdeqhkius`;\nALTER TABLE `tb_ljqwtifhmg` ADD `col_udtcfawuge` year NOT NULL;\nALTER TABLE `tb_ljqwtifhmg` ADD COLUMN `col_zkypjejoqz` longtext CHARACTER SET utf8;\nALTER TABLE `tb_ljqwtifhmg` ADD COLUMN `col_ebgvlcdynr` tinyint(233) unsigned DEFAULT '1' AFTER `col_jskeqnympm`;\nALTER TABLE `tb_ljqwtifhmg` ADD COLUMN `col_hfnljoelph` blob;\nALTER TABLE `tb_ljqwtifhmg` ADD `col_vtvtsqhwby` decimal DEFAULT '1';\nALTER TABLE `tb_ljqwtifhmg` CHARACTER SET = utf8;\nALTER TABLE `tb_ljqwtifhmg` ADD UNIQUE `uk_geldgbtngh` (`col_reyjvzjrca`(10),`col_udtcfawuge`);\nALTER TABLE `tb_ljqwtifhmg` ADD UNIQUE (`col_vqkcruulcb`,`col_jskeqnympm`(32));\nALTER TABLE `tb_ljqwtifhmg` CHANGE `col_jfqoynkdul` `col_vlntyfqpdc` longtext CHARACTER SET utf8mb4;\nALTER TABLE `tb_ljqwtifhmg` DROP COLUMN `col_ebgvlcdynr`, DROP COLUMN `col_vqkcruulcb`;\nALTER TABLE `tb_ljqwtifhmg` DROP `col_hfnljoelph`, DROP `col_vtvtsqhwby`;\nALTER TABLE `tb_ljqwtifhmg` DROP COLUMN `col_xtdeqhkius`;\nALTER TABLE `tb_ljqwtifhmg` DROP `col_vlntyfqpdc`, DROP `col_zkypjejoqz`;\nALTER TABLE `tb_ljqwtifhmg` DROP COLUMN `col_udtcfawuge`;\nALTER TABLE `tb_ljqwtifhmg` DROP `col_reyjvzjrca`;\nALTER TABLE `tb_ljqwtifhmg` DROP COLUMN `col_jskeqnympm`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_40.sql",
    "content": "CREATE TABLE `tb_bijtvrcbjd` (\n  `col_wvmxgyajnm` longblob\n) DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_bijtvrcbjd` TO `tb_wiarbczkeh`;\nRENAME TABLE `tb_wiarbczkeh` TO `tb_imabeghgmt`;\nALTER TABLE `tb_imabeghgmt` ADD UNIQUE `uk_ppyrqytsgk` (`col_wvmxgyajnm`(12));\nALTER TABLE `tb_imabeghgmt` ADD UNIQUE KEY `uk_znvsdkastd` (`col_wvmxgyajnm`(17));\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_41.sql",
    "content": "CREATE TABLE `tb_lqvkbeqhuw` (\n  `col_gseshvltxd` tinytext CHARACTER SET latin1,\n  `col_otuwjnlrtt` decimal,\n  UNIQUE INDEX `col_otuwjnlrtt` (`col_otuwjnlrtt`),\n  UNIQUE `col_gseshvltxd` (`col_gseshvltxd`(26))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_lqvkbeqhuw` TO `tb_mqghelxirz`;\nALTER TABLE `tb_mqghelxirz` ADD COLUMN (`col_gwwjlquinc` mediumint NOT NULL, `col_ibdwyzxgxi` varchar(134));\nALTER TABLE `tb_mqghelxirz` ADD COLUMN (`col_hidvbhcjfu` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4, `col_gubjakxnpz` char);\nALTER TABLE `tb_mqghelxirz` ADD COLUMN (`col_hawbrmwxzw` blob(1199961922), `col_kgokeficzq` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT 'enum_or_set_0');\nALTER TABLE `tb_mqghelxirz` ADD (`col_dplffwllbx` char(146) CHARACTER SET utf8, `col_rikplgqsve` tinyint(146) zerofill NULL);\nALTER TABLE `tb_mqghelxirz` ADD `col_ukmsekjycj` tinyblob;\nALTER TABLE `tb_mqghelxirz` ADD COLUMN `col_ixaybtquqz` smallint(215) unsigned DEFAULT '1' FIRST;\nALTER TABLE `tb_mqghelxirz` ADD COLUMN (`col_zonuplyzdz` tinyblob, `col_snvmotcqtx` mediumtext);\nALTER TABLE `tb_mqghelxirz` CHARACTER SET = utf8mb4;\nALTER TABLE `tb_mqghelxirz` ADD CONSTRAINT symb_hewywavzus PRIMARY KEY (`col_gwwjlquinc`);\nALTER TABLE `tb_mqghelxirz` ADD UNIQUE `col_gwwjlquinc`(`col_gwwjlquinc`,`col_gubjakxnpz`);\nALTER TABLE `tb_mqghelxirz` ALTER `col_rikplgqsve` SET DEFAULT NULL;\nALTER TABLE `tb_mqghelxirz` CHANGE COLUMN `col_dplffwllbx` `col_xltpnadrcs` bigint zerofill NOT NULL;\nALTER TABLE `tb_mqghelxirz` CHANGE `col_hidvbhcjfu` `col_vtkwyvoqkp` varbinary(121) NULL;\nALTER TABLE `tb_mqghelxirz` DROP INDEX `col_gseshvltxd`;\nALTER TABLE `tb_mqghelxirz` DROP KEY `col_gwwjlquinc`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_42.sql",
    "content": "CREATE TABLE `tb_ofxsxmoixc` (\n  `col_tymnumzsjd` tinytext CHARACTER SET latin1,\n  `col_zvcpajjdrr` integer(26) zerofill,\n  UNIQUE `col_tymnumzsjd` (`col_tymnumzsjd`(2))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_ofxsxmoixc` TO `tb_mriknxonls`;\nRENAME TABLE `tb_mriknxonls` TO `tb_hkehwyglax`;\nALTER TABLE `tb_hkehwyglax` ADD `col_hpedrlkbit` tinyblob FIRST;\nALTER TABLE `tb_hkehwyglax` ADD (`col_aftchdhhpb` integer unsigned NULL, `col_engwamylfv` text);\nALTER TABLE `tb_hkehwyglax` ADD `col_dcnadmyyfb` binary FIRST;\nALTER TABLE `tb_hkehwyglax` ADD COLUMN (`col_epoaxrbmcm` double NOT NULL, `col_qknitkqdnz` longblob);\nALTER TABLE `tb_hkehwyglax` ADD COLUMN `col_upulxkgdxc` bigint;\nALTER TABLE `tb_hkehwyglax` ADD COLUMN (`col_fdyhioyktq` tinytext CHARACTER SET utf8mb4, `col_szfqsvrruq` smallint zerofill NULL);\nALTER TABLE `tb_hkehwyglax` ADD (`col_iqohbjwihd` text CHARACTER SET utf8mb4, `col_yxsvpkijew` float(43) NOT NULL);\nALTER TABLE `tb_hkehwyglax` ADD CONSTRAINT PRIMARY KEY (`col_epoaxrbmcm`);\nALTER TABLE `tb_hkehwyglax` ADD UNIQUE KEY `uk_tkjaqutxko` (`col_yxsvpkijew`);\nALTER TABLE `tb_hkehwyglax` ADD UNIQUE (`col_tymnumzsjd`(17),`col_aftchdhhpb`);\nALTER TABLE `tb_hkehwyglax` CHANGE `col_engwamylfv` `col_ivaaxawlsl` mediumtext CHARACTER SET utf8mb4 AFTER `col_hpedrlkbit`;\nALTER TABLE `tb_hkehwyglax` CHANGE COLUMN `col_qknitkqdnz` `col_puxtweqbpn` mediumblob AFTER `col_dcnadmyyfb`;\nALTER TABLE `tb_hkehwyglax` DROP COLUMN `col_epoaxrbmcm`;\nALTER TABLE `tb_hkehwyglax` DROP `col_szfqsvrruq`;\nALTER TABLE `tb_hkehwyglax` DROP COLUMN `col_tymnumzsjd`;\nALTER TABLE `tb_hkehwyglax` DROP `col_hpedrlkbit`, DROP `col_puxtweqbpn`;\nALTER TABLE `tb_hkehwyglax` DROP `col_ivaaxawlsl`;\nALTER TABLE `tb_hkehwyglax` DROP COLUMN `col_upulxkgdxc`;\nALTER TABLE `tb_hkehwyglax` DROP KEY `uk_tkjaqutxko`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_43.sql",
    "content": "CREATE TABLE `tb_imdtsfqnma` (\n  `col_mbzhjizhhg` integer(14) unsigned,\n  `col_lwcvaletgl` numeric(54,3),\n  `col_vzmkkrtqea` bit(28) DEFAULT b'0',\n  `col_rmtdktwjkf` time(3) NULL,\n  UNIQUE KEY `uk_ejklfpuzdw` (`col_rmtdktwjkf`)\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_imdtsfqnma` TO `tb_hbqbstsanm`;\nRENAME TABLE `tb_hbqbstsanm` TO `tb_uoquelzmdk`;\nALTER TABLE `tb_uoquelzmdk` ADD COLUMN (`col_bbvxosyuai` float, `col_wcdxzaykzl` smallint unsigned NULL DEFAULT '1');\nALTER TABLE `tb_uoquelzmdk` ADD `col_njhhehxbdq` mediumtext;\nALTER TABLE `tb_uoquelzmdk` ADD `col_znccfjlzyn` decimal(23,10);\nALTER TABLE `tb_uoquelzmdk` ADD (`col_gpuwdouomx` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 NOT NULL, `col_wwdicmbkug` longblob);\nALTER TABLE `tb_uoquelzmdk` ADD (`col_bdbfyfsjoy` int(184) unsigned zerofill NULL, `col_eroukngokg` bigint(47) unsigned zerofill NOT NULL);\nALTER TABLE `tb_uoquelzmdk` ADD COLUMN (`col_mzeetglota` float(9) NOT NULL, `col_pheamargcl` smallint(239) zerofill);\nALTER TABLE `tb_uoquelzmdk` ADD `col_btyauewuzi` mediumblob AFTER `col_bbvxosyuai`;\nALTER TABLE `tb_uoquelzmdk` ADD UNIQUE KEY `uk_sjpsswkher` (`col_bdbfyfsjoy`,`col_pheamargcl`);\nALTER TABLE `tb_uoquelzmdk` ALTER `col_lwcvaletgl` DROP DEFAULT;\nALTER TABLE `tb_uoquelzmdk` ALTER COLUMN `col_pheamargcl` DROP DEFAULT;\nALTER TABLE `tb_uoquelzmdk` DROP COLUMN `col_bbvxosyuai`;\nALTER TABLE `tb_uoquelzmdk` DROP `col_lwcvaletgl`;\nALTER TABLE `tb_uoquelzmdk` DROP COLUMN `col_eroukngokg`, DROP COLUMN `col_mzeetglota`;\nALTER TABLE `tb_uoquelzmdk` DROP COLUMN `col_znccfjlzyn`, DROP COLUMN `col_vzmkkrtqea`;\nALTER TABLE `tb_uoquelzmdk` DROP COLUMN `col_rmtdktwjkf`;\nALTER TABLE `tb_uoquelzmdk` DROP COLUMN `col_gpuwdouomx`;\nALTER TABLE `tb_uoquelzmdk` DROP `col_pheamargcl`, DROP `col_btyauewuzi`;\nALTER TABLE `tb_uoquelzmdk` DROP COLUMN `col_mbzhjizhhg`, DROP COLUMN `col_bdbfyfsjoy`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_44.sql",
    "content": "CREATE TABLE `tb_sgqyviwkyz` (\n  `col_qcgurbenzo` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4,\n  UNIQUE `uk_vidzaimrjm` (`col_qcgurbenzo`)\n) DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_sgqyviwkyz` TO `tb_faqsxuetwm`;\nALTER TABLE `tb_faqsxuetwm` CHARACTER SET utf8mb4;\nALTER TABLE `tb_faqsxuetwm` ADD UNIQUE KEY `uk_zgssrxjpck` (`col_qcgurbenzo`);\nALTER TABLE `tb_faqsxuetwm` ALTER COLUMN `col_qcgurbenzo` DROP DEFAULT;\nALTER TABLE `tb_faqsxuetwm` ALTER COLUMN `col_qcgurbenzo` DROP DEFAULT;\nALTER TABLE `tb_faqsxuetwm` ALTER COLUMN `col_qcgurbenzo` SET DEFAULT NULL;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_45.sql",
    "content": "CREATE TABLE `tb_pvcychmnrw` (\n  `col_xgykdmygaw` tinyblob\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_hidugktlpo` LIKE `tb_pvcychmnrw`;\nRENAME TABLE `tb_pvcychmnrw` TO `tb_bevepbdlfp`;\nRENAME TABLE `tb_hidugktlpo` TO `tb_nnupayyotj`;\nRENAME TABLE `tb_bevepbdlfp` TO `tb_voanuixent`, `tb_nnupayyotj` TO `tb_znqepghruj`;\nALTER TABLE `tb_znqepghruj` ADD COLUMN (`col_lapmiukuzm` bigint(4) unsigned zerofill, `col_jncrcdzmcj` varchar(224) NULL);\nALTER TABLE `tb_znqepghruj` ADD `col_yozqdpmolb` mediumblob AFTER `col_lapmiukuzm`;\nALTER TABLE `tb_znqepghruj` ADD `col_jfuyjljjqa` longtext CHARACTER SET utf8mb4 FIRST;\nALTER TABLE `tb_znqepghruj` ADD `col_vpxahsfmgv` longtext CHARACTER SET utf8 COLLATE utf8_unicode_ci;\nALTER TABLE `tb_znqepghruj` ADD COLUMN `col_utlqihmybp` varbinary(41) NULL AFTER `col_lapmiukuzm`;\nALTER TABLE `tb_znqepghruj` ADD UNIQUE (`col_xgykdmygaw`(21),`col_utlqihmybp`(30));\nALTER TABLE `tb_znqepghruj` ADD UNIQUE KEY `uk_bkrpsgutim` (`col_jfuyjljjqa`(18),`col_utlqihmybp`(3));\nALTER TABLE `tb_znqepghruj` ALTER `col_utlqihmybp` SET DEFAULT NULL;\nALTER TABLE `tb_znqepghruj` CHANGE COLUMN `col_jncrcdzmcj` `col_ekvpssddsv` year FIRST;\nALTER TABLE `tb_znqepghruj` CHANGE `col_yozqdpmolb` `col_uzlftjvzzr` mediumint(64) zerofill FIRST;\nALTER TABLE `tb_znqepghruj` DROP `col_jfuyjljjqa`, DROP `col_ekvpssddsv`;\nALTER TABLE `tb_znqepghruj` DROP `col_utlqihmybp`;\nALTER TABLE `tb_znqepghruj` DROP COLUMN `col_vpxahsfmgv`;\nALTER TABLE `tb_znqepghruj` DROP `col_lapmiukuzm`, DROP `col_uzlftjvzzr`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_46.sql",
    "content": "CREATE TABLE `tb_zbnbjecfad` (\n  `col_hiezvpgyuu` timestamp(4) NOT NULL DEFAULT CURRENT_TIMESTAMP(4),\n  `col_vydoxpfwit` float(202,3) NULL,\n  `col_kdvvwclils` year(4) DEFAULT '2019',\n  `col_ovrngczyyk` mediumint(81) unsigned,\n  UNIQUE `col_hiezvpgyuu` (`col_hiezvpgyuu`,`col_vydoxpfwit`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_nkikxbvhfw` (\n  `col_swzsjdffqv` blob(2134010468),\n  UNIQUE INDEX `col_swzsjdffqv` (`col_swzsjdffqv`(24)),\n  UNIQUE `col_swzsjdffqv_2` (`col_swzsjdffqv`(32))\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_nkikxbvhfw` TO `tb_cihgbeacba`, `tb_zbnbjecfad` TO `tb_mlsrpqwnhf`;\nDROP TABLE tb_cihgbeacba;\nALTER TABLE `tb_mlsrpqwnhf` ADD COLUMN `col_mfdevzanga` tinyint zerofill NOT NULL;\nALTER TABLE `tb_mlsrpqwnhf` ADD COLUMN `col_yualkpafem` double(197,7);\nALTER TABLE `tb_mlsrpqwnhf` ADD (`col_cmghpeldvl` mediumtext CHARACTER SET utf8, `col_ooogllngga` decimal(38,8) NULL);\nALTER TABLE `tb_mlsrpqwnhf` ADD `col_fkklsgzldp` numeric NOT NULL;\nALTER TABLE `tb_mlsrpqwnhf` ADD COLUMN (`col_bdqubzeijx` tinytext, `col_yeligvvmhm` tinytext CHARACTER SET utf8mb4);\nALTER TABLE `tb_mlsrpqwnhf` CHARACTER SET utf8;\nALTER TABLE `tb_mlsrpqwnhf` ADD CONSTRAINT PRIMARY KEY (`col_hiezvpgyuu`);\nALTER TABLE `tb_mlsrpqwnhf` ADD UNIQUE INDEX `uk_jybutmebnj` (`col_fkklsgzldp`,`col_yeligvvmhm`(2));\nALTER TABLE `tb_mlsrpqwnhf` ALTER `col_ovrngczyyk` DROP DEFAULT;\nALTER TABLE `tb_mlsrpqwnhf` ALTER COLUMN `col_mfdevzanga` DROP DEFAULT;\nALTER TABLE `tb_mlsrpqwnhf` CHANGE COLUMN `col_vydoxpfwit` `col_mitqygycnq` datetime(3) NULL FIRST;\nALTER TABLE `tb_mlsrpqwnhf` DROP COLUMN `col_hiezvpgyuu`, DROP COLUMN `col_ovrngczyyk`;\nALTER TABLE `tb_mlsrpqwnhf` DROP `col_fkklsgzldp`, DROP `col_ooogllngga`;\nALTER TABLE `tb_mlsrpqwnhf` DROP COLUMN `col_mfdevzanga`, DROP COLUMN `col_yualkpafem`;\nALTER TABLE `tb_mlsrpqwnhf` DROP `col_mitqygycnq`, DROP `col_yeligvvmhm`;\nALTER TABLE `tb_mlsrpqwnhf` DROP `col_cmghpeldvl`, DROP `col_bdqubzeijx`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_47.sql",
    "content": "CREATE TABLE `tb_ucmkmerovj` (\n  `col_hcfhnqdpda` tinyblob\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_nsjknrezjn` LIKE `tb_ucmkmerovj`;\nRENAME TABLE `tb_ucmkmerovj` TO `tb_spnawqlyqo`, `tb_nsjknrezjn` TO `tb_ezrzlemqcq`;\nRENAME TABLE `tb_spnawqlyqo` TO `tb_wbbrvurmym`;\nDROP TABLE tb_wbbrvurmym, tb_ezrzlemqcq;\nCREATE TABLE `tb_odwnejztgw` (\n  `col_grrazuxsmj` tinyint(108) unsigned zerofill,\n  UNIQUE `col_grrazuxsmj` (`col_grrazuxsmj`),\n  UNIQUE `uk_faxbizfzvg` (`col_grrazuxsmj`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nALTER TABLE `tb_odwnejztgw` ADD COLUMN `col_dqxacqwdav` year NULL;\nALTER TABLE `tb_odwnejztgw` ADD COLUMN `col_afisennniu` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') NOT NULL DEFAULT 'enum_or_set_0';\nALTER TABLE `tb_odwnejztgw` ADD COLUMN `col_ikgmyfugbh` time(3) FIRST;\nALTER TABLE `tb_odwnejztgw` ADD COLUMN (`col_hsbiyreflo` mediumblob, `col_pmcsqydybm` bit(59));\nALTER TABLE `tb_odwnejztgw` ADD (`col_caewwurnsu` mediumblob, `col_oyxhvytofb` tinyint(62) unsigned zerofill);\nALTER TABLE `tb_odwnejztgw` ADD `col_hxgvemyiam` tinytext CHARACTER SET utf8;\nALTER TABLE `tb_odwnejztgw` ADD COLUMN `col_ouwtrbmtli` varbinary(39) NULL DEFAULT '\\0' FIRST;\nALTER TABLE `tb_odwnejztgw` DEFAULT CHARACTER SET = utf8;\nALTER TABLE `tb_odwnejztgw` ADD CONSTRAINT symb_pztcjvefkb PRIMARY KEY (`col_afisennniu`);\nALTER TABLE `tb_odwnejztgw` CHANGE COLUMN `col_oyxhvytofb` `col_vumeeppqkm` int(62) zerofill;\nALTER TABLE `tb_odwnejztgw` DROP KEY `col_grrazuxsmj`;\nALTER TABLE `tb_odwnejztgw` DROP KEY `uk_faxbizfzvg`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_48.sql",
    "content": "CREATE TABLE `tb_cfbrttmxtt` (\n  `col_fcxqhwmcni` longblob,\n  `col_kswnnckixx` tinytext CHARACTER SET latin1,\n  `col_hpqddjdxxz` longblob,\n  `col_xnreiiwrcm` mediumint(225) unsigned DEFAULT '1',\n  UNIQUE INDEX `uk_cvkkrimfqi` (`col_kswnnckixx`(2),`col_hpqddjdxxz`(29))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_ibnzwrlofl` (\n  `col_kxzbyijcwt` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT 'enum_or_set_0',\n  `col_ydqlwiumbq` year NOT NULL,\n  `col_ektspnhakb` decimal(56,19),\n  PRIMARY KEY (`col_ydqlwiumbq`),\n  UNIQUE `uk_wrgomwzzul` (`col_kxzbyijcwt`,`col_ektspnhakb`),\n  UNIQUE `uk_ufhjbglflj` (`col_ektspnhakb`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_qhfiwjigtv` (\n  `col_gttrfjbbyi` varchar(161) CHARACTER SET utf8 NOT NULL,\n  `col_ksvxcquzhp` longtext CHARACTER SET utf8 COLLATE utf8_unicode_ci,\n  `col_ibahzyeiod` year(4) NOT NULL,\n  CONSTRAINT PRIMARY KEY (`col_gttrfjbbyi`(8)),\n  UNIQUE INDEX `col_ksvxcquzhp` (`col_ksvxcquzhp`(16),`col_ibahzyeiod`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_cfbrttmxtt` TO `tb_fzlrvzctbr`;\nRENAME TABLE `tb_ibnzwrlofl` TO `tb_tmasbkkzbt`;\nRENAME TABLE `tb_qhfiwjigtv` TO `tb_vnbuhzbwvw`;\nALTER TABLE `tb_tmasbkkzbt` ADD COLUMN `col_gvdetvdvvm` text(3429904651);\nALTER TABLE `tb_tmasbkkzbt` ADD UNIQUE `uk_dvgbfwphsv` (`col_gvdetvdvvm`(27));\nALTER TABLE `tb_tmasbkkzbt` ALTER `col_ektspnhakb` SET DEFAULT NULL;\nALTER TABLE `tb_tmasbkkzbt` DROP COLUMN `col_kxzbyijcwt`, DROP COLUMN `col_ektspnhakb`;\nALTER TABLE `tb_tmasbkkzbt` DROP `col_ydqlwiumbq`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_49.sql",
    "content": "CREATE TABLE `tb_yzmdpoldbu` (\n  `col_cmeqnxgnwo` int NULL DEFAULT '1',\n  `col_qgergaavlw` longtext CHARACTER SET utf8,\n  UNIQUE `uk_mctazwqtlw` (`col_qgergaavlw`(14))\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_iuchtibsiu` (\n  `col_qyxegyfxhd` binary NOT NULL,\n  `col_fhrwjmkunp` time NULL DEFAULT '00:00:00',\n  `col_ebdpffnuvl` longblob,\n  `col_ivfpfrbagk` decimal(48),\n  CONSTRAINT PRIMARY KEY (`col_qyxegyfxhd`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_iuchtibsiu` TO `tb_oxrpkkhlpd`;\nALTER TABLE `tb_yzmdpoldbu` ADD COLUMN (`col_qdzrqnbwug` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') NULL DEFAULT 'enum_or_set_0', `col_hdsuyxblyk` double(86,4));\nALTER TABLE `tb_yzmdpoldbu` ADD (`col_pabufpjxkv` tinytext, `col_ietwsffxgn` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2'));\nALTER TABLE `tb_yzmdpoldbu` ADD (`col_hvdglgtlxp` longblob, `col_bwfgathikh` integer unsigned);\nALTER TABLE `tb_yzmdpoldbu` ADD COLUMN `col_sdagljipnl` tinyblob AFTER `col_cmeqnxgnwo`;\nALTER TABLE `tb_yzmdpoldbu` ADD (`col_yenjodhatg` year NULL DEFAULT '2019', `col_fefjkkdwwg` tinytext);\nALTER TABLE `tb_yzmdpoldbu` ADD (`col_bhkqbxsemo` tinytext CHARACTER SET utf8mb4, `col_cwmggcyoud` numeric NULL);\nALTER TABLE `tb_yzmdpoldbu` ADD COLUMN `col_hrwaxjpjgr` binary NOT NULL;\nALTER TABLE `tb_yzmdpoldbu` ADD UNIQUE `uk_bmkecbeunv` (`col_fefjkkdwwg`(12),`col_cwmggcyoud`);\nALTER TABLE `tb_yzmdpoldbu` ALTER COLUMN `col_bwfgathikh` DROP DEFAULT;\nALTER TABLE `tb_yzmdpoldbu` CHANGE COLUMN `col_bhkqbxsemo` `col_kloxucvkgw` bigint(200) unsigned DEFAULT '1' AFTER `col_cwmggcyoud`;\nALTER TABLE `tb_yzmdpoldbu` CHANGE COLUMN `col_yenjodhatg` `col_pbngzmfduy` varchar(225) NOT NULL;\nALTER TABLE `tb_yzmdpoldbu` CHANGE COLUMN `col_cwmggcyoud` `col_prltnqtpwl` datetime(3);\nALTER TABLE `tb_yzmdpoldbu` DROP COLUMN `col_ietwsffxgn`, DROP COLUMN `col_hrwaxjpjgr`;\nALTER TABLE `tb_yzmdpoldbu` DROP `col_hdsuyxblyk`;\nALTER TABLE `tb_yzmdpoldbu` DROP `col_prltnqtpwl`, DROP `col_sdagljipnl`;\nALTER TABLE `tb_yzmdpoldbu` DROP `col_bwfgathikh`, DROP `col_qgergaavlw`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_5.sql",
    "content": "CREATE TABLE `tb_xfewelqveu` (\n  `col_vzrjzlcvms` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,\n  `col_sdyhbfaqdm` tinytext CHARACTER SET utf8,\n  `col_teupgphirm` numeric,\n  UNIQUE INDEX `col_sdyhbfaqdm` (`col_sdyhbfaqdm`(17)),\n  UNIQUE `col_sdyhbfaqdm_2` (`col_sdyhbfaqdm`(2))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_xfewelqveu` TO `tb_upgbkyyruv`;\nRENAME TABLE `tb_upgbkyyruv` TO `tb_ahefjpyxqu`;\nALTER TABLE `tb_ahefjpyxqu` ADD (`col_nkknhggvii` bigint(2) unsigned, `col_egwbfvawdd` double(243,27));\nALTER TABLE `tb_ahefjpyxqu` ALTER COLUMN `col_egwbfvawdd` DROP DEFAULT;\nALTER TABLE `tb_ahefjpyxqu` CHANGE COLUMN `col_teupgphirm` `col_cqrrpavzlu` tinyint(14) NULL DEFAULT '1' AFTER `col_sdyhbfaqdm`;\nALTER TABLE `tb_ahefjpyxqu` CHANGE `col_vzrjzlcvms` `col_djbztucmiv` datetime NULL DEFAULT '2019-07-04 00:00:00' FIRST;\nALTER TABLE `tb_ahefjpyxqu` DROP COLUMN `col_sdyhbfaqdm`, DROP COLUMN `col_djbztucmiv`;\nALTER TABLE `tb_ahefjpyxqu` DROP COLUMN `col_egwbfvawdd`, DROP COLUMN `col_nkknhggvii`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_50.sql",
    "content": "CREATE TABLE `tb_pksakrzcnn` (\n  `col_gtrcjlfnjb` tinyblob,\n  UNIQUE `col_gtrcjlfnjb` (`col_gtrcjlfnjb`(30)),\n  UNIQUE `uk_oobktihzsw` (`col_gtrcjlfnjb`(28))\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_tbfvbntpjg` (\n  `col_qqccessygq` year NOT NULL,\n  PRIMARY KEY (`col_qqccessygq`),\n  UNIQUE `uk_mffeuwunua` (`col_qqccessygq`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_tbfvbntpjg` TO `tb_rhtejtaerv`;\nRENAME TABLE `tb_pksakrzcnn` TO `tb_cfnewnjqhr`, `tb_rhtejtaerv` TO `tb_naclwnujgs`;\nALTER TABLE `tb_cfnewnjqhr` ADD (`col_efozqsfkcb` bit, `col_itpqtfoddn` tinytext CHARACTER SET utf8mb4);\nALTER TABLE `tb_cfnewnjqhr` ADD (`col_givbhjmmfw` smallint(231) zerofill, `col_bvndstnucz` char);\nALTER TABLE `tb_cfnewnjqhr` ADD COLUMN (`col_ongadrkgse` mediumblob, `col_cdwqlqfwox` int unsigned NULL DEFAULT '1');\nALTER TABLE `tb_cfnewnjqhr` DEFAULT CHARACTER SET utf8;\nALTER TABLE `tb_cfnewnjqhr` ADD UNIQUE (`col_gtrcjlfnjb`(11),`col_efozqsfkcb`);\nALTER TABLE `tb_cfnewnjqhr` CHANGE `col_itpqtfoddn` `col_zunavirely` bit NULL FIRST;\nALTER TABLE `tb_cfnewnjqhr` DROP COLUMN `col_bvndstnucz`, DROP COLUMN `col_zunavirely`;\nALTER TABLE `tb_cfnewnjqhr` DROP `col_ongadrkgse`, DROP `col_efozqsfkcb`;\nALTER TABLE `tb_cfnewnjqhr` DROP COLUMN `col_gtrcjlfnjb`;\nALTER TABLE `tb_cfnewnjqhr` DROP `col_givbhjmmfw`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_51.sql",
    "content": "CREATE TABLE `tb_bfwanxinyr` (\n  `col_msdkdkrbqj` tinytext CHARACTER SET latin1,\n  `col_qkgtxzzfie` tinyblob,\n  UNIQUE INDEX `col_msdkdkrbqj` (`col_msdkdkrbqj`(30))\n) DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_bfwanxinyr` TO `tb_wvhiikgeky`;\nRENAME TABLE `tb_wvhiikgeky` TO `tb_krsikytrbw`;\nALTER TABLE `tb_krsikytrbw` ADD COLUMN (`col_lfbganjgad` timestamp(4) NULL, `col_lyscxymhbl` integer unsigned DEFAULT '1');\nALTER TABLE `tb_krsikytrbw` ADD (`col_eystskhwfm` char CHARACTER SET utf8mb4, `col_cqjptjcgyb` binary NOT NULL);\nALTER TABLE `tb_krsikytrbw` ADD COLUMN (`col_mlvshwiulp` numeric(15), `col_lfptlilmsv` int(230) zerofill NOT NULL);\nALTER TABLE `tb_krsikytrbw` ADD COLUMN (`col_inukcthnws` varchar(114), `col_omxbpiulnd` year DEFAULT '2019');\nALTER TABLE `tb_krsikytrbw` ADD COLUMN `col_lnpeucimig` time NOT NULL DEFAULT '00:00:00';\nALTER TABLE `tb_krsikytrbw` ADD `col_idovrewllo` tinytext FIRST;\nALTER TABLE `tb_krsikytrbw` ADD `col_szvdshblvc` tinyint(109) unsigned zerofill;\nALTER TABLE `tb_krsikytrbw` ADD COLUMN `col_qgtkapnaff` blob(2990008429);\nALTER TABLE `tb_krsikytrbw` ADD CONSTRAINT symb_kcuznajfjp PRIMARY KEY (`col_cqjptjcgyb`);\nALTER TABLE `tb_krsikytrbw` ADD UNIQUE (`col_qgtkapnaff`(16));\nALTER TABLE `tb_krsikytrbw` ADD UNIQUE INDEX (`col_cqjptjcgyb`,`col_szvdshblvc`);\nALTER TABLE `tb_krsikytrbw` ALTER `col_eystskhwfm` DROP DEFAULT;\nALTER TABLE `tb_krsikytrbw` ALTER COLUMN `col_cqjptjcgyb` DROP DEFAULT;\nALTER TABLE `tb_krsikytrbw` ALTER COLUMN `col_lnpeucimig` SET DEFAULT '00:00:00';\nALTER TABLE `tb_krsikytrbw` CHANGE `col_idovrewllo` `col_lkhsufhjwr` mediumint(8) zerofill NULL;\nALTER TABLE `tb_krsikytrbw` CHANGE COLUMN `col_lnpeucimig` `col_zdneomelnh` decimal(14) NOT NULL;\nALTER TABLE `tb_krsikytrbw` CHANGE `col_szvdshblvc` `col_lliihnoyoo` integer(145) NOT NULL DEFAULT '1' AFTER `col_lkhsufhjwr`;\nALTER TABLE `tb_krsikytrbw` DROP `col_mlvshwiulp`, DROP `col_lyscxymhbl`;\nALTER TABLE `tb_krsikytrbw` DROP COLUMN `col_inukcthnws`;\nALTER TABLE `tb_krsikytrbw` DROP `col_qgtkapnaff`;\nALTER TABLE `tb_krsikytrbw` DROP COLUMN `col_lkhsufhjwr`, DROP COLUMN `col_msdkdkrbqj`;\nALTER TABLE `tb_krsikytrbw` DROP COLUMN `col_eystskhwfm`, DROP COLUMN `col_zdneomelnh`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_52.sql",
    "content": "CREATE TABLE `tb_udrucjftxw` (\n  `col_tustciiwwp` datetime(2),\n  `col_xhjeuttrui` text(4218326145) CHARACTER SET utf8mb4,\n  `col_gzwherugvm` decimal(35,10),\n  `col_fwooxfmvvs` tinytext CHARACTER SET utf8,\n  UNIQUE `uk_kllnpcqqzt` (`col_xhjeuttrui`(30)),\n  UNIQUE INDEX `uk_omzcuexdxr` (`col_xhjeuttrui`(8),`col_gzwherugvm`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_ykcdymjhfs` LIKE `tb_udrucjftxw`;\nRENAME TABLE `tb_ykcdymjhfs` TO `tb_dkkimqxscg`;\nRENAME TABLE `tb_dkkimqxscg` TO `tb_syxeibzqzx`;\nALTER TABLE `tb_syxeibzqzx` ADD COLUMN (`col_orgcdijcqm` numeric(50,5) NULL, `col_shntqukbsk` datetime NULL);\nALTER TABLE `tb_syxeibzqzx` ADD COLUMN `col_ecxangkhqi` numeric DEFAULT '1' AFTER `col_gzwherugvm`;\nALTER TABLE `tb_syxeibzqzx` ADD `col_nekpdybkhy` integer(53) unsigned DEFAULT '1';\nALTER TABLE `tb_syxeibzqzx` ADD COLUMN (`col_sxwiebuapp` tinyint unsigned NULL DEFAULT '1', `col_mqllkiyvhv` bit DEFAULT b'0');\nALTER TABLE `tb_syxeibzqzx` ADD (`col_wfgcfbwoia` tinyint unsigned zerofill NULL, `col_ftvwzcealb` int DEFAULT '1');\nALTER TABLE `tb_syxeibzqzx` ADD UNIQUE INDEX `uk_puugjtgkjy` (`col_wfgcfbwoia`,`col_ftvwzcealb`);\nALTER TABLE `tb_syxeibzqzx` CHANGE `col_ftvwzcealb` `col_hvglzyyxbw` bigint unsigned NULL DEFAULT '1';\nALTER TABLE `tb_syxeibzqzx` CHANGE `col_orgcdijcqm` `col_gzrngpftzg` tinyint(238) NULL DEFAULT '1';\nALTER TABLE `tb_syxeibzqzx` CHANGE `col_tustciiwwp` `col_aqtxegfokt` tinyblob FIRST;\nALTER TABLE `tb_syxeibzqzx` DROP `col_sxwiebuapp`;\nALTER TABLE `tb_syxeibzqzx` DROP COLUMN `col_ecxangkhqi`, DROP COLUMN `col_wfgcfbwoia`;\nALTER TABLE `tb_syxeibzqzx` DROP COLUMN `col_gzrngpftzg`, DROP COLUMN `col_gzwherugvm`;\nALTER TABLE `tb_syxeibzqzx` DROP COLUMN `col_hvglzyyxbw`;\nALTER TABLE `tb_syxeibzqzx` DROP `col_nekpdybkhy`, DROP `col_aqtxegfokt`;\nALTER TABLE `tb_syxeibzqzx` DROP `col_xhjeuttrui`;\nALTER TABLE `tb_syxeibzqzx` DROP COLUMN `col_mqllkiyvhv`, DROP COLUMN `col_fwooxfmvvs`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_53.sql",
    "content": "CREATE TABLE `tb_gphkzjggwo` (\n  `col_gmbhpsrxst` int(165) NULL DEFAULT '1',\n  `col_cfefurpvif` int unsigned zerofill,\n  UNIQUE `col_cfefurpvif` (`col_cfefurpvif`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_kfmwkcront` LIKE `tb_gphkzjggwo`;\nRENAME TABLE `tb_gphkzjggwo` TO `tb_swbjpgvwuf`;\nRENAME TABLE `tb_swbjpgvwuf` TO `tb_hdbseivabf`;\nRENAME TABLE `tb_kfmwkcront` TO `tb_mnqvagcyml`, `tb_hdbseivabf` TO `tb_eswbmodety`;\nDROP TABLE tb_eswbmodety, tb_mnqvagcyml;\nCREATE TABLE `tb_gcekkribdm` (\n  `col_vbxxcedehr` varbinary(72) DEFAULT '\\0',\n  `col_spnkzcnaaj` tinyint(221) unsigned zerofill NULL,\n  `col_vdafmpnlcj` timestamp NULL,\n  `col_pwwnuhvonf` bit NULL,\n  UNIQUE `uk_oyduszzkbw` (`col_vdafmpnlcj`,`col_pwwnuhvonf`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nALTER TABLE `tb_gcekkribdm` ADD COLUMN (`col_wpdnfgwkmm` float(253,19) NOT NULL, `col_hmbydpntpk` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT 'enum_or_set_0');\nALTER TABLE `tb_gcekkribdm` ADD (`col_mrruauiuzg` mediumblob, `col_cxafkgwrzu` varbinary(36));\nALTER TABLE `tb_gcekkribdm` ADD COLUMN (`col_ooxuaiyuqa` mediumint(107) unsigned zerofill NULL, `col_mxpgmnrigf` decimal);\nALTER TABLE `tb_gcekkribdm` ADD COLUMN (`col_sgjbftdxrq` mediumtext, `col_zboghrfujc` char(34) CHARACTER SET utf8mb4);\nALTER TABLE `tb_gcekkribdm` ADD COLUMN `col_doacvjtxfj` text FIRST;\nALTER TABLE `tb_gcekkribdm` ADD (`col_xpwlcesvfx` integer(73), `col_inpipqloqk` smallint zerofill NULL);\nALTER TABLE `tb_gcekkribdm` ADD `col_kahmeuqzzo` mediumtext CHARACTER SET utf8mb4 AFTER `col_hmbydpntpk`;\nALTER TABLE `tb_gcekkribdm` ADD COLUMN `col_xpuntwyhls` int(253) zerofill FIRST;\nALTER TABLE `tb_gcekkribdm` ADD (`col_rhqisewrfr` binary(209) NULL, `col_dznwcqadnc` mediumtext);\nALTER TABLE `tb_gcekkribdm` CHARACTER SET utf8mb4;\nALTER TABLE `tb_gcekkribdm` CHANGE COLUMN `col_inpipqloqk` `col_lctlnulyqs` varchar(141) CHARACTER SET utf8 DEFAULT '' AFTER `col_spnkzcnaaj`;\nALTER TABLE `tb_gcekkribdm` CHANGE `col_rhqisewrfr` `col_xpdyiqxtxg` decimal(62);\nALTER TABLE `tb_gcekkribdm` CHANGE `col_xpdyiqxtxg` `col_ysqvnorogf` int unsigned DEFAULT '1';\nALTER TABLE `tb_gcekkribdm` DROP KEY `uk_oyduszzkbw`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_54.sql",
    "content": "CREATE TABLE `tb_zauuwyxibd` (\n  `col_rbwuihwtww` float NULL DEFAULT '1',\n  `col_zopsszwsjh` numeric DEFAULT '1',\n  UNIQUE `col_zopsszwsjh` (`col_zopsszwsjh`)\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_zauuwyxibd` TO `tb_cdvsermcmz`;\nRENAME TABLE `tb_cdvsermcmz` TO `tb_fijiqnymmp`;\nALTER TABLE `tb_fijiqnymmp` ADD COLUMN (`col_xxjnkwqqms` varbinary(216) DEFAULT '\\0', `col_rhkizkifwy` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 NULL);\nALTER TABLE `tb_fijiqnymmp` CHANGE COLUMN `col_xxjnkwqqms` `col_tcroqoomon` tinyblob AFTER `col_rbwuihwtww`;\nALTER TABLE `tb_fijiqnymmp` CHANGE `col_zopsszwsjh` `col_wontrujmna` year(4) DEFAULT '2019' AFTER `col_rbwuihwtww`;\nALTER TABLE `tb_fijiqnymmp` DROP COLUMN `col_rhkizkifwy`;\nALTER TABLE `tb_fijiqnymmp` DROP `col_wontrujmna`, DROP `col_rbwuihwtww`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_55.sql",
    "content": "CREATE TABLE `tb_jkbiibupis` (\n  `col_fkolmhdrqv` int unsigned,\n  `col_evazkiwccb` longblob,\n  `col_gfzhcaruwf` tinytext CHARACTER SET utf8,\n  UNIQUE KEY `col_evazkiwccb` (`col_evazkiwccb`(17)),\n  UNIQUE KEY `uk_qeuoketlhl` (`col_gfzhcaruwf`(28))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_pqjlitgelb` (\n  `col_rvdpillohr` smallint(51) unsigned NOT NULL,\n  `col_wjvgjpqbgz` smallint unsigned zerofill NULL,\n  CONSTRAINT symb_vytyeftcau PRIMARY KEY (`col_rvdpillohr`),\n  UNIQUE INDEX `uk_aqetlmillq` (`col_wjvgjpqbgz`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_jkbiibupis` TO `tb_epubreeayc`, `tb_pqjlitgelb` TO `tb_uafierhjhg`;\nALTER TABLE `tb_epubreeayc` ADD COLUMN `col_eznnzdmtjb` blob(2459218563) AFTER `col_gfzhcaruwf`;\nALTER TABLE `tb_epubreeayc` ADD `col_orujerqezb` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4;\nALTER TABLE `tb_epubreeayc` ADD COLUMN (`col_furvidozht` text(2634346399) CHARACTER SET utf8, `col_embnqthyuu` float(30) NOT NULL);\nALTER TABLE `tb_epubreeayc` ADD (`col_nifvahqfqx` tinytext CHARACTER SET utf8mb4, `col_shqnxczemy` binary(149));\nALTER TABLE `tb_epubreeayc` ADD `col_vkrzrlbckh` binary AFTER `col_embnqthyuu`;\nALTER TABLE `tb_epubreeayc` ADD COLUMN `col_aqvohzuvxd` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NOT NULL;\nALTER TABLE `tb_epubreeayc` ADD (`col_aexcfuzeln` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') NULL DEFAULT 'enum_or_set_0', `col_gyjfdfpemu` text(1480656314));\nALTER TABLE `tb_epubreeayc` DEFAULT CHARACTER SET = utf8mb4;\nALTER TABLE `tb_epubreeayc` ADD PRIMARY KEY (`col_embnqthyuu`);\nALTER TABLE `tb_epubreeayc` ADD UNIQUE `uk_uydztaglgb` (`col_aqvohzuvxd`,`col_aexcfuzeln`);\nALTER TABLE `tb_epubreeayc` DROP `col_furvidozht`;\nALTER TABLE `tb_epubreeayc` DROP `col_vkrzrlbckh`;\nALTER TABLE `tb_epubreeayc` DROP `col_gfzhcaruwf`;\nALTER TABLE `tb_epubreeayc` DROP `col_aqvohzuvxd`;\nALTER TABLE `tb_epubreeayc` DROP COLUMN `col_orujerqezb`;\nALTER TABLE `tb_epubreeayc` DROP `col_nifvahqfqx`, DROP `col_eznnzdmtjb`;\nALTER TABLE `tb_epubreeayc` DROP COLUMN `col_aexcfuzeln`, DROP COLUMN `col_evazkiwccb`;\nALTER TABLE `tb_epubreeayc` DROP `col_fkolmhdrqv`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_56.sql",
    "content": "CREATE TABLE `tb_lvzjcjnwfj` (\n  `col_wfdgvtipop` binary(1) NOT NULL,\n  `col_dhvowgmope` date,\n  `col_ztgybltpcr` bit(42) DEFAULT b'0',\n  `col_rfeddmkkmb` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NULL DEFAULT 'enum_or_set_0',\n  CONSTRAINT symb_puisvgsxvj PRIMARY KEY (`col_wfdgvtipop`),\n  UNIQUE `col_rfeddmkkmb` (`col_rfeddmkkmb`),\n  UNIQUE INDEX `col_wfdgvtipop` (`col_wfdgvtipop`)\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_lvzjcjnwfj` TO `tb_gwhtsxuovt`;\nRENAME TABLE `tb_gwhtsxuovt` TO `tb_gvuiytzqsi`;\nRENAME TABLE `tb_gvuiytzqsi` TO `tb_hjqdntirzd`;\nALTER TABLE `tb_hjqdntirzd` ADD COLUMN `col_oirceeozit` mediumtext AFTER `col_wfdgvtipop`;\nALTER TABLE `tb_hjqdntirzd` ADD COLUMN (`col_ckheruciet` blob(829823439), `col_mwlpdcpegm` char NULL);\nALTER TABLE `tb_hjqdntirzd` ADD COLUMN (`col_okjyevogvl` integer NULL DEFAULT '1', `col_nperdtdonu` int(55) unsigned zerofill NOT NULL);\nALTER TABLE `tb_hjqdntirzd` ADD COLUMN (`col_cawkxhaucp` tinyblob, `col_urbzxvvjju` binary(3) NULL);\nALTER TABLE `tb_hjqdntirzd` CHARACTER SET = utf8mb4;\nALTER TABLE `tb_hjqdntirzd` ADD UNIQUE KEY `uk_hrnnhxlode` (`col_urbzxvvjju`);\nALTER TABLE `tb_hjqdntirzd` ADD UNIQUE (`col_mwlpdcpegm`,`col_nperdtdonu`);\nALTER TABLE `tb_hjqdntirzd` ALTER `col_nperdtdonu` DROP DEFAULT;\nALTER TABLE `tb_hjqdntirzd` CHANGE COLUMN `col_mwlpdcpegm` `col_dtiogubkiw` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NULL DEFAULT 'enum_or_set_0' AFTER `col_ckheruciet`;\nALTER TABLE `tb_hjqdntirzd` CHANGE `col_nperdtdonu` `col_uwucrgteir` tinyint(120) DEFAULT '1';\nALTER TABLE `tb_hjqdntirzd` CHANGE `col_ztgybltpcr` `col_egpjhiepzh` smallint(0) DEFAULT '1';\nALTER TABLE `tb_hjqdntirzd` DROP `col_dhvowgmope`, DROP `col_wfdgvtipop`;\nALTER TABLE `tb_hjqdntirzd` DROP COLUMN `col_urbzxvvjju`, DROP COLUMN `col_rfeddmkkmb`;\nALTER TABLE `tb_hjqdntirzd` DROP `col_oirceeozit`, DROP `col_egpjhiepzh`;\nALTER TABLE `tb_hjqdntirzd` DROP COLUMN `col_uwucrgteir`, DROP COLUMN `col_ckheruciet`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_57.sql",
    "content": "CREATE TABLE `tb_fvjncpgwhy` (\n  `col_twxddkipof` bit DEFAULT b'0',\n  `col_gsqeppbqjg` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4,\n  `col_yeejeykwvz` mediumblob,\n  `col_icjtmriski` varbinary(56) NULL,\n  UNIQUE `uk_lqliirowvk` (`col_yeejeykwvz`(18))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_okrocudiku` (\n  `col_ksrzieegxf` smallint(50) zerofill NULL,\n  `col_resqomiafx` tinyblob\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_okrocudiku` TO `tb_bozkivuenk`, `tb_fvjncpgwhy` TO `tb_cegumineka`;\nRENAME TABLE `tb_cegumineka` TO `tb_xmvawoekwx`;\nDROP TABLE tb_bozkivuenk;\nALTER TABLE `tb_xmvawoekwx` ADD COLUMN `col_jzpxlsfskd` varbinary(49) DEFAULT '\\0' FIRST;\nALTER TABLE `tb_xmvawoekwx` CHARACTER SET utf8mb4;\nALTER TABLE `tb_xmvawoekwx` ADD UNIQUE INDEX `uk_gkkpkxazqo` (`col_yeejeykwvz`(18),`col_icjtmriski`(2));\nALTER TABLE `tb_xmvawoekwx` ADD UNIQUE INDEX `uk_sgrofvqufp` (`col_yeejeykwvz`(32),`col_icjtmriski`(2));\nALTER TABLE `tb_xmvawoekwx` CHANGE COLUMN `col_twxddkipof` `col_vvbbdbzdxx` longblob AFTER `col_yeejeykwvz`;\nALTER TABLE `tb_xmvawoekwx` DROP `col_yeejeykwvz`;\nALTER TABLE `tb_xmvawoekwx` DROP `col_jzpxlsfskd`;\nALTER TABLE `tb_xmvawoekwx` DROP `col_vvbbdbzdxx`, DROP `col_icjtmriski`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_58.sql",
    "content": "CREATE TABLE `tb_ezaysnxloa` (\n  `col_koftcyrhcl` int(233) DEFAULT '1',\n  `col_nacwazcyzi` varbinary(12),\n  UNIQUE `col_koftcyrhcl` (`col_koftcyrhcl`)\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_ezaysnxloa` TO `tb_wsxpqlbxhr`;\nALTER TABLE `tb_wsxpqlbxhr` ADD COLUMN (`col_nnckvjhnnd` tinytext CHARACTER SET utf8 COLLATE utf8_unicode_ci, `col_sxwmoaghtk` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT 'enum_or_set_0');\nALTER TABLE `tb_wsxpqlbxhr` ADD `col_btyjfvfohb` double(18,12);\nALTER TABLE `tb_wsxpqlbxhr` ADD (`col_udrjznhpgf` tinytext, `col_ynwgneexdq` mediumtext CHARACTER SET utf8 COLLATE utf8_unicode_ci);\nALTER TABLE `tb_wsxpqlbxhr` ADD COLUMN `col_kkdtlacxiy` char NOT NULL FIRST;\nALTER TABLE `tb_wsxpqlbxhr` ADD `col_xlcidwqtlg` tinytext CHARACTER SET utf8;\nALTER TABLE `tb_wsxpqlbxhr` ADD COLUMN (`col_huxsdgntaw` numeric(27,14) NOT NULL, `col_siklbsrsfa` date NOT NULL);\nALTER TABLE `tb_wsxpqlbxhr` ADD PRIMARY KEY (`col_kkdtlacxiy`,`col_huxsdgntaw`);\nALTER TABLE `tb_wsxpqlbxhr` ADD UNIQUE INDEX `uk_cpzrxvccoo` (`col_nacwazcyzi`(7),`col_xlcidwqtlg`(9));\nALTER TABLE `tb_wsxpqlbxhr` CHANGE COLUMN `col_udrjznhpgf` `col_qpusrblupw` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT 'enum_or_set_0';\nALTER TABLE `tb_wsxpqlbxhr` DROP COLUMN `col_huxsdgntaw`;\nALTER TABLE `tb_wsxpqlbxhr` DROP `col_siklbsrsfa`, DROP `col_ynwgneexdq`;\nALTER TABLE `tb_wsxpqlbxhr` DROP `col_xlcidwqtlg`;\nALTER TABLE `tb_wsxpqlbxhr` DROP KEY `uk_cpzrxvccoo`;\nALTER TABLE `tb_wsxpqlbxhr` DROP KEY `col_koftcyrhcl`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_59.sql",
    "content": "CREATE TABLE `tb_dvddpenkxa` (\n  `col_zswpqbctyi` tinyblob,\n  `col_jdidaolbpa` tinyblob,\n  `col_eemywvvaqc` float DEFAULT '1'\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_iccbmqajux` (\n  `col_rtzczeoxsl` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NULL DEFAULT 'enum_or_set_0',\n  UNIQUE `col_rtzczeoxsl` (`col_rtzczeoxsl`),\n  UNIQUE `uk_qbqnttuesx` (`col_rtzczeoxsl`)\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_dvddpenkxa` TO `tb_gqtjkbvgka`, `tb_iccbmqajux` TO `tb_sjauultjmo`;\nRENAME TABLE `tb_sjauultjmo` TO `tb_kwnuzmzxqv`, `tb_gqtjkbvgka` TO `tb_aolqhhluko`;\nRENAME TABLE `tb_aolqhhluko` TO `tb_pengxwurit`;\nDROP TABLE tb_kwnuzmzxqv, tb_pengxwurit;\nCREATE TABLE `tb_hbheuprskb` (\n  `col_fdqpihurmr` time(0),\n  `col_owakmhospa` longtext CHARACTER SET utf8mb4,\n  `col_qdrqmqehyb` varbinary(89) NOT NULL,\n  `col_mmxaoivplw` time NOT NULL DEFAULT '00:00:00',\n  PRIMARY KEY (`col_qdrqmqehyb`(1)),\n  UNIQUE INDEX `uk_fwmxmptctu` (`col_owakmhospa`(30),`col_mmxaoivplw`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nALTER TABLE `tb_hbheuprskb` ADD COLUMN (`col_lxqjgyhhxu` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT 'enum_or_set_0', `col_mqqxkezdux` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') NOT NULL);\nALTER TABLE `tb_hbheuprskb` DEFAULT CHARACTER SET utf8mb4;\nALTER TABLE `tb_hbheuprskb` ADD UNIQUE INDEX (`col_mqqxkezdux`);\nALTER TABLE `tb_hbheuprskb` ALTER COLUMN `col_mmxaoivplw` SET DEFAULT '00:00:00';\nALTER TABLE `tb_hbheuprskb` ALTER COLUMN `col_mmxaoivplw` DROP DEFAULT;\nALTER TABLE `tb_hbheuprskb` ALTER COLUMN `col_mmxaoivplw` DROP DEFAULT;\nALTER TABLE `tb_hbheuprskb` CHANGE COLUMN `col_lxqjgyhhxu` `col_xxgthtdavh` datetime NOT NULL FIRST;\nALTER TABLE `tb_hbheuprskb` CHANGE `col_fdqpihurmr` `col_wlrahixbmg` blob(812190565);\nALTER TABLE `tb_hbheuprskb` CHANGE COLUMN `col_owakmhospa` `col_riqgldqhjp` integer NULL DEFAULT '1';\nALTER TABLE `tb_hbheuprskb` DROP COLUMN `col_mmxaoivplw`;\nALTER TABLE `tb_hbheuprskb` DROP COLUMN `col_wlrahixbmg`;\nALTER TABLE `tb_hbheuprskb` DROP `col_qdrqmqehyb`;\nALTER TABLE `tb_hbheuprskb` DROP `col_xxgthtdavh`;\nALTER TABLE `tb_hbheuprskb` DROP `col_riqgldqhjp`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_6.sql",
    "content": "CREATE TABLE `tb_cvctdzexnw` (\n  `col_ubxpjfudbv` timestamp(5) DEFAULT CURRENT_TIMESTAMP(5),\n  `col_otmxxxfiqk` year(4) NOT NULL,\n  `col_ctnmteeugh` tinytext CHARACTER SET utf8mb4,\n  UNIQUE KEY `col_ubxpjfudbv` (`col_ubxpjfudbv`,`col_otmxxxfiqk`)\n) DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_cvctdzexnw` TO `tb_yzcwyrztvj`;\nALTER TABLE `tb_yzcwyrztvj` ADD `col_oowroifdzd` mediumblob;\nALTER TABLE `tb_yzcwyrztvj` ADD COLUMN (`col_vnqmuvuxjr` tinyblob, `col_jmsmixjrlt` binary(244) NULL);\nALTER TABLE `tb_yzcwyrztvj` ADD COLUMN (`col_hhnmmxmqtx` int(213) unsigned zerofill NULL, `col_koijxckugd` text(2232458377) CHARACTER SET utf8mb4);\nALTER TABLE `tb_yzcwyrztvj` ADD COLUMN (`col_bjzaoslady` float(19) NULL, `col_gyvlawjxpq` numeric NOT NULL);\nALTER TABLE `tb_yzcwyrztvj` ADD PRIMARY KEY (`col_ubxpjfudbv`);\nALTER TABLE `tb_yzcwyrztvj` ADD UNIQUE KEY `uk_swcaqrkugf` (`col_otmxxxfiqk`,`col_ctnmteeugh`(1));\nALTER TABLE `tb_yzcwyrztvj` ADD UNIQUE (`col_jmsmixjrlt`(22),`col_hhnmmxmqtx`);\nALTER TABLE `tb_yzcwyrztvj` ALTER `col_otmxxxfiqk` SET DEFAULT '2019';\nALTER TABLE `tb_yzcwyrztvj` CHANGE `col_oowroifdzd` `col_oqzqcdxhvk` decimal(35,30) AFTER `col_koijxckugd`;\nALTER TABLE `tb_yzcwyrztvj` DROP `col_gyvlawjxpq`, DROP `col_ctnmteeugh`;\nALTER TABLE `tb_yzcwyrztvj` DROP `col_oqzqcdxhvk`;\nALTER TABLE `tb_yzcwyrztvj` DROP COLUMN `col_koijxckugd`;\nALTER TABLE `tb_yzcwyrztvj` DROP COLUMN `col_otmxxxfiqk`, DROP COLUMN `col_vnqmuvuxjr`;\nALTER TABLE `tb_yzcwyrztvj` DROP COLUMN `col_jmsmixjrlt`;\nALTER TABLE `tb_yzcwyrztvj` DROP `col_hhnmmxmqtx`;\nALTER TABLE `tb_yzcwyrztvj` DROP COLUMN `col_bjzaoslady`;\nALTER TABLE `tb_yzcwyrztvj` DROP KEY `col_ubxpjfudbv`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_60.sql",
    "content": "CREATE TABLE `tb_zsvasnztbf` (\n  `col_vqskztkwqb` blob(2179715620),\n  `col_xrutymggiq` text CHARACTER SET latin1,\n  `col_rjrhithgjd` varbinary(93) NOT NULL,\n  PRIMARY KEY (`col_rjrhithgjd`(23)),\n  UNIQUE `uk_qcuhitxxlz` (`col_rjrhithgjd`(12))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_joibqmiluh` (\n  `col_aszmqpjfka` numeric(49),\n  `col_qmwcrinzvf` time NOT NULL,\n  `col_xgwavsjbcg` longblob,\n  UNIQUE `col_xgwavsjbcg` (`col_xgwavsjbcg`(22))\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_zsvasnztbf` TO `tb_sxhjnreyoa`, `tb_joibqmiluh` TO `tb_qlhhbdmoeq`;\nRENAME TABLE `tb_sxhjnreyoa` TO `tb_idttivasrc`, `tb_qlhhbdmoeq` TO `tb_rjdimmicei`;\nALTER TABLE `tb_idttivasrc` ADD (`col_qgehaatedk` tinyint unsigned zerofill NOT NULL, `col_ngqfbkxgkw` tinyblob);\nALTER TABLE `tb_idttivasrc` ADD `col_naimzyvtyy` mediumint unsigned AFTER `col_qgehaatedk`;\nALTER TABLE `tb_idttivasrc` ADD COLUMN `col_ybyyrfaujt` longtext;\nALTER TABLE `tb_idttivasrc` ADD COLUMN (`col_slxxarfdmi` binary(243), `col_fueiigtecm` blob(2615853032));\nALTER TABLE `tb_idttivasrc` DEFAULT CHARACTER SET utf8mb4;\nALTER TABLE `tb_idttivasrc` ALTER COLUMN `col_rjrhithgjd` DROP DEFAULT;\nALTER TABLE `tb_idttivasrc` DROP COLUMN `col_rjrhithgjd`;\nALTER TABLE `tb_idttivasrc` DROP COLUMN `col_fueiigtecm`, DROP COLUMN `col_ybyyrfaujt`;\nALTER TABLE `tb_idttivasrc` DROP `col_qgehaatedk`, DROP `col_xrutymggiq`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_61.sql",
    "content": "CREATE TABLE `tb_jhzyfvcckl` (\n  `col_qintmgglbx` longblob,\n  `col_ovkqmnppgs` varchar(173) CHARACTER SET utf8 NOT NULL DEFAULT '',\n  CONSTRAINT PRIMARY KEY (`col_ovkqmnppgs`(20))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_lbmxsuqwfl` LIKE `tb_jhzyfvcckl`;\nRENAME TABLE `tb_lbmxsuqwfl` TO `tb_xexteouuua`, `tb_jhzyfvcckl` TO `tb_ifclwhlshu`;\nRENAME TABLE `tb_ifclwhlshu` TO `tb_kuxfqvurrv`;\nRENAME TABLE `tb_xexteouuua` TO `tb_sbjgtoodpq`;\nDROP TABLE tb_kuxfqvurrv;\nALTER TABLE `tb_sbjgtoodpq` ADD (`col_qarkfvqqbu` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT 'enum_or_set_0', `col_qftesnwcek` blob);\nALTER TABLE `tb_sbjgtoodpq` ADD COLUMN (`col_ihnqibzahr` timestamp, `col_vrqkkfmczz` datetime(3));\nALTER TABLE `tb_sbjgtoodpq` ADD COLUMN (`col_rsjadrmlhn` varchar(202) CHARACTER SET utf8mb4 NOT NULL, `col_npydnongql` decimal(45) NOT NULL);\nALTER TABLE `tb_sbjgtoodpq` ADD COLUMN (`col_pfssvgbbli` bigint unsigned zerofill NULL, `col_gygioimzsp` char(93) NOT NULL);\nALTER TABLE `tb_sbjgtoodpq` ADD `col_qqyenpblbe` binary;\nALTER TABLE `tb_sbjgtoodpq` ADD COLUMN (`col_mkayxjoxkl` binary(229), `col_zlrfenamiz` float(28) NULL);\nALTER TABLE `tb_sbjgtoodpq` ADD COLUMN (`col_nghfeukgiz` tinyint(108) unsigned NOT NULL DEFAULT '1', `col_aocdtcdbuv` longtext);\nALTER TABLE `tb_sbjgtoodpq` ADD UNIQUE `uk_eikmgzebja` (`col_ovkqmnppgs`(31),`col_rsjadrmlhn`(24));\nALTER TABLE `tb_sbjgtoodpq` ADD UNIQUE KEY `col_mkayxjoxkl`(`col_mkayxjoxkl`(27),`col_nghfeukgiz`);\nALTER TABLE `tb_sbjgtoodpq` ALTER COLUMN `col_qqyenpblbe` DROP DEFAULT;\nALTER TABLE `tb_sbjgtoodpq` ALTER COLUMN `col_zlrfenamiz` DROP DEFAULT;\nALTER TABLE `tb_sbjgtoodpq` CHANGE `col_rsjadrmlhn` `col_ebmqvifose` bit DEFAULT b'0' AFTER `col_ovkqmnppgs`;\nALTER TABLE `tb_sbjgtoodpq` CHANGE COLUMN `col_qftesnwcek` `col_btsvyjliwe` longtext CHARACTER SET utf8 AFTER `col_gygioimzsp`;\nALTER TABLE `tb_sbjgtoodpq` DROP COLUMN `col_vrqkkfmczz`;\nALTER TABLE `tb_sbjgtoodpq` DROP `col_nghfeukgiz`;\nALTER TABLE `tb_sbjgtoodpq` DROP COLUMN `col_qarkfvqqbu`;\nALTER TABLE `tb_sbjgtoodpq` DROP COLUMN `col_gygioimzsp`;\nALTER TABLE `tb_sbjgtoodpq` DROP `col_qintmgglbx`, DROP `col_ebmqvifose`;\nALTER TABLE `tb_sbjgtoodpq` DROP `col_aocdtcdbuv`;\nALTER TABLE `tb_sbjgtoodpq` DROP `col_ovkqmnppgs`;\nALTER TABLE `tb_sbjgtoodpq` DROP COLUMN `col_ihnqibzahr`, DROP COLUMN `col_btsvyjliwe`;\nALTER TABLE `tb_sbjgtoodpq` DROP KEY `col_mkayxjoxkl`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_62.sql",
    "content": "CREATE TABLE `tb_xuylcctytd` (\n  `col_oxgdbldyfk` bigint(171) zerofill,\n  `col_sfpolurvqu` double(2,2),\n  `col_hkfndsohtj` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET latin1 NOT NULL,\n  CONSTRAINT symb_gppmypbafa PRIMARY KEY (`col_hkfndsohtj`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_xuylcctytd` TO `tb_mvpbukrobp`;\nALTER TABLE `tb_mvpbukrobp` ADD COLUMN `col_gepoechcst` char;\nALTER TABLE `tb_mvpbukrobp` ADD COLUMN (`col_owvaejsbfe` blob, `col_hgaiklgzif` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') NULL);\nALTER TABLE `tb_mvpbukrobp` ADD (`col_ndfdyxpuhz` timestamp(0) DEFAULT CURRENT_TIMESTAMP(0), `col_hnerbhuhmd` timestamp(5) NULL DEFAULT CURRENT_TIMESTAMP(5));\nALTER TABLE `tb_mvpbukrobp` ADD (`col_vrsytgjrfw` date DEFAULT '2019-07-04', `col_vlgjlismyz` text);\nALTER TABLE `tb_mvpbukrobp` ADD (`col_vfwrbmtwyi` tinyblob, `col_qeoodzhosh` blob(445889767));\nALTER TABLE `tb_mvpbukrobp` ADD `col_ivdmwufhla` bit NULL DEFAULT b'0';\nALTER TABLE `tb_mvpbukrobp` ADD (`col_vpymqtoibu` binary(56) NOT NULL, `col_xiuoqstzzw` float(21));\nALTER TABLE `tb_mvpbukrobp` ADD COLUMN (`col_lzdzsmbdyf` tinyint(159) unsigned zerofill NULL, `col_jbqfyecqez` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') NOT NULL);\nALTER TABLE `tb_mvpbukrobp` ADD `col_fjxdpmowuy` mediumtext CHARACTER SET utf8mb4;\nALTER TABLE `tb_mvpbukrobp` ADD UNIQUE `uk_ckopkpiarf` (`col_oxgdbldyfk`,`col_sfpolurvqu`);\nALTER TABLE `tb_mvpbukrobp` ADD UNIQUE KEY `uk_nqultcfeau` (`col_ivdmwufhla`,`col_vpymqtoibu`(19));\nALTER TABLE `tb_mvpbukrobp` DROP COLUMN `col_ivdmwufhla`, DROP COLUMN `col_lzdzsmbdyf`;\nALTER TABLE `tb_mvpbukrobp` DROP `col_hnerbhuhmd`, DROP `col_sfpolurvqu`;\nALTER TABLE `tb_mvpbukrobp` DROP COLUMN `col_qeoodzhosh`;\nALTER TABLE `tb_mvpbukrobp` DROP COLUMN `col_xiuoqstzzw`;\nALTER TABLE `tb_mvpbukrobp` DROP `col_oxgdbldyfk`, DROP `col_vpymqtoibu`;\nALTER TABLE `tb_mvpbukrobp` DROP COLUMN `col_vfwrbmtwyi`;\nALTER TABLE `tb_mvpbukrobp` DROP `col_fjxdpmowuy`, DROP `col_owvaejsbfe`;\nALTER TABLE `tb_mvpbukrobp` DROP PRIMARY KEY;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_63.sql",
    "content": "CREATE TABLE `tb_rabcferkcm` (\n  `col_fflqfgfdyt` varchar(26) CHARACTER SET utf8mb4 NOT NULL DEFAULT ''\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_rabcferkcm` TO `tb_ayfynftwmh`;\nRENAME TABLE `tb_ayfynftwmh` TO `tb_eufiooviox`;\nRENAME TABLE `tb_eufiooviox` TO `tb_txslclddib`;\nALTER TABLE `tb_txslclddib` ADD COLUMN (`col_vkgmvcluzx` bigint unsigned zerofill NULL, `col_zssozexdev` mediumtext CHARACTER SET utf8);\nALTER TABLE `tb_txslclddib` ADD `col_yvgymfxalr` year NULL DEFAULT '2019' AFTER `col_fflqfgfdyt`;\nALTER TABLE `tb_txslclddib` ADD (`col_qjmexurrhz` mediumblob, `col_gileulcldv` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT 'enum_or_set_0');\nALTER TABLE `tb_txslclddib` ADD COLUMN `col_lzgdrufqst` blob(2902581366) AFTER `col_gileulcldv`;\nALTER TABLE `tb_txslclddib` ADD COLUMN (`col_outygtpgyl` numeric(49) NULL, `col_wdxmmljumj` numeric(35));\nALTER TABLE `tb_txslclddib` ADD `col_whoyzvbsui` binary(117) FIRST;\nALTER TABLE `tb_txslclddib` ADD `col_pphxdgjxqs` timestamp;\nALTER TABLE `tb_txslclddib` ADD UNIQUE INDEX (`col_zssozexdev`(11),`col_qjmexurrhz`(14));\nALTER TABLE `tb_txslclddib` ADD UNIQUE INDEX `uk_uvxmxuhrsq` (`col_wdxmmljumj`,`col_pphxdgjxqs`);\nALTER TABLE `tb_txslclddib` ALTER `col_outygtpgyl` DROP DEFAULT;\nALTER TABLE `tb_txslclddib` CHANGE `col_qjmexurrhz` `col_wyitzglcmb` float NULL DEFAULT '1' AFTER `col_outygtpgyl`;\nALTER TABLE `tb_txslclddib` CHANGE `col_gileulcldv` `col_mnviktcwsx` blob;\nALTER TABLE `tb_txslclddib` CHANGE COLUMN `col_wyitzglcmb` `col_prvpzaqcny` integer zerofill;\nALTER TABLE `tb_txslclddib` DROP `col_wdxmmljumj`;\nALTER TABLE `tb_txslclddib` DROP COLUMN `col_pphxdgjxqs`, DROP COLUMN `col_lzgdrufqst`;\nALTER TABLE `tb_txslclddib` DROP `col_outygtpgyl`;\nALTER TABLE `tb_txslclddib` DROP `col_zssozexdev`;\nALTER TABLE `tb_txslclddib` DROP `col_whoyzvbsui`, DROP `col_prvpzaqcny`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_64.sql",
    "content": "CREATE TABLE `tb_vyhepkdocw` (\n  `col_yqmzdxesrj` timestamp(0) NULL,\n  `col_kraxstptzi` varbinary(174),\n  `col_lvqcegncth` mediumblob,\n  `col_slupqsxneh` numeric(14),\n  UNIQUE KEY `uk_wqvouqksra` (`col_lvqcegncth`(8)),\n  UNIQUE KEY `col_slupqsxneh` (`col_slupqsxneh`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_pektpgbgcx` LIKE `tb_vyhepkdocw`;\nCREATE TABLE `tb_zeqwdifiwa` (\n  `col_wovlphbjrk` text(2969615453) CHARACTER SET utf8 COLLATE utf8_unicode_ci,\n  UNIQUE INDEX `uk_eohdfnqdmx` (`col_wovlphbjrk`(28))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_zeqwdifiwa` TO `tb_mwiswycksv`;\nRENAME TABLE `tb_mwiswycksv` TO `tb_kzlrbhxfpu`;\nDROP TABLE tb_pektpgbgcx, tb_kzlrbhxfpu;\nALTER TABLE `tb_vyhepkdocw` ADD `col_chvhleyulg` tinytext;\nALTER TABLE `tb_vyhepkdocw` ADD COLUMN `col_onhyboljxa` date NULL AFTER `col_lvqcegncth`;\nALTER TABLE `tb_vyhepkdocw` ADD (`col_getqnnhjry` date NULL, `col_dlomfzxpjh` mediumblob);\nALTER TABLE `tb_vyhepkdocw` ADD COLUMN `col_ahjuyzjbhk` bit AFTER `col_getqnnhjry`;\nALTER TABLE `tb_vyhepkdocw` ADD COLUMN (`col_hqbuexxcxl` bit, `col_mhqjuefjec` binary(213));\nALTER TABLE `tb_vyhepkdocw` ADD COLUMN (`col_daemlskcfa` double, `col_ewudcirsqc` tinyblob);\nALTER TABLE `tb_vyhepkdocw` ADD UNIQUE `col_daemlskcfa`(`col_onhyboljxa`,`col_slupqsxneh`);\nALTER TABLE `tb_vyhepkdocw` DROP `col_lvqcegncth`;\nALTER TABLE `tb_vyhepkdocw` DROP COLUMN `col_kraxstptzi`, DROP COLUMN `col_ewudcirsqc`;\nALTER TABLE `tb_vyhepkdocw` DROP COLUMN `col_hqbuexxcxl`;\nALTER TABLE `tb_vyhepkdocw` DROP `col_mhqjuefjec`;\nALTER TABLE `tb_vyhepkdocw` DROP `col_onhyboljxa`;\nALTER TABLE `tb_vyhepkdocw` DROP COLUMN `col_dlomfzxpjh`;\nALTER TABLE `tb_vyhepkdocw` DROP KEY `col_daemlskcfa`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_65.sql",
    "content": "CREATE TABLE `tb_vsqjzkimwi` (\n  `col_dyxnwiudqo` mediumtext CHARACTER SET utf8 COLLATE utf8_unicode_ci,\n  `col_savmueldgi` blob(950926319),\n  `col_gzatpknajd` float DEFAULT '1',\n  `col_ebfnpjymeg` tinytext CHARACTER SET utf8mb4,\n  UNIQUE `uk_iortgxjkuc` (`col_savmueldgi`(3))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_pdtvascuyy` (\n  `col_sbuommslma` timestamp(3) DEFAULT CURRENT_TIMESTAMP(3),\n  `col_corovzewna` date NULL DEFAULT '2019-07-04',\n  UNIQUE KEY `col_sbuommslma` (`col_sbuommslma`),\n  UNIQUE INDEX `col_sbuommslma_2` (`col_sbuommslma`)\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_pdtvascuyy` TO `tb_rnradhkfon`, `tb_vsqjzkimwi` TO `tb_ambgylvzkp`;\nALTER TABLE `tb_ambgylvzkp` ADD (`col_dlbzhcqiqy` mediumint(77) unsigned zerofill, `col_siqozvxhgs` set('enum_or_set_0','enum_or_set_1','enum_or_set_2'));\nALTER TABLE `tb_ambgylvzkp` ADD COLUMN (`col_llpqomujks` varchar(24) NOT NULL DEFAULT '', `col_xkicftbwbg` mediumtext);\nALTER TABLE `tb_ambgylvzkp` ADD COLUMN (`col_dkjrphxpni` bit(4), `col_gbegrurwao` year(4) NOT NULL DEFAULT '2019');\nALTER TABLE `tb_ambgylvzkp` ADD COLUMN `col_xsgbuhbqwd` mediumblob AFTER `col_ebfnpjymeg`;\nALTER TABLE `tb_ambgylvzkp` ADD (`col_ubwwasrhlw` tinyblob, `col_uetuxzylgb` integer unsigned zerofill NOT NULL);\nALTER TABLE `tb_ambgylvzkp` ADD COLUMN (`col_bbyekxjypk` bigint(195) unsigned zerofill NULL, `col_eeieaubbdp` numeric(12));\nALTER TABLE `tb_ambgylvzkp` ADD COLUMN `col_smbnzspzed` date NULL AFTER `col_savmueldgi`;\nALTER TABLE `tb_ambgylvzkp` ADD COLUMN `col_nzhjdxjqxl` blob AFTER `col_dkjrphxpni`;\nALTER TABLE `tb_ambgylvzkp` ADD COLUMN (`col_dwnlzyhikn` char(158), `col_evvhlyienk` char(172) CHARACTER SET utf8mb4 NULL);\nALTER TABLE `tb_ambgylvzkp` CHARACTER SET utf8;\nALTER TABLE `tb_ambgylvzkp` ADD PRIMARY KEY (`col_llpqomujks`,`col_gbegrurwao`);\nALTER TABLE `tb_ambgylvzkp` ADD UNIQUE (`col_gbegrurwao`,`col_ubwwasrhlw`(19));\nALTER TABLE `tb_ambgylvzkp` ADD UNIQUE KEY `uk_mvcfpncfde` (`col_xkicftbwbg`(17),`col_gbegrurwao`);\nALTER TABLE `tb_ambgylvzkp` CHANGE COLUMN `col_uetuxzylgb` `col_lhhoxkkbgt` char FIRST;\nALTER TABLE `tb_ambgylvzkp` CHANGE COLUMN `col_gbegrurwao` `col_nkvjzenagy` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NOT NULL;\nALTER TABLE `tb_ambgylvzkp` DROP COLUMN `col_dlbzhcqiqy`, DROP COLUMN `col_siqozvxhgs`;\nALTER TABLE `tb_ambgylvzkp` DROP COLUMN `col_nzhjdxjqxl`, DROP COLUMN `col_gzatpknajd`;\nALTER TABLE `tb_ambgylvzkp` DROP COLUMN `col_xsgbuhbqwd`;\nALTER TABLE `tb_ambgylvzkp` DROP `col_savmueldgi`, DROP `col_ubwwasrhlw`;\nALTER TABLE `tb_ambgylvzkp` DROP COLUMN `col_bbyekxjypk`;\nALTER TABLE `tb_ambgylvzkp` DROP COLUMN `col_dkjrphxpni`, DROP COLUMN `col_dyxnwiudqo`;\nALTER TABLE `tb_ambgylvzkp` DROP COLUMN `col_dwnlzyhikn`;\nALTER TABLE `tb_ambgylvzkp` DROP `col_nkvjzenagy`, DROP `col_lhhoxkkbgt`;\nALTER TABLE `tb_ambgylvzkp` DROP COLUMN `col_xkicftbwbg`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_66.sql",
    "content": "CREATE TABLE `tb_ijmcdmzknr` (\n  `col_pqnfhpfywv` datetime DEFAULT '2019-07-04 00:00:00',\n  `col_mlpkfxnbfa` blob,\n  UNIQUE `uk_ctetrugpen` (`col_mlpkfxnbfa`(8)),\n  UNIQUE KEY `col_mlpkfxnbfa` (`col_mlpkfxnbfa`(23))\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_ijmcdmzknr` TO `tb_mzqlybwqbo`;\nRENAME TABLE `tb_mzqlybwqbo` TO `tb_gnbqbndsaw`;\nALTER TABLE `tb_gnbqbndsaw` ADD (`col_gpjsqkkxse` integer unsigned NULL DEFAULT '1', `col_gmjtupvuvl` text(644744023));\nALTER TABLE `tb_gnbqbndsaw` ADD UNIQUE INDEX `uk_cbwijpiehr` (`col_pqnfhpfywv`,`col_gpjsqkkxse`);\nALTER TABLE `tb_gnbqbndsaw` ADD UNIQUE (`col_mlpkfxnbfa`(18));\nALTER TABLE `tb_gnbqbndsaw` DROP `col_gpjsqkkxse`;\nALTER TABLE `tb_gnbqbndsaw` DROP COLUMN `col_mlpkfxnbfa`, DROP COLUMN `col_gmjtupvuvl`;\nALTER TABLE `tb_gnbqbndsaw` DROP KEY `uk_cbwijpiehr`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_67.sql",
    "content": "CREATE TABLE `tb_mfgvnrsvmu` (\n  `col_bmbjupfwey` longblob,\n  `col_zlboqlzvrz` binary(0) NOT NULL,\n  `col_nxhonchgtt` bit NOT NULL,\n  `col_wituskplcw` year(4) DEFAULT '2019',\n  PRIMARY KEY (`col_nxhonchgtt`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_mfgvnrsvmu` TO `tb_psaessavwh`;\nRENAME TABLE `tb_psaessavwh` TO `tb_pgqtfhwbzc`;\nRENAME TABLE `tb_pgqtfhwbzc` TO `tb_wzvjzesyqu`;\nALTER TABLE `tb_wzvjzesyqu` ADD `col_gsgnhbocxa` date NOT NULL DEFAULT '2019-07-04' FIRST;\nALTER TABLE `tb_wzvjzesyqu` ADD `col_buaiwekzno` float DEFAULT '1' FIRST;\nALTER TABLE `tb_wzvjzesyqu` DEFAULT CHARACTER SET = utf8;\nALTER TABLE `tb_wzvjzesyqu` ALTER `col_nxhonchgtt` DROP DEFAULT;\nALTER TABLE `tb_wzvjzesyqu` ALTER COLUMN `col_gsgnhbocxa` DROP DEFAULT;\nALTER TABLE `tb_wzvjzesyqu` ALTER COLUMN `col_gsgnhbocxa` DROP DEFAULT;\nALTER TABLE `tb_wzvjzesyqu` DROP `col_bmbjupfwey`;\nALTER TABLE `tb_wzvjzesyqu` DROP COLUMN `col_gsgnhbocxa`, DROP COLUMN `col_wituskplcw`;\nALTER TABLE `tb_wzvjzesyqu` DROP `col_nxhonchgtt`, DROP `col_buaiwekzno`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_68.sql",
    "content": "CREATE TABLE `tb_febzciaoij` (\n  `col_cchheryffd` mediumint unsigned NULL,\n  `col_emlschxjrp` mediumblob,\n  `col_qjiterpuli` binary(101),\n  `col_icnjklhceu` numeric(12) NOT NULL,\n  CONSTRAINT PRIMARY KEY (`col_icnjklhceu`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_vmghxdnngw` (\n  `col_qbfketzeju` smallint(77),\n  `col_xwdguyhvwy` bit NULL DEFAULT b'0'\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_xyqwqnvfml` (\n  `col_bfzzufqfye` tinyint(197) zerofill,\n  UNIQUE `uk_hpymxvxhzj` (`col_bfzzufqfye`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_xyqwqnvfml` TO `tb_gfcldozzsj`;\nDROP TABLE tb_gfcldozzsj, tb_febzciaoij;\nALTER TABLE `tb_vmghxdnngw` ADD `col_mhpxueotyg` year(4) NULL FIRST;\nALTER TABLE `tb_vmghxdnngw` ADD (`col_mrbemxbmct` numeric(30), `col_yugqsxovwb` timestamp(2) NULL);\nALTER TABLE `tb_vmghxdnngw` CHARACTER SET = utf8mb4;\nALTER TABLE `tb_vmghxdnngw` ALTER COLUMN `col_xwdguyhvwy` SET DEFAULT b'0';\nALTER TABLE `tb_vmghxdnngw` ALTER `col_mhpxueotyg` DROP DEFAULT;\nALTER TABLE `tb_vmghxdnngw` CHANGE COLUMN `col_qbfketzeju` `col_jwubgoycad` decimal(7,4) NOT NULL AFTER `col_xwdguyhvwy`;\nALTER TABLE `tb_vmghxdnngw` CHANGE `col_jwubgoycad` `col_cuofmwfcxy` tinytext;\nALTER TABLE `tb_vmghxdnngw` CHANGE `col_xwdguyhvwy` `col_itolrjernl` bit(57) NULL AFTER `col_yugqsxovwb`;\nALTER TABLE `tb_vmghxdnngw` DROP `col_mrbemxbmct`, DROP `col_itolrjernl`;\nALTER TABLE `tb_vmghxdnngw` DROP COLUMN `col_yugqsxovwb`, DROP COLUMN `col_mhpxueotyg`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_69.sql",
    "content": "CREATE TABLE `tb_iuqrkykntm` (\n  `col_vqbxwxbdco` float(53) NULL,\n  `col_axuvjogcci` datetime DEFAULT '2019-07-04 00:00:00',\n  `col_rrrdiozgxi` mediumtext CHARACTER SET latin1,\n  `col_hjaoyhupuv` varchar(176) CHARACTER SET utf8 COLLATE utf8_unicode_ci,\n  UNIQUE `col_rrrdiozgxi` (`col_rrrdiozgxi`(23)),\n  UNIQUE KEY `uk_gscqcjtlyg` (`col_hjaoyhupuv`(13))\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_fkndvyyooo` LIKE `tb_iuqrkykntm`;\nRENAME TABLE `tb_iuqrkykntm` TO `tb_gwhacmapbj`;\nRENAME TABLE `tb_gwhacmapbj` TO `tb_havvvaohnr`;\nRENAME TABLE `tb_havvvaohnr` TO `tb_nduadhjfex`;\nDROP TABLE tb_nduadhjfex, tb_fkndvyyooo;\nCREATE TABLE `tb_tilukdjjhc` (\n  `col_kxelvjyosf` int(150),\n  `col_laleouwpiw` int NOT NULL DEFAULT '1',\n  PRIMARY KEY (`col_laleouwpiw`),\n  UNIQUE `uk_hkgebfxhma` (`col_kxelvjyosf`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nALTER TABLE `tb_tilukdjjhc` ADD `col_fgidnnqvqm` year NOT NULL;\nALTER TABLE `tb_tilukdjjhc` ADD COLUMN `col_loxvzbzvge` char CHARACTER SET utf8 NULL AFTER `col_kxelvjyosf`;\nALTER TABLE `tb_tilukdjjhc` ADD COLUMN (`col_uzxvkpgggz` mediumblob, `col_gqssffnbgo` tinyblob);\nALTER TABLE `tb_tilukdjjhc` ADD `col_jtyftybbku` decimal(13,5) NOT NULL AFTER `col_uzxvkpgggz`;\nALTER TABLE `tb_tilukdjjhc` ADD COLUMN `col_drlfahzqxk` datetime(4) NOT NULL;\nALTER TABLE `tb_tilukdjjhc` ADD (`col_bzzxemkcuj` double, `col_olnmovdyfw` bit(3) NULL DEFAULT b'0');\nALTER TABLE `tb_tilukdjjhc` ADD COLUMN `col_avfiwopsik` float;\nALTER TABLE `tb_tilukdjjhc` DEFAULT CHARACTER SET utf8mb4;\nALTER TABLE `tb_tilukdjjhc` ALTER COLUMN `col_bzzxemkcuj` DROP DEFAULT;\nALTER TABLE `tb_tilukdjjhc` CHANGE COLUMN `col_gqssffnbgo` `col_pmqkhijpcr` varbinary(71) NULL DEFAULT '\\0' AFTER `col_fgidnnqvqm`;\nALTER TABLE `tb_tilukdjjhc` CHANGE `col_drlfahzqxk` `col_idhlrzdwud` char CHARACTER SET utf8 NOT NULL AFTER `col_avfiwopsik`;\nALTER TABLE `tb_tilukdjjhc` CHANGE COLUMN `col_avfiwopsik` `col_kcysycgbek` blob(2086586212);\nALTER TABLE `tb_tilukdjjhc` DROP COLUMN `col_bzzxemkcuj`;\nALTER TABLE `tb_tilukdjjhc` DROP PRIMARY KEY;\nALTER TABLE `tb_tilukdjjhc` DROP KEY `uk_hkgebfxhma`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_7.sql",
    "content": "CREATE TABLE `tb_edzrjofyjy` (\n  `col_ryuwsvbvzl` longblob,\n  `col_hqgbphjulh` timestamp\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_edzrjofyjy` TO `tb_dhnyjpcqwn`;\nRENAME TABLE `tb_dhnyjpcqwn` TO `tb_pdshedxikd`;\nRENAME TABLE `tb_pdshedxikd` TO `tb_nuprsugtcj`;\nALTER TABLE `tb_nuprsugtcj` ADD `col_ezppromjmx` int(120) unsigned zerofill NULL;\nALTER TABLE `tb_nuprsugtcj` ADD COLUMN (`col_qwsjkklpfs` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NULL DEFAULT 'enum_or_set_0', `col_iyhhfsuidc` double);\nALTER TABLE `tb_nuprsugtcj` DEFAULT CHARACTER SET utf8mb4;\nALTER TABLE `tb_nuprsugtcj` ADD UNIQUE KEY (`col_iyhhfsuidc`);\nALTER TABLE `tb_nuprsugtcj` ADD UNIQUE KEY `uk_mmyhqwqrpg` (`col_ezppromjmx`);\nALTER TABLE `tb_nuprsugtcj` ALTER COLUMN `col_qwsjkklpfs` SET DEFAULT NULL;\nALTER TABLE `tb_nuprsugtcj` ALTER COLUMN `col_qwsjkklpfs` DROP DEFAULT;\nALTER TABLE `tb_nuprsugtcj` CHANGE COLUMN `col_ryuwsvbvzl` `col_yxvzojfrof` smallint(39) DEFAULT '1' FIRST;\nALTER TABLE `tb_nuprsugtcj` DROP COLUMN `col_iyhhfsuidc`, DROP COLUMN `col_hqgbphjulh`;\nALTER TABLE `tb_nuprsugtcj` DROP COLUMN `col_yxvzojfrof`, DROP COLUMN `col_ezppromjmx`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_70.sql",
    "content": "CREATE TABLE `tb_mfkmsjoicz` (\n  `col_wgoqxgzaqj` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 DEFAULT 'enum_or_set_0',\n  `col_fdlnxqretm` tinyblob,\n  UNIQUE INDEX `uk_qvzxxvonmt` (`col_wgoqxgzaqj`),\n  UNIQUE INDEX `col_wgoqxgzaqj` (`col_wgoqxgzaqj`)\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_mfkmsjoicz` TO `tb_cqcpkwgqnw`;\nRENAME TABLE `tb_cqcpkwgqnw` TO `tb_wqthgwmnob`;\nALTER TABLE `tb_wqthgwmnob` ADD `col_ekbblvxoft` longblob;\nALTER TABLE `tb_wqthgwmnob` ADD COLUMN `col_lgwmegdicv` date NULL DEFAULT '2019-07-04';\nALTER TABLE `tb_wqthgwmnob` CHANGE `col_fdlnxqretm` `col_zfwcxazxyk` bit NOT NULL DEFAULT b'0';\nALTER TABLE `tb_wqthgwmnob` CHANGE `col_lgwmegdicv` `col_enozfpzijr` date;\nALTER TABLE `tb_wqthgwmnob` DROP `col_zfwcxazxyk`;\nALTER TABLE `tb_wqthgwmnob` DROP `col_ekbblvxoft`;\nALTER TABLE `tb_wqthgwmnob` DROP `col_wgoqxgzaqj`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_71.sql",
    "content": "CREATE TABLE `tb_wviibzdwnl` (\n  `col_aslaluhepd` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 DEFAULT 'enum_or_set_0',\n  `col_aqelxtcidu` numeric NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_wviibzdwnl` TO `tb_sfwkwlflbi`;\nALTER TABLE `tb_sfwkwlflbi` ADD COLUMN `col_zblksizcse` blob AFTER `col_aqelxtcidu`;\nALTER TABLE `tb_sfwkwlflbi` ADD COLUMN (`col_ezxxxqpwon` time(2) NULL, `col_wryzwhfdap` mediumtext CHARACTER SET utf8 COLLATE utf8_unicode_ci);\nALTER TABLE `tb_sfwkwlflbi` DEFAULT CHARACTER SET utf8;\nALTER TABLE `tb_sfwkwlflbi` ADD UNIQUE KEY `uk_odmbvgzhkr` (`col_zblksizcse`(18),`col_ezxxxqpwon`);\nALTER TABLE `tb_sfwkwlflbi` CHANGE COLUMN `col_aqelxtcidu` `col_scvucmvmtf` float(38) FIRST;\nALTER TABLE `tb_sfwkwlflbi` CHANGE `col_ezxxxqpwon` `col_xvqalfjvnx` decimal DEFAULT '1' FIRST;\nALTER TABLE `tb_sfwkwlflbi` DROP COLUMN `col_aslaluhepd`;\nALTER TABLE `tb_sfwkwlflbi` DROP COLUMN `col_zblksizcse`, DROP COLUMN `col_scvucmvmtf`;\nALTER TABLE `tb_sfwkwlflbi` DROP COLUMN `col_xvqalfjvnx`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_72.sql",
    "content": "CREATE TABLE `tb_ybomzxquze` (\n  `col_xjawafguvi` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NULL,\n  `col_juwaxfpier` longblob,\n  `col_xnhktpwgoy` tinyblob,\n  `col_sfflidbosv` timestamp(2) NULL,\n  UNIQUE INDEX `col_xjawafguvi` (`col_xjawafguvi`),\n  UNIQUE `uk_tlmnsowqus` (`col_sfflidbosv`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_ybomzxquze` TO `tb_cugzkpefkt`;\nALTER TABLE `tb_cugzkpefkt` ADD (`col_vmjyaetcdt` text(3199621179), `col_qstgsvuago` mediumtext CHARACTER SET utf8mb4);\nALTER TABLE `tb_cugzkpefkt` ADD (`col_noqqlolqsk` blob(1755778528), `col_gyittdjhfg` numeric);\nALTER TABLE `tb_cugzkpefkt` CHARACTER SET utf8;\nALTER TABLE `tb_cugzkpefkt` ADD UNIQUE KEY `uk_anpzhhtomg` (`col_xjawafguvi`,`col_xnhktpwgoy`(16));\nALTER TABLE `tb_cugzkpefkt` ADD UNIQUE INDEX (`col_vmjyaetcdt`(29),`col_qstgsvuago`(1));\nALTER TABLE `tb_cugzkpefkt` DROP `col_juwaxfpier`, DROP `col_qstgsvuago`;\nALTER TABLE `tb_cugzkpefkt` DROP `col_xjawafguvi`;\nALTER TABLE `tb_cugzkpefkt` DROP `col_sfflidbosv`;\nALTER TABLE `tb_cugzkpefkt` DROP COLUMN `col_gyittdjhfg`;\nALTER TABLE `tb_cugzkpefkt` DROP COLUMN `col_vmjyaetcdt`;\nALTER TABLE `tb_cugzkpefkt` DROP `col_noqqlolqsk`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_73.sql",
    "content": "CREATE TABLE `tb_upzbnfzylo` (\n  `col_dppomywdgn` tinyblob,\n  `col_hybjpvnihc` mediumblob,\n  `col_nvqsfunmve` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 DEFAULT 'enum_or_set_0',\n  `col_rvwyvmeidf` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 NOT NULL DEFAULT 'enum_or_set_0',\n  CONSTRAINT PRIMARY KEY (`col_rvwyvmeidf`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_tfimbaoajc` LIKE `tb_upzbnfzylo`;\nCREATE TABLE `tb_hovvshypke` (\n  `col_psutzipcit` integer(29) zerofill,\n  UNIQUE INDEX `col_psutzipcit` (`col_psutzipcit`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_hovvshypke` TO `tb_zixkylluol`, `tb_tfimbaoajc` TO `tb_rmmpcdzkft`;\nALTER TABLE `tb_zixkylluol` ADD COLUMN `col_iwtkwazsiv` time NULL DEFAULT '00:00:00' AFTER `col_psutzipcit`;\nALTER TABLE `tb_zixkylluol` ADD COLUMN `col_cqbtbuqstu` smallint unsigned;\nALTER TABLE `tb_zixkylluol` DEFAULT CHARACTER SET utf8mb4;\nALTER TABLE `tb_zixkylluol` ALTER COLUMN `col_psutzipcit` DROP DEFAULT;\nALTER TABLE `tb_zixkylluol` ALTER `col_psutzipcit` DROP DEFAULT;\nALTER TABLE `tb_zixkylluol` DROP `col_cqbtbuqstu`, DROP `col_iwtkwazsiv`;\nALTER TABLE `tb_zixkylluol` DROP KEY `col_psutzipcit`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_74.sql",
    "content": "CREATE TABLE `tb_ukcldpswkg` (\n  `col_slkmwynegf` integer(250) unsigned zerofill NULL,\n  `col_cjsmvrdiur` bit,\n  `col_prxndrinom` integer unsigned DEFAULT '1',\n  `col_kihpmvmflx` double,\n  UNIQUE `col_prxndrinom` (`col_prxndrinom`),\n  UNIQUE `col_slkmwynegf` (`col_slkmwynegf`,`col_cjsmvrdiur`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_rxvmngvuko` (\n  `col_vabvvfkcss` integer unsigned NULL,\n  `col_sedpeihgba` bit DEFAULT b'0',\n  `col_pjbwfuvwmj` binary(254) NULL,\n  UNIQUE `uk_oqxlgofciy` (`col_pjbwfuvwmj`(31))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_ukcldpswkg` TO `tb_kifaamclft`;\nRENAME TABLE `tb_rxvmngvuko` TO `tb_jfcolfofka`;\nDROP TABLE tb_jfcolfofka, tb_kifaamclft;\nCREATE TABLE `tb_tazkjnlgrx` (\n  `col_tbjrxivrjg` blob\n) DEFAULT CHARSET=utf8;\nALTER TABLE `tb_tazkjnlgrx` ADD (`col_fuqpghhcyy` float, `col_sbwclfupup` binary NULL);\nALTER TABLE `tb_tazkjnlgrx` ADD COLUMN (`col_bmyrokxows` time(4), `col_jxosxbunsc` double(179,7) NULL);\nALTER TABLE `tb_tazkjnlgrx` ADD COLUMN `col_trhadxfbfi` numeric FIRST;\nALTER TABLE `tb_tazkjnlgrx` ADD COLUMN `col_jijmncnsoa` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT 'enum_or_set_0';\nALTER TABLE `tb_tazkjnlgrx` ADD COLUMN `col_ucszyswhkc` bigint zerofill;\nALTER TABLE `tb_tazkjnlgrx` ADD COLUMN `col_fbxbftvxcl` smallint(14) zerofill;\nALTER TABLE `tb_tazkjnlgrx` ADD (`col_vbsyfqxqng` mediumblob, `col_ktnctyhcvl` blob);\nALTER TABLE `tb_tazkjnlgrx` ADD COLUMN `col_pbgxpvfusq` tinyblob AFTER `col_fbxbftvxcl`;\nALTER TABLE `tb_tazkjnlgrx` ADD COLUMN `col_ewzdxvnlrs` bit NOT NULL DEFAULT b'0' FIRST;\nALTER TABLE `tb_tazkjnlgrx` ADD PRIMARY KEY (`col_ewzdxvnlrs`);\nALTER TABLE `tb_tazkjnlgrx` ADD UNIQUE KEY `uk_ygarqhlsva` (`col_tbjrxivrjg`(5),`col_jxosxbunsc`);\nALTER TABLE `tb_tazkjnlgrx` CHANGE `col_pbgxpvfusq` `col_pgtqyvckbi` time;\nALTER TABLE `tb_tazkjnlgrx` CHANGE `col_bmyrokxows` `col_gxpgglefyh` char(40) CHARACTER SET utf8mb4 NULL AFTER `col_ucszyswhkc`;\nALTER TABLE `tb_tazkjnlgrx` DROP COLUMN `col_ucszyswhkc`, DROP COLUMN `col_fuqpghhcyy`;\nALTER TABLE `tb_tazkjnlgrx` DROP `col_ktnctyhcvl`, DROP `col_fbxbftvxcl`;\nALTER TABLE `tb_tazkjnlgrx` DROP COLUMN `col_tbjrxivrjg`;\nALTER TABLE `tb_tazkjnlgrx` DROP COLUMN `col_sbwclfupup`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_75.sql",
    "content": "CREATE TABLE `tb_wumnowgbgm` (\n  `col_dxnkzlgbrh` text(3378091990) CHARACTER SET latin1,\n  `col_dbfjlhoypk` bit(27) NOT NULL,\n  `col_wzrdexqlrw` smallint unsigned NOT NULL,\n  `col_adfenvntyq` char CHARACTER SET utf8mb4,\n  CONSTRAINT symb_jmvitdlrbv PRIMARY KEY (`col_dbfjlhoypk`,`col_wzrdexqlrw`),\n  UNIQUE `uk_xoqexlvgan` (`col_adfenvntyq`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_xwnddbnhpl` LIKE `tb_wumnowgbgm`;\nCREATE TABLE `tb_efrfggoljv` (\n  `col_shpcvotegh` numeric(34),\n  `col_watvncqjsq` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 NULL DEFAULT 'enum_or_set_0',\n  `col_zycpbpgevt` longtext CHARACTER SET latin1,\n  UNIQUE `uk_jkvqqmmqwa` (`col_shpcvotegh`,`col_watvncqjsq`),\n  UNIQUE INDEX `col_zycpbpgevt` (`col_zycpbpgevt`(22))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_efrfggoljv` TO `tb_lznvphwjai`, `tb_wumnowgbgm` TO `tb_vinehxgnxe`;\nDROP TABLE tb_vinehxgnxe;\nDROP TABLE tb_lznvphwjai, tb_xwnddbnhpl;\nCREATE TABLE `tb_mpjfjmkbwn` (\n  `col_lyrrpdesag` bigint zerofill NULL,\n  `col_fehlmkpxfq` char CHARACTER SET latin1,\n  `col_sotvvevbho` year NULL DEFAULT '2019',\n  UNIQUE KEY `uk_odozsruufn` (`col_fehlmkpxfq`),\n  UNIQUE `col_lyrrpdesag` (`col_lyrrpdesag`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nALTER TABLE `tb_mpjfjmkbwn` ADD `col_eyzpohpkcl` integer zerofill NOT NULL AFTER `col_lyrrpdesag`;\nALTER TABLE `tb_mpjfjmkbwn` ADD (`col_kfcxjyhzkq` varchar(178), `col_khvbberyat` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') NOT NULL);\nALTER TABLE `tb_mpjfjmkbwn` ADD COLUMN `col_ximpbczbvl` longblob FIRST;\nALTER TABLE `tb_mpjfjmkbwn` DEFAULT CHARACTER SET = utf8mb4;\nALTER TABLE `tb_mpjfjmkbwn` CHANGE `col_kfcxjyhzkq` `col_bpzkjdwbex` char CHARACTER SET utf8 COLLATE utf8_unicode_ci AFTER `col_fehlmkpxfq`;\nALTER TABLE `tb_mpjfjmkbwn` CHANGE `col_sotvvevbho` `col_whykzkssvd` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') NULL DEFAULT 'enum_or_set_0';\nALTER TABLE `tb_mpjfjmkbwn` CHANGE `col_bpzkjdwbex` `col_oqfdewvoin` bigint unsigned;\nALTER TABLE `tb_mpjfjmkbwn` DROP `col_khvbberyat`;\nALTER TABLE `tb_mpjfjmkbwn` DROP COLUMN `col_whykzkssvd`;\nALTER TABLE `tb_mpjfjmkbwn` DROP `col_ximpbczbvl`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_76.sql",
    "content": "CREATE TABLE `tb_wbajtotdth` (\n  `col_lmpzmediez` int unsigned zerofill,\n  `col_nhckjelmwe` year,\n  `col_yvelqmjboo` varbinary(185) DEFAULT '\\0',\n  `col_uttbttlgkx` smallint(181) unsigned DEFAULT '1',\n  UNIQUE KEY `col_uttbttlgkx` (`col_uttbttlgkx`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_vrtkbtmnws` (\n  `col_iabzixqyhm` tinyblob,\n  `col_otoxjlwatj` date DEFAULT '2019-07-04',\n  UNIQUE KEY `col_otoxjlwatj` (`col_otoxjlwatj`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_wbajtotdth` TO `tb_bxtlrumrtn`, `tb_vrtkbtmnws` TO `tb_irclltefag`;\nALTER TABLE `tb_bxtlrumrtn` CHARACTER SET = utf8mb4;\nALTER TABLE `tb_bxtlrumrtn` ALTER `col_nhckjelmwe` DROP DEFAULT;\nALTER TABLE `tb_bxtlrumrtn` ALTER `col_uttbttlgkx` SET DEFAULT NULL;\nALTER TABLE `tb_bxtlrumrtn` CHANGE COLUMN `col_nhckjelmwe` `col_dgjkrbzltd` numeric(38,25) NOT NULL;\nALTER TABLE `tb_bxtlrumrtn` DROP `col_lmpzmediez`;\nALTER TABLE `tb_bxtlrumrtn` DROP `col_yvelqmjboo`, DROP `col_dgjkrbzltd`;\nALTER TABLE `tb_bxtlrumrtn` DROP INDEX `col_uttbttlgkx`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_77.sql",
    "content": "CREATE TABLE `tb_pwgqnfglhb` (\n  `col_iupsnmieyl` smallint unsigned NULL,\n  `col_gnkgsewitj` numeric DEFAULT '1',\n  `col_cvsykxnvpf` varchar(24) CHARACTER SET utf8 NULL DEFAULT '',\n  `col_xailqzhuwy` blob\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_zhhkhdmeqy` LIKE `tb_pwgqnfglhb`;\nRENAME TABLE `tb_pwgqnfglhb` TO `tb_igmuoxapjx`, `tb_zhhkhdmeqy` TO `tb_wmwynbzgyg`;\nALTER TABLE `tb_igmuoxapjx` DROP `col_xailqzhuwy`;\nALTER TABLE `tb_igmuoxapjx` DROP COLUMN `col_gnkgsewitj`, DROP COLUMN `col_iupsnmieyl`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_78.sql",
    "content": "CREATE TABLE `tb_fbpivvptsa` (\n  `col_hbauqbdefn` datetime,\n  UNIQUE KEY `uk_cxmeeaqnza` (`col_hbauqbdefn`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_fbpivvptsa` TO `tb_rtvtzkfcfx`;\nRENAME TABLE `tb_rtvtzkfcfx` TO `tb_cockfzvkou`;\nALTER TABLE `tb_cockfzvkou` ADD `col_unrdwzfczo` tinyblob AFTER `col_hbauqbdefn`;\nALTER TABLE `tb_cockfzvkou` CHARACTER SET = utf8;\nALTER TABLE `tb_cockfzvkou` ADD UNIQUE (`col_hbauqbdefn`,`col_unrdwzfczo`(7));\nALTER TABLE `tb_cockfzvkou` ADD UNIQUE (`col_hbauqbdefn`);\nALTER TABLE `tb_cockfzvkou` CHANGE COLUMN `col_hbauqbdefn` `col_atkczpjiqk` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') NOT NULL;\nALTER TABLE `tb_cockfzvkou` DROP `col_unrdwzfczo`;\nALTER TABLE `tb_cockfzvkou` DROP KEY `col_hbauqbdefn_2`;\nALTER TABLE `tb_cockfzvkou` DROP INDEX `col_hbauqbdefn`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_79.sql",
    "content": "CREATE TABLE `tb_dkdeujiqjf` (\n  `col_gwfnuyuami` mediumint zerofill,\n  `col_jzcpwtvvhi` numeric NOT NULL DEFAULT '1',\n  PRIMARY KEY (`col_jzcpwtvvhi`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_dkdeujiqjf` TO `tb_ehfacgfjnk`;\nRENAME TABLE `tb_ehfacgfjnk` TO `tb_zwzsaathnd`;\nALTER TABLE `tb_zwzsaathnd` ADD COLUMN `col_axigbojqvl` float(34);\nALTER TABLE `tb_zwzsaathnd` ADD COLUMN (`col_vcejogynpm` time NULL, `col_rxmvdbomhz` time);\nALTER TABLE `tb_zwzsaathnd` ADD COLUMN (`col_nrzmqslqws` mediumtext, `col_dseumehqur` tinyblob);\nALTER TABLE `tb_zwzsaathnd` ADD `col_ojaoqduwkj` date DEFAULT '2019-07-04' FIRST;\nALTER TABLE `tb_zwzsaathnd` ADD `col_rqumywduzu` time FIRST;\nALTER TABLE `tb_zwzsaathnd` ADD `col_xxmdywhgie` mediumint NULL;\nALTER TABLE `tb_zwzsaathnd` CHARACTER SET = utf8;\nALTER TABLE `tb_zwzsaathnd` ADD UNIQUE KEY `col_rqumywduzu`(`col_rqumywduzu`,`col_ojaoqduwkj`);\nALTER TABLE `tb_zwzsaathnd` ADD UNIQUE INDEX `col_dseumehqur`(`col_dseumehqur`(21),`col_xxmdywhgie`);\nALTER TABLE `tb_zwzsaathnd` ALTER COLUMN `col_rxmvdbomhz` SET DEFAULT NULL;\nALTER TABLE `tb_zwzsaathnd` DROP COLUMN `col_ojaoqduwkj`;\nALTER TABLE `tb_zwzsaathnd` DROP `col_rxmvdbomhz`;\nALTER TABLE `tb_zwzsaathnd` DROP COLUMN `col_nrzmqslqws`;\nALTER TABLE `tb_zwzsaathnd` DROP COLUMN `col_axigbojqvl`, DROP COLUMN `col_gwfnuyuami`;\nALTER TABLE `tb_zwzsaathnd` DROP PRIMARY KEY;\nALTER TABLE `tb_zwzsaathnd` DROP INDEX `col_rqumywduzu`;\nALTER TABLE `tb_zwzsaathnd` DROP KEY `col_dseumehqur`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_8.sql",
    "content": "CREATE TABLE `tb_fwnltgnpeg` (\n  `col_gzxmlukzgv` smallint(169) unsigned zerofill NOT NULL,\n  PRIMARY KEY (`col_gzxmlukzgv`),\n  UNIQUE INDEX `uk_gwlvlnvrkh` (`col_gzxmlukzgv`),\n  UNIQUE INDEX `uk_ygsnwxzroc` (`col_gzxmlukzgv`)\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_fwnltgnpeg` TO `tb_hmfoniytbf`;\nALTER TABLE `tb_hmfoniytbf` ADD COLUMN `col_gxqvwbkvyi` datetime(5);\nALTER TABLE `tb_hmfoniytbf` ADD COLUMN (`col_fthqvynbuq` mediumint unsigned zerofill, `col_dcxnatwddd` date DEFAULT '2019-07-04');\nALTER TABLE `tb_hmfoniytbf` ADD COLUMN `col_wvbemkrzdt` longtext CHARACTER SET utf8 COLLATE utf8_unicode_ci FIRST;\nALTER TABLE `tb_hmfoniytbf` ADD `col_alzezpawqi` longblob;\nALTER TABLE `tb_hmfoniytbf` ADD COLUMN `col_tpzhsbkmka` longtext;\nALTER TABLE `tb_hmfoniytbf` ADD COLUMN (`col_urfoabrjor` bit(15) NOT NULL, `col_xreorfbhxc` decimal(35) NULL);\nALTER TABLE `tb_hmfoniytbf` DEFAULT CHARACTER SET utf8;\nALTER TABLE `tb_hmfoniytbf` ADD UNIQUE INDEX `uk_ztdbxlchxi` (`col_alzezpawqi`(18),`col_tpzhsbkmka`(30));\nALTER TABLE `tb_hmfoniytbf` ALTER COLUMN `col_dcxnatwddd` DROP DEFAULT;\nALTER TABLE `tb_hmfoniytbf` DROP COLUMN `col_tpzhsbkmka`, DROP COLUMN `col_dcxnatwddd`;\nALTER TABLE `tb_hmfoniytbf` DROP `col_alzezpawqi`, DROP `col_wvbemkrzdt`;\nALTER TABLE `tb_hmfoniytbf` DROP `col_gzxmlukzgv`, DROP `col_xreorfbhxc`;\nALTER TABLE `tb_hmfoniytbf` DROP `col_gxqvwbkvyi`, DROP `col_fthqvynbuq`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_80.sql",
    "content": "CREATE TABLE `tb_tmotlxzrja` (\n  `col_uesfklwmsk` date DEFAULT '2019-07-04',\n  `col_zskjzqcxkk` varbinary(218) DEFAULT '\\0',\n  `col_rvztkthbca` time(6) NULL,\n  `col_mpmkktdhop` mediumblob,\n  UNIQUE `col_rvztkthbca` (`col_rvztkthbca`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_plneggfdkn` (\n  `col_zzhxpptdgq` longblob,\n  UNIQUE INDEX `uk_voojzaxmwk` (`col_zzhxpptdgq`(21))\n) DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_plneggfdkn` TO `tb_ctvykdvyzx`;\nRENAME TABLE `tb_ctvykdvyzx` TO `tb_amkojtlotu`;\nALTER TABLE `tb_tmotlxzrja` ADD COLUMN `col_kqarzddnnt` date;\nALTER TABLE `tb_tmotlxzrja` ADD `col_tgjhdvpopd` year;\nALTER TABLE `tb_tmotlxzrja` ADD COLUMN (`col_buqqlqfgsv` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') NULL DEFAULT 'enum_or_set_0', `col_erywvwybme` int(13) NULL DEFAULT '1');\nALTER TABLE `tb_tmotlxzrja` ADD COLUMN (`col_glrqptmjgp` varbinary(172), `col_lxemzphwpr` tinyblob);\nALTER TABLE `tb_tmotlxzrja` ADD COLUMN `col_nytimponye` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') NOT NULL;\nALTER TABLE `tb_tmotlxzrja` ADD `col_dmorocleic` numeric NULL;\nALTER TABLE `tb_tmotlxzrja` ADD COLUMN (`col_soiyoovkol` char CHARACTER SET utf8mb4 NULL, `col_kpuqcxwuvq` char NOT NULL);\nALTER TABLE `tb_tmotlxzrja` ADD `col_wppxtgrjdz` tinyblob;\nALTER TABLE `tb_tmotlxzrja` ALTER COLUMN `col_uesfklwmsk` SET DEFAULT '2019-07-04';\nALTER TABLE `tb_tmotlxzrja` DROP COLUMN `col_kpuqcxwuvq`;\nALTER TABLE `tb_tmotlxzrja` DROP `col_lxemzphwpr`;\nALTER TABLE `tb_tmotlxzrja` DROP `col_dmorocleic`;\nALTER TABLE `tb_tmotlxzrja` DROP COLUMN `col_nytimponye`;\nALTER TABLE `tb_tmotlxzrja` DROP `col_buqqlqfgsv`, DROP `col_kqarzddnnt`;\nALTER TABLE `tb_tmotlxzrja` DROP KEY `col_rvztkthbca`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/alter/test_9.sql",
    "content": "CREATE TABLE `tb_walklosuks` (\n  `col_lxbxpuuwyo` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 COLLATE utf8_unicode_ci,\n  `col_rtbkufevvv` smallint zerofill\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_walklosuks` TO `tb_mkeptukxss`;\nRENAME TABLE `tb_mkeptukxss` TO `tb_sqndbrgkvj`;\nALTER TABLE `tb_sqndbrgkvj` ADD (`col_xuafealoty` float, `col_durclethxo` smallint);\nALTER TABLE `tb_sqndbrgkvj` ADD `col_plylqkvjll` time(5);\nALTER TABLE `tb_sqndbrgkvj` ADD COLUMN `col_erbwiiktwe` integer zerofill NULL FIRST;\nALTER TABLE `tb_sqndbrgkvj` ADD (`col_pymdrmukax` float(32), `col_zamcrcjxwy` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT 'enum_or_set_0');\nALTER TABLE `tb_sqndbrgkvj` ADD COLUMN (`col_twjprfcscz` tinytext CHARACTER SET utf8 COLLATE utf8_unicode_ci, `col_zuurdmqnmy` tinytext CHARACTER SET utf8mb4);\nALTER TABLE `tb_sqndbrgkvj` ADD `col_mueqvldinf` integer unsigned DEFAULT '1' FIRST;\nALTER TABLE `tb_sqndbrgkvj` ADD `col_prvruzvlqp` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL;\nALTER TABLE `tb_sqndbrgkvj` ADD COLUMN `col_bujrefmxrj` bit(35) AFTER `col_xuafealoty`;\nALTER TABLE `tb_sqndbrgkvj` CHARACTER SET utf8mb4;\nALTER TABLE `tb_sqndbrgkvj` ADD CONSTRAINT symb_uyzanxlotu PRIMARY KEY (`col_prvruzvlqp`);\nALTER TABLE `tb_sqndbrgkvj` ADD UNIQUE INDEX (`col_plylqkvjll`,`col_pymdrmukax`);\nALTER TABLE `tb_sqndbrgkvj` ADD UNIQUE KEY `col_rtbkufevvv`(`col_rtbkufevvv`,`col_bujrefmxrj`);\nALTER TABLE `tb_sqndbrgkvj` CHANGE `col_durclethxo` `col_sgkaxgwwff` tinyint(123) NOT NULL AFTER `col_lxbxpuuwyo`;\nALTER TABLE `tb_sqndbrgkvj` DROP `col_zamcrcjxwy`;\nALTER TABLE `tb_sqndbrgkvj` DROP `col_bujrefmxrj`;\nALTER TABLE `tb_sqndbrgkvj` DROP COLUMN `col_sgkaxgwwff`;\nALTER TABLE `tb_sqndbrgkvj` DROP `col_erbwiiktwe`, DROP `col_zuurdmqnmy`;\nALTER TABLE `tb_sqndbrgkvj` DROP COLUMN `col_twjprfcscz`, DROP COLUMN `col_lxbxpuuwyo`;\nALTER TABLE `tb_sqndbrgkvj` DROP PRIMARY KEY;\nALTER TABLE `tb_sqndbrgkvj` DROP KEY `col_rtbkufevvv`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/create.sql",
    "content": "CREATE TABLE `test_all` (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT,\n  `c_bit_1` bit(1) DEFAULT NULL,\n  `c_bit_8` bit(8) DEFAULT NULL,\n  `c_bit_16` bit(16) DEFAULT NULL,\n  `c_bit_32` bit(32) DEFAULT NULL,\n  `c_bit_64` bit(64) DEFAULT NULL,\n  `c_bool` boolean DEFAULT NULL,\n  `c_tinyint_1` tinyint(1) DEFAULT NULL,\n  `c_tinyint_4` tinyint(4) DEFAULT NULL,\n  `c_tinyint_8` tinyint(8) DEFAULT NULL,\n  `c_tinyint_8_un` tinyint(8) unsigned DEFAULT NULL,\n  `c_smallint_1` smallint(1) DEFAULT NULL,\n  `c_smallint_16` smallint(16) DEFAULT NULL,\n  `c_smallint_16_un` smallint(16) unsigned DEFAULT NULL,\n  `c_mediumint_1` mediumint(1) DEFAULT NULL,\n  `c_mediumint_24` mediumint(24) DEFAULT NULL,\n  `c_mediumint_24_un` mediumint(24) unsigned DEFAULT NULL,\n  `c_int_1` int(1) DEFAULT NULL,\n  `c_int_32` int(32) DEFAULT NULL,\n  `c_int_32_un` int(32) unsigned DEFAULT NULL,\n  `c_bigint_1` bigint(1) DEFAULT NULL,\n  `c_bigint_64` bigint(64) DEFAULT NULL,\n  `c_bigint_64_un` bigint(64) unsigned DEFAULT NULL,\n  `c_decimal` decimal(10,3) DEFAULT NULL,\n  `c_decimal_pr` decimal(10,3) DEFAULT NULL,\n  `c_float` float DEFAULT NULL,\n  `c_float_pr` float(10,3) DEFAULT NULL,\n  `c_float_un` float(10,3) unsigned DEFAULT NULL,\n  `c_double` double DEFAULT NULL,\n  `c_double_pr` double(10,3) DEFAULT NULL,\n  `c_double_un` double(10,3) unsigned DEFAULT NULL,\n  `c_date` date DEFAULT NULL COMMENT 'date',\n  `c_datetime` datetime DEFAULT NULL,\n  `c_datetime_1` datetime(1) DEFAULT NULL,\n  `c_datetime_3` datetime(3) DEFAULT NULL,\n  `c_datetime_6` datetime(6) DEFAULT NULL,\n  `c_timestamp` timestamp DEFAULT CURRENT_TIMESTAMP,\n  `c_timestamp_1` timestamp(1) DEFAULT 0,\n  `c_timestamp_3` timestamp(3) DEFAULT 0,\n  `c_timestamp_6` timestamp(6) DEFAULT 0,\n  `c_time` time DEFAULT NULL,\n  `c_time_1` time(1) DEFAULT NULL,\n  `c_time_3` time(3) DEFAULT NULL,\n  `c_time_6` time(6) DEFAULT NULL,\n  `c_year` year DEFAULT NULL,\n  `c_year_4` year(4) DEFAULT NULL,\n  `c_char` char(10) DEFAULT NULL,\n  `c_varchar` varchar(10) DEFAULT NULL,\n  `c_binary` binary(10) DEFAULT NULL,\n  `c_varbinary` varbinary(10) DEFAULT NULL,\n  `c_blob_tiny` tinyblob DEFAULT NULL,\n  `c_blob` blob DEFAULT NULL,\n  `c_blob_medium` mediumblob DEFAULT NULL,\n  `c_blob_long` longblob DEFAULT NULL,\n  `c_text_tiny` tinytext DEFAULT NULL,\n  `c_text` text DEFAULT NULL,\n  `c_text_medium` mediumtext DEFAULT NULL,\n  `c_text_long` longtext DEFAULT NULL,\n  `c_enum` enum('a','b','c') DEFAULT NULL,\n  `c_set` set('a','b','c') DEFAULT NULL,\n  `c_json` json DEFAULT NULL,\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='10000000' "
  },
  {
    "path": "parse/src/test/resources/ddl/ddl_any.sql",
    "content": "CREATE TABLE procs_priv (\nHost char(60) COLLATE utf8_bin NOT NULL DEFAULT '',\nDb char(64) COLLATE utf8_bin NOT NULL DEFAULT '',\nUser char(16) COLLATE utf8_bin NOT NULL DEFAULT '',\nRoutine_name char(64) CHARACTER SET utf8 NOT NULL DEFAULT '',\nRoutine_type enum('FUNCTION','PROCEDURE') COLLATE utf8_bin NOT NULL,\nGrantor char(77) COLLATE utf8_bin NOT NULL DEFAULT '',\nProc_priv set('Execute','Alter Routine','Grant') CHARACTER SET utf8 NOT NULL DEFAULT '',\nTimestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\nPRIMARY KEY (Host,Db,User,Routine_name,Routine_type),\nKEY Grantor (Grantor)\n) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Procedure privileges'"
  },
  {
    "path": "parse/src/test/resources/ddl/ddl_create_function_index.sql",
    "content": "CREATE TABLE function_index_test (\r   id INT AUTO_INCREMENT PRIMARY KEY,\r   owner_id INT NOT NULL,\r   code VARCHAR(100) NOT NULL,\r   UNIQUE KEY uk_owner_id_upper_code (owner_id, (upper(code)))\r)\rENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\r\r\rCREATE TABLE function_index_test2 (\r     id INT AUTO_INCREMENT PRIMARY KEY,\r     owner_id INT NOT NULL,\r     code VARCHAR(100) NOT NULL,\r     UNIQUE KEY uk_owner_id_upper_code (owner_id, ((LEFT(UPPER(code), 10))))\r)\rENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\r\rCREATE TABLE function_index_test3 (\r      id INT AUTO_INCREMENT PRIMARY KEY,\r      owner_id INT NOT NULL,\r      code VARCHAR(100) NOT NULL,\r      UNIQUE KEY uk_owner_id_upper_code (owner_id , code(10))\r)\rENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\r\r\rCREATE TABLE function_index_test3 (\r      id INT AUTO_INCREMENT PRIMARY KEY,\r      owner_id INT NOT NULL,\r      code VARCHAR(100) NOT NULL,\r      UNIQUE KEY uk_owner_id_upper_code (code(10))\r)\rENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\r"
  },
  {
    "path": "parse/src/test/resources/ddl/ddl_create_if_not_exist.sql",
    "content": "CREATE TABLE `table_x1` (\n    `id` bigint(20) NOT NULL AUTO_INCREMENT,\n    `key1` longtext NOT NULL COMMENT 'key1',\n    `value1` longtext NOT NULL COMMENT 'value1',\n    PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n\nCREATE TABLE IF NOT EXISTS `table_x1` (\n    `id` bigint(20) NOT NULL AUTO_INCREMENT,\n    `key1` longtext NOT NULL COMMENT 'key1',\n    PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;"
  },
  {
    "path": "parse/src/test/resources/ddl/ddl_test1.sql",
    "content": "create table yushitai_test.card_record (\nid bigint auto_increment,\nlast_update timestamp not null DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\nhint varchar(64) charset ascii not null,\nvalue varchar(255) charset ascii not null,\nprimary key(id),\nunique key hint_uidx(hint)\n) auto_increment=256 ;\n\nDROP TABLE IF EXISTS _card_record_gho /* generated by server */ ;\nDROP TABLE IF EXISTS _card_record_del /* generated by server */ ;\n\ncreate /* gh-ost */ table yushitai_test._card_record_gho like yushitai_test.card_record ;\nalter /* gh-ost */ table yushitai_test._card_record_gho add column customization_id bigint unsigned NOT NULL COMMENT 'TEST' ;\n\ncreate /* gh-ost */ table yushitai_test._card_record_del (\nid int auto_increment primary key\n) engine=InnoDB comment='ghost-cut-over-sentry' ;\n\nDROP TABLE IF EXISTS _card_record_del /* generated by server */ ;\nrename /* gh-ost */ table yushitai_test.card_record to yushitai_test._card_record_del, yushitai_test._card_record_gho to yushitai_test.card_record;"
  },
  {
    "path": "parse/src/test/resources/ddl/ddl_test2.sql",
    "content": "CREATE TABLE yushitai_test.card_record (\n\tid bigint AUTO_INCREMENT,\n\tname varchar(32) DEFAULT NULL,\n\talias varchar(32) DEFAULT NULL,\n\tINDEX index_name(name),\n\tCONSTRAINT pk_id PRIMARY KEY (id),\n\tUNIQUE uk_name (name,alias)\n) AUTO_INCREMENT = 256\n"
  },
  {
    "path": "parse/src/test/resources/ddl/ddl_test3.sql",
    "content": "create table quniya4(name varchar(255) null,value varchar(255) null,id int not null,constraint quniya4_pk primary key (id));\nalter table quniya4 modify id int not null first;\nalter table quniya4 modify id int auto_increment;"
  },
  {
    "path": "parse/src/test/resources/ddl/ddl_test4.sql",
    "content": "CREATE TABLE `test_columnar` (\r   `id` bigint NOT NULL AUTO_INCREMENT,\r   `user_id` bigint NOT NULL,\r   `vault_id` bigint NOT NULL,\r   `address` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL DEFAULT '',\r   `address_from` int NOT NULL DEFAULT '0' ,\r   `alias` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT 'MyAddress' ,\r   `balance` decimal(50, 0) NOT NULL DEFAULT '0' ,\r   `coin_type` int NOT NULL DEFAULT '0' ,\r   `height` bigint DEFAULT '0' ,\r   `shard` smallint NOT NULL DEFAULT '0' ,\r   `chain` int NOT NULL DEFAULT '0' ,\r   `status` smallint NOT NULL DEFAULT '0' ,\r   `account` int NOT NULL DEFAULT '0',\r   `is_change` tinyint DEFAULT '0' ,\r   `address_index` int DEFAULT '0' ,\r   `redeem_script` varchar(512) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,\r   `nonce` bigint UNSIGNED NOT NULL DEFAULT '0',\r   `is_sync` tinyint NOT NULL DEFAULT '0',\r   `flag` tinyint NOT NULL DEFAULT '0',\r   `wallet_type` varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL DEFAULT '',\r   `created_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\r   `modify_date` timestamp NULL DEFAULT NULL ,\r   `address_type` tinyint NOT NULL DEFAULT '0',\r   `risk_type` int NOT NULL DEFAULT '0' ,\r   `balance_source` int NOT NULL DEFAULT '0',\r   `tx_flag` tinyint NOT NULL DEFAULT '0' ,\r   `risk_flag` smallint NOT NULL DEFAULT '0',\r   `business_line` int NOT NULL DEFAULT '1',\r   PRIMARY KEY (`id`),\r   CLUSTERED COLUMNAR INDEX `cc_i_address` (`address`)\r       PARTITION BY HASH(`address`)\r       PARTITIONS 32,\r   UNIQUE KEY `idx_ct_addr` USING BTREE (`user_id`, `coin_type`, `address`)\r) ENGINE = InnoDB AUTO_INCREMENT = 128498037 DEFAULT CHARSET = utf8mb3 DEFAULT COLLATE = utf8mb3_bin ROW_FORMAT = DYNAMIC\rPARTITION BY KEY(`address`)\rPARTITIONS 32\r"
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_1.sql",
    "content": "CREATE TABLE `tb_bbvvzzczcw` (\n  `col_ruygkecjzp` longblob,\n  `col_orycjbfrss` year(4) DEFAULT '2019',\n  `col_aqqnunnega` varbinary(225) DEFAULT NULL,\n  `col_pxwauaruqw` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT 'enum_or_set_0',\n  UNIQUE KEY `col_ruygkecjzp` (`col_ruygkecjzp`(14),`col_orycjbfrss`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_hcvvpyqbtd` (\n  `col_ruygkecjzp` longblob,\n  `col_orycjbfrss` year(4) DEFAULT '2019',\n  `col_aqqnunnega` varbinary(225) DEFAULT NULL,\n  `col_pxwauaruqw` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT 'enum_or_set_0',\n  UNIQUE KEY `col_ruygkecjzp` (`col_ruygkecjzp`(14),`col_orycjbfrss`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_ljqeyzesru` (\n  `col_qmvlxemsmt` datetime(6) DEFAULT NULL,\n  `col_wcntsrfsjf` int(11) DEFAULT '1',\n  `col_kekvofvtus` int(70) unsigned DEFAULT '1',\n  `col_bhbfokpfhm` float DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_rpuyybsdob` (\n  `col_qmvlxemsmt` datetime(6) DEFAULT NULL,\n  `col_wcntsrfsjf` int(11) DEFAULT '1',\n  `col_kekvofvtus` int(70) unsigned DEFAULT '1',\n  `col_bhbfokpfhm` float DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_wewsxxqmxd` (\n  `col_zmjbwpsrnw` timestamp(3) NULL DEFAULT CURRENT_TIMESTAMP(3),\n  `col_qqzmxlmztj` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 DEFAULT 'enum_or_set_0',\n  `col_hwnlilelpf` smallint(5) unsigned DEFAULT '1',\n  `col_oyeoemafea` date DEFAULT '2019-07-04',\n  UNIQUE KEY `symb_biynehpjlu` (`col_hwnlilelpf`,`col_oyeoemafea`),\n  UNIQUE KEY `uk_ztxuhpyaxo` (`col_zmjbwpsrnw`,`col_oyeoemafea`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_yfjonexaag` (\n  `col_hfydymybbg` tinytext,\n  UNIQUE KEY `symb_gpchhhvhwm` (`col_hfydymybbg`(20))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_10.sql",
    "content": "CREATE TABLE `tb_cwypwdifyd` (\n  `col_psyexiqdcu` float DEFAULT NULL,\n  UNIQUE KEY `uk_llrjshsrwa` (`col_psyexiqdcu`),\n  UNIQUE KEY `col_psyexiqdcu` (`col_psyexiqdcu`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_gnhiuztkhp` (\n  `col_mjvvyroage` longblob,\n  `col_yivxmcooat` varbinary(155) NOT NULL,\n  `col_zobuxurthc` date DEFAULT NULL,\n  PRIMARY KEY (`col_yivxmcooat`(10)),\n  UNIQUE KEY `uk_yjydpgltyk` (`col_zobuxurthc`),\n  UNIQUE KEY `uk_ayltsdmkyj` (`col_mjvvyroage`(24))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_omxdljixxx` (\n  `col_virtguzwuh` tinyblob\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_11.sql",
    "content": ""
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_12.sql",
    "content": "CREATE TABLE `tb_jaaspokopu` (\n  `col_cbvwqvuuvo` varbinary(128) NOT NULL,\n  `col_kvspyjtqjg` text,\n  UNIQUE KEY `uk_rjyzqluaky` (`col_cbvwqvuuvo`(3))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_13.sql",
    "content": "CREATE TABLE `tb_enslimtxlk` (\n  `col_rffhwlwajv` mediumint(89) unsigned zerofill DEFAULT NULL,\n  `col_drmxtsfmqu` bit(22) NOT NULL DEFAULT b'0',\n  `col_gpbdvtnnpe` bigint(20) unsigned DEFAULT '1',\n  `col_rdqhjjgkkx` double DEFAULT '1',\n  UNIQUE KEY `col_gpbdvtnnpe` (`col_gpbdvtnnpe`),\n  UNIQUE KEY `col_rdqhjjgkkx` (`col_rdqhjjgkkx`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_14.sql",
    "content": "CREATE TABLE `tb_bmbzkqioww` (\n  `col_cnbjbdtlzc` text,\n  `col_oahevgiptz` tinytext\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_dqutvqabgv` (\n  `col_kfazghqbis` varbinary(61) DEFAULT '\\0',\n  `col_ieyszubjeg` time DEFAULT NULL,\n  `col_dmbvppuzgw` varbinary(167) DEFAULT NULL,\n  `col_dmobnapptq` mediumblob,\n  UNIQUE KEY `col_dmbvppuzgw` (`col_dmbvppuzgw`(14))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_repwxdxmss` (\n  `col_xtrkkmfmiz` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT 'enum_or_set_0',\n  `col_slqrzzopbp` decimal(10,0) NOT NULL DEFAULT '1',\n  UNIQUE KEY `col_xtrkkmfmiz` (`col_xtrkkmfmiz`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_15.sql",
    "content": ""
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_16.sql",
    "content": "CREATE TABLE `tb_sqoczkufxp` (\n  `col_rrdzqbksmd` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 DEFAULT 'enum_or_set_0',\n  `col_spveduzoyj` mediumint(219) unsigned zerofill NOT NULL,\n  `col_zghtsjnauz` datetime(3) DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_17.sql",
    "content": "CREATE TABLE `tb_wbrbzvpfra` (\n  `col_lokvnorvsp` char(235) CHARACTER SET utf8mb4 DEFAULT NULL,\n  `col_vazlbmjjtl` char(1) DEFAULT NULL,\n  `col_kcxzselokz` mediumint(229) unsigned NOT NULL DEFAULT '1',\n  `col_bjiezlcrgf` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') NOT NULL DEFAULT 'enum_or_set_0',\n  PRIMARY KEY (`col_kcxzselokz`,`col_bjiezlcrgf`),\n  UNIQUE KEY `uk_qxibrmyivk` (`col_bjiezlcrgf`),\n  UNIQUE KEY `uk_zmxfbsrjpe` (`col_bjiezlcrgf`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_18.sql",
    "content": "CREATE TABLE `tb_imlfgarrjv` (\n  `col_hbehuyqgfr` binary(1) NOT NULL,\n  `col_pjrrinkrzz` longtext CHARACTER SET utf8 COLLATE utf8_unicode_ci,\n  `col_dqltdiymus` tinyblob,\n  `col_qzxbihrndq` double DEFAULT NULL,\n  UNIQUE KEY `uk_thufyvijgg` (`col_hbehuyqgfr`,`col_dqltdiymus`(17))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_19.sql",
    "content": "CREATE TABLE `tb_qfryzntbot` (\n  `col_awltnvurel` decimal(10,0) DEFAULT '1',\n  `col_wbacbcxgvc` longblob,\n  `col_bewighnliy` double DEFAULT '1'\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_rjbzsfvdte` (\n  `col_awltnvurel` decimal(10,0) DEFAULT '1',\n  `col_wbacbcxgvc` longblob,\n  `col_bewighnliy` double DEFAULT '1'\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_ruhyyyifba` (\n  `col_xzormknbla` int(10) unsigned NOT NULL,\n  `col_lizstxeuhj` time(4) DEFAULT NULL,\n  `col_kmgfxzwfbv` time(1) DEFAULT NULL,\n  UNIQUE KEY `col_kmgfxzwfbv` (`col_kmgfxzwfbv`),\n  UNIQUE KEY `col_kmgfxzwfbv_2` (`col_kmgfxzwfbv`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_2.sql",
    "content": ""
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_20.sql",
    "content": "CREATE TABLE `tb_ljmtrrhglh` (\n  `col_kxypvfvmmi` longblob,\n  `col_vjsgmnsorv` decimal(39,0) DEFAULT NULL,\n  `col_ckrshagjle` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT 'enum_or_set_0'\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_21.sql",
    "content": ""
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_22.sql",
    "content": "CREATE TABLE `tb_ayzakpuupb` (\n  `col_iykolxhoko` decimal(31,0) DEFAULT NULL,\n  `col_cgzreeozpp` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT NULL,\n  `col_iraphtrlrd` varbinary(212) NOT NULL DEFAULT '\\0',\n  PRIMARY KEY (`col_iraphtrlrd`(31)),\n  UNIQUE KEY `col_iraphtrlrd` (`col_iraphtrlrd`(25)),\n  UNIQUE KEY `uk_rzlfipspah` (`col_cgzreeozpp`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_mjixwohckz` (\n  `col_iykolxhoko` decimal(31,0) DEFAULT NULL,\n  `col_cgzreeozpp` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT NULL,\n  `col_iraphtrlrd` varbinary(212) NOT NULL DEFAULT '\\0',\n  PRIMARY KEY (`col_iraphtrlrd`(31)),\n  UNIQUE KEY `col_iraphtrlrd` (`col_iraphtrlrd`(25)),\n  UNIQUE KEY `uk_rzlfipspah` (`col_cgzreeozpp`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_wdurcynllr` (\n  `col_obzlxjlpci` decimal(61,0) DEFAULT NULL,\n  UNIQUE KEY `symb_tszhfwqpyk` (`col_obzlxjlpci`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_23.sql",
    "content": "CREATE TABLE `tb_gvxwgsxgte` (\n  `col_quthabfydl` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL,\n  `col_bpzwhwubra` int(118) unsigned DEFAULT '1',\n  `col_fpkljodgme` time DEFAULT NULL,\n  `col_zxdapdqzmv` blob,\n  UNIQUE KEY `uk_vuzkhjajdc` (`col_bpzwhwubra`,`col_fpkljodgme`),\n  UNIQUE KEY `uk_zknetkwpoq` (`col_fpkljodgme`,`col_zxdapdqzmv`(28))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_oytmynjdbq` (\n  `col_thwosnwagl` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_wtwwuhhmqp` (\n  `col_aiifakdklr` datetime(6) DEFAULT NULL,\n  `col_ulzkdgcmmu` time DEFAULT NULL,\n  UNIQUE KEY `uk_ikryxrhfhx` (`col_aiifakdklr`),\n  UNIQUE KEY `uk_ckiseqvinv` (`col_aiifakdklr`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_24.sql",
    "content": ""
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_25.sql",
    "content": "CREATE TABLE `tb_mzhqjoqwim` (\n  `col_ryksixnuqb` float NOT NULL DEFAULT '1',\n  `col_uvfgzqiidt` decimal(10,0) DEFAULT '1',\n  UNIQUE KEY `uk_eipadvxxrr` (`col_uvfgzqiidt`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_26.sql",
    "content": ""
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_27.sql",
    "content": ""
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_28.sql",
    "content": "CREATE TABLE `tb_nseikjdsdh` (\n  `col_ykpxfugemh` longblob,\n  `col_xxtvhkkirw` float DEFAULT '1',\n  UNIQUE KEY `uk_hzcjlivdvu` (`col_xxtvhkkirw`),\n  UNIQUE KEY `col_ykpxfugemh` (`col_ykpxfugemh`(24),`col_xxtvhkkirw`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_29.sql",
    "content": "CREATE TABLE `tb_bkldmexfby` (\n  `col_mprviuzmsa` mediumint(215) unsigned zerofill DEFAULT NULL,\n  `col_wmnengkfur` decimal(6,0) NOT NULL,\n  `col_toueuqhkhc` longtext CHARACTER SET utf8mb4,\n  PRIMARY KEY (`col_wmnengkfur`),\n  UNIQUE KEY `col_mprviuzmsa` (`col_mprviuzmsa`,`col_wmnengkfur`),\n  UNIQUE KEY `symb_ytbnzrnwgs` (`col_toueuqhkhc`(31))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_jmydpaxtpu` (\n  `col_mprviuzmsa` mediumint(215) unsigned zerofill DEFAULT NULL,\n  `col_wmnengkfur` decimal(6,0) NOT NULL,\n  `col_toueuqhkhc` longtext CHARACTER SET utf8mb4,\n  PRIMARY KEY (`col_wmnengkfur`),\n  UNIQUE KEY `col_mprviuzmsa` (`col_mprviuzmsa`,`col_wmnengkfur`),\n  UNIQUE KEY `symb_ytbnzrnwgs` (`col_toueuqhkhc`(31))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_3.sql",
    "content": "CREATE TABLE `tb_ctxyxxbpqn` (\n  `col_mpmyypobxf` longblob,\n  `col_vdicnalzyn` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n  PRIMARY KEY (`col_vdicnalzyn`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_uasvccezbb` (\n  `col_mpmyypobxf` longblob,\n  `col_vdicnalzyn` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n  PRIMARY KEY (`col_vdicnalzyn`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_30.sql",
    "content": "CREATE TABLE `tb_bjsplgjemd` (\n  `col_fkstgdmdmv` varbinary(215) DEFAULT '\\0',\n  `col_oyzofwwoch` mediumblob,\n  `col_exhsgobpvc` tinyint(246) unsigned zerofill NOT NULL,\n  `col_ypcuorizvb` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT 'enum_or_set_0',\n  PRIMARY KEY (`col_exhsgobpvc`),\n  UNIQUE KEY `col_exhsgobpvc` (`col_exhsgobpvc`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_dxadqwfhhb` (\n  `col_fkstgdmdmv` varbinary(215) DEFAULT '\\0',\n  `col_oyzofwwoch` mediumblob,\n  `col_exhsgobpvc` tinyint(246) unsigned zerofill NOT NULL,\n  `col_ypcuorizvb` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT 'enum_or_set_0',\n  PRIMARY KEY (`col_exhsgobpvc`),\n  UNIQUE KEY `col_exhsgobpvc` (`col_exhsgobpvc`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_iztgdcpcld` (\n  `col_rvnhrlexjo` time DEFAULT '00:00:00',\n  `col_fwwgntdsdt` smallint(5) unsigned zerofill DEFAULT NULL,\n  `col_yxejjdacht` int(213) unsigned zerofill NOT NULL,\n  UNIQUE KEY `uk_svckkuvqce` (`col_rvnhrlexjo`,`col_fwwgntdsdt`),\n  UNIQUE KEY `uk_amgxauyvbp` (`col_rvnhrlexjo`,`col_fwwgntdsdt`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_kubnsybcaf` (\n  `col_ttqqizkwig` bit(43) DEFAULT b'0',\n  `col_yvgpfjhjcj` timestamp(5) NULL DEFAULT NULL,\n  `col_cuvrdliegh` mediumint(8) unsigned zerofill DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_31.sql",
    "content": ""
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_32.sql",
    "content": "CREATE TABLE `tb_arczcfjqat` (\n  `col_dqrslyzpwh` longtext CHARACTER SET utf8 COLLATE utf8_unicode_ci,\n  `col_fcmimikjdw` date DEFAULT NULL,\n  `col_wkslgjtpww` decimal(11,5) NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_kgdpofrysh` (\n  `col_srfyjibwff` time(6) DEFAULT NULL,\n  UNIQUE KEY `uk_sncbjfknhk` (`col_srfyjibwff`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_33.sql",
    "content": "CREATE TABLE `tb_asbrvloeex` (\n  `col_weucftcgtj` decimal(17,13) DEFAULT NULL,\n  `col_fsnwamzmnj` varchar(116) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_vjudeyawut` (\n  `col_geysucimbc` longtext,\n  `col_mlphdouenl` varbinary(160) DEFAULT '\\0'\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_34.sql",
    "content": "CREATE TABLE `tb_vzdatmeqgj` (\n  `col_qvkhqmzvuj` int(224) unsigned DEFAULT NULL,\n  `col_xdasidouyb` float DEFAULT '1',\n  `col_iyneakkoda` time DEFAULT NULL,\n  `col_ixrxayrkoa` varchar(178) DEFAULT ''\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_35.sql",
    "content": ""
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_36.sql",
    "content": "CREATE TABLE `tb_auppieylzo` (\n  `col_oyenywcnaa` smallint(5) unsigned DEFAULT '1',\n  `col_wwtzoyrtid` varchar(233) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL,\n  `col_irailjowqz` longblob\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_btaicbcvzm` (\n  `col_qywkvovncp` year(4) NOT NULL DEFAULT '2019',\n  `col_szxbozzqra` int(10) unsigned DEFAULT NULL,\n  PRIMARY KEY (`col_qywkvovncp`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_jwspnsjkbz` (\n  `col_hjkatsppsc` time(6) NOT NULL,\n  PRIMARY KEY (`col_hjkatsppsc`),\n  UNIQUE KEY `symb_qmwmniwhbe` (`col_hjkatsppsc`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_mxukjfwtfx` (\n  `col_goniustofk` mediumtext,\n  `col_ohnstevypa` blob,\n  `col_nlpdegmfoj` longblob,\n  `col_kcegirvcvq` timestamp(4) NOT NULL DEFAULT CURRENT_TIMESTAMP(4),\n  UNIQUE KEY `uk_clmmzqdrrw` (`col_ohnstevypa`(15))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_rdvmtcfenu` (\n  `col_beaaznijqu` int(10) unsigned NOT NULL DEFAULT '1',\n  `col_tvyjjmsmzf` binary(236) DEFAULT NULL,\n  `col_vwwvtljlov` int(238) unsigned zerofill NOT NULL,\n  `col_eetxjyrroh` longblob\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_uildklperh` (\n  `col_jqdxektcbn` mediumint(73) unsigned zerofill DEFAULT NULL,\n  `col_bnmnlyrpzk` blob,\n  `col_szivvzwgog` date DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_37.sql",
    "content": ""
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_38.sql",
    "content": "CREATE TABLE `tb_cemigpflpg` (\n  `col_teeikxydzy` smallint(86) unsigned zerofill DEFAULT NULL,\n  `col_ntfpjlwmxm` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NOT NULL,\n  `col_fdqhoqsugi` char(248) CHARACTER SET utf8mb4 NOT NULL,\n  `col_hpffggqzyt` smallint(5) unsigned zerofill DEFAULT NULL,\n  PRIMARY KEY (`col_ntfpjlwmxm`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_lvhgwlctrm` (\n  `col_irlhbphjuu` bigint(20) DEFAULT '1',\n  `col_mmyhnykoux` datetime(4) DEFAULT NULL,\n  `col_tbnhrkvbyw` date DEFAULT '2019-07-04',\n  `col_znpwgitvbt` date DEFAULT '2019-07-04'\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_tntbgwfxdz` (\n  `col_oaqwwurqgi` varbinary(236) NOT NULL,\n  `col_ixrprxsjfc` varbinary(67) DEFAULT NULL,\n  `col_nynkysgzrd` binary(157) DEFAULT NULL,\n  PRIMARY KEY (`col_oaqwwurqgi`(5))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_xplnlwuite` (\n  `col_dagcnvtvmo` year(4) NOT NULL,\n  `col_lnppfvjbkl` longblob,\n  PRIMARY KEY (`col_dagcnvtvmo`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_39.sql",
    "content": "CREATE TABLE `tb_onrsvwgpqb` (\n  `col_wsaejbacoe` longtext CHARACTER SET utf8,\n  `col_wgrjfcezod` int(19) NOT NULL,\n  `col_yhavwtiaep` date NOT NULL,\n  `col_ezzupofzra` tinytext CHARACTER SET utf8mb4,\n  UNIQUE KEY `col_wgrjfcezod` (`col_wgrjfcezod`),\n  UNIQUE KEY `col_wsaejbacoe` (`col_wsaejbacoe`(29),`col_wgrjfcezod`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_pactwzqamv` (\n  `col_hriruwciyw` longblob,\n  UNIQUE KEY `col_hriruwciyw` (`col_hriruwciyw`(11)),\n  UNIQUE KEY `uk_ktdzldgjqo` (`col_hriruwciyw`(18))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_xfnqchameq` (\n  `col_lsaozjvioc` tinyint(4) DEFAULT '1',\n  `col_umquuzgoic` binary(1) DEFAULT NULL,\n  `col_hssxpkdkzt` decimal(10,0) DEFAULT '1',\n  UNIQUE KEY `uk_ribdoefndw` (`col_lsaozjvioc`),\n  UNIQUE KEY `uk_ygjhgipibu` (`col_umquuzgoic`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_4.sql",
    "content": "CREATE TABLE `tb_iapmhzrbpl` (\n  `col_vevvvixdsj` double NOT NULL DEFAULT '1',\n  UNIQUE KEY `symb_mvejvudtqx` (`col_vevvvixdsj`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_npfwhbears` (\n  `col_djhzavbkkl` bigint(20) DEFAULT NULL,\n  `col_nnatwjycze` timestamp(3) NULL DEFAULT NULL,\n  UNIQUE KEY `col_djhzavbkkl` (`col_djhzavbkkl`),\n  UNIQUE KEY `uk_giquysylxe` (`col_djhzavbkkl`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_nxxnnxsqeq` (\n  `col_djhzavbkkl` bigint(20) DEFAULT NULL,\n  `col_nnatwjycze` timestamp(3) NULL DEFAULT NULL,\n  UNIQUE KEY `col_djhzavbkkl` (`col_djhzavbkkl`),\n  UNIQUE KEY `uk_giquysylxe` (`col_djhzavbkkl`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_yujleuojse` (\n  `col_ngukvihugo` longblob,\n  UNIQUE KEY `uk_zllsscaepd` (`col_ngukvihugo`(12)),\n  UNIQUE KEY `uk_hwinjetonw` (`col_ngukvihugo`(24))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_5.sql",
    "content": ""
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_6.sql",
    "content": "CREATE TABLE `tb_bpukgjzglw` (\n  `col_sgxesfcvdh` blob,\n  `col_tjhvpjnswu` bigint(20) unsigned DEFAULT NULL,\n  `col_vvbowgfzum` varchar(200) DEFAULT ''\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_chzhfzbmgu` (\n  `col_zqritfblef` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 DEFAULT NULL,\n  `col_tvyzdewvuz` int(17) DEFAULT NULL,\n  `col_rigzrdrdlq` decimal(31,15) DEFAULT NULL,\n  UNIQUE KEY `uk_ckjnyzlzhn` (`col_rigzrdrdlq`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_osccbhgwdn` (\n  `col_wuvofglkav` blob,\n  UNIQUE KEY `col_wuvofglkav` (`col_wuvofglkav`(20)),\n  UNIQUE KEY `col_wuvofglkav_2` (`col_wuvofglkav`(18))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_7.sql",
    "content": "CREATE TABLE `tb_wpozpvwepq` (\n  `col_mhnfdjvvcl` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT 'enum_or_set_0',\n  `col_nppvqejmds` mediumint(8) unsigned zerofill DEFAULT NULL,\n  UNIQUE KEY `uk_cgzmixhhpp` (`col_mhnfdjvvcl`),\n  UNIQUE KEY `col_mhnfdjvvcl` (`col_mhnfdjvvcl`,`col_nppvqejmds`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_8.sql",
    "content": "CREATE TABLE `tb_qdjqayreum` (\n  `col_gqvgqzlgna` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') DEFAULT NULL,\n  `col_xnynymrwbx` decimal(8,1) DEFAULT NULL,\n  UNIQUE KEY `symb_znikarajci` (`col_xnynymrwbx`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/mysql_9.sql",
    "content": "CREATE TABLE `tb_qinfehbzem` (\n  `col_ginzfhyvfi` int(10) unsigned DEFAULT '1',\n  `col_cakcnwuchg` date DEFAULT '2019-07-04',\n  `col_hgdcocydeg` int(10) unsigned zerofill DEFAULT NULL,\n  `col_opsrfpouaa` longblob,\n  UNIQUE KEY `uk_tcqbsivphi` (`col_opsrfpouaa`(1)),\n  UNIQUE KEY `col_hgdcocydeg` (`col_hgdcocydeg`,`col_opsrfpouaa`(29))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_1.sql",
    "content": "CREATE TABLE `tb_quilrfojmp` (\n  `col_ruygkecjzp` longblob,\n  `col_orycjbfrss` year DEFAULT '2019',\n  `col_aqqnunnega` varbinary(225),\n  `col_pxwauaruqw` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 DEFAULT 'enum_or_set_0',\n  UNIQUE `col_ruygkecjzp` (`col_ruygkecjzp`(14),`col_orycjbfrss`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_rpuyybsdob` (\n  `col_qmvlxemsmt` datetime(6),\n  `col_wcntsrfsjf` int NULL DEFAULT '1',\n  `col_kekvofvtus` integer(70) unsigned DEFAULT '1',\n  `col_bhbfokpfhm` float\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_qfmtewribz` (\n  `col_hocmjkikme` int unsigned,\n  `col_qbggcmwxyh` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NOT NULL,\n  `col_fulwqoqveo` mediumint unsigned zerofill,\n  `col_eniifaecwj` integer(159) NOT NULL DEFAULT '1',\n  PRIMARY KEY (`col_qbggcmwxyh`,`col_eniifaecwj`),\n  UNIQUE INDEX `uk_fmvsmeqnst` (`col_fulwqoqveo`),\n  CONSTRAINT `symb_xifnljgzcv` UNIQUE (`col_qbggcmwxyh`,`col_fulwqoqveo`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_odnffrvnvl` LIKE `tb_quilrfojmp`;\nCREATE TABLE `tb_lttgkqunzl` (\n  `col_nllztggwyd` smallint unsigned DEFAULT '1'\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_rkvcdukyuq` LIKE `tb_quilrfojmp`;\nCREATE TABLE `tb_erkppdannn` (\n  `col_zmjbwpsrnw` timestamp(3) NULL DEFAULT CURRENT_TIMESTAMP(3),\n  `col_qqzmxlmztj` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NULL DEFAULT 'enum_or_set_0',\n  `col_hwnlilelpf` smallint unsigned DEFAULT '1',\n  `col_oyeoemafea` date NULL DEFAULT '2019-07-04',\n  CONSTRAINT `symb_biynehpjlu` UNIQUE (`col_hwnlilelpf`,`col_oyeoemafea`),\n  CONSTRAINT `symb_yrommseaif` UNIQUE `uk_ztxuhpyaxo` (`col_zmjbwpsrnw`,`col_oyeoemafea`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_knsgjmsufx` LIKE `tb_odnffrvnvl`;\nCREATE TABLE `tb_ljqeyzesru` LIKE `tb_rpuyybsdob`;\nCREATE TABLE `tb_szlgabmztl` (\n  `col_hfydymybbg` tinytext CHARACTER SET latin1,\n  CONSTRAINT `symb_gpchhhvhwm` UNIQUE KEY (`col_hfydymybbg`(20))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_qfmtewribz` TO `tb_qeokuaneue`;\nRENAME TABLE `tb_lttgkqunzl` TO `tb_uhjgsigdfr`, `tb_erkppdannn` TO `tb_xeoclzosgr`;\nRENAME TABLE `tb_quilrfojmp` TO `tb_hycsuwyoxr`, `tb_knsgjmsufx` TO `tb_bbvvzzczcw`;\nRENAME TABLE `tb_xeoclzosgr` TO `tb_fxxptceefr`;\nRENAME TABLE `tb_odnffrvnvl` TO `tb_rtnozmledi`;\nRENAME TABLE `tb_fxxptceefr` TO `tb_tekgceqrmv`;\nRENAME TABLE `tb_hycsuwyoxr` TO `tb_hcvvpyqbtd`, `tb_szlgabmztl` TO `tb_yfjonexaag`;\nRENAME TABLE `tb_tekgceqrmv` TO `tb_wewsxxqmxd`, `tb_uhjgsigdfr` TO `tb_mbvuditpbx`;\nDROP TABLE tb_mbvuditpbx, tb_rkvcdukyuq;\nDROP TABLE tb_rtnozmledi, tb_qeokuaneue;\nCREATE TABLE `tb_quilrfojmp` (\n  `col_ruygkecjzp` longblob,\n  `col_orycjbfrss` year DEFAULT '2019',\n  `col_aqqnunnega` varbinary(225),\n  `col_pxwauaruqw` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 DEFAULT 'enum_or_set_0',\n  UNIQUE `col_ruygkecjzp` (`col_ruygkecjzp`(14),`col_orycjbfrss`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_rpuyybsdob` (\n  `col_qmvlxemsmt` datetime(6),\n  `col_wcntsrfsjf` int NULL DEFAULT '1',\n  `col_kekvofvtus` integer(70) unsigned DEFAULT '1',\n  `col_bhbfokpfhm` float\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_qfmtewribz` (\n  `col_hocmjkikme` int unsigned,\n  `col_qbggcmwxyh` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NOT NULL,\n  `col_fulwqoqveo` mediumint unsigned zerofill,\n  `col_eniifaecwj` integer(159) NOT NULL DEFAULT '1',\n  PRIMARY KEY (`col_qbggcmwxyh`,`col_eniifaecwj`),\n  UNIQUE INDEX `uk_fmvsmeqnst` (`col_fulwqoqveo`),\n  CONSTRAINT `symb_xifnljgzcv` UNIQUE (`col_qbggcmwxyh`,`col_fulwqoqveo`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_odnffrvnvl` LIKE `tb_quilrfojmp`;\nCREATE TABLE `tb_lttgkqunzl` (\n  `col_nllztggwyd` smallint unsigned DEFAULT '1'\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_rkvcdukyuq` LIKE `tb_quilrfojmp`;\nCREATE TABLE `tb_erkppdannn` (\n  `col_zmjbwpsrnw` timestamp(3) NULL DEFAULT CURRENT_TIMESTAMP(3),\n  `col_qqzmxlmztj` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NULL DEFAULT 'enum_or_set_0',\n  `col_hwnlilelpf` smallint unsigned DEFAULT '1',\n  `col_oyeoemafea` date NULL DEFAULT '2019-07-04',\n  CONSTRAINT `symb_biynehpjlu` UNIQUE (`col_hwnlilelpf`,`col_oyeoemafea`),\n  CONSTRAINT `symb_yrommseaif` UNIQUE `uk_ztxuhpyaxo` (`col_zmjbwpsrnw`,`col_oyeoemafea`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_knsgjmsufx` LIKE `tb_odnffrvnvl`;\nCREATE TABLE `tb_ljqeyzesru` LIKE `tb_rpuyybsdob`;\nCREATE TABLE `tb_szlgabmztl` (\n  `col_hfydymybbg` tinytext CHARACTER SET latin1,\n  CONSTRAINT `symb_gpchhhvhwm` UNIQUE KEY (`col_hfydymybbg`(20))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_qfmtewribz` TO `tb_qeokuaneue`;\nRENAME TABLE `tb_lttgkqunzl` TO `tb_uhjgsigdfr`, `tb_erkppdannn` TO `tb_xeoclzosgr`;\nRENAME TABLE `tb_quilrfojmp` TO `tb_hycsuwyoxr`, `tb_knsgjmsufx` TO `tb_bbvvzzczcw`;\nRENAME TABLE `tb_xeoclzosgr` TO `tb_fxxptceefr`;\nRENAME TABLE `tb_odnffrvnvl` TO `tb_rtnozmledi`;\nRENAME TABLE `tb_fxxptceefr` TO `tb_tekgceqrmv`;\nRENAME TABLE `tb_hycsuwyoxr` TO `tb_hcvvpyqbtd`, `tb_szlgabmztl` TO `tb_yfjonexaag`;\nRENAME TABLE `tb_tekgceqrmv` TO `tb_wewsxxqmxd`, `tb_uhjgsigdfr` TO `tb_mbvuditpbx`;\nDROP TABLE tb_mbvuditpbx, tb_rkvcdukyuq;\nDROP TABLE tb_rtnozmledi, tb_qeokuaneue;\nCREATE TABLE `tb_quilrfojmp` (\n  `col_ruygkecjzp` longblob,\n  `col_orycjbfrss` year DEFAULT '2019',\n  `col_aqqnunnega` varbinary(225),\n  `col_pxwauaruqw` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 DEFAULT 'enum_or_set_0',\n  UNIQUE `col_ruygkecjzp` (`col_ruygkecjzp`(14),`col_orycjbfrss`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_rpuyybsdob` (\n  `col_qmvlxemsmt` datetime(6),\n  `col_wcntsrfsjf` int NULL DEFAULT '1',\n  `col_kekvofvtus` integer(70) unsigned DEFAULT '1',\n  `col_bhbfokpfhm` float\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_qfmtewribz` (\n  `col_hocmjkikme` int unsigned,\n  `col_qbggcmwxyh` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NOT NULL,\n  `col_fulwqoqveo` mediumint unsigned zerofill,\n  `col_eniifaecwj` integer(159) NOT NULL DEFAULT '1',\n  PRIMARY KEY (`col_qbggcmwxyh`,`col_eniifaecwj`),\n  UNIQUE INDEX `uk_fmvsmeqnst` (`col_fulwqoqveo`),\n  CONSTRAINT `symb_xifnljgzcv` UNIQUE (`col_qbggcmwxyh`,`col_fulwqoqveo`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_odnffrvnvl` LIKE `tb_quilrfojmp`;\nCREATE TABLE `tb_lttgkqunzl` (\n  `col_nllztggwyd` smallint unsigned DEFAULT '1'\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_rkvcdukyuq` LIKE `tb_quilrfojmp`;\nCREATE TABLE `tb_erkppdannn` (\n  `col_zmjbwpsrnw` timestamp(3) NULL DEFAULT CURRENT_TIMESTAMP(3),\n  `col_qqzmxlmztj` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NULL DEFAULT 'enum_or_set_0',\n  `col_hwnlilelpf` smallint unsigned DEFAULT '1',\n  `col_oyeoemafea` date NULL DEFAULT '2019-07-04',\n  CONSTRAINT `symb_biynehpjlu` UNIQUE (`col_hwnlilelpf`,`col_oyeoemafea`),\n  CONSTRAINT `symb_yrommseaif` UNIQUE `uk_ztxuhpyaxo` (`col_zmjbwpsrnw`,`col_oyeoemafea`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_knsgjmsufx` LIKE `tb_odnffrvnvl`;\nCREATE TABLE `tb_ljqeyzesru` LIKE `tb_rpuyybsdob`;\nCREATE TABLE `tb_szlgabmztl` (\n  `col_hfydymybbg` tinytext CHARACTER SET latin1,\n  CONSTRAINT `symb_gpchhhvhwm` UNIQUE KEY (`col_hfydymybbg`(20))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_qfmtewribz` TO `tb_qeokuaneue`;\nRENAME TABLE `tb_lttgkqunzl` TO `tb_uhjgsigdfr`, `tb_erkppdannn` TO `tb_xeoclzosgr`;\nRENAME TABLE `tb_quilrfojmp` TO `tb_hycsuwyoxr`, `tb_knsgjmsufx` TO `tb_bbvvzzczcw`;\nRENAME TABLE `tb_xeoclzosgr` TO `tb_fxxptceefr`;\nRENAME TABLE `tb_odnffrvnvl` TO `tb_rtnozmledi`;\nRENAME TABLE `tb_fxxptceefr` TO `tb_tekgceqrmv`;\nRENAME TABLE `tb_hycsuwyoxr` TO `tb_hcvvpyqbtd`, `tb_szlgabmztl` TO `tb_yfjonexaag`;\nRENAME TABLE `tb_tekgceqrmv` TO `tb_wewsxxqmxd`, `tb_uhjgsigdfr` TO `tb_mbvuditpbx`;\nDROP TABLE tb_mbvuditpbx, tb_rkvcdukyuq;\nDROP TABLE tb_rtnozmledi, tb_qeokuaneue;\nCREATE TABLE `tb_quilrfojmp` (\n  `col_ruygkecjzp` longblob,\n  `col_orycjbfrss` year DEFAULT '2019',\n  `col_aqqnunnega` varbinary(225),\n  `col_pxwauaruqw` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 DEFAULT 'enum_or_set_0',\n  UNIQUE `col_ruygkecjzp` (`col_ruygkecjzp`(14),`col_orycjbfrss`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_rpuyybsdob` (\n  `col_qmvlxemsmt` datetime(6),\n  `col_wcntsrfsjf` int NULL DEFAULT '1',\n  `col_kekvofvtus` integer(70) unsigned DEFAULT '1',\n  `col_bhbfokpfhm` float\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_qfmtewribz` (\n  `col_hocmjkikme` int unsigned,\n  `col_qbggcmwxyh` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NOT NULL,\n  `col_fulwqoqveo` mediumint unsigned zerofill,\n  `col_eniifaecwj` integer(159) NOT NULL DEFAULT '1',\n  PRIMARY KEY (`col_qbggcmwxyh`,`col_eniifaecwj`),\n  UNIQUE INDEX `uk_fmvsmeqnst` (`col_fulwqoqveo`),\n  CONSTRAINT `symb_xifnljgzcv` UNIQUE (`col_qbggcmwxyh`,`col_fulwqoqveo`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_odnffrvnvl` LIKE `tb_quilrfojmp`;\nCREATE TABLE `tb_lttgkqunzl` (\n  `col_nllztggwyd` smallint unsigned DEFAULT '1'\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_rkvcdukyuq` LIKE `tb_quilrfojmp`;\nCREATE TABLE `tb_erkppdannn` (\n  `col_zmjbwpsrnw` timestamp(3) NULL DEFAULT CURRENT_TIMESTAMP(3),\n  `col_qqzmxlmztj` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NULL DEFAULT 'enum_or_set_0',\n  `col_hwnlilelpf` smallint unsigned DEFAULT '1',\n  `col_oyeoemafea` date NULL DEFAULT '2019-07-04',\n  CONSTRAINT `symb_biynehpjlu` UNIQUE (`col_hwnlilelpf`,`col_oyeoemafea`),\n  CONSTRAINT `symb_yrommseaif` UNIQUE `uk_ztxuhpyaxo` (`col_zmjbwpsrnw`,`col_oyeoemafea`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_knsgjmsufx` LIKE `tb_odnffrvnvl`;\nCREATE TABLE `tb_ljqeyzesru` LIKE `tb_rpuyybsdob`;\nCREATE TABLE `tb_szlgabmztl` (\n  `col_hfydymybbg` tinytext CHARACTER SET latin1,\n  CONSTRAINT `symb_gpchhhvhwm` UNIQUE KEY (`col_hfydymybbg`(20))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_qfmtewribz` TO `tb_qeokuaneue`;\nRENAME TABLE `tb_lttgkqunzl` TO `tb_uhjgsigdfr`, `tb_erkppdannn` TO `tb_xeoclzosgr`;\nRENAME TABLE `tb_quilrfojmp` TO `tb_hycsuwyoxr`, `tb_knsgjmsufx` TO `tb_bbvvzzczcw`;\nRENAME TABLE `tb_xeoclzosgr` TO `tb_fxxptceefr`;\nRENAME TABLE `tb_odnffrvnvl` TO `tb_rtnozmledi`;\nRENAME TABLE `tb_fxxptceefr` TO `tb_tekgceqrmv`;\nRENAME TABLE `tb_hycsuwyoxr` TO `tb_hcvvpyqbtd`, `tb_szlgabmztl` TO `tb_yfjonexaag`;\nRENAME TABLE `tb_tekgceqrmv` TO `tb_wewsxxqmxd`, `tb_uhjgsigdfr` TO `tb_mbvuditpbx`;\nDROP TABLE tb_mbvuditpbx, tb_rkvcdukyuq;\nDROP TABLE tb_rtnozmledi, tb_qeokuaneue;\nCREATE TABLE `tb_quilrfojmp` (\n  `col_ruygkecjzp` longblob,\n  `col_orycjbfrss` year DEFAULT '2019',\n  `col_aqqnunnega` varbinary(225),\n  `col_pxwauaruqw` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 DEFAULT 'enum_or_set_0',\n  UNIQUE `col_ruygkecjzp` (`col_ruygkecjzp`(14),`col_orycjbfrss`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_rpuyybsdob` (\n  `col_qmvlxemsmt` datetime(6),\n  `col_wcntsrfsjf` int NULL DEFAULT '1',\n  `col_kekvofvtus` integer(70) unsigned DEFAULT '1',\n  `col_bhbfokpfhm` float\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_qfmtewribz` (\n  `col_hocmjkikme` int unsigned,\n  `col_qbggcmwxyh` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NOT NULL,\n  `col_fulwqoqveo` mediumint unsigned zerofill,\n  `col_eniifaecwj` integer(159) NOT NULL DEFAULT '1',\n  PRIMARY KEY (`col_qbggcmwxyh`,`col_eniifaecwj`),\n  UNIQUE INDEX `uk_fmvsmeqnst` (`col_fulwqoqveo`),\n  CONSTRAINT `symb_xifnljgzcv` UNIQUE (`col_qbggcmwxyh`,`col_fulwqoqveo`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_odnffrvnvl` LIKE `tb_quilrfojmp`;\nCREATE TABLE `tb_lttgkqunzl` (\n  `col_nllztggwyd` smallint unsigned DEFAULT '1'\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_rkvcdukyuq` LIKE `tb_quilrfojmp`;\nCREATE TABLE `tb_erkppdannn` (\n  `col_zmjbwpsrnw` timestamp(3) NULL DEFAULT CURRENT_TIMESTAMP(3),\n  `col_qqzmxlmztj` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NULL DEFAULT 'enum_or_set_0',\n  `col_hwnlilelpf` smallint unsigned DEFAULT '1',\n  `col_oyeoemafea` date NULL DEFAULT '2019-07-04',\n  CONSTRAINT `symb_biynehpjlu` UNIQUE (`col_hwnlilelpf`,`col_oyeoemafea`),\n  CONSTRAINT `symb_yrommseaif` UNIQUE `uk_ztxuhpyaxo` (`col_zmjbwpsrnw`,`col_oyeoemafea`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_knsgjmsufx` LIKE `tb_odnffrvnvl`;\nCREATE TABLE `tb_ljqeyzesru` LIKE `tb_rpuyybsdob`;\nCREATE TABLE `tb_szlgabmztl` (\n  `col_hfydymybbg` tinytext CHARACTER SET latin1,\n  CONSTRAINT `symb_gpchhhvhwm` UNIQUE KEY (`col_hfydymybbg`(20))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_qfmtewribz` TO `tb_qeokuaneue`;\nRENAME TABLE `tb_lttgkqunzl` TO `tb_uhjgsigdfr`, `tb_erkppdannn` TO `tb_xeoclzosgr`;\nRENAME TABLE `tb_quilrfojmp` TO `tb_hycsuwyoxr`, `tb_knsgjmsufx` TO `tb_bbvvzzczcw`;\nRENAME TABLE `tb_xeoclzosgr` TO `tb_fxxptceefr`;\nRENAME TABLE `tb_odnffrvnvl` TO `tb_rtnozmledi`;\nRENAME TABLE `tb_fxxptceefr` TO `tb_tekgceqrmv`;\nRENAME TABLE `tb_hycsuwyoxr` TO `tb_hcvvpyqbtd`, `tb_szlgabmztl` TO `tb_yfjonexaag`;\nRENAME TABLE `tb_tekgceqrmv` TO `tb_wewsxxqmxd`, `tb_uhjgsigdfr` TO `tb_mbvuditpbx`;\nDROP TABLE tb_mbvuditpbx, tb_rkvcdukyuq;\nDROP TABLE tb_rtnozmledi, tb_qeokuaneue;\nCREATE TABLE `tb_quilrfojmp` (\n  `col_ruygkecjzp` longblob,\n  `col_orycjbfrss` year DEFAULT '2019',\n  `col_aqqnunnega` varbinary(225),\n  `col_pxwauaruqw` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 DEFAULT 'enum_or_set_0',\n  UNIQUE `col_ruygkecjzp` (`col_ruygkecjzp`(14),`col_orycjbfrss`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_rpuyybsdob` (\n  `col_qmvlxemsmt` datetime(6),\n  `col_wcntsrfsjf` int NULL DEFAULT '1',\n  `col_kekvofvtus` integer(70) unsigned DEFAULT '1',\n  `col_bhbfokpfhm` float\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_qfmtewribz` (\n  `col_hocmjkikme` int unsigned,\n  `col_qbggcmwxyh` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NOT NULL,\n  `col_fulwqoqveo` mediumint unsigned zerofill,\n  `col_eniifaecwj` integer(159) NOT NULL DEFAULT '1',\n  PRIMARY KEY (`col_qbggcmwxyh`,`col_eniifaecwj`),\n  UNIQUE INDEX `uk_fmvsmeqnst` (`col_fulwqoqveo`),\n  CONSTRAINT `symb_xifnljgzcv` UNIQUE (`col_qbggcmwxyh`,`col_fulwqoqveo`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_odnffrvnvl` LIKE `tb_quilrfojmp`;\nCREATE TABLE `tb_lttgkqunzl` (\n  `col_nllztggwyd` smallint unsigned DEFAULT '1'\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_rkvcdukyuq` LIKE `tb_quilrfojmp`;\nCREATE TABLE `tb_erkppdannn` (\n  `col_zmjbwpsrnw` timestamp(3) NULL DEFAULT CURRENT_TIMESTAMP(3),\n  `col_qqzmxlmztj` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NULL DEFAULT 'enum_or_set_0',\n  `col_hwnlilelpf` smallint unsigned DEFAULT '1',\n  `col_oyeoemafea` date NULL DEFAULT '2019-07-04',\n  CONSTRAINT `symb_biynehpjlu` UNIQUE (`col_hwnlilelpf`,`col_oyeoemafea`),\n  CONSTRAINT `symb_yrommseaif` UNIQUE `uk_ztxuhpyaxo` (`col_zmjbwpsrnw`,`col_oyeoemafea`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_knsgjmsufx` LIKE `tb_odnffrvnvl`;\nCREATE TABLE `tb_ljqeyzesru` LIKE `tb_rpuyybsdob`;\nCREATE TABLE `tb_szlgabmztl` (\n  `col_hfydymybbg` tinytext CHARACTER SET latin1,\n  CONSTRAINT `symb_gpchhhvhwm` UNIQUE KEY (`col_hfydymybbg`(20))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_qfmtewribz` TO `tb_qeokuaneue`;\nRENAME TABLE `tb_lttgkqunzl` TO `tb_uhjgsigdfr`, `tb_erkppdannn` TO `tb_xeoclzosgr`;\nRENAME TABLE `tb_quilrfojmp` TO `tb_hycsuwyoxr`, `tb_knsgjmsufx` TO `tb_bbvvzzczcw`;\nRENAME TABLE `tb_xeoclzosgr` TO `tb_fxxptceefr`;\nRENAME TABLE `tb_odnffrvnvl` TO `tb_rtnozmledi`;\nRENAME TABLE `tb_fxxptceefr` TO `tb_tekgceqrmv`;\nRENAME TABLE `tb_hycsuwyoxr` TO `tb_hcvvpyqbtd`, `tb_szlgabmztl` TO `tb_yfjonexaag`;\nRENAME TABLE `tb_tekgceqrmv` TO `tb_wewsxxqmxd`, `tb_uhjgsigdfr` TO `tb_mbvuditpbx`;\nDROP TABLE tb_mbvuditpbx, tb_rkvcdukyuq;\nDROP TABLE tb_rtnozmledi, tb_qeokuaneue;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_10.sql",
    "content": "CREATE TABLE `tb_lvhcdkkoeg` (\n  `col_psyexiqdcu` float(20),\n  CONSTRAINT UNIQUE KEY `uk_llrjshsrwa` (`col_psyexiqdcu`),\n  UNIQUE `col_psyexiqdcu` (`col_psyexiqdcu`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_ujntdzgyww` (\n  `col_mjvvyroage` longblob,\n  `col_yivxmcooat` varbinary(155) NOT NULL,\n  `col_zobuxurthc` date NULL,\n  CONSTRAINT PRIMARY KEY (`col_yivxmcooat`(10)),\n  CONSTRAINT UNIQUE KEY `uk_yjydpgltyk` (`col_zobuxurthc`),\n  UNIQUE INDEX `uk_ayltsdmkyj` (`col_mjvvyroage`(24))\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_wmoxbrqonk` LIKE `tb_lvhcdkkoeg`;\nCREATE TABLE `tb_kteiabltyy` (\n  `col_virtguzwuh` tinyblob\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_zxpkvhzoyd` LIKE `tb_kteiabltyy`;\nRENAME TABLE `tb_wmoxbrqonk` TO `tb_cwypwdifyd`;\nRENAME TABLE `tb_ujntdzgyww` TO `tb_gnhiuztkhp`, `tb_kteiabltyy` TO `tb_omxdljixxx`;\nDROP TABLE tb_zxpkvhzoyd, tb_lvhcdkkoeg;\nCREATE TABLE `tb_lvhcdkkoeg` (\n  `col_psyexiqdcu` float(20),\n  CONSTRAINT UNIQUE KEY `uk_llrjshsrwa` (`col_psyexiqdcu`),\n  UNIQUE `col_psyexiqdcu` (`col_psyexiqdcu`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_ujntdzgyww` (\n  `col_mjvvyroage` longblob,\n  `col_yivxmcooat` varbinary(155) NOT NULL,\n  `col_zobuxurthc` date NULL,\n  CONSTRAINT PRIMARY KEY (`col_yivxmcooat`(10)),\n  CONSTRAINT UNIQUE KEY `uk_yjydpgltyk` (`col_zobuxurthc`),\n  UNIQUE INDEX `uk_ayltsdmkyj` (`col_mjvvyroage`(24))\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_wmoxbrqonk` LIKE `tb_lvhcdkkoeg`;\nCREATE TABLE `tb_kteiabltyy` (\n  `col_virtguzwuh` tinyblob\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_zxpkvhzoyd` LIKE `tb_kteiabltyy`;\nRENAME TABLE `tb_wmoxbrqonk` TO `tb_cwypwdifyd`;\nRENAME TABLE `tb_ujntdzgyww` TO `tb_gnhiuztkhp`, `tb_kteiabltyy` TO `tb_omxdljixxx`;\nDROP TABLE tb_zxpkvhzoyd, tb_lvhcdkkoeg;\nCREATE TABLE `tb_lvhcdkkoeg` (\n  `col_psyexiqdcu` float(20),\n  CONSTRAINT UNIQUE KEY `uk_llrjshsrwa` (`col_psyexiqdcu`),\n  UNIQUE `col_psyexiqdcu` (`col_psyexiqdcu`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_ujntdzgyww` (\n  `col_mjvvyroage` longblob,\n  `col_yivxmcooat` varbinary(155) NOT NULL,\n  `col_zobuxurthc` date NULL,\n  CONSTRAINT PRIMARY KEY (`col_yivxmcooat`(10)),\n  CONSTRAINT UNIQUE KEY `uk_yjydpgltyk` (`col_zobuxurthc`),\n  UNIQUE INDEX `uk_ayltsdmkyj` (`col_mjvvyroage`(24))\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_wmoxbrqonk` LIKE `tb_lvhcdkkoeg`;\nCREATE TABLE `tb_kteiabltyy` (\n  `col_virtguzwuh` tinyblob\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_zxpkvhzoyd` LIKE `tb_kteiabltyy`;\nRENAME TABLE `tb_wmoxbrqonk` TO `tb_cwypwdifyd`;\nRENAME TABLE `tb_ujntdzgyww` TO `tb_gnhiuztkhp`, `tb_kteiabltyy` TO `tb_omxdljixxx`;\nDROP TABLE tb_zxpkvhzoyd, tb_lvhcdkkoeg;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_11.sql",
    "content": ""
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_12.sql",
    "content": "CREATE TABLE `tb_qhsljnukja` (\n  `col_fersnxhqir` numeric(42) NULL,\n  `col_lzdbrgiewo` tinyblob,\n  `col_xdshuwzznl` binary(156) NOT NULL,\n  `col_wguqpgfoll` double NOT NULL DEFAULT '1',\n  CONSTRAINT PRIMARY KEY (`col_xdshuwzznl`(19),`col_wguqpgfoll`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_drxwrxamak` (\n  `col_ijririnvpk` varbinary(57),\n  `col_pzzdnkysqx` int unsigned zerofill NOT NULL,\n  `col_nsnfutrvvi` double(20,8)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_rexvlcurcc` LIKE `tb_drxwrxamak`;\nCREATE TABLE `tb_exsgxyoern` (\n  `col_cnvlgnafnx` date,\n  `col_chjcwavubn` int(73) unsigned,\n  `col_jihokqqpqw` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 DEFAULT 'enum_or_set_0'\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_kjyszidrak` (\n  `col_cbvwqvuuvo` varbinary(128) NOT NULL,\n  `col_kvspyjtqjg` text CHARACTER SET utf8,\n  CONSTRAINT UNIQUE `uk_rjyzqluaky` (`col_cbvwqvuuvo`(3))\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_exsgxyoern` TO `tb_jjevlzpizx`;\nRENAME TABLE `tb_jjevlzpizx` TO `tb_bckwmwbhxe`;\nRENAME TABLE `tb_rexvlcurcc` TO `tb_reoiwwcvxn`, `tb_drxwrxamak` TO `tb_yewsyhywwt`;\nRENAME TABLE `tb_kjyszidrak` TO `tb_jaaspokopu`, `tb_reoiwwcvxn` TO `tb_zcarrcfbqk`;\nRENAME TABLE `tb_yewsyhywwt` TO `tb_qfbjzrlhat`, `tb_qhsljnukja` TO `tb_olxipktwgn`;\nDROP TABLE tb_zcarrcfbqk;\nDROP TABLE tb_bckwmwbhxe;\nDROP TABLE tb_olxipktwgn;\nDROP TABLE tb_qfbjzrlhat;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_13.sql",
    "content": "CREATE TABLE `tb_kvgymhpvjo` (\n  `col_rffhwlwajv` mediumint(89) unsigned zerofill NULL,\n  `col_drmxtsfmqu` bit(22) NOT NULL DEFAULT b'0',\n  `col_gpbdvtnnpe` bigint unsigned NULL DEFAULT '1',\n  `col_rdqhjjgkkx` double NULL DEFAULT '1',\n  CONSTRAINT UNIQUE INDEX `col_gpbdvtnnpe` (`col_gpbdvtnnpe`),\n  UNIQUE `col_rdqhjjgkkx` (`col_rdqhjjgkkx`)\n) DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_kvgymhpvjo` TO `tb_uvkwdpnuqz`;\nRENAME TABLE `tb_uvkwdpnuqz` TO `tb_iqbazrkulq`;\nRENAME TABLE `tb_iqbazrkulq` TO `tb_fvvxpqziif`;\nRENAME TABLE `tb_fvvxpqziif` TO `tb_qlcxjbcfeq`;\nRENAME TABLE `tb_qlcxjbcfeq` TO `tb_tefswwijka`;\nRENAME TABLE `tb_tefswwijka` TO `tb_nrbrxmcrnn`;\nRENAME TABLE `tb_nrbrxmcrnn` TO `tb_khrmrbvepx`;\nRENAME TABLE `tb_khrmrbvepx` TO `tb_hwzpvdoaiu`;\nRENAME TABLE `tb_hwzpvdoaiu` TO `tb_enslimtxlk`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_14.sql",
    "content": "CREATE TABLE `tb_zarsvheubd` (\n  `col_kfazghqbis` varbinary(61) NULL DEFAULT '\\0',\n  `col_ieyszubjeg` time,\n  `col_dmbvppuzgw` varbinary(167),\n  `col_dmobnapptq` mediumblob,\n  UNIQUE `col_dmbvppuzgw` (`col_dmbvppuzgw`(14))\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_aihjtxymif` (\n  `col_cnbjbdtlzc` text CHARACTER SET utf8,\n  `col_oahevgiptz` tinytext CHARACTER SET utf8\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_hkpkpbxmsl` (\n  `col_xtrkkmfmiz` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 DEFAULT 'enum_or_set_0',\n  `col_slqrzzopbp` numeric NOT NULL DEFAULT '1',\n  UNIQUE `col_xtrkkmfmiz` (`col_xtrkkmfmiz`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_zarsvheubd` TO `tb_hyfkesgbwq`, `tb_hkpkpbxmsl` TO `tb_qxnusuzetz`;\nRENAME TABLE `tb_qxnusuzetz` TO `tb_repwxdxmss`, `tb_hyfkesgbwq` TO `tb_ngxrmtcedz`;\nRENAME TABLE `tb_aihjtxymif` TO `tb_bmbzkqioww`, `tb_ngxrmtcedz` TO `tb_dqutvqabgv`;\nCREATE TABLE `tb_zarsvheubd` (\n  `col_kfazghqbis` varbinary(61) NULL DEFAULT '\\0',\n  `col_ieyszubjeg` time,\n  `col_dmbvppuzgw` varbinary(167),\n  `col_dmobnapptq` mediumblob,\n  UNIQUE `col_dmbvppuzgw` (`col_dmbvppuzgw`(14))\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_aihjtxymif` (\n  `col_cnbjbdtlzc` text CHARACTER SET utf8,\n  `col_oahevgiptz` tinytext CHARACTER SET utf8\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_hkpkpbxmsl` (\n  `col_xtrkkmfmiz` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 DEFAULT 'enum_or_set_0',\n  `col_slqrzzopbp` numeric NOT NULL DEFAULT '1',\n  UNIQUE `col_xtrkkmfmiz` (`col_xtrkkmfmiz`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_zarsvheubd` TO `tb_hyfkesgbwq`, `tb_hkpkpbxmsl` TO `tb_qxnusuzetz`;\nRENAME TABLE `tb_qxnusuzetz` TO `tb_repwxdxmss`, `tb_hyfkesgbwq` TO `tb_ngxrmtcedz`;\nRENAME TABLE `tb_aihjtxymif` TO `tb_bmbzkqioww`, `tb_ngxrmtcedz` TO `tb_dqutvqabgv`;\nCREATE TABLE `tb_zarsvheubd` (\n  `col_kfazghqbis` varbinary(61) NULL DEFAULT '\\0',\n  `col_ieyszubjeg` time,\n  `col_dmbvppuzgw` varbinary(167),\n  `col_dmobnapptq` mediumblob,\n  UNIQUE `col_dmbvppuzgw` (`col_dmbvppuzgw`(14))\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_aihjtxymif` (\n  `col_cnbjbdtlzc` text CHARACTER SET utf8,\n  `col_oahevgiptz` tinytext CHARACTER SET utf8\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_hkpkpbxmsl` (\n  `col_xtrkkmfmiz` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 DEFAULT 'enum_or_set_0',\n  `col_slqrzzopbp` numeric NOT NULL DEFAULT '1',\n  UNIQUE `col_xtrkkmfmiz` (`col_xtrkkmfmiz`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_zarsvheubd` TO `tb_hyfkesgbwq`, `tb_hkpkpbxmsl` TO `tb_qxnusuzetz`;\nRENAME TABLE `tb_qxnusuzetz` TO `tb_repwxdxmss`, `tb_hyfkesgbwq` TO `tb_ngxrmtcedz`;\nRENAME TABLE `tb_aihjtxymif` TO `tb_bmbzkqioww`, `tb_ngxrmtcedz` TO `tb_dqutvqabgv`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_15.sql",
    "content": ""
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_16.sql",
    "content": "CREATE TABLE `tb_cuyjfgcqed` (\n  `col_rrdzqbksmd` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 DEFAULT 'enum_or_set_0',\n  `col_spveduzoyj` mediumint(219) zerofill NOT NULL,\n  `col_zghtsjnauz` datetime(3) NULL\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_cuyjfgcqed` TO `tb_vtrbzichgg`;\nRENAME TABLE `tb_vtrbzichgg` TO `tb_tliqnbqkqf`;\nRENAME TABLE `tb_tliqnbqkqf` TO `tb_whudjjpowp`;\nRENAME TABLE `tb_whudjjpowp` TO `tb_bltssdqkjm`;\nRENAME TABLE `tb_bltssdqkjm` TO `tb_sqoczkufxp`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_17.sql",
    "content": "CREATE TABLE `tb_nyxoslfyhc` (\n  `col_nzrjgagsiy` smallint(162) unsigned NULL DEFAULT '1'\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_psucbscimn` (\n  `col_uhvvohvmuw` text(1272911620) CHARACTER SET utf8mb4,\n  UNIQUE `uk_ggqkubbmbr` (`col_uhvvohvmuw`(21)),\n  CONSTRAINT `symb_esejgusggh` UNIQUE (`col_uhvvohvmuw`(32))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_wbrbzvpfra` (\n  `col_lokvnorvsp` char(235) CHARACTER SET utf8mb4,\n  `col_vazlbmjjtl` char CHARACTER SET latin1,\n  `col_kcxzselokz` mediumint(229) unsigned NOT NULL DEFAULT '1',\n  `col_bjiezlcrgf` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET latin1 NOT NULL DEFAULT 'enum_or_set_0',\n  PRIMARY KEY (`col_kcxzselokz`,`col_bjiezlcrgf`),\n  CONSTRAINT `symb_ydlysvxwrf` UNIQUE `uk_qxibrmyivk` (`col_bjiezlcrgf`),\n  UNIQUE `uk_zmxfbsrjpe` (`col_bjiezlcrgf`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_ztljrixvrw` (\n  `col_xqoffthmnd` time(4) NOT NULL,\n  `col_aurisjtkrj` time DEFAULT '00:00:00',\n  PRIMARY KEY (`col_xqoffthmnd`),\n  CONSTRAINT UNIQUE INDEX `col_xqoffthmnd` (`col_xqoffthmnd`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_nsgdkkqgmo` (\n  `col_dmhcmluntp` smallint\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_nsgdkkqgmo` TO `tb_eeqakoxfof`;\nDROP TABLE tb_nyxoslfyhc;\nDROP TABLE tb_eeqakoxfof;\nDROP TABLE tb_ztljrixvrw, tb_psucbscimn;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_18.sql",
    "content": "CREATE TABLE `tb_xxepinenmi` (\n  `col_hbehuyqgfr` binary NOT NULL,\n  `col_pjrrinkrzz` longtext CHARACTER SET utf8 COLLATE utf8_unicode_ci,\n  `col_dqltdiymus` tinyblob,\n  `col_qzxbihrndq` double NULL,\n  CONSTRAINT `symb_wwzhxjsnqm` UNIQUE KEY `uk_thufyvijgg` (`col_hbehuyqgfr`,`col_dqltdiymus`(17))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_xxepinenmi` TO `tb_jtlpclaghu`;\nRENAME TABLE `tb_jtlpclaghu` TO `tb_jnjnhatfsn`;\nRENAME TABLE `tb_jnjnhatfsn` TO `tb_gkwbxrpocf`;\nRENAME TABLE `tb_gkwbxrpocf` TO `tb_idsagxrigc`;\nRENAME TABLE `tb_idsagxrigc` TO `tb_simdoexxdr`;\nRENAME TABLE `tb_simdoexxdr` TO `tb_fzypfnuvfc`;\nRENAME TABLE `tb_fzypfnuvfc` TO `tb_oplfvdflnp`;\nRENAME TABLE `tb_oplfvdflnp` TO `tb_imlfgarrjv`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_19.sql",
    "content": "CREATE TABLE `tb_imaygfshnt` (\n  `col_awltnvurel` numeric NULL DEFAULT '1',\n  `col_wbacbcxgvc` longblob,\n  `col_bewighnliy` double DEFAULT '1'\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_glxbnnkcoa` (\n  `col_ahlnhmqsql` text CHARACTER SET utf8mb4,\n  `col_blmlqemvsa` mediumblob,\n  `col_riziohykgq` decimal(9,3) NOT NULL,\n  `col_tywdbnerjb` integer(182) unsigned,\n  CONSTRAINT PRIMARY KEY (`col_riziohykgq`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_tlrqmnicwr` LIKE `tb_imaygfshnt`;\nCREATE TABLE `tb_zxnzzezzka` LIKE `tb_imaygfshnt`;\nCREATE TABLE `tb_rfagtqwznu` (\n  `col_qittiqcnvc` bit(44) DEFAULT b'0'\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_dlyfeqiynq` (\n  `col_fwwfammsnr` tinytext CHARACTER SET utf8 COLLATE utf8_unicode_ci,\n  `col_hpjlwdunhe` time,\n  CONSTRAINT `symb_hmboygosdg` UNIQUE (`col_fwwfammsnr`(31),`col_hpjlwdunhe`),\n  CONSTRAINT `symb_jtwmljwpgc` UNIQUE INDEX `uk_yehobqqoum` (`col_fwwfammsnr`(17))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_feyelhrmnv` (\n  `col_uzkloskrcr` decimal(14,3) NOT NULL,\n  `col_cmxkwhehyk` blob(1976160958),\n  PRIMARY KEY (`col_uzkloskrcr`),\n  CONSTRAINT `symb_jphlrjgdei` UNIQUE INDEX `uk_smobcykuao` (`col_cmxkwhehyk`(25))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_sxvecelfyb` (\n  `col_zoezqbning` tinyblob,\n  `col_fwuxxxpkrm` char CHARACTER SET utf8 NOT NULL,\n  `col_npwkcywzey` integer(248) zerofill NULL,\n  `col_apmomgcnou` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 NULL,\n  PRIMARY KEY (`col_fwuxxxpkrm`),\n  CONSTRAINT UNIQUE KEY `uk_hchijvhjkj` (`col_fwuxxxpkrm`,`col_apmomgcnou`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_sakzquypth` (\n  `col_onjzrgbzvg` smallint zerofill,\n  `col_eyswydvmwr` binary(217) NULL,\n  `col_ebwgvtfuic` integer unsigned DEFAULT '1',\n  `col_qndkhtfaqm` tinyblob,\n  CONSTRAINT UNIQUE `uk_ktgusajomp` (`col_eyswydvmwr`(28),`col_ebwgvtfuic`),\n  UNIQUE INDEX `col_ebwgvtfuic` (`col_ebwgvtfuic`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_zbvwgnjidh` (\n  `col_xzormknbla` int unsigned NOT NULL,\n  `col_lizstxeuhj` time(4),\n  `col_kmgfxzwfbv` time(1),\n  UNIQUE KEY `col_kmgfxzwfbv` (`col_kmgfxzwfbv`),\n  UNIQUE `col_kmgfxzwfbv_2` (`col_kmgfxzwfbv`)\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_zxnzzezzka` TO `tb_rrvwpvzswg`;\nRENAME TABLE `tb_dlyfeqiynq` TO `tb_knvlrbhvxs`;\nRENAME TABLE `tb_zbvwgnjidh` TO `tb_ruhyyyifba`, `tb_glxbnnkcoa` TO `tb_kfpeuwjwzc`;\nRENAME TABLE `tb_kfpeuwjwzc` TO `tb_zsrskpxhdj`, `tb_feyelhrmnv` TO `tb_uvinkyihqt`;\nRENAME TABLE `tb_imaygfshnt` TO `tb_kvaptpdurn`, `tb_rfagtqwznu` TO `tb_fycvzpnnaa`;\nRENAME TABLE `tb_zsrskpxhdj` TO `tb_tjoadmhvhc`;\nRENAME TABLE `tb_tjoadmhvhc` TO `tb_tvjqzqyunz`, `tb_kvaptpdurn` TO `tb_rjbzsfvdte`;\nRENAME TABLE `tb_rrvwpvzswg` TO `tb_gaubnuxkyk`;\nRENAME TABLE `tb_uvinkyihqt` TO `tb_dmkotfedww`;\nRENAME TABLE `tb_tlrqmnicwr` TO `tb_vlakuowlmg`, `tb_gaubnuxkyk` TO `tb_qfryzntbot`;\nDROP TABLE tb_tvjqzqyunz, tb_dmkotfedww;\nDROP TABLE tb_vlakuowlmg;\nDROP TABLE tb_fycvzpnnaa, tb_knvlrbhvxs;\nDROP TABLE tb_sxvecelfyb, tb_sakzquypth;\nCREATE TABLE `tb_imaygfshnt` (\n  `col_awltnvurel` numeric NULL DEFAULT '1',\n  `col_wbacbcxgvc` longblob,\n  `col_bewighnliy` double DEFAULT '1'\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_glxbnnkcoa` (\n  `col_ahlnhmqsql` text CHARACTER SET utf8mb4,\n  `col_blmlqemvsa` mediumblob,\n  `col_riziohykgq` decimal(9,3) NOT NULL,\n  `col_tywdbnerjb` integer(182) unsigned,\n  CONSTRAINT PRIMARY KEY (`col_riziohykgq`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_tlrqmnicwr` LIKE `tb_imaygfshnt`;\nCREATE TABLE `tb_zxnzzezzka` LIKE `tb_imaygfshnt`;\nCREATE TABLE `tb_rfagtqwznu` (\n  `col_qittiqcnvc` bit(44) DEFAULT b'0'\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_dlyfeqiynq` (\n  `col_fwwfammsnr` tinytext CHARACTER SET utf8 COLLATE utf8_unicode_ci,\n  `col_hpjlwdunhe` time,\n  CONSTRAINT `symb_hmboygosdg` UNIQUE (`col_fwwfammsnr`(31),`col_hpjlwdunhe`),\n  CONSTRAINT `symb_jtwmljwpgc` UNIQUE INDEX `uk_yehobqqoum` (`col_fwwfammsnr`(17))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_feyelhrmnv` (\n  `col_uzkloskrcr` decimal(14,3) NOT NULL,\n  `col_cmxkwhehyk` blob(1976160958),\n  PRIMARY KEY (`col_uzkloskrcr`),\n  CONSTRAINT `symb_jphlrjgdei` UNIQUE INDEX `uk_smobcykuao` (`col_cmxkwhehyk`(25))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_sxvecelfyb` (\n  `col_zoezqbning` tinyblob,\n  `col_fwuxxxpkrm` char CHARACTER SET utf8 NOT NULL,\n  `col_npwkcywzey` integer(248) zerofill NULL,\n  `col_apmomgcnou` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 NULL,\n  PRIMARY KEY (`col_fwuxxxpkrm`),\n  CONSTRAINT UNIQUE KEY `uk_hchijvhjkj` (`col_fwuxxxpkrm`,`col_apmomgcnou`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_sakzquypth` (\n  `col_onjzrgbzvg` smallint zerofill,\n  `col_eyswydvmwr` binary(217) NULL,\n  `col_ebwgvtfuic` integer unsigned DEFAULT '1',\n  `col_qndkhtfaqm` tinyblob,\n  CONSTRAINT UNIQUE `uk_ktgusajomp` (`col_eyswydvmwr`(28),`col_ebwgvtfuic`),\n  UNIQUE INDEX `col_ebwgvtfuic` (`col_ebwgvtfuic`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_zbvwgnjidh` (\n  `col_xzormknbla` int unsigned NOT NULL,\n  `col_lizstxeuhj` time(4),\n  `col_kmgfxzwfbv` time(1),\n  UNIQUE KEY `col_kmgfxzwfbv` (`col_kmgfxzwfbv`),\n  UNIQUE `col_kmgfxzwfbv_2` (`col_kmgfxzwfbv`)\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_zxnzzezzka` TO `tb_rrvwpvzswg`;\nRENAME TABLE `tb_dlyfeqiynq` TO `tb_knvlrbhvxs`;\nRENAME TABLE `tb_zbvwgnjidh` TO `tb_ruhyyyifba`, `tb_glxbnnkcoa` TO `tb_kfpeuwjwzc`;\nRENAME TABLE `tb_kfpeuwjwzc` TO `tb_zsrskpxhdj`, `tb_feyelhrmnv` TO `tb_uvinkyihqt`;\nRENAME TABLE `tb_imaygfshnt` TO `tb_kvaptpdurn`, `tb_rfagtqwznu` TO `tb_fycvzpnnaa`;\nRENAME TABLE `tb_zsrskpxhdj` TO `tb_tjoadmhvhc`;\nRENAME TABLE `tb_tjoadmhvhc` TO `tb_tvjqzqyunz`, `tb_kvaptpdurn` TO `tb_rjbzsfvdte`;\nRENAME TABLE `tb_rrvwpvzswg` TO `tb_gaubnuxkyk`;\nRENAME TABLE `tb_uvinkyihqt` TO `tb_dmkotfedww`;\nRENAME TABLE `tb_tlrqmnicwr` TO `tb_vlakuowlmg`, `tb_gaubnuxkyk` TO `tb_qfryzntbot`;\nDROP TABLE tb_tvjqzqyunz, tb_dmkotfedww;\nDROP TABLE tb_vlakuowlmg;\nDROP TABLE tb_fycvzpnnaa, tb_knvlrbhvxs;\nDROP TABLE tb_sxvecelfyb, tb_sakzquypth;\nCREATE TABLE `tb_imaygfshnt` (\n  `col_awltnvurel` numeric NULL DEFAULT '1',\n  `col_wbacbcxgvc` longblob,\n  `col_bewighnliy` double DEFAULT '1'\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_glxbnnkcoa` (\n  `col_ahlnhmqsql` text CHARACTER SET utf8mb4,\n  `col_blmlqemvsa` mediumblob,\n  `col_riziohykgq` decimal(9,3) NOT NULL,\n  `col_tywdbnerjb` integer(182) unsigned,\n  CONSTRAINT PRIMARY KEY (`col_riziohykgq`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_tlrqmnicwr` LIKE `tb_imaygfshnt`;\nCREATE TABLE `tb_zxnzzezzka` LIKE `tb_imaygfshnt`;\nCREATE TABLE `tb_rfagtqwznu` (\n  `col_qittiqcnvc` bit(44) DEFAULT b'0'\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_dlyfeqiynq` (\n  `col_fwwfammsnr` tinytext CHARACTER SET utf8 COLLATE utf8_unicode_ci,\n  `col_hpjlwdunhe` time,\n  CONSTRAINT `symb_hmboygosdg` UNIQUE (`col_fwwfammsnr`(31),`col_hpjlwdunhe`),\n  CONSTRAINT `symb_jtwmljwpgc` UNIQUE INDEX `uk_yehobqqoum` (`col_fwwfammsnr`(17))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_feyelhrmnv` (\n  `col_uzkloskrcr` decimal(14,3) NOT NULL,\n  `col_cmxkwhehyk` blob(1976160958),\n  PRIMARY KEY (`col_uzkloskrcr`),\n  CONSTRAINT `symb_jphlrjgdei` UNIQUE INDEX `uk_smobcykuao` (`col_cmxkwhehyk`(25))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_sxvecelfyb` (\n  `col_zoezqbning` tinyblob,\n  `col_fwuxxxpkrm` char CHARACTER SET utf8 NOT NULL,\n  `col_npwkcywzey` integer(248) zerofill NULL,\n  `col_apmomgcnou` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 NULL,\n  PRIMARY KEY (`col_fwuxxxpkrm`),\n  CONSTRAINT UNIQUE KEY `uk_hchijvhjkj` (`col_fwuxxxpkrm`,`col_apmomgcnou`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_sakzquypth` (\n  `col_onjzrgbzvg` smallint zerofill,\n  `col_eyswydvmwr` binary(217) NULL,\n  `col_ebwgvtfuic` integer unsigned DEFAULT '1',\n  `col_qndkhtfaqm` tinyblob,\n  CONSTRAINT UNIQUE `uk_ktgusajomp` (`col_eyswydvmwr`(28),`col_ebwgvtfuic`),\n  UNIQUE INDEX `col_ebwgvtfuic` (`col_ebwgvtfuic`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_zbvwgnjidh` (\n  `col_xzormknbla` int unsigned NOT NULL,\n  `col_lizstxeuhj` time(4),\n  `col_kmgfxzwfbv` time(1),\n  UNIQUE KEY `col_kmgfxzwfbv` (`col_kmgfxzwfbv`),\n  UNIQUE `col_kmgfxzwfbv_2` (`col_kmgfxzwfbv`)\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_zxnzzezzka` TO `tb_rrvwpvzswg`;\nRENAME TABLE `tb_dlyfeqiynq` TO `tb_knvlrbhvxs`;\nRENAME TABLE `tb_zbvwgnjidh` TO `tb_ruhyyyifba`, `tb_glxbnnkcoa` TO `tb_kfpeuwjwzc`;\nRENAME TABLE `tb_kfpeuwjwzc` TO `tb_zsrskpxhdj`, `tb_feyelhrmnv` TO `tb_uvinkyihqt`;\nRENAME TABLE `tb_imaygfshnt` TO `tb_kvaptpdurn`, `tb_rfagtqwznu` TO `tb_fycvzpnnaa`;\nRENAME TABLE `tb_zsrskpxhdj` TO `tb_tjoadmhvhc`;\nRENAME TABLE `tb_tjoadmhvhc` TO `tb_tvjqzqyunz`, `tb_kvaptpdurn` TO `tb_rjbzsfvdte`;\nRENAME TABLE `tb_rrvwpvzswg` TO `tb_gaubnuxkyk`;\nRENAME TABLE `tb_uvinkyihqt` TO `tb_dmkotfedww`;\nRENAME TABLE `tb_tlrqmnicwr` TO `tb_vlakuowlmg`, `tb_gaubnuxkyk` TO `tb_qfryzntbot`;\nDROP TABLE tb_tvjqzqyunz, tb_dmkotfedww;\nDROP TABLE tb_vlakuowlmg;\nDROP TABLE tb_fycvzpnnaa, tb_knvlrbhvxs;\nDROP TABLE tb_sxvecelfyb, tb_sakzquypth;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_2.sql",
    "content": ""
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_20.sql",
    "content": "CREATE TABLE `tb_erwzhsrore` (\n  `col_kxypvfvmmi` longblob,\n  `col_vjsgmnsorv` numeric(39),\n  `col_ckrshagjle` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET latin1 DEFAULT 'enum_or_set_0'\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_erwzhsrore` TO `tb_txcwnpmqeu`;\nRENAME TABLE `tb_txcwnpmqeu` TO `tb_oipniahymc`;\nRENAME TABLE `tb_oipniahymc` TO `tb_wuvzjubwfi`;\nRENAME TABLE `tb_wuvzjubwfi` TO `tb_mzejkjhdrh`;\nRENAME TABLE `tb_mzejkjhdrh` TO `tb_ljmtrrhglh`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_21.sql",
    "content": ""
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_22.sql",
    "content": "CREATE TABLE `tb_digeezyvpr` (\n  `col_obzlxjlpci` numeric(61) NULL,\n  CONSTRAINT `symb_tszhfwqpyk` UNIQUE (`col_obzlxjlpci`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_mnebelpxsl` (\n  `col_iykolxhoko` numeric(31),\n  `col_cgzreeozpp` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8,\n  `col_iraphtrlrd` varbinary(212) NOT NULL DEFAULT '\\0',\n  CONSTRAINT symb_gwsukjjxtg PRIMARY KEY (`col_iraphtrlrd`(31)),\n  UNIQUE KEY `uk_rzlfipspah` (`col_cgzreeozpp`),\n  UNIQUE `col_iraphtrlrd` (`col_iraphtrlrd`(25))\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_urqkphvawf` LIKE `tb_mnebelpxsl`;\nRENAME TABLE `tb_urqkphvawf` TO `tb_bafzppiguz`;\nRENAME TABLE `tb_digeezyvpr` TO `tb_sulmivgjpy`, `tb_bafzppiguz` TO `tb_fytbpxcdjl`;\nRENAME TABLE `tb_mnebelpxsl` TO `tb_ounmwpgnzl`, `tb_fytbpxcdjl` TO `tb_betlbqxtir`;\nRENAME TABLE `tb_betlbqxtir` TO `tb_qukciepnqi`;\nRENAME TABLE `tb_sulmivgjpy` TO `tb_mjsscuoztm`, `tb_ounmwpgnzl` TO `tb_xkdnjpdvmj`;\nRENAME TABLE `tb_xkdnjpdvmj` TO `tb_kaxlcttjna`, `tb_qukciepnqi` TO `tb_mjixwohckz`;\nRENAME TABLE `tb_mjsscuoztm` TO `tb_wdurcynllr`;\nRENAME TABLE `tb_kaxlcttjna` TO `tb_ayzakpuupb`;\nCREATE TABLE `tb_digeezyvpr` (\n  `col_obzlxjlpci` numeric(61) NULL,\n  CONSTRAINT `symb_tszhfwqpyk` UNIQUE (`col_obzlxjlpci`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_mnebelpxsl` (\n  `col_iykolxhoko` numeric(31),\n  `col_cgzreeozpp` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8,\n  `col_iraphtrlrd` varbinary(212) NOT NULL DEFAULT '\\0',\n  CONSTRAINT symb_gwsukjjxtg PRIMARY KEY (`col_iraphtrlrd`(31)),\n  UNIQUE KEY `uk_rzlfipspah` (`col_cgzreeozpp`),\n  UNIQUE `col_iraphtrlrd` (`col_iraphtrlrd`(25))\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_urqkphvawf` LIKE `tb_mnebelpxsl`;\nRENAME TABLE `tb_urqkphvawf` TO `tb_bafzppiguz`;\nRENAME TABLE `tb_digeezyvpr` TO `tb_sulmivgjpy`, `tb_bafzppiguz` TO `tb_fytbpxcdjl`;\nRENAME TABLE `tb_mnebelpxsl` TO `tb_ounmwpgnzl`, `tb_fytbpxcdjl` TO `tb_betlbqxtir`;\nRENAME TABLE `tb_betlbqxtir` TO `tb_qukciepnqi`;\nRENAME TABLE `tb_sulmivgjpy` TO `tb_mjsscuoztm`, `tb_ounmwpgnzl` TO `tb_xkdnjpdvmj`;\nRENAME TABLE `tb_xkdnjpdvmj` TO `tb_kaxlcttjna`, `tb_qukciepnqi` TO `tb_mjixwohckz`;\nRENAME TABLE `tb_mjsscuoztm` TO `tb_wdurcynllr`;\nRENAME TABLE `tb_kaxlcttjna` TO `tb_ayzakpuupb`;\nCREATE TABLE `tb_digeezyvpr` (\n  `col_obzlxjlpci` numeric(61) NULL,\n  CONSTRAINT `symb_tszhfwqpyk` UNIQUE (`col_obzlxjlpci`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_mnebelpxsl` (\n  `col_iykolxhoko` numeric(31),\n  `col_cgzreeozpp` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8,\n  `col_iraphtrlrd` varbinary(212) NOT NULL DEFAULT '\\0',\n  CONSTRAINT symb_gwsukjjxtg PRIMARY KEY (`col_iraphtrlrd`(31)),\n  UNIQUE KEY `uk_rzlfipspah` (`col_cgzreeozpp`),\n  UNIQUE `col_iraphtrlrd` (`col_iraphtrlrd`(25))\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_urqkphvawf` LIKE `tb_mnebelpxsl`;\nRENAME TABLE `tb_urqkphvawf` TO `tb_bafzppiguz`;\nRENAME TABLE `tb_digeezyvpr` TO `tb_sulmivgjpy`, `tb_bafzppiguz` TO `tb_fytbpxcdjl`;\nRENAME TABLE `tb_mnebelpxsl` TO `tb_ounmwpgnzl`, `tb_fytbpxcdjl` TO `tb_betlbqxtir`;\nRENAME TABLE `tb_betlbqxtir` TO `tb_qukciepnqi`;\nRENAME TABLE `tb_sulmivgjpy` TO `tb_mjsscuoztm`, `tb_ounmwpgnzl` TO `tb_xkdnjpdvmj`;\nRENAME TABLE `tb_xkdnjpdvmj` TO `tb_kaxlcttjna`, `tb_qukciepnqi` TO `tb_mjixwohckz`;\nRENAME TABLE `tb_mjsscuoztm` TO `tb_wdurcynllr`;\nRENAME TABLE `tb_kaxlcttjna` TO `tb_ayzakpuupb`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_23.sql",
    "content": "CREATE TABLE `tb_njzmhqupzv` (\n  `col_aiifakdklr` datetime(6) NULL,\n  `col_ulzkdgcmmu` time,\n  CONSTRAINT UNIQUE INDEX `uk_ikryxrhfhx` (`col_aiifakdklr`),\n  UNIQUE `uk_ckiseqvinv` (`col_aiifakdklr`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_nzgqzlyxvk` (\n  `col_quthabfydl` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 COLLATE utf8_unicode_ci,\n  `col_bpzwhwubra` int(118) unsigned DEFAULT '1',\n  `col_fpkljodgme` time NULL,\n  `col_zxdapdqzmv` blob,\n  CONSTRAINT `symb_sdbjebxsqk` UNIQUE `uk_vuzkhjajdc` (`col_bpzwhwubra`,`col_fpkljodgme`),\n  UNIQUE `uk_zknetkwpoq` (`col_fpkljodgme`,`col_zxdapdqzmv`(28))\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_dngwjiipsz` (\n  `col_thwosnwagl` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_dngwjiipsz` TO `tb_hdjifcvgjr`;\nRENAME TABLE `tb_hdjifcvgjr` TO `tb_nrcqacgrqr`, `tb_nzgqzlyxvk` TO `tb_pfzkhfodcd`;\nRENAME TABLE `tb_pfzkhfodcd` TO `tb_rvvolpepuv`;\nRENAME TABLE `tb_njzmhqupzv` TO `tb_oqkzkbtfiz`;\nRENAME TABLE `tb_nrcqacgrqr` TO `tb_roetequbaj`, `tb_rvvolpepuv` TO `tb_gvxwgsxgte`;\nRENAME TABLE `tb_oqkzkbtfiz` TO `tb_xsfqjfgvfq`;\nRENAME TABLE `tb_xsfqjfgvfq` TO `tb_sxvwhxpswg`, `tb_roetequbaj` TO `tb_cfukmqodyg`;\nRENAME TABLE `tb_sxvwhxpswg` TO `tb_cfxrlacwgr`, `tb_cfukmqodyg` TO `tb_oytmynjdbq`;\nRENAME TABLE `tb_cfxrlacwgr` TO `tb_xhvastkmfw`;\nRENAME TABLE `tb_xhvastkmfw` TO `tb_wtwwuhhmqp`;\nCREATE TABLE `tb_njzmhqupzv` (\n  `col_aiifakdklr` datetime(6) NULL,\n  `col_ulzkdgcmmu` time,\n  CONSTRAINT UNIQUE INDEX `uk_ikryxrhfhx` (`col_aiifakdklr`),\n  UNIQUE `uk_ckiseqvinv` (`col_aiifakdklr`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_nzgqzlyxvk` (\n  `col_quthabfydl` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 COLLATE utf8_unicode_ci,\n  `col_bpzwhwubra` int(118) unsigned DEFAULT '1',\n  `col_fpkljodgme` time NULL,\n  `col_zxdapdqzmv` blob,\n  CONSTRAINT `symb_sdbjebxsqk` UNIQUE `uk_vuzkhjajdc` (`col_bpzwhwubra`,`col_fpkljodgme`),\n  UNIQUE `uk_zknetkwpoq` (`col_fpkljodgme`,`col_zxdapdqzmv`(28))\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_dngwjiipsz` (\n  `col_thwosnwagl` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_dngwjiipsz` TO `tb_hdjifcvgjr`;\nRENAME TABLE `tb_hdjifcvgjr` TO `tb_nrcqacgrqr`, `tb_nzgqzlyxvk` TO `tb_pfzkhfodcd`;\nRENAME TABLE `tb_pfzkhfodcd` TO `tb_rvvolpepuv`;\nRENAME TABLE `tb_njzmhqupzv` TO `tb_oqkzkbtfiz`;\nRENAME TABLE `tb_nrcqacgrqr` TO `tb_roetequbaj`, `tb_rvvolpepuv` TO `tb_gvxwgsxgte`;\nRENAME TABLE `tb_oqkzkbtfiz` TO `tb_xsfqjfgvfq`;\nRENAME TABLE `tb_xsfqjfgvfq` TO `tb_sxvwhxpswg`, `tb_roetequbaj` TO `tb_cfukmqodyg`;\nRENAME TABLE `tb_sxvwhxpswg` TO `tb_cfxrlacwgr`, `tb_cfukmqodyg` TO `tb_oytmynjdbq`;\nRENAME TABLE `tb_cfxrlacwgr` TO `tb_xhvastkmfw`;\nRENAME TABLE `tb_xhvastkmfw` TO `tb_wtwwuhhmqp`;\nCREATE TABLE `tb_njzmhqupzv` (\n  `col_aiifakdklr` datetime(6) NULL,\n  `col_ulzkdgcmmu` time,\n  CONSTRAINT UNIQUE INDEX `uk_ikryxrhfhx` (`col_aiifakdklr`),\n  UNIQUE `uk_ckiseqvinv` (`col_aiifakdklr`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_nzgqzlyxvk` (\n  `col_quthabfydl` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 COLLATE utf8_unicode_ci,\n  `col_bpzwhwubra` int(118) unsigned DEFAULT '1',\n  `col_fpkljodgme` time NULL,\n  `col_zxdapdqzmv` blob,\n  CONSTRAINT `symb_sdbjebxsqk` UNIQUE `uk_vuzkhjajdc` (`col_bpzwhwubra`,`col_fpkljodgme`),\n  UNIQUE `uk_zknetkwpoq` (`col_fpkljodgme`,`col_zxdapdqzmv`(28))\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_dngwjiipsz` (\n  `col_thwosnwagl` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_dngwjiipsz` TO `tb_hdjifcvgjr`;\nRENAME TABLE `tb_hdjifcvgjr` TO `tb_nrcqacgrqr`, `tb_nzgqzlyxvk` TO `tb_pfzkhfodcd`;\nRENAME TABLE `tb_pfzkhfodcd` TO `tb_rvvolpepuv`;\nRENAME TABLE `tb_njzmhqupzv` TO `tb_oqkzkbtfiz`;\nRENAME TABLE `tb_nrcqacgrqr` TO `tb_roetequbaj`, `tb_rvvolpepuv` TO `tb_gvxwgsxgte`;\nRENAME TABLE `tb_oqkzkbtfiz` TO `tb_xsfqjfgvfq`;\nRENAME TABLE `tb_xsfqjfgvfq` TO `tb_sxvwhxpswg`, `tb_roetequbaj` TO `tb_cfukmqodyg`;\nRENAME TABLE `tb_sxvwhxpswg` TO `tb_cfxrlacwgr`, `tb_cfukmqodyg` TO `tb_oytmynjdbq`;\nRENAME TABLE `tb_cfxrlacwgr` TO `tb_xhvastkmfw`;\nRENAME TABLE `tb_xhvastkmfw` TO `tb_wtwwuhhmqp`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_24.sql",
    "content": ""
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_25.sql",
    "content": "CREATE TABLE `tb_qwatgwvady` (\n  `col_ryksixnuqb` float NOT NULL DEFAULT '1',\n  `col_uvfgzqiidt` decimal NULL DEFAULT '1',\n  CONSTRAINT `symb_mayavottkb` UNIQUE `uk_eipadvxxrr` (`col_uvfgzqiidt`)\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_qwatgwvady` TO `tb_psqgyghpog`;\nRENAME TABLE `tb_psqgyghpog` TO `tb_yswokmohrm`;\nRENAME TABLE `tb_yswokmohrm` TO `tb_jlrosctdeg`;\nRENAME TABLE `tb_jlrosctdeg` TO `tb_gbxuwplthj`;\nRENAME TABLE `tb_gbxuwplthj` TO `tb_yduqcvunha`;\nRENAME TABLE `tb_yduqcvunha` TO `tb_woqjkdejpu`;\nRENAME TABLE `tb_woqjkdejpu` TO `tb_mzhqjoqwim`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_26.sql",
    "content": ""
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_27.sql",
    "content": ""
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_28.sql",
    "content": "CREATE TABLE `tb_wtzuiwpsao` (\n  `col_ykpxfugemh` longblob,\n  `col_xxtvhkkirw` float DEFAULT '1',\n  UNIQUE INDEX `col_ykpxfugemh` (`col_ykpxfugemh`(24),`col_xxtvhkkirw`),\n  UNIQUE `uk_hzcjlivdvu` (`col_xxtvhkkirw`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_wtzuiwpsao` TO `tb_pqgknpjjfb`;\nRENAME TABLE `tb_pqgknpjjfb` TO `tb_cbvdvfenvd`;\nRENAME TABLE `tb_cbvdvfenvd` TO `tb_nseikjdsdh`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_29.sql",
    "content": "CREATE TABLE `tb_wczdgujkxe` (\n  `col_mprviuzmsa` mediumint(215) unsigned zerofill,\n  `col_wmnengkfur` decimal(6) NOT NULL,\n  `col_toueuqhkhc` text(1378767894) CHARACTER SET utf8mb4,\n  CONSTRAINT PRIMARY KEY (`col_wmnengkfur`),\n  CONSTRAINT `symb_ytbnzrnwgs` UNIQUE (`col_toueuqhkhc`(31)),\n  UNIQUE KEY `col_mprviuzmsa` (`col_mprviuzmsa`,`col_wmnengkfur`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_cvcsopmfuk` LIKE `tb_wczdgujkxe`;\nRENAME TABLE `tb_wczdgujkxe` TO `tb_alxysrcrzk`, `tb_cvcsopmfuk` TO `tb_bcgwxxtrfr`;\nRENAME TABLE `tb_bcgwxxtrfr` TO `tb_qfvsxuvwcl`, `tb_alxysrcrzk` TO `tb_esuwpuxvcf`;\nRENAME TABLE `tb_qfvsxuvwcl` TO `tb_nsqdmubznz`, `tb_esuwpuxvcf` TO `tb_rmphoinujw`;\nRENAME TABLE `tb_nsqdmubznz` TO `tb_fgebibysbk`, `tb_rmphoinujw` TO `tb_xntcbmvmxc`;\nRENAME TABLE `tb_xntcbmvmxc` TO `tb_jmydpaxtpu`, `tb_fgebibysbk` TO `tb_bkldmexfby`;\nCREATE TABLE `tb_wczdgujkxe` (\n  `col_mprviuzmsa` mediumint(215) unsigned zerofill,\n  `col_wmnengkfur` decimal(6) NOT NULL,\n  `col_toueuqhkhc` text(1378767894) CHARACTER SET utf8mb4,\n  CONSTRAINT PRIMARY KEY (`col_wmnengkfur`),\n  CONSTRAINT `symb_ytbnzrnwgs` UNIQUE (`col_toueuqhkhc`(31)),\n  UNIQUE KEY `col_mprviuzmsa` (`col_mprviuzmsa`,`col_wmnengkfur`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_cvcsopmfuk` LIKE `tb_wczdgujkxe`;\nRENAME TABLE `tb_wczdgujkxe` TO `tb_alxysrcrzk`, `tb_cvcsopmfuk` TO `tb_bcgwxxtrfr`;\nRENAME TABLE `tb_bcgwxxtrfr` TO `tb_qfvsxuvwcl`, `tb_alxysrcrzk` TO `tb_esuwpuxvcf`;\nRENAME TABLE `tb_qfvsxuvwcl` TO `tb_nsqdmubznz`, `tb_esuwpuxvcf` TO `tb_rmphoinujw`;\nRENAME TABLE `tb_nsqdmubznz` TO `tb_fgebibysbk`, `tb_rmphoinujw` TO `tb_xntcbmvmxc`;\nRENAME TABLE `tb_xntcbmvmxc` TO `tb_jmydpaxtpu`, `tb_fgebibysbk` TO `tb_bkldmexfby`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_3.sql",
    "content": "CREATE TABLE `tb_iijmabwugl` (\n  `col_mpmyypobxf` blob(201306668),\n  `col_vdicnalzyn` timestamp,\n  CONSTRAINT symb_awswjgntin PRIMARY KEY (`col_vdicnalzyn`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_vfsmhwugkr` LIKE `tb_iijmabwugl`;\nRENAME TABLE `tb_vfsmhwugkr` TO `tb_glwwpfhvmj`;\nRENAME TABLE `tb_iijmabwugl` TO `tb_akohtxnugs`;\nRENAME TABLE `tb_akohtxnugs` TO `tb_vnhalkabwa`;\nRENAME TABLE `tb_glwwpfhvmj` TO `tb_fkblfjsafc`;\nRENAME TABLE `tb_vnhalkabwa` TO `tb_vedbpoigoe`, `tb_fkblfjsafc` TO `tb_kscbslxbld`;\nRENAME TABLE `tb_vedbpoigoe` TO `tb_bfwxsithpl`;\nRENAME TABLE `tb_kscbslxbld` TO `tb_vtebiiikpq`, `tb_bfwxsithpl` TO `tb_wtkguyclio`;\nRENAME TABLE `tb_wtkguyclio` TO `tb_jwvvotdbbm`, `tb_vtebiiikpq` TO `tb_jvoxbppagi`;\nRENAME TABLE `tb_jwvvotdbbm` TO `tb_ctxyxxbpqn`;\nRENAME TABLE `tb_jvoxbppagi` TO `tb_uasvccezbb`;\nCREATE TABLE `tb_iijmabwugl` (\n  `col_mpmyypobxf` blob(201306668),\n  `col_vdicnalzyn` timestamp,\n  CONSTRAINT symb_awswjgntin PRIMARY KEY (`col_vdicnalzyn`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_vfsmhwugkr` LIKE `tb_iijmabwugl`;\nRENAME TABLE `tb_vfsmhwugkr` TO `tb_glwwpfhvmj`;\nRENAME TABLE `tb_iijmabwugl` TO `tb_akohtxnugs`;\nRENAME TABLE `tb_akohtxnugs` TO `tb_vnhalkabwa`;\nRENAME TABLE `tb_glwwpfhvmj` TO `tb_fkblfjsafc`;\nRENAME TABLE `tb_vnhalkabwa` TO `tb_vedbpoigoe`, `tb_fkblfjsafc` TO `tb_kscbslxbld`;\nRENAME TABLE `tb_vedbpoigoe` TO `tb_bfwxsithpl`;\nRENAME TABLE `tb_kscbslxbld` TO `tb_vtebiiikpq`, `tb_bfwxsithpl` TO `tb_wtkguyclio`;\nRENAME TABLE `tb_wtkguyclio` TO `tb_jwvvotdbbm`, `tb_vtebiiikpq` TO `tb_jvoxbppagi`;\nRENAME TABLE `tb_jwvvotdbbm` TO `tb_ctxyxxbpqn`;\nRENAME TABLE `tb_jvoxbppagi` TO `tb_uasvccezbb`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_30.sql",
    "content": "CREATE TABLE `tb_hxrlnujcrv` (\n  `col_fkstgdmdmv` varbinary(215) DEFAULT '\\0',\n  `col_oyzofwwoch` mediumblob,\n  `col_exhsgobpvc` tinyint(246) zerofill NOT NULL,\n  `col_ypcuorizvb` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 NULL DEFAULT 'enum_or_set_0',\n  PRIMARY KEY (`col_exhsgobpvc`),\n  CONSTRAINT UNIQUE `col_exhsgobpvc` (`col_exhsgobpvc`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_njohawksae` (\n  `col_knuawjkxqc` year DEFAULT '2019',\n  `col_bhfbpfgzco` mediumtext CHARACTER SET utf8,\n  `col_aqkzimqpda` bit(37) DEFAULT b'0',\n  CONSTRAINT UNIQUE `uk_enknmzojsn` (`col_knuawjkxqc`),\n  UNIQUE KEY `col_aqkzimqpda` (`col_aqkzimqpda`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_iztgdcpcld` (\n  `col_rvnhrlexjo` time DEFAULT '00:00:00',\n  `col_fwwgntdsdt` smallint zerofill,\n  `col_yxejjdacht` int(213) zerofill NOT NULL,\n  UNIQUE KEY `uk_svckkuvqce` (`col_rvnhrlexjo`,`col_fwwgntdsdt`),\n  UNIQUE INDEX `uk_amgxauyvbp` (`col_rvnhrlexjo`,`col_fwwgntdsdt`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_lsynbmkqdy` LIKE `tb_hxrlnujcrv`;\nCREATE TABLE `tb_lqihveibyp` (\n  `col_ttqqizkwig` bit(43) NULL DEFAULT b'0',\n  `col_yvgpfjhjcj` timestamp(5) NULL,\n  `col_cuvrdliegh` mediumint unsigned zerofill\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_vkycuerrcd` (\n  `col_ennnhbifuc` tinytext CHARACTER SET utf8,\n  `col_argkmjdhlo` text(1982098738) CHARACTER SET utf8,\n  `col_nkqouukkqn` date DEFAULT '2019-07-04',\n  CONSTRAINT `symb_rkcyrcasyq` UNIQUE `uk_dmsqvpcazv` (`col_nkqouukkqn`),\n  UNIQUE KEY `uk_stwkfixzhd` (`col_ennnhbifuc`(11),`col_nkqouukkqn`)\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_njohawksae` TO `tb_gcvlfgdqvw`;\nRENAME TABLE `tb_lqihveibyp` TO `tb_sugaoprlwz`;\nRENAME TABLE `tb_hxrlnujcrv` TO `tb_qqtidoozva`;\nRENAME TABLE `tb_sugaoprlwz` TO `tb_kubnsybcaf`;\nRENAME TABLE `tb_lsynbmkqdy` TO `tb_ssvyhzkjrr`;\nRENAME TABLE `tb_vkycuerrcd` TO `tb_skbxuhpnhx`, `tb_gcvlfgdqvw` TO `tb_evibhvcuqj`;\nRENAME TABLE `tb_skbxuhpnhx` TO `tb_qlelzwesdb`, `tb_qqtidoozva` TO `tb_bjsplgjemd`;\nRENAME TABLE `tb_ssvyhzkjrr` TO `tb_dxadqwfhhb`, `tb_evibhvcuqj` TO `tb_zflebwrowg`;\nDROP TABLE tb_zflebwrowg;\nDROP TABLE tb_qlelzwesdb;\nCREATE TABLE `tb_hxrlnujcrv` (\n  `col_fkstgdmdmv` varbinary(215) DEFAULT '\\0',\n  `col_oyzofwwoch` mediumblob,\n  `col_exhsgobpvc` tinyint(246) zerofill NOT NULL,\n  `col_ypcuorizvb` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 NULL DEFAULT 'enum_or_set_0',\n  PRIMARY KEY (`col_exhsgobpvc`),\n  CONSTRAINT UNIQUE `col_exhsgobpvc` (`col_exhsgobpvc`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_njohawksae` (\n  `col_knuawjkxqc` year DEFAULT '2019',\n  `col_bhfbpfgzco` mediumtext CHARACTER SET utf8,\n  `col_aqkzimqpda` bit(37) DEFAULT b'0',\n  CONSTRAINT UNIQUE `uk_enknmzojsn` (`col_knuawjkxqc`),\n  UNIQUE KEY `col_aqkzimqpda` (`col_aqkzimqpda`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_iztgdcpcld` (\n  `col_rvnhrlexjo` time DEFAULT '00:00:00',\n  `col_fwwgntdsdt` smallint zerofill,\n  `col_yxejjdacht` int(213) zerofill NOT NULL,\n  UNIQUE KEY `uk_svckkuvqce` (`col_rvnhrlexjo`,`col_fwwgntdsdt`),\n  UNIQUE INDEX `uk_amgxauyvbp` (`col_rvnhrlexjo`,`col_fwwgntdsdt`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_lsynbmkqdy` LIKE `tb_hxrlnujcrv`;\nCREATE TABLE `tb_lqihveibyp` (\n  `col_ttqqizkwig` bit(43) NULL DEFAULT b'0',\n  `col_yvgpfjhjcj` timestamp(5) NULL,\n  `col_cuvrdliegh` mediumint unsigned zerofill\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_vkycuerrcd` (\n  `col_ennnhbifuc` tinytext CHARACTER SET utf8,\n  `col_argkmjdhlo` text(1982098738) CHARACTER SET utf8,\n  `col_nkqouukkqn` date DEFAULT '2019-07-04',\n  CONSTRAINT `symb_rkcyrcasyq` UNIQUE `uk_dmsqvpcazv` (`col_nkqouukkqn`),\n  UNIQUE KEY `uk_stwkfixzhd` (`col_ennnhbifuc`(11),`col_nkqouukkqn`)\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_njohawksae` TO `tb_gcvlfgdqvw`;\nRENAME TABLE `tb_lqihveibyp` TO `tb_sugaoprlwz`;\nRENAME TABLE `tb_hxrlnujcrv` TO `tb_qqtidoozva`;\nRENAME TABLE `tb_sugaoprlwz` TO `tb_kubnsybcaf`;\nRENAME TABLE `tb_lsynbmkqdy` TO `tb_ssvyhzkjrr`;\nRENAME TABLE `tb_vkycuerrcd` TO `tb_skbxuhpnhx`, `tb_gcvlfgdqvw` TO `tb_evibhvcuqj`;\nRENAME TABLE `tb_skbxuhpnhx` TO `tb_qlelzwesdb`, `tb_qqtidoozva` TO `tb_bjsplgjemd`;\nRENAME TABLE `tb_ssvyhzkjrr` TO `tb_dxadqwfhhb`, `tb_evibhvcuqj` TO `tb_zflebwrowg`;\nDROP TABLE tb_zflebwrowg;\nDROP TABLE tb_qlelzwesdb;\nCREATE TABLE `tb_hxrlnujcrv` (\n  `col_fkstgdmdmv` varbinary(215) DEFAULT '\\0',\n  `col_oyzofwwoch` mediumblob,\n  `col_exhsgobpvc` tinyint(246) zerofill NOT NULL,\n  `col_ypcuorizvb` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 NULL DEFAULT 'enum_or_set_0',\n  PRIMARY KEY (`col_exhsgobpvc`),\n  CONSTRAINT UNIQUE `col_exhsgobpvc` (`col_exhsgobpvc`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_njohawksae` (\n  `col_knuawjkxqc` year DEFAULT '2019',\n  `col_bhfbpfgzco` mediumtext CHARACTER SET utf8,\n  `col_aqkzimqpda` bit(37) DEFAULT b'0',\n  CONSTRAINT UNIQUE `uk_enknmzojsn` (`col_knuawjkxqc`),\n  UNIQUE KEY `col_aqkzimqpda` (`col_aqkzimqpda`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_iztgdcpcld` (\n  `col_rvnhrlexjo` time DEFAULT '00:00:00',\n  `col_fwwgntdsdt` smallint zerofill,\n  `col_yxejjdacht` int(213) zerofill NOT NULL,\n  UNIQUE KEY `uk_svckkuvqce` (`col_rvnhrlexjo`,`col_fwwgntdsdt`),\n  UNIQUE INDEX `uk_amgxauyvbp` (`col_rvnhrlexjo`,`col_fwwgntdsdt`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_lsynbmkqdy` LIKE `tb_hxrlnujcrv`;\nCREATE TABLE `tb_lqihveibyp` (\n  `col_ttqqizkwig` bit(43) NULL DEFAULT b'0',\n  `col_yvgpfjhjcj` timestamp(5) NULL,\n  `col_cuvrdliegh` mediumint unsigned zerofill\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_vkycuerrcd` (\n  `col_ennnhbifuc` tinytext CHARACTER SET utf8,\n  `col_argkmjdhlo` text(1982098738) CHARACTER SET utf8,\n  `col_nkqouukkqn` date DEFAULT '2019-07-04',\n  CONSTRAINT `symb_rkcyrcasyq` UNIQUE `uk_dmsqvpcazv` (`col_nkqouukkqn`),\n  UNIQUE KEY `uk_stwkfixzhd` (`col_ennnhbifuc`(11),`col_nkqouukkqn`)\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_njohawksae` TO `tb_gcvlfgdqvw`;\nRENAME TABLE `tb_lqihveibyp` TO `tb_sugaoprlwz`;\nRENAME TABLE `tb_hxrlnujcrv` TO `tb_qqtidoozva`;\nRENAME TABLE `tb_sugaoprlwz` TO `tb_kubnsybcaf`;\nRENAME TABLE `tb_lsynbmkqdy` TO `tb_ssvyhzkjrr`;\nRENAME TABLE `tb_vkycuerrcd` TO `tb_skbxuhpnhx`, `tb_gcvlfgdqvw` TO `tb_evibhvcuqj`;\nRENAME TABLE `tb_skbxuhpnhx` TO `tb_qlelzwesdb`, `tb_qqtidoozva` TO `tb_bjsplgjemd`;\nRENAME TABLE `tb_ssvyhzkjrr` TO `tb_dxadqwfhhb`, `tb_evibhvcuqj` TO `tb_zflebwrowg`;\nDROP TABLE tb_zflebwrowg;\nDROP TABLE tb_qlelzwesdb;\nCREATE TABLE `tb_hxrlnujcrv` (\n  `col_fkstgdmdmv` varbinary(215) DEFAULT '\\0',\n  `col_oyzofwwoch` mediumblob,\n  `col_exhsgobpvc` tinyint(246) zerofill NOT NULL,\n  `col_ypcuorizvb` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 NULL DEFAULT 'enum_or_set_0',\n  PRIMARY KEY (`col_exhsgobpvc`),\n  CONSTRAINT UNIQUE `col_exhsgobpvc` (`col_exhsgobpvc`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_njohawksae` (\n  `col_knuawjkxqc` year DEFAULT '2019',\n  `col_bhfbpfgzco` mediumtext CHARACTER SET utf8,\n  `col_aqkzimqpda` bit(37) DEFAULT b'0',\n  CONSTRAINT UNIQUE `uk_enknmzojsn` (`col_knuawjkxqc`),\n  UNIQUE KEY `col_aqkzimqpda` (`col_aqkzimqpda`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_iztgdcpcld` (\n  `col_rvnhrlexjo` time DEFAULT '00:00:00',\n  `col_fwwgntdsdt` smallint zerofill,\n  `col_yxejjdacht` int(213) zerofill NOT NULL,\n  UNIQUE KEY `uk_svckkuvqce` (`col_rvnhrlexjo`,`col_fwwgntdsdt`),\n  UNIQUE INDEX `uk_amgxauyvbp` (`col_rvnhrlexjo`,`col_fwwgntdsdt`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_lsynbmkqdy` LIKE `tb_hxrlnujcrv`;\nCREATE TABLE `tb_lqihveibyp` (\n  `col_ttqqizkwig` bit(43) NULL DEFAULT b'0',\n  `col_yvgpfjhjcj` timestamp(5) NULL,\n  `col_cuvrdliegh` mediumint unsigned zerofill\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_vkycuerrcd` (\n  `col_ennnhbifuc` tinytext CHARACTER SET utf8,\n  `col_argkmjdhlo` text(1982098738) CHARACTER SET utf8,\n  `col_nkqouukkqn` date DEFAULT '2019-07-04',\n  CONSTRAINT `symb_rkcyrcasyq` UNIQUE `uk_dmsqvpcazv` (`col_nkqouukkqn`),\n  UNIQUE KEY `uk_stwkfixzhd` (`col_ennnhbifuc`(11),`col_nkqouukkqn`)\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_njohawksae` TO `tb_gcvlfgdqvw`;\nRENAME TABLE `tb_lqihveibyp` TO `tb_sugaoprlwz`;\nRENAME TABLE `tb_hxrlnujcrv` TO `tb_qqtidoozva`;\nRENAME TABLE `tb_sugaoprlwz` TO `tb_kubnsybcaf`;\nRENAME TABLE `tb_lsynbmkqdy` TO `tb_ssvyhzkjrr`;\nRENAME TABLE `tb_vkycuerrcd` TO `tb_skbxuhpnhx`, `tb_gcvlfgdqvw` TO `tb_evibhvcuqj`;\nRENAME TABLE `tb_skbxuhpnhx` TO `tb_qlelzwesdb`, `tb_qqtidoozva` TO `tb_bjsplgjemd`;\nRENAME TABLE `tb_ssvyhzkjrr` TO `tb_dxadqwfhhb`, `tb_evibhvcuqj` TO `tb_zflebwrowg`;\nDROP TABLE tb_zflebwrowg;\nDROP TABLE tb_qlelzwesdb;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_31.sql",
    "content": ""
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_32.sql",
    "content": "CREATE TABLE `tb_zcpikjbepd` (\n  `col_srfyjibwff` time(6),\n  UNIQUE INDEX `uk_sncbjfknhk` (`col_srfyjibwff`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_aebfpjscsh` (\n  `col_dqrslyzpwh` longtext CHARACTER SET utf8 COLLATE utf8_unicode_ci,\n  `col_fcmimikjdw` date,\n  `col_wkslgjtpww` numeric(11,5) NOT NULL\n) DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_aebfpjscsh` TO `tb_ykxgxejkaq`, `tb_zcpikjbepd` TO `tb_ytmcrypwgh`;\nRENAME TABLE `tb_ytmcrypwgh` TO `tb_qfzylchmgx`, `tb_ykxgxejkaq` TO `tb_ilbncnlius`;\nRENAME TABLE `tb_qfzylchmgx` TO `tb_ebiflclztu`, `tb_ilbncnlius` TO `tb_mmagndfxbt`;\nRENAME TABLE `tb_mmagndfxbt` TO `tb_csccikqqvg`, `tb_ebiflclztu` TO `tb_gygmqyoqqr`;\nRENAME TABLE `tb_csccikqqvg` TO `tb_kevrglmsfn`, `tb_gygmqyoqqr` TO `tb_ujvpffcyig`;\nRENAME TABLE `tb_ujvpffcyig` TO `tb_jjsvaaoyby`, `tb_kevrglmsfn` TO `tb_dscfwlikgh`;\nRENAME TABLE `tb_jjsvaaoyby` TO `tb_cvnlurvcrp`, `tb_dscfwlikgh` TO `tb_tfoduoghfr`;\nRENAME TABLE `tb_cvnlurvcrp` TO `tb_hfshgmpqaf`, `tb_tfoduoghfr` TO `tb_pzwwwbdsee`;\nRENAME TABLE `tb_hfshgmpqaf` TO `tb_uvpzcflhkn`, `tb_pzwwwbdsee` TO `tb_arczcfjqat`;\nRENAME TABLE `tb_uvpzcflhkn` TO `tb_kgdpofrysh`;\nCREATE TABLE `tb_zcpikjbepd` (\n  `col_srfyjibwff` time(6),\n  UNIQUE INDEX `uk_sncbjfknhk` (`col_srfyjibwff`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_aebfpjscsh` (\n  `col_dqrslyzpwh` longtext CHARACTER SET utf8 COLLATE utf8_unicode_ci,\n  `col_fcmimikjdw` date,\n  `col_wkslgjtpww` numeric(11,5) NOT NULL\n) DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_aebfpjscsh` TO `tb_ykxgxejkaq`, `tb_zcpikjbepd` TO `tb_ytmcrypwgh`;\nRENAME TABLE `tb_ytmcrypwgh` TO `tb_qfzylchmgx`, `tb_ykxgxejkaq` TO `tb_ilbncnlius`;\nRENAME TABLE `tb_qfzylchmgx` TO `tb_ebiflclztu`, `tb_ilbncnlius` TO `tb_mmagndfxbt`;\nRENAME TABLE `tb_mmagndfxbt` TO `tb_csccikqqvg`, `tb_ebiflclztu` TO `tb_gygmqyoqqr`;\nRENAME TABLE `tb_csccikqqvg` TO `tb_kevrglmsfn`, `tb_gygmqyoqqr` TO `tb_ujvpffcyig`;\nRENAME TABLE `tb_ujvpffcyig` TO `tb_jjsvaaoyby`, `tb_kevrglmsfn` TO `tb_dscfwlikgh`;\nRENAME TABLE `tb_jjsvaaoyby` TO `tb_cvnlurvcrp`, `tb_dscfwlikgh` TO `tb_tfoduoghfr`;\nRENAME TABLE `tb_cvnlurvcrp` TO `tb_hfshgmpqaf`, `tb_tfoduoghfr` TO `tb_pzwwwbdsee`;\nRENAME TABLE `tb_hfshgmpqaf` TO `tb_uvpzcflhkn`, `tb_pzwwwbdsee` TO `tb_arczcfjqat`;\nRENAME TABLE `tb_uvpzcflhkn` TO `tb_kgdpofrysh`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_33.sql",
    "content": "CREATE TABLE `tb_ksdkiecjjm` (\n  `col_eqodwasblm` bigint(208) unsigned zerofill NOT NULL,\n  CONSTRAINT PRIMARY KEY (`col_eqodwasblm`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_xcvebnzbai` (\n  `col_jryfwjfxlz` longtext CHARACTER SET utf8,\n  `col_hqfwhngyto` int(204) zerofill,\n  `col_wctviwncxg` float(48)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_brasazpupt` (\n  `col_geysucimbc` longtext CHARACTER SET latin1,\n  `col_mlphdouenl` varbinary(160) DEFAULT '\\0'\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_eyobhjyopy` (\n  `col_weucftcgtj` decimal(17,13),\n  `col_fsnwamzmnj` varchar(116) CHARACTER SET utf8 COLLATE utf8_unicode_ci\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_yqtxnjayvs` LIKE `tb_eyobhjyopy`;\nRENAME TABLE `tb_yqtxnjayvs` TO `tb_yynypoqbpb`, `tb_ksdkiecjjm` TO `tb_cwvwctfcqf`;\nRENAME TABLE `tb_yynypoqbpb` TO `tb_qptegarzpr`;\nRENAME TABLE `tb_qptegarzpr` TO `tb_xdckscvkrn`, `tb_cwvwctfcqf` TO `tb_rrtqtkgxpm`;\nRENAME TABLE `tb_eyobhjyopy` TO `tb_ojowyuvyle`, `tb_brasazpupt` TO `tb_xadmpevzmv`;\nRENAME TABLE `tb_xdckscvkrn` TO `tb_xipkollcey`, `tb_xadmpevzmv` TO `tb_xlcxrncdua`;\nRENAME TABLE `tb_xlcxrncdua` TO `tb_vjudeyawut`, `tb_ojowyuvyle` TO `tb_asbrvloeex`;\nDROP TABLE tb_xipkollcey, tb_xcvebnzbai;\nDROP TABLE tb_rrtqtkgxpm;\nCREATE TABLE `tb_ksdkiecjjm` (\n  `col_eqodwasblm` bigint(208) unsigned zerofill NOT NULL,\n  CONSTRAINT PRIMARY KEY (`col_eqodwasblm`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_xcvebnzbai` (\n  `col_jryfwjfxlz` longtext CHARACTER SET utf8,\n  `col_hqfwhngyto` int(204) zerofill,\n  `col_wctviwncxg` float(48)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_brasazpupt` (\n  `col_geysucimbc` longtext CHARACTER SET latin1,\n  `col_mlphdouenl` varbinary(160) DEFAULT '\\0'\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_eyobhjyopy` (\n  `col_weucftcgtj` decimal(17,13),\n  `col_fsnwamzmnj` varchar(116) CHARACTER SET utf8 COLLATE utf8_unicode_ci\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_yqtxnjayvs` LIKE `tb_eyobhjyopy`;\nRENAME TABLE `tb_yqtxnjayvs` TO `tb_yynypoqbpb`, `tb_ksdkiecjjm` TO `tb_cwvwctfcqf`;\nRENAME TABLE `tb_yynypoqbpb` TO `tb_qptegarzpr`;\nRENAME TABLE `tb_qptegarzpr` TO `tb_xdckscvkrn`, `tb_cwvwctfcqf` TO `tb_rrtqtkgxpm`;\nRENAME TABLE `tb_eyobhjyopy` TO `tb_ojowyuvyle`, `tb_brasazpupt` TO `tb_xadmpevzmv`;\nRENAME TABLE `tb_xdckscvkrn` TO `tb_xipkollcey`, `tb_xadmpevzmv` TO `tb_xlcxrncdua`;\nRENAME TABLE `tb_xlcxrncdua` TO `tb_vjudeyawut`, `tb_ojowyuvyle` TO `tb_asbrvloeex`;\nDROP TABLE tb_xipkollcey, tb_xcvebnzbai;\nDROP TABLE tb_rrtqtkgxpm;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_34.sql",
    "content": "CREATE TABLE `tb_bxhucobtnq` (\n  `col_qvkhqmzvuj` integer(224) unsigned,\n  `col_xdasidouyb` float DEFAULT '1',\n  `col_iyneakkoda` time,\n  `col_ixrxayrkoa` varchar(178) CHARACTER SET latin1 DEFAULT ''\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_bxhucobtnq` TO `tb_clodifiabp`;\nRENAME TABLE `tb_clodifiabp` TO `tb_wayqdiylsz`;\nRENAME TABLE `tb_wayqdiylsz` TO `tb_ynqbidrqhc`;\nRENAME TABLE `tb_ynqbidrqhc` TO `tb_psqlnlifkt`;\nRENAME TABLE `tb_psqlnlifkt` TO `tb_vzdatmeqgj`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_35.sql",
    "content": ""
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_36.sql",
    "content": "CREATE TABLE `tb_pphhkgnwoa` (\n  `col_oyenywcnaa` smallint unsigned DEFAULT '1',\n  `col_wwtzoyrtid` varchar(233) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL,\n  `col_irailjowqz` longblob\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_jwspnsjkbz` (\n  `col_hjkatsppsc` time(6) NOT NULL,\n  PRIMARY KEY (`col_hjkatsppsc`),\n  CONSTRAINT `symb_qmwmniwhbe` UNIQUE (`col_hjkatsppsc`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_zauhckwehw` (\n  `col_beaaznijqu` int unsigned NOT NULL DEFAULT '1',\n  `col_tvyjjmsmzf` binary(236) NULL,\n  `col_vwwvtljlov` integer(238) unsigned zerofill NOT NULL,\n  `col_eetxjyrroh` longblob\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_ierijdgmja` LIKE `tb_pphhkgnwoa`;\nCREATE TABLE `tb_ewltrcbaze` (\n  `col_qywkvovncp` year NOT NULL DEFAULT '2019',\n  `col_szxbozzqra` integer unsigned,\n  PRIMARY KEY (`col_qywkvovncp`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_dtdrgunkrr` (\n  `col_goniustofk` mediumtext CHARACTER SET latin1,\n  `col_ohnstevypa` blob,\n  `col_nlpdegmfoj` blob(1562746555),\n  `col_kcegirvcvq` timestamp(4) NOT NULL DEFAULT CURRENT_TIMESTAMP(4),\n  UNIQUE `uk_clmmzqdrrw` (`col_ohnstevypa`(15))\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_uildklperh` (\n  `col_jqdxektcbn` mediumint(73) unsigned zerofill,\n  `col_bnmnlyrpzk` blob,\n  `col_szivvzwgog` date\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_ierijdgmja` TO `tb_auppieylzo`;\nRENAME TABLE `tb_zauhckwehw` TO `tb_rdvmtcfenu`, `tb_ewltrcbaze` TO `tb_btaicbcvzm`;\nRENAME TABLE `tb_dtdrgunkrr` TO `tb_mxukjfwtfx`;\nDROP TABLE tb_pphhkgnwoa;\nCREATE TABLE `tb_pphhkgnwoa` (\n  `col_oyenywcnaa` smallint unsigned DEFAULT '1',\n  `col_wwtzoyrtid` varchar(233) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL,\n  `col_irailjowqz` longblob\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_jwspnsjkbz` (\n  `col_hjkatsppsc` time(6) NOT NULL,\n  PRIMARY KEY (`col_hjkatsppsc`),\n  CONSTRAINT `symb_qmwmniwhbe` UNIQUE (`col_hjkatsppsc`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_zauhckwehw` (\n  `col_beaaznijqu` int unsigned NOT NULL DEFAULT '1',\n  `col_tvyjjmsmzf` binary(236) NULL,\n  `col_vwwvtljlov` integer(238) unsigned zerofill NOT NULL,\n  `col_eetxjyrroh` longblob\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_ierijdgmja` LIKE `tb_pphhkgnwoa`;\nCREATE TABLE `tb_ewltrcbaze` (\n  `col_qywkvovncp` year NOT NULL DEFAULT '2019',\n  `col_szxbozzqra` integer unsigned,\n  PRIMARY KEY (`col_qywkvovncp`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_dtdrgunkrr` (\n  `col_goniustofk` mediumtext CHARACTER SET latin1,\n  `col_ohnstevypa` blob,\n  `col_nlpdegmfoj` blob(1562746555),\n  `col_kcegirvcvq` timestamp(4) NOT NULL DEFAULT CURRENT_TIMESTAMP(4),\n  UNIQUE `uk_clmmzqdrrw` (`col_ohnstevypa`(15))\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_uildklperh` (\n  `col_jqdxektcbn` mediumint(73) unsigned zerofill,\n  `col_bnmnlyrpzk` blob,\n  `col_szivvzwgog` date\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_ierijdgmja` TO `tb_auppieylzo`;\nRENAME TABLE `tb_zauhckwehw` TO `tb_rdvmtcfenu`, `tb_ewltrcbaze` TO `tb_btaicbcvzm`;\nRENAME TABLE `tb_dtdrgunkrr` TO `tb_mxukjfwtfx`;\nDROP TABLE tb_pphhkgnwoa;\nCREATE TABLE `tb_pphhkgnwoa` (\n  `col_oyenywcnaa` smallint unsigned DEFAULT '1',\n  `col_wwtzoyrtid` varchar(233) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL,\n  `col_irailjowqz` longblob\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_jwspnsjkbz` (\n  `col_hjkatsppsc` time(6) NOT NULL,\n  PRIMARY KEY (`col_hjkatsppsc`),\n  CONSTRAINT `symb_qmwmniwhbe` UNIQUE (`col_hjkatsppsc`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_zauhckwehw` (\n  `col_beaaznijqu` int unsigned NOT NULL DEFAULT '1',\n  `col_tvyjjmsmzf` binary(236) NULL,\n  `col_vwwvtljlov` integer(238) unsigned zerofill NOT NULL,\n  `col_eetxjyrroh` longblob\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_ierijdgmja` LIKE `tb_pphhkgnwoa`;\nCREATE TABLE `tb_ewltrcbaze` (\n  `col_qywkvovncp` year NOT NULL DEFAULT '2019',\n  `col_szxbozzqra` integer unsigned,\n  PRIMARY KEY (`col_qywkvovncp`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_dtdrgunkrr` (\n  `col_goniustofk` mediumtext CHARACTER SET latin1,\n  `col_ohnstevypa` blob,\n  `col_nlpdegmfoj` blob(1562746555),\n  `col_kcegirvcvq` timestamp(4) NOT NULL DEFAULT CURRENT_TIMESTAMP(4),\n  UNIQUE `uk_clmmzqdrrw` (`col_ohnstevypa`(15))\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_uildklperh` (\n  `col_jqdxektcbn` mediumint(73) unsigned zerofill,\n  `col_bnmnlyrpzk` blob,\n  `col_szivvzwgog` date\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_ierijdgmja` TO `tb_auppieylzo`;\nRENAME TABLE `tb_zauhckwehw` TO `tb_rdvmtcfenu`, `tb_ewltrcbaze` TO `tb_btaicbcvzm`;\nRENAME TABLE `tb_dtdrgunkrr` TO `tb_mxukjfwtfx`;\nDROP TABLE tb_pphhkgnwoa;\nCREATE TABLE `tb_pphhkgnwoa` (\n  `col_oyenywcnaa` smallint unsigned DEFAULT '1',\n  `col_wwtzoyrtid` varchar(233) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL,\n  `col_irailjowqz` longblob\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_jwspnsjkbz` (\n  `col_hjkatsppsc` time(6) NOT NULL,\n  PRIMARY KEY (`col_hjkatsppsc`),\n  CONSTRAINT `symb_qmwmniwhbe` UNIQUE (`col_hjkatsppsc`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_zauhckwehw` (\n  `col_beaaznijqu` int unsigned NOT NULL DEFAULT '1',\n  `col_tvyjjmsmzf` binary(236) NULL,\n  `col_vwwvtljlov` integer(238) unsigned zerofill NOT NULL,\n  `col_eetxjyrroh` longblob\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_ierijdgmja` LIKE `tb_pphhkgnwoa`;\nCREATE TABLE `tb_ewltrcbaze` (\n  `col_qywkvovncp` year NOT NULL DEFAULT '2019',\n  `col_szxbozzqra` integer unsigned,\n  PRIMARY KEY (`col_qywkvovncp`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_dtdrgunkrr` (\n  `col_goniustofk` mediumtext CHARACTER SET latin1,\n  `col_ohnstevypa` blob,\n  `col_nlpdegmfoj` blob(1562746555),\n  `col_kcegirvcvq` timestamp(4) NOT NULL DEFAULT CURRENT_TIMESTAMP(4),\n  UNIQUE `uk_clmmzqdrrw` (`col_ohnstevypa`(15))\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_uildklperh` (\n  `col_jqdxektcbn` mediumint(73) unsigned zerofill,\n  `col_bnmnlyrpzk` blob,\n  `col_szivvzwgog` date\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_ierijdgmja` TO `tb_auppieylzo`;\nRENAME TABLE `tb_zauhckwehw` TO `tb_rdvmtcfenu`, `tb_ewltrcbaze` TO `tb_btaicbcvzm`;\nRENAME TABLE `tb_dtdrgunkrr` TO `tb_mxukjfwtfx`;\nDROP TABLE tb_pphhkgnwoa;\nCREATE TABLE `tb_pphhkgnwoa` (\n  `col_oyenywcnaa` smallint unsigned DEFAULT '1',\n  `col_wwtzoyrtid` varchar(233) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL,\n  `col_irailjowqz` longblob\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_jwspnsjkbz` (\n  `col_hjkatsppsc` time(6) NOT NULL,\n  PRIMARY KEY (`col_hjkatsppsc`),\n  CONSTRAINT `symb_qmwmniwhbe` UNIQUE (`col_hjkatsppsc`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_zauhckwehw` (\n  `col_beaaznijqu` int unsigned NOT NULL DEFAULT '1',\n  `col_tvyjjmsmzf` binary(236) NULL,\n  `col_vwwvtljlov` integer(238) unsigned zerofill NOT NULL,\n  `col_eetxjyrroh` longblob\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_ierijdgmja` LIKE `tb_pphhkgnwoa`;\nCREATE TABLE `tb_ewltrcbaze` (\n  `col_qywkvovncp` year NOT NULL DEFAULT '2019',\n  `col_szxbozzqra` integer unsigned,\n  PRIMARY KEY (`col_qywkvovncp`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_dtdrgunkrr` (\n  `col_goniustofk` mediumtext CHARACTER SET latin1,\n  `col_ohnstevypa` blob,\n  `col_nlpdegmfoj` blob(1562746555),\n  `col_kcegirvcvq` timestamp(4) NOT NULL DEFAULT CURRENT_TIMESTAMP(4),\n  UNIQUE `uk_clmmzqdrrw` (`col_ohnstevypa`(15))\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_uildklperh` (\n  `col_jqdxektcbn` mediumint(73) unsigned zerofill,\n  `col_bnmnlyrpzk` blob,\n  `col_szivvzwgog` date\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_ierijdgmja` TO `tb_auppieylzo`;\nRENAME TABLE `tb_zauhckwehw` TO `tb_rdvmtcfenu`, `tb_ewltrcbaze` TO `tb_btaicbcvzm`;\nRENAME TABLE `tb_dtdrgunkrr` TO `tb_mxukjfwtfx`;\nDROP TABLE tb_pphhkgnwoa;\nCREATE TABLE `tb_pphhkgnwoa` (\n  `col_oyenywcnaa` smallint unsigned DEFAULT '1',\n  `col_wwtzoyrtid` varchar(233) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL,\n  `col_irailjowqz` longblob\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_jwspnsjkbz` (\n  `col_hjkatsppsc` time(6) NOT NULL,\n  PRIMARY KEY (`col_hjkatsppsc`),\n  CONSTRAINT `symb_qmwmniwhbe` UNIQUE (`col_hjkatsppsc`)\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_zauhckwehw` (\n  `col_beaaznijqu` int unsigned NOT NULL DEFAULT '1',\n  `col_tvyjjmsmzf` binary(236) NULL,\n  `col_vwwvtljlov` integer(238) unsigned zerofill NOT NULL,\n  `col_eetxjyrroh` longblob\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_ierijdgmja` LIKE `tb_pphhkgnwoa`;\nCREATE TABLE `tb_ewltrcbaze` (\n  `col_qywkvovncp` year NOT NULL DEFAULT '2019',\n  `col_szxbozzqra` integer unsigned,\n  PRIMARY KEY (`col_qywkvovncp`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_dtdrgunkrr` (\n  `col_goniustofk` mediumtext CHARACTER SET latin1,\n  `col_ohnstevypa` blob,\n  `col_nlpdegmfoj` blob(1562746555),\n  `col_kcegirvcvq` timestamp(4) NOT NULL DEFAULT CURRENT_TIMESTAMP(4),\n  UNIQUE `uk_clmmzqdrrw` (`col_ohnstevypa`(15))\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_uildklperh` (\n  `col_jqdxektcbn` mediumint(73) unsigned zerofill,\n  `col_bnmnlyrpzk` blob,\n  `col_szivvzwgog` date\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_ierijdgmja` TO `tb_auppieylzo`;\nRENAME TABLE `tb_zauhckwehw` TO `tb_rdvmtcfenu`, `tb_ewltrcbaze` TO `tb_btaicbcvzm`;\nRENAME TABLE `tb_dtdrgunkrr` TO `tb_mxukjfwtfx`;\nDROP TABLE tb_pphhkgnwoa;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_37.sql",
    "content": ""
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_38.sql",
    "content": "CREATE TABLE `tb_vqdmgdujbc` (\n  `col_oaqwwurqgi` varbinary(236) NOT NULL,\n  `col_ixrprxsjfc` varbinary(67),\n  `col_nynkysgzrd` binary(157),\n  CONSTRAINT PRIMARY KEY (`col_oaqwwurqgi`(5))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_uvhgkuvnbw` (\n  `col_teeikxydzy` smallint(86) zerofill NULL,\n  `col_ntfpjlwmxm` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NOT NULL,\n  `col_fdqhoqsugi` char(248) CHARACTER SET utf8mb4 NOT NULL,\n  `col_hpffggqzyt` smallint zerofill,\n  CONSTRAINT PRIMARY KEY (`col_ntfpjlwmxm`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_ahtdsnwdye` (\n  `col_dtekjkveju` date,\n  `col_spwzkdxpyh` text CHARACTER SET utf8 COLLATE utf8_unicode_ci,\n  `col_xypfiszpnv` longblob,\n  UNIQUE INDEX `col_dtekjkveju` (`col_dtekjkveju`),\n  CONSTRAINT `symb_oxqigxgxfp` UNIQUE KEY `uk_zuonxdzgig` (`col_dtekjkveju`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_nnobzhrzqo` (\n  `col_dagcnvtvmo` year(4) NOT NULL,\n  `col_lnppfvjbkl` longblob,\n  CONSTRAINT symb_fkpncqgegh PRIMARY KEY (`col_dagcnvtvmo`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_kimzrscxvx` (\n  `col_irlhbphjuu` bigint NULL DEFAULT '1',\n  `col_mmyhnykoux` datetime(4),\n  `col_tbnhrkvbyw` date DEFAULT '2019-07-04',\n  `col_znpwgitvbt` date DEFAULT '2019-07-04'\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_kimzrscxvx` TO `tb_lvhgwlctrm`, `tb_nnobzhrzqo` TO `tb_xplnlwuite`;\nRENAME TABLE `tb_vqdmgdujbc` TO `tb_umtjdrecoe`, `tb_ahtdsnwdye` TO `tb_usrrixyhol`;\nRENAME TABLE `tb_umtjdrecoe` TO `tb_tntbgwfxdz`;\nRENAME TABLE `tb_uvhgkuvnbw` TO `tb_psnsrqzpyc`;\nRENAME TABLE `tb_usrrixyhol` TO `tb_rwgyzdhslb`;\nRENAME TABLE `tb_rwgyzdhslb` TO `tb_wyelqbhtiz`, `tb_psnsrqzpyc` TO `tb_cemigpflpg`;\nDROP TABLE tb_wyelqbhtiz;\nCREATE TABLE `tb_vqdmgdujbc` (\n  `col_oaqwwurqgi` varbinary(236) NOT NULL,\n  `col_ixrprxsjfc` varbinary(67),\n  `col_nynkysgzrd` binary(157),\n  CONSTRAINT PRIMARY KEY (`col_oaqwwurqgi`(5))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_uvhgkuvnbw` (\n  `col_teeikxydzy` smallint(86) zerofill NULL,\n  `col_ntfpjlwmxm` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NOT NULL,\n  `col_fdqhoqsugi` char(248) CHARACTER SET utf8mb4 NOT NULL,\n  `col_hpffggqzyt` smallint zerofill,\n  CONSTRAINT PRIMARY KEY (`col_ntfpjlwmxm`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_ahtdsnwdye` (\n  `col_dtekjkveju` date,\n  `col_spwzkdxpyh` text CHARACTER SET utf8 COLLATE utf8_unicode_ci,\n  `col_xypfiszpnv` longblob,\n  UNIQUE INDEX `col_dtekjkveju` (`col_dtekjkveju`),\n  CONSTRAINT `symb_oxqigxgxfp` UNIQUE KEY `uk_zuonxdzgig` (`col_dtekjkveju`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_nnobzhrzqo` (\n  `col_dagcnvtvmo` year(4) NOT NULL,\n  `col_lnppfvjbkl` longblob,\n  CONSTRAINT symb_fkpncqgegh PRIMARY KEY (`col_dagcnvtvmo`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_kimzrscxvx` (\n  `col_irlhbphjuu` bigint NULL DEFAULT '1',\n  `col_mmyhnykoux` datetime(4),\n  `col_tbnhrkvbyw` date DEFAULT '2019-07-04',\n  `col_znpwgitvbt` date DEFAULT '2019-07-04'\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_kimzrscxvx` TO `tb_lvhgwlctrm`, `tb_nnobzhrzqo` TO `tb_xplnlwuite`;\nRENAME TABLE `tb_vqdmgdujbc` TO `tb_umtjdrecoe`, `tb_ahtdsnwdye` TO `tb_usrrixyhol`;\nRENAME TABLE `tb_umtjdrecoe` TO `tb_tntbgwfxdz`;\nRENAME TABLE `tb_uvhgkuvnbw` TO `tb_psnsrqzpyc`;\nRENAME TABLE `tb_usrrixyhol` TO `tb_rwgyzdhslb`;\nRENAME TABLE `tb_rwgyzdhslb` TO `tb_wyelqbhtiz`, `tb_psnsrqzpyc` TO `tb_cemigpflpg`;\nDROP TABLE tb_wyelqbhtiz;\nCREATE TABLE `tb_vqdmgdujbc` (\n  `col_oaqwwurqgi` varbinary(236) NOT NULL,\n  `col_ixrprxsjfc` varbinary(67),\n  `col_nynkysgzrd` binary(157),\n  CONSTRAINT PRIMARY KEY (`col_oaqwwurqgi`(5))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_uvhgkuvnbw` (\n  `col_teeikxydzy` smallint(86) zerofill NULL,\n  `col_ntfpjlwmxm` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NOT NULL,\n  `col_fdqhoqsugi` char(248) CHARACTER SET utf8mb4 NOT NULL,\n  `col_hpffggqzyt` smallint zerofill,\n  CONSTRAINT PRIMARY KEY (`col_ntfpjlwmxm`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_ahtdsnwdye` (\n  `col_dtekjkveju` date,\n  `col_spwzkdxpyh` text CHARACTER SET utf8 COLLATE utf8_unicode_ci,\n  `col_xypfiszpnv` longblob,\n  UNIQUE INDEX `col_dtekjkveju` (`col_dtekjkveju`),\n  CONSTRAINT `symb_oxqigxgxfp` UNIQUE KEY `uk_zuonxdzgig` (`col_dtekjkveju`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_nnobzhrzqo` (\n  `col_dagcnvtvmo` year(4) NOT NULL,\n  `col_lnppfvjbkl` longblob,\n  CONSTRAINT symb_fkpncqgegh PRIMARY KEY (`col_dagcnvtvmo`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_kimzrscxvx` (\n  `col_irlhbphjuu` bigint NULL DEFAULT '1',\n  `col_mmyhnykoux` datetime(4),\n  `col_tbnhrkvbyw` date DEFAULT '2019-07-04',\n  `col_znpwgitvbt` date DEFAULT '2019-07-04'\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_kimzrscxvx` TO `tb_lvhgwlctrm`, `tb_nnobzhrzqo` TO `tb_xplnlwuite`;\nRENAME TABLE `tb_vqdmgdujbc` TO `tb_umtjdrecoe`, `tb_ahtdsnwdye` TO `tb_usrrixyhol`;\nRENAME TABLE `tb_umtjdrecoe` TO `tb_tntbgwfxdz`;\nRENAME TABLE `tb_uvhgkuvnbw` TO `tb_psnsrqzpyc`;\nRENAME TABLE `tb_usrrixyhol` TO `tb_rwgyzdhslb`;\nRENAME TABLE `tb_rwgyzdhslb` TO `tb_wyelqbhtiz`, `tb_psnsrqzpyc` TO `tb_cemigpflpg`;\nDROP TABLE tb_wyelqbhtiz;\nCREATE TABLE `tb_vqdmgdujbc` (\n  `col_oaqwwurqgi` varbinary(236) NOT NULL,\n  `col_ixrprxsjfc` varbinary(67),\n  `col_nynkysgzrd` binary(157),\n  CONSTRAINT PRIMARY KEY (`col_oaqwwurqgi`(5))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_uvhgkuvnbw` (\n  `col_teeikxydzy` smallint(86) zerofill NULL,\n  `col_ntfpjlwmxm` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NOT NULL,\n  `col_fdqhoqsugi` char(248) CHARACTER SET utf8mb4 NOT NULL,\n  `col_hpffggqzyt` smallint zerofill,\n  CONSTRAINT PRIMARY KEY (`col_ntfpjlwmxm`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_ahtdsnwdye` (\n  `col_dtekjkveju` date,\n  `col_spwzkdxpyh` text CHARACTER SET utf8 COLLATE utf8_unicode_ci,\n  `col_xypfiszpnv` longblob,\n  UNIQUE INDEX `col_dtekjkveju` (`col_dtekjkveju`),\n  CONSTRAINT `symb_oxqigxgxfp` UNIQUE KEY `uk_zuonxdzgig` (`col_dtekjkveju`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_nnobzhrzqo` (\n  `col_dagcnvtvmo` year(4) NOT NULL,\n  `col_lnppfvjbkl` longblob,\n  CONSTRAINT symb_fkpncqgegh PRIMARY KEY (`col_dagcnvtvmo`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_kimzrscxvx` (\n  `col_irlhbphjuu` bigint NULL DEFAULT '1',\n  `col_mmyhnykoux` datetime(4),\n  `col_tbnhrkvbyw` date DEFAULT '2019-07-04',\n  `col_znpwgitvbt` date DEFAULT '2019-07-04'\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_kimzrscxvx` TO `tb_lvhgwlctrm`, `tb_nnobzhrzqo` TO `tb_xplnlwuite`;\nRENAME TABLE `tb_vqdmgdujbc` TO `tb_umtjdrecoe`, `tb_ahtdsnwdye` TO `tb_usrrixyhol`;\nRENAME TABLE `tb_umtjdrecoe` TO `tb_tntbgwfxdz`;\nRENAME TABLE `tb_uvhgkuvnbw` TO `tb_psnsrqzpyc`;\nRENAME TABLE `tb_usrrixyhol` TO `tb_rwgyzdhslb`;\nRENAME TABLE `tb_rwgyzdhslb` TO `tb_wyelqbhtiz`, `tb_psnsrqzpyc` TO `tb_cemigpflpg`;\nDROP TABLE tb_wyelqbhtiz;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_39.sql",
    "content": "CREATE TABLE `tb_lkcruokdfh` (\n  `col_hriruwciyw` blob(3794455272),\n  CONSTRAINT UNIQUE INDEX `col_hriruwciyw` (`col_hriruwciyw`(11)),\n  UNIQUE INDEX `uk_ktdzldgjqo` (`col_hriruwciyw`(18))\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_imepdzhsgh` (\n  `col_wsaejbacoe` longtext CHARACTER SET utf8,\n  `col_wgrjfcezod` integer(19) NOT NULL,\n  `col_yhavwtiaep` date NOT NULL,\n  `col_ezzupofzra` tinytext CHARACTER SET utf8mb4,\n  UNIQUE KEY `col_wsaejbacoe` (`col_wsaejbacoe`(29),`col_wgrjfcezod`),\n  UNIQUE KEY `col_wgrjfcezod` (`col_wgrjfcezod`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_eydxucudno` (\n  `col_lsaozjvioc` tinyint DEFAULT '1',\n  `col_umquuzgoic` binary,\n  `col_hssxpkdkzt` numeric DEFAULT '1',\n  UNIQUE INDEX `uk_ribdoefndw` (`col_lsaozjvioc`),\n  CONSTRAINT UNIQUE KEY `uk_ygjhgipibu` (`col_umquuzgoic`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_imepdzhsgh` TO `tb_rawvvsgmse`;\nRENAME TABLE `tb_lkcruokdfh` TO `tb_scytcshwjf`, `tb_rawvvsgmse` TO `tb_utzdjdjsln`;\nRENAME TABLE `tb_scytcshwjf` TO `tb_hvqlhrcjcf`, `tb_utzdjdjsln` TO `tb_wscheecoug`;\nRENAME TABLE `tb_wscheecoug` TO `tb_ouvrqoxnvh`, `tb_hvqlhrcjcf` TO `tb_pactwzqamv`;\nRENAME TABLE `tb_eydxucudno` TO `tb_ebnesypzau`, `tb_ouvrqoxnvh` TO `tb_onrsvwgpqb`;\nRENAME TABLE `tb_ebnesypzau` TO `tb_xfnqchameq`;\nCREATE TABLE `tb_lkcruokdfh` (\n  `col_hriruwciyw` blob(3794455272),\n  CONSTRAINT UNIQUE INDEX `col_hriruwciyw` (`col_hriruwciyw`(11)),\n  UNIQUE INDEX `uk_ktdzldgjqo` (`col_hriruwciyw`(18))\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_imepdzhsgh` (\n  `col_wsaejbacoe` longtext CHARACTER SET utf8,\n  `col_wgrjfcezod` integer(19) NOT NULL,\n  `col_yhavwtiaep` date NOT NULL,\n  `col_ezzupofzra` tinytext CHARACTER SET utf8mb4,\n  UNIQUE KEY `col_wsaejbacoe` (`col_wsaejbacoe`(29),`col_wgrjfcezod`),\n  UNIQUE KEY `col_wgrjfcezod` (`col_wgrjfcezod`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_eydxucudno` (\n  `col_lsaozjvioc` tinyint DEFAULT '1',\n  `col_umquuzgoic` binary,\n  `col_hssxpkdkzt` numeric DEFAULT '1',\n  UNIQUE INDEX `uk_ribdoefndw` (`col_lsaozjvioc`),\n  CONSTRAINT UNIQUE KEY `uk_ygjhgipibu` (`col_umquuzgoic`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_imepdzhsgh` TO `tb_rawvvsgmse`;\nRENAME TABLE `tb_lkcruokdfh` TO `tb_scytcshwjf`, `tb_rawvvsgmse` TO `tb_utzdjdjsln`;\nRENAME TABLE `tb_scytcshwjf` TO `tb_hvqlhrcjcf`, `tb_utzdjdjsln` TO `tb_wscheecoug`;\nRENAME TABLE `tb_wscheecoug` TO `tb_ouvrqoxnvh`, `tb_hvqlhrcjcf` TO `tb_pactwzqamv`;\nRENAME TABLE `tb_eydxucudno` TO `tb_ebnesypzau`, `tb_ouvrqoxnvh` TO `tb_onrsvwgpqb`;\nRENAME TABLE `tb_ebnesypzau` TO `tb_xfnqchameq`;\nCREATE TABLE `tb_lkcruokdfh` (\n  `col_hriruwciyw` blob(3794455272),\n  CONSTRAINT UNIQUE INDEX `col_hriruwciyw` (`col_hriruwciyw`(11)),\n  UNIQUE INDEX `uk_ktdzldgjqo` (`col_hriruwciyw`(18))\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_imepdzhsgh` (\n  `col_wsaejbacoe` longtext CHARACTER SET utf8,\n  `col_wgrjfcezod` integer(19) NOT NULL,\n  `col_yhavwtiaep` date NOT NULL,\n  `col_ezzupofzra` tinytext CHARACTER SET utf8mb4,\n  UNIQUE KEY `col_wsaejbacoe` (`col_wsaejbacoe`(29),`col_wgrjfcezod`),\n  UNIQUE KEY `col_wgrjfcezod` (`col_wgrjfcezod`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_eydxucudno` (\n  `col_lsaozjvioc` tinyint DEFAULT '1',\n  `col_umquuzgoic` binary,\n  `col_hssxpkdkzt` numeric DEFAULT '1',\n  UNIQUE INDEX `uk_ribdoefndw` (`col_lsaozjvioc`),\n  CONSTRAINT UNIQUE KEY `uk_ygjhgipibu` (`col_umquuzgoic`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_imepdzhsgh` TO `tb_rawvvsgmse`;\nRENAME TABLE `tb_lkcruokdfh` TO `tb_scytcshwjf`, `tb_rawvvsgmse` TO `tb_utzdjdjsln`;\nRENAME TABLE `tb_scytcshwjf` TO `tb_hvqlhrcjcf`, `tb_utzdjdjsln` TO `tb_wscheecoug`;\nRENAME TABLE `tb_wscheecoug` TO `tb_ouvrqoxnvh`, `tb_hvqlhrcjcf` TO `tb_pactwzqamv`;\nRENAME TABLE `tb_eydxucudno` TO `tb_ebnesypzau`, `tb_ouvrqoxnvh` TO `tb_onrsvwgpqb`;\nRENAME TABLE `tb_ebnesypzau` TO `tb_xfnqchameq`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_4.sql",
    "content": "CREATE TABLE `tb_npfwhbears` (\n  `col_djhzavbkkl` bigint NULL,\n  `col_nnatwjycze` timestamp(3) NULL,\n  CONSTRAINT UNIQUE KEY `col_djhzavbkkl` (`col_djhzavbkkl`),\n  UNIQUE `uk_giquysylxe` (`col_djhzavbkkl`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_phdwhdaoks` LIKE `tb_npfwhbears`;\nCREATE TABLE `tb_qxibwgerpc` (\n  `col_vevvvixdsj` double NOT NULL DEFAULT '1',\n  CONSTRAINT `symb_mvejvudtqx` UNIQUE INDEX (`col_vevvvixdsj`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_moapqhgigh` (\n  `col_dabildvylk` numeric(2,2),\n  `col_aquzjnainr` mediumblob,\n  `col_ueplpctsoc` text(472945891) CHARACTER SET utf8mb4,\n  `col_gbbyaoyiod` varbinary(161) NULL DEFAULT '\\0',\n  UNIQUE KEY `col_aquzjnainr` (`col_aquzjnainr`(11),`col_gbbyaoyiod`(27))\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_jbbochhmyq` (\n  `col_ngukvihugo` blob(3694999992),\n  CONSTRAINT UNIQUE `uk_zllsscaepd` (`col_ngukvihugo`(12)),\n  CONSTRAINT `symb_apekibdvlc` UNIQUE KEY `uk_hwinjetonw` (`col_ngukvihugo`(24))\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_qhpsbbtoys` LIKE `tb_qxibwgerpc`;\nRENAME TABLE `tb_jbbochhmyq` TO `tb_gacdzagwgx`;\nRENAME TABLE `tb_gacdzagwgx` TO `tb_ldeoaebpbd`;\nRENAME TABLE `tb_moapqhgigh` TO `tb_ggibvidjxp`, `tb_qhpsbbtoys` TO `tb_edphnejvyp`;\nRENAME TABLE `tb_phdwhdaoks` TO `tb_gqurtkvpbu`, `tb_ggibvidjxp` TO `tb_fodfuxeiry`;\nRENAME TABLE `tb_edphnejvyp` TO `tb_iapmhzrbpl`;\nRENAME TABLE `tb_gqurtkvpbu` TO `tb_nxxnnxsqeq`;\nRENAME TABLE `tb_ldeoaebpbd` TO `tb_yujleuojse`;\nDROP TABLE tb_qxibwgerpc, tb_fodfuxeiry;\nCREATE TABLE `tb_npfwhbears` (\n  `col_djhzavbkkl` bigint NULL,\n  `col_nnatwjycze` timestamp(3) NULL,\n  CONSTRAINT UNIQUE KEY `col_djhzavbkkl` (`col_djhzavbkkl`),\n  UNIQUE `uk_giquysylxe` (`col_djhzavbkkl`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_phdwhdaoks` LIKE `tb_npfwhbears`;\nCREATE TABLE `tb_qxibwgerpc` (\n  `col_vevvvixdsj` double NOT NULL DEFAULT '1',\n  CONSTRAINT `symb_mvejvudtqx` UNIQUE INDEX (`col_vevvvixdsj`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_moapqhgigh` (\n  `col_dabildvylk` numeric(2,2),\n  `col_aquzjnainr` mediumblob,\n  `col_ueplpctsoc` text(472945891) CHARACTER SET utf8mb4,\n  `col_gbbyaoyiod` varbinary(161) NULL DEFAULT '\\0',\n  UNIQUE KEY `col_aquzjnainr` (`col_aquzjnainr`(11),`col_gbbyaoyiod`(27))\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_jbbochhmyq` (\n  `col_ngukvihugo` blob(3694999992),\n  CONSTRAINT UNIQUE `uk_zllsscaepd` (`col_ngukvihugo`(12)),\n  CONSTRAINT `symb_apekibdvlc` UNIQUE KEY `uk_hwinjetonw` (`col_ngukvihugo`(24))\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_qhpsbbtoys` LIKE `tb_qxibwgerpc`;\nRENAME TABLE `tb_jbbochhmyq` TO `tb_gacdzagwgx`;\nRENAME TABLE `tb_gacdzagwgx` TO `tb_ldeoaebpbd`;\nRENAME TABLE `tb_moapqhgigh` TO `tb_ggibvidjxp`, `tb_qhpsbbtoys` TO `tb_edphnejvyp`;\nRENAME TABLE `tb_phdwhdaoks` TO `tb_gqurtkvpbu`, `tb_ggibvidjxp` TO `tb_fodfuxeiry`;\nRENAME TABLE `tb_edphnejvyp` TO `tb_iapmhzrbpl`;\nRENAME TABLE `tb_gqurtkvpbu` TO `tb_nxxnnxsqeq`;\nRENAME TABLE `tb_ldeoaebpbd` TO `tb_yujleuojse`;\nDROP TABLE tb_qxibwgerpc, tb_fodfuxeiry;\nCREATE TABLE `tb_npfwhbears` (\n  `col_djhzavbkkl` bigint NULL,\n  `col_nnatwjycze` timestamp(3) NULL,\n  CONSTRAINT UNIQUE KEY `col_djhzavbkkl` (`col_djhzavbkkl`),\n  UNIQUE `uk_giquysylxe` (`col_djhzavbkkl`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_phdwhdaoks` LIKE `tb_npfwhbears`;\nCREATE TABLE `tb_qxibwgerpc` (\n  `col_vevvvixdsj` double NOT NULL DEFAULT '1',\n  CONSTRAINT `symb_mvejvudtqx` UNIQUE INDEX (`col_vevvvixdsj`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_moapqhgigh` (\n  `col_dabildvylk` numeric(2,2),\n  `col_aquzjnainr` mediumblob,\n  `col_ueplpctsoc` text(472945891) CHARACTER SET utf8mb4,\n  `col_gbbyaoyiod` varbinary(161) NULL DEFAULT '\\0',\n  UNIQUE KEY `col_aquzjnainr` (`col_aquzjnainr`(11),`col_gbbyaoyiod`(27))\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_jbbochhmyq` (\n  `col_ngukvihugo` blob(3694999992),\n  CONSTRAINT UNIQUE `uk_zllsscaepd` (`col_ngukvihugo`(12)),\n  CONSTRAINT `symb_apekibdvlc` UNIQUE KEY `uk_hwinjetonw` (`col_ngukvihugo`(24))\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_qhpsbbtoys` LIKE `tb_qxibwgerpc`;\nRENAME TABLE `tb_jbbochhmyq` TO `tb_gacdzagwgx`;\nRENAME TABLE `tb_gacdzagwgx` TO `tb_ldeoaebpbd`;\nRENAME TABLE `tb_moapqhgigh` TO `tb_ggibvidjxp`, `tb_qhpsbbtoys` TO `tb_edphnejvyp`;\nRENAME TABLE `tb_phdwhdaoks` TO `tb_gqurtkvpbu`, `tb_ggibvidjxp` TO `tb_fodfuxeiry`;\nRENAME TABLE `tb_edphnejvyp` TO `tb_iapmhzrbpl`;\nRENAME TABLE `tb_gqurtkvpbu` TO `tb_nxxnnxsqeq`;\nRENAME TABLE `tb_ldeoaebpbd` TO `tb_yujleuojse`;\nDROP TABLE tb_qxibwgerpc, tb_fodfuxeiry;\nCREATE TABLE `tb_npfwhbears` (\n  `col_djhzavbkkl` bigint NULL,\n  `col_nnatwjycze` timestamp(3) NULL,\n  CONSTRAINT UNIQUE KEY `col_djhzavbkkl` (`col_djhzavbkkl`),\n  UNIQUE `uk_giquysylxe` (`col_djhzavbkkl`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_phdwhdaoks` LIKE `tb_npfwhbears`;\nCREATE TABLE `tb_qxibwgerpc` (\n  `col_vevvvixdsj` double NOT NULL DEFAULT '1',\n  CONSTRAINT `symb_mvejvudtqx` UNIQUE INDEX (`col_vevvvixdsj`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_moapqhgigh` (\n  `col_dabildvylk` numeric(2,2),\n  `col_aquzjnainr` mediumblob,\n  `col_ueplpctsoc` text(472945891) CHARACTER SET utf8mb4,\n  `col_gbbyaoyiod` varbinary(161) NULL DEFAULT '\\0',\n  UNIQUE KEY `col_aquzjnainr` (`col_aquzjnainr`(11),`col_gbbyaoyiod`(27))\n) DEFAULT CHARSET=utf8;\nCREATE TABLE `tb_jbbochhmyq` (\n  `col_ngukvihugo` blob(3694999992),\n  CONSTRAINT UNIQUE `uk_zllsscaepd` (`col_ngukvihugo`(12)),\n  CONSTRAINT `symb_apekibdvlc` UNIQUE KEY `uk_hwinjetonw` (`col_ngukvihugo`(24))\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_qhpsbbtoys` LIKE `tb_qxibwgerpc`;\nRENAME TABLE `tb_jbbochhmyq` TO `tb_gacdzagwgx`;\nRENAME TABLE `tb_gacdzagwgx` TO `tb_ldeoaebpbd`;\nRENAME TABLE `tb_moapqhgigh` TO `tb_ggibvidjxp`, `tb_qhpsbbtoys` TO `tb_edphnejvyp`;\nRENAME TABLE `tb_phdwhdaoks` TO `tb_gqurtkvpbu`, `tb_ggibvidjxp` TO `tb_fodfuxeiry`;\nRENAME TABLE `tb_edphnejvyp` TO `tb_iapmhzrbpl`;\nRENAME TABLE `tb_gqurtkvpbu` TO `tb_nxxnnxsqeq`;\nRENAME TABLE `tb_ldeoaebpbd` TO `tb_yujleuojse`;\nDROP TABLE tb_qxibwgerpc, tb_fodfuxeiry;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_5.sql",
    "content": ""
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_6.sql",
    "content": "CREATE TABLE `tb_fzevsbnyxa` (\n  `col_wuvofglkav` blob,\n  CONSTRAINT UNIQUE INDEX `col_wuvofglkav` (`col_wuvofglkav`(20)),\n  UNIQUE INDEX `col_wuvofglkav_2` (`col_wuvofglkav`(18))\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_fdwsyimqus` (\n  `col_zqritfblef` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NULL,\n  `col_tvyzdewvuz` integer(17),\n  `col_rigzrdrdlq` numeric(31,15) NULL,\n  CONSTRAINT UNIQUE INDEX `uk_ckjnyzlzhn` (`col_rigzrdrdlq`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_igmsbcjwnu` (\n  `col_sgxesfcvdh` blob,\n  `col_tjhvpjnswu` bigint unsigned,\n  `col_vvbowgfzum` varchar(200) CHARACTER SET utf8 DEFAULT ''\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_fdwsyimqus` TO `tb_ubrqfpxtmq`, `tb_fzevsbnyxa` TO `tb_wqdqkksoxc`;\nRENAME TABLE `tb_ubrqfpxtmq` TO `tb_aggxjxbfia`;\nRENAME TABLE `tb_aggxjxbfia` TO `tb_mszwzhbqqo`;\nRENAME TABLE `tb_wqdqkksoxc` TO `tb_osccbhgwdn`;\nRENAME TABLE `tb_mszwzhbqqo` TO `tb_caqffimhoa`;\nRENAME TABLE `tb_caqffimhoa` TO `tb_chzhfzbmgu`, `tb_igmsbcjwnu` TO `tb_bpukgjzglw`;\nCREATE TABLE `tb_fzevsbnyxa` (\n  `col_wuvofglkav` blob,\n  CONSTRAINT UNIQUE INDEX `col_wuvofglkav` (`col_wuvofglkav`(20)),\n  UNIQUE INDEX `col_wuvofglkav_2` (`col_wuvofglkav`(18))\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_fdwsyimqus` (\n  `col_zqritfblef` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NULL,\n  `col_tvyzdewvuz` integer(17),\n  `col_rigzrdrdlq` numeric(31,15) NULL,\n  CONSTRAINT UNIQUE INDEX `uk_ckjnyzlzhn` (`col_rigzrdrdlq`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_igmsbcjwnu` (\n  `col_sgxesfcvdh` blob,\n  `col_tjhvpjnswu` bigint unsigned,\n  `col_vvbowgfzum` varchar(200) CHARACTER SET utf8 DEFAULT ''\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_fdwsyimqus` TO `tb_ubrqfpxtmq`, `tb_fzevsbnyxa` TO `tb_wqdqkksoxc`;\nRENAME TABLE `tb_ubrqfpxtmq` TO `tb_aggxjxbfia`;\nRENAME TABLE `tb_aggxjxbfia` TO `tb_mszwzhbqqo`;\nRENAME TABLE `tb_wqdqkksoxc` TO `tb_osccbhgwdn`;\nRENAME TABLE `tb_mszwzhbqqo` TO `tb_caqffimhoa`;\nRENAME TABLE `tb_caqffimhoa` TO `tb_chzhfzbmgu`, `tb_igmsbcjwnu` TO `tb_bpukgjzglw`;\nCREATE TABLE `tb_fzevsbnyxa` (\n  `col_wuvofglkav` blob,\n  CONSTRAINT UNIQUE INDEX `col_wuvofglkav` (`col_wuvofglkav`(20)),\n  UNIQUE INDEX `col_wuvofglkav_2` (`col_wuvofglkav`(18))\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_fdwsyimqus` (\n  `col_zqritfblef` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8mb4 NULL,\n  `col_tvyzdewvuz` integer(17),\n  `col_rigzrdrdlq` numeric(31,15) NULL,\n  CONSTRAINT UNIQUE INDEX `uk_ckjnyzlzhn` (`col_rigzrdrdlq`)\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_igmsbcjwnu` (\n  `col_sgxesfcvdh` blob,\n  `col_tjhvpjnswu` bigint unsigned,\n  `col_vvbowgfzum` varchar(200) CHARACTER SET utf8 DEFAULT ''\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_fdwsyimqus` TO `tb_ubrqfpxtmq`, `tb_fzevsbnyxa` TO `tb_wqdqkksoxc`;\nRENAME TABLE `tb_ubrqfpxtmq` TO `tb_aggxjxbfia`;\nRENAME TABLE `tb_aggxjxbfia` TO `tb_mszwzhbqqo`;\nRENAME TABLE `tb_wqdqkksoxc` TO `tb_osccbhgwdn`;\nRENAME TABLE `tb_mszwzhbqqo` TO `tb_caqffimhoa`;\nRENAME TABLE `tb_caqffimhoa` TO `tb_chzhfzbmgu`, `tb_igmsbcjwnu` TO `tb_bpukgjzglw`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_7.sql",
    "content": "CREATE TABLE `tb_haqeeunokj` (\n  `col_mhnfdjvvcl` enum('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET utf8 DEFAULT 'enum_or_set_0',\n  `col_nppvqejmds` mediumint unsigned zerofill,\n  UNIQUE KEY `uk_cgzmixhhpp` (`col_mhnfdjvvcl`),\n  CONSTRAINT UNIQUE `col_mhnfdjvvcl` (`col_mhnfdjvvcl`,`col_nppvqejmds`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_haqeeunokj` TO `tb_hbefpxwqdj`;\nRENAME TABLE `tb_hbefpxwqdj` TO `tb_rbbroruegc`;\nRENAME TABLE `tb_rbbroruegc` TO `tb_ahqzqmqdua`;\nRENAME TABLE `tb_ahqzqmqdua` TO `tb_qsdgrixxxx`;\nRENAME TABLE `tb_qsdgrixxxx` TO `tb_bziawjhizf`;\nRENAME TABLE `tb_bziawjhizf` TO `tb_lfcttoxkbw`;\nRENAME TABLE `tb_lfcttoxkbw` TO `tb_ivkxkxjrie`;\nRENAME TABLE `tb_ivkxkxjrie` TO `tb_wpozpvwepq`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_8.sql",
    "content": "CREATE TABLE `tb_ivyeuqyiae` (\n  `col_gqvgqzlgna` set('enum_or_set_0','enum_or_set_1','enum_or_set_2') CHARACTER SET latin1 NULL,\n  `col_xnynymrwbx` numeric(8,1),\n  CONSTRAINT `symb_znikarajci` UNIQUE KEY (`col_xnynymrwbx`)\n) DEFAULT CHARSET=latin1;\nRENAME TABLE `tb_ivyeuqyiae` TO `tb_dzwzhhcyis`;\nRENAME TABLE `tb_dzwzhhcyis` TO `tb_kekmokzyfi`;\nRENAME TABLE `tb_kekmokzyfi` TO `tb_ebwxswnaxz`;\nRENAME TABLE `tb_ebwxswnaxz` TO `tb_qdjqayreum`;\n"
  },
  {
    "path": "parse/src/test/resources/ddl/table/test_9.sql",
    "content": "CREATE TABLE `tb_qinfehbzem` (\n  `col_ginzfhyvfi` int unsigned NULL DEFAULT '1',\n  `col_cakcnwuchg` date DEFAULT '2019-07-04',\n  `col_hgdcocydeg` integer unsigned zerofill,\n  `col_opsrfpouaa` longblob,\n  UNIQUE `uk_tcqbsivphi` (`col_opsrfpouaa`(1)),\n  UNIQUE INDEX `col_hgdcocydeg` (`col_hgdcocydeg`,`col_opsrfpouaa`(29))\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_gcwttmsayc` (\n  `col_rwfupswrnp` tinytext CHARACTER SET utf8mb4,\n  UNIQUE KEY `uk_rqatmzledw` (`col_rwfupswrnp`(6))\n) DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_wvnpljeqpj` (\n  `col_qrgsrjkyom` double(87,17) NULL,\n  UNIQUE INDEX `col_qrgsrjkyom` (`col_qrgsrjkyom`),\n  UNIQUE INDEX `col_qrgsrjkyom_2` (`col_qrgsrjkyom`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\nCREATE TABLE `tb_kezjbtsebu` LIKE `tb_gcwttmsayc`;\nCREATE TABLE `tb_cjwgkhdfpa` LIKE `tb_gcwttmsayc`;\nCREATE TABLE `tb_uvqnvkckwl` LIKE `tb_gcwttmsayc`;\nCREATE TABLE `tb_rcqcegxwfy` (\n  `col_crzrgcsrtd` int NOT NULL,\n  `col_hkaqkrqzfj` mediumtext CHARACTER SET utf8mb4,\n  `col_wobtyvzfom` blob,\n  CONSTRAINT `symb_lyzhvxawge` UNIQUE INDEX `uk_gomrdpfzlr` (`col_crzrgcsrtd`),\n  UNIQUE `uk_xcqwpumviu` (`col_crzrgcsrtd`,`col_wobtyvzfom`(4))\n) DEFAULT CHARSET=utf8;\nRENAME TABLE `tb_gcwttmsayc` TO `tb_kwqumakbsd`;\nRENAME TABLE `tb_wvnpljeqpj` TO `tb_moiidbfdwn`, `tb_uvqnvkckwl` TO `tb_avkqzktrix`;\nRENAME TABLE `tb_rcqcegxwfy` TO `tb_rtbwxgyymu`, `tb_kezjbtsebu` TO `tb_qddvuiqxts`;\nRENAME TABLE `tb_qddvuiqxts` TO `tb_dxqnwmkzok`;\nRENAME TABLE `tb_moiidbfdwn` TO `tb_zhkwttzekg`;\nDROP TABLE tb_zhkwttzekg, tb_cjwgkhdfpa;\nDROP TABLE tb_rtbwxgyymu, tb_dxqnwmkzok;\nDROP TABLE tb_kwqumakbsd;\nDROP TABLE tb_avkqzktrix;\n"
  },
  {
    "path": "parse/src/test/resources/dummy.txt",
    "content": "本文件仅仅为定位绝对路径使用"
  },
  {
    "path": "parse/src/test/resources/tsdb/derby-tsdb.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns=\"http://www.springframework.org/schema/beans\" xmlns:tx=\"http://www.springframework.org/schema/tx\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd\n\thttp://www.springframework.org/schema/tx\n    http://www.springframework.org/schema/tx/spring-tx-2.0.xsd\"\n       default-autowire=\"byName\">\n\t\n\t<!-- 基于db的实现 -->\n\t<bean id=\"tableMetaTSDB\" class=\"com.alibaba.otter.canal.parse.inbound.mysql.tsdb.DatabaseTableMeta\">\n\t\t<property name=\"metaHistoryDAO\" ref=\"metaHistoryDAO\"/>\n\t\t<property name=\"metaSnapshotDAO\" ref=\"metaSnapshotDAO\"/>\n\t</bean>\n\t\n    <bean id=\"dataSource\" class=\"com.alibaba.druid.pool.DruidDataSource\" destroy-method=\"close\">\n        <property name=\"driverClassName\" value=\"org.apache.derby.jdbc.EmbeddedDriver\" />\n        <property name=\"url\" value=\"jdbc:derby:derbyTest;create=true\" />\n\t\t<property name=\"username\" value=\"canal\" />\n\t\t<property name=\"password\" value=\"canal\" />\n        <property name=\"maxActive\" value=\"30\" />\n        <property name=\"initialSize\" value=\"0\" />\n        <property name=\"minIdle\" value=\"1\" />\n        <property name=\"maxWait\" value=\"10000\" />\n        <property name=\"timeBetweenEvictionRunsMillis\" value=\"60000\" />\n        <property name=\"minEvictableIdleTimeMillis\" value=\"300000\" />\n        <property name=\"testWhileIdle\" value=\"true\" />\n        <property name=\"testOnBorrow\" value=\"false\" />\n        <property name=\"testOnReturn\" value=\"false\" />\n        <property name=\"useUnfairLock\" value=\"true\" />\n\t</bean>\n\n    <bean id=\"sqlSessionFactory\" class=\"org.mybatis.spring.SqlSessionFactoryBean\">\n        <property name=\"dataSource\" ref=\"dataSource\"/>\n        <property name=\"configLocation\" value=\"classpath:tsdb/sql-map/sqlmap-config.xml\"/>\n    </bean>\n\n    <bean id=\"metaHistoryDAO\" class=\"com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao.MetaHistoryDAO\">\n        <property name=\"sqlSessionFactory\" ref=\"sqlSessionFactory\"/>\n    </bean>\n\n    <bean id=\"metaSnapshotDAO\" class=\"com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao.MetaSnapshotDAO\">\n        <property name=\"sqlSessionFactory\" ref=\"sqlSessionFactory\"/>\n    </bean>\n</beans>\n"
  },
  {
    "path": "parse/src/test/resources/tsdb/h2-tsdb.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns=\"http://www.springframework.org/schema/beans\" xmlns:tx=\"http://www.springframework.org/schema/tx\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd\n\thttp://www.springframework.org/schema/tx\n    http://www.springframework.org/schema/tx/spring-tx-2.0.xsd\"\n       default-autowire=\"byName\">\n\t\n\t<!-- 基于db的实现 -->\n\t<bean id=\"tableMetaTSDB\" class=\"com.alibaba.otter.canal.parse.inbound.mysql.tsdb.DatabaseTableMeta\" destroy-method=\"destory\">\n\t\t<property name=\"metaHistoryDAO\" ref=\"metaHistoryDAO\"/>\n\t\t<property name=\"metaSnapshotDAO\" ref=\"metaSnapshotDAO\"/>\n\t</bean>\n\t\n    <bean id=\"dataSource\" class=\"com.alibaba.druid.pool.DruidDataSource\" destroy-method=\"close\">\n        <property name=\"driverClassName\" value=\"org.h2.Driver\" />\n        <property name=\"url\" value=\"jdbc:h2:/tmp/example;CACHE_SIZE=1000;MODE=MYSQL;\" />\n\t\t<property name=\"username\" value=\"canal\" />\n\t\t<property name=\"password\" value=\"canal\" />\n        <property name=\"maxActive\" value=\"30\" />\n        <property name=\"initialSize\" value=\"0\" />\n        <property name=\"minIdle\" value=\"1\" />\n        <property name=\"maxWait\" value=\"10000\" />\n        <property name=\"timeBetweenEvictionRunsMillis\" value=\"60000\" />\n        <property name=\"minEvictableIdleTimeMillis\" value=\"300000\" />\n        <property name=\"testWhileIdle\" value=\"true\" />\n        <property name=\"testOnBorrow\" value=\"false\" />\n        <property name=\"testOnReturn\" value=\"false\" />\n        <property name=\"useUnfairLock\" value=\"true\" />\n\t</bean>\n\n    <bean id=\"sqlSessionFactory\" class=\"org.mybatis.spring.SqlSessionFactoryBean\">\n        <property name=\"dataSource\" ref=\"dataSource\"/>\n        <property name=\"configLocation\" value=\"classpath:tsdb/sql-map/sqlmap-config.xml\"/>\n    </bean>\n\n    <bean id=\"metaHistoryDAO\" class=\"com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao.MetaHistoryDAO\">\n        <property name=\"sqlSessionFactory\" ref=\"sqlSessionFactory\"/>\n    </bean>\n\n    <bean id=\"metaSnapshotDAO\" class=\"com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao.MetaSnapshotDAO\">\n        <property name=\"sqlSessionFactory\" ref=\"sqlSessionFactory\"/>\n    </bean>\n</beans>\n"
  },
  {
    "path": "parse/src/test/resources/tsdb/mysql-tsdb.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns=\"http://www.springframework.org/schema/beans\" xmlns:tx=\"http://www.springframework.org/schema/tx\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd\n\thttp://www.springframework.org/schema/tx\n    http://www.springframework.org/schema/tx/spring-tx-2.0.xsd\"\n       default-autowire=\"byName\">\n\t\n\t<!-- 基于db的实现 -->\n\t<bean id=\"tableMetaTSDB\" class=\"com.alibaba.otter.canal.parse.inbound.mysql.tsdb.DatabaseTableMeta\" destroy-method=\"destory\">\n\t\t<property name=\"metaHistoryDAO\" ref=\"metaHistoryDAO\"/>\n\t\t<property name=\"metaSnapshotDAO\" ref=\"metaSnapshotDAO\"/>\n\t</bean>\n\t\n    <bean id=\"dataSource\" class=\"com.alibaba.druid.pool.DruidDataSource\" destroy-method=\"close\">\n        <property name=\"driverClassName\" value=\"com.mysql.jdbc.Driver\" />\n        <property name=\"url\" value=\"jdbc:mysql://127.0.0.1:3306/canal_tsdb\" />\n\t\t<property name=\"username\" value=\"canal\" />\n\t\t<property name=\"password\" value=\"canal\" />\n        <property name=\"maxActive\" value=\"30\" />\n        <property name=\"initialSize\" value=\"0\" />\n        <property name=\"minIdle\" value=\"1\" />\n        <property name=\"maxWait\" value=\"10000\" />\n        <property name=\"timeBetweenEvictionRunsMillis\" value=\"60000\" />\n        <property name=\"minEvictableIdleTimeMillis\" value=\"300000\" />\n        <property name=\"validationQuery\" value=\"SELECT 1\" />\n        <property name=\"exceptionSorterClassName\" value=\"com.alibaba.druid.pool.vendor.MySqlExceptionSorter\" />\n        <property name=\"validConnectionCheckerClassName\" value=\"com.alibaba.druid.pool.vendor.MySqlValidConnectionChecker\" />\n        <property name=\"testWhileIdle\" value=\"true\" />\n        <property name=\"testOnBorrow\" value=\"false\" />\n        <property name=\"testOnReturn\" value=\"false\" />\n        <property name=\"useUnfairLock\" value=\"true\" />\n\t</bean>\n\n    <bean id=\"sqlSessionFactory\" class=\"org.mybatis.spring.SqlSessionFactoryBean\">\n        <property name=\"dataSource\" ref=\"dataSource\"/>\n        <property name=\"configLocation\" value=\"classpath:tsdb/sql-map/sqlmap-config.xml\"/>\n    </bean>\n\n    <bean id=\"metaHistoryDAO\" class=\"com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao.MetaHistoryDAO\">\n        <property name=\"sqlSessionFactory\" ref=\"sqlSessionFactory\"/>\n    </bean>\n\n    <bean id=\"metaSnapshotDAO\" class=\"com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao.MetaSnapshotDAO\">\n        <property name=\"sqlSessionFactory\" ref=\"sqlSessionFactory\"/>\n    </bean>\n</beans>\n"
  },
  {
    "path": "parse/src/test/resources/tsdb/sql-map/sqlmap-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE configuration PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n<configuration>\n    <typeAliases>\n        <typeAlias alias=\"metaHistoryDO\" type=\"com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao.MetaHistoryDO\"/>\n        <typeAlias alias=\"metaSnapshotDO\" type=\"com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao.MetaSnapshotDO\"/>\n    </typeAliases>\n\n    <mappers>\n        <mapper resource=\"tsdb/sql-map/sqlmap_history.xml\"/>\n        <mapper resource=\"tsdb/sql-map/sqlmap_snapshot.xml\"/>\n    </mappers>\n</configuration>\n"
  },
  {
    "path": "parse/src/test/resources/tsdb/sql-map/sqlmap_history.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao.MetaHistoryMapper\">\n    <sql id=\"allColumns\">\n        <![CDATA[\n\t\tgmt_create,gmt_modified,destination,binlog_file,binlog_offest,binlog_master_id,binlog_timestamp,use_schema,sql_schema,sql_table,sql_text,sql_type,extra\n        ]]>\n    </sql>\n    <sql id=\"allVOColumns\">\n        <![CDATA[\n\t\ta.id as id,a.gmt_create as gmtCreate,a.gmt_modified as gmtModified,\n\t\ta.destination as destination,a.binlog_file as binlogFile,a.binlog_offest as binlogOffest,a.binlog_master_id as binlogMasterId,a.binlog_timestamp as binlogTimestamp,\n\t\ta.use_schema as useSchema,a.sql_schema as sqlSchema,a.sql_table as sqlTable,a.sql_text as sqlText,a.sql_type as sqlType,a.extra as extra\n        ]]>\n    </sql>\n\n    <select id=\"findByTimestamp\" parameterType=\"java.util.Map\" resultType=\"metaHistoryDO\">\n        select\n        <include refid=\"allVOColumns\"/>\n        from meta_history a\n        <![CDATA[\n        where destination = #{destination} and binlog_timestamp >= #{snapshotTimestamp} and binlog_timestamp <= #{timestamp}\n        order by binlog_timestamp asc,id asc\n        ]]>\n    </select>\n\n    <insert id=\"insert\" parameterType=\"metaHistoryDO\">\n        insert into meta_history (<include refid=\"allColumns\"/>)\n        values(CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,#{destination},#{binlogFile},#{binlogOffest},#{binlogMasterId},#{binlogTimestamp},#{useSchema},#{sqlSchema},#{sqlTable},#{sqlText},#{sqlType},#{extra})\n    </insert>\n\n    <delete id=\"deleteByName\" parameterType=\"java.util.Map\">\n        delete from meta_history\n        where destination=#{destination}\n    </delete>\n\n\n    <delete id=\"deleteByTimestamp\" parameterType=\"java.util.Map\">\n        <![CDATA[\n\t\tdelete from meta_history\n\t\twhere destination=#{destination} and binlog_timestamp < #{timestamp}\n        ]]>\n    </delete>\n</mapper>"
  },
  {
    "path": "parse/src/test/resources/tsdb/sql-map/sqlmap_snapshot.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.alibaba.otter.canal.parse.inbound.mysql.tsdb.dao.MetaSnapshotMapper\">\n    <sql id=\"allColumns\">\n        <![CDATA[\n\t\tgmt_create,gmt_modified,destination,binlog_file,binlog_offest,binlog_master_id,binlog_timestamp,data,extra\n        ]]>\n    </sql>\n    <sql id=\"allVOColumns\">\n        <![CDATA[\n\t\ta.id as id,a.gmt_create as gmtCreate,a.gmt_modified as gmtModified,\n\t\ta.destination as destination,a.binlog_file as binlogFile,a.binlog_offest as binlogOffest,a.binlog_master_id as binlogMasterId,a.binlog_timestamp as binlogTimestamp,a.data as data,a.extra as extra\n        ]]>\n    </sql>\n\n    <select id=\"findByTimestamp\" parameterType=\"java.util.Map\" resultType=\"metaSnapshotDO\">\n        select <include refid=\"allVOColumns\"/>\n        <![CDATA[\n        from meta_snapshot a\n        where destination = #{destination} and binlog_timestamp < #{timestamp}\n        order by binlog_timestamp desc,id desc\n        limit 1\n        ]]>\n    </select>\n\n    <insert id=\"insert\" parameterType=\"metaSnapshotDO\">\n        insert into meta_snapshot (<include refid=\"allColumns\"/>)\n        values(CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,#{destination},#{binlogFile},#{binlogOffest},#{binlogMasterId},#{binlogTimestamp},#{data},#{extra})\n    </insert>\n\n    <update id=\"update\" parameterType=\"metaSnapshotDO\">\n        update meta_snapshot set gmt_modified=now(),\n        binlog_file=#{binlogFile},binlog_offest=#{binlogOffest},binlog_master_id=#{binlogMasterId},binlog_timestamp=#{binlogTimestamp},data=#{data},extra=#{extra}\n        where destination=#{destination} and binlog_timestamp=0\n    </update>\n\n    <delete id=\"deleteByName\" parameterType=\"java.util.Map\">\n        delete from meta_snapshot\n        where destination=#{destination}\n    </delete>\n\n    <delete id=\"deleteByTimestamp\" parameterType=\"java.util.Map\">\n        <![CDATA[\n\t\tdelete from meta_snapshot\n\t\twhere destination=#{destination} and binlog_timestamp < #{timestamp} and binlog_timestamp > 0\n        ]]>\n    </delete>\n</mapper>"
  },
  {
    "path": "pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>com.alibaba.otter</groupId>\n    <artifactId>canal</artifactId>\n    <packaging>pom</packaging>\n    <name>canal module for otter ${project.version}</name>\n    <version>1.1.9-SNAPSHOT</version>\n    <url>https://github.com/alibaba/canal</url>\n    <developers>\n        <developer>\n            <name>agapple</name>\n            <url>http://agapple.iteye.com</url>\n            <email>jianghang115@gmail.com</email>\n            <timezone>8</timezone>\n        </developer>\n        <developer>\n            <name>zavakid</name>\n            <url>http://www.zavakid.com</url>\n            <email>zava.kid@gmail.com</email>\n            <timezone>8</timezone>\n        </developer>\n        <developer>\n            <name>in355hz</name>\n            <url>http://in355hz.iteye.com</url>\n            <email>in355hz@gmail.com</email>\n            <timezone>8</timezone>\n        </developer>\n    </developers>\n\n    <licenses>\n        <license>\n            <name>Apache License, Version 2.0</name>\n            <url>http://www.apache.org/licenses/LICENSE-2.0</url>\n        </license>\n    </licenses>\n\n    <scm>\n        <url>git@github.com:alibaba/canal.git</url>\n        <connection>scm:git:git@github.com:alibaba/canal.git</connection>\n        <developerConnection>scm:git:git@github.com:alibaba/canal.git</developerConnection>\n    </scm>\n\n    <repositories>\n        <repository>\n            <id>central</id>\n            <url>https://repo1.maven.org/maven2</url>\n            <releases>\n                <enabled>true</enabled>\n            </releases>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </repository>\n        <repository>\n            <id>java.net</id>\n            <url>https://download.java.net/maven/2/</url>\n            <releases>\n                <enabled>true</enabled>\n            </releases>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </repository>\n    </repositories>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <!--maven properties-->\n        <downloadSources>true</downloadSources>\n        <!-- compiler settings properties -->\n        <java_source_version>1.8</java_source_version>\n        <java_target_version>1.8</java_target_version>\n        <file_encoding>UTF-8</file_encoding>\n        <javadoc_skip>true</javadoc_skip>\n        <spring_version>5.3.26</spring_version>\n        <log4j_version>2.17.0</log4j_version>\n        <rocketmq_version>4.9.8</rocketmq_version>\n        <rabbitmq_version>5.18.0</rabbitmq_version>\n        <mq_amqp_client>1.0.3</mq_amqp_client>\n        <kafka_version>2.4.0</kafka_version>\n        <pulsar_version>2.11.4</pulsar_version>\n        <mysql_driver_version>5.1.48</mysql_driver_version>\n        <maven-jacoco-plugin.version>0.8.3</maven-jacoco-plugin.version>\n        <maven-surefire.version>2.22.1</maven-surefire.version>\n        <argline>-server -Xms512m -Xmx1024m -Dfile.encoding=UTF-8\n            -Djava.net.preferIPv4Stack=true -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m\n        </argline>\n        <maven-compiler-plugin.version>3.7.0</maven-compiler-plugin.version>\n        <javax.annotation-api.version>1.3.2</javax.annotation-api.version>\n    \t<closeTestReports>true</closeTestReports>\n    </properties>\n\n    <modules>\n        <module>common</module>\n        <module>meta</module>\n        <module>dbsync</module>\n        <module>filter</module>\n        <module>driver</module>\n        <module>parse</module>\n        <module>sink</module>\n        <module>store</module>\n        <module>protocol</module>\n        <module>instance</module>\n        <module>server</module>\n        <module>client</module>\n        <module>deployer</module>\n        <module>example</module>\n        <module>prometheus</module>\n        <module>admin</module>\n        <module>client-adapter</module>\n        <module>connector</module>\n    </modules>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-core</artifactId>\n                <version>${spring_version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-aop</artifactId>\n                <version>${spring_version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-context</artifactId>\n                <version>${spring_version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-jdbc</artifactId>\n                <version>${spring_version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-orm</artifactId>\n                <version>${spring_version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-tx</artifactId>\n                <version>${spring_version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-web</artifactId>\n                <version>${spring_version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-webmvc</artifactId>\n                <version>${spring_version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-jcl</artifactId>\n                <version>${spring_version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-expression</artifactId>\n                <version>${spring_version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-beans</artifactId>\n                <version>${spring_version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-test</artifactId>\n                <version>${spring_version}</version>\n                <scope>test</scope>\n            </dependency>\n            <!-- external -->\n            <dependency>\n                <groupId>commons-lang</groupId>\n                <artifactId>commons-lang</artifactId>\n                <version>2.6</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.commons</groupId>\n                <artifactId>commons-lang3</artifactId>\n                <version>3.7</version>\n            </dependency>\n            <dependency>\n                <groupId>commons-io</groupId>\n                <artifactId>commons-io</artifactId>\n                <version>2.4</version>\n            </dependency>\n            <dependency>\n                <groupId>commons-codec</groupId>\n                <artifactId>commons-codec</artifactId>\n                <version>1.9</version>\n            </dependency>\n            <dependency>\n                <groupId>commons-beanutils</groupId>\n                <artifactId>commons-beanutils</artifactId>\n                <version>1.9.4</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.commons</groupId>\n                <artifactId>commons-compress</artifactId>\n                <version>1.22</version>\n            </dependency>\n            <dependency>\n                <groupId>com.github.luben</groupId>\n                <artifactId>zstd-jni</artifactId>\n                <version>1.5.2-5</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.httpcomponents</groupId>\n                <artifactId>httpclient</artifactId>\n                <version>4.5.13</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.zookeeper</groupId>\n                <artifactId>zookeeper</artifactId>\n                <version>3.5.6</version>\n                <exclusions>\n                    <exclusion>\n                        <groupId>log4j</groupId>\n                        <artifactId>log4j</artifactId>\n                    </exclusion>\n                    <exclusion>\n                        <groupId>org.slf4j</groupId>\n                        <artifactId>slf4j-log4j12</artifactId>\n                    </exclusion>\n                    <exclusion>\n                        <groupId>org.slf4j</groupId>\n                        <artifactId>slf4j-api</artifactId>\n                    </exclusion>\n                    <exclusion>\n                        <groupId>jline</groupId>\n                        <artifactId>jline</artifactId>\n                    </exclusion>\n                    <exclusion>\n                        <groupId>io.netty</groupId>\n                        <artifactId>netty-handler</artifactId>\n                    </exclusion>\n                    <exclusion>\n                        <groupId>io.netty</groupId>\n                        <artifactId>netty-transport-native-epoll</artifactId>\n                    </exclusion>\n                </exclusions>\n            </dependency>\n            <dependency>\n                <groupId>com.101tec</groupId>\n                <artifactId>zkclient</artifactId>\n                <version>0.10</version>\n            </dependency>\n            <dependency>\n                <groupId>com.alibaba.fastjson2</groupId>\n                <artifactId>fastjson2</artifactId>\n                <version>2.0.31</version>\n            </dependency>\n            <dependency>\n                <groupId>com.google.guava</groupId>\n                <artifactId>guava</artifactId>\n                <version>22.0</version>\n            </dependency>\n            <dependency>\n                <groupId>com.googlecode.aviator</groupId>\n                <artifactId>aviator</artifactId>\n                <version>2.2.1</version>\n            </dependency>\n            <dependency>\n                <groupId>oro</groupId>\n                <artifactId>oro</artifactId>\n                <version>2.0.8</version>\n            </dependency>\n            <dependency>\n                <groupId>io.netty</groupId>\n                <artifactId>netty-all</artifactId>\n                <version>4.1.68.Final</version>\n            </dependency>\n            <dependency>\n                <groupId>org.jboss.netty</groupId>\n                <artifactId>netty</artifactId>\n                <version>3.2.10.Final</version>\n            </dependency>\n            <dependency>\n                <groupId>com.google.protobuf</groupId>\n                <artifactId>protobuf-java</artifactId>\n                <version>3.6.1</version>\n            </dependency>\n            <dependency>\n                <groupId>org.mybatis</groupId>\n                <artifactId>mybatis-spring</artifactId>\n                <version>2.0.4</version>\n            </dependency>\n            <dependency>\n                <groupId>org.mybatis</groupId>\n                <artifactId>mybatis</artifactId>\n                <version>3.5.6</version>\n            </dependency>\n            <dependency>\n                <groupId>com.alibaba</groupId>\n                <artifactId>druid</artifactId>\n                <version>1.2.21</version>\n            </dependency>\n            <dependency>\n                <groupId>com.lmax</groupId>\n                <artifactId>disruptor</artifactId>\n                <version>3.4.2</version>\n            </dependency>\n            <!-- log -->\n            <dependency>\n                <groupId>ch.qos.logback</groupId>\n                <artifactId>logback-core</artifactId>\n                <version>1.2.9</version>\n            </dependency>\n            <dependency>\n                <groupId>ch.qos.logback</groupId>\n                <artifactId>logback-classic</artifactId>\n                <version>1.2.9</version>\n            </dependency>\n            <dependency>\n                <groupId>org.slf4j</groupId>\n                <artifactId>jcl-over-slf4j</artifactId>\n                <version>1.7.12</version>\n            </dependency>\n            <dependency>\n                <groupId>org.slf4j</groupId>\n                <artifactId>slf4j-api</artifactId>\n                <version>1.7.12</version>\n            </dependency>\n            <dependency>\n                <groupId>com.h2database</groupId>\n                <artifactId>h2</artifactId>\n                <version>2.2.224</version>\n            </dependency>\n            <dependency>\n                <groupId>mysql</groupId>\n                <artifactId>mysql-connector-java</artifactId>\n                <version>${mysql_driver_version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.google.code.findbugs</groupId>\n                <artifactId>jsr305</artifactId>\n                <version>3.0.2</version>\n            </dependency>\n            <dependency>\n                <groupId>javax.annotation</groupId>\n                <artifactId>javax.annotation-api</artifactId>\n                <version>${javax.annotation-api.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.logging.log4j</groupId>\n                <artifactId>log4j-core</artifactId>\n                <version>${log4j_version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.logging.log4j</groupId>\n                <artifactId>log4j-api</artifactId>\n                <version>${log4j_version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.logging.log4j</groupId>\n                <artifactId>log4j-to-slf4j</artifactId>\n                <version>${log4j_version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.alibaba.polardbx</groupId>\n                <artifactId>polardbx-parser</artifactId>\n                <version>5.4.19</version>\n            </dependency>\n\n            <!-- test dependency -->\n            <dependency>\n                <groupId>junit</groupId>\n                <artifactId>junit</artifactId>\n                <version>4.12</version>\n                <scope>test</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.powermock</groupId>\n                <artifactId>powermock-api-mockito</artifactId>\n                <version>1.6.5</version>\n                <scope>test</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.powermock</groupId>\n                <artifactId>powermock-module-junit4</artifactId>\n                <version>1.6.5</version>\n                <scope>test</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.mockito</groupId>\n                <artifactId>mockito-all</artifactId>\n                <version>1.10.19</version>\n                <scope>test</scope>\n            </dependency>\n            <dependency>\n                <groupId>com.diffblue</groupId>\n                <artifactId>deeptestutils</artifactId>\n                <version>1.9.0</version>\n                <scope>test</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <build>\n        <extensions>\n            <extension>\n                <groupId>org.jvnet.wagon-svn</groupId>\n                <artifactId>wagon-svn</artifactId>\n                <version>1.9</version>\n            </extension>\n            <extension>\n                <groupId>org.apache.maven.wagon</groupId>\n                <artifactId>wagon-http-shared</artifactId>\n                <version>1.0-beta-7</version>\n            </extension>\n        </extensions>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-source-plugin</artifactId>\n                <version>2.4</version>\n                <executions>\n                    <execution>\n                        <id>attach-sources</id>\n                        <goals>\n                            <goal>jar</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>${maven-compiler-plugin.version}</version>\n                <configuration>\n                    <source>${java_source_version}</source>\n                    <target>${java_target_version}</target>\n                    <encoding>${file_encoding}</encoding>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n                <version>${maven-jacoco-plugin.version}</version>\n                <executions>\n                    <execution>\n                        <id>jacoco-initialize</id>\n                        <goals>\n                            <goal>prepare-agent</goal>\n                        </goals>\n                        <configuration>\n                            <propertyName>jacocoArgLine</propertyName>\n                        </configuration>\n                    </execution>\n                    <execution>\n                        <id>report-aggregate</id>\n                        <phase>verify</phase>\n                        <goals>\n                            <goal>report-aggregate</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>${maven-surefire.version}</version>\n                <configuration>\n                    <useSystemClassLoader>true</useSystemClassLoader>\n                    <forkMode>once</forkMode>\n                    <argLine>${argline} ${jacocoArgLine}</argLine>\n                    <systemProperties>\n                        <!-- common shared -->\n                    </systemProperties>\n                \t<parallel>classes</parallel>\n                \t<useUnlimitedThreads>true</useUnlimitedThreads>\n                \t<disableXmlReport>${closeTestReports}</disableXmlReport>\n\n                </configuration>\n            </plugin>\n            <!-- javadoc -->\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-javadoc-plugin</artifactId>\n                <version>2.9.1</version>\n                <executions>\n                    <execution>\n                            <id>attach-javadocs</id>\n                            <goals>\n                                <goal>jar</goal>\n                            </goals>\n                        </execution>\n                    </executions>\n                <configuration>\n                  <skip>${javadoc_skip}</skip>\n                  <!-- workaround for https://bugs.openjdk.java.net/browse/JDK-8212233 -->\n                  <javaApiLinks>\n                     <property>\n                         <name>foo</name>\n                         <value>bar</value>\n                     </property>\n                  </javaApiLinks>\n                  <encoding>${file_encoding}</encoding>\n                  <charset>${file_encoding}</charset>\n                  <additionalparam>-Xdoclint:none</additionalparam>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-gpg-plugin</artifactId>\n                <version>3.2.8</version>\n                <executions>\n                    <execution>\n                        <id>sign-artifacts</id>\n                        <phase>verify</phase>\n                        <goals>\n                            <goal>sign</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.sonatype.central</groupId>\n                <artifactId>central-publishing-maven-plugin</artifactId>\n                <version>0.8.0</version>\n                <extensions>true</extensions>\n                <configuration>\n                    <publishingServerId>central</publishingServerId>\n                </configuration>\n            </plugin>\n        </plugins>\n        <pluginManagement>\n            <plugins>\n                <plugin>\n                    <artifactId>maven-jar-plugin</artifactId>\n                    <version>3.0.2</version>\n                </plugin>\n            </plugins>\n        </pluginManagement>\n    </build>\n</project>\n"
  },
  {
    "path": "prometheus/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>canal</artifactId>\n        <groupId>com.alibaba.otter</groupId>\n        <version>1.1.9-SNAPSHOT</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>com.alibaba.otter</groupId>\n    <artifactId>canal.prometheus</artifactId>\n    <version>1.1.9-SNAPSHOT</version>\n    <name>canal prometheus module for otter ${project.version}</name>\n    <dependencies>\n        <dependency>\n            <groupId>org.jctools</groupId>\n            <artifactId>jctools-core</artifactId>\n            <version>2.1.2</version>\n        </dependency>\n        <dependency>\n            <groupId>io.prometheus</groupId>\n            <artifactId>simpleclient</artifactId>\n            <version>0.4.0</version>\n        </dependency>\n        <dependency>\n            <groupId>io.prometheus</groupId>\n            <artifactId>simpleclient_hotspot</artifactId>\n            <version>0.4.0</version>\n        </dependency>\n        <dependency>\n            <groupId>io.prometheus</groupId>\n            <artifactId>simpleclient_httpserver</artifactId>\n            <version>0.4.0</version>\n        </dependency>\n        <dependency>\n            <groupId>io.prometheus</groupId>\n            <artifactId>simpleclient_pushgateway</artifactId>\n            <version>0.4.0</version>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>canal.instance.core</artifactId>\n            <version>${project.version}</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>canal.server</artifactId>\n            <version>${project.version}</version>\n            <scope>provided</scope>\n        </dependency>\n    </dependencies>\n\n</project>\n"
  },
  {
    "path": "prometheus/src/main/java/com/alibaba/otter/canal/prometheus/CanalInstanceExports.java",
    "content": "package com.alibaba.otter.canal.prometheus;\n\nimport com.alibaba.otter.canal.instance.core.CanalInstance;\nimport com.alibaba.otter.canal.prometheus.impl.*;\nimport io.prometheus.client.Collector;\nimport io.prometheus.client.CollectorRegistry;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * @author Chuanyi Li\n */\npublic class CanalInstanceExports {\n\n    private static final Logger      logger           = LoggerFactory.getLogger(CanalInstanceExports.class);\n    public static final String       DEST             = \"destination\";\n    public static final String[]     DEST_LABELS      = {DEST};\n    public static final List<String> DEST_LABELS_LIST = Collections.singletonList(DEST);\n    private final Collector          storeCollector;\n    private final Collector          entryCollector;\n    private final Collector          metaCollector;\n    private final Collector          sinkCollector;\n    private final Collector          parserCollector;\n\n    private CanalInstanceExports() {\n        this.storeCollector = StoreCollector.instance();\n        this.entryCollector = EntryCollector.instance();\n        this.metaCollector = MetaCollector.instance();\n        this.sinkCollector = SinkCollector.instance();\n        this.parserCollector = ParserCollector.instance();\n    }\n\n    private static class SingletonHolder {\n        private static final CanalInstanceExports SINGLETON = new CanalInstanceExports();\n    }\n\n    public static CanalInstanceExports instance() {\n        return SingletonHolder.SINGLETON;\n    }\n\n    public void initialize() {\n        storeCollector.register();\n        entryCollector.register();\n        metaCollector.register();\n        sinkCollector.register();\n        parserCollector.register();\n    }\n\n    public void terminate() {\n        CollectorRegistry.defaultRegistry.unregister(storeCollector);\n        CollectorRegistry.defaultRegistry.unregister(entryCollector);\n        CollectorRegistry.defaultRegistry.unregister(metaCollector);\n        CollectorRegistry.defaultRegistry.unregister(sinkCollector);\n        CollectorRegistry.defaultRegistry.unregister(parserCollector);\n    }\n\n    void register(CanalInstance instance) {\n        requiredInstanceRegistry(storeCollector).register(instance);\n        requiredInstanceRegistry(entryCollector).register(instance);\n        requiredInstanceRegistry(metaCollector).register(instance);\n        requiredInstanceRegistry(sinkCollector).register(instance);\n        requiredInstanceRegistry(parserCollector).register(instance);\n        logger.info(\"Successfully register metrics for instance {}.\", instance.getDestination());\n    }\n\n    void unregister(CanalInstance instance) {\n        requiredInstanceRegistry(storeCollector).unregister(instance);\n        requiredInstanceRegistry(entryCollector).unregister(instance);\n        requiredInstanceRegistry(metaCollector).unregister(instance);\n        requiredInstanceRegistry(sinkCollector).unregister(instance);\n        requiredInstanceRegistry(parserCollector).unregister(instance);\n        logger.info(\"Successfully unregister metrics for instance {}.\", instance.getDestination());\n    }\n\n    private InstanceRegistry requiredInstanceRegistry(Collector collector) {\n        if (!(collector instanceof InstanceRegistry)) {\n            throw new IllegalArgumentException(\"Canal prometheus collector need to implement InstanceRegistry.\");\n        }\n        return (InstanceRegistry) collector;\n    }\n\n}\n"
  },
  {
    "path": "prometheus/src/main/java/com/alibaba/otter/canal/prometheus/InstanceRegistry.java",
    "content": "package com.alibaba.otter.canal.prometheus;\n\nimport com.alibaba.otter.canal.instance.core.CanalInstance;\n\n/**\n * @author Chuanyi Li\n */\npublic interface InstanceRegistry {\n\n    void register(CanalInstance instance);\n\n    void unregister(CanalInstance instance);\n\n}\n"
  },
  {
    "path": "prometheus/src/main/java/com/alibaba/otter/canal/prometheus/PrometheusProvider.java",
    "content": "package com.alibaba.otter.canal.prometheus;\n\nimport com.alibaba.otter.canal.spi.CanalMetricsProvider;\nimport com.alibaba.otter.canal.spi.CanalMetricsService;\n\n/**\n * @author Chuanyi Li\n */\npublic class PrometheusProvider implements CanalMetricsProvider {\n\n    @Override\n    public CanalMetricsService getService() {\n        return PrometheusService.getInstance();\n    }\n}\n"
  },
  {
    "path": "prometheus/src/main/java/com/alibaba/otter/canal/prometheus/PrometheusService.java",
    "content": "package com.alibaba.otter.canal.prometheus;\n\nimport com.alibaba.otter.canal.instance.core.CanalInstance;\nimport com.alibaba.otter.canal.prometheus.impl.PrometheusClientInstanceProfiler;\nimport com.alibaba.otter.canal.server.netty.ClientInstanceProfiler;\nimport com.alibaba.otter.canal.spi.CanalMetricsService;\nimport io.prometheus.client.exporter.HTTPServer;\nimport io.prometheus.client.hotspot.DefaultExports;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.IOException;\n\nimport static com.alibaba.otter.canal.server.netty.CanalServerWithNettyProfiler.NOP;\nimport static com.alibaba.otter.canal.server.netty.CanalServerWithNettyProfiler.profiler;\n\n/**\n * @author Chuanyi Li\n */\npublic class PrometheusService implements CanalMetricsService {\n\n    private static final Logger          logger          = LoggerFactory.getLogger(PrometheusService.class);\n    private final CanalInstanceExports   instanceExports;\n    private volatile boolean             running         = false;\n    private int                          port;\n    private HTTPServer                   server;\n    private final ClientInstanceProfiler clientProfiler;\n\n    private PrometheusService() {\n        this.instanceExports = CanalInstanceExports.instance();\n        this.clientProfiler = PrometheusClientInstanceProfiler.instance();\n    }\n\n    private static class SingletonHolder {\n        private static final PrometheusService SINGLETON = new PrometheusService();\n    }\n\n    public static PrometheusService getInstance() {\n        return SingletonHolder.SINGLETON;\n    }\n\n    @Override\n    public void initialize() {\n        try {\n            logger.info(\"Start prometheus HTTPServer on port {}.\", port);\n            //TODO 2.Https?\n            server = new HTTPServer(port);\n        } catch (IOException e) {\n            logger.warn(\"Unable to start prometheus HTTPServer.\", e);\n            return;\n        }\n        try {\n            // JVM exports\n            DefaultExports.initialize();\n            instanceExports.initialize();\n            if (!clientProfiler.isStart()) {\n                clientProfiler.start();\n            }\n            profiler().setInstanceProfiler(clientProfiler);\n        } catch (Throwable t) {\n            logger.warn(\"Unable to initialize server exports.\", t);\n        }\n\n        running = true;\n    }\n\n    @Override\n    public void terminate() {\n        running = false;\n        try {\n            instanceExports.terminate();\n            if (clientProfiler.isStart()) {\n                clientProfiler.stop();\n            }\n            profiler().setInstanceProfiler(NOP);\n            if (server != null) {\n                server.stop();\n            }\n        } catch (Throwable t) {\n            logger.warn(\"Something happened while terminating.\", t);\n        }\n    }\n\n    @Override\n    public boolean isRunning() {\n        return running;\n    }\n\n    @Override\n    public void register(CanalInstance instance) {\n        if (instance.isStart()) {\n            logger.warn(\"Cannot register metrics for destination {} that is running.\", instance.getDestination());\n            return;\n        }\n        try {\n            instanceExports.register(instance);\n        } catch (Throwable t) {\n            logger.warn(\"Unable to register instance exports for {}.\", instance.getDestination(), t);\n        }\n        logger.info(\"Register metrics for destination {}.\", instance.getDestination());\n    }\n\n    @Override\n    public void unregister(CanalInstance instance) {\n        if (instance.isStart()) {\n            logger.warn(\"Try unregister metrics after destination {} is stopped.\", instance.getDestination());\n        }\n        try {\n            instanceExports.unregister(instance);\n        } catch (Throwable t) {\n            logger.warn(\"Unable to unregister instance exports for {}.\", instance.getDestination(), t);\n        }\n        logger.info(\"Unregister metrics for destination {}.\", instance.getDestination());\n    }\n\n    @Override\n    public void setServerPort(int port) {\n        this.port = port;\n    }\n\n}\n"
  },
  {
    "path": "prometheus/src/main/java/com/alibaba/otter/canal/prometheus/impl/EntryCollector.java",
    "content": "package com.alibaba.otter.canal.prometheus.impl;\n\nimport com.alibaba.otter.canal.instance.core.CanalInstance;\nimport com.alibaba.otter.canal.prometheus.InstanceRegistry;\nimport com.alibaba.otter.canal.sink.CanalEventDownStreamHandler;\nimport com.alibaba.otter.canal.sink.CanalEventSink;\nimport com.alibaba.otter.canal.sink.entry.EntryEventSink;\nimport com.google.common.base.Preconditions;\nimport io.prometheus.client.Collector;\nimport io.prometheus.client.CounterMetricFamily;\nimport io.prometheus.client.GaugeMetricFamily;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport static com.alibaba.otter.canal.prometheus.CanalInstanceExports.DEST_LABELS_LIST;\n\n/**\n * @author Chuanyi Li\n */\npublic class EntryCollector extends Collector implements InstanceRegistry {\n\n    private static final Logger                             logger            = LoggerFactory.getLogger(SinkCollector.class);\n    private static final String                             DELAY             = \"canal_instance_traffic_delay\";\n    private static final String                             TRANSACTION       = \"canal_instance_transactions\";\n    private static final String                             DELAY_HELP        = \"Traffic delay of canal instance in milliseconds\";\n    private static final String                             TRANSACTION_HELP  = \"Transactions counter of canal instance\";\n    private final ConcurrentMap<String, EntryMetricsHolder> instances        = new ConcurrentHashMap<>();\n\n    private EntryCollector() {}\n\n    private static class SingletonHolder {\n        private static final EntryCollector SINGLETON = new EntryCollector();\n    }\n\n    public static EntryCollector instance() {\n        return SingletonHolder.SINGLETON;\n    }\n\n    @Override\n    public List<MetricFamilySamples> collect() {\n        List<MetricFamilySamples> mfs = new ArrayList<>();\n        GaugeMetricFamily delay = new GaugeMetricFamily(DELAY,\n                DELAY_HELP, DEST_LABELS_LIST);\n        CounterMetricFamily transactions = new CounterMetricFamily(TRANSACTION,\n                TRANSACTION_HELP, DEST_LABELS_LIST);\n        for (EntryMetricsHolder emh : instances.values()) {\n            long now = System.currentTimeMillis();\n            long latest = emh.latestExecTime.get();\n            // execTime > now，delay显示为0\n            long d = (now >= latest) ? (now - latest) : 0;\n            delay.addMetric(emh.destLabelValues, d);\n            transactions.addMetric(emh.destLabelValues, emh.transactionCounter.doubleValue());\n        }\n        mfs.add(delay);\n        mfs.add(transactions);\n        return mfs;\n    }\n\n    @Override\n    public void register(CanalInstance instance) {\n        final String destination = instance.getDestination();\n        EntryMetricsHolder holder = new EntryMetricsHolder();\n        holder.destLabelValues = Collections.singletonList(destination);\n        CanalEventSink sink = instance.getEventSink();\n        if (!(sink instanceof EntryEventSink)) {\n            throw new IllegalArgumentException(\"CanalEventSink must be EntryEventSink\");\n        }\n        EntryEventSink entrySink = (EntryEventSink) sink;\n        PrometheusCanalEventDownStreamHandler handler = assembleHandler(entrySink);\n        holder.latestExecTime = handler.getLatestExecuteTime();\n        holder.transactionCounter = handler.getTransactionCounter();\n        Preconditions.checkNotNull(holder.latestExecTime);\n        Preconditions.checkNotNull(holder.transactionCounter);\n        EntryMetricsHolder old = instances.put(destination, holder);\n        if (old != null) {\n            logger.warn(\"Remove stale EntryCollector for instance {}.\", destination);\n        }\n    }\n\n    @Override\n    public void unregister(CanalInstance instance) {\n        final String destination = instance.getDestination();\n        CanalEventSink sink = instance.getEventSink();\n        if (!(sink instanceof EntryEventSink)) {\n            throw new IllegalArgumentException(\"CanalEventSink must be EntryEventSink\");\n        }\n        unloadHandler((EntryEventSink) sink);\n        instances.remove(destination);\n    }\n\n    private PrometheusCanalEventDownStreamHandler assembleHandler(EntryEventSink entrySink) {\n        PrometheusCanalEventDownStreamHandler ph = new PrometheusCanalEventDownStreamHandler();\n        List<CanalEventDownStreamHandler> handlers = entrySink.getHandlers();\n        for (CanalEventDownStreamHandler handler : handlers) {\n            if (handler instanceof PrometheusCanalEventDownStreamHandler) {\n                throw new IllegalStateException(\"PrometheusCanalEventDownStreamHandler already exists in handlers.\");\n            }\n        }\n        entrySink.addHandler(ph, 0);\n        return ph;\n    }\n\n    private void unloadHandler(EntryEventSink entrySink) {\n        List<CanalEventDownStreamHandler> handlers = entrySink.getHandlers();\n        int i = 0;\n        for (; i < handlers.size(); i++) {\n            if (handlers.get(i) instanceof PrometheusCanalEventDownStreamHandler) {\n                break;\n            }\n        }\n        entrySink.removeHandler(i);\n        // Ensure no PrometheusCanalEventDownStreamHandler\n        handlers = entrySink.getHandlers();\n        for (CanalEventDownStreamHandler handler : handlers) {\n            if (handler instanceof PrometheusCanalEventDownStreamHandler) {\n                throw new IllegalStateException(\"Multiple prometheusCanalEventDownStreamHandler exists in handlers.\");\n            }\n        }\n    }\n\n    private static class EntryMetricsHolder {\n        private AtomicLong   latestExecTime;\n        private AtomicLong   transactionCounter;\n        private List<String> destLabelValues;\n    }\n\n}\n"
  },
  {
    "path": "prometheus/src/main/java/com/alibaba/otter/canal/prometheus/impl/MetaCollector.java",
    "content": "package com.alibaba.otter.canal.prometheus.impl;\n\nimport com.alibaba.otter.canal.instance.core.CanalInstance;\nimport com.alibaba.otter.canal.instance.spring.CanalInstanceWithSpring;\nimport com.alibaba.otter.canal.meta.CanalMetaManager;\nimport com.alibaba.otter.canal.prometheus.InstanceRegistry;\nimport com.alibaba.otter.canal.protocol.ClientIdentity;\nimport com.google.common.base.Preconditions;\nimport io.prometheus.client.Collector;\nimport io.prometheus.client.GaugeMetricFamily;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\nimport static com.alibaba.otter.canal.prometheus.CanalInstanceExports.DEST_LABELS_LIST;\n\n/**\n * @author Chuanyi Li\n */\npublic class MetaCollector extends Collector implements InstanceRegistry {\n\n    private static final List<String>                      INFO_LABELS_LIST  = Arrays.asList(\"destination\", \"mode\");\n    private static final Logger                            logger            = LoggerFactory.getLogger(MetaCollector.class);\n    private static final String                            INSTANCE          = \"canal_instance\";\n    private static final String                            INSTANCE_HELP     = \"Canal instance\";\n    private static final String                            SUBSCRIPTION      = \"canal_instance_subscriptions\";\n    private static final String                            SUBSCRIPTION_HELP = \"Canal instance subscriptions\";\n    private final ConcurrentMap<String, MetaMetricsHolder> instances         = new ConcurrentHashMap<>();\n\n    private MetaCollector() {}\n\n    private static class SingletonHolder {\n        private static final MetaCollector SINGLETON = new MetaCollector();\n    }\n\n    public static MetaCollector instance() {\n        return SingletonHolder.SINGLETON;\n    }\n\n    @Override\n    public List<MetricFamilySamples> collect() {\n        List<MetricFamilySamples> mfs = new ArrayList<>();\n        GaugeMetricFamily instanceInfo = new GaugeMetricFamily(INSTANCE,\n                INSTANCE_HELP, INFO_LABELS_LIST);\n        GaugeMetricFamily subsInfo = new GaugeMetricFamily(SUBSCRIPTION,\n                SUBSCRIPTION_HELP, DEST_LABELS_LIST);\n        for (Map.Entry<String, MetaMetricsHolder> nme : instances.entrySet()) {\n            final String destination = nme.getKey();\n            final MetaMetricsHolder nmh = nme.getValue();\n            instanceInfo.addMetric(nmh.infoLabelValues, 1);\n            List<ClientIdentity> subs = nmh.metaManager.listAllSubscribeInfo(destination);\n            int count = subs == null ? 0 : subs.size();\n            subsInfo.addMetric(nmh.destLabelValues, count);\n        }\n        mfs.add(instanceInfo);\n        mfs.add(subsInfo);\n        return mfs;\n    }\n\n    @Override\n    public void register(CanalInstance instance) {\n        final String destination = instance.getDestination();\n        MetaMetricsHolder holder = new MetaMetricsHolder();\n        String mode = (instance instanceof CanalInstanceWithSpring) ? \"spring\" : \"manager\";\n        holder.infoLabelValues = Arrays.asList(destination, mode);\n        holder.destLabelValues = Collections.singletonList(destination);\n        holder.metaManager = instance.getMetaManager();\n        Preconditions.checkNotNull(holder.metaManager);\n        MetaMetricsHolder old = instances.put(destination, holder);\n        if (old != null) {\n            logger.warn(\"Remove stale MetaCollector for instance {}.\", destination);\n        }\n    }\n\n    @Override\n    public void unregister(CanalInstance instance) {\n        final String destination = instance.getDestination();\n        instances.remove(destination);\n    }\n\n    private static class MetaMetricsHolder {\n        private List<String>     infoLabelValues;\n        private List<String>     destLabelValues;\n        private CanalMetaManager metaManager;\n    }\n\n\n}\n"
  },
  {
    "path": "prometheus/src/main/java/com/alibaba/otter/canal/prometheus/impl/ParserCollector.java",
    "content": "package com.alibaba.otter.canal.prometheus.impl;\n\nimport static com.alibaba.otter.canal.prometheus.CanalInstanceExports.DEST;\n\nimport com.alibaba.otter.canal.parse.inbound.group.GroupEventParser;\nimport com.alibaba.otter.canal.parse.inbound.mysql.AbstractMysqlEventParser;\nimport io.prometheus.client.Collector;\nimport io.prometheus.client.CounterMetricFamily;\nimport io.prometheus.client.GaugeMetricFamily;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.instance.core.CanalInstance;\nimport com.alibaba.otter.canal.parse.CanalEventParser;\nimport com.alibaba.otter.canal.prometheus.InstanceRegistry;\nimport com.google.common.base.Preconditions;\n\n/**\n * @author Chuanyi Li\n */\npublic class ParserCollector extends Collector implements InstanceRegistry {\n\n    private static final Logger                              logger                = LoggerFactory.getLogger(ParserCollector.class);\n    private static final long                                NANO_PER_MILLI        = 1000 * 1000L;\n    private static final String                              PUBLISH_BLOCKING      = \"canal_instance_publish_blocking_time\";\n    private static final String                              RECEIVED_BINLOG       = \"canal_instance_received_binlog_bytes\";\n    private static final String                              PARSER_MODE           = \"canal_instance_parser_mode\";\n    private static final String                              MODE_LABEL            = \"parallel\";\n    private static final String                              PARSER_LABEL          = \"parser\";\n    private static final String                              PUBLISH_BLOCKING_HELP = \"Publish blocking time of dump thread in milliseconds\";\n    private static final String                              RECEIVED_BINLOG_HELP  = \"Received binlog bytes\";\n    private static final String                              MODE_HELP             = \"Parser mode(parallel/serial) of instance\";\n    private final List<String>                               modeLabels            = Arrays.asList(DEST, MODE_LABEL);\n    private final List<String>                               parserLabels          = Arrays.asList(DEST, PARSER_LABEL);\n    private final ConcurrentMap<String, ParserMetricsHolder> instances             = new ConcurrentHashMap<>();\n\n    private ParserCollector() {}\n\n    private static class SingletonHolder {\n        private static final ParserCollector SINGLETON = new ParserCollector();\n    }\n\n    public static ParserCollector instance() {\n        return SingletonHolder.SINGLETON;\n    }\n\n    @Override\n    public List<MetricFamilySamples> collect() {\n        List<MetricFamilySamples> mfs = new ArrayList<>();\n        CounterMetricFamily bytesCounter = new CounterMetricFamily(RECEIVED_BINLOG,\n                RECEIVED_BINLOG_HELP, parserLabels);\n        GaugeMetricFamily modeGauge = new GaugeMetricFamily(PARSER_MODE,\n                MODE_HELP, modeLabels);\n        CounterMetricFamily blockingCounter = new CounterMetricFamily(PUBLISH_BLOCKING,\n                PUBLISH_BLOCKING_HELP, parserLabels);\n        for (ParserMetricsHolder emh : instances.values()) {\n            if (emh instanceof GroupParserMetricsHolder) {\n                GroupParserMetricsHolder group = (GroupParserMetricsHolder) emh;\n                for (ParserMetricsHolder semh :  group.holders) {\n                    singleCollect(bytesCounter, blockingCounter, modeGauge, semh);\n                }\n            }\n            else {\n                singleCollect(bytesCounter, blockingCounter, modeGauge, emh);\n            }\n        }\n        mfs.add(bytesCounter);\n        mfs.add(modeGauge);\n        if (!blockingCounter.samples.isEmpty()) {\n            mfs.add(blockingCounter);\n        }\n        return mfs;\n    }\n\n    private void singleCollect(CounterMetricFamily bytesCounter, CounterMetricFamily blockingCounter, GaugeMetricFamily modeGauge, ParserMetricsHolder holder) {\n        if (holder.isParallel) {\n            blockingCounter.addMetric(holder.parserLabelValues, (holder.eventsPublishBlockingTime.doubleValue() / NANO_PER_MILLI));\n        }\n        modeGauge.addMetric(holder.modeLabelValues, 1);\n        bytesCounter.addMetric(holder.parserLabelValues, holder.receivedBinlogBytes.doubleValue());\n    }\n\n    @Override\n    public void register(CanalInstance instance) {\n        final String destination = instance.getDestination();\n        ParserMetricsHolder holder;\n        CanalEventParser parser = instance.getEventParser();\n        if (parser instanceof AbstractMysqlEventParser) {\n            holder = singleHolder(destination, (AbstractMysqlEventParser)parser, \"0\");\n        } else if (parser instanceof GroupEventParser) {\n            holder = groupHolder(destination, (GroupEventParser)parser);\n        } else {\n            throw new IllegalArgumentException(\"CanalEventParser must be either AbstractMysqlEventParser or GroupEventParser.\");\n        }\n        Preconditions.checkNotNull(holder);\n        ParserMetricsHolder old = instances.put(destination, holder);\n        if (old != null) {\n            logger.warn(\"Remove stale ParserCollector for instance {}.\", destination);\n        }\n    }\n\n    private ParserMetricsHolder singleHolder(String destination, AbstractMysqlEventParser parser, String id) {\n        ParserMetricsHolder holder = new ParserMetricsHolder();\n        holder.parserLabelValues = Arrays.asList(destination, id);\n        holder.modeLabelValues = Arrays.asList(destination, Boolean.toString(parser.isParallel()));\n        holder.eventsPublishBlockingTime = parser.getEventsPublishBlockingTime();\n        holder.receivedBinlogBytes = parser.getReceivedBinlogBytes();\n        holder.isParallel = parser.isParallel();\n        Preconditions.checkNotNull(holder.eventsPublishBlockingTime);\n        Preconditions.checkNotNull(holder.receivedBinlogBytes);\n        return holder;\n    }\n\n    private GroupParserMetricsHolder groupHolder(String destination, GroupEventParser group) {\n        List<CanalEventParser> parsers = group.getEventParsers();\n        GroupParserMetricsHolder groupHolder = new GroupParserMetricsHolder();\n        int num = parsers.size();\n        for (int i = 0; i < num; i ++) {\n            CanalEventParser parser = parsers.get(i);\n            if (parser instanceof AbstractMysqlEventParser) {\n                ParserMetricsHolder single = singleHolder(destination, (AbstractMysqlEventParser)parser, Integer.toString(i + 1));\n                groupHolder.holders.add(single);\n            } else {\n                logger.warn(\"Null or non AbstractMysqlEventParser, ignore.\");\n            }\n        }\n        return groupHolder;\n    }\n\n    @Override\n    public void unregister(CanalInstance instance) {\n        final String destination = instance.getDestination();\n        instances.remove(destination);\n    }\n\n    private static class ParserMetricsHolder {\n        private List<String> parserLabelValues;\n        private List<String> modeLabelValues;\n        // metrics for single parser\n        private AtomicLong   receivedBinlogBytes;\n        private AtomicLong   eventsPublishBlockingTime;\n        // parser mode\n        private boolean      isParallel;\n    }\n\n    private static class GroupParserMetricsHolder extends ParserMetricsHolder {\n        private final List<ParserMetricsHolder> holders = new ArrayList<>();\n    }\n\n}\n"
  },
  {
    "path": "prometheus/src/main/java/com/alibaba/otter/canal/prometheus/impl/PrometheusCanalEventDownStreamHandler.java",
    "content": "package com.alibaba.otter.canal.prometheus.impl;\n\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport com.alibaba.otter.canal.protocol.CanalEntry;\nimport com.alibaba.otter.canal.protocol.CanalEntry.EntryType;\nimport com.alibaba.otter.canal.sink.AbstractCanalEventDownStreamHandler;\nimport com.alibaba.otter.canal.store.model.Event;\n\n/**\n * @author Chuanyi Li\n */\npublic class PrometheusCanalEventDownStreamHandler extends AbstractCanalEventDownStreamHandler<List<Event>> {\n\n    private final AtomicLong latestExecuteTime  = new AtomicLong(System.currentTimeMillis());\n    private final AtomicLong transactionCounter = new AtomicLong(0L);\n\n    @Override\n    public List<Event> before(List<Event> events) {\n        long localExecTime = 0L;\n        if (events != null && !events.isEmpty()) {\n            for (Event e : events) {\n                EntryType type = e.getEntryType();\n                if (type == null) continue;\n                switch (type) {\n                    case TRANSACTIONBEGIN: {\n                        long exec = e.getExecuteTime();\n                        if (exec > 0) {\n                            localExecTime = exec;\n                        }\n                        break;\n                    }\n                    case ROWDATA: {\n                        long exec = e.getExecuteTime();\n                        if (exec > 0) {\n                            localExecTime = exec;\n                        }\n                        break;\n                    }\n                    case TRANSACTIONEND: {\n                        long exec = e.getExecuteTime();\n                        if (exec > 0) {\n                            localExecTime = exec;\n                        }\n                        transactionCounter.incrementAndGet();\n                        break;\n                    }\n                    case HEARTBEAT:\n                        CanalEntry.EventType eventType = e.getEventType();\n                        if (eventType == CanalEntry.EventType.MHEARTBEAT) {\n                            localExecTime = System.currentTimeMillis();\n                        }\n                        break;\n                    default:\n                        break;\n                }\n            }\n            if (localExecTime > 0) {\n                latestExecuteTime.set(localExecTime);\n            }\n        }\n        return events;\n    }\n\n    @Override\n    public void start() {\n\n        super.start();\n    }\n\n    @Override\n    public void stop() {\n        super.stop();\n    }\n\n    public AtomicLong getLatestExecuteTime() {\n        return latestExecuteTime;\n    }\n\n    public AtomicLong getTransactionCounter() {\n        return transactionCounter;\n    }\n\n}\n"
  },
  {
    "path": "prometheus/src/main/java/com/alibaba/otter/canal/prometheus/impl/PrometheusClientInstanceProfiler.java",
    "content": "package com.alibaba.otter.canal.prometheus.impl;\n\nimport com.alibaba.otter.canal.protocol.CanalPacket.PacketType;\nimport com.alibaba.otter.canal.server.netty.ClientInstanceProfiler;\nimport com.alibaba.otter.canal.server.netty.listener.ChannelFutureAggregator.ClientRequestResult;\nimport io.prometheus.client.CollectorRegistry;\nimport io.prometheus.client.Counter;\nimport io.prometheus.client.Histogram;\n\nimport static com.alibaba.otter.canal.prometheus.CanalInstanceExports.DEST;\nimport static com.alibaba.otter.canal.prometheus.CanalInstanceExports.DEST_LABELS;\n\n/**\n * @author Chuanyi Li\n */\npublic class PrometheusClientInstanceProfiler implements ClientInstanceProfiler {\n\n    private static final long   NANO_PER_MILLI = 1000 * 1000L;\n    private static final String PACKET_TYPE    = \"canal_instance_client_packets\";\n    private static final String OUTBOUND_BYTES = \"canal_instance_client_bytes\";\n    private static final String EMPTY_BATCHES  = \"canal_instance_client_empty_batches\";\n    private static final String ERRORS         = \"canal_instance_client_request_error\";\n    private static final String LATENCY        = \"canal_instance_client_request_latency\";\n    private final Counter       outboundCounter;\n    private final Counter       packetsCounter;\n    private final Counter       emptyBatchesCounter;\n    private final Counter       errorsCounter;\n    private final Histogram     responseLatency;\n    private volatile boolean    running        = false;\n\n    private static class SingletonHolder {\n        private static final PrometheusClientInstanceProfiler SINGLETON = new PrometheusClientInstanceProfiler();\n    }\n\n    public static PrometheusClientInstanceProfiler instance() {\n        return SingletonHolder.SINGLETON;\n    }\n\n    private PrometheusClientInstanceProfiler() {\n        this.outboundCounter = Counter.build()\n                .labelNames(DEST_LABELS)\n                .name(OUTBOUND_BYTES)\n                .help(\"Total bytes sent to client.\")\n                .create();\n        this.packetsCounter = Counter.build()\n                .labelNames(new String[]{DEST, \"packetType\"})\n                .name(PACKET_TYPE)\n                .help(\"Total packets sent to client.\")\n                .create();\n        this.emptyBatchesCounter = Counter.build()\n                .labelNames(DEST_LABELS)\n                .name(EMPTY_BATCHES)\n                .help(\"Total empty batches sent to client.\")\n                .create();\n        this.errorsCounter = Counter.build()\n                .labelNames(new String[]{DEST, \"errorCode\"})\n                .name(ERRORS)\n                .help(\"Total client request errors.\")\n                .create();\n        this.responseLatency = Histogram.build()\n                .labelNames(DEST_LABELS)\n                .name(LATENCY)\n                .help(\"Client request latency.\")\n                // buckets in milliseconds\n                .buckets(2.5, 10.0, 25.0, 100.0)\n                .create();\n    }\n\n    @Override\n    public void profiling(ClientRequestResult result) {\n        String destination = result.getDestination();\n        PacketType type = result.getType();\n        outboundCounter.labels(destination).inc(result.getAmount());\n        short errorCode = result.getErrorCode();\n        if (errorCode > 0) {\n            errorsCounter.labels(destination, Short.toString(errorCode)).inc();\n        }\n        long latency = result.getLatency();\n        responseLatency.labels(destination).observe(((double) latency) / NANO_PER_MILLI);\n        switch (type) {\n            case GET:\n                boolean empty = result.getEmpty();\n                // 区分一下空包\n                if (empty) {\n                    emptyBatchesCounter.labels(destination).inc();\n                } else {\n                    packetsCounter.labels(destination, type.name()).inc();\n                }\n                break;\n            // reserve for others\n            default:\n                packetsCounter.labels(destination, type.name()).inc();\n                break;\n        }\n    }\n\n    @Override\n    public void start() {\n        if (outboundCounter != null) {\n            outboundCounter.register();\n        }\n        if (packetsCounter != null) {\n            packetsCounter.register();\n        }\n        if (emptyBatchesCounter != null) {\n            emptyBatchesCounter.register();\n        }\n        if (errorsCounter != null) {\n            errorsCounter.register();\n        }\n        if (responseLatency != null) {\n            responseLatency.register();\n        }\n        running = true;\n    }\n\n    @Override\n    public void stop() {\n        running = false;\n        if (outboundCounter != null) {\n            CollectorRegistry.defaultRegistry.unregister(outboundCounter);\n        }\n        if (packetsCounter != null) {\n            CollectorRegistry.defaultRegistry.unregister(packetsCounter);\n        }\n        if (emptyBatchesCounter != null) {\n            CollectorRegistry.defaultRegistry.unregister(emptyBatchesCounter);\n        }\n        if (errorsCounter != null) {\n            CollectorRegistry.defaultRegistry.unregister(errorsCounter);\n        }\n        if (responseLatency != null) {\n            CollectorRegistry.defaultRegistry.unregister(responseLatency);\n        }\n    }\n\n    @Override\n    public boolean isStart() {\n        return running;\n    }\n}\n"
  },
  {
    "path": "prometheus/src/main/java/com/alibaba/otter/canal/prometheus/impl/SinkCollector.java",
    "content": "package com.alibaba.otter.canal.prometheus.impl;\n\nimport static com.alibaba.otter.canal.prometheus.CanalInstanceExports.DEST_LABELS_LIST;\nimport io.prometheus.client.Collector;\nimport io.prometheus.client.CounterMetricFamily;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.instance.core.CanalInstance;\nimport com.alibaba.otter.canal.prometheus.InstanceRegistry;\nimport com.alibaba.otter.canal.sink.CanalEventSink;\nimport com.alibaba.otter.canal.sink.entry.EntryEventSink;\nimport com.google.common.base.Preconditions;\n\n/**\n * @author Chuanyi Li\n */\npublic class SinkCollector extends Collector implements InstanceRegistry {\n\n    private static final Logger                            logger               = LoggerFactory.getLogger(SinkCollector.class);\n    private static final long                              NANO_PER_MILLI       = 1000 * 1000L;\n    private static final String                            SINK_BLOCKING_TIME   = \"canal_instance_sink_blocking_time\";\n    private static final String                            SINK_BLOCK_TIME_HELP = \"Total sink blocking time in milliseconds\";\n    private final ConcurrentMap<String, SinkMetricsHolder> instances            = new ConcurrentHashMap<>();\n\n    private SinkCollector(){\n    }\n\n    private static class SingletonHolder {\n\n        private static final SinkCollector SINGLETON = new SinkCollector();\n    }\n\n    public static SinkCollector instance() {\n        return SingletonHolder.SINGLETON;\n    }\n\n    @Override\n    public List<MetricFamilySamples> collect() {\n        List<MetricFamilySamples> mfs = new ArrayList<>();\n        CounterMetricFamily blockingCounter = new CounterMetricFamily(SINK_BLOCKING_TIME,\n            SINK_BLOCK_TIME_HELP,\n            DEST_LABELS_LIST);\n        for (SinkMetricsHolder smh : instances.values()) {\n            blockingCounter.addMetric(smh.destLabelValues, (smh.eventsSinkBlockingTime.doubleValue() / NANO_PER_MILLI));\n        }\n        mfs.add(blockingCounter);\n        return mfs;\n    }\n\n    @Override\n    public void register(CanalInstance instance) {\n        final String destination = instance.getDestination();\n        SinkMetricsHolder holder = new SinkMetricsHolder();\n        holder.destLabelValues = Collections.singletonList(destination);\n        CanalEventSink sink = instance.getEventSink();\n        if (!(sink instanceof EntryEventSink)) {\n            throw new IllegalArgumentException(\"CanalEventSink must be EntryEventSink\");\n        }\n        EntryEventSink entrySink = (EntryEventSink) sink;\n        holder.eventsSinkBlockingTime = entrySink.getEventsSinkBlockingTime();\n        Preconditions.checkNotNull(holder.eventsSinkBlockingTime);\n        SinkMetricsHolder old = instances.put(destination, holder);\n        if (old != null) {\n            logger.warn(\"Remote stale SinkCollector for instance {}.\", destination);\n        }\n    }\n\n    @Override\n    public void unregister(CanalInstance instance) {\n        final String destination = instance.getDestination();\n        instances.remove(destination);\n    }\n\n    private static class SinkMetricsHolder {\n\n        private AtomicLong   eventsSinkBlockingTime;\n        private List<String> destLabelValues;\n    }\n}\n"
  },
  {
    "path": "prometheus/src/main/java/com/alibaba/otter/canal/prometheus/impl/StoreCollector.java",
    "content": "package com.alibaba.otter.canal.prometheus.impl;\n\nimport static com.alibaba.otter.canal.prometheus.CanalInstanceExports.DEST;\nimport static com.alibaba.otter.canal.prometheus.CanalInstanceExports.DEST_LABELS_LIST;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.instance.core.CanalInstance;\nimport com.alibaba.otter.canal.prometheus.InstanceRegistry;\nimport com.alibaba.otter.canal.store.CanalEventStore;\nimport com.alibaba.otter.canal.store.memory.MemoryEventStoreWithBuffer;\nimport com.alibaba.otter.canal.store.model.BatchMode;\nimport com.google.common.base.Preconditions;\n\nimport io.prometheus.client.Collector;\nimport io.prometheus.client.CounterMetricFamily;\nimport io.prometheus.client.GaugeMetricFamily;\n\n/**\n * @author Chuanyi Li\n */\npublic class StoreCollector extends Collector implements InstanceRegistry {\n\n    private static final Logger                             logger           = LoggerFactory\n        .getLogger(SinkCollector.class);\n    private static final String                             PRODUCE          = \"canal_instance_store_produce_seq\";\n    private static final String                             CONSUME          = \"canal_instance_store_consume_seq\";\n    private static final String                             STORE            = \"canal_instance_store\";\n    private static final String                             PRODUCE_MEM      = \"canal_instance_store_produce_mem\";\n    private static final String                             CONSUME_MEM      = \"canal_instance_store_consume_mem\";\n    private static final String                             PUT_DELAY        = \"canal_instance_put_delay\";\n    private static final String                             GET_DELAY        = \"canal_instance_get_delay\";\n    private static final String                             ACK_DELAY        = \"canal_instance_ack_delay\";\n    private static final String                             PUT_ROWS         = \"canal_instance_put_rows\";\n    private static final String                             GET_ROWS         = \"canal_instance_get_rows\";\n    private static final String                             ACK_ROWS         = \"canal_instance_ack_rows\";\n    private static final String                             PRODUCE_HELP     = \"Produced events counter of canal instance\";\n    private static final String                             CONSUME_HELP     = \"Consumed events counter of canal instance\";\n    private static final String                             STORE_HELP       = \"Canal instance info\";\n    private static final String                             PRODUCE_MEM_HELP = \"Produced mem bytes of canal instance\";\n    private static final String                             CONSUME_MEM_HELP = \"Consumed mem bytes of canal instance\";\n    private static final String                             PUT_DELAY_HELP   = \"Traffic delay of canal instance put\";\n    private static final String                             GET_DELAY_HELP   = \"Traffic delay of canal instance get\";\n    private static final String                             ACK_DELAY_HELP   = \"Traffic delay of canal instance ack\";\n    private static final String                             PUT_ROWS_HELP    = \"Put table rows of canal instance\";\n    private static final String                             GET_ROWS_HELP    = \"Got table rows of canal instance\";\n    private static final String                             ACK_ROWS_HELP    = \"Acked table rows of canal instance\";\n    private final ConcurrentMap<String, StoreMetricsHolder> instances        = new ConcurrentHashMap<>();\n    private final List<String>                              storeLabelsList  = Arrays.asList(DEST, \"batchMode\", \"size\");\n\n    private StoreCollector(){\n    }\n\n    public static StoreCollector instance() {\n        return SingletonHolder.SINGLETON;\n    }\n\n    @Override\n    public List<MetricFamilySamples> collect() {\n        List<MetricFamilySamples> mfs = new ArrayList<>();\n        CounterMetricFamily put = new CounterMetricFamily(PRODUCE, PRODUCE_HELP, DEST_LABELS_LIST);\n        CounterMetricFamily ack = new CounterMetricFamily(CONSUME, CONSUME_HELP, DEST_LABELS_LIST);\n        GaugeMetricFamily store = new GaugeMetricFamily(STORE, STORE_HELP, storeLabelsList);\n        CounterMetricFamily putMem = new CounterMetricFamily(PRODUCE_MEM, PRODUCE_MEM_HELP, DEST_LABELS_LIST);\n        CounterMetricFamily ackMem = new CounterMetricFamily(CONSUME_MEM, CONSUME_MEM_HELP, DEST_LABELS_LIST);\n        GaugeMetricFamily putDelay = new GaugeMetricFamily(PUT_DELAY, PUT_DELAY_HELP, DEST_LABELS_LIST);\n        GaugeMetricFamily getDelay = new GaugeMetricFamily(GET_DELAY, GET_DELAY_HELP, DEST_LABELS_LIST);\n        GaugeMetricFamily ackDelay = new GaugeMetricFamily(ACK_DELAY, ACK_DELAY_HELP, DEST_LABELS_LIST);\n        CounterMetricFamily putRows = new CounterMetricFamily(PUT_ROWS, PUT_ROWS_HELP, DEST_LABELS_LIST);\n        CounterMetricFamily getRows = new CounterMetricFamily(GET_ROWS, GET_ROWS_HELP, DEST_LABELS_LIST);\n        CounterMetricFamily ackRows = new CounterMetricFamily(ACK_ROWS, ACK_ROWS_HELP, DEST_LABELS_LIST);\n        boolean hasMem = false;\n        for (StoreMetricsHolder smh : instances.values()) {\n            final boolean isMem = smh.batchMode.isMemSize();\n            put.addMetric(smh.destLabelValues, smh.putSeq.doubleValue());\n            ack.addMetric(smh.destLabelValues, smh.ackSeq.doubleValue());\n            long pet = smh.putExecTime.get();\n            // 防止出现启动时，未消费造成的get, ack延时小于前阶段的情况\n            long get = Math.min(smh.getExecTime.get(), pet);\n            long aet = Math.min(smh.ackExecTime.get(), get);\n            long now = System.currentTimeMillis();\n            // execTime > now，delay显示为0\n            long pd = (now >= pet) ? (now - pet) : 0;\n            putDelay.addMetric(smh.destLabelValues, pd);\n            long gd = (now >= get) ? (now - get) : 0;\n            getDelay.addMetric(smh.destLabelValues, gd);\n            long ad = (now >= aet) ? (now - aet) : 0;\n            ackDelay.addMetric(smh.destLabelValues, ad);\n            putRows.addMetric(smh.destLabelValues, smh.putTableRows.doubleValue());\n            getRows.addMetric(smh.destLabelValues, smh.getTableRows.doubleValue());\n            ackRows.addMetric(smh.destLabelValues, smh.ackTableRows.doubleValue());\n            store.addMetric(smh.storeLabelValues, 1);\n            if (isMem) {\n                hasMem = true;\n                putMem.addMetric(smh.destLabelValues, smh.putMemSize.doubleValue());\n                ackMem.addMetric(smh.destLabelValues, smh.ackMemSize.doubleValue());\n            }\n        }\n        mfs.add(put);\n        mfs.add(ack);\n        mfs.add(store);\n        mfs.add(putDelay);\n        mfs.add(getDelay);\n        mfs.add(ackDelay);\n        mfs.add(putRows);\n        mfs.add(getRows);\n        mfs.add(ackRows);\n        if (hasMem) {\n            mfs.add(putMem);\n            mfs.add(ackMem);\n        }\n        return mfs;\n    }\n\n    @Override\n    public void register(CanalInstance instance) {\n        final String destination = instance.getDestination();\n        StoreMetricsHolder holder = new StoreMetricsHolder();\n        CanalEventStore store = instance.getEventStore();\n        if (!(store instanceof MemoryEventStoreWithBuffer)) {\n            throw new IllegalArgumentException(\"EventStore must be MemoryEventStoreWithBuffer\");\n        }\n        MemoryEventStoreWithBuffer memStore = (MemoryEventStoreWithBuffer) store;\n        holder.batchMode = memStore.getBatchMode();\n        holder.putSeq = memStore.getPutSequence();\n        holder.ackSeq = memStore.getAckSequence();\n        holder.destLabelValues = Collections.singletonList(destination);\n        holder.size = memStore.getBufferSize();\n        holder.storeLabelValues = Arrays.asList(destination, holder.batchMode.name(), Integer.toString(holder.size));\n        holder.putExecTime = memStore.getPutExecTime();\n        holder.getExecTime = memStore.getGetExecTime();\n        holder.ackExecTime = memStore.getAckExecTime();\n        holder.putTableRows = memStore.getPutTableRows();\n        holder.getTableRows = memStore.getGetTableRows();\n        holder.ackTableRows = memStore.getAckTableRows();\n        Preconditions.checkNotNull(holder.batchMode);\n        Preconditions.checkNotNull(holder.putSeq);\n        Preconditions.checkNotNull(holder.ackSeq);\n        if (holder.batchMode.isMemSize()) {\n            holder.putMemSize = memStore.getPutMemSize();\n            holder.ackMemSize = memStore.getAckMemSize();\n            Preconditions.checkNotNull(holder.putMemSize);\n            Preconditions.checkNotNull(holder.ackMemSize);\n        }\n        StoreMetricsHolder old = instances.put(destination, holder);\n        if (old != null) {\n            logger.warn(\"Remote stale StoreCollector for instance {}.\", destination);\n        }\n    }\n\n    @Override\n    public void unregister(CanalInstance instance) {\n        final String destination = instance.getDestination();\n        instances.remove(destination);\n    }\n\n    private static class SingletonHolder {\n\n        private static final StoreCollector SINGLETON = new StoreCollector();\n    }\n\n    private static class StoreMetricsHolder {\n\n        private AtomicLong   putSeq;\n        private AtomicLong   ackSeq;\n        private BatchMode    batchMode;\n        private AtomicLong   putMemSize;\n        private AtomicLong   ackMemSize;\n        private AtomicLong   putExecTime;\n        private AtomicLong   getExecTime;\n        private AtomicLong   ackExecTime;\n        private AtomicLong   putTableRows;\n        private AtomicLong   getTableRows;\n        private AtomicLong   ackTableRows;\n        private int          size;\n        private List<String> destLabelValues;\n        private List<String> storeLabelValues;\n    }\n}\n"
  },
  {
    "path": "prometheus/src/main/resources/META-INF/services/com.alibaba.otter.canal.spi.CanalMetricsProvider",
    "content": "com.alibaba.otter.canal.prometheus.PrometheusProvider\n"
  },
  {
    "path": "protocol/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>com.alibaba.otter</groupId>\n\t\t<artifactId>canal</artifactId>\n\t\t<version>1.1.9-SNAPSHOT</version>\n\t\t<relativePath>../pom.xml</relativePath>\n\t</parent>\n\t<groupId>com.alibaba.otter</groupId>\n\t<artifactId>canal.protocol</artifactId>\n\t<packaging>jar</packaging>\n\t<name>canal protocol module for otter ${project.version}</name>\n\t<url>http://b2b-doc.alibaba-inc.com/display/opentech/Otter</url>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.common</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.google.protobuf</groupId>\n\t\t\t<artifactId>protobuf-java</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>commons-lang</groupId>\n\t\t\t<artifactId>commons-lang</artifactId>\n\t\t</dependency>\n\t\t<!-- junit -->\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "protocol/src/main/java/com/alibaba/otter/canal/protocol/AdminPacket.java",
    "content": "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n// source: AdminProtocol.proto\n\npackage com.alibaba.otter.canal.protocol;\n\npublic final class AdminPacket {\n  private AdminPacket() {}\n  public static void registerAllExtensions(\n      com.google.protobuf.ExtensionRegistryLite registry) {\n  }\n\n  public static void registerAllExtensions(\n      com.google.protobuf.ExtensionRegistry registry) {\n    registerAllExtensions(\n        (com.google.protobuf.ExtensionRegistryLite) registry);\n  }\n  /**\n   * Protobuf enum {@code com.alibaba.otter.canal.protocol.PacketType}\n   */\n  public enum PacketType\n      implements com.google.protobuf.ProtocolMessageEnum {\n    /**\n     * <pre>\n     *compatible\n     * </pre>\n     *\n     * <code>PACKAGETYPECOMPATIBLEPROTO2 = 0;</code>\n     */\n    PACKAGETYPECOMPATIBLEPROTO2(0),\n    /**\n     * <code>HANDSHAKE = 1;</code>\n     */\n    HANDSHAKE(1),\n    /**\n     * <code>CLIENTAUTHENTICATION = 2;</code>\n     */\n    CLIENTAUTHENTICATION(2),\n    /**\n     * <code>ACK = 3;</code>\n     */\n    ACK(3),\n    /**\n     * <code>SERVER = 4;</code>\n     */\n    SERVER(4),\n    /**\n     * <code>INSTANCE = 5;</code>\n     */\n    INSTANCE(5),\n    /**\n     * <code>LOG = 6;</code>\n     */\n    LOG(6),\n    UNRECOGNIZED(-1),\n    ;\n\n    /**\n     * <pre>\n     *compatible\n     * </pre>\n     *\n     * <code>PACKAGETYPECOMPATIBLEPROTO2 = 0;</code>\n     */\n    public static final int PACKAGETYPECOMPATIBLEPROTO2_VALUE = 0;\n    /**\n     * <code>HANDSHAKE = 1;</code>\n     */\n    public static final int HANDSHAKE_VALUE = 1;\n    /**\n     * <code>CLIENTAUTHENTICATION = 2;</code>\n     */\n    public static final int CLIENTAUTHENTICATION_VALUE = 2;\n    /**\n     * <code>ACK = 3;</code>\n     */\n    public static final int ACK_VALUE = 3;\n    /**\n     * <code>SERVER = 4;</code>\n     */\n    public static final int SERVER_VALUE = 4;\n    /**\n     * <code>INSTANCE = 5;</code>\n     */\n    public static final int INSTANCE_VALUE = 5;\n    /**\n     * <code>LOG = 6;</code>\n     */\n    public static final int LOG_VALUE = 6;\n\n\n    public final int getNumber() {\n      if (this == UNRECOGNIZED) {\n        throw new java.lang.IllegalArgumentException(\n            \"Can't get the number of an unknown enum value.\");\n      }\n      return value;\n    }\n\n    /**\n     * @deprecated Use {@link #forNumber(int)} instead.\n     */\n    @java.lang.Deprecated\n    public static PacketType valueOf(int value) {\n      return forNumber(value);\n    }\n\n    public static PacketType forNumber(int value) {\n      switch (value) {\n        case 0: return PACKAGETYPECOMPATIBLEPROTO2;\n        case 1: return HANDSHAKE;\n        case 2: return CLIENTAUTHENTICATION;\n        case 3: return ACK;\n        case 4: return SERVER;\n        case 5: return INSTANCE;\n        case 6: return LOG;\n        default: return null;\n      }\n    }\n\n    public static com.google.protobuf.Internal.EnumLiteMap<PacketType>\n        internalGetValueMap() {\n      return internalValueMap;\n    }\n    private static final com.google.protobuf.Internal.EnumLiteMap<\n        PacketType> internalValueMap =\n          new com.google.protobuf.Internal.EnumLiteMap<PacketType>() {\n            public PacketType findValueByNumber(int number) {\n              return PacketType.forNumber(number);\n            }\n          };\n\n    public final com.google.protobuf.Descriptors.EnumValueDescriptor\n        getValueDescriptor() {\n      return getDescriptor().getValues().get(ordinal());\n    }\n    public final com.google.protobuf.Descriptors.EnumDescriptor\n        getDescriptorForType() {\n      return getDescriptor();\n    }\n    public static final com.google.protobuf.Descriptors.EnumDescriptor\n        getDescriptor() {\n      return com.alibaba.otter.canal.protocol.AdminPacket.getDescriptor().getEnumTypes().get(0);\n    }\n\n    private static final PacketType[] VALUES = values();\n\n    public static PacketType valueOf(\n        com.google.protobuf.Descriptors.EnumValueDescriptor desc) {\n      if (desc.getType() != getDescriptor()) {\n        throw new java.lang.IllegalArgumentException(\n          \"EnumValueDescriptor is not for this type.\");\n      }\n      if (desc.getIndex() == -1) {\n        return UNRECOGNIZED;\n      }\n      return VALUES[desc.getIndex()];\n    }\n\n    private final int value;\n\n    private PacketType(int value) {\n      this.value = value;\n    }\n\n    // @@protoc_insertion_point(enum_scope:com.alibaba.otter.canal.protocol.PacketType)\n  }\n\n  public interface PacketOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.Packet)\n      com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <code>int32 magic_number = 1;</code>\n     */\n    int getMagicNumber();\n\n    /**\n     * <code>int32 version = 2;</code>\n     */\n    int getVersion();\n\n    /**\n     * <code>.com.alibaba.otter.canal.protocol.PacketType type = 3;</code>\n     */\n    int getTypeValue();\n    /**\n     * <code>.com.alibaba.otter.canal.protocol.PacketType type = 3;</code>\n     */\n    com.alibaba.otter.canal.protocol.AdminPacket.PacketType getType();\n\n    /**\n     * <code>bytes body = 4;</code>\n     */\n    com.google.protobuf.ByteString getBody();\n\n    public com.alibaba.otter.canal.protocol.AdminPacket.Packet.MagicNumberPresentCase getMagicNumberPresentCase();\n\n    public com.alibaba.otter.canal.protocol.AdminPacket.Packet.VersionPresentCase getVersionPresentCase();\n  }\n  /**\n   * Protobuf type {@code com.alibaba.otter.canal.protocol.Packet}\n   */\n  public  static final class Packet extends\n      com.google.protobuf.GeneratedMessageV3 implements\n      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.Packet)\n      PacketOrBuilder {\n  private static final long serialVersionUID = 0L;\n    // Use Packet.newBuilder() to construct.\n    private Packet(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {\n      super(builder);\n    }\n    private Packet() {\n      type_ = 0;\n      body_ = com.google.protobuf.ByteString.EMPTY;\n    }\n\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n    getUnknownFields() {\n      return this.unknownFields;\n    }\n    private Packet(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      this();\n      if (extensionRegistry == null) {\n        throw new java.lang.NullPointerException();\n      }\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            case 8: {\n              magicNumberPresentCase_ = 1;\n              magicNumberPresent_ = input.readInt32();\n              break;\n            }\n            case 16: {\n              versionPresentCase_ = 2;\n              versionPresent_ = input.readInt32();\n              break;\n            }\n            case 24: {\n              int rawValue = input.readEnum();\n\n              type_ = rawValue;\n              break;\n            }\n            case 34: {\n\n              body_ = input.readBytes();\n              break;\n            }\n            default: {\n              if (!parseUnknownFieldProto3(\n                  input, unknownFields, extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Packet_descriptor;\n    }\n\n    @java.lang.Override\n    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Packet_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              com.alibaba.otter.canal.protocol.AdminPacket.Packet.class, com.alibaba.otter.canal.protocol.AdminPacket.Packet.Builder.class);\n    }\n\n    private int magicNumberPresentCase_ = 0;\n    private java.lang.Object magicNumberPresent_;\n    public enum MagicNumberPresentCase\n        implements com.google.protobuf.Internal.EnumLite {\n      MAGIC_NUMBER(1),\n      MAGICNUMBERPRESENT_NOT_SET(0);\n      private final int value;\n      private MagicNumberPresentCase(int value) {\n        this.value = value;\n      }\n      /**\n       * @deprecated Use {@link #forNumber(int)} instead.\n       */\n      @java.lang.Deprecated\n      public static MagicNumberPresentCase valueOf(int value) {\n        return forNumber(value);\n      }\n\n      public static MagicNumberPresentCase forNumber(int value) {\n        switch (value) {\n          case 1: return MAGIC_NUMBER;\n          case 0: return MAGICNUMBERPRESENT_NOT_SET;\n          default: return null;\n        }\n      }\n      public int getNumber() {\n        return this.value;\n      }\n    };\n\n    public MagicNumberPresentCase\n    getMagicNumberPresentCase() {\n      return MagicNumberPresentCase.forNumber(\n          magicNumberPresentCase_);\n    }\n\n    private int versionPresentCase_ = 0;\n    private java.lang.Object versionPresent_;\n    public enum VersionPresentCase\n        implements com.google.protobuf.Internal.EnumLite {\n      VERSION(2),\n      VERSIONPRESENT_NOT_SET(0);\n      private final int value;\n      private VersionPresentCase(int value) {\n        this.value = value;\n      }\n      /**\n       * @deprecated Use {@link #forNumber(int)} instead.\n       */\n      @java.lang.Deprecated\n      public static VersionPresentCase valueOf(int value) {\n        return forNumber(value);\n      }\n\n      public static VersionPresentCase forNumber(int value) {\n        switch (value) {\n          case 2: return VERSION;\n          case 0: return VERSIONPRESENT_NOT_SET;\n          default: return null;\n        }\n      }\n      public int getNumber() {\n        return this.value;\n      }\n    };\n\n    public VersionPresentCase\n    getVersionPresentCase() {\n      return VersionPresentCase.forNumber(\n          versionPresentCase_);\n    }\n\n    public static final int MAGIC_NUMBER_FIELD_NUMBER = 1;\n    /**\n     * <code>int32 magic_number = 1;</code>\n     */\n    public int getMagicNumber() {\n      if (magicNumberPresentCase_ == 1) {\n        return (java.lang.Integer) magicNumberPresent_;\n      }\n      return 0;\n    }\n\n    public static final int VERSION_FIELD_NUMBER = 2;\n    /**\n     * <code>int32 version = 2;</code>\n     */\n    public int getVersion() {\n      if (versionPresentCase_ == 2) {\n        return (java.lang.Integer) versionPresent_;\n      }\n      return 0;\n    }\n\n    public static final int TYPE_FIELD_NUMBER = 3;\n    private int type_;\n    /**\n     * <code>.com.alibaba.otter.canal.protocol.PacketType type = 3;</code>\n     */\n    public int getTypeValue() {\n      return type_;\n    }\n    /**\n     * <code>.com.alibaba.otter.canal.protocol.PacketType type = 3;</code>\n     */\n    public com.alibaba.otter.canal.protocol.AdminPacket.PacketType getType() {\n      @SuppressWarnings(\"deprecation\")\n      com.alibaba.otter.canal.protocol.AdminPacket.PacketType result = com.alibaba.otter.canal.protocol.AdminPacket.PacketType.valueOf(type_);\n      return result == null ? com.alibaba.otter.canal.protocol.AdminPacket.PacketType.UNRECOGNIZED : result;\n    }\n\n    public static final int BODY_FIELD_NUMBER = 4;\n    private com.google.protobuf.ByteString body_;\n    /**\n     * <code>bytes body = 4;</code>\n     */\n    public com.google.protobuf.ByteString getBody() {\n      return body_;\n    }\n\n    private byte memoizedIsInitialized = -1;\n    @java.lang.Override\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    @java.lang.Override\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      if (magicNumberPresentCase_ == 1) {\n        output.writeInt32(\n            1, (int)((java.lang.Integer) magicNumberPresent_));\n      }\n      if (versionPresentCase_ == 2) {\n        output.writeInt32(\n            2, (int)((java.lang.Integer) versionPresent_));\n      }\n      if (type_ != com.alibaba.otter.canal.protocol.AdminPacket.PacketType.PACKAGETYPECOMPATIBLEPROTO2.getNumber()) {\n        output.writeEnum(3, type_);\n      }\n      if (!body_.isEmpty()) {\n        output.writeBytes(4, body_);\n      }\n      unknownFields.writeTo(output);\n    }\n\n    @java.lang.Override\n    public int getSerializedSize() {\n      int size = memoizedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (magicNumberPresentCase_ == 1) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(\n              1, (int)((java.lang.Integer) magicNumberPresent_));\n      }\n      if (versionPresentCase_ == 2) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(\n              2, (int)((java.lang.Integer) versionPresent_));\n      }\n      if (type_ != com.alibaba.otter.canal.protocol.AdminPacket.PacketType.PACKAGETYPECOMPATIBLEPROTO2.getNumber()) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeEnumSize(3, type_);\n      }\n      if (!body_.isEmpty()) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(4, body_);\n      }\n      size += unknownFields.getSerializedSize();\n      memoizedSize = size;\n      return size;\n    }\n\n    @java.lang.Override\n    public boolean equals(final java.lang.Object obj) {\n      if (obj == this) {\n       return true;\n      }\n      if (!(obj instanceof com.alibaba.otter.canal.protocol.AdminPacket.Packet)) {\n        return super.equals(obj);\n      }\n      com.alibaba.otter.canal.protocol.AdminPacket.Packet other = (com.alibaba.otter.canal.protocol.AdminPacket.Packet) obj;\n\n      boolean result = true;\n      result = result && type_ == other.type_;\n      result = result && getBody()\n          .equals(other.getBody());\n      result = result && getMagicNumberPresentCase().equals(\n          other.getMagicNumberPresentCase());\n      if (!result) return false;\n      switch (magicNumberPresentCase_) {\n        case 1:\n          result = result && (getMagicNumber()\n              == other.getMagicNumber());\n          break;\n        case 0:\n        default:\n      }\n      result = result && getVersionPresentCase().equals(\n          other.getVersionPresentCase());\n      if (!result) return false;\n      switch (versionPresentCase_) {\n        case 2:\n          result = result && (getVersion()\n              == other.getVersion());\n          break;\n        case 0:\n        default:\n      }\n      result = result && unknownFields.equals(other.unknownFields);\n      return result;\n    }\n\n    @java.lang.Override\n    public int hashCode() {\n      if (memoizedHashCode != 0) {\n        return memoizedHashCode;\n      }\n      int hash = 41;\n      hash = (19 * hash) + getDescriptor().hashCode();\n      hash = (37 * hash) + TYPE_FIELD_NUMBER;\n      hash = (53 * hash) + type_;\n      hash = (37 * hash) + BODY_FIELD_NUMBER;\n      hash = (53 * hash) + getBody().hashCode();\n      switch (magicNumberPresentCase_) {\n        case 1:\n          hash = (37 * hash) + MAGIC_NUMBER_FIELD_NUMBER;\n          hash = (53 * hash) + getMagicNumber();\n          break;\n        case 0:\n        default:\n      }\n      switch (versionPresentCase_) {\n        case 2:\n          hash = (37 * hash) + VERSION_FIELD_NUMBER;\n          hash = (53 * hash) + getVersion();\n          break;\n        case 0:\n        default:\n      }\n      hash = (29 * hash) + unknownFields.hashCode();\n      memoizedHashCode = hash;\n      return hash;\n    }\n\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Packet parseFrom(\n        java.nio.ByteBuffer data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Packet parseFrom(\n        java.nio.ByteBuffer data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Packet parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Packet parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Packet parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Packet parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Packet parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Packet parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Packet parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Packet parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Packet parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Packet parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    @java.lang.Override\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder() {\n      return DEFAULT_INSTANCE.toBuilder();\n    }\n    public static Builder newBuilder(com.alibaba.otter.canal.protocol.AdminPacket.Packet prototype) {\n      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n    }\n    @java.lang.Override\n    public Builder toBuilder() {\n      return this == DEFAULT_INSTANCE\n          ? new Builder() : new Builder().mergeFrom(this);\n    }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code com.alibaba.otter.canal.protocol.Packet}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.Packet)\n        com.alibaba.otter.canal.protocol.AdminPacket.PacketOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Packet_descriptor;\n      }\n\n      @java.lang.Override\n      protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Packet_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                com.alibaba.otter.canal.protocol.AdminPacket.Packet.class, com.alibaba.otter.canal.protocol.AdminPacket.Packet.Builder.class);\n      }\n\n      // Construct using com.alibaba.otter.canal.protocol.AdminPacket.Packet.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessageV3\n                .alwaysUseFieldBuilders) {\n        }\n      }\n      @java.lang.Override\n      public Builder clear() {\n        super.clear();\n        type_ = 0;\n\n        body_ = com.google.protobuf.ByteString.EMPTY;\n\n        magicNumberPresentCase_ = 0;\n        magicNumberPresent_ = null;\n        versionPresentCase_ = 0;\n        versionPresent_ = null;\n        return this;\n      }\n\n      @java.lang.Override\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Packet_descriptor;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.AdminPacket.Packet getDefaultInstanceForType() {\n        return com.alibaba.otter.canal.protocol.AdminPacket.Packet.getDefaultInstance();\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.AdminPacket.Packet build() {\n        com.alibaba.otter.canal.protocol.AdminPacket.Packet result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.AdminPacket.Packet buildPartial() {\n        com.alibaba.otter.canal.protocol.AdminPacket.Packet result = new com.alibaba.otter.canal.protocol.AdminPacket.Packet(this);\n        if (magicNumberPresentCase_ == 1) {\n          result.magicNumberPresent_ = magicNumberPresent_;\n        }\n        if (versionPresentCase_ == 2) {\n          result.versionPresent_ = versionPresent_;\n        }\n        result.type_ = type_;\n        result.body_ = body_;\n        result.magicNumberPresentCase_ = magicNumberPresentCase_;\n        result.versionPresentCase_ = versionPresentCase_;\n        onBuilt();\n        return result;\n      }\n\n      @java.lang.Override\n      public Builder clone() {\n        return (Builder) super.clone();\n      }\n      @java.lang.Override\n      public Builder setField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.setField(field, value);\n      }\n      @java.lang.Override\n      public Builder clearField(\n          com.google.protobuf.Descriptors.FieldDescriptor field) {\n        return (Builder) super.clearField(field);\n      }\n      @java.lang.Override\n      public Builder clearOneof(\n          com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n        return (Builder) super.clearOneof(oneof);\n      }\n      @java.lang.Override\n      public Builder setRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          int index, java.lang.Object value) {\n        return (Builder) super.setRepeatedField(field, index, value);\n      }\n      @java.lang.Override\n      public Builder addRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.addRepeatedField(field, value);\n      }\n      @java.lang.Override\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof com.alibaba.otter.canal.protocol.AdminPacket.Packet) {\n          return mergeFrom((com.alibaba.otter.canal.protocol.AdminPacket.Packet)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(com.alibaba.otter.canal.protocol.AdminPacket.Packet other) {\n        if (other == com.alibaba.otter.canal.protocol.AdminPacket.Packet.getDefaultInstance()) return this;\n        if (other.type_ != 0) {\n          setTypeValue(other.getTypeValue());\n        }\n        if (other.getBody() != com.google.protobuf.ByteString.EMPTY) {\n          setBody(other.getBody());\n        }\n        switch (other.getMagicNumberPresentCase()) {\n          case MAGIC_NUMBER: {\n            setMagicNumber(other.getMagicNumber());\n            break;\n          }\n          case MAGICNUMBERPRESENT_NOT_SET: {\n            break;\n          }\n        }\n        switch (other.getVersionPresentCase()) {\n          case VERSION: {\n            setVersion(other.getVersion());\n            break;\n          }\n          case VERSIONPRESENT_NOT_SET: {\n            break;\n          }\n        }\n        this.mergeUnknownFields(other.unknownFields);\n        onChanged();\n        return this;\n      }\n\n      @java.lang.Override\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      @java.lang.Override\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        com.alibaba.otter.canal.protocol.AdminPacket.Packet parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (com.alibaba.otter.canal.protocol.AdminPacket.Packet) e.getUnfinishedMessage();\n          throw e.unwrapIOException();\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int magicNumberPresentCase_ = 0;\n      private java.lang.Object magicNumberPresent_;\n      public MagicNumberPresentCase\n          getMagicNumberPresentCase() {\n        return MagicNumberPresentCase.forNumber(\n            magicNumberPresentCase_);\n      }\n\n      public Builder clearMagicNumberPresent() {\n        magicNumberPresentCase_ = 0;\n        magicNumberPresent_ = null;\n        onChanged();\n        return this;\n      }\n\n      private int versionPresentCase_ = 0;\n      private java.lang.Object versionPresent_;\n      public VersionPresentCase\n          getVersionPresentCase() {\n        return VersionPresentCase.forNumber(\n            versionPresentCase_);\n      }\n\n      public Builder clearVersionPresent() {\n        versionPresentCase_ = 0;\n        versionPresent_ = null;\n        onChanged();\n        return this;\n      }\n\n\n      /**\n       * <code>int32 magic_number = 1;</code>\n       */\n      public int getMagicNumber() {\n        if (magicNumberPresentCase_ == 1) {\n          return (java.lang.Integer) magicNumberPresent_;\n        }\n        return 0;\n      }\n      /**\n       * <code>int32 magic_number = 1;</code>\n       */\n      public Builder setMagicNumber(int value) {\n        magicNumberPresentCase_ = 1;\n        magicNumberPresent_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>int32 magic_number = 1;</code>\n       */\n      public Builder clearMagicNumber() {\n        if (magicNumberPresentCase_ == 1) {\n          magicNumberPresentCase_ = 0;\n          magicNumberPresent_ = null;\n          onChanged();\n        }\n        return this;\n      }\n\n      /**\n       * <code>int32 version = 2;</code>\n       */\n      public int getVersion() {\n        if (versionPresentCase_ == 2) {\n          return (java.lang.Integer) versionPresent_;\n        }\n        return 0;\n      }\n      /**\n       * <code>int32 version = 2;</code>\n       */\n      public Builder setVersion(int value) {\n        versionPresentCase_ = 2;\n        versionPresent_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>int32 version = 2;</code>\n       */\n      public Builder clearVersion() {\n        if (versionPresentCase_ == 2) {\n          versionPresentCase_ = 0;\n          versionPresent_ = null;\n          onChanged();\n        }\n        return this;\n      }\n\n      private int type_ = 0;\n      /**\n       * <code>.com.alibaba.otter.canal.protocol.PacketType type = 3;</code>\n       */\n      public int getTypeValue() {\n        return type_;\n      }\n      /**\n       * <code>.com.alibaba.otter.canal.protocol.PacketType type = 3;</code>\n       */\n      public Builder setTypeValue(int value) {\n        type_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>.com.alibaba.otter.canal.protocol.PacketType type = 3;</code>\n       */\n      public com.alibaba.otter.canal.protocol.AdminPacket.PacketType getType() {\n        @SuppressWarnings(\"deprecation\")\n        com.alibaba.otter.canal.protocol.AdminPacket.PacketType result = com.alibaba.otter.canal.protocol.AdminPacket.PacketType.valueOf(type_);\n        return result == null ? com.alibaba.otter.canal.protocol.AdminPacket.PacketType.UNRECOGNIZED : result;\n      }\n      /**\n       * <code>.com.alibaba.otter.canal.protocol.PacketType type = 3;</code>\n       */\n      public Builder setType(com.alibaba.otter.canal.protocol.AdminPacket.PacketType value) {\n        if (value == null) {\n          throw new NullPointerException();\n        }\n        \n        type_ = value.getNumber();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>.com.alibaba.otter.canal.protocol.PacketType type = 3;</code>\n       */\n      public Builder clearType() {\n        \n        type_ = 0;\n        onChanged();\n        return this;\n      }\n\n      private com.google.protobuf.ByteString body_ = com.google.protobuf.ByteString.EMPTY;\n      /**\n       * <code>bytes body = 4;</code>\n       */\n      public com.google.protobuf.ByteString getBody() {\n        return body_;\n      }\n      /**\n       * <code>bytes body = 4;</code>\n       */\n      public Builder setBody(com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        body_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>bytes body = 4;</code>\n       */\n      public Builder clearBody() {\n        \n        body_ = getDefaultInstance().getBody();\n        onChanged();\n        return this;\n      }\n      @java.lang.Override\n      public final Builder setUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.setUnknownFieldsProto3(unknownFields);\n      }\n\n      @java.lang.Override\n      public final Builder mergeUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.mergeUnknownFields(unknownFields);\n      }\n\n\n      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.Packet)\n    }\n\n    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.Packet)\n    private static final com.alibaba.otter.canal.protocol.AdminPacket.Packet DEFAULT_INSTANCE;\n    static {\n      DEFAULT_INSTANCE = new com.alibaba.otter.canal.protocol.AdminPacket.Packet();\n    }\n\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Packet getDefaultInstance() {\n      return DEFAULT_INSTANCE;\n    }\n\n    private static final com.google.protobuf.Parser<Packet>\n        PARSER = new com.google.protobuf.AbstractParser<Packet>() {\n      @java.lang.Override\n      public Packet parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new Packet(input, extensionRegistry);\n      }\n    };\n\n    public static com.google.protobuf.Parser<Packet> parser() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<Packet> getParserForType() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.alibaba.otter.canal.protocol.AdminPacket.Packet getDefaultInstanceForType() {\n      return DEFAULT_INSTANCE;\n    }\n\n  }\n\n  public interface AckOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.Ack)\n      com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <code>int32 code = 1;</code>\n     */\n    int getCode();\n\n    /**\n     * <pre>\n     * if something like compression is not supported, erorr_message will tell about it.\n     * </pre>\n     *\n     * <code>string message = 2;</code>\n     */\n    java.lang.String getMessage();\n    /**\n     * <pre>\n     * if something like compression is not supported, erorr_message will tell about it.\n     * </pre>\n     *\n     * <code>string message = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getMessageBytes();\n\n    public com.alibaba.otter.canal.protocol.AdminPacket.Ack.ErrorCodePresentCase getErrorCodePresentCase();\n  }\n  /**\n   * Protobuf type {@code com.alibaba.otter.canal.protocol.Ack}\n   */\n  public  static final class Ack extends\n      com.google.protobuf.GeneratedMessageV3 implements\n      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.Ack)\n      AckOrBuilder {\n  private static final long serialVersionUID = 0L;\n    // Use Ack.newBuilder() to construct.\n    private Ack(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {\n      super(builder);\n    }\n    private Ack() {\n      message_ = \"\";\n    }\n\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n    getUnknownFields() {\n      return this.unknownFields;\n    }\n    private Ack(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      this();\n      if (extensionRegistry == null) {\n        throw new java.lang.NullPointerException();\n      }\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            case 8: {\n              errorCodePresentCase_ = 1;\n              errorCodePresent_ = input.readInt32();\n              break;\n            }\n            case 18: {\n              java.lang.String s = input.readStringRequireUtf8();\n\n              message_ = s;\n              break;\n            }\n            default: {\n              if (!parseUnknownFieldProto3(\n                  input, unknownFields, extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Ack_descriptor;\n    }\n\n    @java.lang.Override\n    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Ack_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              com.alibaba.otter.canal.protocol.AdminPacket.Ack.class, com.alibaba.otter.canal.protocol.AdminPacket.Ack.Builder.class);\n    }\n\n    private int errorCodePresentCase_ = 0;\n    private java.lang.Object errorCodePresent_;\n    public enum ErrorCodePresentCase\n        implements com.google.protobuf.Internal.EnumLite {\n      CODE(1),\n      ERRORCODEPRESENT_NOT_SET(0);\n      private final int value;\n      private ErrorCodePresentCase(int value) {\n        this.value = value;\n      }\n      /**\n       * @deprecated Use {@link #forNumber(int)} instead.\n       */\n      @java.lang.Deprecated\n      public static ErrorCodePresentCase valueOf(int value) {\n        return forNumber(value);\n      }\n\n      public static ErrorCodePresentCase forNumber(int value) {\n        switch (value) {\n          case 1: return CODE;\n          case 0: return ERRORCODEPRESENT_NOT_SET;\n          default: return null;\n        }\n      }\n      public int getNumber() {\n        return this.value;\n      }\n    };\n\n    public ErrorCodePresentCase\n    getErrorCodePresentCase() {\n      return ErrorCodePresentCase.forNumber(\n          errorCodePresentCase_);\n    }\n\n    public static final int CODE_FIELD_NUMBER = 1;\n    /**\n     * <code>int32 code = 1;</code>\n     */\n    public int getCode() {\n      if (errorCodePresentCase_ == 1) {\n        return (java.lang.Integer) errorCodePresent_;\n      }\n      return 0;\n    }\n\n    public static final int MESSAGE_FIELD_NUMBER = 2;\n    private volatile java.lang.Object message_;\n    /**\n     * <pre>\n     * if something like compression is not supported, erorr_message will tell about it.\n     * </pre>\n     *\n     * <code>string message = 2;</code>\n     */\n    public java.lang.String getMessage() {\n      java.lang.Object ref = message_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        message_ = s;\n        return s;\n      }\n    }\n    /**\n     * <pre>\n     * if something like compression is not supported, erorr_message will tell about it.\n     * </pre>\n     *\n     * <code>string message = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getMessageBytes() {\n      java.lang.Object ref = message_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        message_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private byte memoizedIsInitialized = -1;\n    @java.lang.Override\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    @java.lang.Override\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      if (errorCodePresentCase_ == 1) {\n        output.writeInt32(\n            1, (int)((java.lang.Integer) errorCodePresent_));\n      }\n      if (!getMessageBytes().isEmpty()) {\n        com.google.protobuf.GeneratedMessageV3.writeString(output, 2, message_);\n      }\n      unknownFields.writeTo(output);\n    }\n\n    @java.lang.Override\n    public int getSerializedSize() {\n      int size = memoizedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (errorCodePresentCase_ == 1) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(\n              1, (int)((java.lang.Integer) errorCodePresent_));\n      }\n      if (!getMessageBytes().isEmpty()) {\n        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, message_);\n      }\n      size += unknownFields.getSerializedSize();\n      memoizedSize = size;\n      return size;\n    }\n\n    @java.lang.Override\n    public boolean equals(final java.lang.Object obj) {\n      if (obj == this) {\n       return true;\n      }\n      if (!(obj instanceof com.alibaba.otter.canal.protocol.AdminPacket.Ack)) {\n        return super.equals(obj);\n      }\n      com.alibaba.otter.canal.protocol.AdminPacket.Ack other = (com.alibaba.otter.canal.protocol.AdminPacket.Ack) obj;\n\n      boolean result = true;\n      result = result && getMessage()\n          .equals(other.getMessage());\n      result = result && getErrorCodePresentCase().equals(\n          other.getErrorCodePresentCase());\n      if (!result) return false;\n      switch (errorCodePresentCase_) {\n        case 1:\n          result = result && (getCode()\n              == other.getCode());\n          break;\n        case 0:\n        default:\n      }\n      result = result && unknownFields.equals(other.unknownFields);\n      return result;\n    }\n\n    @java.lang.Override\n    public int hashCode() {\n      if (memoizedHashCode != 0) {\n        return memoizedHashCode;\n      }\n      int hash = 41;\n      hash = (19 * hash) + getDescriptor().hashCode();\n      hash = (37 * hash) + MESSAGE_FIELD_NUMBER;\n      hash = (53 * hash) + getMessage().hashCode();\n      switch (errorCodePresentCase_) {\n        case 1:\n          hash = (37 * hash) + CODE_FIELD_NUMBER;\n          hash = (53 * hash) + getCode();\n          break;\n        case 0:\n        default:\n      }\n      hash = (29 * hash) + unknownFields.hashCode();\n      memoizedHashCode = hash;\n      return hash;\n    }\n\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Ack parseFrom(\n        java.nio.ByteBuffer data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Ack parseFrom(\n        java.nio.ByteBuffer data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Ack parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Ack parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Ack parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Ack parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Ack parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Ack parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Ack parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Ack parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Ack parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Ack parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    @java.lang.Override\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder() {\n      return DEFAULT_INSTANCE.toBuilder();\n    }\n    public static Builder newBuilder(com.alibaba.otter.canal.protocol.AdminPacket.Ack prototype) {\n      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n    }\n    @java.lang.Override\n    public Builder toBuilder() {\n      return this == DEFAULT_INSTANCE\n          ? new Builder() : new Builder().mergeFrom(this);\n    }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code com.alibaba.otter.canal.protocol.Ack}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.Ack)\n        com.alibaba.otter.canal.protocol.AdminPacket.AckOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Ack_descriptor;\n      }\n\n      @java.lang.Override\n      protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Ack_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                com.alibaba.otter.canal.protocol.AdminPacket.Ack.class, com.alibaba.otter.canal.protocol.AdminPacket.Ack.Builder.class);\n      }\n\n      // Construct using com.alibaba.otter.canal.protocol.AdminPacket.Ack.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessageV3\n                .alwaysUseFieldBuilders) {\n        }\n      }\n      @java.lang.Override\n      public Builder clear() {\n        super.clear();\n        message_ = \"\";\n\n        errorCodePresentCase_ = 0;\n        errorCodePresent_ = null;\n        return this;\n      }\n\n      @java.lang.Override\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Ack_descriptor;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.AdminPacket.Ack getDefaultInstanceForType() {\n        return com.alibaba.otter.canal.protocol.AdminPacket.Ack.getDefaultInstance();\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.AdminPacket.Ack build() {\n        com.alibaba.otter.canal.protocol.AdminPacket.Ack result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.AdminPacket.Ack buildPartial() {\n        com.alibaba.otter.canal.protocol.AdminPacket.Ack result = new com.alibaba.otter.canal.protocol.AdminPacket.Ack(this);\n        if (errorCodePresentCase_ == 1) {\n          result.errorCodePresent_ = errorCodePresent_;\n        }\n        result.message_ = message_;\n        result.errorCodePresentCase_ = errorCodePresentCase_;\n        onBuilt();\n        return result;\n      }\n\n      @java.lang.Override\n      public Builder clone() {\n        return (Builder) super.clone();\n      }\n      @java.lang.Override\n      public Builder setField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.setField(field, value);\n      }\n      @java.lang.Override\n      public Builder clearField(\n          com.google.protobuf.Descriptors.FieldDescriptor field) {\n        return (Builder) super.clearField(field);\n      }\n      @java.lang.Override\n      public Builder clearOneof(\n          com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n        return (Builder) super.clearOneof(oneof);\n      }\n      @java.lang.Override\n      public Builder setRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          int index, java.lang.Object value) {\n        return (Builder) super.setRepeatedField(field, index, value);\n      }\n      @java.lang.Override\n      public Builder addRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.addRepeatedField(field, value);\n      }\n      @java.lang.Override\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof com.alibaba.otter.canal.protocol.AdminPacket.Ack) {\n          return mergeFrom((com.alibaba.otter.canal.protocol.AdminPacket.Ack)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(com.alibaba.otter.canal.protocol.AdminPacket.Ack other) {\n        if (other == com.alibaba.otter.canal.protocol.AdminPacket.Ack.getDefaultInstance()) return this;\n        if (!other.getMessage().isEmpty()) {\n          message_ = other.message_;\n          onChanged();\n        }\n        switch (other.getErrorCodePresentCase()) {\n          case CODE: {\n            setCode(other.getCode());\n            break;\n          }\n          case ERRORCODEPRESENT_NOT_SET: {\n            break;\n          }\n        }\n        this.mergeUnknownFields(other.unknownFields);\n        onChanged();\n        return this;\n      }\n\n      @java.lang.Override\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      @java.lang.Override\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        com.alibaba.otter.canal.protocol.AdminPacket.Ack parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (com.alibaba.otter.canal.protocol.AdminPacket.Ack) e.getUnfinishedMessage();\n          throw e.unwrapIOException();\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int errorCodePresentCase_ = 0;\n      private java.lang.Object errorCodePresent_;\n      public ErrorCodePresentCase\n          getErrorCodePresentCase() {\n        return ErrorCodePresentCase.forNumber(\n            errorCodePresentCase_);\n      }\n\n      public Builder clearErrorCodePresent() {\n        errorCodePresentCase_ = 0;\n        errorCodePresent_ = null;\n        onChanged();\n        return this;\n      }\n\n\n      /**\n       * <code>int32 code = 1;</code>\n       */\n      public int getCode() {\n        if (errorCodePresentCase_ == 1) {\n          return (java.lang.Integer) errorCodePresent_;\n        }\n        return 0;\n      }\n      /**\n       * <code>int32 code = 1;</code>\n       */\n      public Builder setCode(int value) {\n        errorCodePresentCase_ = 1;\n        errorCodePresent_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>int32 code = 1;</code>\n       */\n      public Builder clearCode() {\n        if (errorCodePresentCase_ == 1) {\n          errorCodePresentCase_ = 0;\n          errorCodePresent_ = null;\n          onChanged();\n        }\n        return this;\n      }\n\n      private java.lang.Object message_ = \"\";\n      /**\n       * <pre>\n       * if something like compression is not supported, erorr_message will tell about it.\n       * </pre>\n       *\n       * <code>string message = 2;</code>\n       */\n      public java.lang.String getMessage() {\n        java.lang.Object ref = message_;\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          message_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <pre>\n       * if something like compression is not supported, erorr_message will tell about it.\n       * </pre>\n       *\n       * <code>string message = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getMessageBytes() {\n        java.lang.Object ref = message_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          message_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <pre>\n       * if something like compression is not supported, erorr_message will tell about it.\n       * </pre>\n       *\n       * <code>string message = 2;</code>\n       */\n      public Builder setMessage(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        message_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <pre>\n       * if something like compression is not supported, erorr_message will tell about it.\n       * </pre>\n       *\n       * <code>string message = 2;</code>\n       */\n      public Builder clearMessage() {\n        \n        message_ = getDefaultInstance().getMessage();\n        onChanged();\n        return this;\n      }\n      /**\n       * <pre>\n       * if something like compression is not supported, erorr_message will tell about it.\n       * </pre>\n       *\n       * <code>string message = 2;</code>\n       */\n      public Builder setMessageBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  checkByteStringIsUtf8(value);\n        \n        message_ = value;\n        onChanged();\n        return this;\n      }\n      @java.lang.Override\n      public final Builder setUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.setUnknownFieldsProto3(unknownFields);\n      }\n\n      @java.lang.Override\n      public final Builder mergeUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.mergeUnknownFields(unknownFields);\n      }\n\n\n      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.Ack)\n    }\n\n    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.Ack)\n    private static final com.alibaba.otter.canal.protocol.AdminPacket.Ack DEFAULT_INSTANCE;\n    static {\n      DEFAULT_INSTANCE = new com.alibaba.otter.canal.protocol.AdminPacket.Ack();\n    }\n\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Ack getDefaultInstance() {\n      return DEFAULT_INSTANCE;\n    }\n\n    private static final com.google.protobuf.Parser<Ack>\n        PARSER = new com.google.protobuf.AbstractParser<Ack>() {\n      @java.lang.Override\n      public Ack parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new Ack(input, extensionRegistry);\n      }\n    };\n\n    public static com.google.protobuf.Parser<Ack> parser() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<Ack> getParserForType() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.alibaba.otter.canal.protocol.AdminPacket.Ack getDefaultInstanceForType() {\n      return DEFAULT_INSTANCE;\n    }\n\n  }\n\n  public interface HandshakeOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.Handshake)\n      com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <code>string communication_encoding = 1;</code>\n     */\n    java.lang.String getCommunicationEncoding();\n    /**\n     * <code>string communication_encoding = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getCommunicationEncodingBytes();\n\n    /**\n     * <code>bytes seeds = 2;</code>\n     */\n    com.google.protobuf.ByteString getSeeds();\n\n    public com.alibaba.otter.canal.protocol.AdminPacket.Handshake.CommunicationEncodingPresentCase getCommunicationEncodingPresentCase();\n  }\n  /**\n   * Protobuf type {@code com.alibaba.otter.canal.protocol.Handshake}\n   */\n  public  static final class Handshake extends\n      com.google.protobuf.GeneratedMessageV3 implements\n      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.Handshake)\n      HandshakeOrBuilder {\n  private static final long serialVersionUID = 0L;\n    // Use Handshake.newBuilder() to construct.\n    private Handshake(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {\n      super(builder);\n    }\n    private Handshake() {\n      seeds_ = com.google.protobuf.ByteString.EMPTY;\n    }\n\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n    getUnknownFields() {\n      return this.unknownFields;\n    }\n    private Handshake(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      this();\n      if (extensionRegistry == null) {\n        throw new java.lang.NullPointerException();\n      }\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            case 10: {\n              java.lang.String s = input.readStringRequireUtf8();\n              communicationEncodingPresentCase_ = 1;\n              communicationEncodingPresent_ = s;\n              break;\n            }\n            case 18: {\n\n              seeds_ = input.readBytes();\n              break;\n            }\n            default: {\n              if (!parseUnknownFieldProto3(\n                  input, unknownFields, extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Handshake_descriptor;\n    }\n\n    @java.lang.Override\n    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Handshake_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              com.alibaba.otter.canal.protocol.AdminPacket.Handshake.class, com.alibaba.otter.canal.protocol.AdminPacket.Handshake.Builder.class);\n    }\n\n    private int communicationEncodingPresentCase_ = 0;\n    private java.lang.Object communicationEncodingPresent_;\n    public enum CommunicationEncodingPresentCase\n        implements com.google.protobuf.Internal.EnumLite {\n      COMMUNICATION_ENCODING(1),\n      COMMUNICATIONENCODINGPRESENT_NOT_SET(0);\n      private final int value;\n      private CommunicationEncodingPresentCase(int value) {\n        this.value = value;\n      }\n      /**\n       * @deprecated Use {@link #forNumber(int)} instead.\n       */\n      @java.lang.Deprecated\n      public static CommunicationEncodingPresentCase valueOf(int value) {\n        return forNumber(value);\n      }\n\n      public static CommunicationEncodingPresentCase forNumber(int value) {\n        switch (value) {\n          case 1: return COMMUNICATION_ENCODING;\n          case 0: return COMMUNICATIONENCODINGPRESENT_NOT_SET;\n          default: return null;\n        }\n      }\n      public int getNumber() {\n        return this.value;\n      }\n    };\n\n    public CommunicationEncodingPresentCase\n    getCommunicationEncodingPresentCase() {\n      return CommunicationEncodingPresentCase.forNumber(\n          communicationEncodingPresentCase_);\n    }\n\n    public static final int COMMUNICATION_ENCODING_FIELD_NUMBER = 1;\n    /**\n     * <code>string communication_encoding = 1;</code>\n     */\n    public java.lang.String getCommunicationEncoding() {\n      java.lang.Object ref = \"\";\n      if (communicationEncodingPresentCase_ == 1) {\n        ref = communicationEncodingPresent_;\n      }\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (communicationEncodingPresentCase_ == 1) {\n          communicationEncodingPresent_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>string communication_encoding = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getCommunicationEncodingBytes() {\n      java.lang.Object ref = \"\";\n      if (communicationEncodingPresentCase_ == 1) {\n        ref = communicationEncodingPresent_;\n      }\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        if (communicationEncodingPresentCase_ == 1) {\n          communicationEncodingPresent_ = b;\n        }\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int SEEDS_FIELD_NUMBER = 2;\n    private com.google.protobuf.ByteString seeds_;\n    /**\n     * <code>bytes seeds = 2;</code>\n     */\n    public com.google.protobuf.ByteString getSeeds() {\n      return seeds_;\n    }\n\n    private byte memoizedIsInitialized = -1;\n    @java.lang.Override\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    @java.lang.Override\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      if (communicationEncodingPresentCase_ == 1) {\n        com.google.protobuf.GeneratedMessageV3.writeString(output, 1, communicationEncodingPresent_);\n      }\n      if (!seeds_.isEmpty()) {\n        output.writeBytes(2, seeds_);\n      }\n      unknownFields.writeTo(output);\n    }\n\n    @java.lang.Override\n    public int getSerializedSize() {\n      int size = memoizedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (communicationEncodingPresentCase_ == 1) {\n        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, communicationEncodingPresent_);\n      }\n      if (!seeds_.isEmpty()) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, seeds_);\n      }\n      size += unknownFields.getSerializedSize();\n      memoizedSize = size;\n      return size;\n    }\n\n    @java.lang.Override\n    public boolean equals(final java.lang.Object obj) {\n      if (obj == this) {\n       return true;\n      }\n      if (!(obj instanceof com.alibaba.otter.canal.protocol.AdminPacket.Handshake)) {\n        return super.equals(obj);\n      }\n      com.alibaba.otter.canal.protocol.AdminPacket.Handshake other = (com.alibaba.otter.canal.protocol.AdminPacket.Handshake) obj;\n\n      boolean result = true;\n      result = result && getSeeds()\n          .equals(other.getSeeds());\n      result = result && getCommunicationEncodingPresentCase().equals(\n          other.getCommunicationEncodingPresentCase());\n      if (!result) return false;\n      switch (communicationEncodingPresentCase_) {\n        case 1:\n          result = result && getCommunicationEncoding()\n              .equals(other.getCommunicationEncoding());\n          break;\n        case 0:\n        default:\n      }\n      result = result && unknownFields.equals(other.unknownFields);\n      return result;\n    }\n\n    @java.lang.Override\n    public int hashCode() {\n      if (memoizedHashCode != 0) {\n        return memoizedHashCode;\n      }\n      int hash = 41;\n      hash = (19 * hash) + getDescriptor().hashCode();\n      hash = (37 * hash) + SEEDS_FIELD_NUMBER;\n      hash = (53 * hash) + getSeeds().hashCode();\n      switch (communicationEncodingPresentCase_) {\n        case 1:\n          hash = (37 * hash) + COMMUNICATION_ENCODING_FIELD_NUMBER;\n          hash = (53 * hash) + getCommunicationEncoding().hashCode();\n          break;\n        case 0:\n        default:\n      }\n      hash = (29 * hash) + unknownFields.hashCode();\n      memoizedHashCode = hash;\n      return hash;\n    }\n\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Handshake parseFrom(\n        java.nio.ByteBuffer data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Handshake parseFrom(\n        java.nio.ByteBuffer data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Handshake parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Handshake parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Handshake parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Handshake parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Handshake parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Handshake parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Handshake parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Handshake parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Handshake parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Handshake parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    @java.lang.Override\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder() {\n      return DEFAULT_INSTANCE.toBuilder();\n    }\n    public static Builder newBuilder(com.alibaba.otter.canal.protocol.AdminPacket.Handshake prototype) {\n      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n    }\n    @java.lang.Override\n    public Builder toBuilder() {\n      return this == DEFAULT_INSTANCE\n          ? new Builder() : new Builder().mergeFrom(this);\n    }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code com.alibaba.otter.canal.protocol.Handshake}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.Handshake)\n        com.alibaba.otter.canal.protocol.AdminPacket.HandshakeOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Handshake_descriptor;\n      }\n\n      @java.lang.Override\n      protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Handshake_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                com.alibaba.otter.canal.protocol.AdminPacket.Handshake.class, com.alibaba.otter.canal.protocol.AdminPacket.Handshake.Builder.class);\n      }\n\n      // Construct using com.alibaba.otter.canal.protocol.AdminPacket.Handshake.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessageV3\n                .alwaysUseFieldBuilders) {\n        }\n      }\n      @java.lang.Override\n      public Builder clear() {\n        super.clear();\n        seeds_ = com.google.protobuf.ByteString.EMPTY;\n\n        communicationEncodingPresentCase_ = 0;\n        communicationEncodingPresent_ = null;\n        return this;\n      }\n\n      @java.lang.Override\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Handshake_descriptor;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.AdminPacket.Handshake getDefaultInstanceForType() {\n        return com.alibaba.otter.canal.protocol.AdminPacket.Handshake.getDefaultInstance();\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.AdminPacket.Handshake build() {\n        com.alibaba.otter.canal.protocol.AdminPacket.Handshake result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.AdminPacket.Handshake buildPartial() {\n        com.alibaba.otter.canal.protocol.AdminPacket.Handshake result = new com.alibaba.otter.canal.protocol.AdminPacket.Handshake(this);\n        if (communicationEncodingPresentCase_ == 1) {\n          result.communicationEncodingPresent_ = communicationEncodingPresent_;\n        }\n        result.seeds_ = seeds_;\n        result.communicationEncodingPresentCase_ = communicationEncodingPresentCase_;\n        onBuilt();\n        return result;\n      }\n\n      @java.lang.Override\n      public Builder clone() {\n        return (Builder) super.clone();\n      }\n      @java.lang.Override\n      public Builder setField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.setField(field, value);\n      }\n      @java.lang.Override\n      public Builder clearField(\n          com.google.protobuf.Descriptors.FieldDescriptor field) {\n        return (Builder) super.clearField(field);\n      }\n      @java.lang.Override\n      public Builder clearOneof(\n          com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n        return (Builder) super.clearOneof(oneof);\n      }\n      @java.lang.Override\n      public Builder setRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          int index, java.lang.Object value) {\n        return (Builder) super.setRepeatedField(field, index, value);\n      }\n      @java.lang.Override\n      public Builder addRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.addRepeatedField(field, value);\n      }\n      @java.lang.Override\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof com.alibaba.otter.canal.protocol.AdminPacket.Handshake) {\n          return mergeFrom((com.alibaba.otter.canal.protocol.AdminPacket.Handshake)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(com.alibaba.otter.canal.protocol.AdminPacket.Handshake other) {\n        if (other == com.alibaba.otter.canal.protocol.AdminPacket.Handshake.getDefaultInstance()) return this;\n        if (other.getSeeds() != com.google.protobuf.ByteString.EMPTY) {\n          setSeeds(other.getSeeds());\n        }\n        switch (other.getCommunicationEncodingPresentCase()) {\n          case COMMUNICATION_ENCODING: {\n            communicationEncodingPresentCase_ = 1;\n            communicationEncodingPresent_ = other.communicationEncodingPresent_;\n            onChanged();\n            break;\n          }\n          case COMMUNICATIONENCODINGPRESENT_NOT_SET: {\n            break;\n          }\n        }\n        this.mergeUnknownFields(other.unknownFields);\n        onChanged();\n        return this;\n      }\n\n      @java.lang.Override\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      @java.lang.Override\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        com.alibaba.otter.canal.protocol.AdminPacket.Handshake parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (com.alibaba.otter.canal.protocol.AdminPacket.Handshake) e.getUnfinishedMessage();\n          throw e.unwrapIOException();\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int communicationEncodingPresentCase_ = 0;\n      private java.lang.Object communicationEncodingPresent_;\n      public CommunicationEncodingPresentCase\n          getCommunicationEncodingPresentCase() {\n        return CommunicationEncodingPresentCase.forNumber(\n            communicationEncodingPresentCase_);\n      }\n\n      public Builder clearCommunicationEncodingPresent() {\n        communicationEncodingPresentCase_ = 0;\n        communicationEncodingPresent_ = null;\n        onChanged();\n        return this;\n      }\n\n\n      /**\n       * <code>string communication_encoding = 1;</code>\n       */\n      public java.lang.String getCommunicationEncoding() {\n        java.lang.Object ref = \"\";\n        if (communicationEncodingPresentCase_ == 1) {\n          ref = communicationEncodingPresent_;\n        }\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          if (communicationEncodingPresentCase_ == 1) {\n            communicationEncodingPresent_ = s;\n          }\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>string communication_encoding = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getCommunicationEncodingBytes() {\n        java.lang.Object ref = \"\";\n        if (communicationEncodingPresentCase_ == 1) {\n          ref = communicationEncodingPresent_;\n        }\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          if (communicationEncodingPresentCase_ == 1) {\n            communicationEncodingPresent_ = b;\n          }\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>string communication_encoding = 1;</code>\n       */\n      public Builder setCommunicationEncoding(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  communicationEncodingPresentCase_ = 1;\n        communicationEncodingPresent_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string communication_encoding = 1;</code>\n       */\n      public Builder clearCommunicationEncoding() {\n        if (communicationEncodingPresentCase_ == 1) {\n          communicationEncodingPresentCase_ = 0;\n          communicationEncodingPresent_ = null;\n          onChanged();\n        }\n        return this;\n      }\n      /**\n       * <code>string communication_encoding = 1;</code>\n       */\n      public Builder setCommunicationEncodingBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  checkByteStringIsUtf8(value);\n        communicationEncodingPresentCase_ = 1;\n        communicationEncodingPresent_ = value;\n        onChanged();\n        return this;\n      }\n\n      private com.google.protobuf.ByteString seeds_ = com.google.protobuf.ByteString.EMPTY;\n      /**\n       * <code>bytes seeds = 2;</code>\n       */\n      public com.google.protobuf.ByteString getSeeds() {\n        return seeds_;\n      }\n      /**\n       * <code>bytes seeds = 2;</code>\n       */\n      public Builder setSeeds(com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        seeds_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>bytes seeds = 2;</code>\n       */\n      public Builder clearSeeds() {\n        \n        seeds_ = getDefaultInstance().getSeeds();\n        onChanged();\n        return this;\n      }\n      @java.lang.Override\n      public final Builder setUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.setUnknownFieldsProto3(unknownFields);\n      }\n\n      @java.lang.Override\n      public final Builder mergeUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.mergeUnknownFields(unknownFields);\n      }\n\n\n      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.Handshake)\n    }\n\n    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.Handshake)\n    private static final com.alibaba.otter.canal.protocol.AdminPacket.Handshake DEFAULT_INSTANCE;\n    static {\n      DEFAULT_INSTANCE = new com.alibaba.otter.canal.protocol.AdminPacket.Handshake();\n    }\n\n    public static com.alibaba.otter.canal.protocol.AdminPacket.Handshake getDefaultInstance() {\n      return DEFAULT_INSTANCE;\n    }\n\n    private static final com.google.protobuf.Parser<Handshake>\n        PARSER = new com.google.protobuf.AbstractParser<Handshake>() {\n      @java.lang.Override\n      public Handshake parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new Handshake(input, extensionRegistry);\n      }\n    };\n\n    public static com.google.protobuf.Parser<Handshake> parser() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<Handshake> getParserForType() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.alibaba.otter.canal.protocol.AdminPacket.Handshake getDefaultInstanceForType() {\n      return DEFAULT_INSTANCE;\n    }\n\n  }\n\n  public interface ClientAuthOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.ClientAuth)\n      com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <code>string username = 1;</code>\n     */\n    java.lang.String getUsername();\n    /**\n     * <code>string username = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getUsernameBytes();\n\n    /**\n     * <pre>\n     * hashed password with seeds from Handshake message\n     * </pre>\n     *\n     * <code>bytes password = 2;</code>\n     */\n    com.google.protobuf.ByteString getPassword();\n\n    /**\n     * <pre>\n     * in seconds\n     * </pre>\n     *\n     * <code>int32 net_read_timeout = 3;</code>\n     */\n    int getNetReadTimeout();\n\n    /**\n     * <pre>\n     * in seconds\n     * </pre>\n     *\n     * <code>int32 net_write_timeout = 4;</code>\n     */\n    int getNetWriteTimeout();\n\n    public com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth.NetReadTimeoutPresentCase getNetReadTimeoutPresentCase();\n\n    public com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth.NetWriteTimeoutPresentCase getNetWriteTimeoutPresentCase();\n  }\n  /**\n   * <pre>\n   * client authentication\n   * </pre>\n   *\n   * Protobuf type {@code com.alibaba.otter.canal.protocol.ClientAuth}\n   */\n  public  static final class ClientAuth extends\n      com.google.protobuf.GeneratedMessageV3 implements\n      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.ClientAuth)\n      ClientAuthOrBuilder {\n  private static final long serialVersionUID = 0L;\n    // Use ClientAuth.newBuilder() to construct.\n    private ClientAuth(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {\n      super(builder);\n    }\n    private ClientAuth() {\n      username_ = \"\";\n      password_ = com.google.protobuf.ByteString.EMPTY;\n    }\n\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n    getUnknownFields() {\n      return this.unknownFields;\n    }\n    private ClientAuth(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      this();\n      if (extensionRegistry == null) {\n        throw new java.lang.NullPointerException();\n      }\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            case 10: {\n              java.lang.String s = input.readStringRequireUtf8();\n\n              username_ = s;\n              break;\n            }\n            case 18: {\n\n              password_ = input.readBytes();\n              break;\n            }\n            case 24: {\n              netReadTimeoutPresentCase_ = 3;\n              netReadTimeoutPresent_ = input.readInt32();\n              break;\n            }\n            case 32: {\n              netWriteTimeoutPresentCase_ = 4;\n              netWriteTimeoutPresent_ = input.readInt32();\n              break;\n            }\n            default: {\n              if (!parseUnknownFieldProto3(\n                  input, unknownFields, extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_ClientAuth_descriptor;\n    }\n\n    @java.lang.Override\n    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_ClientAuth_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth.class, com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth.Builder.class);\n    }\n\n    private int netReadTimeoutPresentCase_ = 0;\n    private java.lang.Object netReadTimeoutPresent_;\n    public enum NetReadTimeoutPresentCase\n        implements com.google.protobuf.Internal.EnumLite {\n      NET_READ_TIMEOUT(3),\n      NETREADTIMEOUTPRESENT_NOT_SET(0);\n      private final int value;\n      private NetReadTimeoutPresentCase(int value) {\n        this.value = value;\n      }\n      /**\n       * @deprecated Use {@link #forNumber(int)} instead.\n       */\n      @java.lang.Deprecated\n      public static NetReadTimeoutPresentCase valueOf(int value) {\n        return forNumber(value);\n      }\n\n      public static NetReadTimeoutPresentCase forNumber(int value) {\n        switch (value) {\n          case 3: return NET_READ_TIMEOUT;\n          case 0: return NETREADTIMEOUTPRESENT_NOT_SET;\n          default: return null;\n        }\n      }\n      public int getNumber() {\n        return this.value;\n      }\n    };\n\n    public NetReadTimeoutPresentCase\n    getNetReadTimeoutPresentCase() {\n      return NetReadTimeoutPresentCase.forNumber(\n          netReadTimeoutPresentCase_);\n    }\n\n    private int netWriteTimeoutPresentCase_ = 0;\n    private java.lang.Object netWriteTimeoutPresent_;\n    public enum NetWriteTimeoutPresentCase\n        implements com.google.protobuf.Internal.EnumLite {\n      NET_WRITE_TIMEOUT(4),\n      NETWRITETIMEOUTPRESENT_NOT_SET(0);\n      private final int value;\n      private NetWriteTimeoutPresentCase(int value) {\n        this.value = value;\n      }\n      /**\n       * @deprecated Use {@link #forNumber(int)} instead.\n       */\n      @java.lang.Deprecated\n      public static NetWriteTimeoutPresentCase valueOf(int value) {\n        return forNumber(value);\n      }\n\n      public static NetWriteTimeoutPresentCase forNumber(int value) {\n        switch (value) {\n          case 4: return NET_WRITE_TIMEOUT;\n          case 0: return NETWRITETIMEOUTPRESENT_NOT_SET;\n          default: return null;\n        }\n      }\n      public int getNumber() {\n        return this.value;\n      }\n    };\n\n    public NetWriteTimeoutPresentCase\n    getNetWriteTimeoutPresentCase() {\n      return NetWriteTimeoutPresentCase.forNumber(\n          netWriteTimeoutPresentCase_);\n    }\n\n    public static final int USERNAME_FIELD_NUMBER = 1;\n    private volatile java.lang.Object username_;\n    /**\n     * <code>string username = 1;</code>\n     */\n    public java.lang.String getUsername() {\n      java.lang.Object ref = username_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        username_ = s;\n        return s;\n      }\n    }\n    /**\n     * <code>string username = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getUsernameBytes() {\n      java.lang.Object ref = username_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        username_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int PASSWORD_FIELD_NUMBER = 2;\n    private com.google.protobuf.ByteString password_;\n    /**\n     * <pre>\n     * hashed password with seeds from Handshake message\n     * </pre>\n     *\n     * <code>bytes password = 2;</code>\n     */\n    public com.google.protobuf.ByteString getPassword() {\n      return password_;\n    }\n\n    public static final int NET_READ_TIMEOUT_FIELD_NUMBER = 3;\n    /**\n     * <pre>\n     * in seconds\n     * </pre>\n     *\n     * <code>int32 net_read_timeout = 3;</code>\n     */\n    public int getNetReadTimeout() {\n      if (netReadTimeoutPresentCase_ == 3) {\n        return (java.lang.Integer) netReadTimeoutPresent_;\n      }\n      return 0;\n    }\n\n    public static final int NET_WRITE_TIMEOUT_FIELD_NUMBER = 4;\n    /**\n     * <pre>\n     * in seconds\n     * </pre>\n     *\n     * <code>int32 net_write_timeout = 4;</code>\n     */\n    public int getNetWriteTimeout() {\n      if (netWriteTimeoutPresentCase_ == 4) {\n        return (java.lang.Integer) netWriteTimeoutPresent_;\n      }\n      return 0;\n    }\n\n    private byte memoizedIsInitialized = -1;\n    @java.lang.Override\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    @java.lang.Override\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      if (!getUsernameBytes().isEmpty()) {\n        com.google.protobuf.GeneratedMessageV3.writeString(output, 1, username_);\n      }\n      if (!password_.isEmpty()) {\n        output.writeBytes(2, password_);\n      }\n      if (netReadTimeoutPresentCase_ == 3) {\n        output.writeInt32(\n            3, (int)((java.lang.Integer) netReadTimeoutPresent_));\n      }\n      if (netWriteTimeoutPresentCase_ == 4) {\n        output.writeInt32(\n            4, (int)((java.lang.Integer) netWriteTimeoutPresent_));\n      }\n      unknownFields.writeTo(output);\n    }\n\n    @java.lang.Override\n    public int getSerializedSize() {\n      int size = memoizedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (!getUsernameBytes().isEmpty()) {\n        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, username_);\n      }\n      if (!password_.isEmpty()) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, password_);\n      }\n      if (netReadTimeoutPresentCase_ == 3) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(\n              3, (int)((java.lang.Integer) netReadTimeoutPresent_));\n      }\n      if (netWriteTimeoutPresentCase_ == 4) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(\n              4, (int)((java.lang.Integer) netWriteTimeoutPresent_));\n      }\n      size += unknownFields.getSerializedSize();\n      memoizedSize = size;\n      return size;\n    }\n\n    @java.lang.Override\n    public boolean equals(final java.lang.Object obj) {\n      if (obj == this) {\n       return true;\n      }\n      if (!(obj instanceof com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth)) {\n        return super.equals(obj);\n      }\n      com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth other = (com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth) obj;\n\n      boolean result = true;\n      result = result && getUsername()\n          .equals(other.getUsername());\n      result = result && getPassword()\n          .equals(other.getPassword());\n      result = result && getNetReadTimeoutPresentCase().equals(\n          other.getNetReadTimeoutPresentCase());\n      if (!result) return false;\n      switch (netReadTimeoutPresentCase_) {\n        case 3:\n          result = result && (getNetReadTimeout()\n              == other.getNetReadTimeout());\n          break;\n        case 0:\n        default:\n      }\n      result = result && getNetWriteTimeoutPresentCase().equals(\n          other.getNetWriteTimeoutPresentCase());\n      if (!result) return false;\n      switch (netWriteTimeoutPresentCase_) {\n        case 4:\n          result = result && (getNetWriteTimeout()\n              == other.getNetWriteTimeout());\n          break;\n        case 0:\n        default:\n      }\n      result = result && unknownFields.equals(other.unknownFields);\n      return result;\n    }\n\n    @java.lang.Override\n    public int hashCode() {\n      if (memoizedHashCode != 0) {\n        return memoizedHashCode;\n      }\n      int hash = 41;\n      hash = (19 * hash) + getDescriptor().hashCode();\n      hash = (37 * hash) + USERNAME_FIELD_NUMBER;\n      hash = (53 * hash) + getUsername().hashCode();\n      hash = (37 * hash) + PASSWORD_FIELD_NUMBER;\n      hash = (53 * hash) + getPassword().hashCode();\n      switch (netReadTimeoutPresentCase_) {\n        case 3:\n          hash = (37 * hash) + NET_READ_TIMEOUT_FIELD_NUMBER;\n          hash = (53 * hash) + getNetReadTimeout();\n          break;\n        case 0:\n        default:\n      }\n      switch (netWriteTimeoutPresentCase_) {\n        case 4:\n          hash = (37 * hash) + NET_WRITE_TIMEOUT_FIELD_NUMBER;\n          hash = (53 * hash) + getNetWriteTimeout();\n          break;\n        case 0:\n        default:\n      }\n      hash = (29 * hash) + unknownFields.hashCode();\n      memoizedHashCode = hash;\n      return hash;\n    }\n\n    public static com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth parseFrom(\n        java.nio.ByteBuffer data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth parseFrom(\n        java.nio.ByteBuffer data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    @java.lang.Override\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder() {\n      return DEFAULT_INSTANCE.toBuilder();\n    }\n    public static Builder newBuilder(com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth prototype) {\n      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n    }\n    @java.lang.Override\n    public Builder toBuilder() {\n      return this == DEFAULT_INSTANCE\n          ? new Builder() : new Builder().mergeFrom(this);\n    }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * <pre>\n     * client authentication\n     * </pre>\n     *\n     * Protobuf type {@code com.alibaba.otter.canal.protocol.ClientAuth}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.ClientAuth)\n        com.alibaba.otter.canal.protocol.AdminPacket.ClientAuthOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_ClientAuth_descriptor;\n      }\n\n      @java.lang.Override\n      protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_ClientAuth_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth.class, com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth.Builder.class);\n      }\n\n      // Construct using com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessageV3\n                .alwaysUseFieldBuilders) {\n        }\n      }\n      @java.lang.Override\n      public Builder clear() {\n        super.clear();\n        username_ = \"\";\n\n        password_ = com.google.protobuf.ByteString.EMPTY;\n\n        netReadTimeoutPresentCase_ = 0;\n        netReadTimeoutPresent_ = null;\n        netWriteTimeoutPresentCase_ = 0;\n        netWriteTimeoutPresent_ = null;\n        return this;\n      }\n\n      @java.lang.Override\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_ClientAuth_descriptor;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth getDefaultInstanceForType() {\n        return com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth.getDefaultInstance();\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth build() {\n        com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth buildPartial() {\n        com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth result = new com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth(this);\n        result.username_ = username_;\n        result.password_ = password_;\n        if (netReadTimeoutPresentCase_ == 3) {\n          result.netReadTimeoutPresent_ = netReadTimeoutPresent_;\n        }\n        if (netWriteTimeoutPresentCase_ == 4) {\n          result.netWriteTimeoutPresent_ = netWriteTimeoutPresent_;\n        }\n        result.netReadTimeoutPresentCase_ = netReadTimeoutPresentCase_;\n        result.netWriteTimeoutPresentCase_ = netWriteTimeoutPresentCase_;\n        onBuilt();\n        return result;\n      }\n\n      @java.lang.Override\n      public Builder clone() {\n        return (Builder) super.clone();\n      }\n      @java.lang.Override\n      public Builder setField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.setField(field, value);\n      }\n      @java.lang.Override\n      public Builder clearField(\n          com.google.protobuf.Descriptors.FieldDescriptor field) {\n        return (Builder) super.clearField(field);\n      }\n      @java.lang.Override\n      public Builder clearOneof(\n          com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n        return (Builder) super.clearOneof(oneof);\n      }\n      @java.lang.Override\n      public Builder setRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          int index, java.lang.Object value) {\n        return (Builder) super.setRepeatedField(field, index, value);\n      }\n      @java.lang.Override\n      public Builder addRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.addRepeatedField(field, value);\n      }\n      @java.lang.Override\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth) {\n          return mergeFrom((com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth other) {\n        if (other == com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth.getDefaultInstance()) return this;\n        if (!other.getUsername().isEmpty()) {\n          username_ = other.username_;\n          onChanged();\n        }\n        if (other.getPassword() != com.google.protobuf.ByteString.EMPTY) {\n          setPassword(other.getPassword());\n        }\n        switch (other.getNetReadTimeoutPresentCase()) {\n          case NET_READ_TIMEOUT: {\n            setNetReadTimeout(other.getNetReadTimeout());\n            break;\n          }\n          case NETREADTIMEOUTPRESENT_NOT_SET: {\n            break;\n          }\n        }\n        switch (other.getNetWriteTimeoutPresentCase()) {\n          case NET_WRITE_TIMEOUT: {\n            setNetWriteTimeout(other.getNetWriteTimeout());\n            break;\n          }\n          case NETWRITETIMEOUTPRESENT_NOT_SET: {\n            break;\n          }\n        }\n        this.mergeUnknownFields(other.unknownFields);\n        onChanged();\n        return this;\n      }\n\n      @java.lang.Override\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      @java.lang.Override\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth) e.getUnfinishedMessage();\n          throw e.unwrapIOException();\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int netReadTimeoutPresentCase_ = 0;\n      private java.lang.Object netReadTimeoutPresent_;\n      public NetReadTimeoutPresentCase\n          getNetReadTimeoutPresentCase() {\n        return NetReadTimeoutPresentCase.forNumber(\n            netReadTimeoutPresentCase_);\n      }\n\n      public Builder clearNetReadTimeoutPresent() {\n        netReadTimeoutPresentCase_ = 0;\n        netReadTimeoutPresent_ = null;\n        onChanged();\n        return this;\n      }\n\n      private int netWriteTimeoutPresentCase_ = 0;\n      private java.lang.Object netWriteTimeoutPresent_;\n      public NetWriteTimeoutPresentCase\n          getNetWriteTimeoutPresentCase() {\n        return NetWriteTimeoutPresentCase.forNumber(\n            netWriteTimeoutPresentCase_);\n      }\n\n      public Builder clearNetWriteTimeoutPresent() {\n        netWriteTimeoutPresentCase_ = 0;\n        netWriteTimeoutPresent_ = null;\n        onChanged();\n        return this;\n      }\n\n\n      private java.lang.Object username_ = \"\";\n      /**\n       * <code>string username = 1;</code>\n       */\n      public java.lang.String getUsername() {\n        java.lang.Object ref = username_;\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          username_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>string username = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getUsernameBytes() {\n        java.lang.Object ref = username_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          username_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>string username = 1;</code>\n       */\n      public Builder setUsername(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        username_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string username = 1;</code>\n       */\n      public Builder clearUsername() {\n        \n        username_ = getDefaultInstance().getUsername();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string username = 1;</code>\n       */\n      public Builder setUsernameBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  checkByteStringIsUtf8(value);\n        \n        username_ = value;\n        onChanged();\n        return this;\n      }\n\n      private com.google.protobuf.ByteString password_ = com.google.protobuf.ByteString.EMPTY;\n      /**\n       * <pre>\n       * hashed password with seeds from Handshake message\n       * </pre>\n       *\n       * <code>bytes password = 2;</code>\n       */\n      public com.google.protobuf.ByteString getPassword() {\n        return password_;\n      }\n      /**\n       * <pre>\n       * hashed password with seeds from Handshake message\n       * </pre>\n       *\n       * <code>bytes password = 2;</code>\n       */\n      public Builder setPassword(com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        password_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <pre>\n       * hashed password with seeds from Handshake message\n       * </pre>\n       *\n       * <code>bytes password = 2;</code>\n       */\n      public Builder clearPassword() {\n        \n        password_ = getDefaultInstance().getPassword();\n        onChanged();\n        return this;\n      }\n\n      /**\n       * <pre>\n       * in seconds\n       * </pre>\n       *\n       * <code>int32 net_read_timeout = 3;</code>\n       */\n      public int getNetReadTimeout() {\n        if (netReadTimeoutPresentCase_ == 3) {\n          return (java.lang.Integer) netReadTimeoutPresent_;\n        }\n        return 0;\n      }\n      /**\n       * <pre>\n       * in seconds\n       * </pre>\n       *\n       * <code>int32 net_read_timeout = 3;</code>\n       */\n      public Builder setNetReadTimeout(int value) {\n        netReadTimeoutPresentCase_ = 3;\n        netReadTimeoutPresent_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <pre>\n       * in seconds\n       * </pre>\n       *\n       * <code>int32 net_read_timeout = 3;</code>\n       */\n      public Builder clearNetReadTimeout() {\n        if (netReadTimeoutPresentCase_ == 3) {\n          netReadTimeoutPresentCase_ = 0;\n          netReadTimeoutPresent_ = null;\n          onChanged();\n        }\n        return this;\n      }\n\n      /**\n       * <pre>\n       * in seconds\n       * </pre>\n       *\n       * <code>int32 net_write_timeout = 4;</code>\n       */\n      public int getNetWriteTimeout() {\n        if (netWriteTimeoutPresentCase_ == 4) {\n          return (java.lang.Integer) netWriteTimeoutPresent_;\n        }\n        return 0;\n      }\n      /**\n       * <pre>\n       * in seconds\n       * </pre>\n       *\n       * <code>int32 net_write_timeout = 4;</code>\n       */\n      public Builder setNetWriteTimeout(int value) {\n        netWriteTimeoutPresentCase_ = 4;\n        netWriteTimeoutPresent_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <pre>\n       * in seconds\n       * </pre>\n       *\n       * <code>int32 net_write_timeout = 4;</code>\n       */\n      public Builder clearNetWriteTimeout() {\n        if (netWriteTimeoutPresentCase_ == 4) {\n          netWriteTimeoutPresentCase_ = 0;\n          netWriteTimeoutPresent_ = null;\n          onChanged();\n        }\n        return this;\n      }\n      @java.lang.Override\n      public final Builder setUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.setUnknownFieldsProto3(unknownFields);\n      }\n\n      @java.lang.Override\n      public final Builder mergeUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.mergeUnknownFields(unknownFields);\n      }\n\n\n      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.ClientAuth)\n    }\n\n    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.ClientAuth)\n    private static final com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth DEFAULT_INSTANCE;\n    static {\n      DEFAULT_INSTANCE = new com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth();\n    }\n\n    public static com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth getDefaultInstance() {\n      return DEFAULT_INSTANCE;\n    }\n\n    private static final com.google.protobuf.Parser<ClientAuth>\n        PARSER = new com.google.protobuf.AbstractParser<ClientAuth>() {\n      @java.lang.Override\n      public ClientAuth parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new ClientAuth(input, extensionRegistry);\n      }\n    };\n\n    public static com.google.protobuf.Parser<ClientAuth> parser() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<ClientAuth> getParserForType() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth getDefaultInstanceForType() {\n      return DEFAULT_INSTANCE;\n    }\n\n  }\n\n  public interface ServerAdminOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.ServerAdmin)\n      com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <pre>\n     * check/start/stop/restart/list\n     * </pre>\n     *\n     * <code>string action = 1;</code>\n     */\n    java.lang.String getAction();\n    /**\n     * <pre>\n     * check/start/stop/restart/list\n     * </pre>\n     *\n     * <code>string action = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getActionBytes();\n  }\n  /**\n   * Protobuf type {@code com.alibaba.otter.canal.protocol.ServerAdmin}\n   */\n  public  static final class ServerAdmin extends\n      com.google.protobuf.GeneratedMessageV3 implements\n      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.ServerAdmin)\n      ServerAdminOrBuilder {\n  private static final long serialVersionUID = 0L;\n    // Use ServerAdmin.newBuilder() to construct.\n    private ServerAdmin(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {\n      super(builder);\n    }\n    private ServerAdmin() {\n      action_ = \"\";\n    }\n\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n    getUnknownFields() {\n      return this.unknownFields;\n    }\n    private ServerAdmin(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      this();\n      if (extensionRegistry == null) {\n        throw new java.lang.NullPointerException();\n      }\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            case 10: {\n              java.lang.String s = input.readStringRequireUtf8();\n\n              action_ = s;\n              break;\n            }\n            default: {\n              if (!parseUnknownFieldProto3(\n                  input, unknownFields, extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_ServerAdmin_descriptor;\n    }\n\n    @java.lang.Override\n    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_ServerAdmin_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin.class, com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin.Builder.class);\n    }\n\n    public static final int ACTION_FIELD_NUMBER = 1;\n    private volatile java.lang.Object action_;\n    /**\n     * <pre>\n     * check/start/stop/restart/list\n     * </pre>\n     *\n     * <code>string action = 1;</code>\n     */\n    public java.lang.String getAction() {\n      java.lang.Object ref = action_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        action_ = s;\n        return s;\n      }\n    }\n    /**\n     * <pre>\n     * check/start/stop/restart/list\n     * </pre>\n     *\n     * <code>string action = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getActionBytes() {\n      java.lang.Object ref = action_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        action_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private byte memoizedIsInitialized = -1;\n    @java.lang.Override\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    @java.lang.Override\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      if (!getActionBytes().isEmpty()) {\n        com.google.protobuf.GeneratedMessageV3.writeString(output, 1, action_);\n      }\n      unknownFields.writeTo(output);\n    }\n\n    @java.lang.Override\n    public int getSerializedSize() {\n      int size = memoizedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (!getActionBytes().isEmpty()) {\n        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, action_);\n      }\n      size += unknownFields.getSerializedSize();\n      memoizedSize = size;\n      return size;\n    }\n\n    @java.lang.Override\n    public boolean equals(final java.lang.Object obj) {\n      if (obj == this) {\n       return true;\n      }\n      if (!(obj instanceof com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin)) {\n        return super.equals(obj);\n      }\n      com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin other = (com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin) obj;\n\n      boolean result = true;\n      result = result && getAction()\n          .equals(other.getAction());\n      result = result && unknownFields.equals(other.unknownFields);\n      return result;\n    }\n\n    @java.lang.Override\n    public int hashCode() {\n      if (memoizedHashCode != 0) {\n        return memoizedHashCode;\n      }\n      int hash = 41;\n      hash = (19 * hash) + getDescriptor().hashCode();\n      hash = (37 * hash) + ACTION_FIELD_NUMBER;\n      hash = (53 * hash) + getAction().hashCode();\n      hash = (29 * hash) + unknownFields.hashCode();\n      memoizedHashCode = hash;\n      return hash;\n    }\n\n    public static com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin parseFrom(\n        java.nio.ByteBuffer data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin parseFrom(\n        java.nio.ByteBuffer data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    @java.lang.Override\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder() {\n      return DEFAULT_INSTANCE.toBuilder();\n    }\n    public static Builder newBuilder(com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin prototype) {\n      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n    }\n    @java.lang.Override\n    public Builder toBuilder() {\n      return this == DEFAULT_INSTANCE\n          ? new Builder() : new Builder().mergeFrom(this);\n    }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code com.alibaba.otter.canal.protocol.ServerAdmin}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.ServerAdmin)\n        com.alibaba.otter.canal.protocol.AdminPacket.ServerAdminOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_ServerAdmin_descriptor;\n      }\n\n      @java.lang.Override\n      protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_ServerAdmin_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin.class, com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin.Builder.class);\n      }\n\n      // Construct using com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessageV3\n                .alwaysUseFieldBuilders) {\n        }\n      }\n      @java.lang.Override\n      public Builder clear() {\n        super.clear();\n        action_ = \"\";\n\n        return this;\n      }\n\n      @java.lang.Override\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_ServerAdmin_descriptor;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin getDefaultInstanceForType() {\n        return com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin.getDefaultInstance();\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin build() {\n        com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin buildPartial() {\n        com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin result = new com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin(this);\n        result.action_ = action_;\n        onBuilt();\n        return result;\n      }\n\n      @java.lang.Override\n      public Builder clone() {\n        return (Builder) super.clone();\n      }\n      @java.lang.Override\n      public Builder setField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.setField(field, value);\n      }\n      @java.lang.Override\n      public Builder clearField(\n          com.google.protobuf.Descriptors.FieldDescriptor field) {\n        return (Builder) super.clearField(field);\n      }\n      @java.lang.Override\n      public Builder clearOneof(\n          com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n        return (Builder) super.clearOneof(oneof);\n      }\n      @java.lang.Override\n      public Builder setRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          int index, java.lang.Object value) {\n        return (Builder) super.setRepeatedField(field, index, value);\n      }\n      @java.lang.Override\n      public Builder addRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.addRepeatedField(field, value);\n      }\n      @java.lang.Override\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin) {\n          return mergeFrom((com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin other) {\n        if (other == com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin.getDefaultInstance()) return this;\n        if (!other.getAction().isEmpty()) {\n          action_ = other.action_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.unknownFields);\n        onChanged();\n        return this;\n      }\n\n      @java.lang.Override\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      @java.lang.Override\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin) e.getUnfinishedMessage();\n          throw e.unwrapIOException();\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n\n      private java.lang.Object action_ = \"\";\n      /**\n       * <pre>\n       * check/start/stop/restart/list\n       * </pre>\n       *\n       * <code>string action = 1;</code>\n       */\n      public java.lang.String getAction() {\n        java.lang.Object ref = action_;\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          action_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <pre>\n       * check/start/stop/restart/list\n       * </pre>\n       *\n       * <code>string action = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getActionBytes() {\n        java.lang.Object ref = action_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          action_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <pre>\n       * check/start/stop/restart/list\n       * </pre>\n       *\n       * <code>string action = 1;</code>\n       */\n      public Builder setAction(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        action_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <pre>\n       * check/start/stop/restart/list\n       * </pre>\n       *\n       * <code>string action = 1;</code>\n       */\n      public Builder clearAction() {\n        \n        action_ = getDefaultInstance().getAction();\n        onChanged();\n        return this;\n      }\n      /**\n       * <pre>\n       * check/start/stop/restart/list\n       * </pre>\n       *\n       * <code>string action = 1;</code>\n       */\n      public Builder setActionBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  checkByteStringIsUtf8(value);\n        \n        action_ = value;\n        onChanged();\n        return this;\n      }\n      @java.lang.Override\n      public final Builder setUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.setUnknownFieldsProto3(unknownFields);\n      }\n\n      @java.lang.Override\n      public final Builder mergeUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.mergeUnknownFields(unknownFields);\n      }\n\n\n      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.ServerAdmin)\n    }\n\n    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.ServerAdmin)\n    private static final com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin DEFAULT_INSTANCE;\n    static {\n      DEFAULT_INSTANCE = new com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin();\n    }\n\n    public static com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin getDefaultInstance() {\n      return DEFAULT_INSTANCE;\n    }\n\n    private static final com.google.protobuf.Parser<ServerAdmin>\n        PARSER = new com.google.protobuf.AbstractParser<ServerAdmin>() {\n      @java.lang.Override\n      public ServerAdmin parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new ServerAdmin(input, extensionRegistry);\n      }\n    };\n\n    public static com.google.protobuf.Parser<ServerAdmin> parser() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<ServerAdmin> getParserForType() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin getDefaultInstanceForType() {\n      return DEFAULT_INSTANCE;\n    }\n\n  }\n\n  public interface InstanceAdminOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.InstanceAdmin)\n      com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <code>string destination = 1;</code>\n     */\n    java.lang.String getDestination();\n    /**\n     * <code>string destination = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getDestinationBytes();\n\n    /**\n     * <pre>\n     * check/start/stop/reload\n     * </pre>\n     *\n     * <code>string action = 2;</code>\n     */\n    java.lang.String getAction();\n    /**\n     * <pre>\n     * check/start/stop/reload\n     * </pre>\n     *\n     * <code>string action = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getActionBytes();\n  }\n  /**\n   * Protobuf type {@code com.alibaba.otter.canal.protocol.InstanceAdmin}\n   */\n  public  static final class InstanceAdmin extends\n      com.google.protobuf.GeneratedMessageV3 implements\n      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.InstanceAdmin)\n      InstanceAdminOrBuilder {\n  private static final long serialVersionUID = 0L;\n    // Use InstanceAdmin.newBuilder() to construct.\n    private InstanceAdmin(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {\n      super(builder);\n    }\n    private InstanceAdmin() {\n      destination_ = \"\";\n      action_ = \"\";\n    }\n\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n    getUnknownFields() {\n      return this.unknownFields;\n    }\n    private InstanceAdmin(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      this();\n      if (extensionRegistry == null) {\n        throw new java.lang.NullPointerException();\n      }\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            case 10: {\n              java.lang.String s = input.readStringRequireUtf8();\n\n              destination_ = s;\n              break;\n            }\n            case 18: {\n              java.lang.String s = input.readStringRequireUtf8();\n\n              action_ = s;\n              break;\n            }\n            default: {\n              if (!parseUnknownFieldProto3(\n                  input, unknownFields, extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_InstanceAdmin_descriptor;\n    }\n\n    @java.lang.Override\n    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_InstanceAdmin_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin.class, com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin.Builder.class);\n    }\n\n    public static final int DESTINATION_FIELD_NUMBER = 1;\n    private volatile java.lang.Object destination_;\n    /**\n     * <code>string destination = 1;</code>\n     */\n    public java.lang.String getDestination() {\n      java.lang.Object ref = destination_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        destination_ = s;\n        return s;\n      }\n    }\n    /**\n     * <code>string destination = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getDestinationBytes() {\n      java.lang.Object ref = destination_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        destination_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int ACTION_FIELD_NUMBER = 2;\n    private volatile java.lang.Object action_;\n    /**\n     * <pre>\n     * check/start/stop/reload\n     * </pre>\n     *\n     * <code>string action = 2;</code>\n     */\n    public java.lang.String getAction() {\n      java.lang.Object ref = action_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        action_ = s;\n        return s;\n      }\n    }\n    /**\n     * <pre>\n     * check/start/stop/reload\n     * </pre>\n     *\n     * <code>string action = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getActionBytes() {\n      java.lang.Object ref = action_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        action_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private byte memoizedIsInitialized = -1;\n    @java.lang.Override\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    @java.lang.Override\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      if (!getDestinationBytes().isEmpty()) {\n        com.google.protobuf.GeneratedMessageV3.writeString(output, 1, destination_);\n      }\n      if (!getActionBytes().isEmpty()) {\n        com.google.protobuf.GeneratedMessageV3.writeString(output, 2, action_);\n      }\n      unknownFields.writeTo(output);\n    }\n\n    @java.lang.Override\n    public int getSerializedSize() {\n      int size = memoizedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (!getDestinationBytes().isEmpty()) {\n        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, destination_);\n      }\n      if (!getActionBytes().isEmpty()) {\n        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, action_);\n      }\n      size += unknownFields.getSerializedSize();\n      memoizedSize = size;\n      return size;\n    }\n\n    @java.lang.Override\n    public boolean equals(final java.lang.Object obj) {\n      if (obj == this) {\n       return true;\n      }\n      if (!(obj instanceof com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin)) {\n        return super.equals(obj);\n      }\n      com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin other = (com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin) obj;\n\n      boolean result = true;\n      result = result && getDestination()\n          .equals(other.getDestination());\n      result = result && getAction()\n          .equals(other.getAction());\n      result = result && unknownFields.equals(other.unknownFields);\n      return result;\n    }\n\n    @java.lang.Override\n    public int hashCode() {\n      if (memoizedHashCode != 0) {\n        return memoizedHashCode;\n      }\n      int hash = 41;\n      hash = (19 * hash) + getDescriptor().hashCode();\n      hash = (37 * hash) + DESTINATION_FIELD_NUMBER;\n      hash = (53 * hash) + getDestination().hashCode();\n      hash = (37 * hash) + ACTION_FIELD_NUMBER;\n      hash = (53 * hash) + getAction().hashCode();\n      hash = (29 * hash) + unknownFields.hashCode();\n      memoizedHashCode = hash;\n      return hash;\n    }\n\n    public static com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin parseFrom(\n        java.nio.ByteBuffer data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin parseFrom(\n        java.nio.ByteBuffer data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    @java.lang.Override\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder() {\n      return DEFAULT_INSTANCE.toBuilder();\n    }\n    public static Builder newBuilder(com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin prototype) {\n      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n    }\n    @java.lang.Override\n    public Builder toBuilder() {\n      return this == DEFAULT_INSTANCE\n          ? new Builder() : new Builder().mergeFrom(this);\n    }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code com.alibaba.otter.canal.protocol.InstanceAdmin}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.InstanceAdmin)\n        com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdminOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_InstanceAdmin_descriptor;\n      }\n\n      @java.lang.Override\n      protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_InstanceAdmin_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin.class, com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin.Builder.class);\n      }\n\n      // Construct using com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessageV3\n                .alwaysUseFieldBuilders) {\n        }\n      }\n      @java.lang.Override\n      public Builder clear() {\n        super.clear();\n        destination_ = \"\";\n\n        action_ = \"\";\n\n        return this;\n      }\n\n      @java.lang.Override\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_InstanceAdmin_descriptor;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin getDefaultInstanceForType() {\n        return com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin.getDefaultInstance();\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin build() {\n        com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin buildPartial() {\n        com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin result = new com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin(this);\n        result.destination_ = destination_;\n        result.action_ = action_;\n        onBuilt();\n        return result;\n      }\n\n      @java.lang.Override\n      public Builder clone() {\n        return (Builder) super.clone();\n      }\n      @java.lang.Override\n      public Builder setField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.setField(field, value);\n      }\n      @java.lang.Override\n      public Builder clearField(\n          com.google.protobuf.Descriptors.FieldDescriptor field) {\n        return (Builder) super.clearField(field);\n      }\n      @java.lang.Override\n      public Builder clearOneof(\n          com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n        return (Builder) super.clearOneof(oneof);\n      }\n      @java.lang.Override\n      public Builder setRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          int index, java.lang.Object value) {\n        return (Builder) super.setRepeatedField(field, index, value);\n      }\n      @java.lang.Override\n      public Builder addRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.addRepeatedField(field, value);\n      }\n      @java.lang.Override\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin) {\n          return mergeFrom((com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin other) {\n        if (other == com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin.getDefaultInstance()) return this;\n        if (!other.getDestination().isEmpty()) {\n          destination_ = other.destination_;\n          onChanged();\n        }\n        if (!other.getAction().isEmpty()) {\n          action_ = other.action_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.unknownFields);\n        onChanged();\n        return this;\n      }\n\n      @java.lang.Override\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      @java.lang.Override\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin) e.getUnfinishedMessage();\n          throw e.unwrapIOException();\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n\n      private java.lang.Object destination_ = \"\";\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public java.lang.String getDestination() {\n        java.lang.Object ref = destination_;\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          destination_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getDestinationBytes() {\n        java.lang.Object ref = destination_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          destination_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public Builder setDestination(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        destination_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public Builder clearDestination() {\n        \n        destination_ = getDefaultInstance().getDestination();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public Builder setDestinationBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  checkByteStringIsUtf8(value);\n        \n        destination_ = value;\n        onChanged();\n        return this;\n      }\n\n      private java.lang.Object action_ = \"\";\n      /**\n       * <pre>\n       * check/start/stop/reload\n       * </pre>\n       *\n       * <code>string action = 2;</code>\n       */\n      public java.lang.String getAction() {\n        java.lang.Object ref = action_;\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          action_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <pre>\n       * check/start/stop/reload\n       * </pre>\n       *\n       * <code>string action = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getActionBytes() {\n        java.lang.Object ref = action_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          action_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <pre>\n       * check/start/stop/reload\n       * </pre>\n       *\n       * <code>string action = 2;</code>\n       */\n      public Builder setAction(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        action_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <pre>\n       * check/start/stop/reload\n       * </pre>\n       *\n       * <code>string action = 2;</code>\n       */\n      public Builder clearAction() {\n        \n        action_ = getDefaultInstance().getAction();\n        onChanged();\n        return this;\n      }\n      /**\n       * <pre>\n       * check/start/stop/reload\n       * </pre>\n       *\n       * <code>string action = 2;</code>\n       */\n      public Builder setActionBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  checkByteStringIsUtf8(value);\n        \n        action_ = value;\n        onChanged();\n        return this;\n      }\n      @java.lang.Override\n      public final Builder setUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.setUnknownFieldsProto3(unknownFields);\n      }\n\n      @java.lang.Override\n      public final Builder mergeUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.mergeUnknownFields(unknownFields);\n      }\n\n\n      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.InstanceAdmin)\n    }\n\n    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.InstanceAdmin)\n    private static final com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin DEFAULT_INSTANCE;\n    static {\n      DEFAULT_INSTANCE = new com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin();\n    }\n\n    public static com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin getDefaultInstance() {\n      return DEFAULT_INSTANCE;\n    }\n\n    private static final com.google.protobuf.Parser<InstanceAdmin>\n        PARSER = new com.google.protobuf.AbstractParser<InstanceAdmin>() {\n      @java.lang.Override\n      public InstanceAdmin parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new InstanceAdmin(input, extensionRegistry);\n      }\n    };\n\n    public static com.google.protobuf.Parser<InstanceAdmin> parser() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<InstanceAdmin> getParserForType() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin getDefaultInstanceForType() {\n      return DEFAULT_INSTANCE;\n    }\n\n  }\n\n  public interface LogAdminOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.LogAdmin)\n      com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <pre>\n     * canal/instance\n     * </pre>\n     *\n     * <code>string type = 1;</code>\n     */\n    java.lang.String getType();\n    /**\n     * <pre>\n     * canal/instance\n     * </pre>\n     *\n     * <code>string type = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getTypeBytes();\n\n    /**\n     * <code>string action = 2;</code>\n     */\n    java.lang.String getAction();\n    /**\n     * <code>string action = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getActionBytes();\n\n    /**\n     * <code>string destination = 3;</code>\n     */\n    java.lang.String getDestination();\n    /**\n     * <code>string destination = 3;</code>\n     */\n    com.google.protobuf.ByteString\n        getDestinationBytes();\n\n    /**\n     * <code>string file = 4;</code>\n     */\n    java.lang.String getFile();\n    /**\n     * <code>string file = 4;</code>\n     */\n    com.google.protobuf.ByteString\n        getFileBytes();\n\n    /**\n     * <pre>\n     * 默认tail 100行，最大不超过4MB\n     * </pre>\n     *\n     * <code>int32 count = 5;</code>\n     */\n    int getCount();\n\n    public com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin.DestinationPresentCase getDestinationPresentCase();\n\n    public com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin.FilePresentCase getFilePresentCase();\n\n    public com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin.CountPresentCase getCountPresentCase();\n  }\n  /**\n   * Protobuf type {@code com.alibaba.otter.canal.protocol.LogAdmin}\n   */\n  public  static final class LogAdmin extends\n      com.google.protobuf.GeneratedMessageV3 implements\n      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.LogAdmin)\n      LogAdminOrBuilder {\n  private static final long serialVersionUID = 0L;\n    // Use LogAdmin.newBuilder() to construct.\n    private LogAdmin(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {\n      super(builder);\n    }\n    private LogAdmin() {\n      type_ = \"\";\n      action_ = \"\";\n    }\n\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n    getUnknownFields() {\n      return this.unknownFields;\n    }\n    private LogAdmin(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      this();\n      if (extensionRegistry == null) {\n        throw new java.lang.NullPointerException();\n      }\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            case 10: {\n              java.lang.String s = input.readStringRequireUtf8();\n\n              type_ = s;\n              break;\n            }\n            case 18: {\n              java.lang.String s = input.readStringRequireUtf8();\n\n              action_ = s;\n              break;\n            }\n            case 26: {\n              java.lang.String s = input.readStringRequireUtf8();\n              destinationPresentCase_ = 3;\n              destinationPresent_ = s;\n              break;\n            }\n            case 34: {\n              java.lang.String s = input.readStringRequireUtf8();\n              filePresentCase_ = 4;\n              filePresent_ = s;\n              break;\n            }\n            case 40: {\n              countPresentCase_ = 5;\n              countPresent_ = input.readInt32();\n              break;\n            }\n            default: {\n              if (!parseUnknownFieldProto3(\n                  input, unknownFields, extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_LogAdmin_descriptor;\n    }\n\n    @java.lang.Override\n    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_LogAdmin_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin.class, com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin.Builder.class);\n    }\n\n    private int destinationPresentCase_ = 0;\n    private java.lang.Object destinationPresent_;\n    public enum DestinationPresentCase\n        implements com.google.protobuf.Internal.EnumLite {\n      DESTINATION(3),\n      DESTINATIONPRESENT_NOT_SET(0);\n      private final int value;\n      private DestinationPresentCase(int value) {\n        this.value = value;\n      }\n      /**\n       * @deprecated Use {@link #forNumber(int)} instead.\n       */\n      @java.lang.Deprecated\n      public static DestinationPresentCase valueOf(int value) {\n        return forNumber(value);\n      }\n\n      public static DestinationPresentCase forNumber(int value) {\n        switch (value) {\n          case 3: return DESTINATION;\n          case 0: return DESTINATIONPRESENT_NOT_SET;\n          default: return null;\n        }\n      }\n      public int getNumber() {\n        return this.value;\n      }\n    };\n\n    public DestinationPresentCase\n    getDestinationPresentCase() {\n      return DestinationPresentCase.forNumber(\n          destinationPresentCase_);\n    }\n\n    private int filePresentCase_ = 0;\n    private java.lang.Object filePresent_;\n    public enum FilePresentCase\n        implements com.google.protobuf.Internal.EnumLite {\n      FILE(4),\n      FILEPRESENT_NOT_SET(0);\n      private final int value;\n      private FilePresentCase(int value) {\n        this.value = value;\n      }\n      /**\n       * @deprecated Use {@link #forNumber(int)} instead.\n       */\n      @java.lang.Deprecated\n      public static FilePresentCase valueOf(int value) {\n        return forNumber(value);\n      }\n\n      public static FilePresentCase forNumber(int value) {\n        switch (value) {\n          case 4: return FILE;\n          case 0: return FILEPRESENT_NOT_SET;\n          default: return null;\n        }\n      }\n      public int getNumber() {\n        return this.value;\n      }\n    };\n\n    public FilePresentCase\n    getFilePresentCase() {\n      return FilePresentCase.forNumber(\n          filePresentCase_);\n    }\n\n    private int countPresentCase_ = 0;\n    private java.lang.Object countPresent_;\n    public enum CountPresentCase\n        implements com.google.protobuf.Internal.EnumLite {\n      COUNT(5),\n      COUNTPRESENT_NOT_SET(0);\n      private final int value;\n      private CountPresentCase(int value) {\n        this.value = value;\n      }\n      /**\n       * @deprecated Use {@link #forNumber(int)} instead.\n       */\n      @java.lang.Deprecated\n      public static CountPresentCase valueOf(int value) {\n        return forNumber(value);\n      }\n\n      public static CountPresentCase forNumber(int value) {\n        switch (value) {\n          case 5: return COUNT;\n          case 0: return COUNTPRESENT_NOT_SET;\n          default: return null;\n        }\n      }\n      public int getNumber() {\n        return this.value;\n      }\n    };\n\n    public CountPresentCase\n    getCountPresentCase() {\n      return CountPresentCase.forNumber(\n          countPresentCase_);\n    }\n\n    public static final int TYPE_FIELD_NUMBER = 1;\n    private volatile java.lang.Object type_;\n    /**\n     * <pre>\n     * canal/instance\n     * </pre>\n     *\n     * <code>string type = 1;</code>\n     */\n    public java.lang.String getType() {\n      java.lang.Object ref = type_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        type_ = s;\n        return s;\n      }\n    }\n    /**\n     * <pre>\n     * canal/instance\n     * </pre>\n     *\n     * <code>string type = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getTypeBytes() {\n      java.lang.Object ref = type_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        type_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int ACTION_FIELD_NUMBER = 2;\n    private volatile java.lang.Object action_;\n    /**\n     * <code>string action = 2;</code>\n     */\n    public java.lang.String getAction() {\n      java.lang.Object ref = action_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        action_ = s;\n        return s;\n      }\n    }\n    /**\n     * <code>string action = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getActionBytes() {\n      java.lang.Object ref = action_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        action_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int DESTINATION_FIELD_NUMBER = 3;\n    /**\n     * <code>string destination = 3;</code>\n     */\n    public java.lang.String getDestination() {\n      java.lang.Object ref = \"\";\n      if (destinationPresentCase_ == 3) {\n        ref = destinationPresent_;\n      }\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (destinationPresentCase_ == 3) {\n          destinationPresent_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>string destination = 3;</code>\n     */\n    public com.google.protobuf.ByteString\n        getDestinationBytes() {\n      java.lang.Object ref = \"\";\n      if (destinationPresentCase_ == 3) {\n        ref = destinationPresent_;\n      }\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        if (destinationPresentCase_ == 3) {\n          destinationPresent_ = b;\n        }\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int FILE_FIELD_NUMBER = 4;\n    /**\n     * <code>string file = 4;</code>\n     */\n    public java.lang.String getFile() {\n      java.lang.Object ref = \"\";\n      if (filePresentCase_ == 4) {\n        ref = filePresent_;\n      }\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (filePresentCase_ == 4) {\n          filePresent_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>string file = 4;</code>\n     */\n    public com.google.protobuf.ByteString\n        getFileBytes() {\n      java.lang.Object ref = \"\";\n      if (filePresentCase_ == 4) {\n        ref = filePresent_;\n      }\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        if (filePresentCase_ == 4) {\n          filePresent_ = b;\n        }\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int COUNT_FIELD_NUMBER = 5;\n    /**\n     * <pre>\n     * 默认tail 100行，最大不超过4MB\n     * </pre>\n     *\n     * <code>int32 count = 5;</code>\n     */\n    public int getCount() {\n      if (countPresentCase_ == 5) {\n        return (java.lang.Integer) countPresent_;\n      }\n      return 0;\n    }\n\n    private byte memoizedIsInitialized = -1;\n    @java.lang.Override\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    @java.lang.Override\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      if (!getTypeBytes().isEmpty()) {\n        com.google.protobuf.GeneratedMessageV3.writeString(output, 1, type_);\n      }\n      if (!getActionBytes().isEmpty()) {\n        com.google.protobuf.GeneratedMessageV3.writeString(output, 2, action_);\n      }\n      if (destinationPresentCase_ == 3) {\n        com.google.protobuf.GeneratedMessageV3.writeString(output, 3, destinationPresent_);\n      }\n      if (filePresentCase_ == 4) {\n        com.google.protobuf.GeneratedMessageV3.writeString(output, 4, filePresent_);\n      }\n      if (countPresentCase_ == 5) {\n        output.writeInt32(\n            5, (int)((java.lang.Integer) countPresent_));\n      }\n      unknownFields.writeTo(output);\n    }\n\n    @java.lang.Override\n    public int getSerializedSize() {\n      int size = memoizedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (!getTypeBytes().isEmpty()) {\n        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, type_);\n      }\n      if (!getActionBytes().isEmpty()) {\n        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, action_);\n      }\n      if (destinationPresentCase_ == 3) {\n        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, destinationPresent_);\n      }\n      if (filePresentCase_ == 4) {\n        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(4, filePresent_);\n      }\n      if (countPresentCase_ == 5) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(\n              5, (int)((java.lang.Integer) countPresent_));\n      }\n      size += unknownFields.getSerializedSize();\n      memoizedSize = size;\n      return size;\n    }\n\n    @java.lang.Override\n    public boolean equals(final java.lang.Object obj) {\n      if (obj == this) {\n       return true;\n      }\n      if (!(obj instanceof com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin)) {\n        return super.equals(obj);\n      }\n      com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin other = (com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin) obj;\n\n      boolean result = true;\n      result = result && getType()\n          .equals(other.getType());\n      result = result && getAction()\n          .equals(other.getAction());\n      result = result && getDestinationPresentCase().equals(\n          other.getDestinationPresentCase());\n      if (!result) return false;\n      switch (destinationPresentCase_) {\n        case 3:\n          result = result && getDestination()\n              .equals(other.getDestination());\n          break;\n        case 0:\n        default:\n      }\n      result = result && getFilePresentCase().equals(\n          other.getFilePresentCase());\n      if (!result) return false;\n      switch (filePresentCase_) {\n        case 4:\n          result = result && getFile()\n              .equals(other.getFile());\n          break;\n        case 0:\n        default:\n      }\n      result = result && getCountPresentCase().equals(\n          other.getCountPresentCase());\n      if (!result) return false;\n      switch (countPresentCase_) {\n        case 5:\n          result = result && (getCount()\n              == other.getCount());\n          break;\n        case 0:\n        default:\n      }\n      result = result && unknownFields.equals(other.unknownFields);\n      return result;\n    }\n\n    @java.lang.Override\n    public int hashCode() {\n      if (memoizedHashCode != 0) {\n        return memoizedHashCode;\n      }\n      int hash = 41;\n      hash = (19 * hash) + getDescriptor().hashCode();\n      hash = (37 * hash) + TYPE_FIELD_NUMBER;\n      hash = (53 * hash) + getType().hashCode();\n      hash = (37 * hash) + ACTION_FIELD_NUMBER;\n      hash = (53 * hash) + getAction().hashCode();\n      switch (destinationPresentCase_) {\n        case 3:\n          hash = (37 * hash) + DESTINATION_FIELD_NUMBER;\n          hash = (53 * hash) + getDestination().hashCode();\n          break;\n        case 0:\n        default:\n      }\n      switch (filePresentCase_) {\n        case 4:\n          hash = (37 * hash) + FILE_FIELD_NUMBER;\n          hash = (53 * hash) + getFile().hashCode();\n          break;\n        case 0:\n        default:\n      }\n      switch (countPresentCase_) {\n        case 5:\n          hash = (37 * hash) + COUNT_FIELD_NUMBER;\n          hash = (53 * hash) + getCount();\n          break;\n        case 0:\n        default:\n      }\n      hash = (29 * hash) + unknownFields.hashCode();\n      memoizedHashCode = hash;\n      return hash;\n    }\n\n    public static com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin parseFrom(\n        java.nio.ByteBuffer data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin parseFrom(\n        java.nio.ByteBuffer data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    @java.lang.Override\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder() {\n      return DEFAULT_INSTANCE.toBuilder();\n    }\n    public static Builder newBuilder(com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin prototype) {\n      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n    }\n    @java.lang.Override\n    public Builder toBuilder() {\n      return this == DEFAULT_INSTANCE\n          ? new Builder() : new Builder().mergeFrom(this);\n    }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code com.alibaba.otter.canal.protocol.LogAdmin}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.LogAdmin)\n        com.alibaba.otter.canal.protocol.AdminPacket.LogAdminOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_LogAdmin_descriptor;\n      }\n\n      @java.lang.Override\n      protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_LogAdmin_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin.class, com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin.Builder.class);\n      }\n\n      // Construct using com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessageV3\n                .alwaysUseFieldBuilders) {\n        }\n      }\n      @java.lang.Override\n      public Builder clear() {\n        super.clear();\n        type_ = \"\";\n\n        action_ = \"\";\n\n        destinationPresentCase_ = 0;\n        destinationPresent_ = null;\n        filePresentCase_ = 0;\n        filePresent_ = null;\n        countPresentCase_ = 0;\n        countPresent_ = null;\n        return this;\n      }\n\n      @java.lang.Override\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_LogAdmin_descriptor;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin getDefaultInstanceForType() {\n        return com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin.getDefaultInstance();\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin build() {\n        com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin buildPartial() {\n        com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin result = new com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin(this);\n        result.type_ = type_;\n        result.action_ = action_;\n        if (destinationPresentCase_ == 3) {\n          result.destinationPresent_ = destinationPresent_;\n        }\n        if (filePresentCase_ == 4) {\n          result.filePresent_ = filePresent_;\n        }\n        if (countPresentCase_ == 5) {\n          result.countPresent_ = countPresent_;\n        }\n        result.destinationPresentCase_ = destinationPresentCase_;\n        result.filePresentCase_ = filePresentCase_;\n        result.countPresentCase_ = countPresentCase_;\n        onBuilt();\n        return result;\n      }\n\n      @java.lang.Override\n      public Builder clone() {\n        return (Builder) super.clone();\n      }\n      @java.lang.Override\n      public Builder setField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.setField(field, value);\n      }\n      @java.lang.Override\n      public Builder clearField(\n          com.google.protobuf.Descriptors.FieldDescriptor field) {\n        return (Builder) super.clearField(field);\n      }\n      @java.lang.Override\n      public Builder clearOneof(\n          com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n        return (Builder) super.clearOneof(oneof);\n      }\n      @java.lang.Override\n      public Builder setRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          int index, java.lang.Object value) {\n        return (Builder) super.setRepeatedField(field, index, value);\n      }\n      @java.lang.Override\n      public Builder addRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.addRepeatedField(field, value);\n      }\n      @java.lang.Override\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin) {\n          return mergeFrom((com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin other) {\n        if (other == com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin.getDefaultInstance()) return this;\n        if (!other.getType().isEmpty()) {\n          type_ = other.type_;\n          onChanged();\n        }\n        if (!other.getAction().isEmpty()) {\n          action_ = other.action_;\n          onChanged();\n        }\n        switch (other.getDestinationPresentCase()) {\n          case DESTINATION: {\n            destinationPresentCase_ = 3;\n            destinationPresent_ = other.destinationPresent_;\n            onChanged();\n            break;\n          }\n          case DESTINATIONPRESENT_NOT_SET: {\n            break;\n          }\n        }\n        switch (other.getFilePresentCase()) {\n          case FILE: {\n            filePresentCase_ = 4;\n            filePresent_ = other.filePresent_;\n            onChanged();\n            break;\n          }\n          case FILEPRESENT_NOT_SET: {\n            break;\n          }\n        }\n        switch (other.getCountPresentCase()) {\n          case COUNT: {\n            setCount(other.getCount());\n            break;\n          }\n          case COUNTPRESENT_NOT_SET: {\n            break;\n          }\n        }\n        this.mergeUnknownFields(other.unknownFields);\n        onChanged();\n        return this;\n      }\n\n      @java.lang.Override\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      @java.lang.Override\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin) e.getUnfinishedMessage();\n          throw e.unwrapIOException();\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int destinationPresentCase_ = 0;\n      private java.lang.Object destinationPresent_;\n      public DestinationPresentCase\n          getDestinationPresentCase() {\n        return DestinationPresentCase.forNumber(\n            destinationPresentCase_);\n      }\n\n      public Builder clearDestinationPresent() {\n        destinationPresentCase_ = 0;\n        destinationPresent_ = null;\n        onChanged();\n        return this;\n      }\n\n      private int filePresentCase_ = 0;\n      private java.lang.Object filePresent_;\n      public FilePresentCase\n          getFilePresentCase() {\n        return FilePresentCase.forNumber(\n            filePresentCase_);\n      }\n\n      public Builder clearFilePresent() {\n        filePresentCase_ = 0;\n        filePresent_ = null;\n        onChanged();\n        return this;\n      }\n\n      private int countPresentCase_ = 0;\n      private java.lang.Object countPresent_;\n      public CountPresentCase\n          getCountPresentCase() {\n        return CountPresentCase.forNumber(\n            countPresentCase_);\n      }\n\n      public Builder clearCountPresent() {\n        countPresentCase_ = 0;\n        countPresent_ = null;\n        onChanged();\n        return this;\n      }\n\n\n      private java.lang.Object type_ = \"\";\n      /**\n       * <pre>\n       * canal/instance\n       * </pre>\n       *\n       * <code>string type = 1;</code>\n       */\n      public java.lang.String getType() {\n        java.lang.Object ref = type_;\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          type_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <pre>\n       * canal/instance\n       * </pre>\n       *\n       * <code>string type = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getTypeBytes() {\n        java.lang.Object ref = type_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          type_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <pre>\n       * canal/instance\n       * </pre>\n       *\n       * <code>string type = 1;</code>\n       */\n      public Builder setType(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        type_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <pre>\n       * canal/instance\n       * </pre>\n       *\n       * <code>string type = 1;</code>\n       */\n      public Builder clearType() {\n        \n        type_ = getDefaultInstance().getType();\n        onChanged();\n        return this;\n      }\n      /**\n       * <pre>\n       * canal/instance\n       * </pre>\n       *\n       * <code>string type = 1;</code>\n       */\n      public Builder setTypeBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  checkByteStringIsUtf8(value);\n        \n        type_ = value;\n        onChanged();\n        return this;\n      }\n\n      private java.lang.Object action_ = \"\";\n      /**\n       * <code>string action = 2;</code>\n       */\n      public java.lang.String getAction() {\n        java.lang.Object ref = action_;\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          action_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>string action = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getActionBytes() {\n        java.lang.Object ref = action_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          action_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>string action = 2;</code>\n       */\n      public Builder setAction(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        action_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string action = 2;</code>\n       */\n      public Builder clearAction() {\n        \n        action_ = getDefaultInstance().getAction();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string action = 2;</code>\n       */\n      public Builder setActionBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  checkByteStringIsUtf8(value);\n        \n        action_ = value;\n        onChanged();\n        return this;\n      }\n\n      /**\n       * <code>string destination = 3;</code>\n       */\n      public java.lang.String getDestination() {\n        java.lang.Object ref = \"\";\n        if (destinationPresentCase_ == 3) {\n          ref = destinationPresent_;\n        }\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          if (destinationPresentCase_ == 3) {\n            destinationPresent_ = s;\n          }\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>string destination = 3;</code>\n       */\n      public com.google.protobuf.ByteString\n          getDestinationBytes() {\n        java.lang.Object ref = \"\";\n        if (destinationPresentCase_ == 3) {\n          ref = destinationPresent_;\n        }\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          if (destinationPresentCase_ == 3) {\n            destinationPresent_ = b;\n          }\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>string destination = 3;</code>\n       */\n      public Builder setDestination(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  destinationPresentCase_ = 3;\n        destinationPresent_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string destination = 3;</code>\n       */\n      public Builder clearDestination() {\n        if (destinationPresentCase_ == 3) {\n          destinationPresentCase_ = 0;\n          destinationPresent_ = null;\n          onChanged();\n        }\n        return this;\n      }\n      /**\n       * <code>string destination = 3;</code>\n       */\n      public Builder setDestinationBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  checkByteStringIsUtf8(value);\n        destinationPresentCase_ = 3;\n        destinationPresent_ = value;\n        onChanged();\n        return this;\n      }\n\n      /**\n       * <code>string file = 4;</code>\n       */\n      public java.lang.String getFile() {\n        java.lang.Object ref = \"\";\n        if (filePresentCase_ == 4) {\n          ref = filePresent_;\n        }\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          if (filePresentCase_ == 4) {\n            filePresent_ = s;\n          }\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>string file = 4;</code>\n       */\n      public com.google.protobuf.ByteString\n          getFileBytes() {\n        java.lang.Object ref = \"\";\n        if (filePresentCase_ == 4) {\n          ref = filePresent_;\n        }\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          if (filePresentCase_ == 4) {\n            filePresent_ = b;\n          }\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>string file = 4;</code>\n       */\n      public Builder setFile(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  filePresentCase_ = 4;\n        filePresent_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string file = 4;</code>\n       */\n      public Builder clearFile() {\n        if (filePresentCase_ == 4) {\n          filePresentCase_ = 0;\n          filePresent_ = null;\n          onChanged();\n        }\n        return this;\n      }\n      /**\n       * <code>string file = 4;</code>\n       */\n      public Builder setFileBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  checkByteStringIsUtf8(value);\n        filePresentCase_ = 4;\n        filePresent_ = value;\n        onChanged();\n        return this;\n      }\n\n      /**\n       * <pre>\n       * 默认tail 100行，最大不超过4MB\n       * </pre>\n       *\n       * <code>int32 count = 5;</code>\n       */\n      public int getCount() {\n        if (countPresentCase_ == 5) {\n          return (java.lang.Integer) countPresent_;\n        }\n        return 0;\n      }\n      /**\n       * <pre>\n       * 默认tail 100行，最大不超过4MB\n       * </pre>\n       *\n       * <code>int32 count = 5;</code>\n       */\n      public Builder setCount(int value) {\n        countPresentCase_ = 5;\n        countPresent_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <pre>\n       * 默认tail 100行，最大不超过4MB\n       * </pre>\n       *\n       * <code>int32 count = 5;</code>\n       */\n      public Builder clearCount() {\n        if (countPresentCase_ == 5) {\n          countPresentCase_ = 0;\n          countPresent_ = null;\n          onChanged();\n        }\n        return this;\n      }\n      @java.lang.Override\n      public final Builder setUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.setUnknownFieldsProto3(unknownFields);\n      }\n\n      @java.lang.Override\n      public final Builder mergeUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.mergeUnknownFields(unknownFields);\n      }\n\n\n      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.LogAdmin)\n    }\n\n    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.LogAdmin)\n    private static final com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin DEFAULT_INSTANCE;\n    static {\n      DEFAULT_INSTANCE = new com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin();\n    }\n\n    public static com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin getDefaultInstance() {\n      return DEFAULT_INSTANCE;\n    }\n\n    private static final com.google.protobuf.Parser<LogAdmin>\n        PARSER = new com.google.protobuf.AbstractParser<LogAdmin>() {\n      @java.lang.Override\n      public LogAdmin parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new LogAdmin(input, extensionRegistry);\n      }\n    };\n\n    public static com.google.protobuf.Parser<LogAdmin> parser() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<LogAdmin> getParserForType() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin getDefaultInstanceForType() {\n      return DEFAULT_INSTANCE;\n    }\n\n  }\n\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_com_alibaba_otter_canal_protocol_Packet_descriptor;\n  private static final \n    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n      internal_static_com_alibaba_otter_canal_protocol_Packet_fieldAccessorTable;\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_com_alibaba_otter_canal_protocol_Ack_descriptor;\n  private static final \n    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n      internal_static_com_alibaba_otter_canal_protocol_Ack_fieldAccessorTable;\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_com_alibaba_otter_canal_protocol_Handshake_descriptor;\n  private static final \n    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n      internal_static_com_alibaba_otter_canal_protocol_Handshake_fieldAccessorTable;\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_com_alibaba_otter_canal_protocol_ClientAuth_descriptor;\n  private static final \n    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n      internal_static_com_alibaba_otter_canal_protocol_ClientAuth_fieldAccessorTable;\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_com_alibaba_otter_canal_protocol_ServerAdmin_descriptor;\n  private static final \n    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n      internal_static_com_alibaba_otter_canal_protocol_ServerAdmin_fieldAccessorTable;\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_com_alibaba_otter_canal_protocol_InstanceAdmin_descriptor;\n  private static final \n    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n      internal_static_com_alibaba_otter_canal_protocol_InstanceAdmin_fieldAccessorTable;\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_com_alibaba_otter_canal_protocol_LogAdmin_descriptor;\n  private static final \n    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n      internal_static_com_alibaba_otter_canal_protocol_LogAdmin_fieldAccessorTable;\n\n  public static com.google.protobuf.Descriptors.FileDescriptor\n      getDescriptor() {\n    return descriptor;\n  }\n  private static  com.google.protobuf.Descriptors.FileDescriptor\n      descriptor;\n  static {\n    java.lang.String[] descriptorData = {\n      \"\\n\\023AdminProtocol.proto\\022 com.alibaba.otter\" +\n      \".canal.protocol\\\"\\250\\001\\n\\006Packet\\022\\026\\n\\014magic_numb\" +\n      \"er\\030\\001 \\001(\\005H\\000\\022\\021\\n\\007version\\030\\002 \\001(\\005H\\001\\022:\\n\\004type\\030\\003 \" +\n      \"\\001(\\0162,.com.alibaba.otter.canal.protocol.P\" +\n      \"acketType\\022\\014\\n\\004body\\030\\004 \\001(\\014B\\026\\n\\024magic_number_\" +\n      \"presentB\\021\\n\\017version_present\\\"<\\n\\003Ack\\022\\016\\n\\004cod\" +\n      \"e\\030\\001 \\001(\\005H\\000\\022\\017\\n\\007message\\030\\002 \\001(\\tB\\024\\n\\022error_code\" +\n      \"_present\\\"^\\n\\tHandshake\\022 \\n\\026communication_e\" +\n      \"ncoding\\030\\001 \\001(\\tH\\000\\022\\r\\n\\005seeds\\030\\002 \\001(\\014B \\n\\036commun\" +\n      \"ication_encoding_present\\\"\\242\\001\\n\\nClientAuth\\022\" +\n      \"\\020\\n\\010username\\030\\001 \\001(\\t\\022\\020\\n\\010password\\030\\002 \\001(\\014\\022\\032\\n\\020n\" +\n      \"et_read_timeout\\030\\003 \\001(\\005H\\000\\022\\033\\n\\021net_write_tim\" +\n      \"eout\\030\\004 \\001(\\005H\\001B\\032\\n\\030net_read_timeout_present\" +\n      \"B\\033\\n\\031net_write_timeout_present\\\"\\035\\n\\013ServerA\" +\n      \"dmin\\022\\016\\n\\006action\\030\\001 \\001(\\t\\\"4\\n\\rInstanceAdmin\\022\\023\\n\" +\n      \"\\013destination\\030\\001 \\001(\\t\\022\\016\\n\\006action\\030\\002 \\001(\\t\\\"\\230\\001\\n\\010L\" +\n      \"ogAdmin\\022\\014\\n\\004type\\030\\001 \\001(\\t\\022\\016\\n\\006action\\030\\002 \\001(\\t\\022\\025\\n\" +\n      \"\\013destination\\030\\003 \\001(\\tH\\000\\022\\016\\n\\004file\\030\\004 \\001(\\tH\\001\\022\\017\\n\\005\" +\n      \"count\\030\\005 \\001(\\005H\\002B\\025\\n\\023destination_presentB\\016\\n\\014\" +\n      \"file_presentB\\017\\n\\rcount_present*\\202\\001\\n\\nPacket\" +\n      \"Type\\022\\037\\n\\033PACKAGETYPECOMPATIBLEPROTO2\\020\\000\\022\\r\\n\" +\n      \"\\tHANDSHAKE\\020\\001\\022\\030\\n\\024CLIENTAUTHENTICATION\\020\\002\\022\\007\" +\n      \"\\n\\003ACK\\020\\003\\022\\n\\n\\006SERVER\\020\\004\\022\\014\\n\\010INSTANCE\\020\\005\\022\\007\\n\\003LOG\" +\n      \"\\020\\006B1\\n com.alibaba.otter.canal.protocolB\\013\" +\n      \"AdminPacketH\\001b\\006proto3\"\n    };\n    com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =\n        new com.google.protobuf.Descriptors.FileDescriptor.    InternalDescriptorAssigner() {\n          public com.google.protobuf.ExtensionRegistry assignDescriptors(\n              com.google.protobuf.Descriptors.FileDescriptor root) {\n            descriptor = root;\n            return null;\n          }\n        };\n    com.google.protobuf.Descriptors.FileDescriptor\n      .internalBuildGeneratedFileFrom(descriptorData,\n        new com.google.protobuf.Descriptors.FileDescriptor[] {\n        }, assigner);\n    internal_static_com_alibaba_otter_canal_protocol_Packet_descriptor =\n      getDescriptor().getMessageTypes().get(0);\n    internal_static_com_alibaba_otter_canal_protocol_Packet_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n        internal_static_com_alibaba_otter_canal_protocol_Packet_descriptor,\n        new java.lang.String[] { \"MagicNumber\", \"Version\", \"Type\", \"Body\", \"MagicNumberPresent\", \"VersionPresent\", });\n    internal_static_com_alibaba_otter_canal_protocol_Ack_descriptor =\n      getDescriptor().getMessageTypes().get(1);\n    internal_static_com_alibaba_otter_canal_protocol_Ack_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n        internal_static_com_alibaba_otter_canal_protocol_Ack_descriptor,\n        new java.lang.String[] { \"Code\", \"Message\", \"ErrorCodePresent\", });\n    internal_static_com_alibaba_otter_canal_protocol_Handshake_descriptor =\n      getDescriptor().getMessageTypes().get(2);\n    internal_static_com_alibaba_otter_canal_protocol_Handshake_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n        internal_static_com_alibaba_otter_canal_protocol_Handshake_descriptor,\n        new java.lang.String[] { \"CommunicationEncoding\", \"Seeds\", \"CommunicationEncodingPresent\", });\n    internal_static_com_alibaba_otter_canal_protocol_ClientAuth_descriptor =\n      getDescriptor().getMessageTypes().get(3);\n    internal_static_com_alibaba_otter_canal_protocol_ClientAuth_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n        internal_static_com_alibaba_otter_canal_protocol_ClientAuth_descriptor,\n        new java.lang.String[] { \"Username\", \"Password\", \"NetReadTimeout\", \"NetWriteTimeout\", \"NetReadTimeoutPresent\", \"NetWriteTimeoutPresent\", });\n    internal_static_com_alibaba_otter_canal_protocol_ServerAdmin_descriptor =\n      getDescriptor().getMessageTypes().get(4);\n    internal_static_com_alibaba_otter_canal_protocol_ServerAdmin_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n        internal_static_com_alibaba_otter_canal_protocol_ServerAdmin_descriptor,\n        new java.lang.String[] { \"Action\", });\n    internal_static_com_alibaba_otter_canal_protocol_InstanceAdmin_descriptor =\n      getDescriptor().getMessageTypes().get(5);\n    internal_static_com_alibaba_otter_canal_protocol_InstanceAdmin_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n        internal_static_com_alibaba_otter_canal_protocol_InstanceAdmin_descriptor,\n        new java.lang.String[] { \"Destination\", \"Action\", });\n    internal_static_com_alibaba_otter_canal_protocol_LogAdmin_descriptor =\n      getDescriptor().getMessageTypes().get(6);\n    internal_static_com_alibaba_otter_canal_protocol_LogAdmin_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n        internal_static_com_alibaba_otter_canal_protocol_LogAdmin_descriptor,\n        new java.lang.String[] { \"Type\", \"Action\", \"Destination\", \"File\", \"Count\", \"DestinationPresent\", \"FilePresent\", \"CountPresent\", });\n  }\n\n  // @@protoc_insertion_point(outer_class_scope)\n}\n"
  },
  {
    "path": "protocol/src/main/java/com/alibaba/otter/canal/protocol/AdminProtocol.proto",
    "content": "syntax = \"proto3\";\npackage com.alibaba.otter.canal.protocol;\n\noption java_package = \"com.alibaba.otter.canal.protocol\";\noption java_outer_classname = \"AdminPacket\";\noption optimize_for = SPEED;\n\nenum PacketType {\n    //compatible\n    PACKAGETYPECOMPATIBLEPROTO2 = 0;\n    HANDSHAKE = 1;\n    CLIENTAUTHENTICATION = 2;\n    ACK = 3;\n    SERVER = 4;\n    INSTANCE = 5;\n    LOG = 6;\n}\n\nmessage Packet {\n     //[default = 17];\n     oneof magic_number_present {\n         int32 magic_number = 1;\n     }\n     // [default = 1]\n     oneof version_present {\n          int32 version = 2;\n     };\n     PacketType type = 3;\n     bytes body = 4;\n}\n\nmessage Ack {\n    // [default = 0]\n    oneof error_code_present {\n        int32 code = 1;\n    }\n    string message = 2; // if something like compression is not supported, erorr_message will tell about it.\n}\n\nmessage Handshake {\n    //  [default = \"utf8\"];\n    oneof communication_encoding_present {\n        string communication_encoding = 1;\n    }\n    bytes seeds = 2;\n}\n\n// client authentication\nmessage ClientAuth {\n    string username = 1;\n    bytes password = 2; // hashed password with seeds from Handshake message\n    // [default = 0]\n    oneof net_read_timeout_present {\n         int32 net_read_timeout = 3; // in seconds\n    }\n    // [default = 0];\n    oneof net_write_timeout_present {\n        int32 net_write_timeout = 4; // in seconds\n    }\n}\n\nmessage ServerAdmin {\n    string action = 1; // check/start/stop/restart/list\n}\n\nmessage InstanceAdmin {\n    string destination = 1;\n    string action = 2; // check/start/stop/reload\n}\n\nmessage LogAdmin {\n\tstring type = 1; // canal/instance\n\tstring action = 2;\n\toneof destination_present {\n\t\tstring destination = 3;\n\t}\n\toneof file_present {\n\t\tstring file = 4;\n\t}\n\toneof count_present {\n\t\tint32 count = 5; // 默认tail 100行，最大不超过4MB\n\t}\n}"
  },
  {
    "path": "protocol/src/main/java/com/alibaba/otter/canal/protocol/CanalEntry.java",
    "content": "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n// source: EntryProtocol.proto\n\npackage com.alibaba.otter.canal.protocol;\n\npublic final class CanalEntry {\n  private CanalEntry() {}\n  public static void registerAllExtensions(\n      com.google.protobuf.ExtensionRegistry registry) {\n  }\n  /**\n   * Protobuf enum {@code com.alibaba.otter.canal.protocol.EntryType}\n   *\n   * <pre>\n   **打散后的事件类型，主要用于标识事务的开始，变更数据，结束*\n   * </pre>\n   */\n  public enum EntryType\n      implements com.google.protobuf.ProtocolMessageEnum {\n    /**\n     * <code>TRANSACTIONBEGIN = 1;</code>\n     */\n    TRANSACTIONBEGIN(0, 1),\n    /**\n     * <code>ROWDATA = 2;</code>\n     */\n    ROWDATA(1, 2),\n    /**\n     * <code>TRANSACTIONEND = 3;</code>\n     */\n    TRANSACTIONEND(2, 3),\n    /**\n     * <code>HEARTBEAT = 4;</code>\n     *\n     * <pre>\n     ** 心跳类型，内部使用，外部暂不可见，可忽略 *\n     * </pre>\n     */\n    HEARTBEAT(3, 4),\n    /**\n     * <code>GTIDLOG = 5;</code>\n     */\n    GTIDLOG(4, 5),\n    ;\n\n    /**\n     * <code>TRANSACTIONBEGIN = 1;</code>\n     */\n    public static final int TRANSACTIONBEGIN_VALUE = 1;\n    /**\n     * <code>ROWDATA = 2;</code>\n     */\n    public static final int ROWDATA_VALUE = 2;\n    /**\n     * <code>TRANSACTIONEND = 3;</code>\n     */\n    public static final int TRANSACTIONEND_VALUE = 3;\n    /**\n     * <code>HEARTBEAT = 4;</code>\n     *\n     * <pre>\n     ** 心跳类型，内部使用，外部暂不可见，可忽略 *\n     * </pre>\n     */\n    public static final int HEARTBEAT_VALUE = 4;\n    /**\n     * <code>GTIDLOG = 5;</code>\n     */\n    public static final int GTIDLOG_VALUE = 5;\n\n\n    public final int getNumber() { return value; }\n\n    public static EntryType valueOf(int value) {\n      switch (value) {\n        case 1: return TRANSACTIONBEGIN;\n        case 2: return ROWDATA;\n        case 3: return TRANSACTIONEND;\n        case 4: return HEARTBEAT;\n        case 5: return GTIDLOG;\n        default: return null;\n      }\n    }\n\n    public static com.google.protobuf.Internal.EnumLiteMap<EntryType>\n        internalGetValueMap() {\n      return internalValueMap;\n    }\n    private static com.google.protobuf.Internal.EnumLiteMap<EntryType>\n        internalValueMap =\n          new com.google.protobuf.Internal.EnumLiteMap<EntryType>() {\n            public EntryType findValueByNumber(int number) {\n              return EntryType.valueOf(number);\n            }\n          };\n\n    public final com.google.protobuf.Descriptors.EnumValueDescriptor\n        getValueDescriptor() {\n      return getDescriptor().getValues().get(index);\n    }\n    public final com.google.protobuf.Descriptors.EnumDescriptor\n        getDescriptorForType() {\n      return getDescriptor();\n    }\n    public static final com.google.protobuf.Descriptors.EnumDescriptor\n        getDescriptor() {\n      return CanalEntry.getDescriptor().getEnumTypes().get(0);\n    }\n\n    private static final EntryType[] VALUES = values();\n\n    public static EntryType valueOf(\n        com.google.protobuf.Descriptors.EnumValueDescriptor desc) {\n      if (desc.getType() != getDescriptor()) {\n        throw new IllegalArgumentException(\n          \"EnumValueDescriptor is not for this type.\");\n      }\n      return VALUES[desc.getIndex()];\n    }\n\n    private final int index;\n    private final int value;\n\n    private EntryType(int index, int value) {\n      this.index = index;\n      this.value = value;\n    }\n\n    // @@protoc_insertion_point(enum_scope:com.alibaba.otter.canal.protocol.EntryType)\n  }\n\n  /**\n   * Protobuf enum {@code com.alibaba.otter.canal.protocol.EventType}\n   *\n   * <pre>\n   ** 事件类型 *\n   * </pre>\n   */\n  public enum EventType\n      implements com.google.protobuf.ProtocolMessageEnum {\n    /**\n     * <code>INSERT = 1;</code>\n     */\n    INSERT(0, 1),\n    /**\n     * <code>UPDATE = 2;</code>\n     */\n    UPDATE(1, 2),\n    /**\n     * <code>DELETE = 3;</code>\n     */\n    DELETE(2, 3),\n    /**\n     * <code>CREATE = 4;</code>\n     */\n    CREATE(3, 4),\n    /**\n     * <code>ALTER = 5;</code>\n     */\n    ALTER(4, 5),\n    /**\n     * <code>ERASE = 6;</code>\n     */\n    ERASE(5, 6),\n    /**\n     * <code>QUERY = 7;</code>\n     */\n    QUERY(6, 7),\n    /**\n     * <code>TRUNCATE = 8;</code>\n     */\n    TRUNCATE(7, 8),\n    /**\n     * <code>RENAME = 9;</code>\n     */\n    RENAME(8, 9),\n    /**\n     * <code>CINDEX = 10;</code>\n     *\n     * <pre>\n     **CREATE INDEX*\n     * </pre>\n     */\n    CINDEX(9, 10),\n    /**\n     * <code>DINDEX = 11;</code>\n     */\n    DINDEX(10, 11),\n    /**\n     * <code>GTID = 12;</code>\n     */\n    GTID(11, 12),\n    /**\n     * <code>XACOMMIT = 13;</code>\n     *\n     * <pre>\n     ** XA *\n     * </pre>\n     */\n    XACOMMIT(12, 13),\n    /**\n     * <code>XAROLLBACK = 14;</code>\n     */\n    XAROLLBACK(13, 14),\n    /**\n     * <code>MHEARTBEAT = 15;</code>\n     *\n     * <pre>\n     ** MASTER HEARTBEAT *\n     * </pre>\n     */\n    MHEARTBEAT(14, 15),\n    ;\n\n    /**\n     * <code>INSERT = 1;</code>\n     */\n    public static final int INSERT_VALUE = 1;\n    /**\n     * <code>UPDATE = 2;</code>\n     */\n    public static final int UPDATE_VALUE = 2;\n    /**\n     * <code>DELETE = 3;</code>\n     */\n    public static final int DELETE_VALUE = 3;\n    /**\n     * <code>CREATE = 4;</code>\n     */\n    public static final int CREATE_VALUE = 4;\n    /**\n     * <code>ALTER = 5;</code>\n     */\n    public static final int ALTER_VALUE = 5;\n    /**\n     * <code>ERASE = 6;</code>\n     */\n    public static final int ERASE_VALUE = 6;\n    /**\n     * <code>QUERY = 7;</code>\n     */\n    public static final int QUERY_VALUE = 7;\n    /**\n     * <code>TRUNCATE = 8;</code>\n     */\n    public static final int TRUNCATE_VALUE = 8;\n    /**\n     * <code>RENAME = 9;</code>\n     */\n    public static final int RENAME_VALUE = 9;\n    /**\n     * <code>CINDEX = 10;</code>\n     *\n     * <pre>\n     **CREATE INDEX*\n     * </pre>\n     */\n    public static final int CINDEX_VALUE = 10;\n    /**\n     * <code>DINDEX = 11;</code>\n     */\n    public static final int DINDEX_VALUE = 11;\n    /**\n     * <code>GTID = 12;</code>\n     */\n    public static final int GTID_VALUE = 12;\n    /**\n     * <code>XACOMMIT = 13;</code>\n     *\n     * <pre>\n     ** XA *\n     * </pre>\n     */\n    public static final int XACOMMIT_VALUE = 13;\n    /**\n     * <code>XAROLLBACK = 14;</code>\n     */\n    public static final int XAROLLBACK_VALUE = 14;\n    /**\n     * <code>MHEARTBEAT = 15;</code>\n     *\n     * <pre>\n     ** MASTER HEARTBEAT *\n     * </pre>\n     */\n    public static final int MHEARTBEAT_VALUE = 15;\n\n\n    public final int getNumber() { return value; }\n\n    public static EventType valueOf(int value) {\n      switch (value) {\n        case 1: return INSERT;\n        case 2: return UPDATE;\n        case 3: return DELETE;\n        case 4: return CREATE;\n        case 5: return ALTER;\n        case 6: return ERASE;\n        case 7: return QUERY;\n        case 8: return TRUNCATE;\n        case 9: return RENAME;\n        case 10: return CINDEX;\n        case 11: return DINDEX;\n        case 12: return GTID;\n        case 13: return XACOMMIT;\n        case 14: return XAROLLBACK;\n        case 15: return MHEARTBEAT;\n        default: return null;\n      }\n    }\n\n    public static com.google.protobuf.Internal.EnumLiteMap<EventType>\n        internalGetValueMap() {\n      return internalValueMap;\n    }\n    private static com.google.protobuf.Internal.EnumLiteMap<EventType>\n        internalValueMap =\n          new com.google.protobuf.Internal.EnumLiteMap<EventType>() {\n            public EventType findValueByNumber(int number) {\n              return EventType.valueOf(number);\n            }\n          };\n\n    public final com.google.protobuf.Descriptors.EnumValueDescriptor\n        getValueDescriptor() {\n      return getDescriptor().getValues().get(index);\n    }\n    public final com.google.protobuf.Descriptors.EnumDescriptor\n        getDescriptorForType() {\n      return getDescriptor();\n    }\n    public static final com.google.protobuf.Descriptors.EnumDescriptor\n        getDescriptor() {\n      return CanalEntry.getDescriptor().getEnumTypes().get(1);\n    }\n\n    private static final EventType[] VALUES = values();\n\n    public static EventType valueOf(\n        com.google.protobuf.Descriptors.EnumValueDescriptor desc) {\n      if (desc.getType() != getDescriptor()) {\n        throw new IllegalArgumentException(\n          \"EnumValueDescriptor is not for this type.\");\n      }\n      return VALUES[desc.getIndex()];\n    }\n\n    private final int index;\n    private final int value;\n\n    private EventType(int index, int value) {\n      this.index = index;\n      this.value = value;\n    }\n\n    // @@protoc_insertion_point(enum_scope:com.alibaba.otter.canal.protocol.EventType)\n  }\n\n  /**\n   * Protobuf enum {@code com.alibaba.otter.canal.protocol.Type}\n   *\n   * <pre>\n   **数据库类型*\n   * </pre>\n   */\n  public enum Type\n      implements com.google.protobuf.ProtocolMessageEnum {\n    /**\n     * <code>ORACLE = 1;</code>\n     */\n    ORACLE(0, 1),\n    /**\n     * <code>MYSQL = 2;</code>\n     */\n    MYSQL(1, 2),\n    /**\n     * <code>PGSQL = 3;</code>\n     */\n    PGSQL(2, 3),\n    ;\n\n    /**\n     * <code>ORACLE = 1;</code>\n     */\n    public static final int ORACLE_VALUE = 1;\n    /**\n     * <code>MYSQL = 2;</code>\n     */\n    public static final int MYSQL_VALUE = 2;\n    /**\n     * <code>PGSQL = 3;</code>\n     */\n    public static final int PGSQL_VALUE = 3;\n\n\n    public final int getNumber() { return value; }\n\n    public static Type valueOf(int value) {\n      switch (value) {\n        case 1: return ORACLE;\n        case 2: return MYSQL;\n        case 3: return PGSQL;\n        default: return null;\n      }\n    }\n\n    public static com.google.protobuf.Internal.EnumLiteMap<Type>\n        internalGetValueMap() {\n      return internalValueMap;\n    }\n    private static com.google.protobuf.Internal.EnumLiteMap<Type>\n        internalValueMap =\n          new com.google.protobuf.Internal.EnumLiteMap<Type>() {\n            public Type findValueByNumber(int number) {\n              return Type.valueOf(number);\n            }\n          };\n\n    public final com.google.protobuf.Descriptors.EnumValueDescriptor\n        getValueDescriptor() {\n      return getDescriptor().getValues().get(index);\n    }\n    public final com.google.protobuf.Descriptors.EnumDescriptor\n        getDescriptorForType() {\n      return getDescriptor();\n    }\n    public static final com.google.protobuf.Descriptors.EnumDescriptor\n        getDescriptor() {\n      return CanalEntry.getDescriptor().getEnumTypes().get(2);\n    }\n\n    private static final Type[] VALUES = values();\n\n    public static Type valueOf(\n        com.google.protobuf.Descriptors.EnumValueDescriptor desc) {\n      if (desc.getType() != getDescriptor()) {\n        throw new IllegalArgumentException(\n          \"EnumValueDescriptor is not for this type.\");\n      }\n      return VALUES[desc.getIndex()];\n    }\n\n    private final int index;\n    private final int value;\n\n    private Type(int index, int value) {\n      this.index = index;\n      this.value = value;\n    }\n\n    // @@protoc_insertion_point(enum_scope:com.alibaba.otter.canal.protocol.Type)\n  }\n\n  public interface EntryOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.Entry)\n      com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <code>optional .com.alibaba.otter.canal.protocol.Header header = 1;</code>\n     *\n     * <pre>\n     **协议头部信息*\n     * </pre>\n     */\n    boolean hasHeader();\n    /**\n     * <code>optional .com.alibaba.otter.canal.protocol.Header header = 1;</code>\n     *\n     * <pre>\n     **协议头部信息*\n     * </pre>\n     */\n    Header getHeader();\n    /**\n     * <code>optional .com.alibaba.otter.canal.protocol.Header header = 1;</code>\n     *\n     * <pre>\n     **协议头部信息*\n     * </pre>\n     */\n    HeaderOrBuilder getHeaderOrBuilder();\n\n    /**\n     * <code>optional .com.alibaba.otter.canal.protocol.EntryType entryType = 2 [default = ROWDATA];</code>\n     *\n     * <pre>\n     **打散后的事件类型*\n     * </pre>\n     */\n    boolean hasEntryType();\n    /**\n     * <code>optional .com.alibaba.otter.canal.protocol.EntryType entryType = 2 [default = ROWDATA];</code>\n     *\n     * <pre>\n     **打散后的事件类型*\n     * </pre>\n     */\n    EntryType getEntryType();\n\n    /**\n     * <code>optional bytes storeValue = 3;</code>\n     *\n     * <pre>\n     **传输的二进制数组*\n     * </pre>\n     */\n    boolean hasStoreValue();\n    /**\n     * <code>optional bytes storeValue = 3;</code>\n     *\n     * <pre>\n     **传输的二进制数组*\n     * </pre>\n     */\n    com.google.protobuf.ByteString getStoreValue();\n  }\n  /**\n   * Protobuf type {@code com.alibaba.otter.canal.protocol.Entry}\n   *\n   * <pre>\n   ****************************************************************\n   * message model\n   *如果要在Enum中新增类型，确保以前的类型的下标值不变.\n   ***************************************************************\n   * </pre>\n   */\n  public static final class Entry extends\n      com.google.protobuf.GeneratedMessage implements\n      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.Entry)\n      EntryOrBuilder {\n    // Use Entry.newBuilder() to construct.\n    private Entry(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private Entry(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final Entry defaultInstance;\n    public static Entry getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public Entry getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private Entry(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              Header.Builder subBuilder = null;\n              if (((bitField0_ & 0x00000001) == 0x00000001)) {\n                subBuilder = header_.toBuilder();\n              }\n              header_ = input.readMessage(Header.PARSER, extensionRegistry);\n              if (subBuilder != null) {\n                subBuilder.mergeFrom(header_);\n                header_ = subBuilder.buildPartial();\n              }\n              bitField0_ |= 0x00000001;\n              break;\n            }\n            case 16: {\n              int rawValue = input.readEnum();\n              EntryType value = EntryType.valueOf(rawValue);\n              if (value == null) {\n                unknownFields.mergeVarintField(2, rawValue);\n              } else {\n                bitField0_ |= 0x00000002;\n                entryType_ = value;\n              }\n              break;\n            }\n            case 26: {\n              bitField0_ |= 0x00000004;\n              storeValue_ = input.readBytes();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_Entry_descriptor;\n    }\n\n    protected FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_Entry_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              Entry.class, Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<Entry> PARSER =\n        new com.google.protobuf.AbstractParser<Entry>() {\n      public Entry parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new Entry(input, extensionRegistry);\n      }\n    };\n\n    @Override\n    public com.google.protobuf.Parser<Entry> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    public static final int HEADER_FIELD_NUMBER = 1;\n    private Header header_;\n    /**\n     * <code>optional .com.alibaba.otter.canal.protocol.Header header = 1;</code>\n     *\n     * <pre>\n     **协议头部信息*\n     * </pre>\n     */\n    public boolean hasHeader() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>optional .com.alibaba.otter.canal.protocol.Header header = 1;</code>\n     *\n     * <pre>\n     **协议头部信息*\n     * </pre>\n     */\n    public Header getHeader() {\n      return header_;\n    }\n    /**\n     * <code>optional .com.alibaba.otter.canal.protocol.Header header = 1;</code>\n     *\n     * <pre>\n     **协议头部信息*\n     * </pre>\n     */\n    public HeaderOrBuilder getHeaderOrBuilder() {\n      return header_;\n    }\n\n    public static final int ENTRYTYPE_FIELD_NUMBER = 2;\n    private EntryType entryType_;\n    /**\n     * <code>optional .com.alibaba.otter.canal.protocol.EntryType entryType = 2 [default = ROWDATA];</code>\n     *\n     * <pre>\n     **打散后的事件类型*\n     * </pre>\n     */\n    public boolean hasEntryType() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>optional .com.alibaba.otter.canal.protocol.EntryType entryType = 2 [default = ROWDATA];</code>\n     *\n     * <pre>\n     **打散后的事件类型*\n     * </pre>\n     */\n    public EntryType getEntryType() {\n      return entryType_;\n    }\n\n    public static final int STOREVALUE_FIELD_NUMBER = 3;\n    private com.google.protobuf.ByteString storeValue_;\n    /**\n     * <code>optional bytes storeValue = 3;</code>\n     *\n     * <pre>\n     **传输的二进制数组*\n     * </pre>\n     */\n    public boolean hasStoreValue() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>optional bytes storeValue = 3;</code>\n     *\n     * <pre>\n     **传输的二进制数组*\n     * </pre>\n     */\n    public com.google.protobuf.ByteString getStoreValue() {\n      return storeValue_;\n    }\n\n    private void initFields() {\n      header_ = Header.getDefaultInstance();\n      entryType_ = EntryType.ROWDATA;\n      storeValue_ = com.google.protobuf.ByteString.EMPTY;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeMessage(1, header_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeEnum(2, entryType_.getNumber());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeBytes(3, storeValue_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(1, header_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeEnumSize(2, entryType_.getNumber());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(3, storeValue_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @Override\n    protected Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static Entry parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static Entry parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static Entry parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static Entry parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static Entry parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static Entry parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static Entry parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static Entry parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static Entry parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static Entry parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(Entry prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @Override\n    protected Builder newBuilderForType(\n        BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code com.alibaba.otter.canal.protocol.Entry}\n     *\n     * <pre>\n     ****************************************************************\n     * message model\n     *如果要在Enum中新增类型，确保以前的类型的下标值不变.\n     ***************************************************************\n     * </pre>\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.Entry)\n        EntryOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_Entry_descriptor;\n      }\n\n      protected FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_Entry_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                Entry.class, Builder.class);\n      }\n\n      // Construct using com.alibaba.otter.canal.protocol.CanalEntry.Entry.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getHeaderFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        if (headerBuilder_ == null) {\n          header_ = Header.getDefaultInstance();\n        } else {\n          headerBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000001);\n        entryType_ = EntryType.ROWDATA;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        storeValue_ = com.google.protobuf.ByteString.EMPTY;\n        bitField0_ = (bitField0_ & ~0x00000004);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_Entry_descriptor;\n      }\n\n      public Entry getDefaultInstanceForType() {\n        return Entry.getDefaultInstance();\n      }\n\n      public Entry build() {\n        Entry result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public Entry buildPartial() {\n        Entry result = new Entry(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        if (headerBuilder_ == null) {\n          result.header_ = header_;\n        } else {\n          result.header_ = headerBuilder_.build();\n        }\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.entryType_ = entryType_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.storeValue_ = storeValue_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof Entry) {\n          return mergeFrom((Entry)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(Entry other) {\n        if (other == Entry.getDefaultInstance()) return this;\n        if (other.hasHeader()) {\n          mergeHeader(other.getHeader());\n        }\n        if (other.hasEntryType()) {\n          setEntryType(other.getEntryType());\n        }\n        if (other.hasStoreValue()) {\n          setStoreValue(other.getStoreValue());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        Entry parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (Entry) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      private Header header_ = Header.getDefaultInstance();\n      private com.google.protobuf.SingleFieldBuilder<\n          Header, Header.Builder, HeaderOrBuilder> headerBuilder_;\n      /**\n       * <code>optional .com.alibaba.otter.canal.protocol.Header header = 1;</code>\n       *\n       * <pre>\n       **协议头部信息*\n       * </pre>\n       */\n      public boolean hasHeader() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>optional .com.alibaba.otter.canal.protocol.Header header = 1;</code>\n       *\n       * <pre>\n       **协议头部信息*\n       * </pre>\n       */\n      public Header getHeader() {\n        if (headerBuilder_ == null) {\n          return header_;\n        } else {\n          return headerBuilder_.getMessage();\n        }\n      }\n      /**\n       * <code>optional .com.alibaba.otter.canal.protocol.Header header = 1;</code>\n       *\n       * <pre>\n       **协议头部信息*\n       * </pre>\n       */\n      public Builder setHeader(Header value) {\n        if (headerBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          header_ = value;\n          onChanged();\n        } else {\n          headerBuilder_.setMessage(value);\n        }\n        bitField0_ |= 0x00000001;\n        return this;\n      }\n      /**\n       * <code>optional .com.alibaba.otter.canal.protocol.Header header = 1;</code>\n       *\n       * <pre>\n       **协议头部信息*\n       * </pre>\n       */\n      public Builder setHeader(\n          Header.Builder builderForValue) {\n        if (headerBuilder_ == null) {\n          header_ = builderForValue.build();\n          onChanged();\n        } else {\n          headerBuilder_.setMessage(builderForValue.build());\n        }\n        bitField0_ |= 0x00000001;\n        return this;\n      }\n      /**\n       * <code>optional .com.alibaba.otter.canal.protocol.Header header = 1;</code>\n       *\n       * <pre>\n       **协议头部信息*\n       * </pre>\n       */\n      public Builder mergeHeader(Header value) {\n        if (headerBuilder_ == null) {\n          if (((bitField0_ & 0x00000001) == 0x00000001) &&\n              header_ != Header.getDefaultInstance()) {\n            header_ =\n              Header.newBuilder(header_).mergeFrom(value).buildPartial();\n          } else {\n            header_ = value;\n          }\n          onChanged();\n        } else {\n          headerBuilder_.mergeFrom(value);\n        }\n        bitField0_ |= 0x00000001;\n        return this;\n      }\n      /**\n       * <code>optional .com.alibaba.otter.canal.protocol.Header header = 1;</code>\n       *\n       * <pre>\n       **协议头部信息*\n       * </pre>\n       */\n      public Builder clearHeader() {\n        if (headerBuilder_ == null) {\n          header_ = Header.getDefaultInstance();\n          onChanged();\n        } else {\n          headerBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000001);\n        return this;\n      }\n      /**\n       * <code>optional .com.alibaba.otter.canal.protocol.Header header = 1;</code>\n       *\n       * <pre>\n       **协议头部信息*\n       * </pre>\n       */\n      public Header.Builder getHeaderBuilder() {\n        bitField0_ |= 0x00000001;\n        onChanged();\n        return getHeaderFieldBuilder().getBuilder();\n      }\n      /**\n       * <code>optional .com.alibaba.otter.canal.protocol.Header header = 1;</code>\n       *\n       * <pre>\n       **协议头部信息*\n       * </pre>\n       */\n      public HeaderOrBuilder getHeaderOrBuilder() {\n        if (headerBuilder_ != null) {\n          return headerBuilder_.getMessageOrBuilder();\n        } else {\n          return header_;\n        }\n      }\n      /**\n       * <code>optional .com.alibaba.otter.canal.protocol.Header header = 1;</code>\n       *\n       * <pre>\n       **协议头部信息*\n       * </pre>\n       */\n      private com.google.protobuf.SingleFieldBuilder<\n          Header, Header.Builder, HeaderOrBuilder>\n          getHeaderFieldBuilder() {\n        if (headerBuilder_ == null) {\n          headerBuilder_ = new com.google.protobuf.SingleFieldBuilder<\n              Header, Header.Builder, HeaderOrBuilder>(\n                  getHeader(),\n                  getParentForChildren(),\n                  isClean());\n          header_ = null;\n        }\n        return headerBuilder_;\n      }\n\n      private EntryType entryType_ = EntryType.ROWDATA;\n      /**\n       * <code>optional .com.alibaba.otter.canal.protocol.EntryType entryType = 2 [default = ROWDATA];</code>\n       *\n       * <pre>\n       **打散后的事件类型*\n       * </pre>\n       */\n      public boolean hasEntryType() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>optional .com.alibaba.otter.canal.protocol.EntryType entryType = 2 [default = ROWDATA];</code>\n       *\n       * <pre>\n       **打散后的事件类型*\n       * </pre>\n       */\n      public EntryType getEntryType() {\n        return entryType_;\n      }\n      /**\n       * <code>optional .com.alibaba.otter.canal.protocol.EntryType entryType = 2 [default = ROWDATA];</code>\n       *\n       * <pre>\n       **打散后的事件类型*\n       * </pre>\n       */\n      public Builder setEntryType(EntryType value) {\n        if (value == null) {\n          throw new NullPointerException();\n        }\n        bitField0_ |= 0x00000002;\n        entryType_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional .com.alibaba.otter.canal.protocol.EntryType entryType = 2 [default = ROWDATA];</code>\n       *\n       * <pre>\n       **打散后的事件类型*\n       * </pre>\n       */\n      public Builder clearEntryType() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        entryType_ = EntryType.ROWDATA;\n        onChanged();\n        return this;\n      }\n\n      private com.google.protobuf.ByteString storeValue_ = com.google.protobuf.ByteString.EMPTY;\n      /**\n       * <code>optional bytes storeValue = 3;</code>\n       *\n       * <pre>\n       **传输的二进制数组*\n       * </pre>\n       */\n      public boolean hasStoreValue() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>optional bytes storeValue = 3;</code>\n       *\n       * <pre>\n       **传输的二进制数组*\n       * </pre>\n       */\n      public com.google.protobuf.ByteString getStoreValue() {\n        return storeValue_;\n      }\n      /**\n       * <code>optional bytes storeValue = 3;</code>\n       *\n       * <pre>\n       **传输的二进制数组*\n       * </pre>\n       */\n      public Builder setStoreValue(com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        storeValue_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional bytes storeValue = 3;</code>\n       *\n       * <pre>\n       **传输的二进制数组*\n       * </pre>\n       */\n      public Builder clearStoreValue() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        storeValue_ = getDefaultInstance().getStoreValue();\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.Entry)\n    }\n\n    static {\n      defaultInstance = new Entry(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.Entry)\n  }\n\n  public interface HeaderOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.Header)\n      com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <code>optional int32 version = 1 [default = 1];</code>\n     *\n     * <pre>\n     **协议的版本号*\n     * </pre>\n     */\n    boolean hasVersion();\n    /**\n     * <code>optional int32 version = 1 [default = 1];</code>\n     *\n     * <pre>\n     **协议的版本号*\n     * </pre>\n     */\n    int getVersion();\n\n    /**\n     * <code>optional string logfileName = 2;</code>\n     *\n     * <pre>\n     **binlog/redolog 文件名*\n     * </pre>\n     */\n    boolean hasLogfileName();\n    /**\n     * <code>optional string logfileName = 2;</code>\n     *\n     * <pre>\n     **binlog/redolog 文件名*\n     * </pre>\n     */\n    String getLogfileName();\n    /**\n     * <code>optional string logfileName = 2;</code>\n     *\n     * <pre>\n     **binlog/redolog 文件名*\n     * </pre>\n     */\n    com.google.protobuf.ByteString\n        getLogfileNameBytes();\n\n    /**\n     * <code>optional int64 logfileOffset = 3;</code>\n     *\n     * <pre>\n     **binlog/redolog 文件的偏移位置*\n     * </pre>\n     */\n    boolean hasLogfileOffset();\n    /**\n     * <code>optional int64 logfileOffset = 3;</code>\n     *\n     * <pre>\n     **binlog/redolog 文件的偏移位置*\n     * </pre>\n     */\n    long getLogfileOffset();\n\n    /**\n     * <code>optional int64 serverId = 4;</code>\n     *\n     * <pre>\n     **服务端serverId*\n     * </pre>\n     */\n    boolean hasServerId();\n    /**\n     * <code>optional int64 serverId = 4;</code>\n     *\n     * <pre>\n     **服务端serverId*\n     * </pre>\n     */\n    long getServerId();\n\n    /**\n     * <code>optional string serverenCode = 5;</code>\n     *\n     * <pre>\n     ** 变更数据的编码 *\n     * </pre>\n     */\n    boolean hasServerenCode();\n    /**\n     * <code>optional string serverenCode = 5;</code>\n     *\n     * <pre>\n     ** 变更数据的编码 *\n     * </pre>\n     */\n    String getServerenCode();\n    /**\n     * <code>optional string serverenCode = 5;</code>\n     *\n     * <pre>\n     ** 变更数据的编码 *\n     * </pre>\n     */\n    com.google.protobuf.ByteString\n        getServerenCodeBytes();\n\n    /**\n     * <code>optional int64 executeTime = 6;</code>\n     *\n     * <pre>\n     **变更数据的执行时间 *\n     * </pre>\n     */\n    boolean hasExecuteTime();\n    /**\n     * <code>optional int64 executeTime = 6;</code>\n     *\n     * <pre>\n     **变更数据的执行时间 *\n     * </pre>\n     */\n    long getExecuteTime();\n\n    /**\n     * <code>optional .com.alibaba.otter.canal.protocol.Type sourceType = 7 [default = MYSQL];</code>\n     *\n     * <pre>\n     ** 变更数据的来源*\n     * </pre>\n     */\n    boolean hasSourceType();\n    /**\n     * <code>optional .com.alibaba.otter.canal.protocol.Type sourceType = 7 [default = MYSQL];</code>\n     *\n     * <pre>\n     ** 变更数据的来源*\n     * </pre>\n     */\n    Type getSourceType();\n\n    /**\n     * <code>optional string schemaName = 8;</code>\n     *\n     * <pre>\n     ** 变更数据的schemaname*\n     * </pre>\n     */\n    boolean hasSchemaName();\n    /**\n     * <code>optional string schemaName = 8;</code>\n     *\n     * <pre>\n     ** 变更数据的schemaname*\n     * </pre>\n     */\n    String getSchemaName();\n    /**\n     * <code>optional string schemaName = 8;</code>\n     *\n     * <pre>\n     ** 变更数据的schemaname*\n     * </pre>\n     */\n    com.google.protobuf.ByteString\n        getSchemaNameBytes();\n\n    /**\n     * <code>optional string tableName = 9;</code>\n     *\n     * <pre>\n     **变更数据的tablename*\n     * </pre>\n     */\n    boolean hasTableName();\n    /**\n     * <code>optional string tableName = 9;</code>\n     *\n     * <pre>\n     **变更数据的tablename*\n     * </pre>\n     */\n    String getTableName();\n    /**\n     * <code>optional string tableName = 9;</code>\n     *\n     * <pre>\n     **变更数据的tablename*\n     * </pre>\n     */\n    com.google.protobuf.ByteString\n        getTableNameBytes();\n\n    /**\n     * <code>optional int64 eventLength = 10;</code>\n     *\n     * <pre>\n     **每个event的长度*\n     * </pre>\n     */\n    boolean hasEventLength();\n    /**\n     * <code>optional int64 eventLength = 10;</code>\n     *\n     * <pre>\n     **每个event的长度*\n     * </pre>\n     */\n    long getEventLength();\n\n    /**\n     * <code>optional .com.alibaba.otter.canal.protocol.EventType eventType = 11 [default = UPDATE];</code>\n     *\n     * <pre>\n     **数据变更类型*\n     * </pre>\n     */\n    boolean hasEventType();\n    /**\n     * <code>optional .com.alibaba.otter.canal.protocol.EventType eventType = 11 [default = UPDATE];</code>\n     *\n     * <pre>\n     **数据变更类型*\n     * </pre>\n     */\n    EventType getEventType();\n\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 12;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    java.util.List<Pair>\n        getPropsList();\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 12;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    Pair getProps(int index);\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 12;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    int getPropsCount();\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 12;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    java.util.List<? extends PairOrBuilder>\n        getPropsOrBuilderList();\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 12;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    PairOrBuilder getPropsOrBuilder(int index);\n\n    /**\n     * <code>optional string gtid = 13;</code>\n     *\n     * <pre>\n     **当前事务的gitd*\n     * </pre>\n     */\n    boolean hasGtid();\n    /**\n     * <code>optional string gtid = 13;</code>\n     *\n     * <pre>\n     **当前事务的gitd*\n     * </pre>\n     */\n    String getGtid();\n    /**\n     * <code>optional string gtid = 13;</code>\n     *\n     * <pre>\n     **当前事务的gitd*\n     * </pre>\n     */\n    com.google.protobuf.ByteString\n        getGtidBytes();\n  }\n  /**\n   * Protobuf type {@code com.alibaba.otter.canal.protocol.Header}\n   *\n   * <pre>\n   **message Header*\n   * </pre>\n   */\n  public static final class Header extends\n      com.google.protobuf.GeneratedMessage implements\n      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.Header)\n      HeaderOrBuilder {\n    // Use Header.newBuilder() to construct.\n    private Header(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private Header(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final Header defaultInstance;\n    public static Header getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public Header getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private Header(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 8: {\n              bitField0_ |= 0x00000001;\n              version_ = input.readInt32();\n              break;\n            }\n            case 18: {\n              com.google.protobuf.ByteString bs = input.readBytes();\n              bitField0_ |= 0x00000002;\n              logfileName_ = bs;\n              break;\n            }\n            case 24: {\n              bitField0_ |= 0x00000004;\n              logfileOffset_ = input.readInt64();\n              break;\n            }\n            case 32: {\n              bitField0_ |= 0x00000008;\n              serverId_ = input.readInt64();\n              break;\n            }\n            case 42: {\n              com.google.protobuf.ByteString bs = input.readBytes();\n              bitField0_ |= 0x00000010;\n              serverenCode_ = bs;\n              break;\n            }\n            case 48: {\n              bitField0_ |= 0x00000020;\n              executeTime_ = input.readInt64();\n              break;\n            }\n            case 56: {\n              int rawValue = input.readEnum();\n              Type value = Type.valueOf(rawValue);\n              if (value == null) {\n                unknownFields.mergeVarintField(7, rawValue);\n              } else {\n                bitField0_ |= 0x00000040;\n                sourceType_ = value;\n              }\n              break;\n            }\n            case 66: {\n              com.google.protobuf.ByteString bs = input.readBytes();\n              bitField0_ |= 0x00000080;\n              schemaName_ = bs;\n              break;\n            }\n            case 74: {\n              com.google.protobuf.ByteString bs = input.readBytes();\n              bitField0_ |= 0x00000100;\n              tableName_ = bs;\n              break;\n            }\n            case 80: {\n              bitField0_ |= 0x00000200;\n              eventLength_ = input.readInt64();\n              break;\n            }\n            case 88: {\n              int rawValue = input.readEnum();\n              EventType value = EventType.valueOf(rawValue);\n              if (value == null) {\n                unknownFields.mergeVarintField(11, rawValue);\n              } else {\n                bitField0_ |= 0x00000400;\n                eventType_ = value;\n              }\n              break;\n            }\n            case 98: {\n              if (!((mutable_bitField0_ & 0x00000800) == 0x00000800)) {\n                props_ = new java.util.ArrayList<Pair>();\n                mutable_bitField0_ |= 0x00000800;\n              }\n              props_.add(input.readMessage(Pair.PARSER, extensionRegistry));\n              break;\n            }\n            case 106: {\n              com.google.protobuf.ByteString bs = input.readBytes();\n              bitField0_ |= 0x00000800;\n              gtid_ = bs;\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000800) == 0x00000800)) {\n          props_ = java.util.Collections.unmodifiableList(props_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_Header_descriptor;\n    }\n\n    protected FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_Header_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              Header.class, Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<Header> PARSER =\n        new com.google.protobuf.AbstractParser<Header>() {\n      public Header parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new Header(input, extensionRegistry);\n      }\n    };\n\n    @Override\n    public com.google.protobuf.Parser<Header> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    public static final int VERSION_FIELD_NUMBER = 1;\n    private int version_;\n    /**\n     * <code>optional int32 version = 1 [default = 1];</code>\n     *\n     * <pre>\n     **协议的版本号*\n     * </pre>\n     */\n    public boolean hasVersion() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>optional int32 version = 1 [default = 1];</code>\n     *\n     * <pre>\n     **协议的版本号*\n     * </pre>\n     */\n    public int getVersion() {\n      return version_;\n    }\n\n    public static final int LOGFILENAME_FIELD_NUMBER = 2;\n    private Object logfileName_;\n    /**\n     * <code>optional string logfileName = 2;</code>\n     *\n     * <pre>\n     **binlog/redolog 文件名*\n     * </pre>\n     */\n    public boolean hasLogfileName() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>optional string logfileName = 2;</code>\n     *\n     * <pre>\n     **binlog/redolog 文件名*\n     * </pre>\n     */\n    public String getLogfileName() {\n      Object ref = logfileName_;\n      if (ref instanceof String) {\n        return (String) ref;\n      } else {\n        com.google.protobuf.ByteString bs =\n            (com.google.protobuf.ByteString) ref;\n        String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          logfileName_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string logfileName = 2;</code>\n     *\n     * <pre>\n     **binlog/redolog 文件名*\n     * </pre>\n     */\n    public com.google.protobuf.ByteString\n        getLogfileNameBytes() {\n      Object ref = logfileName_;\n      if (ref instanceof String) {\n        com.google.protobuf.ByteString b =\n            com.google.protobuf.ByteString.copyFromUtf8(\n                (String) ref);\n        logfileName_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int LOGFILEOFFSET_FIELD_NUMBER = 3;\n    private long logfileOffset_;\n    /**\n     * <code>optional int64 logfileOffset = 3;</code>\n     *\n     * <pre>\n     **binlog/redolog 文件的偏移位置*\n     * </pre>\n     */\n    public boolean hasLogfileOffset() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>optional int64 logfileOffset = 3;</code>\n     *\n     * <pre>\n     **binlog/redolog 文件的偏移位置*\n     * </pre>\n     */\n    public long getLogfileOffset() {\n      return logfileOffset_;\n    }\n\n    public static final int SERVERID_FIELD_NUMBER = 4;\n    private long serverId_;\n    /**\n     * <code>optional int64 serverId = 4;</code>\n     *\n     * <pre>\n     **服务端serverId*\n     * </pre>\n     */\n    public boolean hasServerId() {\n      return ((bitField0_ & 0x00000008) == 0x00000008);\n    }\n    /**\n     * <code>optional int64 serverId = 4;</code>\n     *\n     * <pre>\n     **服务端serverId*\n     * </pre>\n     */\n    public long getServerId() {\n      return serverId_;\n    }\n\n    public static final int SERVERENCODE_FIELD_NUMBER = 5;\n    private Object serverenCode_;\n    /**\n     * <code>optional string serverenCode = 5;</code>\n     *\n     * <pre>\n     ** 变更数据的编码 *\n     * </pre>\n     */\n    public boolean hasServerenCode() {\n      return ((bitField0_ & 0x00000010) == 0x00000010);\n    }\n    /**\n     * <code>optional string serverenCode = 5;</code>\n     *\n     * <pre>\n     ** 变更数据的编码 *\n     * </pre>\n     */\n    public String getServerenCode() {\n      Object ref = serverenCode_;\n      if (ref instanceof String) {\n        return (String) ref;\n      } else {\n        com.google.protobuf.ByteString bs =\n            (com.google.protobuf.ByteString) ref;\n        String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          serverenCode_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string serverenCode = 5;</code>\n     *\n     * <pre>\n     ** 变更数据的编码 *\n     * </pre>\n     */\n    public com.google.protobuf.ByteString\n        getServerenCodeBytes() {\n      Object ref = serverenCode_;\n      if (ref instanceof String) {\n        com.google.protobuf.ByteString b =\n            com.google.protobuf.ByteString.copyFromUtf8(\n                (String) ref);\n        serverenCode_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int EXECUTETIME_FIELD_NUMBER = 6;\n    private long executeTime_;\n    /**\n     * <code>optional int64 executeTime = 6;</code>\n     *\n     * <pre>\n     **变更数据的执行时间 *\n     * </pre>\n     */\n    public boolean hasExecuteTime() {\n      return ((bitField0_ & 0x00000020) == 0x00000020);\n    }\n    /**\n     * <code>optional int64 executeTime = 6;</code>\n     *\n     * <pre>\n     **变更数据的执行时间 *\n     * </pre>\n     */\n    public long getExecuteTime() {\n      return executeTime_;\n    }\n\n    public static final int SOURCETYPE_FIELD_NUMBER = 7;\n    private Type sourceType_;\n    /**\n     * <code>optional .com.alibaba.otter.canal.protocol.Type sourceType = 7 [default = MYSQL];</code>\n     *\n     * <pre>\n     ** 变更数据的来源*\n     * </pre>\n     */\n    public boolean hasSourceType() {\n      return ((bitField0_ & 0x00000040) == 0x00000040);\n    }\n    /**\n     * <code>optional .com.alibaba.otter.canal.protocol.Type sourceType = 7 [default = MYSQL];</code>\n     *\n     * <pre>\n     ** 变更数据的来源*\n     * </pre>\n     */\n    public Type getSourceType() {\n      return sourceType_;\n    }\n\n    public static final int SCHEMANAME_FIELD_NUMBER = 8;\n    private Object schemaName_;\n    /**\n     * <code>optional string schemaName = 8;</code>\n     *\n     * <pre>\n     ** 变更数据的schemaname*\n     * </pre>\n     */\n    public boolean hasSchemaName() {\n      return ((bitField0_ & 0x00000080) == 0x00000080);\n    }\n    /**\n     * <code>optional string schemaName = 8;</code>\n     *\n     * <pre>\n     ** 变更数据的schemaname*\n     * </pre>\n     */\n    public String getSchemaName() {\n      Object ref = schemaName_;\n      if (ref instanceof String) {\n        return (String) ref;\n      } else {\n        com.google.protobuf.ByteString bs =\n            (com.google.protobuf.ByteString) ref;\n        String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          schemaName_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string schemaName = 8;</code>\n     *\n     * <pre>\n     ** 变更数据的schemaname*\n     * </pre>\n     */\n    public com.google.protobuf.ByteString\n        getSchemaNameBytes() {\n      Object ref = schemaName_;\n      if (ref instanceof String) {\n        com.google.protobuf.ByteString b =\n            com.google.protobuf.ByteString.copyFromUtf8(\n                (String) ref);\n        schemaName_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int TABLENAME_FIELD_NUMBER = 9;\n    private Object tableName_;\n    /**\n     * <code>optional string tableName = 9;</code>\n     *\n     * <pre>\n     **变更数据的tablename*\n     * </pre>\n     */\n    public boolean hasTableName() {\n      return ((bitField0_ & 0x00000100) == 0x00000100);\n    }\n    /**\n     * <code>optional string tableName = 9;</code>\n     *\n     * <pre>\n     **变更数据的tablename*\n     * </pre>\n     */\n    public String getTableName() {\n      Object ref = tableName_;\n      if (ref instanceof String) {\n        return (String) ref;\n      } else {\n        com.google.protobuf.ByteString bs =\n            (com.google.protobuf.ByteString) ref;\n        String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          tableName_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string tableName = 9;</code>\n     *\n     * <pre>\n     **变更数据的tablename*\n     * </pre>\n     */\n    public com.google.protobuf.ByteString\n        getTableNameBytes() {\n      Object ref = tableName_;\n      if (ref instanceof String) {\n        com.google.protobuf.ByteString b =\n            com.google.protobuf.ByteString.copyFromUtf8(\n                (String) ref);\n        tableName_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int EVENTLENGTH_FIELD_NUMBER = 10;\n    private long eventLength_;\n    /**\n     * <code>optional int64 eventLength = 10;</code>\n     *\n     * <pre>\n     **每个event的长度*\n     * </pre>\n     */\n    public boolean hasEventLength() {\n      return ((bitField0_ & 0x00000200) == 0x00000200);\n    }\n    /**\n     * <code>optional int64 eventLength = 10;</code>\n     *\n     * <pre>\n     **每个event的长度*\n     * </pre>\n     */\n    public long getEventLength() {\n      return eventLength_;\n    }\n\n    public static final int EVENTTYPE_FIELD_NUMBER = 11;\n    private EventType eventType_;\n    /**\n     * <code>optional .com.alibaba.otter.canal.protocol.EventType eventType = 11 [default = UPDATE];</code>\n     *\n     * <pre>\n     **数据变更类型*\n     * </pre>\n     */\n    public boolean hasEventType() {\n      return ((bitField0_ & 0x00000400) == 0x00000400);\n    }\n    /**\n     * <code>optional .com.alibaba.otter.canal.protocol.EventType eventType = 11 [default = UPDATE];</code>\n     *\n     * <pre>\n     **数据变更类型*\n     * </pre>\n     */\n    public EventType getEventType() {\n      return eventType_;\n    }\n\n    public static final int PROPS_FIELD_NUMBER = 12;\n    private java.util.List<Pair> props_;\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 12;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public java.util.List<Pair> getPropsList() {\n      return props_;\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 12;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public java.util.List<? extends PairOrBuilder>\n        getPropsOrBuilderList() {\n      return props_;\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 12;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public int getPropsCount() {\n      return props_.size();\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 12;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public Pair getProps(int index) {\n      return props_.get(index);\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 12;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public PairOrBuilder getPropsOrBuilder(\n        int index) {\n      return props_.get(index);\n    }\n\n    public static final int GTID_FIELD_NUMBER = 13;\n    private Object gtid_;\n    /**\n     * <code>optional string gtid = 13;</code>\n     *\n     * <pre>\n     **当前事务的gitd*\n     * </pre>\n     */\n    public boolean hasGtid() {\n      return ((bitField0_ & 0x00000800) == 0x00000800);\n    }\n    /**\n     * <code>optional string gtid = 13;</code>\n     *\n     * <pre>\n     **当前事务的gitd*\n     * </pre>\n     */\n    public String getGtid() {\n      Object ref = gtid_;\n      if (ref instanceof String) {\n        return (String) ref;\n      } else {\n        com.google.protobuf.ByteString bs =\n            (com.google.protobuf.ByteString) ref;\n        String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          gtid_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string gtid = 13;</code>\n     *\n     * <pre>\n     **当前事务的gitd*\n     * </pre>\n     */\n    public com.google.protobuf.ByteString\n        getGtidBytes() {\n      Object ref = gtid_;\n      if (ref instanceof String) {\n        com.google.protobuf.ByteString b =\n            com.google.protobuf.ByteString.copyFromUtf8(\n                (String) ref);\n        gtid_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      version_ = 1;\n      logfileName_ = \"\";\n      logfileOffset_ = 0L;\n      serverId_ = 0L;\n      serverenCode_ = \"\";\n      executeTime_ = 0L;\n      sourceType_ = Type.MYSQL;\n      schemaName_ = \"\";\n      tableName_ = \"\";\n      eventLength_ = 0L;\n      eventType_ = EventType.UPDATE;\n      props_ = java.util.Collections.emptyList();\n      gtid_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeInt32(1, version_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeBytes(2, getLogfileNameBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeInt64(3, logfileOffset_);\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        output.writeInt64(4, serverId_);\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        output.writeBytes(5, getServerenCodeBytes());\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        output.writeInt64(6, executeTime_);\n      }\n      if (((bitField0_ & 0x00000040) == 0x00000040)) {\n        output.writeEnum(7, sourceType_.getNumber());\n      }\n      if (((bitField0_ & 0x00000080) == 0x00000080)) {\n        output.writeBytes(8, getSchemaNameBytes());\n      }\n      if (((bitField0_ & 0x00000100) == 0x00000100)) {\n        output.writeBytes(9, getTableNameBytes());\n      }\n      if (((bitField0_ & 0x00000200) == 0x00000200)) {\n        output.writeInt64(10, eventLength_);\n      }\n      if (((bitField0_ & 0x00000400) == 0x00000400)) {\n        output.writeEnum(11, eventType_.getNumber());\n      }\n      for (int i = 0; i < props_.size(); i++) {\n        output.writeMessage(12, props_.get(i));\n      }\n      if (((bitField0_ & 0x00000800) == 0x00000800)) {\n        output.writeBytes(13, getGtidBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(1, version_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, getLogfileNameBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(3, logfileOffset_);\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(4, serverId_);\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(5, getServerenCodeBytes());\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(6, executeTime_);\n      }\n      if (((bitField0_ & 0x00000040) == 0x00000040)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeEnumSize(7, sourceType_.getNumber());\n      }\n      if (((bitField0_ & 0x00000080) == 0x00000080)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(8, getSchemaNameBytes());\n      }\n      if (((bitField0_ & 0x00000100) == 0x00000100)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(9, getTableNameBytes());\n      }\n      if (((bitField0_ & 0x00000200) == 0x00000200)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(10, eventLength_);\n      }\n      if (((bitField0_ & 0x00000400) == 0x00000400)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeEnumSize(11, eventType_.getNumber());\n      }\n      for (int i = 0; i < props_.size(); i++) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(12, props_.get(i));\n      }\n      if (((bitField0_ & 0x00000800) == 0x00000800)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(13, getGtidBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @Override\n    protected Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static Header parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static Header parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static Header parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static Header parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static Header parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static Header parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static Header parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static Header parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static Header parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static Header parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(Header prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @Override\n    protected Builder newBuilderForType(\n        BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code com.alibaba.otter.canal.protocol.Header}\n     *\n     * <pre>\n     **message Header*\n     * </pre>\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.Header)\n        HeaderOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_Header_descriptor;\n      }\n\n      protected FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_Header_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                Header.class, Builder.class);\n      }\n\n      // Construct using com.alibaba.otter.canal.protocol.CanalEntry.Header.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getPropsFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        version_ = 1;\n        bitField0_ = (bitField0_ & ~0x00000001);\n        logfileName_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000002);\n        logfileOffset_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000004);\n        serverId_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000008);\n        serverenCode_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000010);\n        executeTime_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000020);\n        sourceType_ = Type.MYSQL;\n        bitField0_ = (bitField0_ & ~0x00000040);\n        schemaName_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000080);\n        tableName_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000100);\n        eventLength_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000200);\n        eventType_ = EventType.UPDATE;\n        bitField0_ = (bitField0_ & ~0x00000400);\n        if (propsBuilder_ == null) {\n          props_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000800);\n        } else {\n          propsBuilder_.clear();\n        }\n        gtid_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00001000);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_Header_descriptor;\n      }\n\n      public Header getDefaultInstanceForType() {\n        return Header.getDefaultInstance();\n      }\n\n      public Header build() {\n        Header result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public Header buildPartial() {\n        Header result = new Header(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.version_ = version_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.logfileName_ = logfileName_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.logfileOffset_ = logfileOffset_;\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000008;\n        }\n        result.serverId_ = serverId_;\n        if (((from_bitField0_ & 0x00000010) == 0x00000010)) {\n          to_bitField0_ |= 0x00000010;\n        }\n        result.serverenCode_ = serverenCode_;\n        if (((from_bitField0_ & 0x00000020) == 0x00000020)) {\n          to_bitField0_ |= 0x00000020;\n        }\n        result.executeTime_ = executeTime_;\n        if (((from_bitField0_ & 0x00000040) == 0x00000040)) {\n          to_bitField0_ |= 0x00000040;\n        }\n        result.sourceType_ = sourceType_;\n        if (((from_bitField0_ & 0x00000080) == 0x00000080)) {\n          to_bitField0_ |= 0x00000080;\n        }\n        result.schemaName_ = schemaName_;\n        if (((from_bitField0_ & 0x00000100) == 0x00000100)) {\n          to_bitField0_ |= 0x00000100;\n        }\n        result.tableName_ = tableName_;\n        if (((from_bitField0_ & 0x00000200) == 0x00000200)) {\n          to_bitField0_ |= 0x00000200;\n        }\n        result.eventLength_ = eventLength_;\n        if (((from_bitField0_ & 0x00000400) == 0x00000400)) {\n          to_bitField0_ |= 0x00000400;\n        }\n        result.eventType_ = eventType_;\n        if (propsBuilder_ == null) {\n          if (((bitField0_ & 0x00000800) == 0x00000800)) {\n            props_ = java.util.Collections.unmodifiableList(props_);\n            bitField0_ = (bitField0_ & ~0x00000800);\n          }\n          result.props_ = props_;\n        } else {\n          result.props_ = propsBuilder_.build();\n        }\n        if (((from_bitField0_ & 0x00001000) == 0x00001000)) {\n          to_bitField0_ |= 0x00000800;\n        }\n        result.gtid_ = gtid_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof Header) {\n          return mergeFrom((Header)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(Header other) {\n        if (other == Header.getDefaultInstance()) return this;\n        if (other.hasVersion()) {\n          setVersion(other.getVersion());\n        }\n        if (other.hasLogfileName()) {\n          bitField0_ |= 0x00000002;\n          logfileName_ = other.logfileName_;\n          onChanged();\n        }\n        if (other.hasLogfileOffset()) {\n          setLogfileOffset(other.getLogfileOffset());\n        }\n        if (other.hasServerId()) {\n          setServerId(other.getServerId());\n        }\n        if (other.hasServerenCode()) {\n          bitField0_ |= 0x00000010;\n          serverenCode_ = other.serverenCode_;\n          onChanged();\n        }\n        if (other.hasExecuteTime()) {\n          setExecuteTime(other.getExecuteTime());\n        }\n        if (other.hasSourceType()) {\n          setSourceType(other.getSourceType());\n        }\n        if (other.hasSchemaName()) {\n          bitField0_ |= 0x00000080;\n          schemaName_ = other.schemaName_;\n          onChanged();\n        }\n        if (other.hasTableName()) {\n          bitField0_ |= 0x00000100;\n          tableName_ = other.tableName_;\n          onChanged();\n        }\n        if (other.hasEventLength()) {\n          setEventLength(other.getEventLength());\n        }\n        if (other.hasEventType()) {\n          setEventType(other.getEventType());\n        }\n        if (propsBuilder_ == null) {\n          if (!other.props_.isEmpty()) {\n            if (props_.isEmpty()) {\n              props_ = other.props_;\n              bitField0_ = (bitField0_ & ~0x00000800);\n            } else {\n              ensurePropsIsMutable();\n              props_.addAll(other.props_);\n            }\n            onChanged();\n          }\n        } else {\n          if (!other.props_.isEmpty()) {\n            if (propsBuilder_.isEmpty()) {\n              propsBuilder_.dispose();\n              propsBuilder_ = null;\n              props_ = other.props_;\n              bitField0_ = (bitField0_ & ~0x00000800);\n              propsBuilder_ =\n                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n                   getPropsFieldBuilder() : null;\n            } else {\n              propsBuilder_.addAllMessages(other.props_);\n            }\n          }\n        }\n        if (other.hasGtid()) {\n          bitField0_ |= 0x00001000;\n          gtid_ = other.gtid_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        Header parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (Header) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      private int version_ = 1;\n      /**\n       * <code>optional int32 version = 1 [default = 1];</code>\n       *\n       * <pre>\n       **协议的版本号*\n       * </pre>\n       */\n      public boolean hasVersion() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>optional int32 version = 1 [default = 1];</code>\n       *\n       * <pre>\n       **协议的版本号*\n       * </pre>\n       */\n      public int getVersion() {\n        return version_;\n      }\n      /**\n       * <code>optional int32 version = 1 [default = 1];</code>\n       *\n       * <pre>\n       **协议的版本号*\n       * </pre>\n       */\n      public Builder setVersion(int value) {\n        bitField0_ |= 0x00000001;\n        version_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 version = 1 [default = 1];</code>\n       *\n       * <pre>\n       **协议的版本号*\n       * </pre>\n       */\n      public Builder clearVersion() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        version_ = 1;\n        onChanged();\n        return this;\n      }\n\n      private Object logfileName_ = \"\";\n      /**\n       * <code>optional string logfileName = 2;</code>\n       *\n       * <pre>\n       **binlog/redolog 文件名*\n       * </pre>\n       */\n      public boolean hasLogfileName() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>optional string logfileName = 2;</code>\n       *\n       * <pre>\n       **binlog/redolog 文件名*\n       * </pre>\n       */\n      public String getLogfileName() {\n        Object ref = logfileName_;\n        if (!(ref instanceof String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          String s = bs.toStringUtf8();\n          if (bs.isValidUtf8()) {\n            logfileName_ = s;\n          }\n          return s;\n        } else {\n          return (String) ref;\n        }\n      }\n      /**\n       * <code>optional string logfileName = 2;</code>\n       *\n       * <pre>\n       **binlog/redolog 文件名*\n       * </pre>\n       */\n      public com.google.protobuf.ByteString\n          getLogfileNameBytes() {\n        Object ref = logfileName_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b =\n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (String) ref);\n          logfileName_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string logfileName = 2;</code>\n       *\n       * <pre>\n       **binlog/redolog 文件名*\n       * </pre>\n       */\n      public Builder setLogfileName(\n          String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        logfileName_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string logfileName = 2;</code>\n       *\n       * <pre>\n       **binlog/redolog 文件名*\n       * </pre>\n       */\n      public Builder clearLogfileName() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        logfileName_ = getDefaultInstance().getLogfileName();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string logfileName = 2;</code>\n       *\n       * <pre>\n       **binlog/redolog 文件名*\n       * </pre>\n       */\n      public Builder setLogfileNameBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        logfileName_ = value;\n        onChanged();\n        return this;\n      }\n\n      private long logfileOffset_ ;\n      /**\n       * <code>optional int64 logfileOffset = 3;</code>\n       *\n       * <pre>\n       **binlog/redolog 文件的偏移位置*\n       * </pre>\n       */\n      public boolean hasLogfileOffset() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>optional int64 logfileOffset = 3;</code>\n       *\n       * <pre>\n       **binlog/redolog 文件的偏移位置*\n       * </pre>\n       */\n      public long getLogfileOffset() {\n        return logfileOffset_;\n      }\n      /**\n       * <code>optional int64 logfileOffset = 3;</code>\n       *\n       * <pre>\n       **binlog/redolog 文件的偏移位置*\n       * </pre>\n       */\n      public Builder setLogfileOffset(long value) {\n        bitField0_ |= 0x00000004;\n        logfileOffset_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int64 logfileOffset = 3;</code>\n       *\n       * <pre>\n       **binlog/redolog 文件的偏移位置*\n       * </pre>\n       */\n      public Builder clearLogfileOffset() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        logfileOffset_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      private long serverId_ ;\n      /**\n       * <code>optional int64 serverId = 4;</code>\n       *\n       * <pre>\n       **服务端serverId*\n       * </pre>\n       */\n      public boolean hasServerId() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>optional int64 serverId = 4;</code>\n       *\n       * <pre>\n       **服务端serverId*\n       * </pre>\n       */\n      public long getServerId() {\n        return serverId_;\n      }\n      /**\n       * <code>optional int64 serverId = 4;</code>\n       *\n       * <pre>\n       **服务端serverId*\n       * </pre>\n       */\n      public Builder setServerId(long value) {\n        bitField0_ |= 0x00000008;\n        serverId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int64 serverId = 4;</code>\n       *\n       * <pre>\n       **服务端serverId*\n       * </pre>\n       */\n      public Builder clearServerId() {\n        bitField0_ = (bitField0_ & ~0x00000008);\n        serverId_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      private Object serverenCode_ = \"\";\n      /**\n       * <code>optional string serverenCode = 5;</code>\n       *\n       * <pre>\n       ** 变更数据的编码 *\n       * </pre>\n       */\n      public boolean hasServerenCode() {\n        return ((bitField0_ & 0x00000010) == 0x00000010);\n      }\n      /**\n       * <code>optional string serverenCode = 5;</code>\n       *\n       * <pre>\n       ** 变更数据的编码 *\n       * </pre>\n       */\n      public String getServerenCode() {\n        Object ref = serverenCode_;\n        if (!(ref instanceof String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          String s = bs.toStringUtf8();\n          if (bs.isValidUtf8()) {\n            serverenCode_ = s;\n          }\n          return s;\n        } else {\n          return (String) ref;\n        }\n      }\n      /**\n       * <code>optional string serverenCode = 5;</code>\n       *\n       * <pre>\n       ** 变更数据的编码 *\n       * </pre>\n       */\n      public com.google.protobuf.ByteString\n          getServerenCodeBytes() {\n        Object ref = serverenCode_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b =\n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (String) ref);\n          serverenCode_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string serverenCode = 5;</code>\n       *\n       * <pre>\n       ** 变更数据的编码 *\n       * </pre>\n       */\n      public Builder setServerenCode(\n          String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000010;\n        serverenCode_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string serverenCode = 5;</code>\n       *\n       * <pre>\n       ** 变更数据的编码 *\n       * </pre>\n       */\n      public Builder clearServerenCode() {\n        bitField0_ = (bitField0_ & ~0x00000010);\n        serverenCode_ = getDefaultInstance().getServerenCode();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string serverenCode = 5;</code>\n       *\n       * <pre>\n       ** 变更数据的编码 *\n       * </pre>\n       */\n      public Builder setServerenCodeBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000010;\n        serverenCode_ = value;\n        onChanged();\n        return this;\n      }\n\n      private long executeTime_ ;\n      /**\n       * <code>optional int64 executeTime = 6;</code>\n       *\n       * <pre>\n       **变更数据的执行时间 *\n       * </pre>\n       */\n      public boolean hasExecuteTime() {\n        return ((bitField0_ & 0x00000020) == 0x00000020);\n      }\n      /**\n       * <code>optional int64 executeTime = 6;</code>\n       *\n       * <pre>\n       **变更数据的执行时间 *\n       * </pre>\n       */\n      public long getExecuteTime() {\n        return executeTime_;\n      }\n      /**\n       * <code>optional int64 executeTime = 6;</code>\n       *\n       * <pre>\n       **变更数据的执行时间 *\n       * </pre>\n       */\n      public Builder setExecuteTime(long value) {\n        bitField0_ |= 0x00000020;\n        executeTime_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int64 executeTime = 6;</code>\n       *\n       * <pre>\n       **变更数据的执行时间 *\n       * </pre>\n       */\n      public Builder clearExecuteTime() {\n        bitField0_ = (bitField0_ & ~0x00000020);\n        executeTime_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      private Type sourceType_ = Type.MYSQL;\n      /**\n       * <code>optional .com.alibaba.otter.canal.protocol.Type sourceType = 7 [default = MYSQL];</code>\n       *\n       * <pre>\n       ** 变更数据的来源*\n       * </pre>\n       */\n      public boolean hasSourceType() {\n        return ((bitField0_ & 0x00000040) == 0x00000040);\n      }\n      /**\n       * <code>optional .com.alibaba.otter.canal.protocol.Type sourceType = 7 [default = MYSQL];</code>\n       *\n       * <pre>\n       ** 变更数据的来源*\n       * </pre>\n       */\n      public Type getSourceType() {\n        return sourceType_;\n      }\n      /**\n       * <code>optional .com.alibaba.otter.canal.protocol.Type sourceType = 7 [default = MYSQL];</code>\n       *\n       * <pre>\n       ** 变更数据的来源*\n       * </pre>\n       */\n      public Builder setSourceType(Type value) {\n        if (value == null) {\n          throw new NullPointerException();\n        }\n        bitField0_ |= 0x00000040;\n        sourceType_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional .com.alibaba.otter.canal.protocol.Type sourceType = 7 [default = MYSQL];</code>\n       *\n       * <pre>\n       ** 变更数据的来源*\n       * </pre>\n       */\n      public Builder clearSourceType() {\n        bitField0_ = (bitField0_ & ~0x00000040);\n        sourceType_ = Type.MYSQL;\n        onChanged();\n        return this;\n      }\n\n      private Object schemaName_ = \"\";\n      /**\n       * <code>optional string schemaName = 8;</code>\n       *\n       * <pre>\n       ** 变更数据的schemaname*\n       * </pre>\n       */\n      public boolean hasSchemaName() {\n        return ((bitField0_ & 0x00000080) == 0x00000080);\n      }\n      /**\n       * <code>optional string schemaName = 8;</code>\n       *\n       * <pre>\n       ** 变更数据的schemaname*\n       * </pre>\n       */\n      public String getSchemaName() {\n        Object ref = schemaName_;\n        if (!(ref instanceof String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          String s = bs.toStringUtf8();\n          if (bs.isValidUtf8()) {\n            schemaName_ = s;\n          }\n          return s;\n        } else {\n          return (String) ref;\n        }\n      }\n      /**\n       * <code>optional string schemaName = 8;</code>\n       *\n       * <pre>\n       ** 变更数据的schemaname*\n       * </pre>\n       */\n      public com.google.protobuf.ByteString\n          getSchemaNameBytes() {\n        Object ref = schemaName_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b =\n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (String) ref);\n          schemaName_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string schemaName = 8;</code>\n       *\n       * <pre>\n       ** 变更数据的schemaname*\n       * </pre>\n       */\n      public Builder setSchemaName(\n          String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000080;\n        schemaName_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string schemaName = 8;</code>\n       *\n       * <pre>\n       ** 变更数据的schemaname*\n       * </pre>\n       */\n      public Builder clearSchemaName() {\n        bitField0_ = (bitField0_ & ~0x00000080);\n        schemaName_ = getDefaultInstance().getSchemaName();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string schemaName = 8;</code>\n       *\n       * <pre>\n       ** 变更数据的schemaname*\n       * </pre>\n       */\n      public Builder setSchemaNameBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000080;\n        schemaName_ = value;\n        onChanged();\n        return this;\n      }\n\n      private Object tableName_ = \"\";\n      /**\n       * <code>optional string tableName = 9;</code>\n       *\n       * <pre>\n       **变更数据的tablename*\n       * </pre>\n       */\n      public boolean hasTableName() {\n        return ((bitField0_ & 0x00000100) == 0x00000100);\n      }\n      /**\n       * <code>optional string tableName = 9;</code>\n       *\n       * <pre>\n       **变更数据的tablename*\n       * </pre>\n       */\n      public String getTableName() {\n        Object ref = tableName_;\n        if (!(ref instanceof String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          String s = bs.toStringUtf8();\n          if (bs.isValidUtf8()) {\n            tableName_ = s;\n          }\n          return s;\n        } else {\n          return (String) ref;\n        }\n      }\n      /**\n       * <code>optional string tableName = 9;</code>\n       *\n       * <pre>\n       **变更数据的tablename*\n       * </pre>\n       */\n      public com.google.protobuf.ByteString\n          getTableNameBytes() {\n        Object ref = tableName_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b =\n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (String) ref);\n          tableName_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string tableName = 9;</code>\n       *\n       * <pre>\n       **变更数据的tablename*\n       * </pre>\n       */\n      public Builder setTableName(\n          String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000100;\n        tableName_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string tableName = 9;</code>\n       *\n       * <pre>\n       **变更数据的tablename*\n       * </pre>\n       */\n      public Builder clearTableName() {\n        bitField0_ = (bitField0_ & ~0x00000100);\n        tableName_ = getDefaultInstance().getTableName();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string tableName = 9;</code>\n       *\n       * <pre>\n       **变更数据的tablename*\n       * </pre>\n       */\n      public Builder setTableNameBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000100;\n        tableName_ = value;\n        onChanged();\n        return this;\n      }\n\n      private long eventLength_ ;\n      /**\n       * <code>optional int64 eventLength = 10;</code>\n       *\n       * <pre>\n       **每个event的长度*\n       * </pre>\n       */\n      public boolean hasEventLength() {\n        return ((bitField0_ & 0x00000200) == 0x00000200);\n      }\n      /**\n       * <code>optional int64 eventLength = 10;</code>\n       *\n       * <pre>\n       **每个event的长度*\n       * </pre>\n       */\n      public long getEventLength() {\n        return eventLength_;\n      }\n      /**\n       * <code>optional int64 eventLength = 10;</code>\n       *\n       * <pre>\n       **每个event的长度*\n       * </pre>\n       */\n      public Builder setEventLength(long value) {\n        bitField0_ |= 0x00000200;\n        eventLength_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int64 eventLength = 10;</code>\n       *\n       * <pre>\n       **每个event的长度*\n       * </pre>\n       */\n      public Builder clearEventLength() {\n        bitField0_ = (bitField0_ & ~0x00000200);\n        eventLength_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      private EventType eventType_ = EventType.UPDATE;\n      /**\n       * <code>optional .com.alibaba.otter.canal.protocol.EventType eventType = 11 [default = UPDATE];</code>\n       *\n       * <pre>\n       **数据变更类型*\n       * </pre>\n       */\n      public boolean hasEventType() {\n        return ((bitField0_ & 0x00000400) == 0x00000400);\n      }\n      /**\n       * <code>optional .com.alibaba.otter.canal.protocol.EventType eventType = 11 [default = UPDATE];</code>\n       *\n       * <pre>\n       **数据变更类型*\n       * </pre>\n       */\n      public EventType getEventType() {\n        return eventType_;\n      }\n      /**\n       * <code>optional .com.alibaba.otter.canal.protocol.EventType eventType = 11 [default = UPDATE];</code>\n       *\n       * <pre>\n       **数据变更类型*\n       * </pre>\n       */\n      public Builder setEventType(EventType value) {\n        if (value == null) {\n          throw new NullPointerException();\n        }\n        bitField0_ |= 0x00000400;\n        eventType_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional .com.alibaba.otter.canal.protocol.EventType eventType = 11 [default = UPDATE];</code>\n       *\n       * <pre>\n       **数据变更类型*\n       * </pre>\n       */\n      public Builder clearEventType() {\n        bitField0_ = (bitField0_ & ~0x00000400);\n        eventType_ = EventType.UPDATE;\n        onChanged();\n        return this;\n      }\n\n      private java.util.List<Pair> props_ =\n        java.util.Collections.emptyList();\n      private void ensurePropsIsMutable() {\n        if (!((bitField0_ & 0x00000800) == 0x00000800)) {\n          props_ = new java.util.ArrayList<Pair>(props_);\n          bitField0_ |= 0x00000800;\n         }\n      }\n\n      private com.google.protobuf.RepeatedFieldBuilder<\n          Pair, Pair.Builder, PairOrBuilder> propsBuilder_;\n\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 12;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public java.util.List<Pair> getPropsList() {\n        if (propsBuilder_ == null) {\n          return java.util.Collections.unmodifiableList(props_);\n        } else {\n          return propsBuilder_.getMessageList();\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 12;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public int getPropsCount() {\n        if (propsBuilder_ == null) {\n          return props_.size();\n        } else {\n          return propsBuilder_.getCount();\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 12;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Pair getProps(int index) {\n        if (propsBuilder_ == null) {\n          return props_.get(index);\n        } else {\n          return propsBuilder_.getMessage(index);\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 12;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder setProps(\n          int index, Pair value) {\n        if (propsBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensurePropsIsMutable();\n          props_.set(index, value);\n          onChanged();\n        } else {\n          propsBuilder_.setMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 12;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder setProps(\n          int index, Pair.Builder builderForValue) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          props_.set(index, builderForValue.build());\n          onChanged();\n        } else {\n          propsBuilder_.setMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 12;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addProps(Pair value) {\n        if (propsBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensurePropsIsMutable();\n          props_.add(value);\n          onChanged();\n        } else {\n          propsBuilder_.addMessage(value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 12;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addProps(\n          int index, Pair value) {\n        if (propsBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensurePropsIsMutable();\n          props_.add(index, value);\n          onChanged();\n        } else {\n          propsBuilder_.addMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 12;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addProps(\n          Pair.Builder builderForValue) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          props_.add(builderForValue.build());\n          onChanged();\n        } else {\n          propsBuilder_.addMessage(builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 12;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addProps(\n          int index, Pair.Builder builderForValue) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          props_.add(index, builderForValue.build());\n          onChanged();\n        } else {\n          propsBuilder_.addMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 12;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addAllProps(\n          Iterable<? extends Pair> values) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          com.google.protobuf.AbstractMessageLite.Builder.addAll(\n              values, props_);\n          onChanged();\n        } else {\n          propsBuilder_.addAllMessages(values);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 12;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder clearProps() {\n        if (propsBuilder_ == null) {\n          props_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000800);\n          onChanged();\n        } else {\n          propsBuilder_.clear();\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 12;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder removeProps(int index) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          props_.remove(index);\n          onChanged();\n        } else {\n          propsBuilder_.remove(index);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 12;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Pair.Builder getPropsBuilder(\n          int index) {\n        return getPropsFieldBuilder().getBuilder(index);\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 12;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public PairOrBuilder getPropsOrBuilder(\n          int index) {\n        if (propsBuilder_ == null) {\n          return props_.get(index);  } else {\n          return propsBuilder_.getMessageOrBuilder(index);\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 12;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public java.util.List<? extends PairOrBuilder>\n           getPropsOrBuilderList() {\n        if (propsBuilder_ != null) {\n          return propsBuilder_.getMessageOrBuilderList();\n        } else {\n          return java.util.Collections.unmodifiableList(props_);\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 12;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Pair.Builder addPropsBuilder() {\n        return getPropsFieldBuilder().addBuilder(\n            Pair.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 12;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Pair.Builder addPropsBuilder(\n          int index) {\n        return getPropsFieldBuilder().addBuilder(\n            index, Pair.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 12;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public java.util.List<Pair.Builder>\n           getPropsBuilderList() {\n        return getPropsFieldBuilder().getBuilderList();\n      }\n      private com.google.protobuf.RepeatedFieldBuilder<\n          Pair, Pair.Builder, PairOrBuilder>\n          getPropsFieldBuilder() {\n        if (propsBuilder_ == null) {\n          propsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<\n              Pair, Pair.Builder, PairOrBuilder>(\n                  props_,\n                  ((bitField0_ & 0x00000800) == 0x00000800),\n                  getParentForChildren(),\n                  isClean());\n          props_ = null;\n        }\n        return propsBuilder_;\n      }\n\n      private Object gtid_ = \"\";\n      /**\n       * <code>optional string gtid = 13;</code>\n       *\n       * <pre>\n       **当前事务的gitd*\n       * </pre>\n       */\n      public boolean hasGtid() {\n        return ((bitField0_ & 0x00001000) == 0x00001000);\n      }\n      /**\n       * <code>optional string gtid = 13;</code>\n       *\n       * <pre>\n       **当前事务的gitd*\n       * </pre>\n       */\n      public String getGtid() {\n        Object ref = gtid_;\n        if (!(ref instanceof String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          String s = bs.toStringUtf8();\n          if (bs.isValidUtf8()) {\n            gtid_ = s;\n          }\n          return s;\n        } else {\n          return (String) ref;\n        }\n      }\n      /**\n       * <code>optional string gtid = 13;</code>\n       *\n       * <pre>\n       **当前事务的gitd*\n       * </pre>\n       */\n      public com.google.protobuf.ByteString\n          getGtidBytes() {\n        Object ref = gtid_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b =\n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (String) ref);\n          gtid_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string gtid = 13;</code>\n       *\n       * <pre>\n       **当前事务的gitd*\n       * </pre>\n       */\n      public Builder setGtid(\n          String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00001000;\n        gtid_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string gtid = 13;</code>\n       *\n       * <pre>\n       **当前事务的gitd*\n       * </pre>\n       */\n      public Builder clearGtid() {\n        bitField0_ = (bitField0_ & ~0x00001000);\n        gtid_ = getDefaultInstance().getGtid();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string gtid = 13;</code>\n       *\n       * <pre>\n       **当前事务的gitd*\n       * </pre>\n       */\n      public Builder setGtidBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00001000;\n        gtid_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.Header)\n    }\n\n    static {\n      defaultInstance = new Header(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.Header)\n  }\n\n  public interface ColumnOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.Column)\n      com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <code>optional int32 index = 1;</code>\n     *\n     * <pre>\n     **字段下标*\n     * </pre>\n     */\n    boolean hasIndex();\n    /**\n     * <code>optional int32 index = 1;</code>\n     *\n     * <pre>\n     **字段下标*\n     * </pre>\n     */\n    int getIndex();\n\n    /**\n     * <code>optional int32 sqlType = 2;</code>\n     *\n     * <pre>\n     **字段java中类型*\n     * </pre>\n     */\n    boolean hasSqlType();\n    /**\n     * <code>optional int32 sqlType = 2;</code>\n     *\n     * <pre>\n     **字段java中类型*\n     * </pre>\n     */\n    int getSqlType();\n\n    /**\n     * <code>optional string name = 3;</code>\n     *\n     * <pre>\n     **字段名称(忽略大小写)，在mysql中是没有的*\n     * </pre>\n     */\n    boolean hasName();\n    /**\n     * <code>optional string name = 3;</code>\n     *\n     * <pre>\n     **字段名称(忽略大小写)，在mysql中是没有的*\n     * </pre>\n     */\n    String getName();\n    /**\n     * <code>optional string name = 3;</code>\n     *\n     * <pre>\n     **字段名称(忽略大小写)，在mysql中是没有的*\n     * </pre>\n     */\n    com.google.protobuf.ByteString\n        getNameBytes();\n\n    /**\n     * <code>optional bool isKey = 4;</code>\n     *\n     * <pre>\n     **是否是主键*\n     * </pre>\n     */\n    boolean hasIsKey();\n    /**\n     * <code>optional bool isKey = 4;</code>\n     *\n     * <pre>\n     **是否是主键*\n     * </pre>\n     */\n    boolean getIsKey();\n\n    /**\n     * <code>optional bool updated = 5;</code>\n     *\n     * <pre>\n     **如果EventType=UPDATE,用于标识这个字段值是否有修改*\n     * </pre>\n     */\n    boolean hasUpdated();\n    /**\n     * <code>optional bool updated = 5;</code>\n     *\n     * <pre>\n     **如果EventType=UPDATE,用于标识这个字段值是否有修改*\n     * </pre>\n     */\n    boolean getUpdated();\n\n    /**\n     * <code>optional bool isNull = 6 [default = false];</code>\n     *\n     * <pre>\n     ** 标识是否为空  *\n     * </pre>\n     */\n    boolean hasIsNull();\n    /**\n     * <code>optional bool isNull = 6 [default = false];</code>\n     *\n     * <pre>\n     ** 标识是否为空  *\n     * </pre>\n     */\n    boolean getIsNull();\n\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 7;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    java.util.List<Pair>\n        getPropsList();\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 7;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    Pair getProps(int index);\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 7;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    int getPropsCount();\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 7;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    java.util.List<? extends PairOrBuilder>\n        getPropsOrBuilderList();\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 7;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    PairOrBuilder getPropsOrBuilder(int index);\n\n    /**\n     * <code>optional string value = 8;</code>\n     *\n     * <pre>\n     ** 字段值,timestamp,Datetime是一个时间格式的文本 *\n     * </pre>\n     */\n    boolean hasValue();\n    /**\n     * <code>optional string value = 8;</code>\n     *\n     * <pre>\n     ** 字段值,timestamp,Datetime是一个时间格式的文本 *\n     * </pre>\n     */\n    String getValue();\n    /**\n     * <code>optional string value = 8;</code>\n     *\n     * <pre>\n     ** 字段值,timestamp,Datetime是一个时间格式的文本 *\n     * </pre>\n     */\n    com.google.protobuf.ByteString\n        getValueBytes();\n\n    /**\n     * <code>optional int32 length = 9;</code>\n     *\n     * <pre>\n     ** 对应数据对象原始长度 *\n     * </pre>\n     */\n    boolean hasLength();\n    /**\n     * <code>optional int32 length = 9;</code>\n     *\n     * <pre>\n     ** 对应数据对象原始长度 *\n     * </pre>\n     */\n    int getLength();\n\n    /**\n     * <code>optional string mysqlType = 10;</code>\n     *\n     * <pre>\n     **字段mysql类型*\n     * </pre>\n     */\n    boolean hasMysqlType();\n    /**\n     * <code>optional string mysqlType = 10;</code>\n     *\n     * <pre>\n     **字段mysql类型*\n     * </pre>\n     */\n    String getMysqlType();\n    /**\n     * <code>optional string mysqlType = 10;</code>\n     *\n     * <pre>\n     **字段mysql类型*\n     * </pre>\n     */\n    com.google.protobuf.ByteString\n        getMysqlTypeBytes();\n  }\n  /**\n   * Protobuf type {@code com.alibaba.otter.canal.protocol.Column}\n   *\n   * <pre>\n   **每个字段的数据结构*\n   * </pre>\n   */\n  public static final class Column extends\n      com.google.protobuf.GeneratedMessage implements\n      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.Column)\n      ColumnOrBuilder {\n    // Use Column.newBuilder() to construct.\n    private Column(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private Column(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final Column defaultInstance;\n    public static Column getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public Column getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private Column(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 8: {\n              bitField0_ |= 0x00000001;\n              index_ = input.readInt32();\n              break;\n            }\n            case 16: {\n              bitField0_ |= 0x00000002;\n              sqlType_ = input.readInt32();\n              break;\n            }\n            case 26: {\n              com.google.protobuf.ByteString bs = input.readBytes();\n              bitField0_ |= 0x00000004;\n              name_ = bs;\n              break;\n            }\n            case 32: {\n              bitField0_ |= 0x00000008;\n              isKey_ = input.readBool();\n              break;\n            }\n            case 40: {\n              bitField0_ |= 0x00000010;\n              updated_ = input.readBool();\n              break;\n            }\n            case 48: {\n              bitField0_ |= 0x00000020;\n              isNull_ = input.readBool();\n              break;\n            }\n            case 58: {\n              if (!((mutable_bitField0_ & 0x00000040) == 0x00000040)) {\n                props_ = new java.util.ArrayList<Pair>();\n                mutable_bitField0_ |= 0x00000040;\n              }\n              props_.add(input.readMessage(Pair.PARSER, extensionRegistry));\n              break;\n            }\n            case 66: {\n              com.google.protobuf.ByteString bs = input.readBytes();\n              bitField0_ |= 0x00000040;\n              value_ = bs;\n              break;\n            }\n            case 72: {\n              bitField0_ |= 0x00000080;\n              length_ = input.readInt32();\n              break;\n            }\n            case 82: {\n              com.google.protobuf.ByteString bs = input.readBytes();\n              bitField0_ |= 0x00000100;\n              mysqlType_ = bs;\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000040) == 0x00000040)) {\n          props_ = java.util.Collections.unmodifiableList(props_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_Column_descriptor;\n    }\n\n    protected FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_Column_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              Column.class, Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<Column> PARSER =\n        new com.google.protobuf.AbstractParser<Column>() {\n      public Column parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new Column(input, extensionRegistry);\n      }\n    };\n\n    @Override\n    public com.google.protobuf.Parser<Column> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    public static final int INDEX_FIELD_NUMBER = 1;\n    private int index_;\n    /**\n     * <code>optional int32 index = 1;</code>\n     *\n     * <pre>\n     **字段下标*\n     * </pre>\n     */\n    public boolean hasIndex() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>optional int32 index = 1;</code>\n     *\n     * <pre>\n     **字段下标*\n     * </pre>\n     */\n    public int getIndex() {\n      return index_;\n    }\n\n    public static final int SQLTYPE_FIELD_NUMBER = 2;\n    private int sqlType_;\n    /**\n     * <code>optional int32 sqlType = 2;</code>\n     *\n     * <pre>\n     **字段java中类型*\n     * </pre>\n     */\n    public boolean hasSqlType() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>optional int32 sqlType = 2;</code>\n     *\n     * <pre>\n     **字段java中类型*\n     * </pre>\n     */\n    public int getSqlType() {\n      return sqlType_;\n    }\n\n    public static final int NAME_FIELD_NUMBER = 3;\n    private Object name_;\n    /**\n     * <code>optional string name = 3;</code>\n     *\n     * <pre>\n     **字段名称(忽略大小写)，在mysql中是没有的*\n     * </pre>\n     */\n    public boolean hasName() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>optional string name = 3;</code>\n     *\n     * <pre>\n     **字段名称(忽略大小写)，在mysql中是没有的*\n     * </pre>\n     */\n    public String getName() {\n      Object ref = name_;\n      if (ref instanceof String) {\n        return (String) ref;\n      } else {\n        com.google.protobuf.ByteString bs =\n            (com.google.protobuf.ByteString) ref;\n        String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          name_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string name = 3;</code>\n     *\n     * <pre>\n     **字段名称(忽略大小写)，在mysql中是没有的*\n     * </pre>\n     */\n    public com.google.protobuf.ByteString\n        getNameBytes() {\n      Object ref = name_;\n      if (ref instanceof String) {\n        com.google.protobuf.ByteString b =\n            com.google.protobuf.ByteString.copyFromUtf8(\n                (String) ref);\n        name_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int ISKEY_FIELD_NUMBER = 4;\n    private boolean isKey_;\n    /**\n     * <code>optional bool isKey = 4;</code>\n     *\n     * <pre>\n     **是否是主键*\n     * </pre>\n     */\n    public boolean hasIsKey() {\n      return ((bitField0_ & 0x00000008) == 0x00000008);\n    }\n    /**\n     * <code>optional bool isKey = 4;</code>\n     *\n     * <pre>\n     **是否是主键*\n     * </pre>\n     */\n    public boolean getIsKey() {\n      return isKey_;\n    }\n\n    public static final int UPDATED_FIELD_NUMBER = 5;\n    private boolean updated_;\n    /**\n     * <code>optional bool updated = 5;</code>\n     *\n     * <pre>\n     **如果EventType=UPDATE,用于标识这个字段值是否有修改*\n     * </pre>\n     */\n    public boolean hasUpdated() {\n      return ((bitField0_ & 0x00000010) == 0x00000010);\n    }\n    /**\n     * <code>optional bool updated = 5;</code>\n     *\n     * <pre>\n     **如果EventType=UPDATE,用于标识这个字段值是否有修改*\n     * </pre>\n     */\n    public boolean getUpdated() {\n      return updated_;\n    }\n\n    public static final int ISNULL_FIELD_NUMBER = 6;\n    private boolean isNull_;\n    /**\n     * <code>optional bool isNull = 6 [default = false];</code>\n     *\n     * <pre>\n     ** 标识是否为空  *\n     * </pre>\n     */\n    public boolean hasIsNull() {\n      return ((bitField0_ & 0x00000020) == 0x00000020);\n    }\n    /**\n     * <code>optional bool isNull = 6 [default = false];</code>\n     *\n     * <pre>\n     ** 标识是否为空  *\n     * </pre>\n     */\n    public boolean getIsNull() {\n      return isNull_;\n    }\n\n    public static final int PROPS_FIELD_NUMBER = 7;\n    private java.util.List<Pair> props_;\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 7;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public java.util.List<Pair> getPropsList() {\n      return props_;\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 7;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public java.util.List<? extends PairOrBuilder>\n        getPropsOrBuilderList() {\n      return props_;\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 7;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public int getPropsCount() {\n      return props_.size();\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 7;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public Pair getProps(int index) {\n      return props_.get(index);\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 7;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public PairOrBuilder getPropsOrBuilder(\n        int index) {\n      return props_.get(index);\n    }\n\n    public static final int VALUE_FIELD_NUMBER = 8;\n    private Object value_;\n    /**\n     * <code>optional string value = 8;</code>\n     *\n     * <pre>\n     ** 字段值,timestamp,Datetime是一个时间格式的文本 *\n     * </pre>\n     */\n    public boolean hasValue() {\n      return ((bitField0_ & 0x00000040) == 0x00000040);\n    }\n    /**\n     * <code>optional string value = 8;</code>\n     *\n     * <pre>\n     ** 字段值,timestamp,Datetime是一个时间格式的文本 *\n     * </pre>\n     */\n    public String getValue() {\n      Object ref = value_;\n      if (ref instanceof String) {\n        return (String) ref;\n      } else {\n        com.google.protobuf.ByteString bs =\n            (com.google.protobuf.ByteString) ref;\n        String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          value_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string value = 8;</code>\n     *\n     * <pre>\n     ** 字段值,timestamp,Datetime是一个时间格式的文本 *\n     * </pre>\n     */\n    public com.google.protobuf.ByteString\n        getValueBytes() {\n      Object ref = value_;\n      if (ref instanceof String) {\n        com.google.protobuf.ByteString b =\n            com.google.protobuf.ByteString.copyFromUtf8(\n                (String) ref);\n        value_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int LENGTH_FIELD_NUMBER = 9;\n    private int length_;\n    /**\n     * <code>optional int32 length = 9;</code>\n     *\n     * <pre>\n     ** 对应数据对象原始长度 *\n     * </pre>\n     */\n    public boolean hasLength() {\n      return ((bitField0_ & 0x00000080) == 0x00000080);\n    }\n    /**\n     * <code>optional int32 length = 9;</code>\n     *\n     * <pre>\n     ** 对应数据对象原始长度 *\n     * </pre>\n     */\n    public int getLength() {\n      return length_;\n    }\n\n    public static final int MYSQLTYPE_FIELD_NUMBER = 10;\n    private Object mysqlType_;\n    /**\n     * <code>optional string mysqlType = 10;</code>\n     *\n     * <pre>\n     **字段mysql类型*\n     * </pre>\n     */\n    public boolean hasMysqlType() {\n      return ((bitField0_ & 0x00000100) == 0x00000100);\n    }\n    /**\n     * <code>optional string mysqlType = 10;</code>\n     *\n     * <pre>\n     **字段mysql类型*\n     * </pre>\n     */\n    public String getMysqlType() {\n      Object ref = mysqlType_;\n      if (ref instanceof String) {\n        return (String) ref;\n      } else {\n        com.google.protobuf.ByteString bs =\n            (com.google.protobuf.ByteString) ref;\n        String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          mysqlType_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string mysqlType = 10;</code>\n     *\n     * <pre>\n     **字段mysql类型*\n     * </pre>\n     */\n    public com.google.protobuf.ByteString\n        getMysqlTypeBytes() {\n      Object ref = mysqlType_;\n      if (ref instanceof String) {\n        com.google.protobuf.ByteString b =\n            com.google.protobuf.ByteString.copyFromUtf8(\n                (String) ref);\n        mysqlType_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      index_ = 0;\n      sqlType_ = 0;\n      name_ = \"\";\n      isKey_ = false;\n      updated_ = false;\n      isNull_ = false;\n      props_ = java.util.Collections.emptyList();\n      value_ = \"\";\n      length_ = 0;\n      mysqlType_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeInt32(1, index_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeInt32(2, sqlType_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeBytes(3, getNameBytes());\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        output.writeBool(4, isKey_);\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        output.writeBool(5, updated_);\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        output.writeBool(6, isNull_);\n      }\n      for (int i = 0; i < props_.size(); i++) {\n        output.writeMessage(7, props_.get(i));\n      }\n      if (((bitField0_ & 0x00000040) == 0x00000040)) {\n        output.writeBytes(8, getValueBytes());\n      }\n      if (((bitField0_ & 0x00000080) == 0x00000080)) {\n        output.writeInt32(9, length_);\n      }\n      if (((bitField0_ & 0x00000100) == 0x00000100)) {\n        output.writeBytes(10, getMysqlTypeBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(1, index_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(2, sqlType_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(3, getNameBytes());\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBoolSize(4, isKey_);\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBoolSize(5, updated_);\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBoolSize(6, isNull_);\n      }\n      for (int i = 0; i < props_.size(); i++) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(7, props_.get(i));\n      }\n      if (((bitField0_ & 0x00000040) == 0x00000040)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(8, getValueBytes());\n      }\n      if (((bitField0_ & 0x00000080) == 0x00000080)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(9, length_);\n      }\n      if (((bitField0_ & 0x00000100) == 0x00000100)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(10, getMysqlTypeBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @Override\n    protected Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static Column parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static Column parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static Column parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static Column parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static Column parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static Column parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static Column parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static Column parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static Column parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static Column parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(Column prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @Override\n    protected Builder newBuilderForType(\n        BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code com.alibaba.otter.canal.protocol.Column}\n     *\n     * <pre>\n     **每个字段的数据结构*\n     * </pre>\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.Column)\n        ColumnOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_Column_descriptor;\n      }\n\n      protected FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_Column_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                Column.class, Builder.class);\n      }\n\n      // Construct using com.alibaba.otter.canal.protocol.CanalEntry.Column.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getPropsFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        index_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000001);\n        sqlType_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        name_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000004);\n        isKey_ = false;\n        bitField0_ = (bitField0_ & ~0x00000008);\n        updated_ = false;\n        bitField0_ = (bitField0_ & ~0x00000010);\n        isNull_ = false;\n        bitField0_ = (bitField0_ & ~0x00000020);\n        if (propsBuilder_ == null) {\n          props_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000040);\n        } else {\n          propsBuilder_.clear();\n        }\n        value_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000080);\n        length_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000100);\n        mysqlType_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000200);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_Column_descriptor;\n      }\n\n      public Column getDefaultInstanceForType() {\n        return Column.getDefaultInstance();\n      }\n\n      public Column build() {\n        Column result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public Column buildPartial() {\n        Column result = new Column(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.index_ = index_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.sqlType_ = sqlType_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.name_ = name_;\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000008;\n        }\n        result.isKey_ = isKey_;\n        if (((from_bitField0_ & 0x00000010) == 0x00000010)) {\n          to_bitField0_ |= 0x00000010;\n        }\n        result.updated_ = updated_;\n        if (((from_bitField0_ & 0x00000020) == 0x00000020)) {\n          to_bitField0_ |= 0x00000020;\n        }\n        result.isNull_ = isNull_;\n        if (propsBuilder_ == null) {\n          if (((bitField0_ & 0x00000040) == 0x00000040)) {\n            props_ = java.util.Collections.unmodifiableList(props_);\n            bitField0_ = (bitField0_ & ~0x00000040);\n          }\n          result.props_ = props_;\n        } else {\n          result.props_ = propsBuilder_.build();\n        }\n        if (((from_bitField0_ & 0x00000080) == 0x00000080)) {\n          to_bitField0_ |= 0x00000040;\n        }\n        result.value_ = value_;\n        if (((from_bitField0_ & 0x00000100) == 0x00000100)) {\n          to_bitField0_ |= 0x00000080;\n        }\n        result.length_ = length_;\n        if (((from_bitField0_ & 0x00000200) == 0x00000200)) {\n          to_bitField0_ |= 0x00000100;\n        }\n        result.mysqlType_ = mysqlType_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof Column) {\n          return mergeFrom((Column)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(Column other) {\n        if (other == Column.getDefaultInstance()) return this;\n        if (other.hasIndex()) {\n          setIndex(other.getIndex());\n        }\n        if (other.hasSqlType()) {\n          setSqlType(other.getSqlType());\n        }\n        if (other.hasName()) {\n          bitField0_ |= 0x00000004;\n          name_ = other.name_;\n          onChanged();\n        }\n        if (other.hasIsKey()) {\n          setIsKey(other.getIsKey());\n        }\n        if (other.hasUpdated()) {\n          setUpdated(other.getUpdated());\n        }\n        if (other.hasIsNull()) {\n          setIsNull(other.getIsNull());\n        }\n        if (propsBuilder_ == null) {\n          if (!other.props_.isEmpty()) {\n            if (props_.isEmpty()) {\n              props_ = other.props_;\n              bitField0_ = (bitField0_ & ~0x00000040);\n            } else {\n              ensurePropsIsMutable();\n              props_.addAll(other.props_);\n            }\n            onChanged();\n          }\n        } else {\n          if (!other.props_.isEmpty()) {\n            if (propsBuilder_.isEmpty()) {\n              propsBuilder_.dispose();\n              propsBuilder_ = null;\n              props_ = other.props_;\n              bitField0_ = (bitField0_ & ~0x00000040);\n              propsBuilder_ =\n                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n                   getPropsFieldBuilder() : null;\n            } else {\n              propsBuilder_.addAllMessages(other.props_);\n            }\n          }\n        }\n        if (other.hasValue()) {\n          bitField0_ |= 0x00000080;\n          value_ = other.value_;\n          onChanged();\n        }\n        if (other.hasLength()) {\n          setLength(other.getLength());\n        }\n        if (other.hasMysqlType()) {\n          bitField0_ |= 0x00000200;\n          mysqlType_ = other.mysqlType_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        Column parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (Column) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      private int index_ ;\n      /**\n       * <code>optional int32 index = 1;</code>\n       *\n       * <pre>\n       **字段下标*\n       * </pre>\n       */\n      public boolean hasIndex() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>optional int32 index = 1;</code>\n       *\n       * <pre>\n       **字段下标*\n       * </pre>\n       */\n      public int getIndex() {\n        return index_;\n      }\n      /**\n       * <code>optional int32 index = 1;</code>\n       *\n       * <pre>\n       **字段下标*\n       * </pre>\n       */\n      public Builder setIndex(int value) {\n        bitField0_ |= 0x00000001;\n        index_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 index = 1;</code>\n       *\n       * <pre>\n       **字段下标*\n       * </pre>\n       */\n      public Builder clearIndex() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        index_ = 0;\n        onChanged();\n        return this;\n      }\n\n      private int sqlType_ ;\n      /**\n       * <code>optional int32 sqlType = 2;</code>\n       *\n       * <pre>\n       **字段java中类型*\n       * </pre>\n       */\n      public boolean hasSqlType() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>optional int32 sqlType = 2;</code>\n       *\n       * <pre>\n       **字段java中类型*\n       * </pre>\n       */\n      public int getSqlType() {\n        return sqlType_;\n      }\n      /**\n       * <code>optional int32 sqlType = 2;</code>\n       *\n       * <pre>\n       **字段java中类型*\n       * </pre>\n       */\n      public Builder setSqlType(int value) {\n        bitField0_ |= 0x00000002;\n        sqlType_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 sqlType = 2;</code>\n       *\n       * <pre>\n       **字段java中类型*\n       * </pre>\n       */\n      public Builder clearSqlType() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        sqlType_ = 0;\n        onChanged();\n        return this;\n      }\n\n      private Object name_ = \"\";\n      /**\n       * <code>optional string name = 3;</code>\n       *\n       * <pre>\n       **字段名称(忽略大小写)，在mysql中是没有的*\n       * </pre>\n       */\n      public boolean hasName() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>optional string name = 3;</code>\n       *\n       * <pre>\n       **字段名称(忽略大小写)，在mysql中是没有的*\n       * </pre>\n       */\n      public String getName() {\n        Object ref = name_;\n        if (!(ref instanceof String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          String s = bs.toStringUtf8();\n          if (bs.isValidUtf8()) {\n            name_ = s;\n          }\n          return s;\n        } else {\n          return (String) ref;\n        }\n      }\n      /**\n       * <code>optional string name = 3;</code>\n       *\n       * <pre>\n       **字段名称(忽略大小写)，在mysql中是没有的*\n       * </pre>\n       */\n      public com.google.protobuf.ByteString\n          getNameBytes() {\n        Object ref = name_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b =\n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (String) ref);\n          name_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string name = 3;</code>\n       *\n       * <pre>\n       **字段名称(忽略大小写)，在mysql中是没有的*\n       * </pre>\n       */\n      public Builder setName(\n          String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        name_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string name = 3;</code>\n       *\n       * <pre>\n       **字段名称(忽略大小写)，在mysql中是没有的*\n       * </pre>\n       */\n      public Builder clearName() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        name_ = getDefaultInstance().getName();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string name = 3;</code>\n       *\n       * <pre>\n       **字段名称(忽略大小写)，在mysql中是没有的*\n       * </pre>\n       */\n      public Builder setNameBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        name_ = value;\n        onChanged();\n        return this;\n      }\n\n      private boolean isKey_ ;\n      /**\n       * <code>optional bool isKey = 4;</code>\n       *\n       * <pre>\n       **是否是主键*\n       * </pre>\n       */\n      public boolean hasIsKey() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>optional bool isKey = 4;</code>\n       *\n       * <pre>\n       **是否是主键*\n       * </pre>\n       */\n      public boolean getIsKey() {\n        return isKey_;\n      }\n      /**\n       * <code>optional bool isKey = 4;</code>\n       *\n       * <pre>\n       **是否是主键*\n       * </pre>\n       */\n      public Builder setIsKey(boolean value) {\n        bitField0_ |= 0x00000008;\n        isKey_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional bool isKey = 4;</code>\n       *\n       * <pre>\n       **是否是主键*\n       * </pre>\n       */\n      public Builder clearIsKey() {\n        bitField0_ = (bitField0_ & ~0x00000008);\n        isKey_ = false;\n        onChanged();\n        return this;\n      }\n\n      private boolean updated_ ;\n      /**\n       * <code>optional bool updated = 5;</code>\n       *\n       * <pre>\n       **如果EventType=UPDATE,用于标识这个字段值是否有修改*\n       * </pre>\n       */\n      public boolean hasUpdated() {\n        return ((bitField0_ & 0x00000010) == 0x00000010);\n      }\n      /**\n       * <code>optional bool updated = 5;</code>\n       *\n       * <pre>\n       **如果EventType=UPDATE,用于标识这个字段值是否有修改*\n       * </pre>\n       */\n      public boolean getUpdated() {\n        return updated_;\n      }\n      /**\n       * <code>optional bool updated = 5;</code>\n       *\n       * <pre>\n       **如果EventType=UPDATE,用于标识这个字段值是否有修改*\n       * </pre>\n       */\n      public Builder setUpdated(boolean value) {\n        bitField0_ |= 0x00000010;\n        updated_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional bool updated = 5;</code>\n       *\n       * <pre>\n       **如果EventType=UPDATE,用于标识这个字段值是否有修改*\n       * </pre>\n       */\n      public Builder clearUpdated() {\n        bitField0_ = (bitField0_ & ~0x00000010);\n        updated_ = false;\n        onChanged();\n        return this;\n      }\n\n      private boolean isNull_ ;\n      /**\n       * <code>optional bool isNull = 6 [default = false];</code>\n       *\n       * <pre>\n       ** 标识是否为空  *\n       * </pre>\n       */\n      public boolean hasIsNull() {\n        return ((bitField0_ & 0x00000020) == 0x00000020);\n      }\n      /**\n       * <code>optional bool isNull = 6 [default = false];</code>\n       *\n       * <pre>\n       ** 标识是否为空  *\n       * </pre>\n       */\n      public boolean getIsNull() {\n        return isNull_;\n      }\n      /**\n       * <code>optional bool isNull = 6 [default = false];</code>\n       *\n       * <pre>\n       ** 标识是否为空  *\n       * </pre>\n       */\n      public Builder setIsNull(boolean value) {\n        bitField0_ |= 0x00000020;\n        isNull_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional bool isNull = 6 [default = false];</code>\n       *\n       * <pre>\n       ** 标识是否为空  *\n       * </pre>\n       */\n      public Builder clearIsNull() {\n        bitField0_ = (bitField0_ & ~0x00000020);\n        isNull_ = false;\n        onChanged();\n        return this;\n      }\n\n      private java.util.List<Pair> props_ =\n        java.util.Collections.emptyList();\n      private void ensurePropsIsMutable() {\n        if (!((bitField0_ & 0x00000040) == 0x00000040)) {\n          props_ = new java.util.ArrayList<Pair>(props_);\n          bitField0_ |= 0x00000040;\n         }\n      }\n\n      private com.google.protobuf.RepeatedFieldBuilder<\n          Pair, Pair.Builder, PairOrBuilder> propsBuilder_;\n\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 7;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public java.util.List<Pair> getPropsList() {\n        if (propsBuilder_ == null) {\n          return java.util.Collections.unmodifiableList(props_);\n        } else {\n          return propsBuilder_.getMessageList();\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 7;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public int getPropsCount() {\n        if (propsBuilder_ == null) {\n          return props_.size();\n        } else {\n          return propsBuilder_.getCount();\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 7;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Pair getProps(int index) {\n        if (propsBuilder_ == null) {\n          return props_.get(index);\n        } else {\n          return propsBuilder_.getMessage(index);\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 7;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder setProps(\n          int index, Pair value) {\n        if (propsBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensurePropsIsMutable();\n          props_.set(index, value);\n          onChanged();\n        } else {\n          propsBuilder_.setMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 7;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder setProps(\n          int index, Pair.Builder builderForValue) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          props_.set(index, builderForValue.build());\n          onChanged();\n        } else {\n          propsBuilder_.setMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 7;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addProps(Pair value) {\n        if (propsBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensurePropsIsMutable();\n          props_.add(value);\n          onChanged();\n        } else {\n          propsBuilder_.addMessage(value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 7;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addProps(\n          int index, Pair value) {\n        if (propsBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensurePropsIsMutable();\n          props_.add(index, value);\n          onChanged();\n        } else {\n          propsBuilder_.addMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 7;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addProps(\n          Pair.Builder builderForValue) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          props_.add(builderForValue.build());\n          onChanged();\n        } else {\n          propsBuilder_.addMessage(builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 7;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addProps(\n          int index, Pair.Builder builderForValue) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          props_.add(index, builderForValue.build());\n          onChanged();\n        } else {\n          propsBuilder_.addMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 7;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addAllProps(\n          Iterable<? extends Pair> values) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          com.google.protobuf.AbstractMessageLite.Builder.addAll(\n              values, props_);\n          onChanged();\n        } else {\n          propsBuilder_.addAllMessages(values);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 7;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder clearProps() {\n        if (propsBuilder_ == null) {\n          props_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000040);\n          onChanged();\n        } else {\n          propsBuilder_.clear();\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 7;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder removeProps(int index) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          props_.remove(index);\n          onChanged();\n        } else {\n          propsBuilder_.remove(index);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 7;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Pair.Builder getPropsBuilder(\n          int index) {\n        return getPropsFieldBuilder().getBuilder(index);\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 7;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public PairOrBuilder getPropsOrBuilder(\n          int index) {\n        if (propsBuilder_ == null) {\n          return props_.get(index);  } else {\n          return propsBuilder_.getMessageOrBuilder(index);\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 7;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public java.util.List<? extends PairOrBuilder>\n           getPropsOrBuilderList() {\n        if (propsBuilder_ != null) {\n          return propsBuilder_.getMessageOrBuilderList();\n        } else {\n          return java.util.Collections.unmodifiableList(props_);\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 7;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Pair.Builder addPropsBuilder() {\n        return getPropsFieldBuilder().addBuilder(\n            Pair.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 7;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Pair.Builder addPropsBuilder(\n          int index) {\n        return getPropsFieldBuilder().addBuilder(\n            index, Pair.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 7;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public java.util.List<Pair.Builder>\n           getPropsBuilderList() {\n        return getPropsFieldBuilder().getBuilderList();\n      }\n      private com.google.protobuf.RepeatedFieldBuilder<\n          Pair, Pair.Builder, PairOrBuilder>\n          getPropsFieldBuilder() {\n        if (propsBuilder_ == null) {\n          propsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<\n              Pair, Pair.Builder, PairOrBuilder>(\n                  props_,\n                  ((bitField0_ & 0x00000040) == 0x00000040),\n                  getParentForChildren(),\n                  isClean());\n          props_ = null;\n        }\n        return propsBuilder_;\n      }\n\n      private Object value_ = \"\";\n      /**\n       * <code>optional string value = 8;</code>\n       *\n       * <pre>\n       ** 字段值,timestamp,Datetime是一个时间格式的文本 *\n       * </pre>\n       */\n      public boolean hasValue() {\n        return ((bitField0_ & 0x00000080) == 0x00000080);\n      }\n      /**\n       * <code>optional string value = 8;</code>\n       *\n       * <pre>\n       ** 字段值,timestamp,Datetime是一个时间格式的文本 *\n       * </pre>\n       */\n      public String getValue() {\n        Object ref = value_;\n        if (!(ref instanceof String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          String s = bs.toStringUtf8();\n          if (bs.isValidUtf8()) {\n            value_ = s;\n          }\n          return s;\n        } else {\n          return (String) ref;\n        }\n      }\n      /**\n       * <code>optional string value = 8;</code>\n       *\n       * <pre>\n       ** 字段值,timestamp,Datetime是一个时间格式的文本 *\n       * </pre>\n       */\n      public com.google.protobuf.ByteString\n          getValueBytes() {\n        Object ref = value_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b =\n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (String) ref);\n          value_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string value = 8;</code>\n       *\n       * <pre>\n       ** 字段值,timestamp,Datetime是一个时间格式的文本 *\n       * </pre>\n       */\n      public Builder setValue(\n          String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000080;\n        value_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string value = 8;</code>\n       *\n       * <pre>\n       ** 字段值,timestamp,Datetime是一个时间格式的文本 *\n       * </pre>\n       */\n      public Builder clearValue() {\n        bitField0_ = (bitField0_ & ~0x00000080);\n        value_ = getDefaultInstance().getValue();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string value = 8;</code>\n       *\n       * <pre>\n       ** 字段值,timestamp,Datetime是一个时间格式的文本 *\n       * </pre>\n       */\n      public Builder setValueBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000080;\n        value_ = value;\n        onChanged();\n        return this;\n      }\n\n      private int length_ ;\n      /**\n       * <code>optional int32 length = 9;</code>\n       *\n       * <pre>\n       ** 对应数据对象原始长度 *\n       * </pre>\n       */\n      public boolean hasLength() {\n        return ((bitField0_ & 0x00000100) == 0x00000100);\n      }\n      /**\n       * <code>optional int32 length = 9;</code>\n       *\n       * <pre>\n       ** 对应数据对象原始长度 *\n       * </pre>\n       */\n      public int getLength() {\n        return length_;\n      }\n      /**\n       * <code>optional int32 length = 9;</code>\n       *\n       * <pre>\n       ** 对应数据对象原始长度 *\n       * </pre>\n       */\n      public Builder setLength(int value) {\n        bitField0_ |= 0x00000100;\n        length_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 length = 9;</code>\n       *\n       * <pre>\n       ** 对应数据对象原始长度 *\n       * </pre>\n       */\n      public Builder clearLength() {\n        bitField0_ = (bitField0_ & ~0x00000100);\n        length_ = 0;\n        onChanged();\n        return this;\n      }\n\n      private Object mysqlType_ = \"\";\n      /**\n       * <code>optional string mysqlType = 10;</code>\n       *\n       * <pre>\n       **字段mysql类型*\n       * </pre>\n       */\n      public boolean hasMysqlType() {\n        return ((bitField0_ & 0x00000200) == 0x00000200);\n      }\n      /**\n       * <code>optional string mysqlType = 10;</code>\n       *\n       * <pre>\n       **字段mysql类型*\n       * </pre>\n       */\n      public String getMysqlType() {\n        Object ref = mysqlType_;\n        if (!(ref instanceof String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          String s = bs.toStringUtf8();\n          if (bs.isValidUtf8()) {\n            mysqlType_ = s;\n          }\n          return s;\n        } else {\n          return (String) ref;\n        }\n      }\n      /**\n       * <code>optional string mysqlType = 10;</code>\n       *\n       * <pre>\n       **字段mysql类型*\n       * </pre>\n       */\n      public com.google.protobuf.ByteString\n          getMysqlTypeBytes() {\n        Object ref = mysqlType_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b =\n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (String) ref);\n          mysqlType_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string mysqlType = 10;</code>\n       *\n       * <pre>\n       **字段mysql类型*\n       * </pre>\n       */\n      public Builder setMysqlType(\n          String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000200;\n        mysqlType_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string mysqlType = 10;</code>\n       *\n       * <pre>\n       **字段mysql类型*\n       * </pre>\n       */\n      public Builder clearMysqlType() {\n        bitField0_ = (bitField0_ & ~0x00000200);\n        mysqlType_ = getDefaultInstance().getMysqlType();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string mysqlType = 10;</code>\n       *\n       * <pre>\n       **字段mysql类型*\n       * </pre>\n       */\n      public Builder setMysqlTypeBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000200;\n        mysqlType_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.Column)\n    }\n\n    static {\n      defaultInstance = new Column(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.Column)\n  }\n\n  public interface RowDataOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.RowData)\n      com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Column beforeColumns = 1;</code>\n     *\n     * <pre>\n     ** 字段信息，增量数据(修改前,删除前) *\n     * </pre>\n     */\n    java.util.List<Column>\n        getBeforeColumnsList();\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Column beforeColumns = 1;</code>\n     *\n     * <pre>\n     ** 字段信息，增量数据(修改前,删除前) *\n     * </pre>\n     */\n    Column getBeforeColumns(int index);\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Column beforeColumns = 1;</code>\n     *\n     * <pre>\n     ** 字段信息，增量数据(修改前,删除前) *\n     * </pre>\n     */\n    int getBeforeColumnsCount();\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Column beforeColumns = 1;</code>\n     *\n     * <pre>\n     ** 字段信息，增量数据(修改前,删除前) *\n     * </pre>\n     */\n    java.util.List<? extends ColumnOrBuilder>\n        getBeforeColumnsOrBuilderList();\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Column beforeColumns = 1;</code>\n     *\n     * <pre>\n     ** 字段信息，增量数据(修改前,删除前) *\n     * </pre>\n     */\n    ColumnOrBuilder getBeforeColumnsOrBuilder(int index);\n\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Column afterColumns = 2;</code>\n     *\n     * <pre>\n     ** 字段信息，增量数据(修改后,新增后)  *\n     * </pre>\n     */\n    java.util.List<Column>\n        getAfterColumnsList();\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Column afterColumns = 2;</code>\n     *\n     * <pre>\n     ** 字段信息，增量数据(修改后,新增后)  *\n     * </pre>\n     */\n    Column getAfterColumns(int index);\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Column afterColumns = 2;</code>\n     *\n     * <pre>\n     ** 字段信息，增量数据(修改后,新增后)  *\n     * </pre>\n     */\n    int getAfterColumnsCount();\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Column afterColumns = 2;</code>\n     *\n     * <pre>\n     ** 字段信息，增量数据(修改后,新增后)  *\n     * </pre>\n     */\n    java.util.List<? extends ColumnOrBuilder>\n        getAfterColumnsOrBuilderList();\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Column afterColumns = 2;</code>\n     *\n     * <pre>\n     ** 字段信息，增量数据(修改后,新增后)  *\n     * </pre>\n     */\n    ColumnOrBuilder getAfterColumnsOrBuilder(int index);\n\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    java.util.List<Pair>\n        getPropsList();\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    Pair getProps(int index);\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    int getPropsCount();\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    java.util.List<? extends PairOrBuilder>\n        getPropsOrBuilderList();\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    PairOrBuilder getPropsOrBuilder(int index);\n  }\n  /**\n   * Protobuf type {@code com.alibaba.otter.canal.protocol.RowData}\n   */\n  public static final class RowData extends\n      com.google.protobuf.GeneratedMessage implements\n      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.RowData)\n      RowDataOrBuilder {\n    // Use RowData.newBuilder() to construct.\n    private RowData(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private RowData(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final RowData defaultInstance;\n    public static RowData getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public RowData getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private RowData(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n                beforeColumns_ = new java.util.ArrayList<Column>();\n                mutable_bitField0_ |= 0x00000001;\n              }\n              beforeColumns_.add(input.readMessage(Column.PARSER, extensionRegistry));\n              break;\n            }\n            case 18: {\n              if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) {\n                afterColumns_ = new java.util.ArrayList<Column>();\n                mutable_bitField0_ |= 0x00000002;\n              }\n              afterColumns_.add(input.readMessage(Column.PARSER, extensionRegistry));\n              break;\n            }\n            case 26: {\n              if (!((mutable_bitField0_ & 0x00000004) == 0x00000004)) {\n                props_ = new java.util.ArrayList<Pair>();\n                mutable_bitField0_ |= 0x00000004;\n              }\n              props_.add(input.readMessage(Pair.PARSER, extensionRegistry));\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n          beforeColumns_ = java.util.Collections.unmodifiableList(beforeColumns_);\n        }\n        if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) {\n          afterColumns_ = java.util.Collections.unmodifiableList(afterColumns_);\n        }\n        if (((mutable_bitField0_ & 0x00000004) == 0x00000004)) {\n          props_ = java.util.Collections.unmodifiableList(props_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_RowData_descriptor;\n    }\n\n    protected FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_RowData_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              RowData.class, Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<RowData> PARSER =\n        new com.google.protobuf.AbstractParser<RowData>() {\n      public RowData parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new RowData(input, extensionRegistry);\n      }\n    };\n\n    @Override\n    public com.google.protobuf.Parser<RowData> getParserForType() {\n      return PARSER;\n    }\n\n    public static final int BEFORECOLUMNS_FIELD_NUMBER = 1;\n    private java.util.List<Column> beforeColumns_;\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Column beforeColumns = 1;</code>\n     *\n     * <pre>\n     ** 字段信息，增量数据(修改前,删除前) *\n     * </pre>\n     */\n    public java.util.List<Column> getBeforeColumnsList() {\n      return beforeColumns_;\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Column beforeColumns = 1;</code>\n     *\n     * <pre>\n     ** 字段信息，增量数据(修改前,删除前) *\n     * </pre>\n     */\n    public java.util.List<? extends ColumnOrBuilder>\n        getBeforeColumnsOrBuilderList() {\n      return beforeColumns_;\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Column beforeColumns = 1;</code>\n     *\n     * <pre>\n     ** 字段信息，增量数据(修改前,删除前) *\n     * </pre>\n     */\n    public int getBeforeColumnsCount() {\n      return beforeColumns_.size();\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Column beforeColumns = 1;</code>\n     *\n     * <pre>\n     ** 字段信息，增量数据(修改前,删除前) *\n     * </pre>\n     */\n    public Column getBeforeColumns(int index) {\n      return beforeColumns_.get(index);\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Column beforeColumns = 1;</code>\n     *\n     * <pre>\n     ** 字段信息，增量数据(修改前,删除前) *\n     * </pre>\n     */\n    public ColumnOrBuilder getBeforeColumnsOrBuilder(\n        int index) {\n      return beforeColumns_.get(index);\n    }\n\n    public static final int AFTERCOLUMNS_FIELD_NUMBER = 2;\n    private java.util.List<Column> afterColumns_;\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Column afterColumns = 2;</code>\n     *\n     * <pre>\n     ** 字段信息，增量数据(修改后,新增后)  *\n     * </pre>\n     */\n    public java.util.List<Column> getAfterColumnsList() {\n      return afterColumns_;\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Column afterColumns = 2;</code>\n     *\n     * <pre>\n     ** 字段信息，增量数据(修改后,新增后)  *\n     * </pre>\n     */\n    public java.util.List<? extends ColumnOrBuilder>\n        getAfterColumnsOrBuilderList() {\n      return afterColumns_;\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Column afterColumns = 2;</code>\n     *\n     * <pre>\n     ** 字段信息，增量数据(修改后,新增后)  *\n     * </pre>\n     */\n    public int getAfterColumnsCount() {\n      return afterColumns_.size();\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Column afterColumns = 2;</code>\n     *\n     * <pre>\n     ** 字段信息，增量数据(修改后,新增后)  *\n     * </pre>\n     */\n    public Column getAfterColumns(int index) {\n      return afterColumns_.get(index);\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Column afterColumns = 2;</code>\n     *\n     * <pre>\n     ** 字段信息，增量数据(修改后,新增后)  *\n     * </pre>\n     */\n    public ColumnOrBuilder getAfterColumnsOrBuilder(\n        int index) {\n      return afterColumns_.get(index);\n    }\n\n    public static final int PROPS_FIELD_NUMBER = 3;\n    private java.util.List<Pair> props_;\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public java.util.List<Pair> getPropsList() {\n      return props_;\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public java.util.List<? extends PairOrBuilder>\n        getPropsOrBuilderList() {\n      return props_;\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public int getPropsCount() {\n      return props_.size();\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public Pair getProps(int index) {\n      return props_.get(index);\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public PairOrBuilder getPropsOrBuilder(\n        int index) {\n      return props_.get(index);\n    }\n\n    private void initFields() {\n      beforeColumns_ = java.util.Collections.emptyList();\n      afterColumns_ = java.util.Collections.emptyList();\n      props_ = java.util.Collections.emptyList();\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      for (int i = 0; i < beforeColumns_.size(); i++) {\n        output.writeMessage(1, beforeColumns_.get(i));\n      }\n      for (int i = 0; i < afterColumns_.size(); i++) {\n        output.writeMessage(2, afterColumns_.get(i));\n      }\n      for (int i = 0; i < props_.size(); i++) {\n        output.writeMessage(3, props_.get(i));\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      for (int i = 0; i < beforeColumns_.size(); i++) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(1, beforeColumns_.get(i));\n      }\n      for (int i = 0; i < afterColumns_.size(); i++) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(2, afterColumns_.get(i));\n      }\n      for (int i = 0; i < props_.size(); i++) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(3, props_.get(i));\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @Override\n    protected Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static RowData parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static RowData parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static RowData parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static RowData parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static RowData parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static RowData parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static RowData parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static RowData parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static RowData parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static RowData parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(RowData prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @Override\n    protected Builder newBuilderForType(\n        BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code com.alibaba.otter.canal.protocol.RowData}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.RowData)\n        RowDataOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_RowData_descriptor;\n      }\n\n      protected FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_RowData_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                RowData.class, Builder.class);\n      }\n\n      // Construct using com.alibaba.otter.canal.protocol.CanalEntry.RowData.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getBeforeColumnsFieldBuilder();\n          getAfterColumnsFieldBuilder();\n          getPropsFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        if (beforeColumnsBuilder_ == null) {\n          beforeColumns_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000001);\n        } else {\n          beforeColumnsBuilder_.clear();\n        }\n        if (afterColumnsBuilder_ == null) {\n          afterColumns_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000002);\n        } else {\n          afterColumnsBuilder_.clear();\n        }\n        if (propsBuilder_ == null) {\n          props_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000004);\n        } else {\n          propsBuilder_.clear();\n        }\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_RowData_descriptor;\n      }\n\n      public RowData getDefaultInstanceForType() {\n        return RowData.getDefaultInstance();\n      }\n\n      public RowData build() {\n        RowData result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public RowData buildPartial() {\n        RowData result = new RowData(this);\n        int from_bitField0_ = bitField0_;\n        if (beforeColumnsBuilder_ == null) {\n          if (((bitField0_ & 0x00000001) == 0x00000001)) {\n            beforeColumns_ = java.util.Collections.unmodifiableList(beforeColumns_);\n            bitField0_ = (bitField0_ & ~0x00000001);\n          }\n          result.beforeColumns_ = beforeColumns_;\n        } else {\n          result.beforeColumns_ = beforeColumnsBuilder_.build();\n        }\n        if (afterColumnsBuilder_ == null) {\n          if (((bitField0_ & 0x00000002) == 0x00000002)) {\n            afterColumns_ = java.util.Collections.unmodifiableList(afterColumns_);\n            bitField0_ = (bitField0_ & ~0x00000002);\n          }\n          result.afterColumns_ = afterColumns_;\n        } else {\n          result.afterColumns_ = afterColumnsBuilder_.build();\n        }\n        if (propsBuilder_ == null) {\n          if (((bitField0_ & 0x00000004) == 0x00000004)) {\n            props_ = java.util.Collections.unmodifiableList(props_);\n            bitField0_ = (bitField0_ & ~0x00000004);\n          }\n          result.props_ = props_;\n        } else {\n          result.props_ = propsBuilder_.build();\n        }\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof RowData) {\n          return mergeFrom((RowData)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(RowData other) {\n        if (other == RowData.getDefaultInstance()) return this;\n        if (beforeColumnsBuilder_ == null) {\n          if (!other.beforeColumns_.isEmpty()) {\n            if (beforeColumns_.isEmpty()) {\n              beforeColumns_ = other.beforeColumns_;\n              bitField0_ = (bitField0_ & ~0x00000001);\n            } else {\n              ensureBeforeColumnsIsMutable();\n              beforeColumns_.addAll(other.beforeColumns_);\n            }\n            onChanged();\n          }\n        } else {\n          if (!other.beforeColumns_.isEmpty()) {\n            if (beforeColumnsBuilder_.isEmpty()) {\n              beforeColumnsBuilder_.dispose();\n              beforeColumnsBuilder_ = null;\n              beforeColumns_ = other.beforeColumns_;\n              bitField0_ = (bitField0_ & ~0x00000001);\n              beforeColumnsBuilder_ =\n                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n                   getBeforeColumnsFieldBuilder() : null;\n            } else {\n              beforeColumnsBuilder_.addAllMessages(other.beforeColumns_);\n            }\n          }\n        }\n        if (afterColumnsBuilder_ == null) {\n          if (!other.afterColumns_.isEmpty()) {\n            if (afterColumns_.isEmpty()) {\n              afterColumns_ = other.afterColumns_;\n              bitField0_ = (bitField0_ & ~0x00000002);\n            } else {\n              ensureAfterColumnsIsMutable();\n              afterColumns_.addAll(other.afterColumns_);\n            }\n            onChanged();\n          }\n        } else {\n          if (!other.afterColumns_.isEmpty()) {\n            if (afterColumnsBuilder_.isEmpty()) {\n              afterColumnsBuilder_.dispose();\n              afterColumnsBuilder_ = null;\n              afterColumns_ = other.afterColumns_;\n              bitField0_ = (bitField0_ & ~0x00000002);\n              afterColumnsBuilder_ =\n                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n                   getAfterColumnsFieldBuilder() : null;\n            } else {\n              afterColumnsBuilder_.addAllMessages(other.afterColumns_);\n            }\n          }\n        }\n        if (propsBuilder_ == null) {\n          if (!other.props_.isEmpty()) {\n            if (props_.isEmpty()) {\n              props_ = other.props_;\n              bitField0_ = (bitField0_ & ~0x00000004);\n            } else {\n              ensurePropsIsMutable();\n              props_.addAll(other.props_);\n            }\n            onChanged();\n          }\n        } else {\n          if (!other.props_.isEmpty()) {\n            if (propsBuilder_.isEmpty()) {\n              propsBuilder_.dispose();\n              propsBuilder_ = null;\n              props_ = other.props_;\n              bitField0_ = (bitField0_ & ~0x00000004);\n              propsBuilder_ =\n                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n                   getPropsFieldBuilder() : null;\n            } else {\n              propsBuilder_.addAllMessages(other.props_);\n            }\n          }\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        RowData parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (RowData) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      private java.util.List<Column> beforeColumns_ =\n        java.util.Collections.emptyList();\n      private void ensureBeforeColumnsIsMutable() {\n        if (!((bitField0_ & 0x00000001) == 0x00000001)) {\n          beforeColumns_ = new java.util.ArrayList<Column>(beforeColumns_);\n          bitField0_ |= 0x00000001;\n         }\n      }\n\n      private com.google.protobuf.RepeatedFieldBuilder<\n          Column, Column.Builder, ColumnOrBuilder> beforeColumnsBuilder_;\n\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column beforeColumns = 1;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改前,删除前) *\n       * </pre>\n       */\n      public java.util.List<Column> getBeforeColumnsList() {\n        if (beforeColumnsBuilder_ == null) {\n          return java.util.Collections.unmodifiableList(beforeColumns_);\n        } else {\n          return beforeColumnsBuilder_.getMessageList();\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column beforeColumns = 1;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改前,删除前) *\n       * </pre>\n       */\n      public int getBeforeColumnsCount() {\n        if (beforeColumnsBuilder_ == null) {\n          return beforeColumns_.size();\n        } else {\n          return beforeColumnsBuilder_.getCount();\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column beforeColumns = 1;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改前,删除前) *\n       * </pre>\n       */\n      public Column getBeforeColumns(int index) {\n        if (beforeColumnsBuilder_ == null) {\n          return beforeColumns_.get(index);\n        } else {\n          return beforeColumnsBuilder_.getMessage(index);\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column beforeColumns = 1;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改前,删除前) *\n       * </pre>\n       */\n      public Builder setBeforeColumns(\n          int index, Column value) {\n        if (beforeColumnsBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureBeforeColumnsIsMutable();\n          beforeColumns_.set(index, value);\n          onChanged();\n        } else {\n          beforeColumnsBuilder_.setMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column beforeColumns = 1;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改前,删除前) *\n       * </pre>\n       */\n      public Builder setBeforeColumns(\n          int index, Column.Builder builderForValue) {\n        if (beforeColumnsBuilder_ == null) {\n          ensureBeforeColumnsIsMutable();\n          beforeColumns_.set(index, builderForValue.build());\n          onChanged();\n        } else {\n          beforeColumnsBuilder_.setMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column beforeColumns = 1;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改前,删除前) *\n       * </pre>\n       */\n      public Builder addBeforeColumns(Column value) {\n        if (beforeColumnsBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureBeforeColumnsIsMutable();\n          beforeColumns_.add(value);\n          onChanged();\n        } else {\n          beforeColumnsBuilder_.addMessage(value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column beforeColumns = 1;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改前,删除前) *\n       * </pre>\n       */\n      public Builder addBeforeColumns(\n          int index, Column value) {\n        if (beforeColumnsBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureBeforeColumnsIsMutable();\n          beforeColumns_.add(index, value);\n          onChanged();\n        } else {\n          beforeColumnsBuilder_.addMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column beforeColumns = 1;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改前,删除前) *\n       * </pre>\n       */\n      public Builder addBeforeColumns(\n          Column.Builder builderForValue) {\n        if (beforeColumnsBuilder_ == null) {\n          ensureBeforeColumnsIsMutable();\n          beforeColumns_.add(builderForValue.build());\n          onChanged();\n        } else {\n          beforeColumnsBuilder_.addMessage(builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column beforeColumns = 1;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改前,删除前) *\n       * </pre>\n       */\n      public Builder addBeforeColumns(\n          int index, Column.Builder builderForValue) {\n        if (beforeColumnsBuilder_ == null) {\n          ensureBeforeColumnsIsMutable();\n          beforeColumns_.add(index, builderForValue.build());\n          onChanged();\n        } else {\n          beforeColumnsBuilder_.addMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column beforeColumns = 1;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改前,删除前) *\n       * </pre>\n       */\n      public Builder addAllBeforeColumns(\n          Iterable<? extends Column> values) {\n        if (beforeColumnsBuilder_ == null) {\n          ensureBeforeColumnsIsMutable();\n          com.google.protobuf.AbstractMessageLite.Builder.addAll(\n              values, beforeColumns_);\n          onChanged();\n        } else {\n          beforeColumnsBuilder_.addAllMessages(values);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column beforeColumns = 1;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改前,删除前) *\n       * </pre>\n       */\n      public Builder clearBeforeColumns() {\n        if (beforeColumnsBuilder_ == null) {\n          beforeColumns_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000001);\n          onChanged();\n        } else {\n          beforeColumnsBuilder_.clear();\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column beforeColumns = 1;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改前,删除前) *\n       * </pre>\n       */\n      public Builder removeBeforeColumns(int index) {\n        if (beforeColumnsBuilder_ == null) {\n          ensureBeforeColumnsIsMutable();\n          beforeColumns_.remove(index);\n          onChanged();\n        } else {\n          beforeColumnsBuilder_.remove(index);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column beforeColumns = 1;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改前,删除前) *\n       * </pre>\n       */\n      public Column.Builder getBeforeColumnsBuilder(\n          int index) {\n        return getBeforeColumnsFieldBuilder().getBuilder(index);\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column beforeColumns = 1;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改前,删除前) *\n       * </pre>\n       */\n      public ColumnOrBuilder getBeforeColumnsOrBuilder(\n          int index) {\n        if (beforeColumnsBuilder_ == null) {\n          return beforeColumns_.get(index);  } else {\n          return beforeColumnsBuilder_.getMessageOrBuilder(index);\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column beforeColumns = 1;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改前,删除前) *\n       * </pre>\n       */\n      public java.util.List<? extends ColumnOrBuilder>\n           getBeforeColumnsOrBuilderList() {\n        if (beforeColumnsBuilder_ != null) {\n          return beforeColumnsBuilder_.getMessageOrBuilderList();\n        } else {\n          return java.util.Collections.unmodifiableList(beforeColumns_);\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column beforeColumns = 1;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改前,删除前) *\n       * </pre>\n       */\n      public Column.Builder addBeforeColumnsBuilder() {\n        return getBeforeColumnsFieldBuilder().addBuilder(\n            Column.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column beforeColumns = 1;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改前,删除前) *\n       * </pre>\n       */\n      public Column.Builder addBeforeColumnsBuilder(\n          int index) {\n        return getBeforeColumnsFieldBuilder().addBuilder(\n            index, Column.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column beforeColumns = 1;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改前,删除前) *\n       * </pre>\n       */\n      public java.util.List<Column.Builder>\n           getBeforeColumnsBuilderList() {\n        return getBeforeColumnsFieldBuilder().getBuilderList();\n      }\n      private com.google.protobuf.RepeatedFieldBuilder<\n          Column, Column.Builder, ColumnOrBuilder>\n          getBeforeColumnsFieldBuilder() {\n        if (beforeColumnsBuilder_ == null) {\n          beforeColumnsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<\n              Column, Column.Builder, ColumnOrBuilder>(\n                  beforeColumns_,\n                  ((bitField0_ & 0x00000001) == 0x00000001),\n                  getParentForChildren(),\n                  isClean());\n          beforeColumns_ = null;\n        }\n        return beforeColumnsBuilder_;\n      }\n\n      private java.util.List<Column> afterColumns_ =\n        java.util.Collections.emptyList();\n      private void ensureAfterColumnsIsMutable() {\n        if (!((bitField0_ & 0x00000002) == 0x00000002)) {\n          afterColumns_ = new java.util.ArrayList<Column>(afterColumns_);\n          bitField0_ |= 0x00000002;\n         }\n      }\n\n      private com.google.protobuf.RepeatedFieldBuilder<\n          Column, Column.Builder, ColumnOrBuilder> afterColumnsBuilder_;\n\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column afterColumns = 2;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改后,新增后)  *\n       * </pre>\n       */\n      public java.util.List<Column> getAfterColumnsList() {\n        if (afterColumnsBuilder_ == null) {\n          return java.util.Collections.unmodifiableList(afterColumns_);\n        } else {\n          return afterColumnsBuilder_.getMessageList();\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column afterColumns = 2;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改后,新增后)  *\n       * </pre>\n       */\n      public int getAfterColumnsCount() {\n        if (afterColumnsBuilder_ == null) {\n          return afterColumns_.size();\n        } else {\n          return afterColumnsBuilder_.getCount();\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column afterColumns = 2;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改后,新增后)  *\n       * </pre>\n       */\n      public Column getAfterColumns(int index) {\n        if (afterColumnsBuilder_ == null) {\n          return afterColumns_.get(index);\n        } else {\n          return afterColumnsBuilder_.getMessage(index);\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column afterColumns = 2;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改后,新增后)  *\n       * </pre>\n       */\n      public Builder setAfterColumns(\n          int index, Column value) {\n        if (afterColumnsBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureAfterColumnsIsMutable();\n          afterColumns_.set(index, value);\n          onChanged();\n        } else {\n          afterColumnsBuilder_.setMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column afterColumns = 2;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改后,新增后)  *\n       * </pre>\n       */\n      public Builder setAfterColumns(\n          int index, Column.Builder builderForValue) {\n        if (afterColumnsBuilder_ == null) {\n          ensureAfterColumnsIsMutable();\n          afterColumns_.set(index, builderForValue.build());\n          onChanged();\n        } else {\n          afterColumnsBuilder_.setMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column afterColumns = 2;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改后,新增后)  *\n       * </pre>\n       */\n      public Builder addAfterColumns(Column value) {\n        if (afterColumnsBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureAfterColumnsIsMutable();\n          afterColumns_.add(value);\n          onChanged();\n        } else {\n          afterColumnsBuilder_.addMessage(value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column afterColumns = 2;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改后,新增后)  *\n       * </pre>\n       */\n      public Builder addAfterColumns(\n          int index, Column value) {\n        if (afterColumnsBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureAfterColumnsIsMutable();\n          afterColumns_.add(index, value);\n          onChanged();\n        } else {\n          afterColumnsBuilder_.addMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column afterColumns = 2;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改后,新增后)  *\n       * </pre>\n       */\n      public Builder addAfterColumns(\n          Column.Builder builderForValue) {\n        if (afterColumnsBuilder_ == null) {\n          ensureAfterColumnsIsMutable();\n          afterColumns_.add(builderForValue.build());\n          onChanged();\n        } else {\n          afterColumnsBuilder_.addMessage(builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column afterColumns = 2;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改后,新增后)  *\n       * </pre>\n       */\n      public Builder addAfterColumns(\n          int index, Column.Builder builderForValue) {\n        if (afterColumnsBuilder_ == null) {\n          ensureAfterColumnsIsMutable();\n          afterColumns_.add(index, builderForValue.build());\n          onChanged();\n        } else {\n          afterColumnsBuilder_.addMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column afterColumns = 2;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改后,新增后)  *\n       * </pre>\n       */\n      public Builder addAllAfterColumns(\n          Iterable<? extends Column> values) {\n        if (afterColumnsBuilder_ == null) {\n          ensureAfterColumnsIsMutable();\n          com.google.protobuf.AbstractMessageLite.Builder.addAll(\n              values, afterColumns_);\n          onChanged();\n        } else {\n          afterColumnsBuilder_.addAllMessages(values);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column afterColumns = 2;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改后,新增后)  *\n       * </pre>\n       */\n      public Builder clearAfterColumns() {\n        if (afterColumnsBuilder_ == null) {\n          afterColumns_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000002);\n          onChanged();\n        } else {\n          afterColumnsBuilder_.clear();\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column afterColumns = 2;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改后,新增后)  *\n       * </pre>\n       */\n      public Builder removeAfterColumns(int index) {\n        if (afterColumnsBuilder_ == null) {\n          ensureAfterColumnsIsMutable();\n          afterColumns_.remove(index);\n          onChanged();\n        } else {\n          afterColumnsBuilder_.remove(index);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column afterColumns = 2;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改后,新增后)  *\n       * </pre>\n       */\n      public Column.Builder getAfterColumnsBuilder(\n          int index) {\n        return getAfterColumnsFieldBuilder().getBuilder(index);\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column afterColumns = 2;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改后,新增后)  *\n       * </pre>\n       */\n      public ColumnOrBuilder getAfterColumnsOrBuilder(\n          int index) {\n        if (afterColumnsBuilder_ == null) {\n          return afterColumns_.get(index);  } else {\n          return afterColumnsBuilder_.getMessageOrBuilder(index);\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column afterColumns = 2;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改后,新增后)  *\n       * </pre>\n       */\n      public java.util.List<? extends ColumnOrBuilder>\n           getAfterColumnsOrBuilderList() {\n        if (afterColumnsBuilder_ != null) {\n          return afterColumnsBuilder_.getMessageOrBuilderList();\n        } else {\n          return java.util.Collections.unmodifiableList(afterColumns_);\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column afterColumns = 2;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改后,新增后)  *\n       * </pre>\n       */\n      public Column.Builder addAfterColumnsBuilder() {\n        return getAfterColumnsFieldBuilder().addBuilder(\n            Column.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column afterColumns = 2;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改后,新增后)  *\n       * </pre>\n       */\n      public Column.Builder addAfterColumnsBuilder(\n          int index) {\n        return getAfterColumnsFieldBuilder().addBuilder(\n            index, Column.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Column afterColumns = 2;</code>\n       *\n       * <pre>\n       ** 字段信息，增量数据(修改后,新增后)  *\n       * </pre>\n       */\n      public java.util.List<Column.Builder>\n           getAfterColumnsBuilderList() {\n        return getAfterColumnsFieldBuilder().getBuilderList();\n      }\n      private com.google.protobuf.RepeatedFieldBuilder<\n          Column, Column.Builder, ColumnOrBuilder>\n          getAfterColumnsFieldBuilder() {\n        if (afterColumnsBuilder_ == null) {\n          afterColumnsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<\n              Column, Column.Builder, ColumnOrBuilder>(\n                  afterColumns_,\n                  ((bitField0_ & 0x00000002) == 0x00000002),\n                  getParentForChildren(),\n                  isClean());\n          afterColumns_ = null;\n        }\n        return afterColumnsBuilder_;\n      }\n\n      private java.util.List<Pair> props_ =\n        java.util.Collections.emptyList();\n      private void ensurePropsIsMutable() {\n        if (!((bitField0_ & 0x00000004) == 0x00000004)) {\n          props_ = new java.util.ArrayList<Pair>(props_);\n          bitField0_ |= 0x00000004;\n         }\n      }\n\n      private com.google.protobuf.RepeatedFieldBuilder<\n          Pair, Pair.Builder, PairOrBuilder> propsBuilder_;\n\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public java.util.List<Pair> getPropsList() {\n        if (propsBuilder_ == null) {\n          return java.util.Collections.unmodifiableList(props_);\n        } else {\n          return propsBuilder_.getMessageList();\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public int getPropsCount() {\n        if (propsBuilder_ == null) {\n          return props_.size();\n        } else {\n          return propsBuilder_.getCount();\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Pair getProps(int index) {\n        if (propsBuilder_ == null) {\n          return props_.get(index);\n        } else {\n          return propsBuilder_.getMessage(index);\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder setProps(\n          int index, Pair value) {\n        if (propsBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensurePropsIsMutable();\n          props_.set(index, value);\n          onChanged();\n        } else {\n          propsBuilder_.setMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder setProps(\n          int index, Pair.Builder builderForValue) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          props_.set(index, builderForValue.build());\n          onChanged();\n        } else {\n          propsBuilder_.setMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addProps(Pair value) {\n        if (propsBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensurePropsIsMutable();\n          props_.add(value);\n          onChanged();\n        } else {\n          propsBuilder_.addMessage(value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addProps(\n          int index, Pair value) {\n        if (propsBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensurePropsIsMutable();\n          props_.add(index, value);\n          onChanged();\n        } else {\n          propsBuilder_.addMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addProps(\n          Pair.Builder builderForValue) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          props_.add(builderForValue.build());\n          onChanged();\n        } else {\n          propsBuilder_.addMessage(builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addProps(\n          int index, Pair.Builder builderForValue) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          props_.add(index, builderForValue.build());\n          onChanged();\n        } else {\n          propsBuilder_.addMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addAllProps(\n          Iterable<? extends Pair> values) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          com.google.protobuf.AbstractMessageLite.Builder.addAll(\n              values, props_);\n          onChanged();\n        } else {\n          propsBuilder_.addAllMessages(values);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder clearProps() {\n        if (propsBuilder_ == null) {\n          props_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000004);\n          onChanged();\n        } else {\n          propsBuilder_.clear();\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder removeProps(int index) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          props_.remove(index);\n          onChanged();\n        } else {\n          propsBuilder_.remove(index);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Pair.Builder getPropsBuilder(\n          int index) {\n        return getPropsFieldBuilder().getBuilder(index);\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public PairOrBuilder getPropsOrBuilder(\n          int index) {\n        if (propsBuilder_ == null) {\n          return props_.get(index);  } else {\n          return propsBuilder_.getMessageOrBuilder(index);\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public java.util.List<? extends PairOrBuilder>\n           getPropsOrBuilderList() {\n        if (propsBuilder_ != null) {\n          return propsBuilder_.getMessageOrBuilderList();\n        } else {\n          return java.util.Collections.unmodifiableList(props_);\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Pair.Builder addPropsBuilder() {\n        return getPropsFieldBuilder().addBuilder(\n            Pair.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Pair.Builder addPropsBuilder(\n          int index) {\n        return getPropsFieldBuilder().addBuilder(\n            index, Pair.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public java.util.List<Pair.Builder>\n           getPropsBuilderList() {\n        return getPropsFieldBuilder().getBuilderList();\n      }\n      private com.google.protobuf.RepeatedFieldBuilder<\n          Pair, Pair.Builder, PairOrBuilder>\n          getPropsFieldBuilder() {\n        if (propsBuilder_ == null) {\n          propsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<\n              Pair, Pair.Builder, PairOrBuilder>(\n                  props_,\n                  ((bitField0_ & 0x00000004) == 0x00000004),\n                  getParentForChildren(),\n                  isClean());\n          props_ = null;\n        }\n        return propsBuilder_;\n      }\n\n      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.RowData)\n    }\n\n    static {\n      defaultInstance = new RowData(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.RowData)\n  }\n\n  public interface RowChangeOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.RowChange)\n      com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <code>optional int64 tableId = 1;</code>\n     *\n     * <pre>\n     **tableId,由数据库产生*\n     * </pre>\n     */\n    boolean hasTableId();\n    /**\n     * <code>optional int64 tableId = 1;</code>\n     *\n     * <pre>\n     **tableId,由数据库产生*\n     * </pre>\n     */\n    long getTableId();\n\n    /**\n     * <code>optional .com.alibaba.otter.canal.protocol.EventType eventType = 2 [default = UPDATE];</code>\n     *\n     * <pre>\n     **数据变更类型*\n     * </pre>\n     */\n    boolean hasEventType();\n    /**\n     * <code>optional .com.alibaba.otter.canal.protocol.EventType eventType = 2 [default = UPDATE];</code>\n     *\n     * <pre>\n     **数据变更类型*\n     * </pre>\n     */\n    EventType getEventType();\n\n    /**\n     * <code>optional bool isDdl = 10 [default = false];</code>\n     *\n     * <pre>\n     ** 标识是否是ddl语句  *\n     * </pre>\n     */\n    boolean hasIsDdl();\n    /**\n     * <code>optional bool isDdl = 10 [default = false];</code>\n     *\n     * <pre>\n     ** 标识是否是ddl语句  *\n     * </pre>\n     */\n    boolean getIsDdl();\n\n    /**\n     * <code>optional string sql = 11;</code>\n     *\n     * <pre>\n     ** ddl/query的sql语句  *\n     * </pre>\n     */\n    boolean hasSql();\n    /**\n     * <code>optional string sql = 11;</code>\n     *\n     * <pre>\n     ** ddl/query的sql语句  *\n     * </pre>\n     */\n    String getSql();\n    /**\n     * <code>optional string sql = 11;</code>\n     *\n     * <pre>\n     ** ddl/query的sql语句  *\n     * </pre>\n     */\n    com.google.protobuf.ByteString\n        getSqlBytes();\n\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.RowData rowDatas = 12;</code>\n     *\n     * <pre>\n     ** 一次数据库变更可能存在多行  *\n     * </pre>\n     */\n    java.util.List<RowData>\n        getRowDatasList();\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.RowData rowDatas = 12;</code>\n     *\n     * <pre>\n     ** 一次数据库变更可能存在多行  *\n     * </pre>\n     */\n    RowData getRowDatas(int index);\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.RowData rowDatas = 12;</code>\n     *\n     * <pre>\n     ** 一次数据库变更可能存在多行  *\n     * </pre>\n     */\n    int getRowDatasCount();\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.RowData rowDatas = 12;</code>\n     *\n     * <pre>\n     ** 一次数据库变更可能存在多行  *\n     * </pre>\n     */\n    java.util.List<? extends RowDataOrBuilder>\n        getRowDatasOrBuilderList();\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.RowData rowDatas = 12;</code>\n     *\n     * <pre>\n     ** 一次数据库变更可能存在多行  *\n     * </pre>\n     */\n    RowDataOrBuilder getRowDatasOrBuilder(int index);\n\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 13;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    java.util.List<Pair>\n        getPropsList();\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 13;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    Pair getProps(int index);\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 13;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    int getPropsCount();\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 13;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    java.util.List<? extends PairOrBuilder>\n        getPropsOrBuilderList();\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 13;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    PairOrBuilder getPropsOrBuilder(int index);\n\n    /**\n     * <code>optional string ddlSchemaName = 14;</code>\n     *\n     * <pre>\n     ** ddl/query的schemaName，会存在跨库ddl，需要保留执行ddl的当前schemaName  *\n     * </pre>\n     */\n    boolean hasDdlSchemaName();\n    /**\n     * <code>optional string ddlSchemaName = 14;</code>\n     *\n     * <pre>\n     ** ddl/query的schemaName，会存在跨库ddl，需要保留执行ddl的当前schemaName  *\n     * </pre>\n     */\n    String getDdlSchemaName();\n    /**\n     * <code>optional string ddlSchemaName = 14;</code>\n     *\n     * <pre>\n     ** ddl/query的schemaName，会存在跨库ddl，需要保留执行ddl的当前schemaName  *\n     * </pre>\n     */\n    com.google.protobuf.ByteString\n        getDdlSchemaNameBytes();\n  }\n  /**\n   * Protobuf type {@code com.alibaba.otter.canal.protocol.RowChange}\n   *\n   * <pre>\n   **message row 每行变更数据的数据结构*\n   * </pre>\n   */\n  public static final class RowChange extends\n      com.google.protobuf.GeneratedMessage implements\n      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.RowChange)\n      RowChangeOrBuilder {\n    // Use RowChange.newBuilder() to construct.\n    private RowChange(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private RowChange(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final RowChange defaultInstance;\n    public static RowChange getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public RowChange getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private RowChange(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 8: {\n              bitField0_ |= 0x00000001;\n              tableId_ = input.readInt64();\n              break;\n            }\n            case 16: {\n              int rawValue = input.readEnum();\n              EventType value = EventType.valueOf(rawValue);\n              if (value == null) {\n                unknownFields.mergeVarintField(2, rawValue);\n              } else {\n                bitField0_ |= 0x00000002;\n                eventType_ = value;\n              }\n              break;\n            }\n            case 80: {\n              bitField0_ |= 0x00000004;\n              isDdl_ = input.readBool();\n              break;\n            }\n            case 90: {\n              com.google.protobuf.ByteString bs = input.readBytes();\n              bitField0_ |= 0x00000008;\n              sql_ = bs;\n              break;\n            }\n            case 98: {\n              if (!((mutable_bitField0_ & 0x00000010) == 0x00000010)) {\n                rowDatas_ = new java.util.ArrayList<RowData>();\n                mutable_bitField0_ |= 0x00000010;\n              }\n              rowDatas_.add(input.readMessage(RowData.PARSER, extensionRegistry));\n              break;\n            }\n            case 106: {\n              if (!((mutable_bitField0_ & 0x00000020) == 0x00000020)) {\n                props_ = new java.util.ArrayList<Pair>();\n                mutable_bitField0_ |= 0x00000020;\n              }\n              props_.add(input.readMessage(Pair.PARSER, extensionRegistry));\n              break;\n            }\n            case 114: {\n              com.google.protobuf.ByteString bs = input.readBytes();\n              bitField0_ |= 0x00000010;\n              ddlSchemaName_ = bs;\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000010) == 0x00000010)) {\n          rowDatas_ = java.util.Collections.unmodifiableList(rowDatas_);\n        }\n        if (((mutable_bitField0_ & 0x00000020) == 0x00000020)) {\n          props_ = java.util.Collections.unmodifiableList(props_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_RowChange_descriptor;\n    }\n\n    protected FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_RowChange_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              RowChange.class, Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<RowChange> PARSER =\n        new com.google.protobuf.AbstractParser<RowChange>() {\n      public RowChange parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new RowChange(input, extensionRegistry);\n      }\n    };\n\n    @Override\n    public com.google.protobuf.Parser<RowChange> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    public static final int TABLEID_FIELD_NUMBER = 1;\n    private long tableId_;\n    /**\n     * <code>optional int64 tableId = 1;</code>\n     *\n     * <pre>\n     **tableId,由数据库产生*\n     * </pre>\n     */\n    public boolean hasTableId() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>optional int64 tableId = 1;</code>\n     *\n     * <pre>\n     **tableId,由数据库产生*\n     * </pre>\n     */\n    public long getTableId() {\n      return tableId_;\n    }\n\n    public static final int EVENTTYPE_FIELD_NUMBER = 2;\n    private EventType eventType_;\n    /**\n     * <code>optional .com.alibaba.otter.canal.protocol.EventType eventType = 2 [default = UPDATE];</code>\n     *\n     * <pre>\n     **数据变更类型*\n     * </pre>\n     */\n    public boolean hasEventType() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>optional .com.alibaba.otter.canal.protocol.EventType eventType = 2 [default = UPDATE];</code>\n     *\n     * <pre>\n     **数据变更类型*\n     * </pre>\n     */\n    public EventType getEventType() {\n      return eventType_;\n    }\n\n    public static final int ISDDL_FIELD_NUMBER = 10;\n    private boolean isDdl_;\n    /**\n     * <code>optional bool isDdl = 10 [default = false];</code>\n     *\n     * <pre>\n     ** 标识是否是ddl语句  *\n     * </pre>\n     */\n    public boolean hasIsDdl() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>optional bool isDdl = 10 [default = false];</code>\n     *\n     * <pre>\n     ** 标识是否是ddl语句  *\n     * </pre>\n     */\n    public boolean getIsDdl() {\n      return isDdl_;\n    }\n\n    public static final int SQL_FIELD_NUMBER = 11;\n    private Object sql_;\n    /**\n     * <code>optional string sql = 11;</code>\n     *\n     * <pre>\n     ** ddl/query的sql语句  *\n     * </pre>\n     */\n    public boolean hasSql() {\n      return ((bitField0_ & 0x00000008) == 0x00000008);\n    }\n    /**\n     * <code>optional string sql = 11;</code>\n     *\n     * <pre>\n     ** ddl/query的sql语句  *\n     * </pre>\n     */\n    public String getSql() {\n      Object ref = sql_;\n      if (ref instanceof String) {\n        return (String) ref;\n      } else {\n        com.google.protobuf.ByteString bs =\n            (com.google.protobuf.ByteString) ref;\n        String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          sql_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string sql = 11;</code>\n     *\n     * <pre>\n     ** ddl/query的sql语句  *\n     * </pre>\n     */\n    public com.google.protobuf.ByteString\n        getSqlBytes() {\n      Object ref = sql_;\n      if (ref instanceof String) {\n        com.google.protobuf.ByteString b =\n            com.google.protobuf.ByteString.copyFromUtf8(\n                (String) ref);\n        sql_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int ROWDATAS_FIELD_NUMBER = 12;\n    private java.util.List<RowData> rowDatas_;\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.RowData rowDatas = 12;</code>\n     *\n     * <pre>\n     ** 一次数据库变更可能存在多行  *\n     * </pre>\n     */\n    public java.util.List<RowData> getRowDatasList() {\n      return rowDatas_;\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.RowData rowDatas = 12;</code>\n     *\n     * <pre>\n     ** 一次数据库变更可能存在多行  *\n     * </pre>\n     */\n    public java.util.List<? extends RowDataOrBuilder>\n        getRowDatasOrBuilderList() {\n      return rowDatas_;\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.RowData rowDatas = 12;</code>\n     *\n     * <pre>\n     ** 一次数据库变更可能存在多行  *\n     * </pre>\n     */\n    public int getRowDatasCount() {\n      return rowDatas_.size();\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.RowData rowDatas = 12;</code>\n     *\n     * <pre>\n     ** 一次数据库变更可能存在多行  *\n     * </pre>\n     */\n    public RowData getRowDatas(int index) {\n      return rowDatas_.get(index);\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.RowData rowDatas = 12;</code>\n     *\n     * <pre>\n     ** 一次数据库变更可能存在多行  *\n     * </pre>\n     */\n    public RowDataOrBuilder getRowDatasOrBuilder(\n        int index) {\n      return rowDatas_.get(index);\n    }\n\n    public static final int PROPS_FIELD_NUMBER = 13;\n    private java.util.List<Pair> props_;\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 13;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public java.util.List<Pair> getPropsList() {\n      return props_;\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 13;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public java.util.List<? extends PairOrBuilder>\n        getPropsOrBuilderList() {\n      return props_;\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 13;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public int getPropsCount() {\n      return props_.size();\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 13;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public Pair getProps(int index) {\n      return props_.get(index);\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 13;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public PairOrBuilder getPropsOrBuilder(\n        int index) {\n      return props_.get(index);\n    }\n\n    public static final int DDLSCHEMANAME_FIELD_NUMBER = 14;\n    private Object ddlSchemaName_;\n    /**\n     * <code>optional string ddlSchemaName = 14;</code>\n     *\n     * <pre>\n     ** ddl/query的schemaName，会存在跨库ddl，需要保留执行ddl的当前schemaName  *\n     * </pre>\n     */\n    public boolean hasDdlSchemaName() {\n      return ((bitField0_ & 0x00000010) == 0x00000010);\n    }\n    /**\n     * <code>optional string ddlSchemaName = 14;</code>\n     *\n     * <pre>\n     ** ddl/query的schemaName，会存在跨库ddl，需要保留执行ddl的当前schemaName  *\n     * </pre>\n     */\n    public String getDdlSchemaName() {\n      Object ref = ddlSchemaName_;\n      if (ref instanceof String) {\n        return (String) ref;\n      } else {\n        com.google.protobuf.ByteString bs =\n            (com.google.protobuf.ByteString) ref;\n        String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          ddlSchemaName_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string ddlSchemaName = 14;</code>\n     *\n     * <pre>\n     ** ddl/query的schemaName，会存在跨库ddl，需要保留执行ddl的当前schemaName  *\n     * </pre>\n     */\n    public com.google.protobuf.ByteString\n        getDdlSchemaNameBytes() {\n      Object ref = ddlSchemaName_;\n      if (ref instanceof String) {\n        com.google.protobuf.ByteString b =\n            com.google.protobuf.ByteString.copyFromUtf8(\n                (String) ref);\n        ddlSchemaName_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      tableId_ = 0L;\n      eventType_ = EventType.UPDATE;\n      isDdl_ = false;\n      sql_ = \"\";\n      rowDatas_ = java.util.Collections.emptyList();\n      props_ = java.util.Collections.emptyList();\n      ddlSchemaName_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeInt64(1, tableId_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeEnum(2, eventType_.getNumber());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeBool(10, isDdl_);\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        output.writeBytes(11, getSqlBytes());\n      }\n      for (int i = 0; i < rowDatas_.size(); i++) {\n        output.writeMessage(12, rowDatas_.get(i));\n      }\n      for (int i = 0; i < props_.size(); i++) {\n        output.writeMessage(13, props_.get(i));\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        output.writeBytes(14, getDdlSchemaNameBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(1, tableId_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeEnumSize(2, eventType_.getNumber());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBoolSize(10, isDdl_);\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(11, getSqlBytes());\n      }\n      for (int i = 0; i < rowDatas_.size(); i++) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(12, rowDatas_.get(i));\n      }\n      for (int i = 0; i < props_.size(); i++) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(13, props_.get(i));\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(14, getDdlSchemaNameBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @Override\n    protected Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static RowChange parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static RowChange parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static RowChange parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static RowChange parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static RowChange parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static RowChange parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static RowChange parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static RowChange parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static RowChange parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static RowChange parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(RowChange prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @Override\n    protected Builder newBuilderForType(\n        BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code com.alibaba.otter.canal.protocol.RowChange}\n     *\n     * <pre>\n     **message row 每行变更数据的数据结构*\n     * </pre>\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.RowChange)\n        RowChangeOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_RowChange_descriptor;\n      }\n\n      protected FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_RowChange_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                RowChange.class, Builder.class);\n      }\n\n      // Construct using com.alibaba.otter.canal.protocol.CanalEntry.RowChange.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getRowDatasFieldBuilder();\n          getPropsFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        tableId_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000001);\n        eventType_ = EventType.UPDATE;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        isDdl_ = false;\n        bitField0_ = (bitField0_ & ~0x00000004);\n        sql_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000008);\n        if (rowDatasBuilder_ == null) {\n          rowDatas_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000010);\n        } else {\n          rowDatasBuilder_.clear();\n        }\n        if (propsBuilder_ == null) {\n          props_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000020);\n        } else {\n          propsBuilder_.clear();\n        }\n        ddlSchemaName_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000040);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_RowChange_descriptor;\n      }\n\n      public RowChange getDefaultInstanceForType() {\n        return RowChange.getDefaultInstance();\n      }\n\n      public RowChange build() {\n        RowChange result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public RowChange buildPartial() {\n        RowChange result = new RowChange(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.tableId_ = tableId_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.eventType_ = eventType_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.isDdl_ = isDdl_;\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000008;\n        }\n        result.sql_ = sql_;\n        if (rowDatasBuilder_ == null) {\n          if (((bitField0_ & 0x00000010) == 0x00000010)) {\n            rowDatas_ = java.util.Collections.unmodifiableList(rowDatas_);\n            bitField0_ = (bitField0_ & ~0x00000010);\n          }\n          result.rowDatas_ = rowDatas_;\n        } else {\n          result.rowDatas_ = rowDatasBuilder_.build();\n        }\n        if (propsBuilder_ == null) {\n          if (((bitField0_ & 0x00000020) == 0x00000020)) {\n            props_ = java.util.Collections.unmodifiableList(props_);\n            bitField0_ = (bitField0_ & ~0x00000020);\n          }\n          result.props_ = props_;\n        } else {\n          result.props_ = propsBuilder_.build();\n        }\n        if (((from_bitField0_ & 0x00000040) == 0x00000040)) {\n          to_bitField0_ |= 0x00000010;\n        }\n        result.ddlSchemaName_ = ddlSchemaName_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof RowChange) {\n          return mergeFrom((RowChange)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(RowChange other) {\n        if (other == RowChange.getDefaultInstance()) return this;\n        if (other.hasTableId()) {\n          setTableId(other.getTableId());\n        }\n        if (other.hasEventType()) {\n          setEventType(other.getEventType());\n        }\n        if (other.hasIsDdl()) {\n          setIsDdl(other.getIsDdl());\n        }\n        if (other.hasSql()) {\n          bitField0_ |= 0x00000008;\n          sql_ = other.sql_;\n          onChanged();\n        }\n        if (rowDatasBuilder_ == null) {\n          if (!other.rowDatas_.isEmpty()) {\n            if (rowDatas_.isEmpty()) {\n              rowDatas_ = other.rowDatas_;\n              bitField0_ = (bitField0_ & ~0x00000010);\n            } else {\n              ensureRowDatasIsMutable();\n              rowDatas_.addAll(other.rowDatas_);\n            }\n            onChanged();\n          }\n        } else {\n          if (!other.rowDatas_.isEmpty()) {\n            if (rowDatasBuilder_.isEmpty()) {\n              rowDatasBuilder_.dispose();\n              rowDatasBuilder_ = null;\n              rowDatas_ = other.rowDatas_;\n              bitField0_ = (bitField0_ & ~0x00000010);\n              rowDatasBuilder_ =\n                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n                   getRowDatasFieldBuilder() : null;\n            } else {\n              rowDatasBuilder_.addAllMessages(other.rowDatas_);\n            }\n          }\n        }\n        if (propsBuilder_ == null) {\n          if (!other.props_.isEmpty()) {\n            if (props_.isEmpty()) {\n              props_ = other.props_;\n              bitField0_ = (bitField0_ & ~0x00000020);\n            } else {\n              ensurePropsIsMutable();\n              props_.addAll(other.props_);\n            }\n            onChanged();\n          }\n        } else {\n          if (!other.props_.isEmpty()) {\n            if (propsBuilder_.isEmpty()) {\n              propsBuilder_.dispose();\n              propsBuilder_ = null;\n              props_ = other.props_;\n              bitField0_ = (bitField0_ & ~0x00000020);\n              propsBuilder_ =\n                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n                   getPropsFieldBuilder() : null;\n            } else {\n              propsBuilder_.addAllMessages(other.props_);\n            }\n          }\n        }\n        if (other.hasDdlSchemaName()) {\n          bitField0_ |= 0x00000040;\n          ddlSchemaName_ = other.ddlSchemaName_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        RowChange parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (RowChange) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      private long tableId_ ;\n      /**\n       * <code>optional int64 tableId = 1;</code>\n       *\n       * <pre>\n       **tableId,由数据库产生*\n       * </pre>\n       */\n      public boolean hasTableId() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>optional int64 tableId = 1;</code>\n       *\n       * <pre>\n       **tableId,由数据库产生*\n       * </pre>\n       */\n      public long getTableId() {\n        return tableId_;\n      }\n      /**\n       * <code>optional int64 tableId = 1;</code>\n       *\n       * <pre>\n       **tableId,由数据库产生*\n       * </pre>\n       */\n      public Builder setTableId(long value) {\n        bitField0_ |= 0x00000001;\n        tableId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int64 tableId = 1;</code>\n       *\n       * <pre>\n       **tableId,由数据库产生*\n       * </pre>\n       */\n      public Builder clearTableId() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        tableId_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      private EventType eventType_ = EventType.UPDATE;\n      /**\n       * <code>optional .com.alibaba.otter.canal.protocol.EventType eventType = 2 [default = UPDATE];</code>\n       *\n       * <pre>\n       **数据变更类型*\n       * </pre>\n       */\n      public boolean hasEventType() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>optional .com.alibaba.otter.canal.protocol.EventType eventType = 2 [default = UPDATE];</code>\n       *\n       * <pre>\n       **数据变更类型*\n       * </pre>\n       */\n      public EventType getEventType() {\n        return eventType_;\n      }\n      /**\n       * <code>optional .com.alibaba.otter.canal.protocol.EventType eventType = 2 [default = UPDATE];</code>\n       *\n       * <pre>\n       **数据变更类型*\n       * </pre>\n       */\n      public Builder setEventType(EventType value) {\n        if (value == null) {\n          throw new NullPointerException();\n        }\n        bitField0_ |= 0x00000002;\n        eventType_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional .com.alibaba.otter.canal.protocol.EventType eventType = 2 [default = UPDATE];</code>\n       *\n       * <pre>\n       **数据变更类型*\n       * </pre>\n       */\n      public Builder clearEventType() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        eventType_ = EventType.UPDATE;\n        onChanged();\n        return this;\n      }\n\n      private boolean isDdl_ ;\n      /**\n       * <code>optional bool isDdl = 10 [default = false];</code>\n       *\n       * <pre>\n       ** 标识是否是ddl语句  *\n       * </pre>\n       */\n      public boolean hasIsDdl() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>optional bool isDdl = 10 [default = false];</code>\n       *\n       * <pre>\n       ** 标识是否是ddl语句  *\n       * </pre>\n       */\n      public boolean getIsDdl() {\n        return isDdl_;\n      }\n      /**\n       * <code>optional bool isDdl = 10 [default = false];</code>\n       *\n       * <pre>\n       ** 标识是否是ddl语句  *\n       * </pre>\n       */\n      public Builder setIsDdl(boolean value) {\n        bitField0_ |= 0x00000004;\n        isDdl_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional bool isDdl = 10 [default = false];</code>\n       *\n       * <pre>\n       ** 标识是否是ddl语句  *\n       * </pre>\n       */\n      public Builder clearIsDdl() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        isDdl_ = false;\n        onChanged();\n        return this;\n      }\n\n      private Object sql_ = \"\";\n      /**\n       * <code>optional string sql = 11;</code>\n       *\n       * <pre>\n       ** ddl/query的sql语句  *\n       * </pre>\n       */\n      public boolean hasSql() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>optional string sql = 11;</code>\n       *\n       * <pre>\n       ** ddl/query的sql语句  *\n       * </pre>\n       */\n      public String getSql() {\n        Object ref = sql_;\n        if (!(ref instanceof String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          String s = bs.toStringUtf8();\n          if (bs.isValidUtf8()) {\n            sql_ = s;\n          }\n          return s;\n        } else {\n          return (String) ref;\n        }\n      }\n      /**\n       * <code>optional string sql = 11;</code>\n       *\n       * <pre>\n       ** ddl/query的sql语句  *\n       * </pre>\n       */\n      public com.google.protobuf.ByteString\n          getSqlBytes() {\n        Object ref = sql_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b =\n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (String) ref);\n          sql_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string sql = 11;</code>\n       *\n       * <pre>\n       ** ddl/query的sql语句  *\n       * </pre>\n       */\n      public Builder setSql(\n          String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000008;\n        sql_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string sql = 11;</code>\n       *\n       * <pre>\n       ** ddl/query的sql语句  *\n       * </pre>\n       */\n      public Builder clearSql() {\n        bitField0_ = (bitField0_ & ~0x00000008);\n        sql_ = getDefaultInstance().getSql();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string sql = 11;</code>\n       *\n       * <pre>\n       ** ddl/query的sql语句  *\n       * </pre>\n       */\n      public Builder setSqlBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000008;\n        sql_ = value;\n        onChanged();\n        return this;\n      }\n\n      private java.util.List<RowData> rowDatas_ =\n        java.util.Collections.emptyList();\n      private void ensureRowDatasIsMutable() {\n        if (!((bitField0_ & 0x00000010) == 0x00000010)) {\n          rowDatas_ = new java.util.ArrayList<RowData>(rowDatas_);\n          bitField0_ |= 0x00000010;\n         }\n      }\n\n      private com.google.protobuf.RepeatedFieldBuilder<\n          RowData, RowData.Builder, RowDataOrBuilder> rowDatasBuilder_;\n\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.RowData rowDatas = 12;</code>\n       *\n       * <pre>\n       ** 一次数据库变更可能存在多行  *\n       * </pre>\n       */\n      public java.util.List<RowData> getRowDatasList() {\n        if (rowDatasBuilder_ == null) {\n          return java.util.Collections.unmodifiableList(rowDatas_);\n        } else {\n          return rowDatasBuilder_.getMessageList();\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.RowData rowDatas = 12;</code>\n       *\n       * <pre>\n       ** 一次数据库变更可能存在多行  *\n       * </pre>\n       */\n      public int getRowDatasCount() {\n        if (rowDatasBuilder_ == null) {\n          return rowDatas_.size();\n        } else {\n          return rowDatasBuilder_.getCount();\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.RowData rowDatas = 12;</code>\n       *\n       * <pre>\n       ** 一次数据库变更可能存在多行  *\n       * </pre>\n       */\n      public RowData getRowDatas(int index) {\n        if (rowDatasBuilder_ == null) {\n          return rowDatas_.get(index);\n        } else {\n          return rowDatasBuilder_.getMessage(index);\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.RowData rowDatas = 12;</code>\n       *\n       * <pre>\n       ** 一次数据库变更可能存在多行  *\n       * </pre>\n       */\n      public Builder setRowDatas(\n          int index, RowData value) {\n        if (rowDatasBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureRowDatasIsMutable();\n          rowDatas_.set(index, value);\n          onChanged();\n        } else {\n          rowDatasBuilder_.setMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.RowData rowDatas = 12;</code>\n       *\n       * <pre>\n       ** 一次数据库变更可能存在多行  *\n       * </pre>\n       */\n      public Builder setRowDatas(\n          int index, RowData.Builder builderForValue) {\n        if (rowDatasBuilder_ == null) {\n          ensureRowDatasIsMutable();\n          rowDatas_.set(index, builderForValue.build());\n          onChanged();\n        } else {\n          rowDatasBuilder_.setMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.RowData rowDatas = 12;</code>\n       *\n       * <pre>\n       ** 一次数据库变更可能存在多行  *\n       * </pre>\n       */\n      public Builder addRowDatas(RowData value) {\n        if (rowDatasBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureRowDatasIsMutable();\n          rowDatas_.add(value);\n          onChanged();\n        } else {\n          rowDatasBuilder_.addMessage(value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.RowData rowDatas = 12;</code>\n       *\n       * <pre>\n       ** 一次数据库变更可能存在多行  *\n       * </pre>\n       */\n      public Builder addRowDatas(\n          int index, RowData value) {\n        if (rowDatasBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureRowDatasIsMutable();\n          rowDatas_.add(index, value);\n          onChanged();\n        } else {\n          rowDatasBuilder_.addMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.RowData rowDatas = 12;</code>\n       *\n       * <pre>\n       ** 一次数据库变更可能存在多行  *\n       * </pre>\n       */\n      public Builder addRowDatas(\n          RowData.Builder builderForValue) {\n        if (rowDatasBuilder_ == null) {\n          ensureRowDatasIsMutable();\n          rowDatas_.add(builderForValue.build());\n          onChanged();\n        } else {\n          rowDatasBuilder_.addMessage(builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.RowData rowDatas = 12;</code>\n       *\n       * <pre>\n       ** 一次数据库变更可能存在多行  *\n       * </pre>\n       */\n      public Builder addRowDatas(\n          int index, RowData.Builder builderForValue) {\n        if (rowDatasBuilder_ == null) {\n          ensureRowDatasIsMutable();\n          rowDatas_.add(index, builderForValue.build());\n          onChanged();\n        } else {\n          rowDatasBuilder_.addMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.RowData rowDatas = 12;</code>\n       *\n       * <pre>\n       ** 一次数据库变更可能存在多行  *\n       * </pre>\n       */\n      public Builder addAllRowDatas(\n          Iterable<? extends RowData> values) {\n        if (rowDatasBuilder_ == null) {\n          ensureRowDatasIsMutable();\n          com.google.protobuf.AbstractMessageLite.Builder.addAll(\n              values, rowDatas_);\n          onChanged();\n        } else {\n          rowDatasBuilder_.addAllMessages(values);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.RowData rowDatas = 12;</code>\n       *\n       * <pre>\n       ** 一次数据库变更可能存在多行  *\n       * </pre>\n       */\n      public Builder clearRowDatas() {\n        if (rowDatasBuilder_ == null) {\n          rowDatas_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000010);\n          onChanged();\n        } else {\n          rowDatasBuilder_.clear();\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.RowData rowDatas = 12;</code>\n       *\n       * <pre>\n       ** 一次数据库变更可能存在多行  *\n       * </pre>\n       */\n      public Builder removeRowDatas(int index) {\n        if (rowDatasBuilder_ == null) {\n          ensureRowDatasIsMutable();\n          rowDatas_.remove(index);\n          onChanged();\n        } else {\n          rowDatasBuilder_.remove(index);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.RowData rowDatas = 12;</code>\n       *\n       * <pre>\n       ** 一次数据库变更可能存在多行  *\n       * </pre>\n       */\n      public RowData.Builder getRowDatasBuilder(\n          int index) {\n        return getRowDatasFieldBuilder().getBuilder(index);\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.RowData rowDatas = 12;</code>\n       *\n       * <pre>\n       ** 一次数据库变更可能存在多行  *\n       * </pre>\n       */\n      public RowDataOrBuilder getRowDatasOrBuilder(\n          int index) {\n        if (rowDatasBuilder_ == null) {\n          return rowDatas_.get(index);  } else {\n          return rowDatasBuilder_.getMessageOrBuilder(index);\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.RowData rowDatas = 12;</code>\n       *\n       * <pre>\n       ** 一次数据库变更可能存在多行  *\n       * </pre>\n       */\n      public java.util.List<? extends RowDataOrBuilder>\n           getRowDatasOrBuilderList() {\n        if (rowDatasBuilder_ != null) {\n          return rowDatasBuilder_.getMessageOrBuilderList();\n        } else {\n          return java.util.Collections.unmodifiableList(rowDatas_);\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.RowData rowDatas = 12;</code>\n       *\n       * <pre>\n       ** 一次数据库变更可能存在多行  *\n       * </pre>\n       */\n      public RowData.Builder addRowDatasBuilder() {\n        return getRowDatasFieldBuilder().addBuilder(\n            RowData.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.RowData rowDatas = 12;</code>\n       *\n       * <pre>\n       ** 一次数据库变更可能存在多行  *\n       * </pre>\n       */\n      public RowData.Builder addRowDatasBuilder(\n          int index) {\n        return getRowDatasFieldBuilder().addBuilder(\n            index, RowData.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.RowData rowDatas = 12;</code>\n       *\n       * <pre>\n       ** 一次数据库变更可能存在多行  *\n       * </pre>\n       */\n      public java.util.List<RowData.Builder>\n           getRowDatasBuilderList() {\n        return getRowDatasFieldBuilder().getBuilderList();\n      }\n      private com.google.protobuf.RepeatedFieldBuilder<\n          RowData, RowData.Builder, RowDataOrBuilder>\n          getRowDatasFieldBuilder() {\n        if (rowDatasBuilder_ == null) {\n          rowDatasBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<\n              RowData, RowData.Builder, RowDataOrBuilder>(\n                  rowDatas_,\n                  ((bitField0_ & 0x00000010) == 0x00000010),\n                  getParentForChildren(),\n                  isClean());\n          rowDatas_ = null;\n        }\n        return rowDatasBuilder_;\n      }\n\n      private java.util.List<Pair> props_ =\n        java.util.Collections.emptyList();\n      private void ensurePropsIsMutable() {\n        if (!((bitField0_ & 0x00000020) == 0x00000020)) {\n          props_ = new java.util.ArrayList<Pair>(props_);\n          bitField0_ |= 0x00000020;\n         }\n      }\n\n      private com.google.protobuf.RepeatedFieldBuilder<\n          Pair, Pair.Builder, PairOrBuilder> propsBuilder_;\n\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 13;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public java.util.List<Pair> getPropsList() {\n        if (propsBuilder_ == null) {\n          return java.util.Collections.unmodifiableList(props_);\n        } else {\n          return propsBuilder_.getMessageList();\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 13;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public int getPropsCount() {\n        if (propsBuilder_ == null) {\n          return props_.size();\n        } else {\n          return propsBuilder_.getCount();\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 13;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Pair getProps(int index) {\n        if (propsBuilder_ == null) {\n          return props_.get(index);\n        } else {\n          return propsBuilder_.getMessage(index);\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 13;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder setProps(\n          int index, Pair value) {\n        if (propsBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensurePropsIsMutable();\n          props_.set(index, value);\n          onChanged();\n        } else {\n          propsBuilder_.setMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 13;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder setProps(\n          int index, Pair.Builder builderForValue) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          props_.set(index, builderForValue.build());\n          onChanged();\n        } else {\n          propsBuilder_.setMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 13;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addProps(Pair value) {\n        if (propsBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensurePropsIsMutable();\n          props_.add(value);\n          onChanged();\n        } else {\n          propsBuilder_.addMessage(value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 13;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addProps(\n          int index, Pair value) {\n        if (propsBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensurePropsIsMutable();\n          props_.add(index, value);\n          onChanged();\n        } else {\n          propsBuilder_.addMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 13;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addProps(\n          Pair.Builder builderForValue) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          props_.add(builderForValue.build());\n          onChanged();\n        } else {\n          propsBuilder_.addMessage(builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 13;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addProps(\n          int index, Pair.Builder builderForValue) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          props_.add(index, builderForValue.build());\n          onChanged();\n        } else {\n          propsBuilder_.addMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 13;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addAllProps(\n          Iterable<? extends Pair> values) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          com.google.protobuf.AbstractMessageLite.Builder.addAll(\n              values, props_);\n          onChanged();\n        } else {\n          propsBuilder_.addAllMessages(values);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 13;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder clearProps() {\n        if (propsBuilder_ == null) {\n          props_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000020);\n          onChanged();\n        } else {\n          propsBuilder_.clear();\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 13;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder removeProps(int index) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          props_.remove(index);\n          onChanged();\n        } else {\n          propsBuilder_.remove(index);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 13;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Pair.Builder getPropsBuilder(\n          int index) {\n        return getPropsFieldBuilder().getBuilder(index);\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 13;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public PairOrBuilder getPropsOrBuilder(\n          int index) {\n        if (propsBuilder_ == null) {\n          return props_.get(index);  } else {\n          return propsBuilder_.getMessageOrBuilder(index);\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 13;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public java.util.List<? extends PairOrBuilder>\n           getPropsOrBuilderList() {\n        if (propsBuilder_ != null) {\n          return propsBuilder_.getMessageOrBuilderList();\n        } else {\n          return java.util.Collections.unmodifiableList(props_);\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 13;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Pair.Builder addPropsBuilder() {\n        return getPropsFieldBuilder().addBuilder(\n            Pair.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 13;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Pair.Builder addPropsBuilder(\n          int index) {\n        return getPropsFieldBuilder().addBuilder(\n            index, Pair.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 13;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public java.util.List<Pair.Builder>\n           getPropsBuilderList() {\n        return getPropsFieldBuilder().getBuilderList();\n      }\n      private com.google.protobuf.RepeatedFieldBuilder<\n          Pair, Pair.Builder, PairOrBuilder>\n          getPropsFieldBuilder() {\n        if (propsBuilder_ == null) {\n          propsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<\n              Pair, Pair.Builder, PairOrBuilder>(\n                  props_,\n                  ((bitField0_ & 0x00000020) == 0x00000020),\n                  getParentForChildren(),\n                  isClean());\n          props_ = null;\n        }\n        return propsBuilder_;\n      }\n\n      private Object ddlSchemaName_ = \"\";\n      /**\n       * <code>optional string ddlSchemaName = 14;</code>\n       *\n       * <pre>\n       ** ddl/query的schemaName，会存在跨库ddl，需要保留执行ddl的当前schemaName  *\n       * </pre>\n       */\n      public boolean hasDdlSchemaName() {\n        return ((bitField0_ & 0x00000040) == 0x00000040);\n      }\n      /**\n       * <code>optional string ddlSchemaName = 14;</code>\n       *\n       * <pre>\n       ** ddl/query的schemaName，会存在跨库ddl，需要保留执行ddl的当前schemaName  *\n       * </pre>\n       */\n      public String getDdlSchemaName() {\n        Object ref = ddlSchemaName_;\n        if (!(ref instanceof String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          String s = bs.toStringUtf8();\n          if (bs.isValidUtf8()) {\n            ddlSchemaName_ = s;\n          }\n          return s;\n        } else {\n          return (String) ref;\n        }\n      }\n      /**\n       * <code>optional string ddlSchemaName = 14;</code>\n       *\n       * <pre>\n       ** ddl/query的schemaName，会存在跨库ddl，需要保留执行ddl的当前schemaName  *\n       * </pre>\n       */\n      public com.google.protobuf.ByteString\n          getDdlSchemaNameBytes() {\n        Object ref = ddlSchemaName_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b =\n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (String) ref);\n          ddlSchemaName_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string ddlSchemaName = 14;</code>\n       *\n       * <pre>\n       ** ddl/query的schemaName，会存在跨库ddl，需要保留执行ddl的当前schemaName  *\n       * </pre>\n       */\n      public Builder setDdlSchemaName(\n          String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000040;\n        ddlSchemaName_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string ddlSchemaName = 14;</code>\n       *\n       * <pre>\n       ** ddl/query的schemaName，会存在跨库ddl，需要保留执行ddl的当前schemaName  *\n       * </pre>\n       */\n      public Builder clearDdlSchemaName() {\n        bitField0_ = (bitField0_ & ~0x00000040);\n        ddlSchemaName_ = getDefaultInstance().getDdlSchemaName();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string ddlSchemaName = 14;</code>\n       *\n       * <pre>\n       ** ddl/query的schemaName，会存在跨库ddl，需要保留执行ddl的当前schemaName  *\n       * </pre>\n       */\n      public Builder setDdlSchemaNameBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000040;\n        ddlSchemaName_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.RowChange)\n    }\n\n    static {\n      defaultInstance = new RowChange(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.RowChange)\n  }\n\n  public interface TransactionBeginOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.TransactionBegin)\n      com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <code>optional int64 executeTime = 1;</code>\n     *\n     * <pre>\n     **已废弃，请使用header里的executeTime*\n     * </pre>\n     */\n    boolean hasExecuteTime();\n    /**\n     * <code>optional int64 executeTime = 1;</code>\n     *\n     * <pre>\n     **已废弃，请使用header里的executeTime*\n     * </pre>\n     */\n    long getExecuteTime();\n\n    /**\n     * <code>optional string transactionId = 2;</code>\n     *\n     * <pre>\n     **已废弃，Begin里不提供事务id*\n     * </pre>\n     */\n    boolean hasTransactionId();\n    /**\n     * <code>optional string transactionId = 2;</code>\n     *\n     * <pre>\n     **已废弃，Begin里不提供事务id*\n     * </pre>\n     */\n    String getTransactionId();\n    /**\n     * <code>optional string transactionId = 2;</code>\n     *\n     * <pre>\n     **已废弃，Begin里不提供事务id*\n     * </pre>\n     */\n    com.google.protobuf.ByteString\n        getTransactionIdBytes();\n\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    java.util.List<Pair>\n        getPropsList();\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    Pair getProps(int index);\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    int getPropsCount();\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    java.util.List<? extends PairOrBuilder>\n        getPropsOrBuilderList();\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    PairOrBuilder getPropsOrBuilder(int index);\n\n    /**\n     * <code>optional int64 threadId = 4;</code>\n     *\n     * <pre>\n     **执行的thread Id*\n     * </pre>\n     */\n    boolean hasThreadId();\n    /**\n     * <code>optional int64 threadId = 4;</code>\n     *\n     * <pre>\n     **执行的thread Id*\n     * </pre>\n     */\n    long getThreadId();\n  }\n  /**\n   * Protobuf type {@code com.alibaba.otter.canal.protocol.TransactionBegin}\n   *\n   * <pre>\n   **开始事务的一些信息*\n   * </pre>\n   */\n  public static final class TransactionBegin extends\n      com.google.protobuf.GeneratedMessage implements\n      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.TransactionBegin)\n      TransactionBeginOrBuilder {\n    // Use TransactionBegin.newBuilder() to construct.\n    private TransactionBegin(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private TransactionBegin(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final TransactionBegin defaultInstance;\n    public static TransactionBegin getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public TransactionBegin getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private TransactionBegin(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 8: {\n              bitField0_ |= 0x00000001;\n              executeTime_ = input.readInt64();\n              break;\n            }\n            case 18: {\n              com.google.protobuf.ByteString bs = input.readBytes();\n              bitField0_ |= 0x00000002;\n              transactionId_ = bs;\n              break;\n            }\n            case 26: {\n              if (!((mutable_bitField0_ & 0x00000004) == 0x00000004)) {\n                props_ = new java.util.ArrayList<Pair>();\n                mutable_bitField0_ |= 0x00000004;\n              }\n              props_.add(input.readMessage(Pair.PARSER, extensionRegistry));\n              break;\n            }\n            case 32: {\n              bitField0_ |= 0x00000004;\n              threadId_ = input.readInt64();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000004) == 0x00000004)) {\n          props_ = java.util.Collections.unmodifiableList(props_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_TransactionBegin_descriptor;\n    }\n\n    protected FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_TransactionBegin_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              TransactionBegin.class, Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<TransactionBegin> PARSER =\n        new com.google.protobuf.AbstractParser<TransactionBegin>() {\n      public TransactionBegin parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new TransactionBegin(input, extensionRegistry);\n      }\n    };\n\n    @Override\n    public com.google.protobuf.Parser<TransactionBegin> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    public static final int EXECUTETIME_FIELD_NUMBER = 1;\n    private long executeTime_;\n    /**\n     * <code>optional int64 executeTime = 1;</code>\n     *\n     * <pre>\n     **已废弃，请使用header里的executeTime*\n     * </pre>\n     */\n    public boolean hasExecuteTime() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>optional int64 executeTime = 1;</code>\n     *\n     * <pre>\n     **已废弃，请使用header里的executeTime*\n     * </pre>\n     */\n    public long getExecuteTime() {\n      return executeTime_;\n    }\n\n    public static final int TRANSACTIONID_FIELD_NUMBER = 2;\n    private Object transactionId_;\n    /**\n     * <code>optional string transactionId = 2;</code>\n     *\n     * <pre>\n     **已废弃，Begin里不提供事务id*\n     * </pre>\n     */\n    public boolean hasTransactionId() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>optional string transactionId = 2;</code>\n     *\n     * <pre>\n     **已废弃，Begin里不提供事务id*\n     * </pre>\n     */\n    public String getTransactionId() {\n      Object ref = transactionId_;\n      if (ref instanceof String) {\n        return (String) ref;\n      } else {\n        com.google.protobuf.ByteString bs =\n            (com.google.protobuf.ByteString) ref;\n        String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          transactionId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string transactionId = 2;</code>\n     *\n     * <pre>\n     **已废弃，Begin里不提供事务id*\n     * </pre>\n     */\n    public com.google.protobuf.ByteString\n        getTransactionIdBytes() {\n      Object ref = transactionId_;\n      if (ref instanceof String) {\n        com.google.protobuf.ByteString b =\n            com.google.protobuf.ByteString.copyFromUtf8(\n                (String) ref);\n        transactionId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int PROPS_FIELD_NUMBER = 3;\n    private java.util.List<Pair> props_;\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public java.util.List<Pair> getPropsList() {\n      return props_;\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public java.util.List<? extends PairOrBuilder>\n        getPropsOrBuilderList() {\n      return props_;\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public int getPropsCount() {\n      return props_.size();\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public Pair getProps(int index) {\n      return props_.get(index);\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public PairOrBuilder getPropsOrBuilder(\n        int index) {\n      return props_.get(index);\n    }\n\n    public static final int THREADID_FIELD_NUMBER = 4;\n    private long threadId_;\n    /**\n     * <code>optional int64 threadId = 4;</code>\n     *\n     * <pre>\n     **执行的thread Id*\n     * </pre>\n     */\n    public boolean hasThreadId() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>optional int64 threadId = 4;</code>\n     *\n     * <pre>\n     **执行的thread Id*\n     * </pre>\n     */\n    public long getThreadId() {\n      return threadId_;\n    }\n\n    private void initFields() {\n      executeTime_ = 0L;\n      transactionId_ = \"\";\n      props_ = java.util.Collections.emptyList();\n      threadId_ = 0L;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeInt64(1, executeTime_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeBytes(2, getTransactionIdBytes());\n      }\n      for (int i = 0; i < props_.size(); i++) {\n        output.writeMessage(3, props_.get(i));\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeInt64(4, threadId_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(1, executeTime_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, getTransactionIdBytes());\n      }\n      for (int i = 0; i < props_.size(); i++) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(3, props_.get(i));\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(4, threadId_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @Override\n    protected Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static TransactionBegin parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static TransactionBegin parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static TransactionBegin parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static TransactionBegin parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static TransactionBegin parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static TransactionBegin parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static TransactionBegin parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static TransactionBegin parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static TransactionBegin parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static TransactionBegin parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(TransactionBegin prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @Override\n    protected Builder newBuilderForType(\n        BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code com.alibaba.otter.canal.protocol.TransactionBegin}\n     *\n     * <pre>\n     **开始事务的一些信息*\n     * </pre>\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.TransactionBegin)\n        TransactionBeginOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_TransactionBegin_descriptor;\n      }\n\n      protected FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_TransactionBegin_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                TransactionBegin.class, Builder.class);\n      }\n\n      // Construct using com.alibaba.otter.canal.protocol.CanalEntry.TransactionBegin.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getPropsFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        executeTime_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000001);\n        transactionId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000002);\n        if (propsBuilder_ == null) {\n          props_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000004);\n        } else {\n          propsBuilder_.clear();\n        }\n        threadId_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000008);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_TransactionBegin_descriptor;\n      }\n\n      public TransactionBegin getDefaultInstanceForType() {\n        return TransactionBegin.getDefaultInstance();\n      }\n\n      public TransactionBegin build() {\n        TransactionBegin result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public TransactionBegin buildPartial() {\n        TransactionBegin result = new TransactionBegin(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.executeTime_ = executeTime_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.transactionId_ = transactionId_;\n        if (propsBuilder_ == null) {\n          if (((bitField0_ & 0x00000004) == 0x00000004)) {\n            props_ = java.util.Collections.unmodifiableList(props_);\n            bitField0_ = (bitField0_ & ~0x00000004);\n          }\n          result.props_ = props_;\n        } else {\n          result.props_ = propsBuilder_.build();\n        }\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.threadId_ = threadId_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof TransactionBegin) {\n          return mergeFrom((TransactionBegin)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(TransactionBegin other) {\n        if (other == TransactionBegin.getDefaultInstance()) return this;\n        if (other.hasExecuteTime()) {\n          setExecuteTime(other.getExecuteTime());\n        }\n        if (other.hasTransactionId()) {\n          bitField0_ |= 0x00000002;\n          transactionId_ = other.transactionId_;\n          onChanged();\n        }\n        if (propsBuilder_ == null) {\n          if (!other.props_.isEmpty()) {\n            if (props_.isEmpty()) {\n              props_ = other.props_;\n              bitField0_ = (bitField0_ & ~0x00000004);\n            } else {\n              ensurePropsIsMutable();\n              props_.addAll(other.props_);\n            }\n            onChanged();\n          }\n        } else {\n          if (!other.props_.isEmpty()) {\n            if (propsBuilder_.isEmpty()) {\n              propsBuilder_.dispose();\n              propsBuilder_ = null;\n              props_ = other.props_;\n              bitField0_ = (bitField0_ & ~0x00000004);\n              propsBuilder_ =\n                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n                   getPropsFieldBuilder() : null;\n            } else {\n              propsBuilder_.addAllMessages(other.props_);\n            }\n          }\n        }\n        if (other.hasThreadId()) {\n          setThreadId(other.getThreadId());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        TransactionBegin parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (TransactionBegin) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      private long executeTime_ ;\n      /**\n       * <code>optional int64 executeTime = 1;</code>\n       *\n       * <pre>\n       **已废弃，请使用header里的executeTime*\n       * </pre>\n       */\n      public boolean hasExecuteTime() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>optional int64 executeTime = 1;</code>\n       *\n       * <pre>\n       **已废弃，请使用header里的executeTime*\n       * </pre>\n       */\n      public long getExecuteTime() {\n        return executeTime_;\n      }\n      /**\n       * <code>optional int64 executeTime = 1;</code>\n       *\n       * <pre>\n       **已废弃，请使用header里的executeTime*\n       * </pre>\n       */\n      public Builder setExecuteTime(long value) {\n        bitField0_ |= 0x00000001;\n        executeTime_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int64 executeTime = 1;</code>\n       *\n       * <pre>\n       **已废弃，请使用header里的executeTime*\n       * </pre>\n       */\n      public Builder clearExecuteTime() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        executeTime_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      private Object transactionId_ = \"\";\n      /**\n       * <code>optional string transactionId = 2;</code>\n       *\n       * <pre>\n       **已废弃，Begin里不提供事务id*\n       * </pre>\n       */\n      public boolean hasTransactionId() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>optional string transactionId = 2;</code>\n       *\n       * <pre>\n       **已废弃，Begin里不提供事务id*\n       * </pre>\n       */\n      public String getTransactionId() {\n        Object ref = transactionId_;\n        if (!(ref instanceof String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          String s = bs.toStringUtf8();\n          if (bs.isValidUtf8()) {\n            transactionId_ = s;\n          }\n          return s;\n        } else {\n          return (String) ref;\n        }\n      }\n      /**\n       * <code>optional string transactionId = 2;</code>\n       *\n       * <pre>\n       **已废弃，Begin里不提供事务id*\n       * </pre>\n       */\n      public com.google.protobuf.ByteString\n          getTransactionIdBytes() {\n        Object ref = transactionId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b =\n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (String) ref);\n          transactionId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string transactionId = 2;</code>\n       *\n       * <pre>\n       **已废弃，Begin里不提供事务id*\n       * </pre>\n       */\n      public Builder setTransactionId(\n          String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        transactionId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string transactionId = 2;</code>\n       *\n       * <pre>\n       **已废弃，Begin里不提供事务id*\n       * </pre>\n       */\n      public Builder clearTransactionId() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        transactionId_ = getDefaultInstance().getTransactionId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string transactionId = 2;</code>\n       *\n       * <pre>\n       **已废弃，Begin里不提供事务id*\n       * </pre>\n       */\n      public Builder setTransactionIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        transactionId_ = value;\n        onChanged();\n        return this;\n      }\n\n      private java.util.List<Pair> props_ =\n        java.util.Collections.emptyList();\n      private void ensurePropsIsMutable() {\n        if (!((bitField0_ & 0x00000004) == 0x00000004)) {\n          props_ = new java.util.ArrayList<Pair>(props_);\n          bitField0_ |= 0x00000004;\n         }\n      }\n\n      private com.google.protobuf.RepeatedFieldBuilder<\n          Pair, Pair.Builder, PairOrBuilder> propsBuilder_;\n\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public java.util.List<Pair> getPropsList() {\n        if (propsBuilder_ == null) {\n          return java.util.Collections.unmodifiableList(props_);\n        } else {\n          return propsBuilder_.getMessageList();\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public int getPropsCount() {\n        if (propsBuilder_ == null) {\n          return props_.size();\n        } else {\n          return propsBuilder_.getCount();\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Pair getProps(int index) {\n        if (propsBuilder_ == null) {\n          return props_.get(index);\n        } else {\n          return propsBuilder_.getMessage(index);\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder setProps(\n          int index, Pair value) {\n        if (propsBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensurePropsIsMutable();\n          props_.set(index, value);\n          onChanged();\n        } else {\n          propsBuilder_.setMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder setProps(\n          int index, Pair.Builder builderForValue) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          props_.set(index, builderForValue.build());\n          onChanged();\n        } else {\n          propsBuilder_.setMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addProps(Pair value) {\n        if (propsBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensurePropsIsMutable();\n          props_.add(value);\n          onChanged();\n        } else {\n          propsBuilder_.addMessage(value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addProps(\n          int index, Pair value) {\n        if (propsBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensurePropsIsMutable();\n          props_.add(index, value);\n          onChanged();\n        } else {\n          propsBuilder_.addMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addProps(\n          Pair.Builder builderForValue) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          props_.add(builderForValue.build());\n          onChanged();\n        } else {\n          propsBuilder_.addMessage(builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addProps(\n          int index, Pair.Builder builderForValue) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          props_.add(index, builderForValue.build());\n          onChanged();\n        } else {\n          propsBuilder_.addMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addAllProps(\n          Iterable<? extends Pair> values) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          com.google.protobuf.AbstractMessageLite.Builder.addAll(\n              values, props_);\n          onChanged();\n        } else {\n          propsBuilder_.addAllMessages(values);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder clearProps() {\n        if (propsBuilder_ == null) {\n          props_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000004);\n          onChanged();\n        } else {\n          propsBuilder_.clear();\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder removeProps(int index) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          props_.remove(index);\n          onChanged();\n        } else {\n          propsBuilder_.remove(index);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Pair.Builder getPropsBuilder(\n          int index) {\n        return getPropsFieldBuilder().getBuilder(index);\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public PairOrBuilder getPropsOrBuilder(\n          int index) {\n        if (propsBuilder_ == null) {\n          return props_.get(index);  } else {\n          return propsBuilder_.getMessageOrBuilder(index);\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public java.util.List<? extends PairOrBuilder>\n           getPropsOrBuilderList() {\n        if (propsBuilder_ != null) {\n          return propsBuilder_.getMessageOrBuilderList();\n        } else {\n          return java.util.Collections.unmodifiableList(props_);\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Pair.Builder addPropsBuilder() {\n        return getPropsFieldBuilder().addBuilder(\n            Pair.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Pair.Builder addPropsBuilder(\n          int index) {\n        return getPropsFieldBuilder().addBuilder(\n            index, Pair.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public java.util.List<Pair.Builder>\n           getPropsBuilderList() {\n        return getPropsFieldBuilder().getBuilderList();\n      }\n      private com.google.protobuf.RepeatedFieldBuilder<\n          Pair, Pair.Builder, PairOrBuilder>\n          getPropsFieldBuilder() {\n        if (propsBuilder_ == null) {\n          propsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<\n              Pair, Pair.Builder, PairOrBuilder>(\n                  props_,\n                  ((bitField0_ & 0x00000004) == 0x00000004),\n                  getParentForChildren(),\n                  isClean());\n          props_ = null;\n        }\n        return propsBuilder_;\n      }\n\n      private long threadId_ ;\n      /**\n       * <code>optional int64 threadId = 4;</code>\n       *\n       * <pre>\n       **执行的thread Id*\n       * </pre>\n       */\n      public boolean hasThreadId() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>optional int64 threadId = 4;</code>\n       *\n       * <pre>\n       **执行的thread Id*\n       * </pre>\n       */\n      public long getThreadId() {\n        return threadId_;\n      }\n      /**\n       * <code>optional int64 threadId = 4;</code>\n       *\n       * <pre>\n       **执行的thread Id*\n       * </pre>\n       */\n      public Builder setThreadId(long value) {\n        bitField0_ |= 0x00000008;\n        threadId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int64 threadId = 4;</code>\n       *\n       * <pre>\n       **执行的thread Id*\n       * </pre>\n       */\n      public Builder clearThreadId() {\n        bitField0_ = (bitField0_ & ~0x00000008);\n        threadId_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.TransactionBegin)\n    }\n\n    static {\n      defaultInstance = new TransactionBegin(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.TransactionBegin)\n  }\n\n  public interface TransactionEndOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.TransactionEnd)\n      com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <code>optional int64 executeTime = 1;</code>\n     *\n     * <pre>\n     **已废弃，请使用header里的executeTime*\n     * </pre>\n     */\n    boolean hasExecuteTime();\n    /**\n     * <code>optional int64 executeTime = 1;</code>\n     *\n     * <pre>\n     **已废弃，请使用header里的executeTime*\n     * </pre>\n     */\n    long getExecuteTime();\n\n    /**\n     * <code>optional string transactionId = 2;</code>\n     *\n     * <pre>\n     **事务号*\n     * </pre>\n     */\n    boolean hasTransactionId();\n    /**\n     * <code>optional string transactionId = 2;</code>\n     *\n     * <pre>\n     **事务号*\n     * </pre>\n     */\n    String getTransactionId();\n    /**\n     * <code>optional string transactionId = 2;</code>\n     *\n     * <pre>\n     **事务号*\n     * </pre>\n     */\n    com.google.protobuf.ByteString\n        getTransactionIdBytes();\n\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    java.util.List<Pair>\n        getPropsList();\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    Pair getProps(int index);\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    int getPropsCount();\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    java.util.List<? extends PairOrBuilder>\n        getPropsOrBuilderList();\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    PairOrBuilder getPropsOrBuilder(int index);\n  }\n  /**\n   * Protobuf type {@code com.alibaba.otter.canal.protocol.TransactionEnd}\n   *\n   * <pre>\n   **结束事务的一些信息*\n   * </pre>\n   */\n  public static final class TransactionEnd extends\n      com.google.protobuf.GeneratedMessage implements\n      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.TransactionEnd)\n      TransactionEndOrBuilder {\n    // Use TransactionEnd.newBuilder() to construct.\n    private TransactionEnd(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private TransactionEnd(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final TransactionEnd defaultInstance;\n    public static TransactionEnd getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public TransactionEnd getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private TransactionEnd(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 8: {\n              bitField0_ |= 0x00000001;\n              executeTime_ = input.readInt64();\n              break;\n            }\n            case 18: {\n              com.google.protobuf.ByteString bs = input.readBytes();\n              bitField0_ |= 0x00000002;\n              transactionId_ = bs;\n              break;\n            }\n            case 26: {\n              if (!((mutable_bitField0_ & 0x00000004) == 0x00000004)) {\n                props_ = new java.util.ArrayList<Pair>();\n                mutable_bitField0_ |= 0x00000004;\n              }\n              props_.add(input.readMessage(Pair.PARSER, extensionRegistry));\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000004) == 0x00000004)) {\n          props_ = java.util.Collections.unmodifiableList(props_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_TransactionEnd_descriptor;\n    }\n\n    protected FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_TransactionEnd_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              TransactionEnd.class, Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<TransactionEnd> PARSER =\n        new com.google.protobuf.AbstractParser<TransactionEnd>() {\n      public TransactionEnd parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new TransactionEnd(input, extensionRegistry);\n      }\n    };\n\n    @Override\n    public com.google.protobuf.Parser<TransactionEnd> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    public static final int EXECUTETIME_FIELD_NUMBER = 1;\n    private long executeTime_;\n    /**\n     * <code>optional int64 executeTime = 1;</code>\n     *\n     * <pre>\n     **已废弃，请使用header里的executeTime*\n     * </pre>\n     */\n    public boolean hasExecuteTime() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>optional int64 executeTime = 1;</code>\n     *\n     * <pre>\n     **已废弃，请使用header里的executeTime*\n     * </pre>\n     */\n    public long getExecuteTime() {\n      return executeTime_;\n    }\n\n    public static final int TRANSACTIONID_FIELD_NUMBER = 2;\n    private Object transactionId_;\n    /**\n     * <code>optional string transactionId = 2;</code>\n     *\n     * <pre>\n     **事务号*\n     * </pre>\n     */\n    public boolean hasTransactionId() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>optional string transactionId = 2;</code>\n     *\n     * <pre>\n     **事务号*\n     * </pre>\n     */\n    public String getTransactionId() {\n      Object ref = transactionId_;\n      if (ref instanceof String) {\n        return (String) ref;\n      } else {\n        com.google.protobuf.ByteString bs =\n            (com.google.protobuf.ByteString) ref;\n        String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          transactionId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string transactionId = 2;</code>\n     *\n     * <pre>\n     **事务号*\n     * </pre>\n     */\n    public com.google.protobuf.ByteString\n        getTransactionIdBytes() {\n      Object ref = transactionId_;\n      if (ref instanceof String) {\n        com.google.protobuf.ByteString b =\n            com.google.protobuf.ByteString.copyFromUtf8(\n                (String) ref);\n        transactionId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int PROPS_FIELD_NUMBER = 3;\n    private java.util.List<Pair> props_;\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public java.util.List<Pair> getPropsList() {\n      return props_;\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public java.util.List<? extends PairOrBuilder>\n        getPropsOrBuilderList() {\n      return props_;\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public int getPropsCount() {\n      return props_.size();\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public Pair getProps(int index) {\n      return props_.get(index);\n    }\n    /**\n     * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public PairOrBuilder getPropsOrBuilder(\n        int index) {\n      return props_.get(index);\n    }\n\n    private void initFields() {\n      executeTime_ = 0L;\n      transactionId_ = \"\";\n      props_ = java.util.Collections.emptyList();\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeInt64(1, executeTime_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeBytes(2, getTransactionIdBytes());\n      }\n      for (int i = 0; i < props_.size(); i++) {\n        output.writeMessage(3, props_.get(i));\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(1, executeTime_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, getTransactionIdBytes());\n      }\n      for (int i = 0; i < props_.size(); i++) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(3, props_.get(i));\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @Override\n    protected Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static TransactionEnd parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static TransactionEnd parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static TransactionEnd parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static TransactionEnd parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static TransactionEnd parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static TransactionEnd parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static TransactionEnd parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static TransactionEnd parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static TransactionEnd parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static TransactionEnd parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(TransactionEnd prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @Override\n    protected Builder newBuilderForType(\n        BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code com.alibaba.otter.canal.protocol.TransactionEnd}\n     *\n     * <pre>\n     **结束事务的一些信息*\n     * </pre>\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.TransactionEnd)\n        TransactionEndOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_TransactionEnd_descriptor;\n      }\n\n      protected FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_TransactionEnd_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                TransactionEnd.class, Builder.class);\n      }\n\n      // Construct using com.alibaba.otter.canal.protocol.CanalEntry.TransactionEnd.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getPropsFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        executeTime_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000001);\n        transactionId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000002);\n        if (propsBuilder_ == null) {\n          props_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000004);\n        } else {\n          propsBuilder_.clear();\n        }\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_TransactionEnd_descriptor;\n      }\n\n      public TransactionEnd getDefaultInstanceForType() {\n        return TransactionEnd.getDefaultInstance();\n      }\n\n      public TransactionEnd build() {\n        TransactionEnd result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public TransactionEnd buildPartial() {\n        TransactionEnd result = new TransactionEnd(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.executeTime_ = executeTime_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.transactionId_ = transactionId_;\n        if (propsBuilder_ == null) {\n          if (((bitField0_ & 0x00000004) == 0x00000004)) {\n            props_ = java.util.Collections.unmodifiableList(props_);\n            bitField0_ = (bitField0_ & ~0x00000004);\n          }\n          result.props_ = props_;\n        } else {\n          result.props_ = propsBuilder_.build();\n        }\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof TransactionEnd) {\n          return mergeFrom((TransactionEnd)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(TransactionEnd other) {\n        if (other == TransactionEnd.getDefaultInstance()) return this;\n        if (other.hasExecuteTime()) {\n          setExecuteTime(other.getExecuteTime());\n        }\n        if (other.hasTransactionId()) {\n          bitField0_ |= 0x00000002;\n          transactionId_ = other.transactionId_;\n          onChanged();\n        }\n        if (propsBuilder_ == null) {\n          if (!other.props_.isEmpty()) {\n            if (props_.isEmpty()) {\n              props_ = other.props_;\n              bitField0_ = (bitField0_ & ~0x00000004);\n            } else {\n              ensurePropsIsMutable();\n              props_.addAll(other.props_);\n            }\n            onChanged();\n          }\n        } else {\n          if (!other.props_.isEmpty()) {\n            if (propsBuilder_.isEmpty()) {\n              propsBuilder_.dispose();\n              propsBuilder_ = null;\n              props_ = other.props_;\n              bitField0_ = (bitField0_ & ~0x00000004);\n              propsBuilder_ =\n                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n                   getPropsFieldBuilder() : null;\n            } else {\n              propsBuilder_.addAllMessages(other.props_);\n            }\n          }\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        TransactionEnd parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (TransactionEnd) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      private long executeTime_ ;\n      /**\n       * <code>optional int64 executeTime = 1;</code>\n       *\n       * <pre>\n       **已废弃，请使用header里的executeTime*\n       * </pre>\n       */\n      public boolean hasExecuteTime() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>optional int64 executeTime = 1;</code>\n       *\n       * <pre>\n       **已废弃，请使用header里的executeTime*\n       * </pre>\n       */\n      public long getExecuteTime() {\n        return executeTime_;\n      }\n      /**\n       * <code>optional int64 executeTime = 1;</code>\n       *\n       * <pre>\n       **已废弃，请使用header里的executeTime*\n       * </pre>\n       */\n      public Builder setExecuteTime(long value) {\n        bitField0_ |= 0x00000001;\n        executeTime_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int64 executeTime = 1;</code>\n       *\n       * <pre>\n       **已废弃，请使用header里的executeTime*\n       * </pre>\n       */\n      public Builder clearExecuteTime() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        executeTime_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      private Object transactionId_ = \"\";\n      /**\n       * <code>optional string transactionId = 2;</code>\n       *\n       * <pre>\n       **事务号*\n       * </pre>\n       */\n      public boolean hasTransactionId() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>optional string transactionId = 2;</code>\n       *\n       * <pre>\n       **事务号*\n       * </pre>\n       */\n      public String getTransactionId() {\n        Object ref = transactionId_;\n        if (!(ref instanceof String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          String s = bs.toStringUtf8();\n          if (bs.isValidUtf8()) {\n            transactionId_ = s;\n          }\n          return s;\n        } else {\n          return (String) ref;\n        }\n      }\n      /**\n       * <code>optional string transactionId = 2;</code>\n       *\n       * <pre>\n       **事务号*\n       * </pre>\n       */\n      public com.google.protobuf.ByteString\n          getTransactionIdBytes() {\n        Object ref = transactionId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b =\n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (String) ref);\n          transactionId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string transactionId = 2;</code>\n       *\n       * <pre>\n       **事务号*\n       * </pre>\n       */\n      public Builder setTransactionId(\n          String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        transactionId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string transactionId = 2;</code>\n       *\n       * <pre>\n       **事务号*\n       * </pre>\n       */\n      public Builder clearTransactionId() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        transactionId_ = getDefaultInstance().getTransactionId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string transactionId = 2;</code>\n       *\n       * <pre>\n       **事务号*\n       * </pre>\n       */\n      public Builder setTransactionIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        transactionId_ = value;\n        onChanged();\n        return this;\n      }\n\n      private java.util.List<Pair> props_ =\n        java.util.Collections.emptyList();\n      private void ensurePropsIsMutable() {\n        if (!((bitField0_ & 0x00000004) == 0x00000004)) {\n          props_ = new java.util.ArrayList<Pair>(props_);\n          bitField0_ |= 0x00000004;\n         }\n      }\n\n      private com.google.protobuf.RepeatedFieldBuilder<\n          Pair, Pair.Builder, PairOrBuilder> propsBuilder_;\n\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public java.util.List<Pair> getPropsList() {\n        if (propsBuilder_ == null) {\n          return java.util.Collections.unmodifiableList(props_);\n        } else {\n          return propsBuilder_.getMessageList();\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public int getPropsCount() {\n        if (propsBuilder_ == null) {\n          return props_.size();\n        } else {\n          return propsBuilder_.getCount();\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Pair getProps(int index) {\n        if (propsBuilder_ == null) {\n          return props_.get(index);\n        } else {\n          return propsBuilder_.getMessage(index);\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder setProps(\n          int index, Pair value) {\n        if (propsBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensurePropsIsMutable();\n          props_.set(index, value);\n          onChanged();\n        } else {\n          propsBuilder_.setMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder setProps(\n          int index, Pair.Builder builderForValue) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          props_.set(index, builderForValue.build());\n          onChanged();\n        } else {\n          propsBuilder_.setMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addProps(Pair value) {\n        if (propsBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensurePropsIsMutable();\n          props_.add(value);\n          onChanged();\n        } else {\n          propsBuilder_.addMessage(value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addProps(\n          int index, Pair value) {\n        if (propsBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensurePropsIsMutable();\n          props_.add(index, value);\n          onChanged();\n        } else {\n          propsBuilder_.addMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addProps(\n          Pair.Builder builderForValue) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          props_.add(builderForValue.build());\n          onChanged();\n        } else {\n          propsBuilder_.addMessage(builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addProps(\n          int index, Pair.Builder builderForValue) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          props_.add(index, builderForValue.build());\n          onChanged();\n        } else {\n          propsBuilder_.addMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder addAllProps(\n          Iterable<? extends Pair> values) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          com.google.protobuf.AbstractMessageLite.Builder.addAll(\n              values, props_);\n          onChanged();\n        } else {\n          propsBuilder_.addAllMessages(values);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder clearProps() {\n        if (propsBuilder_ == null) {\n          props_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000004);\n          onChanged();\n        } else {\n          propsBuilder_.clear();\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Builder removeProps(int index) {\n        if (propsBuilder_ == null) {\n          ensurePropsIsMutable();\n          props_.remove(index);\n          onChanged();\n        } else {\n          propsBuilder_.remove(index);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Pair.Builder getPropsBuilder(\n          int index) {\n        return getPropsFieldBuilder().getBuilder(index);\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public PairOrBuilder getPropsOrBuilder(\n          int index) {\n        if (propsBuilder_ == null) {\n          return props_.get(index);  } else {\n          return propsBuilder_.getMessageOrBuilder(index);\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public java.util.List<? extends PairOrBuilder>\n           getPropsOrBuilderList() {\n        if (propsBuilder_ != null) {\n          return propsBuilder_.getMessageOrBuilderList();\n        } else {\n          return java.util.Collections.unmodifiableList(props_);\n        }\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Pair.Builder addPropsBuilder() {\n        return getPropsFieldBuilder().addBuilder(\n            Pair.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public Pair.Builder addPropsBuilder(\n          int index) {\n        return getPropsFieldBuilder().addBuilder(\n            index, Pair.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .com.alibaba.otter.canal.protocol.Pair props = 3;</code>\n       *\n       * <pre>\n       **预留扩展*\n       * </pre>\n       */\n      public java.util.List<Pair.Builder>\n           getPropsBuilderList() {\n        return getPropsFieldBuilder().getBuilderList();\n      }\n      private com.google.protobuf.RepeatedFieldBuilder<\n          Pair, Pair.Builder, PairOrBuilder>\n          getPropsFieldBuilder() {\n        if (propsBuilder_ == null) {\n          propsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<\n              Pair, Pair.Builder, PairOrBuilder>(\n                  props_,\n                  ((bitField0_ & 0x00000004) == 0x00000004),\n                  getParentForChildren(),\n                  isClean());\n          props_ = null;\n        }\n        return propsBuilder_;\n      }\n\n      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.TransactionEnd)\n    }\n\n    static {\n      defaultInstance = new TransactionEnd(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.TransactionEnd)\n  }\n\n  public interface PairOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.Pair)\n      com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <code>optional string key = 1;</code>\n     */\n    boolean hasKey();\n    /**\n     * <code>optional string key = 1;</code>\n     */\n    String getKey();\n    /**\n     * <code>optional string key = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getKeyBytes();\n\n    /**\n     * <code>optional string value = 2;</code>\n     */\n    boolean hasValue();\n    /**\n     * <code>optional string value = 2;</code>\n     */\n    String getValue();\n    /**\n     * <code>optional string value = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getValueBytes();\n  }\n  /**\n   * Protobuf type {@code com.alibaba.otter.canal.protocol.Pair}\n   *\n   * <pre>\n   **预留扩展*\n   * </pre>\n   */\n  public static final class Pair extends\n      com.google.protobuf.GeneratedMessage implements\n      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.Pair)\n      PairOrBuilder {\n    // Use Pair.newBuilder() to construct.\n    private Pair(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private Pair(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final Pair defaultInstance;\n    public static Pair getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public Pair getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private Pair(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              com.google.protobuf.ByteString bs = input.readBytes();\n              bitField0_ |= 0x00000001;\n              key_ = bs;\n              break;\n            }\n            case 18: {\n              com.google.protobuf.ByteString bs = input.readBytes();\n              bitField0_ |= 0x00000002;\n              value_ = bs;\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_Pair_descriptor;\n    }\n\n    protected FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_Pair_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              Pair.class, Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<Pair> PARSER =\n        new com.google.protobuf.AbstractParser<Pair>() {\n      public Pair parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new Pair(input, extensionRegistry);\n      }\n    };\n\n    @Override\n    public com.google.protobuf.Parser<Pair> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    public static final int KEY_FIELD_NUMBER = 1;\n    private Object key_;\n    /**\n     * <code>optional string key = 1;</code>\n     */\n    public boolean hasKey() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>optional string key = 1;</code>\n     */\n    public String getKey() {\n      Object ref = key_;\n      if (ref instanceof String) {\n        return (String) ref;\n      } else {\n        com.google.protobuf.ByteString bs =\n            (com.google.protobuf.ByteString) ref;\n        String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          key_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string key = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getKeyBytes() {\n      Object ref = key_;\n      if (ref instanceof String) {\n        com.google.protobuf.ByteString b =\n            com.google.protobuf.ByteString.copyFromUtf8(\n                (String) ref);\n        key_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int VALUE_FIELD_NUMBER = 2;\n    private Object value_;\n    /**\n     * <code>optional string value = 2;</code>\n     */\n    public boolean hasValue() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>optional string value = 2;</code>\n     */\n    public String getValue() {\n      Object ref = value_;\n      if (ref instanceof String) {\n        return (String) ref;\n      } else {\n        com.google.protobuf.ByteString bs =\n            (com.google.protobuf.ByteString) ref;\n        String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          value_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string value = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getValueBytes() {\n      Object ref = value_;\n      if (ref instanceof String) {\n        com.google.protobuf.ByteString b =\n            com.google.protobuf.ByteString.copyFromUtf8(\n                (String) ref);\n        value_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      key_ = \"\";\n      value_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getKeyBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeBytes(2, getValueBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getKeyBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, getValueBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @Override\n    protected Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static Pair parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static Pair parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static Pair parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static Pair parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static Pair parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static Pair parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static Pair parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static Pair parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static Pair parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static Pair parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(Pair prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @Override\n    protected Builder newBuilderForType(\n        BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code com.alibaba.otter.canal.protocol.Pair}\n     *\n     * <pre>\n     **预留扩展*\n     * </pre>\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.Pair)\n        PairOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_Pair_descriptor;\n      }\n\n      protected FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_Pair_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                Pair.class, Builder.class);\n      }\n\n      // Construct using com.alibaba.otter.canal.protocol.CanalEntry.Pair.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        key_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        value_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000002);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return CanalEntry.internal_static_com_alibaba_otter_canal_protocol_Pair_descriptor;\n      }\n\n      public Pair getDefaultInstanceForType() {\n        return Pair.getDefaultInstance();\n      }\n\n      public Pair build() {\n        Pair result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public Pair buildPartial() {\n        Pair result = new Pair(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.key_ = key_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.value_ = value_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof Pair) {\n          return mergeFrom((Pair)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(Pair other) {\n        if (other == Pair.getDefaultInstance()) return this;\n        if (other.hasKey()) {\n          bitField0_ |= 0x00000001;\n          key_ = other.key_;\n          onChanged();\n        }\n        if (other.hasValue()) {\n          bitField0_ |= 0x00000002;\n          value_ = other.value_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        Pair parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (Pair) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      private Object key_ = \"\";\n      /**\n       * <code>optional string key = 1;</code>\n       */\n      public boolean hasKey() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>optional string key = 1;</code>\n       */\n      public String getKey() {\n        Object ref = key_;\n        if (!(ref instanceof String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          String s = bs.toStringUtf8();\n          if (bs.isValidUtf8()) {\n            key_ = s;\n          }\n          return s;\n        } else {\n          return (String) ref;\n        }\n      }\n      /**\n       * <code>optional string key = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getKeyBytes() {\n        Object ref = key_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b =\n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (String) ref);\n          key_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string key = 1;</code>\n       */\n      public Builder setKey(\n          String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        key_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string key = 1;</code>\n       */\n      public Builder clearKey() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        key_ = getDefaultInstance().getKey();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string key = 1;</code>\n       */\n      public Builder setKeyBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        key_ = value;\n        onChanged();\n        return this;\n      }\n\n      private Object value_ = \"\";\n      /**\n       * <code>optional string value = 2;</code>\n       */\n      public boolean hasValue() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>optional string value = 2;</code>\n       */\n      public String getValue() {\n        Object ref = value_;\n        if (!(ref instanceof String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          String s = bs.toStringUtf8();\n          if (bs.isValidUtf8()) {\n            value_ = s;\n          }\n          return s;\n        } else {\n          return (String) ref;\n        }\n      }\n      /**\n       * <code>optional string value = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getValueBytes() {\n        Object ref = value_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b =\n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (String) ref);\n          value_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string value = 2;</code>\n       */\n      public Builder setValue(\n          String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        value_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string value = 2;</code>\n       */\n      public Builder clearValue() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        value_ = getDefaultInstance().getValue();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string value = 2;</code>\n       */\n      public Builder setValueBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        value_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.Pair)\n    }\n\n    static {\n      defaultInstance = new Pair(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.Pair)\n  }\n\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_com_alibaba_otter_canal_protocol_Entry_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_com_alibaba_otter_canal_protocol_Entry_fieldAccessorTable;\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_com_alibaba_otter_canal_protocol_Header_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_com_alibaba_otter_canal_protocol_Header_fieldAccessorTable;\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_com_alibaba_otter_canal_protocol_Column_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_com_alibaba_otter_canal_protocol_Column_fieldAccessorTable;\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_com_alibaba_otter_canal_protocol_RowData_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_com_alibaba_otter_canal_protocol_RowData_fieldAccessorTable;\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_com_alibaba_otter_canal_protocol_RowChange_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_com_alibaba_otter_canal_protocol_RowChange_fieldAccessorTable;\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_com_alibaba_otter_canal_protocol_TransactionBegin_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_com_alibaba_otter_canal_protocol_TransactionBegin_fieldAccessorTable;\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_com_alibaba_otter_canal_protocol_TransactionEnd_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_com_alibaba_otter_canal_protocol_TransactionEnd_fieldAccessorTable;\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_com_alibaba_otter_canal_protocol_Pair_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_com_alibaba_otter_canal_protocol_Pair_fieldAccessorTable;\n\n  public static com.google.protobuf.Descriptors.FileDescriptor\n      getDescriptor() {\n    return descriptor;\n  }\n  private static com.google.protobuf.Descriptors.FileDescriptor\n      descriptor;\n  static {\n    String[] descriptorData = {\n      \"\\n\\023EntryProtocol.proto\\022 com.alibaba.otter\" +\n      \".canal.protocol\\\"\\236\\001\\n\\005Entry\\0228\\n\\006header\\030\\001 \\001(\" +\n      \"\\0132(.com.alibaba.otter.canal.protocol.Hea\" +\n      \"der\\022G\\n\\tentryType\\030\\002 \\001(\\0162+.com.alibaba.ott\" +\n      \"er.canal.protocol.EntryType:\\007ROWDATA\\022\\022\\n\\n\" +\n      \"storeValue\\030\\003 \\001(\\014\\\"\\221\\003\\n\\006Header\\022\\022\\n\\007version\\030\\001\" +\n      \" \\001(\\005:\\0011\\022\\023\\n\\013logfileName\\030\\002 \\001(\\t\\022\\025\\n\\rlogfileO\" +\n      \"ffset\\030\\003 \\001(\\003\\022\\020\\n\\010serverId\\030\\004 \\001(\\003\\022\\024\\n\\014servere\" +\n      \"nCode\\030\\005 \\001(\\t\\022\\023\\n\\013executeTime\\030\\006 \\001(\\003\\022A\\n\\nsour\" +\n      \"ceType\\030\\007 \\001(\\0162&.com.alibaba.otter.canal.p\",\n      \"rotocol.Type:\\005MYSQL\\022\\022\\n\\nschemaName\\030\\010 \\001(\\t\\022\" +\n      \"\\021\\n\\ttableName\\030\\t \\001(\\t\\022\\023\\n\\013eventLength\\030\\n \\001(\\003\\022\" +\n      \"F\\n\\teventType\\030\\013 \\001(\\0162+.com.alibaba.otter.c\" +\n      \"anal.protocol.EventType:\\006UPDATE\\0225\\n\\005props\" +\n      \"\\030\\014 \\003(\\0132&.com.alibaba.otter.canal.protoco\" +\n      \"l.Pair\\022\\014\\n\\004gtid\\030\\r \\001(\\t\\\"\\326\\001\\n\\006Column\\022\\r\\n\\005index\" +\n      \"\\030\\001 \\001(\\005\\022\\017\\n\\007sqlType\\030\\002 \\001(\\005\\022\\014\\n\\004name\\030\\003 \\001(\\t\\022\\r\\n\" +\n      \"\\005isKey\\030\\004 \\001(\\010\\022\\017\\n\\007updated\\030\\005 \\001(\\010\\022\\025\\n\\006isNull\\030\" +\n      \"\\006 \\001(\\010:\\005false\\0225\\n\\005props\\030\\007 \\003(\\0132&.com.alibab\" +\n      \"a.otter.canal.protocol.Pair\\022\\r\\n\\005value\\030\\010 \\001\",\n      \"(\\t\\022\\016\\n\\006length\\030\\t \\001(\\005\\022\\021\\n\\tmysqlType\\030\\n \\001(\\t\\\"\\301\\001\" +\n      \"\\n\\007RowData\\022?\\n\\rbeforeColumns\\030\\001 \\003(\\0132(.com.a\" +\n      \"libaba.otter.canal.protocol.Column\\022>\\n\\014af\" +\n      \"terColumns\\030\\002 \\003(\\0132(.com.alibaba.otter.can\" +\n      \"al.protocol.Column\\0225\\n\\005props\\030\\003 \\003(\\0132&.com.\" +\n      \"alibaba.otter.canal.protocol.Pair\\\"\\222\\002\\n\\tRo\" +\n      \"wChange\\022\\017\\n\\007tableId\\030\\001 \\001(\\003\\022F\\n\\teventType\\030\\002 \" +\n      \"\\001(\\0162+.com.alibaba.otter.canal.protocol.E\" +\n      \"ventType:\\006UPDATE\\022\\024\\n\\005isDdl\\030\\n \\001(\\010:\\005false\\022\\013\" +\n      \"\\n\\003sql\\030\\013 \\001(\\t\\022;\\n\\010rowDatas\\030\\014 \\003(\\0132).com.alib\",\n      \"aba.otter.canal.protocol.RowData\\0225\\n\\005prop\" +\n      \"s\\030\\r \\003(\\0132&.com.alibaba.otter.canal.protoc\" +\n      \"ol.Pair\\022\\025\\n\\rddlSchemaName\\030\\016 \\001(\\t\\\"\\207\\001\\n\\020Trans\" +\n      \"actionBegin\\022\\023\\n\\013executeTime\\030\\001 \\001(\\003\\022\\025\\n\\rtran\" +\n      \"sactionId\\030\\002 \\001(\\t\\0225\\n\\005props\\030\\003 \\003(\\0132&.com.ali\" +\n      \"baba.otter.canal.protocol.Pair\\022\\020\\n\\010thread\" +\n      \"Id\\030\\004 \\001(\\003\\\"s\\n\\016TransactionEnd\\022\\023\\n\\013executeTim\" +\n      \"e\\030\\001 \\001(\\003\\022\\025\\n\\rtransactionId\\030\\002 \\001(\\t\\0225\\n\\005props\\030\" +\n      \"\\003 \\003(\\0132&.com.alibaba.otter.canal.protocol\" +\n      \".Pair\\\"\\\"\\n\\004Pair\\022\\013\\n\\003key\\030\\001 \\001(\\t\\022\\r\\n\\005value\\030\\002 \\001(\",\n      \"\\t*^\\n\\tEntryType\\022\\024\\n\\020TRANSACTIONBEGIN\\020\\001\\022\\013\\n\\007\" +\n      \"ROWDATA\\020\\002\\022\\022\\n\\016TRANSACTIONEND\\020\\003\\022\\r\\n\\tHEARTBE\" +\n      \"AT\\020\\004\\022\\013\\n\\007GTIDLOG\\020\\005*\\306\\001\\n\\tEventType\\022\\n\\n\\006INSER\" +\n      \"T\\020\\001\\022\\n\\n\\006UPDATE\\020\\002\\022\\n\\n\\006DELETE\\020\\003\\022\\n\\n\\006CREATE\\020\\004\\022\" +\n      \"\\t\\n\\005ALTER\\020\\005\\022\\t\\n\\005ERASE\\020\\006\\022\\t\\n\\005QUERY\\020\\007\\022\\014\\n\\010TRUN\" +\n      \"CATE\\020\\010\\022\\n\\n\\006RENAME\\020\\t\\022\\n\\n\\006CINDEX\\020\\n\\022\\n\\n\\006DINDEX\" +\n      \"\\020\\013\\022\\010\\n\\004GTID\\020\\014\\022\\014\\n\\010XACOMMIT\\020\\r\\022\\016\\n\\nXAROLLBACK\" +\n      \"\\020\\016\\022\\016\\n\\nMHEARTBEAT\\020\\017*(\\n\\004Type\\022\\n\\n\\006ORACLE\\020\\001\\022\\t\" +\n      \"\\n\\005MYSQL\\020\\002\\022\\t\\n\\005PGSQL\\020\\003B0\\n com.alibaba.otte\" +\n      \"r.canal.protocolB\\nCanalEntryH\\001\"\n    };\n    com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =\n        new com.google.protobuf.Descriptors.FileDescriptor.    InternalDescriptorAssigner() {\n          public com.google.protobuf.ExtensionRegistry assignDescriptors(\n              com.google.protobuf.Descriptors.FileDescriptor root) {\n            descriptor = root;\n            return null;\n          }\n        };\n    com.google.protobuf.Descriptors.FileDescriptor\n      .internalBuildGeneratedFileFrom(descriptorData,\n        new com.google.protobuf.Descriptors.FileDescriptor[] {\n        }, assigner);\n    internal_static_com_alibaba_otter_canal_protocol_Entry_descriptor =\n      getDescriptor().getMessageTypes().get(0);\n    internal_static_com_alibaba_otter_canal_protocol_Entry_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n        internal_static_com_alibaba_otter_canal_protocol_Entry_descriptor,\n        new String[] { \"Header\", \"EntryType\", \"StoreValue\", });\n    internal_static_com_alibaba_otter_canal_protocol_Header_descriptor =\n      getDescriptor().getMessageTypes().get(1);\n    internal_static_com_alibaba_otter_canal_protocol_Header_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n        internal_static_com_alibaba_otter_canal_protocol_Header_descriptor,\n        new String[] { \"Version\", \"LogfileName\", \"LogfileOffset\", \"ServerId\", \"ServerenCode\", \"ExecuteTime\", \"SourceType\", \"SchemaName\", \"TableName\", \"EventLength\", \"EventType\", \"Props\", \"Gtid\", });\n    internal_static_com_alibaba_otter_canal_protocol_Column_descriptor =\n      getDescriptor().getMessageTypes().get(2);\n    internal_static_com_alibaba_otter_canal_protocol_Column_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n        internal_static_com_alibaba_otter_canal_protocol_Column_descriptor,\n        new String[] { \"Index\", \"SqlType\", \"Name\", \"IsKey\", \"Updated\", \"IsNull\", \"Props\", \"Value\", \"Length\", \"MysqlType\", });\n    internal_static_com_alibaba_otter_canal_protocol_RowData_descriptor =\n      getDescriptor().getMessageTypes().get(3);\n    internal_static_com_alibaba_otter_canal_protocol_RowData_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n        internal_static_com_alibaba_otter_canal_protocol_RowData_descriptor,\n        new String[] { \"BeforeColumns\", \"AfterColumns\", \"Props\", });\n    internal_static_com_alibaba_otter_canal_protocol_RowChange_descriptor =\n      getDescriptor().getMessageTypes().get(4);\n    internal_static_com_alibaba_otter_canal_protocol_RowChange_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n        internal_static_com_alibaba_otter_canal_protocol_RowChange_descriptor,\n        new String[] { \"TableId\", \"EventType\", \"IsDdl\", \"Sql\", \"RowDatas\", \"Props\", \"DdlSchemaName\", });\n    internal_static_com_alibaba_otter_canal_protocol_TransactionBegin_descriptor =\n      getDescriptor().getMessageTypes().get(5);\n    internal_static_com_alibaba_otter_canal_protocol_TransactionBegin_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n        internal_static_com_alibaba_otter_canal_protocol_TransactionBegin_descriptor,\n        new String[] { \"ExecuteTime\", \"TransactionId\", \"Props\", \"ThreadId\", });\n    internal_static_com_alibaba_otter_canal_protocol_TransactionEnd_descriptor =\n      getDescriptor().getMessageTypes().get(6);\n    internal_static_com_alibaba_otter_canal_protocol_TransactionEnd_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n        internal_static_com_alibaba_otter_canal_protocol_TransactionEnd_descriptor,\n        new String[] { \"ExecuteTime\", \"TransactionId\", \"Props\", });\n    internal_static_com_alibaba_otter_canal_protocol_Pair_descriptor =\n      getDescriptor().getMessageTypes().get(7);\n    internal_static_com_alibaba_otter_canal_protocol_Pair_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n        internal_static_com_alibaba_otter_canal_protocol_Pair_descriptor,\n        new String[] { \"Key\", \"Value\", });\n  }\n\n  // @@protoc_insertion_point(outer_class_scope)\n}\n"
  },
  {
    "path": "protocol/src/main/java/com/alibaba/otter/canal/protocol/CanalPacket.java",
    "content": "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n// source: CanalProtocol.proto\n\npackage com.alibaba.otter.canal.protocol;\n\npublic final class CanalPacket {\n  private CanalPacket() {}\n  public static void registerAllExtensions(\n      com.google.protobuf.ExtensionRegistryLite registry) {\n  }\n\n  public static void registerAllExtensions(\n      com.google.protobuf.ExtensionRegistry registry) {\n    registerAllExtensions(\n        (com.google.protobuf.ExtensionRegistryLite) registry);\n  }\n  /**\n   * Protobuf enum {@code com.alibaba.otter.canal.protocol.Compression}\n   */\n  public enum Compression\n      implements com.google.protobuf.ProtocolMessageEnum {\n    /**\n     * <code>COMPRESSIONCOMPATIBLEPROTO2 = 0;</code>\n     */\n    COMPRESSIONCOMPATIBLEPROTO2(0),\n    /**\n     * <code>NONE = 1;</code>\n     */\n    NONE(1),\n    /**\n     * <code>ZLIB = 2;</code>\n     */\n    ZLIB(2),\n    /**\n     * <code>GZIP = 3;</code>\n     */\n    GZIP(3),\n    /**\n     * <code>LZF = 4;</code>\n     */\n    LZF(4),\n    UNRECOGNIZED(-1),\n    ;\n\n    /**\n     * <code>COMPRESSIONCOMPATIBLEPROTO2 = 0;</code>\n     */\n    public static final int COMPRESSIONCOMPATIBLEPROTO2_VALUE = 0;\n    /**\n     * <code>NONE = 1;</code>\n     */\n    public static final int NONE_VALUE = 1;\n    /**\n     * <code>ZLIB = 2;</code>\n     */\n    public static final int ZLIB_VALUE = 2;\n    /**\n     * <code>GZIP = 3;</code>\n     */\n    public static final int GZIP_VALUE = 3;\n    /**\n     * <code>LZF = 4;</code>\n     */\n    public static final int LZF_VALUE = 4;\n\n\n    public final int getNumber() {\n      if (this == UNRECOGNIZED) {\n        throw new java.lang.IllegalArgumentException(\n            \"Can't get the number of an unknown enum value.\");\n      }\n      return value;\n    }\n\n    /**\n     * @deprecated Use {@link #forNumber(int)} instead.\n     */\n    @java.lang.Deprecated\n    public static Compression valueOf(int value) {\n      return forNumber(value);\n    }\n\n    public static Compression forNumber(int value) {\n      switch (value) {\n        case 0: return COMPRESSIONCOMPATIBLEPROTO2;\n        case 1: return NONE;\n        case 2: return ZLIB;\n        case 3: return GZIP;\n        case 4: return LZF;\n        default: return null;\n      }\n    }\n\n    public static com.google.protobuf.Internal.EnumLiteMap<Compression>\n        internalGetValueMap() {\n      return internalValueMap;\n    }\n    private static final com.google.protobuf.Internal.EnumLiteMap<\n        Compression> internalValueMap =\n          new com.google.protobuf.Internal.EnumLiteMap<Compression>() {\n            public Compression findValueByNumber(int number) {\n              return Compression.forNumber(number);\n            }\n          };\n\n    public final com.google.protobuf.Descriptors.EnumValueDescriptor\n        getValueDescriptor() {\n      return getDescriptor().getValues().get(ordinal());\n    }\n    public final com.google.protobuf.Descriptors.EnumDescriptor\n        getDescriptorForType() {\n      return getDescriptor();\n    }\n    public static final com.google.protobuf.Descriptors.EnumDescriptor\n        getDescriptor() {\n      return com.alibaba.otter.canal.protocol.CanalPacket.getDescriptor().getEnumTypes().get(0);\n    }\n\n    private static final Compression[] VALUES = values();\n\n    public static Compression valueOf(\n        com.google.protobuf.Descriptors.EnumValueDescriptor desc) {\n      if (desc.getType() != getDescriptor()) {\n        throw new java.lang.IllegalArgumentException(\n          \"EnumValueDescriptor is not for this type.\");\n      }\n      if (desc.getIndex() == -1) {\n        return UNRECOGNIZED;\n      }\n      return VALUES[desc.getIndex()];\n    }\n\n    private final int value;\n\n    private Compression(int value) {\n      this.value = value;\n    }\n\n    // @@protoc_insertion_point(enum_scope:com.alibaba.otter.canal.protocol.Compression)\n  }\n\n  /**\n   * Protobuf enum {@code com.alibaba.otter.canal.protocol.PacketType}\n   */\n  public enum PacketType\n      implements com.google.protobuf.ProtocolMessageEnum {\n    /**\n     * <pre>\n     *compatible\n     * </pre>\n     *\n     * <code>PACKAGETYPECOMPATIBLEPROTO2 = 0;</code>\n     */\n    PACKAGETYPECOMPATIBLEPROTO2(0),\n    /**\n     * <code>HANDSHAKE = 1;</code>\n     */\n    HANDSHAKE(1),\n    /**\n     * <code>CLIENTAUTHENTICATION = 2;</code>\n     */\n    CLIENTAUTHENTICATION(2),\n    /**\n     * <code>ACK = 3;</code>\n     */\n    ACK(3),\n    /**\n     * <code>SUBSCRIPTION = 4;</code>\n     */\n    SUBSCRIPTION(4),\n    /**\n     * <code>UNSUBSCRIPTION = 5;</code>\n     */\n    UNSUBSCRIPTION(5),\n    /**\n     * <code>GET = 6;</code>\n     */\n    GET(6),\n    /**\n     * <code>MESSAGES = 7;</code>\n     */\n    MESSAGES(7),\n    /**\n     * <code>CLIENTACK = 8;</code>\n     */\n    CLIENTACK(8),\n    /**\n     * <pre>\n     * management part\n     * </pre>\n     *\n     * <code>SHUTDOWN = 9;</code>\n     */\n    SHUTDOWN(9),\n    /**\n     * <pre>\n     * integration\n     * </pre>\n     *\n     * <code>DUMP = 10;</code>\n     */\n    DUMP(10),\n    /**\n     * <code>HEARTBEAT = 11;</code>\n     */\n    HEARTBEAT(11),\n    /**\n     * <code>CLIENTROLLBACK = 12;</code>\n     */\n    CLIENTROLLBACK(12),\n    UNRECOGNIZED(-1),\n    ;\n\n    /**\n     * <pre>\n     *compatible\n     * </pre>\n     *\n     * <code>PACKAGETYPECOMPATIBLEPROTO2 = 0;</code>\n     */\n    public static final int PACKAGETYPECOMPATIBLEPROTO2_VALUE = 0;\n    /**\n     * <code>HANDSHAKE = 1;</code>\n     */\n    public static final int HANDSHAKE_VALUE = 1;\n    /**\n     * <code>CLIENTAUTHENTICATION = 2;</code>\n     */\n    public static final int CLIENTAUTHENTICATION_VALUE = 2;\n    /**\n     * <code>ACK = 3;</code>\n     */\n    public static final int ACK_VALUE = 3;\n    /**\n     * <code>SUBSCRIPTION = 4;</code>\n     */\n    public static final int SUBSCRIPTION_VALUE = 4;\n    /**\n     * <code>UNSUBSCRIPTION = 5;</code>\n     */\n    public static final int UNSUBSCRIPTION_VALUE = 5;\n    /**\n     * <code>GET = 6;</code>\n     */\n    public static final int GET_VALUE = 6;\n    /**\n     * <code>MESSAGES = 7;</code>\n     */\n    public static final int MESSAGES_VALUE = 7;\n    /**\n     * <code>CLIENTACK = 8;</code>\n     */\n    public static final int CLIENTACK_VALUE = 8;\n    /**\n     * <pre>\n     * management part\n     * </pre>\n     *\n     * <code>SHUTDOWN = 9;</code>\n     */\n    public static final int SHUTDOWN_VALUE = 9;\n    /**\n     * <pre>\n     * integration\n     * </pre>\n     *\n     * <code>DUMP = 10;</code>\n     */\n    public static final int DUMP_VALUE = 10;\n    /**\n     * <code>HEARTBEAT = 11;</code>\n     */\n    public static final int HEARTBEAT_VALUE = 11;\n    /**\n     * <code>CLIENTROLLBACK = 12;</code>\n     */\n    public static final int CLIENTROLLBACK_VALUE = 12;\n\n\n    public final int getNumber() {\n      if (this == UNRECOGNIZED) {\n        throw new java.lang.IllegalArgumentException(\n            \"Can't get the number of an unknown enum value.\");\n      }\n      return value;\n    }\n\n    /**\n     * @deprecated Use {@link #forNumber(int)} instead.\n     */\n    @java.lang.Deprecated\n    public static PacketType valueOf(int value) {\n      return forNumber(value);\n    }\n\n    public static PacketType forNumber(int value) {\n      switch (value) {\n        case 0: return PACKAGETYPECOMPATIBLEPROTO2;\n        case 1: return HANDSHAKE;\n        case 2: return CLIENTAUTHENTICATION;\n        case 3: return ACK;\n        case 4: return SUBSCRIPTION;\n        case 5: return UNSUBSCRIPTION;\n        case 6: return GET;\n        case 7: return MESSAGES;\n        case 8: return CLIENTACK;\n        case 9: return SHUTDOWN;\n        case 10: return DUMP;\n        case 11: return HEARTBEAT;\n        case 12: return CLIENTROLLBACK;\n        default: return null;\n      }\n    }\n\n    public static com.google.protobuf.Internal.EnumLiteMap<PacketType>\n        internalGetValueMap() {\n      return internalValueMap;\n    }\n    private static final com.google.protobuf.Internal.EnumLiteMap<\n        PacketType> internalValueMap =\n          new com.google.protobuf.Internal.EnumLiteMap<PacketType>() {\n            public PacketType findValueByNumber(int number) {\n              return PacketType.forNumber(number);\n            }\n          };\n\n    public final com.google.protobuf.Descriptors.EnumValueDescriptor\n        getValueDescriptor() {\n      return getDescriptor().getValues().get(ordinal());\n    }\n    public final com.google.protobuf.Descriptors.EnumDescriptor\n        getDescriptorForType() {\n      return getDescriptor();\n    }\n    public static final com.google.protobuf.Descriptors.EnumDescriptor\n        getDescriptor() {\n      return com.alibaba.otter.canal.protocol.CanalPacket.getDescriptor().getEnumTypes().get(1);\n    }\n\n    private static final PacketType[] VALUES = values();\n\n    public static PacketType valueOf(\n        com.google.protobuf.Descriptors.EnumValueDescriptor desc) {\n      if (desc.getType() != getDescriptor()) {\n        throw new java.lang.IllegalArgumentException(\n          \"EnumValueDescriptor is not for this type.\");\n      }\n      if (desc.getIndex() == -1) {\n        return UNRECOGNIZED;\n      }\n      return VALUES[desc.getIndex()];\n    }\n\n    private final int value;\n\n    private PacketType(int value) {\n      this.value = value;\n    }\n\n    // @@protoc_insertion_point(enum_scope:com.alibaba.otter.canal.protocol.PacketType)\n  }\n\n  public interface PacketOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.Packet)\n      com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <code>int32 magic_number = 1;</code>\n     */\n    int getMagicNumber();\n\n    /**\n     * <code>int32 version = 2;</code>\n     */\n    int getVersion();\n\n    /**\n     * <code>.com.alibaba.otter.canal.protocol.PacketType type = 3;</code>\n     */\n    int getTypeValue();\n    /**\n     * <code>.com.alibaba.otter.canal.protocol.PacketType type = 3;</code>\n     */\n    com.alibaba.otter.canal.protocol.CanalPacket.PacketType getType();\n\n    /**\n     * <code>.com.alibaba.otter.canal.protocol.Compression compression = 4;</code>\n     */\n    int getCompressionValue();\n    /**\n     * <code>.com.alibaba.otter.canal.protocol.Compression compression = 4;</code>\n     */\n    com.alibaba.otter.canal.protocol.CanalPacket.Compression getCompression();\n\n    /**\n     * <code>bytes body = 5;</code>\n     */\n    com.google.protobuf.ByteString getBody();\n\n    public com.alibaba.otter.canal.protocol.CanalPacket.Packet.MagicNumberPresentCase getMagicNumberPresentCase();\n\n    public com.alibaba.otter.canal.protocol.CanalPacket.Packet.VersionPresentCase getVersionPresentCase();\n\n    public com.alibaba.otter.canal.protocol.CanalPacket.Packet.CompressionPresentCase getCompressionPresentCase();\n  }\n  /**\n   * Protobuf type {@code com.alibaba.otter.canal.protocol.Packet}\n   */\n  public  static final class Packet extends\n      com.google.protobuf.GeneratedMessageV3 implements\n      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.Packet)\n      PacketOrBuilder {\n  private static final long serialVersionUID = 0L;\n    // Use Packet.newBuilder() to construct.\n    private Packet(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {\n      super(builder);\n    }\n    private Packet() {\n      type_ = 0;\n      body_ = com.google.protobuf.ByteString.EMPTY;\n    }\n\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n    getUnknownFields() {\n      return this.unknownFields;\n    }\n    private Packet(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      this();\n      if (extensionRegistry == null) {\n        throw new java.lang.NullPointerException();\n      }\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            case 8: {\n              magicNumberPresentCase_ = 1;\n              magicNumberPresent_ = input.readInt32();\n              break;\n            }\n            case 16: {\n              versionPresentCase_ = 2;\n              versionPresent_ = input.readInt32();\n              break;\n            }\n            case 24: {\n              int rawValue = input.readEnum();\n\n              type_ = rawValue;\n              break;\n            }\n            case 32: {\n              int rawValue = input.readEnum();\n              compressionPresentCase_ = 4;\n              compressionPresent_ = rawValue;\n              break;\n            }\n            case 42: {\n\n              body_ = input.readBytes();\n              break;\n            }\n            default: {\n              if (!parseUnknownFieldProto3(\n                  input, unknownFields, extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Packet_descriptor;\n    }\n\n    @java.lang.Override\n    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Packet_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              com.alibaba.otter.canal.protocol.CanalPacket.Packet.class, com.alibaba.otter.canal.protocol.CanalPacket.Packet.Builder.class);\n    }\n\n    private int magicNumberPresentCase_ = 0;\n    private java.lang.Object magicNumberPresent_;\n    public enum MagicNumberPresentCase\n        implements com.google.protobuf.Internal.EnumLite {\n      MAGIC_NUMBER(1),\n      MAGICNUMBERPRESENT_NOT_SET(0);\n      private final int value;\n      private MagicNumberPresentCase(int value) {\n        this.value = value;\n      }\n      /**\n       * @deprecated Use {@link #forNumber(int)} instead.\n       */\n      @java.lang.Deprecated\n      public static MagicNumberPresentCase valueOf(int value) {\n        return forNumber(value);\n      }\n\n      public static MagicNumberPresentCase forNumber(int value) {\n        switch (value) {\n          case 1: return MAGIC_NUMBER;\n          case 0: return MAGICNUMBERPRESENT_NOT_SET;\n          default: return null;\n        }\n      }\n      public int getNumber() {\n        return this.value;\n      }\n    };\n\n    public MagicNumberPresentCase\n    getMagicNumberPresentCase() {\n      return MagicNumberPresentCase.forNumber(\n          magicNumberPresentCase_);\n    }\n\n    private int versionPresentCase_ = 0;\n    private java.lang.Object versionPresent_;\n    public enum VersionPresentCase\n        implements com.google.protobuf.Internal.EnumLite {\n      VERSION(2),\n      VERSIONPRESENT_NOT_SET(0);\n      private final int value;\n      private VersionPresentCase(int value) {\n        this.value = value;\n      }\n      /**\n       * @deprecated Use {@link #forNumber(int)} instead.\n       */\n      @java.lang.Deprecated\n      public static VersionPresentCase valueOf(int value) {\n        return forNumber(value);\n      }\n\n      public static VersionPresentCase forNumber(int value) {\n        switch (value) {\n          case 2: return VERSION;\n          case 0: return VERSIONPRESENT_NOT_SET;\n          default: return null;\n        }\n      }\n      public int getNumber() {\n        return this.value;\n      }\n    };\n\n    public VersionPresentCase\n    getVersionPresentCase() {\n      return VersionPresentCase.forNumber(\n          versionPresentCase_);\n    }\n\n    private int compressionPresentCase_ = 0;\n    private java.lang.Object compressionPresent_;\n    public enum CompressionPresentCase\n        implements com.google.protobuf.Internal.EnumLite {\n      COMPRESSION(4),\n      COMPRESSIONPRESENT_NOT_SET(0);\n      private final int value;\n      private CompressionPresentCase(int value) {\n        this.value = value;\n      }\n      /**\n       * @deprecated Use {@link #forNumber(int)} instead.\n       */\n      @java.lang.Deprecated\n      public static CompressionPresentCase valueOf(int value) {\n        return forNumber(value);\n      }\n\n      public static CompressionPresentCase forNumber(int value) {\n        switch (value) {\n          case 4: return COMPRESSION;\n          case 0: return COMPRESSIONPRESENT_NOT_SET;\n          default: return null;\n        }\n      }\n      public int getNumber() {\n        return this.value;\n      }\n    };\n\n    public CompressionPresentCase\n    getCompressionPresentCase() {\n      return CompressionPresentCase.forNumber(\n          compressionPresentCase_);\n    }\n\n    public static final int MAGIC_NUMBER_FIELD_NUMBER = 1;\n    /**\n     * <code>int32 magic_number = 1;</code>\n     */\n    public int getMagicNumber() {\n      if (magicNumberPresentCase_ == 1) {\n        return (java.lang.Integer) magicNumberPresent_;\n      }\n      return 0;\n    }\n\n    public static final int VERSION_FIELD_NUMBER = 2;\n    /**\n     * <code>int32 version = 2;</code>\n     */\n    public int getVersion() {\n      if (versionPresentCase_ == 2) {\n        return (java.lang.Integer) versionPresent_;\n      }\n      return 0;\n    }\n\n    public static final int TYPE_FIELD_NUMBER = 3;\n    private int type_;\n    /**\n     * <code>.com.alibaba.otter.canal.protocol.PacketType type = 3;</code>\n     */\n    public int getTypeValue() {\n      return type_;\n    }\n    /**\n     * <code>.com.alibaba.otter.canal.protocol.PacketType type = 3;</code>\n     */\n    public com.alibaba.otter.canal.protocol.CanalPacket.PacketType getType() {\n      @SuppressWarnings(\"deprecation\")\n      com.alibaba.otter.canal.protocol.CanalPacket.PacketType result = com.alibaba.otter.canal.protocol.CanalPacket.PacketType.valueOf(type_);\n      return result == null ? com.alibaba.otter.canal.protocol.CanalPacket.PacketType.UNRECOGNIZED : result;\n    }\n\n    public static final int COMPRESSION_FIELD_NUMBER = 4;\n    /**\n     * <code>.com.alibaba.otter.canal.protocol.Compression compression = 4;</code>\n     */\n    public int getCompressionValue() {\n      if (compressionPresentCase_ == 4) {\n        return (java.lang.Integer) compressionPresent_;\n      }\n      return 0;\n    }\n    /**\n     * <code>.com.alibaba.otter.canal.protocol.Compression compression = 4;</code>\n     */\n    public com.alibaba.otter.canal.protocol.CanalPacket.Compression getCompression() {\n      if (compressionPresentCase_ == 4) {\n        @SuppressWarnings(\"deprecation\")\n        com.alibaba.otter.canal.protocol.CanalPacket.Compression result = com.alibaba.otter.canal.protocol.CanalPacket.Compression.valueOf(\n            (java.lang.Integer) compressionPresent_);\n        return result == null ? com.alibaba.otter.canal.protocol.CanalPacket.Compression.UNRECOGNIZED : result;\n      }\n      return com.alibaba.otter.canal.protocol.CanalPacket.Compression.COMPRESSIONCOMPATIBLEPROTO2;\n    }\n\n    public static final int BODY_FIELD_NUMBER = 5;\n    private com.google.protobuf.ByteString body_;\n    /**\n     * <code>bytes body = 5;</code>\n     */\n    public com.google.protobuf.ByteString getBody() {\n      return body_;\n    }\n\n    private byte memoizedIsInitialized = -1;\n    @java.lang.Override\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    @java.lang.Override\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      if (magicNumberPresentCase_ == 1) {\n        output.writeInt32(\n            1, (int)((java.lang.Integer) magicNumberPresent_));\n      }\n      if (versionPresentCase_ == 2) {\n        output.writeInt32(\n            2, (int)((java.lang.Integer) versionPresent_));\n      }\n      if (type_ != com.alibaba.otter.canal.protocol.CanalPacket.PacketType.PACKAGETYPECOMPATIBLEPROTO2.getNumber()) {\n        output.writeEnum(3, type_);\n      }\n      if (compressionPresentCase_ == 4) {\n        output.writeEnum(4, ((java.lang.Integer) compressionPresent_));\n      }\n      if (!body_.isEmpty()) {\n        output.writeBytes(5, body_);\n      }\n      unknownFields.writeTo(output);\n    }\n\n    @java.lang.Override\n    public int getSerializedSize() {\n      int size = memoizedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (magicNumberPresentCase_ == 1) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(\n              1, (int)((java.lang.Integer) magicNumberPresent_));\n      }\n      if (versionPresentCase_ == 2) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(\n              2, (int)((java.lang.Integer) versionPresent_));\n      }\n      if (type_ != com.alibaba.otter.canal.protocol.CanalPacket.PacketType.PACKAGETYPECOMPATIBLEPROTO2.getNumber()) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeEnumSize(3, type_);\n      }\n      if (compressionPresentCase_ == 4) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeEnumSize(4, ((java.lang.Integer) compressionPresent_));\n      }\n      if (!body_.isEmpty()) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(5, body_);\n      }\n      size += unknownFields.getSerializedSize();\n      memoizedSize = size;\n      return size;\n    }\n\n    @java.lang.Override\n    public boolean equals(final java.lang.Object obj) {\n      if (obj == this) {\n       return true;\n      }\n      if (!(obj instanceof com.alibaba.otter.canal.protocol.CanalPacket.Packet)) {\n        return super.equals(obj);\n      }\n      com.alibaba.otter.canal.protocol.CanalPacket.Packet other = (com.alibaba.otter.canal.protocol.CanalPacket.Packet) obj;\n\n      boolean result = true;\n      result = result && type_ == other.type_;\n      result = result && getBody()\n          .equals(other.getBody());\n      result = result && getMagicNumberPresentCase().equals(\n          other.getMagicNumberPresentCase());\n      if (!result) return false;\n      switch (magicNumberPresentCase_) {\n        case 1:\n          result = result && (getMagicNumber()\n              == other.getMagicNumber());\n          break;\n        case 0:\n        default:\n      }\n      result = result && getVersionPresentCase().equals(\n          other.getVersionPresentCase());\n      if (!result) return false;\n      switch (versionPresentCase_) {\n        case 2:\n          result = result && (getVersion()\n              == other.getVersion());\n          break;\n        case 0:\n        default:\n      }\n      result = result && getCompressionPresentCase().equals(\n          other.getCompressionPresentCase());\n      if (!result) return false;\n      switch (compressionPresentCase_) {\n        case 4:\n          result = result && getCompressionValue()\n              == other.getCompressionValue();\n          break;\n        case 0:\n        default:\n      }\n      result = result && unknownFields.equals(other.unknownFields);\n      return result;\n    }\n\n    @java.lang.Override\n    public int hashCode() {\n      if (memoizedHashCode != 0) {\n        return memoizedHashCode;\n      }\n      int hash = 41;\n      hash = (19 * hash) + getDescriptor().hashCode();\n      hash = (37 * hash) + TYPE_FIELD_NUMBER;\n      hash = (53 * hash) + type_;\n      hash = (37 * hash) + BODY_FIELD_NUMBER;\n      hash = (53 * hash) + getBody().hashCode();\n      switch (magicNumberPresentCase_) {\n        case 1:\n          hash = (37 * hash) + MAGIC_NUMBER_FIELD_NUMBER;\n          hash = (53 * hash) + getMagicNumber();\n          break;\n        case 0:\n        default:\n      }\n      switch (versionPresentCase_) {\n        case 2:\n          hash = (37 * hash) + VERSION_FIELD_NUMBER;\n          hash = (53 * hash) + getVersion();\n          break;\n        case 0:\n        default:\n      }\n      switch (compressionPresentCase_) {\n        case 4:\n          hash = (37 * hash) + COMPRESSION_FIELD_NUMBER;\n          hash = (53 * hash) + getCompressionValue();\n          break;\n        case 0:\n        default:\n      }\n      hash = (29 * hash) + unknownFields.hashCode();\n      memoizedHashCode = hash;\n      return hash;\n    }\n\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Packet parseFrom(\n        java.nio.ByteBuffer data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Packet parseFrom(\n        java.nio.ByteBuffer data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Packet parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Packet parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Packet parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Packet parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Packet parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Packet parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Packet parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Packet parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Packet parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Packet parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    @java.lang.Override\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder() {\n      return DEFAULT_INSTANCE.toBuilder();\n    }\n    public static Builder newBuilder(com.alibaba.otter.canal.protocol.CanalPacket.Packet prototype) {\n      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n    }\n    @java.lang.Override\n    public Builder toBuilder() {\n      return this == DEFAULT_INSTANCE\n          ? new Builder() : new Builder().mergeFrom(this);\n    }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code com.alibaba.otter.canal.protocol.Packet}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.Packet)\n        com.alibaba.otter.canal.protocol.CanalPacket.PacketOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Packet_descriptor;\n      }\n\n      @java.lang.Override\n      protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Packet_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                com.alibaba.otter.canal.protocol.CanalPacket.Packet.class, com.alibaba.otter.canal.protocol.CanalPacket.Packet.Builder.class);\n      }\n\n      // Construct using com.alibaba.otter.canal.protocol.CanalPacket.Packet.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessageV3\n                .alwaysUseFieldBuilders) {\n        }\n      }\n      @java.lang.Override\n      public Builder clear() {\n        super.clear();\n        type_ = 0;\n\n        body_ = com.google.protobuf.ByteString.EMPTY;\n\n        magicNumberPresentCase_ = 0;\n        magicNumberPresent_ = null;\n        versionPresentCase_ = 0;\n        versionPresent_ = null;\n        compressionPresentCase_ = 0;\n        compressionPresent_ = null;\n        return this;\n      }\n\n      @java.lang.Override\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Packet_descriptor;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.Packet getDefaultInstanceForType() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.Packet.getDefaultInstance();\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.Packet build() {\n        com.alibaba.otter.canal.protocol.CanalPacket.Packet result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.Packet buildPartial() {\n        com.alibaba.otter.canal.protocol.CanalPacket.Packet result = new com.alibaba.otter.canal.protocol.CanalPacket.Packet(this);\n        if (magicNumberPresentCase_ == 1) {\n          result.magicNumberPresent_ = magicNumberPresent_;\n        }\n        if (versionPresentCase_ == 2) {\n          result.versionPresent_ = versionPresent_;\n        }\n        result.type_ = type_;\n        if (compressionPresentCase_ == 4) {\n          result.compressionPresent_ = compressionPresent_;\n        }\n        result.body_ = body_;\n        result.magicNumberPresentCase_ = magicNumberPresentCase_;\n        result.versionPresentCase_ = versionPresentCase_;\n        result.compressionPresentCase_ = compressionPresentCase_;\n        onBuilt();\n        return result;\n      }\n\n      @java.lang.Override\n      public Builder clone() {\n        return (Builder) super.clone();\n      }\n      @java.lang.Override\n      public Builder setField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.setField(field, value);\n      }\n      @java.lang.Override\n      public Builder clearField(\n          com.google.protobuf.Descriptors.FieldDescriptor field) {\n        return (Builder) super.clearField(field);\n      }\n      @java.lang.Override\n      public Builder clearOneof(\n          com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n        return (Builder) super.clearOneof(oneof);\n      }\n      @java.lang.Override\n      public Builder setRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          int index, java.lang.Object value) {\n        return (Builder) super.setRepeatedField(field, index, value);\n      }\n      @java.lang.Override\n      public Builder addRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.addRepeatedField(field, value);\n      }\n      @java.lang.Override\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof com.alibaba.otter.canal.protocol.CanalPacket.Packet) {\n          return mergeFrom((com.alibaba.otter.canal.protocol.CanalPacket.Packet)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(com.alibaba.otter.canal.protocol.CanalPacket.Packet other) {\n        if (other == com.alibaba.otter.canal.protocol.CanalPacket.Packet.getDefaultInstance()) return this;\n        if (other.type_ != 0) {\n          setTypeValue(other.getTypeValue());\n        }\n        if (other.getBody() != com.google.protobuf.ByteString.EMPTY) {\n          setBody(other.getBody());\n        }\n        switch (other.getMagicNumberPresentCase()) {\n          case MAGIC_NUMBER: {\n            setMagicNumber(other.getMagicNumber());\n            break;\n          }\n          case MAGICNUMBERPRESENT_NOT_SET: {\n            break;\n          }\n        }\n        switch (other.getVersionPresentCase()) {\n          case VERSION: {\n            setVersion(other.getVersion());\n            break;\n          }\n          case VERSIONPRESENT_NOT_SET: {\n            break;\n          }\n        }\n        switch (other.getCompressionPresentCase()) {\n          case COMPRESSION: {\n            setCompressionValue(other.getCompressionValue());\n            break;\n          }\n          case COMPRESSIONPRESENT_NOT_SET: {\n            break;\n          }\n        }\n        this.mergeUnknownFields(other.unknownFields);\n        onChanged();\n        return this;\n      }\n\n      @java.lang.Override\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      @java.lang.Override\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        com.alibaba.otter.canal.protocol.CanalPacket.Packet parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (com.alibaba.otter.canal.protocol.CanalPacket.Packet) e.getUnfinishedMessage();\n          throw e.unwrapIOException();\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int magicNumberPresentCase_ = 0;\n      private java.lang.Object magicNumberPresent_;\n      public MagicNumberPresentCase\n          getMagicNumberPresentCase() {\n        return MagicNumberPresentCase.forNumber(\n            magicNumberPresentCase_);\n      }\n\n      public Builder clearMagicNumberPresent() {\n        magicNumberPresentCase_ = 0;\n        magicNumberPresent_ = null;\n        onChanged();\n        return this;\n      }\n\n      private int versionPresentCase_ = 0;\n      private java.lang.Object versionPresent_;\n      public VersionPresentCase\n          getVersionPresentCase() {\n        return VersionPresentCase.forNumber(\n            versionPresentCase_);\n      }\n\n      public Builder clearVersionPresent() {\n        versionPresentCase_ = 0;\n        versionPresent_ = null;\n        onChanged();\n        return this;\n      }\n\n      private int compressionPresentCase_ = 0;\n      private java.lang.Object compressionPresent_;\n      public CompressionPresentCase\n          getCompressionPresentCase() {\n        return CompressionPresentCase.forNumber(\n            compressionPresentCase_);\n      }\n\n      public Builder clearCompressionPresent() {\n        compressionPresentCase_ = 0;\n        compressionPresent_ = null;\n        onChanged();\n        return this;\n      }\n\n\n      /**\n       * <code>int32 magic_number = 1;</code>\n       */\n      public int getMagicNumber() {\n        if (magicNumberPresentCase_ == 1) {\n          return (java.lang.Integer) magicNumberPresent_;\n        }\n        return 0;\n      }\n      /**\n       * <code>int32 magic_number = 1;</code>\n       */\n      public Builder setMagicNumber(int value) {\n        magicNumberPresentCase_ = 1;\n        magicNumberPresent_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>int32 magic_number = 1;</code>\n       */\n      public Builder clearMagicNumber() {\n        if (magicNumberPresentCase_ == 1) {\n          magicNumberPresentCase_ = 0;\n          magicNumberPresent_ = null;\n          onChanged();\n        }\n        return this;\n      }\n\n      /**\n       * <code>int32 version = 2;</code>\n       */\n      public int getVersion() {\n        if (versionPresentCase_ == 2) {\n          return (java.lang.Integer) versionPresent_;\n        }\n        return 0;\n      }\n      /**\n       * <code>int32 version = 2;</code>\n       */\n      public Builder setVersion(int value) {\n        versionPresentCase_ = 2;\n        versionPresent_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>int32 version = 2;</code>\n       */\n      public Builder clearVersion() {\n        if (versionPresentCase_ == 2) {\n          versionPresentCase_ = 0;\n          versionPresent_ = null;\n          onChanged();\n        }\n        return this;\n      }\n\n      private int type_ = 0;\n      /**\n       * <code>.com.alibaba.otter.canal.protocol.PacketType type = 3;</code>\n       */\n      public int getTypeValue() {\n        return type_;\n      }\n      /**\n       * <code>.com.alibaba.otter.canal.protocol.PacketType type = 3;</code>\n       */\n      public Builder setTypeValue(int value) {\n        type_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>.com.alibaba.otter.canal.protocol.PacketType type = 3;</code>\n       */\n      public com.alibaba.otter.canal.protocol.CanalPacket.PacketType getType() {\n        @SuppressWarnings(\"deprecation\")\n        com.alibaba.otter.canal.protocol.CanalPacket.PacketType result = com.alibaba.otter.canal.protocol.CanalPacket.PacketType.valueOf(type_);\n        return result == null ? com.alibaba.otter.canal.protocol.CanalPacket.PacketType.UNRECOGNIZED : result;\n      }\n      /**\n       * <code>.com.alibaba.otter.canal.protocol.PacketType type = 3;</code>\n       */\n      public Builder setType(com.alibaba.otter.canal.protocol.CanalPacket.PacketType value) {\n        if (value == null) {\n          throw new NullPointerException();\n        }\n        \n        type_ = value.getNumber();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>.com.alibaba.otter.canal.protocol.PacketType type = 3;</code>\n       */\n      public Builder clearType() {\n        \n        type_ = 0;\n        onChanged();\n        return this;\n      }\n\n      /**\n       * <code>.com.alibaba.otter.canal.protocol.Compression compression = 4;</code>\n       */\n      public int getCompressionValue() {\n        if (compressionPresentCase_ == 4) {\n          return ((java.lang.Integer) compressionPresent_).intValue();\n        }\n        return 0;\n      }\n      /**\n       * <code>.com.alibaba.otter.canal.protocol.Compression compression = 4;</code>\n       */\n      public Builder setCompressionValue(int value) {\n        compressionPresentCase_ = 4;\n        compressionPresent_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>.com.alibaba.otter.canal.protocol.Compression compression = 4;</code>\n       */\n      public com.alibaba.otter.canal.protocol.CanalPacket.Compression getCompression() {\n        if (compressionPresentCase_ == 4) {\n          @SuppressWarnings(\"deprecation\")\n          com.alibaba.otter.canal.protocol.CanalPacket.Compression result = com.alibaba.otter.canal.protocol.CanalPacket.Compression.valueOf(\n              (java.lang.Integer) compressionPresent_);\n          return result == null ? com.alibaba.otter.canal.protocol.CanalPacket.Compression.UNRECOGNIZED : result;\n        }\n        return com.alibaba.otter.canal.protocol.CanalPacket.Compression.COMPRESSIONCOMPATIBLEPROTO2;\n      }\n      /**\n       * <code>.com.alibaba.otter.canal.protocol.Compression compression = 4;</code>\n       */\n      public Builder setCompression(com.alibaba.otter.canal.protocol.CanalPacket.Compression value) {\n        if (value == null) {\n          throw new NullPointerException();\n        }\n        compressionPresentCase_ = 4;\n        compressionPresent_ = value.getNumber();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>.com.alibaba.otter.canal.protocol.Compression compression = 4;</code>\n       */\n      public Builder clearCompression() {\n        if (compressionPresentCase_ == 4) {\n          compressionPresentCase_ = 0;\n          compressionPresent_ = null;\n          onChanged();\n        }\n        return this;\n      }\n\n      private com.google.protobuf.ByteString body_ = com.google.protobuf.ByteString.EMPTY;\n      /**\n       * <code>bytes body = 5;</code>\n       */\n      public com.google.protobuf.ByteString getBody() {\n        return body_;\n      }\n      /**\n       * <code>bytes body = 5;</code>\n       */\n      public Builder setBody(com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        body_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>bytes body = 5;</code>\n       */\n      public Builder clearBody() {\n        \n        body_ = getDefaultInstance().getBody();\n        onChanged();\n        return this;\n      }\n      @java.lang.Override\n      public final Builder setUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.setUnknownFieldsProto3(unknownFields);\n      }\n\n      @java.lang.Override\n      public final Builder mergeUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.mergeUnknownFields(unknownFields);\n      }\n\n\n      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.Packet)\n    }\n\n    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.Packet)\n    private static final com.alibaba.otter.canal.protocol.CanalPacket.Packet DEFAULT_INSTANCE;\n    static {\n      DEFAULT_INSTANCE = new com.alibaba.otter.canal.protocol.CanalPacket.Packet();\n    }\n\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Packet getDefaultInstance() {\n      return DEFAULT_INSTANCE;\n    }\n\n    private static final com.google.protobuf.Parser<Packet>\n        PARSER = new com.google.protobuf.AbstractParser<Packet>() {\n      @java.lang.Override\n      public Packet parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new Packet(input, extensionRegistry);\n      }\n    };\n\n    public static com.google.protobuf.Parser<Packet> parser() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<Packet> getParserForType() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.alibaba.otter.canal.protocol.CanalPacket.Packet getDefaultInstanceForType() {\n      return DEFAULT_INSTANCE;\n    }\n\n  }\n\n  public interface HeartBeatOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.HeartBeat)\n      com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <code>int64 send_timestamp = 1;</code>\n     */\n    long getSendTimestamp();\n\n    /**\n     * <code>int64 start_timestamp = 2;</code>\n     */\n    long getStartTimestamp();\n  }\n  /**\n   * Protobuf type {@code com.alibaba.otter.canal.protocol.HeartBeat}\n   */\n  public  static final class HeartBeat extends\n      com.google.protobuf.GeneratedMessageV3 implements\n      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.HeartBeat)\n      HeartBeatOrBuilder {\n  private static final long serialVersionUID = 0L;\n    // Use HeartBeat.newBuilder() to construct.\n    private HeartBeat(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {\n      super(builder);\n    }\n    private HeartBeat() {\n      sendTimestamp_ = 0L;\n      startTimestamp_ = 0L;\n    }\n\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n    getUnknownFields() {\n      return this.unknownFields;\n    }\n    private HeartBeat(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      this();\n      if (extensionRegistry == null) {\n        throw new java.lang.NullPointerException();\n      }\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            case 8: {\n\n              sendTimestamp_ = input.readInt64();\n              break;\n            }\n            case 16: {\n\n              startTimestamp_ = input.readInt64();\n              break;\n            }\n            default: {\n              if (!parseUnknownFieldProto3(\n                  input, unknownFields, extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_HeartBeat_descriptor;\n    }\n\n    @java.lang.Override\n    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_HeartBeat_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat.class, com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat.Builder.class);\n    }\n\n    public static final int SEND_TIMESTAMP_FIELD_NUMBER = 1;\n    private long sendTimestamp_;\n    /**\n     * <code>int64 send_timestamp = 1;</code>\n     */\n    public long getSendTimestamp() {\n      return sendTimestamp_;\n    }\n\n    public static final int START_TIMESTAMP_FIELD_NUMBER = 2;\n    private long startTimestamp_;\n    /**\n     * <code>int64 start_timestamp = 2;</code>\n     */\n    public long getStartTimestamp() {\n      return startTimestamp_;\n    }\n\n    private byte memoizedIsInitialized = -1;\n    @java.lang.Override\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    @java.lang.Override\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      if (sendTimestamp_ != 0L) {\n        output.writeInt64(1, sendTimestamp_);\n      }\n      if (startTimestamp_ != 0L) {\n        output.writeInt64(2, startTimestamp_);\n      }\n      unknownFields.writeTo(output);\n    }\n\n    @java.lang.Override\n    public int getSerializedSize() {\n      int size = memoizedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (sendTimestamp_ != 0L) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(1, sendTimestamp_);\n      }\n      if (startTimestamp_ != 0L) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(2, startTimestamp_);\n      }\n      size += unknownFields.getSerializedSize();\n      memoizedSize = size;\n      return size;\n    }\n\n    @java.lang.Override\n    public boolean equals(final java.lang.Object obj) {\n      if (obj == this) {\n       return true;\n      }\n      if (!(obj instanceof com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat)) {\n        return super.equals(obj);\n      }\n      com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat other = (com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat) obj;\n\n      boolean result = true;\n      result = result && (getSendTimestamp()\n          == other.getSendTimestamp());\n      result = result && (getStartTimestamp()\n          == other.getStartTimestamp());\n      result = result && unknownFields.equals(other.unknownFields);\n      return result;\n    }\n\n    @java.lang.Override\n    public int hashCode() {\n      if (memoizedHashCode != 0) {\n        return memoizedHashCode;\n      }\n      int hash = 41;\n      hash = (19 * hash) + getDescriptor().hashCode();\n      hash = (37 * hash) + SEND_TIMESTAMP_FIELD_NUMBER;\n      hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n          getSendTimestamp());\n      hash = (37 * hash) + START_TIMESTAMP_FIELD_NUMBER;\n      hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n          getStartTimestamp());\n      hash = (29 * hash) + unknownFields.hashCode();\n      memoizedHashCode = hash;\n      return hash;\n    }\n\n    public static com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat parseFrom(\n        java.nio.ByteBuffer data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat parseFrom(\n        java.nio.ByteBuffer data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    @java.lang.Override\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder() {\n      return DEFAULT_INSTANCE.toBuilder();\n    }\n    public static Builder newBuilder(com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat prototype) {\n      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n    }\n    @java.lang.Override\n    public Builder toBuilder() {\n      return this == DEFAULT_INSTANCE\n          ? new Builder() : new Builder().mergeFrom(this);\n    }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code com.alibaba.otter.canal.protocol.HeartBeat}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.HeartBeat)\n        com.alibaba.otter.canal.protocol.CanalPacket.HeartBeatOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_HeartBeat_descriptor;\n      }\n\n      @java.lang.Override\n      protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_HeartBeat_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat.class, com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat.Builder.class);\n      }\n\n      // Construct using com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessageV3\n                .alwaysUseFieldBuilders) {\n        }\n      }\n      @java.lang.Override\n      public Builder clear() {\n        super.clear();\n        sendTimestamp_ = 0L;\n\n        startTimestamp_ = 0L;\n\n        return this;\n      }\n\n      @java.lang.Override\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_HeartBeat_descriptor;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat getDefaultInstanceForType() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat.getDefaultInstance();\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat build() {\n        com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat buildPartial() {\n        com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat result = new com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat(this);\n        result.sendTimestamp_ = sendTimestamp_;\n        result.startTimestamp_ = startTimestamp_;\n        onBuilt();\n        return result;\n      }\n\n      @java.lang.Override\n      public Builder clone() {\n        return (Builder) super.clone();\n      }\n      @java.lang.Override\n      public Builder setField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.setField(field, value);\n      }\n      @java.lang.Override\n      public Builder clearField(\n          com.google.protobuf.Descriptors.FieldDescriptor field) {\n        return (Builder) super.clearField(field);\n      }\n      @java.lang.Override\n      public Builder clearOneof(\n          com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n        return (Builder) super.clearOneof(oneof);\n      }\n      @java.lang.Override\n      public Builder setRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          int index, java.lang.Object value) {\n        return (Builder) super.setRepeatedField(field, index, value);\n      }\n      @java.lang.Override\n      public Builder addRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.addRepeatedField(field, value);\n      }\n      @java.lang.Override\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat) {\n          return mergeFrom((com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat other) {\n        if (other == com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat.getDefaultInstance()) return this;\n        if (other.getSendTimestamp() != 0L) {\n          setSendTimestamp(other.getSendTimestamp());\n        }\n        if (other.getStartTimestamp() != 0L) {\n          setStartTimestamp(other.getStartTimestamp());\n        }\n        this.mergeUnknownFields(other.unknownFields);\n        onChanged();\n        return this;\n      }\n\n      @java.lang.Override\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      @java.lang.Override\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat) e.getUnfinishedMessage();\n          throw e.unwrapIOException();\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n\n      private long sendTimestamp_ ;\n      /**\n       * <code>int64 send_timestamp = 1;</code>\n       */\n      public long getSendTimestamp() {\n        return sendTimestamp_;\n      }\n      /**\n       * <code>int64 send_timestamp = 1;</code>\n       */\n      public Builder setSendTimestamp(long value) {\n        \n        sendTimestamp_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>int64 send_timestamp = 1;</code>\n       */\n      public Builder clearSendTimestamp() {\n        \n        sendTimestamp_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      private long startTimestamp_ ;\n      /**\n       * <code>int64 start_timestamp = 2;</code>\n       */\n      public long getStartTimestamp() {\n        return startTimestamp_;\n      }\n      /**\n       * <code>int64 start_timestamp = 2;</code>\n       */\n      public Builder setStartTimestamp(long value) {\n        \n        startTimestamp_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>int64 start_timestamp = 2;</code>\n       */\n      public Builder clearStartTimestamp() {\n        \n        startTimestamp_ = 0L;\n        onChanged();\n        return this;\n      }\n      @java.lang.Override\n      public final Builder setUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.setUnknownFieldsProto3(unknownFields);\n      }\n\n      @java.lang.Override\n      public final Builder mergeUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.mergeUnknownFields(unknownFields);\n      }\n\n\n      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.HeartBeat)\n    }\n\n    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.HeartBeat)\n    private static final com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat DEFAULT_INSTANCE;\n    static {\n      DEFAULT_INSTANCE = new com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat();\n    }\n\n    public static com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat getDefaultInstance() {\n      return DEFAULT_INSTANCE;\n    }\n\n    private static final com.google.protobuf.Parser<HeartBeat>\n        PARSER = new com.google.protobuf.AbstractParser<HeartBeat>() {\n      @java.lang.Override\n      public HeartBeat parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new HeartBeat(input, extensionRegistry);\n      }\n    };\n\n    public static com.google.protobuf.Parser<HeartBeat> parser() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<HeartBeat> getParserForType() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.alibaba.otter.canal.protocol.CanalPacket.HeartBeat getDefaultInstanceForType() {\n      return DEFAULT_INSTANCE;\n    }\n\n  }\n\n  public interface HandshakeOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.Handshake)\n      com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <code>string communication_encoding = 1;</code>\n     */\n    java.lang.String getCommunicationEncoding();\n    /**\n     * <code>string communication_encoding = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getCommunicationEncodingBytes();\n\n    /**\n     * <code>bytes seeds = 2;</code>\n     */\n    com.google.protobuf.ByteString getSeeds();\n\n    /**\n     * <code>.com.alibaba.otter.canal.protocol.Compression supported_compressions = 3;</code>\n     */\n    int getSupportedCompressionsValue();\n    /**\n     * <code>.com.alibaba.otter.canal.protocol.Compression supported_compressions = 3;</code>\n     */\n    com.alibaba.otter.canal.protocol.CanalPacket.Compression getSupportedCompressions();\n\n    public com.alibaba.otter.canal.protocol.CanalPacket.Handshake.CommunicationEncodingPresentCase getCommunicationEncodingPresentCase();\n  }\n  /**\n   * Protobuf type {@code com.alibaba.otter.canal.protocol.Handshake}\n   */\n  public  static final class Handshake extends\n      com.google.protobuf.GeneratedMessageV3 implements\n      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.Handshake)\n      HandshakeOrBuilder {\n  private static final long serialVersionUID = 0L;\n    // Use Handshake.newBuilder() to construct.\n    private Handshake(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {\n      super(builder);\n    }\n    private Handshake() {\n      seeds_ = com.google.protobuf.ByteString.EMPTY;\n      supportedCompressions_ = 0;\n    }\n\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n    getUnknownFields() {\n      return this.unknownFields;\n    }\n    private Handshake(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      this();\n      if (extensionRegistry == null) {\n        throw new java.lang.NullPointerException();\n      }\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            case 10: {\n              java.lang.String s = input.readStringRequireUtf8();\n              communicationEncodingPresentCase_ = 1;\n              communicationEncodingPresent_ = s;\n              break;\n            }\n            case 18: {\n\n              seeds_ = input.readBytes();\n              break;\n            }\n            case 24: {\n              int rawValue = input.readEnum();\n\n              supportedCompressions_ = rawValue;\n              break;\n            }\n            default: {\n              if (!parseUnknownFieldProto3(\n                  input, unknownFields, extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Handshake_descriptor;\n    }\n\n    @java.lang.Override\n    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Handshake_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              com.alibaba.otter.canal.protocol.CanalPacket.Handshake.class, com.alibaba.otter.canal.protocol.CanalPacket.Handshake.Builder.class);\n    }\n\n    private int communicationEncodingPresentCase_ = 0;\n    private java.lang.Object communicationEncodingPresent_;\n    public enum CommunicationEncodingPresentCase\n        implements com.google.protobuf.Internal.EnumLite {\n      COMMUNICATION_ENCODING(1),\n      COMMUNICATIONENCODINGPRESENT_NOT_SET(0);\n      private final int value;\n      private CommunicationEncodingPresentCase(int value) {\n        this.value = value;\n      }\n      /**\n       * @deprecated Use {@link #forNumber(int)} instead.\n       */\n      @java.lang.Deprecated\n      public static CommunicationEncodingPresentCase valueOf(int value) {\n        return forNumber(value);\n      }\n\n      public static CommunicationEncodingPresentCase forNumber(int value) {\n        switch (value) {\n          case 1: return COMMUNICATION_ENCODING;\n          case 0: return COMMUNICATIONENCODINGPRESENT_NOT_SET;\n          default: return null;\n        }\n      }\n      public int getNumber() {\n        return this.value;\n      }\n    };\n\n    public CommunicationEncodingPresentCase\n    getCommunicationEncodingPresentCase() {\n      return CommunicationEncodingPresentCase.forNumber(\n          communicationEncodingPresentCase_);\n    }\n\n    public static final int COMMUNICATION_ENCODING_FIELD_NUMBER = 1;\n    /**\n     * <code>string communication_encoding = 1;</code>\n     */\n    public java.lang.String getCommunicationEncoding() {\n      java.lang.Object ref = \"\";\n      if (communicationEncodingPresentCase_ == 1) {\n        ref = communicationEncodingPresent_;\n      }\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (communicationEncodingPresentCase_ == 1) {\n          communicationEncodingPresent_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>string communication_encoding = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getCommunicationEncodingBytes() {\n      java.lang.Object ref = \"\";\n      if (communicationEncodingPresentCase_ == 1) {\n        ref = communicationEncodingPresent_;\n      }\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        if (communicationEncodingPresentCase_ == 1) {\n          communicationEncodingPresent_ = b;\n        }\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int SEEDS_FIELD_NUMBER = 2;\n    private com.google.protobuf.ByteString seeds_;\n    /**\n     * <code>bytes seeds = 2;</code>\n     */\n    public com.google.protobuf.ByteString getSeeds() {\n      return seeds_;\n    }\n\n    public static final int SUPPORTED_COMPRESSIONS_FIELD_NUMBER = 3;\n    private int supportedCompressions_;\n    /**\n     * <code>.com.alibaba.otter.canal.protocol.Compression supported_compressions = 3;</code>\n     */\n    public int getSupportedCompressionsValue() {\n      return supportedCompressions_;\n    }\n    /**\n     * <code>.com.alibaba.otter.canal.protocol.Compression supported_compressions = 3;</code>\n     */\n    public com.alibaba.otter.canal.protocol.CanalPacket.Compression getSupportedCompressions() {\n      @SuppressWarnings(\"deprecation\")\n      com.alibaba.otter.canal.protocol.CanalPacket.Compression result = com.alibaba.otter.canal.protocol.CanalPacket.Compression.valueOf(supportedCompressions_);\n      return result == null ? com.alibaba.otter.canal.protocol.CanalPacket.Compression.UNRECOGNIZED : result;\n    }\n\n    private byte memoizedIsInitialized = -1;\n    @java.lang.Override\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    @java.lang.Override\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      if (communicationEncodingPresentCase_ == 1) {\n        com.google.protobuf.GeneratedMessageV3.writeString(output, 1, communicationEncodingPresent_);\n      }\n      if (!seeds_.isEmpty()) {\n        output.writeBytes(2, seeds_);\n      }\n      if (supportedCompressions_ != com.alibaba.otter.canal.protocol.CanalPacket.Compression.COMPRESSIONCOMPATIBLEPROTO2.getNumber()) {\n        output.writeEnum(3, supportedCompressions_);\n      }\n      unknownFields.writeTo(output);\n    }\n\n    @java.lang.Override\n    public int getSerializedSize() {\n      int size = memoizedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (communicationEncodingPresentCase_ == 1) {\n        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, communicationEncodingPresent_);\n      }\n      if (!seeds_.isEmpty()) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, seeds_);\n      }\n      if (supportedCompressions_ != com.alibaba.otter.canal.protocol.CanalPacket.Compression.COMPRESSIONCOMPATIBLEPROTO2.getNumber()) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeEnumSize(3, supportedCompressions_);\n      }\n      size += unknownFields.getSerializedSize();\n      memoizedSize = size;\n      return size;\n    }\n\n    @java.lang.Override\n    public boolean equals(final java.lang.Object obj) {\n      if (obj == this) {\n       return true;\n      }\n      if (!(obj instanceof com.alibaba.otter.canal.protocol.CanalPacket.Handshake)) {\n        return super.equals(obj);\n      }\n      com.alibaba.otter.canal.protocol.CanalPacket.Handshake other = (com.alibaba.otter.canal.protocol.CanalPacket.Handshake) obj;\n\n      boolean result = true;\n      result = result && getSeeds()\n          .equals(other.getSeeds());\n      result = result && supportedCompressions_ == other.supportedCompressions_;\n      result = result && getCommunicationEncodingPresentCase().equals(\n          other.getCommunicationEncodingPresentCase());\n      if (!result) return false;\n      switch (communicationEncodingPresentCase_) {\n        case 1:\n          result = result && getCommunicationEncoding()\n              .equals(other.getCommunicationEncoding());\n          break;\n        case 0:\n        default:\n      }\n      result = result && unknownFields.equals(other.unknownFields);\n      return result;\n    }\n\n    @java.lang.Override\n    public int hashCode() {\n      if (memoizedHashCode != 0) {\n        return memoizedHashCode;\n      }\n      int hash = 41;\n      hash = (19 * hash) + getDescriptor().hashCode();\n      hash = (37 * hash) + SEEDS_FIELD_NUMBER;\n      hash = (53 * hash) + getSeeds().hashCode();\n      hash = (37 * hash) + SUPPORTED_COMPRESSIONS_FIELD_NUMBER;\n      hash = (53 * hash) + supportedCompressions_;\n      switch (communicationEncodingPresentCase_) {\n        case 1:\n          hash = (37 * hash) + COMMUNICATION_ENCODING_FIELD_NUMBER;\n          hash = (53 * hash) + getCommunicationEncoding().hashCode();\n          break;\n        case 0:\n        default:\n      }\n      hash = (29 * hash) + unknownFields.hashCode();\n      memoizedHashCode = hash;\n      return hash;\n    }\n\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Handshake parseFrom(\n        java.nio.ByteBuffer data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Handshake parseFrom(\n        java.nio.ByteBuffer data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Handshake parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Handshake parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Handshake parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Handshake parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Handshake parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Handshake parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Handshake parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Handshake parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Handshake parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Handshake parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    @java.lang.Override\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder() {\n      return DEFAULT_INSTANCE.toBuilder();\n    }\n    public static Builder newBuilder(com.alibaba.otter.canal.protocol.CanalPacket.Handshake prototype) {\n      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n    }\n    @java.lang.Override\n    public Builder toBuilder() {\n      return this == DEFAULT_INSTANCE\n          ? new Builder() : new Builder().mergeFrom(this);\n    }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code com.alibaba.otter.canal.protocol.Handshake}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.Handshake)\n        com.alibaba.otter.canal.protocol.CanalPacket.HandshakeOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Handshake_descriptor;\n      }\n\n      @java.lang.Override\n      protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Handshake_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                com.alibaba.otter.canal.protocol.CanalPacket.Handshake.class, com.alibaba.otter.canal.protocol.CanalPacket.Handshake.Builder.class);\n      }\n\n      // Construct using com.alibaba.otter.canal.protocol.CanalPacket.Handshake.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessageV3\n                .alwaysUseFieldBuilders) {\n        }\n      }\n      @java.lang.Override\n      public Builder clear() {\n        super.clear();\n        seeds_ = com.google.protobuf.ByteString.EMPTY;\n\n        supportedCompressions_ = 0;\n\n        communicationEncodingPresentCase_ = 0;\n        communicationEncodingPresent_ = null;\n        return this;\n      }\n\n      @java.lang.Override\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Handshake_descriptor;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.Handshake getDefaultInstanceForType() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.Handshake.getDefaultInstance();\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.Handshake build() {\n        com.alibaba.otter.canal.protocol.CanalPacket.Handshake result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.Handshake buildPartial() {\n        com.alibaba.otter.canal.protocol.CanalPacket.Handshake result = new com.alibaba.otter.canal.protocol.CanalPacket.Handshake(this);\n        if (communicationEncodingPresentCase_ == 1) {\n          result.communicationEncodingPresent_ = communicationEncodingPresent_;\n        }\n        result.seeds_ = seeds_;\n        result.supportedCompressions_ = supportedCompressions_;\n        result.communicationEncodingPresentCase_ = communicationEncodingPresentCase_;\n        onBuilt();\n        return result;\n      }\n\n      @java.lang.Override\n      public Builder clone() {\n        return (Builder) super.clone();\n      }\n      @java.lang.Override\n      public Builder setField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.setField(field, value);\n      }\n      @java.lang.Override\n      public Builder clearField(\n          com.google.protobuf.Descriptors.FieldDescriptor field) {\n        return (Builder) super.clearField(field);\n      }\n      @java.lang.Override\n      public Builder clearOneof(\n          com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n        return (Builder) super.clearOneof(oneof);\n      }\n      @java.lang.Override\n      public Builder setRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          int index, java.lang.Object value) {\n        return (Builder) super.setRepeatedField(field, index, value);\n      }\n      @java.lang.Override\n      public Builder addRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.addRepeatedField(field, value);\n      }\n      @java.lang.Override\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof com.alibaba.otter.canal.protocol.CanalPacket.Handshake) {\n          return mergeFrom((com.alibaba.otter.canal.protocol.CanalPacket.Handshake)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(com.alibaba.otter.canal.protocol.CanalPacket.Handshake other) {\n        if (other == com.alibaba.otter.canal.protocol.CanalPacket.Handshake.getDefaultInstance()) return this;\n        if (other.getSeeds() != com.google.protobuf.ByteString.EMPTY) {\n          setSeeds(other.getSeeds());\n        }\n        if (other.supportedCompressions_ != 0) {\n          setSupportedCompressionsValue(other.getSupportedCompressionsValue());\n        }\n        switch (other.getCommunicationEncodingPresentCase()) {\n          case COMMUNICATION_ENCODING: {\n            communicationEncodingPresentCase_ = 1;\n            communicationEncodingPresent_ = other.communicationEncodingPresent_;\n            onChanged();\n            break;\n          }\n          case COMMUNICATIONENCODINGPRESENT_NOT_SET: {\n            break;\n          }\n        }\n        this.mergeUnknownFields(other.unknownFields);\n        onChanged();\n        return this;\n      }\n\n      @java.lang.Override\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      @java.lang.Override\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        com.alibaba.otter.canal.protocol.CanalPacket.Handshake parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (com.alibaba.otter.canal.protocol.CanalPacket.Handshake) e.getUnfinishedMessage();\n          throw e.unwrapIOException();\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int communicationEncodingPresentCase_ = 0;\n      private java.lang.Object communicationEncodingPresent_;\n      public CommunicationEncodingPresentCase\n          getCommunicationEncodingPresentCase() {\n        return CommunicationEncodingPresentCase.forNumber(\n            communicationEncodingPresentCase_);\n      }\n\n      public Builder clearCommunicationEncodingPresent() {\n        communicationEncodingPresentCase_ = 0;\n        communicationEncodingPresent_ = null;\n        onChanged();\n        return this;\n      }\n\n\n      /**\n       * <code>string communication_encoding = 1;</code>\n       */\n      public java.lang.String getCommunicationEncoding() {\n        java.lang.Object ref = \"\";\n        if (communicationEncodingPresentCase_ == 1) {\n          ref = communicationEncodingPresent_;\n        }\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          if (communicationEncodingPresentCase_ == 1) {\n            communicationEncodingPresent_ = s;\n          }\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>string communication_encoding = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getCommunicationEncodingBytes() {\n        java.lang.Object ref = \"\";\n        if (communicationEncodingPresentCase_ == 1) {\n          ref = communicationEncodingPresent_;\n        }\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          if (communicationEncodingPresentCase_ == 1) {\n            communicationEncodingPresent_ = b;\n          }\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>string communication_encoding = 1;</code>\n       */\n      public Builder setCommunicationEncoding(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  communicationEncodingPresentCase_ = 1;\n        communicationEncodingPresent_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string communication_encoding = 1;</code>\n       */\n      public Builder clearCommunicationEncoding() {\n        if (communicationEncodingPresentCase_ == 1) {\n          communicationEncodingPresentCase_ = 0;\n          communicationEncodingPresent_ = null;\n          onChanged();\n        }\n        return this;\n      }\n      /**\n       * <code>string communication_encoding = 1;</code>\n       */\n      public Builder setCommunicationEncodingBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  checkByteStringIsUtf8(value);\n        communicationEncodingPresentCase_ = 1;\n        communicationEncodingPresent_ = value;\n        onChanged();\n        return this;\n      }\n\n      private com.google.protobuf.ByteString seeds_ = com.google.protobuf.ByteString.EMPTY;\n      /**\n       * <code>bytes seeds = 2;</code>\n       */\n      public com.google.protobuf.ByteString getSeeds() {\n        return seeds_;\n      }\n      /**\n       * <code>bytes seeds = 2;</code>\n       */\n      public Builder setSeeds(com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        seeds_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>bytes seeds = 2;</code>\n       */\n      public Builder clearSeeds() {\n        \n        seeds_ = getDefaultInstance().getSeeds();\n        onChanged();\n        return this;\n      }\n\n      private int supportedCompressions_ = 0;\n      /**\n       * <code>.com.alibaba.otter.canal.protocol.Compression supported_compressions = 3;</code>\n       */\n      public int getSupportedCompressionsValue() {\n        return supportedCompressions_;\n      }\n      /**\n       * <code>.com.alibaba.otter.canal.protocol.Compression supported_compressions = 3;</code>\n       */\n      public Builder setSupportedCompressionsValue(int value) {\n        supportedCompressions_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>.com.alibaba.otter.canal.protocol.Compression supported_compressions = 3;</code>\n       */\n      public com.alibaba.otter.canal.protocol.CanalPacket.Compression getSupportedCompressions() {\n        @SuppressWarnings(\"deprecation\")\n        com.alibaba.otter.canal.protocol.CanalPacket.Compression result = com.alibaba.otter.canal.protocol.CanalPacket.Compression.valueOf(supportedCompressions_);\n        return result == null ? com.alibaba.otter.canal.protocol.CanalPacket.Compression.UNRECOGNIZED : result;\n      }\n      /**\n       * <code>.com.alibaba.otter.canal.protocol.Compression supported_compressions = 3;</code>\n       */\n      public Builder setSupportedCompressions(com.alibaba.otter.canal.protocol.CanalPacket.Compression value) {\n        if (value == null) {\n          throw new NullPointerException();\n        }\n        \n        supportedCompressions_ = value.getNumber();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>.com.alibaba.otter.canal.protocol.Compression supported_compressions = 3;</code>\n       */\n      public Builder clearSupportedCompressions() {\n        \n        supportedCompressions_ = 0;\n        onChanged();\n        return this;\n      }\n      @java.lang.Override\n      public final Builder setUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.setUnknownFieldsProto3(unknownFields);\n      }\n\n      @java.lang.Override\n      public final Builder mergeUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.mergeUnknownFields(unknownFields);\n      }\n\n\n      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.Handshake)\n    }\n\n    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.Handshake)\n    private static final com.alibaba.otter.canal.protocol.CanalPacket.Handshake DEFAULT_INSTANCE;\n    static {\n      DEFAULT_INSTANCE = new com.alibaba.otter.canal.protocol.CanalPacket.Handshake();\n    }\n\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Handshake getDefaultInstance() {\n      return DEFAULT_INSTANCE;\n    }\n\n    private static final com.google.protobuf.Parser<Handshake>\n        PARSER = new com.google.protobuf.AbstractParser<Handshake>() {\n      @java.lang.Override\n      public Handshake parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new Handshake(input, extensionRegistry);\n      }\n    };\n\n    public static com.google.protobuf.Parser<Handshake> parser() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<Handshake> getParserForType() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.alibaba.otter.canal.protocol.CanalPacket.Handshake getDefaultInstanceForType() {\n      return DEFAULT_INSTANCE;\n    }\n\n  }\n\n  public interface ClientAuthOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.ClientAuth)\n      com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <code>string username = 1;</code>\n     */\n    java.lang.String getUsername();\n    /**\n     * <code>string username = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getUsernameBytes();\n\n    /**\n     * <pre>\n     * hashed password with seeds from Handshake message\n     * </pre>\n     *\n     * <code>bytes password = 2;</code>\n     */\n    com.google.protobuf.ByteString getPassword();\n\n    /**\n     * <pre>\n     * in seconds\n     * </pre>\n     *\n     * <code>int32 net_read_timeout = 3;</code>\n     */\n    int getNetReadTimeout();\n\n    /**\n     * <pre>\n     * in seconds\n     * </pre>\n     *\n     * <code>int32 net_write_timeout = 4;</code>\n     */\n    int getNetWriteTimeout();\n\n    /**\n     * <code>string destination = 5;</code>\n     */\n    java.lang.String getDestination();\n    /**\n     * <code>string destination = 5;</code>\n     */\n    com.google.protobuf.ByteString\n        getDestinationBytes();\n\n    /**\n     * <code>string client_id = 6;</code>\n     */\n    java.lang.String getClientId();\n    /**\n     * <code>string client_id = 6;</code>\n     */\n    com.google.protobuf.ByteString\n        getClientIdBytes();\n\n    /**\n     * <code>string filter = 7;</code>\n     */\n    java.lang.String getFilter();\n    /**\n     * <code>string filter = 7;</code>\n     */\n    com.google.protobuf.ByteString\n        getFilterBytes();\n\n    /**\n     * <code>int64 start_timestamp = 8;</code>\n     */\n    long getStartTimestamp();\n\n    public com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth.NetReadTimeoutPresentCase getNetReadTimeoutPresentCase();\n\n    public com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth.NetWriteTimeoutPresentCase getNetWriteTimeoutPresentCase();\n  }\n  /**\n   * <pre>\n   * client authentication\n   * </pre>\n   *\n   * Protobuf type {@code com.alibaba.otter.canal.protocol.ClientAuth}\n   */\n  public  static final class ClientAuth extends\n      com.google.protobuf.GeneratedMessageV3 implements\n      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.ClientAuth)\n      ClientAuthOrBuilder {\n  private static final long serialVersionUID = 0L;\n    // Use ClientAuth.newBuilder() to construct.\n    private ClientAuth(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {\n      super(builder);\n    }\n    private ClientAuth() {\n      username_ = \"\";\n      password_ = com.google.protobuf.ByteString.EMPTY;\n      destination_ = \"\";\n      clientId_ = \"\";\n      filter_ = \"\";\n      startTimestamp_ = 0L;\n    }\n\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n    getUnknownFields() {\n      return this.unknownFields;\n    }\n    private ClientAuth(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      this();\n      if (extensionRegistry == null) {\n        throw new java.lang.NullPointerException();\n      }\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            case 10: {\n              java.lang.String s = input.readStringRequireUtf8();\n\n              username_ = s;\n              break;\n            }\n            case 18: {\n\n              password_ = input.readBytes();\n              break;\n            }\n            case 24: {\n              netReadTimeoutPresentCase_ = 3;\n              netReadTimeoutPresent_ = input.readInt32();\n              break;\n            }\n            case 32: {\n              netWriteTimeoutPresentCase_ = 4;\n              netWriteTimeoutPresent_ = input.readInt32();\n              break;\n            }\n            case 42: {\n              java.lang.String s = input.readStringRequireUtf8();\n\n              destination_ = s;\n              break;\n            }\n            case 50: {\n              java.lang.String s = input.readStringRequireUtf8();\n\n              clientId_ = s;\n              break;\n            }\n            case 58: {\n              java.lang.String s = input.readStringRequireUtf8();\n\n              filter_ = s;\n              break;\n            }\n            case 64: {\n\n              startTimestamp_ = input.readInt64();\n              break;\n            }\n            default: {\n              if (!parseUnknownFieldProto3(\n                  input, unknownFields, extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_ClientAuth_descriptor;\n    }\n\n    @java.lang.Override\n    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_ClientAuth_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth.class, com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth.Builder.class);\n    }\n\n    private int netReadTimeoutPresentCase_ = 0;\n    private java.lang.Object netReadTimeoutPresent_;\n    public enum NetReadTimeoutPresentCase\n        implements com.google.protobuf.Internal.EnumLite {\n      NET_READ_TIMEOUT(3),\n      NETREADTIMEOUTPRESENT_NOT_SET(0);\n      private final int value;\n      private NetReadTimeoutPresentCase(int value) {\n        this.value = value;\n      }\n      /**\n       * @deprecated Use {@link #forNumber(int)} instead.\n       */\n      @java.lang.Deprecated\n      public static NetReadTimeoutPresentCase valueOf(int value) {\n        return forNumber(value);\n      }\n\n      public static NetReadTimeoutPresentCase forNumber(int value) {\n        switch (value) {\n          case 3: return NET_READ_TIMEOUT;\n          case 0: return NETREADTIMEOUTPRESENT_NOT_SET;\n          default: return null;\n        }\n      }\n      public int getNumber() {\n        return this.value;\n      }\n    };\n\n    public NetReadTimeoutPresentCase\n    getNetReadTimeoutPresentCase() {\n      return NetReadTimeoutPresentCase.forNumber(\n          netReadTimeoutPresentCase_);\n    }\n\n    private int netWriteTimeoutPresentCase_ = 0;\n    private java.lang.Object netWriteTimeoutPresent_;\n    public enum NetWriteTimeoutPresentCase\n        implements com.google.protobuf.Internal.EnumLite {\n      NET_WRITE_TIMEOUT(4),\n      NETWRITETIMEOUTPRESENT_NOT_SET(0);\n      private final int value;\n      private NetWriteTimeoutPresentCase(int value) {\n        this.value = value;\n      }\n      /**\n       * @deprecated Use {@link #forNumber(int)} instead.\n       */\n      @java.lang.Deprecated\n      public static NetWriteTimeoutPresentCase valueOf(int value) {\n        return forNumber(value);\n      }\n\n      public static NetWriteTimeoutPresentCase forNumber(int value) {\n        switch (value) {\n          case 4: return NET_WRITE_TIMEOUT;\n          case 0: return NETWRITETIMEOUTPRESENT_NOT_SET;\n          default: return null;\n        }\n      }\n      public int getNumber() {\n        return this.value;\n      }\n    };\n\n    public NetWriteTimeoutPresentCase\n    getNetWriteTimeoutPresentCase() {\n      return NetWriteTimeoutPresentCase.forNumber(\n          netWriteTimeoutPresentCase_);\n    }\n\n    public static final int USERNAME_FIELD_NUMBER = 1;\n    private volatile java.lang.Object username_;\n    /**\n     * <code>string username = 1;</code>\n     */\n    public java.lang.String getUsername() {\n      java.lang.Object ref = username_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        username_ = s;\n        return s;\n      }\n    }\n    /**\n     * <code>string username = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getUsernameBytes() {\n      java.lang.Object ref = username_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        username_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int PASSWORD_FIELD_NUMBER = 2;\n    private com.google.protobuf.ByteString password_;\n    /**\n     * <pre>\n     * hashed password with seeds from Handshake message\n     * </pre>\n     *\n     * <code>bytes password = 2;</code>\n     */\n    public com.google.protobuf.ByteString getPassword() {\n      return password_;\n    }\n\n    public static final int NET_READ_TIMEOUT_FIELD_NUMBER = 3;\n    /**\n     * <pre>\n     * in seconds\n     * </pre>\n     *\n     * <code>int32 net_read_timeout = 3;</code>\n     */\n    public int getNetReadTimeout() {\n      if (netReadTimeoutPresentCase_ == 3) {\n        return (java.lang.Integer) netReadTimeoutPresent_;\n      }\n      return 0;\n    }\n\n    public static final int NET_WRITE_TIMEOUT_FIELD_NUMBER = 4;\n    /**\n     * <pre>\n     * in seconds\n     * </pre>\n     *\n     * <code>int32 net_write_timeout = 4;</code>\n     */\n    public int getNetWriteTimeout() {\n      if (netWriteTimeoutPresentCase_ == 4) {\n        return (java.lang.Integer) netWriteTimeoutPresent_;\n      }\n      return 0;\n    }\n\n    public static final int DESTINATION_FIELD_NUMBER = 5;\n    private volatile java.lang.Object destination_;\n    /**\n     * <code>string destination = 5;</code>\n     */\n    public java.lang.String getDestination() {\n      java.lang.Object ref = destination_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        destination_ = s;\n        return s;\n      }\n    }\n    /**\n     * <code>string destination = 5;</code>\n     */\n    public com.google.protobuf.ByteString\n        getDestinationBytes() {\n      java.lang.Object ref = destination_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        destination_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int CLIENT_ID_FIELD_NUMBER = 6;\n    private volatile java.lang.Object clientId_;\n    /**\n     * <code>string client_id = 6;</code>\n     */\n    public java.lang.String getClientId() {\n      java.lang.Object ref = clientId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        clientId_ = s;\n        return s;\n      }\n    }\n    /**\n     * <code>string client_id = 6;</code>\n     */\n    public com.google.protobuf.ByteString\n        getClientIdBytes() {\n      java.lang.Object ref = clientId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        clientId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int FILTER_FIELD_NUMBER = 7;\n    private volatile java.lang.Object filter_;\n    /**\n     * <code>string filter = 7;</code>\n     */\n    public java.lang.String getFilter() {\n      java.lang.Object ref = filter_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        filter_ = s;\n        return s;\n      }\n    }\n    /**\n     * <code>string filter = 7;</code>\n     */\n    public com.google.protobuf.ByteString\n        getFilterBytes() {\n      java.lang.Object ref = filter_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        filter_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int START_TIMESTAMP_FIELD_NUMBER = 8;\n    private long startTimestamp_;\n    /**\n     * <code>int64 start_timestamp = 8;</code>\n     */\n    public long getStartTimestamp() {\n      return startTimestamp_;\n    }\n\n    private byte memoizedIsInitialized = -1;\n    @java.lang.Override\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    @java.lang.Override\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      if (!getUsernameBytes().isEmpty()) {\n        com.google.protobuf.GeneratedMessageV3.writeString(output, 1, username_);\n      }\n      if (!password_.isEmpty()) {\n        output.writeBytes(2, password_);\n      }\n      if (netReadTimeoutPresentCase_ == 3) {\n        output.writeInt32(\n            3, (int)((java.lang.Integer) netReadTimeoutPresent_));\n      }\n      if (netWriteTimeoutPresentCase_ == 4) {\n        output.writeInt32(\n            4, (int)((java.lang.Integer) netWriteTimeoutPresent_));\n      }\n      if (!getDestinationBytes().isEmpty()) {\n        com.google.protobuf.GeneratedMessageV3.writeString(output, 5, destination_);\n      }\n      if (!getClientIdBytes().isEmpty()) {\n        com.google.protobuf.GeneratedMessageV3.writeString(output, 6, clientId_);\n      }\n      if (!getFilterBytes().isEmpty()) {\n        com.google.protobuf.GeneratedMessageV3.writeString(output, 7, filter_);\n      }\n      if (startTimestamp_ != 0L) {\n        output.writeInt64(8, startTimestamp_);\n      }\n      unknownFields.writeTo(output);\n    }\n\n    @java.lang.Override\n    public int getSerializedSize() {\n      int size = memoizedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (!getUsernameBytes().isEmpty()) {\n        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, username_);\n      }\n      if (!password_.isEmpty()) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, password_);\n      }\n      if (netReadTimeoutPresentCase_ == 3) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(\n              3, (int)((java.lang.Integer) netReadTimeoutPresent_));\n      }\n      if (netWriteTimeoutPresentCase_ == 4) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(\n              4, (int)((java.lang.Integer) netWriteTimeoutPresent_));\n      }\n      if (!getDestinationBytes().isEmpty()) {\n        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(5, destination_);\n      }\n      if (!getClientIdBytes().isEmpty()) {\n        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(6, clientId_);\n      }\n      if (!getFilterBytes().isEmpty()) {\n        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(7, filter_);\n      }\n      if (startTimestamp_ != 0L) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(8, startTimestamp_);\n      }\n      size += unknownFields.getSerializedSize();\n      memoizedSize = size;\n      return size;\n    }\n\n    @java.lang.Override\n    public boolean equals(final java.lang.Object obj) {\n      if (obj == this) {\n       return true;\n      }\n      if (!(obj instanceof com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth)) {\n        return super.equals(obj);\n      }\n      com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth other = (com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth) obj;\n\n      boolean result = true;\n      result = result && getUsername()\n          .equals(other.getUsername());\n      result = result && getPassword()\n          .equals(other.getPassword());\n      result = result && getDestination()\n          .equals(other.getDestination());\n      result = result && getClientId()\n          .equals(other.getClientId());\n      result = result && getFilter()\n          .equals(other.getFilter());\n      result = result && (getStartTimestamp()\n          == other.getStartTimestamp());\n      result = result && getNetReadTimeoutPresentCase().equals(\n          other.getNetReadTimeoutPresentCase());\n      if (!result) return false;\n      switch (netReadTimeoutPresentCase_) {\n        case 3:\n          result = result && (getNetReadTimeout()\n              == other.getNetReadTimeout());\n          break;\n        case 0:\n        default:\n      }\n      result = result && getNetWriteTimeoutPresentCase().equals(\n          other.getNetWriteTimeoutPresentCase());\n      if (!result) return false;\n      switch (netWriteTimeoutPresentCase_) {\n        case 4:\n          result = result && (getNetWriteTimeout()\n              == other.getNetWriteTimeout());\n          break;\n        case 0:\n        default:\n      }\n      result = result && unknownFields.equals(other.unknownFields);\n      return result;\n    }\n\n    @java.lang.Override\n    public int hashCode() {\n      if (memoizedHashCode != 0) {\n        return memoizedHashCode;\n      }\n      int hash = 41;\n      hash = (19 * hash) + getDescriptor().hashCode();\n      hash = (37 * hash) + USERNAME_FIELD_NUMBER;\n      hash = (53 * hash) + getUsername().hashCode();\n      hash = (37 * hash) + PASSWORD_FIELD_NUMBER;\n      hash = (53 * hash) + getPassword().hashCode();\n      hash = (37 * hash) + DESTINATION_FIELD_NUMBER;\n      hash = (53 * hash) + getDestination().hashCode();\n      hash = (37 * hash) + CLIENT_ID_FIELD_NUMBER;\n      hash = (53 * hash) + getClientId().hashCode();\n      hash = (37 * hash) + FILTER_FIELD_NUMBER;\n      hash = (53 * hash) + getFilter().hashCode();\n      hash = (37 * hash) + START_TIMESTAMP_FIELD_NUMBER;\n      hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n          getStartTimestamp());\n      switch (netReadTimeoutPresentCase_) {\n        case 3:\n          hash = (37 * hash) + NET_READ_TIMEOUT_FIELD_NUMBER;\n          hash = (53 * hash) + getNetReadTimeout();\n          break;\n        case 0:\n        default:\n      }\n      switch (netWriteTimeoutPresentCase_) {\n        case 4:\n          hash = (37 * hash) + NET_WRITE_TIMEOUT_FIELD_NUMBER;\n          hash = (53 * hash) + getNetWriteTimeout();\n          break;\n        case 0:\n        default:\n      }\n      hash = (29 * hash) + unknownFields.hashCode();\n      memoizedHashCode = hash;\n      return hash;\n    }\n\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth parseFrom(\n        java.nio.ByteBuffer data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth parseFrom(\n        java.nio.ByteBuffer data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    @java.lang.Override\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder() {\n      return DEFAULT_INSTANCE.toBuilder();\n    }\n    public static Builder newBuilder(com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth prototype) {\n      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n    }\n    @java.lang.Override\n    public Builder toBuilder() {\n      return this == DEFAULT_INSTANCE\n          ? new Builder() : new Builder().mergeFrom(this);\n    }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * <pre>\n     * client authentication\n     * </pre>\n     *\n     * Protobuf type {@code com.alibaba.otter.canal.protocol.ClientAuth}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.ClientAuth)\n        com.alibaba.otter.canal.protocol.CanalPacket.ClientAuthOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_ClientAuth_descriptor;\n      }\n\n      @java.lang.Override\n      protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_ClientAuth_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth.class, com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth.Builder.class);\n      }\n\n      // Construct using com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessageV3\n                .alwaysUseFieldBuilders) {\n        }\n      }\n      @java.lang.Override\n      public Builder clear() {\n        super.clear();\n        username_ = \"\";\n\n        password_ = com.google.protobuf.ByteString.EMPTY;\n\n        destination_ = \"\";\n\n        clientId_ = \"\";\n\n        filter_ = \"\";\n\n        startTimestamp_ = 0L;\n\n        netReadTimeoutPresentCase_ = 0;\n        netReadTimeoutPresent_ = null;\n        netWriteTimeoutPresentCase_ = 0;\n        netWriteTimeoutPresent_ = null;\n        return this;\n      }\n\n      @java.lang.Override\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_ClientAuth_descriptor;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth getDefaultInstanceForType() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth.getDefaultInstance();\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth build() {\n        com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth buildPartial() {\n        com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth result = new com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth(this);\n        result.username_ = username_;\n        result.password_ = password_;\n        if (netReadTimeoutPresentCase_ == 3) {\n          result.netReadTimeoutPresent_ = netReadTimeoutPresent_;\n        }\n        if (netWriteTimeoutPresentCase_ == 4) {\n          result.netWriteTimeoutPresent_ = netWriteTimeoutPresent_;\n        }\n        result.destination_ = destination_;\n        result.clientId_ = clientId_;\n        result.filter_ = filter_;\n        result.startTimestamp_ = startTimestamp_;\n        result.netReadTimeoutPresentCase_ = netReadTimeoutPresentCase_;\n        result.netWriteTimeoutPresentCase_ = netWriteTimeoutPresentCase_;\n        onBuilt();\n        return result;\n      }\n\n      @java.lang.Override\n      public Builder clone() {\n        return (Builder) super.clone();\n      }\n      @java.lang.Override\n      public Builder setField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.setField(field, value);\n      }\n      @java.lang.Override\n      public Builder clearField(\n          com.google.protobuf.Descriptors.FieldDescriptor field) {\n        return (Builder) super.clearField(field);\n      }\n      @java.lang.Override\n      public Builder clearOneof(\n          com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n        return (Builder) super.clearOneof(oneof);\n      }\n      @java.lang.Override\n      public Builder setRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          int index, java.lang.Object value) {\n        return (Builder) super.setRepeatedField(field, index, value);\n      }\n      @java.lang.Override\n      public Builder addRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.addRepeatedField(field, value);\n      }\n      @java.lang.Override\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth) {\n          return mergeFrom((com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth other) {\n        if (other == com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth.getDefaultInstance()) return this;\n        if (!other.getUsername().isEmpty()) {\n          username_ = other.username_;\n          onChanged();\n        }\n        if (other.getPassword() != com.google.protobuf.ByteString.EMPTY) {\n          setPassword(other.getPassword());\n        }\n        if (!other.getDestination().isEmpty()) {\n          destination_ = other.destination_;\n          onChanged();\n        }\n        if (!other.getClientId().isEmpty()) {\n          clientId_ = other.clientId_;\n          onChanged();\n        }\n        if (!other.getFilter().isEmpty()) {\n          filter_ = other.filter_;\n          onChanged();\n        }\n        if (other.getStartTimestamp() != 0L) {\n          setStartTimestamp(other.getStartTimestamp());\n        }\n        switch (other.getNetReadTimeoutPresentCase()) {\n          case NET_READ_TIMEOUT: {\n            setNetReadTimeout(other.getNetReadTimeout());\n            break;\n          }\n          case NETREADTIMEOUTPRESENT_NOT_SET: {\n            break;\n          }\n        }\n        switch (other.getNetWriteTimeoutPresentCase()) {\n          case NET_WRITE_TIMEOUT: {\n            setNetWriteTimeout(other.getNetWriteTimeout());\n            break;\n          }\n          case NETWRITETIMEOUTPRESENT_NOT_SET: {\n            break;\n          }\n        }\n        this.mergeUnknownFields(other.unknownFields);\n        onChanged();\n        return this;\n      }\n\n      @java.lang.Override\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      @java.lang.Override\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth) e.getUnfinishedMessage();\n          throw e.unwrapIOException();\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int netReadTimeoutPresentCase_ = 0;\n      private java.lang.Object netReadTimeoutPresent_;\n      public NetReadTimeoutPresentCase\n          getNetReadTimeoutPresentCase() {\n        return NetReadTimeoutPresentCase.forNumber(\n            netReadTimeoutPresentCase_);\n      }\n\n      public Builder clearNetReadTimeoutPresent() {\n        netReadTimeoutPresentCase_ = 0;\n        netReadTimeoutPresent_ = null;\n        onChanged();\n        return this;\n      }\n\n      private int netWriteTimeoutPresentCase_ = 0;\n      private java.lang.Object netWriteTimeoutPresent_;\n      public NetWriteTimeoutPresentCase\n          getNetWriteTimeoutPresentCase() {\n        return NetWriteTimeoutPresentCase.forNumber(\n            netWriteTimeoutPresentCase_);\n      }\n\n      public Builder clearNetWriteTimeoutPresent() {\n        netWriteTimeoutPresentCase_ = 0;\n        netWriteTimeoutPresent_ = null;\n        onChanged();\n        return this;\n      }\n\n\n      private java.lang.Object username_ = \"\";\n      /**\n       * <code>string username = 1;</code>\n       */\n      public java.lang.String getUsername() {\n        java.lang.Object ref = username_;\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          username_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>string username = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getUsernameBytes() {\n        java.lang.Object ref = username_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          username_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>string username = 1;</code>\n       */\n      public Builder setUsername(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        username_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string username = 1;</code>\n       */\n      public Builder clearUsername() {\n        \n        username_ = getDefaultInstance().getUsername();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string username = 1;</code>\n       */\n      public Builder setUsernameBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  checkByteStringIsUtf8(value);\n        \n        username_ = value;\n        onChanged();\n        return this;\n      }\n\n      private com.google.protobuf.ByteString password_ = com.google.protobuf.ByteString.EMPTY;\n      /**\n       * <pre>\n       * hashed password with seeds from Handshake message\n       * </pre>\n       *\n       * <code>bytes password = 2;</code>\n       */\n      public com.google.protobuf.ByteString getPassword() {\n        return password_;\n      }\n      /**\n       * <pre>\n       * hashed password with seeds from Handshake message\n       * </pre>\n       *\n       * <code>bytes password = 2;</code>\n       */\n      public Builder setPassword(com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        password_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <pre>\n       * hashed password with seeds from Handshake message\n       * </pre>\n       *\n       * <code>bytes password = 2;</code>\n       */\n      public Builder clearPassword() {\n        \n        password_ = getDefaultInstance().getPassword();\n        onChanged();\n        return this;\n      }\n\n      /**\n       * <pre>\n       * in seconds\n       * </pre>\n       *\n       * <code>int32 net_read_timeout = 3;</code>\n       */\n      public int getNetReadTimeout() {\n        if (netReadTimeoutPresentCase_ == 3) {\n          return (java.lang.Integer) netReadTimeoutPresent_;\n        }\n        return 0;\n      }\n      /**\n       * <pre>\n       * in seconds\n       * </pre>\n       *\n       * <code>int32 net_read_timeout = 3;</code>\n       */\n      public Builder setNetReadTimeout(int value) {\n        netReadTimeoutPresentCase_ = 3;\n        netReadTimeoutPresent_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <pre>\n       * in seconds\n       * </pre>\n       *\n       * <code>int32 net_read_timeout = 3;</code>\n       */\n      public Builder clearNetReadTimeout() {\n        if (netReadTimeoutPresentCase_ == 3) {\n          netReadTimeoutPresentCase_ = 0;\n          netReadTimeoutPresent_ = null;\n          onChanged();\n        }\n        return this;\n      }\n\n      /**\n       * <pre>\n       * in seconds\n       * </pre>\n       *\n       * <code>int32 net_write_timeout = 4;</code>\n       */\n      public int getNetWriteTimeout() {\n        if (netWriteTimeoutPresentCase_ == 4) {\n          return (java.lang.Integer) netWriteTimeoutPresent_;\n        }\n        return 0;\n      }\n      /**\n       * <pre>\n       * in seconds\n       * </pre>\n       *\n       * <code>int32 net_write_timeout = 4;</code>\n       */\n      public Builder setNetWriteTimeout(int value) {\n        netWriteTimeoutPresentCase_ = 4;\n        netWriteTimeoutPresent_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <pre>\n       * in seconds\n       * </pre>\n       *\n       * <code>int32 net_write_timeout = 4;</code>\n       */\n      public Builder clearNetWriteTimeout() {\n        if (netWriteTimeoutPresentCase_ == 4) {\n          netWriteTimeoutPresentCase_ = 0;\n          netWriteTimeoutPresent_ = null;\n          onChanged();\n        }\n        return this;\n      }\n\n      private java.lang.Object destination_ = \"\";\n      /**\n       * <code>string destination = 5;</code>\n       */\n      public java.lang.String getDestination() {\n        java.lang.Object ref = destination_;\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          destination_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>string destination = 5;</code>\n       */\n      public com.google.protobuf.ByteString\n          getDestinationBytes() {\n        java.lang.Object ref = destination_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          destination_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>string destination = 5;</code>\n       */\n      public Builder setDestination(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        destination_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string destination = 5;</code>\n       */\n      public Builder clearDestination() {\n        \n        destination_ = getDefaultInstance().getDestination();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string destination = 5;</code>\n       */\n      public Builder setDestinationBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  checkByteStringIsUtf8(value);\n        \n        destination_ = value;\n        onChanged();\n        return this;\n      }\n\n      private java.lang.Object clientId_ = \"\";\n      /**\n       * <code>string client_id = 6;</code>\n       */\n      public java.lang.String getClientId() {\n        java.lang.Object ref = clientId_;\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          clientId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>string client_id = 6;</code>\n       */\n      public com.google.protobuf.ByteString\n          getClientIdBytes() {\n        java.lang.Object ref = clientId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          clientId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>string client_id = 6;</code>\n       */\n      public Builder setClientId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        clientId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string client_id = 6;</code>\n       */\n      public Builder clearClientId() {\n        \n        clientId_ = getDefaultInstance().getClientId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string client_id = 6;</code>\n       */\n      public Builder setClientIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  checkByteStringIsUtf8(value);\n        \n        clientId_ = value;\n        onChanged();\n        return this;\n      }\n\n      private java.lang.Object filter_ = \"\";\n      /**\n       * <code>string filter = 7;</code>\n       */\n      public java.lang.String getFilter() {\n        java.lang.Object ref = filter_;\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          filter_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>string filter = 7;</code>\n       */\n      public com.google.protobuf.ByteString\n          getFilterBytes() {\n        java.lang.Object ref = filter_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          filter_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>string filter = 7;</code>\n       */\n      public Builder setFilter(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        filter_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string filter = 7;</code>\n       */\n      public Builder clearFilter() {\n        \n        filter_ = getDefaultInstance().getFilter();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string filter = 7;</code>\n       */\n      public Builder setFilterBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  checkByteStringIsUtf8(value);\n        \n        filter_ = value;\n        onChanged();\n        return this;\n      }\n\n      private long startTimestamp_ ;\n      /**\n       * <code>int64 start_timestamp = 8;</code>\n       */\n      public long getStartTimestamp() {\n        return startTimestamp_;\n      }\n      /**\n       * <code>int64 start_timestamp = 8;</code>\n       */\n      public Builder setStartTimestamp(long value) {\n        \n        startTimestamp_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>int64 start_timestamp = 8;</code>\n       */\n      public Builder clearStartTimestamp() {\n        \n        startTimestamp_ = 0L;\n        onChanged();\n        return this;\n      }\n      @java.lang.Override\n      public final Builder setUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.setUnknownFieldsProto3(unknownFields);\n      }\n\n      @java.lang.Override\n      public final Builder mergeUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.mergeUnknownFields(unknownFields);\n      }\n\n\n      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.ClientAuth)\n    }\n\n    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.ClientAuth)\n    private static final com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth DEFAULT_INSTANCE;\n    static {\n      DEFAULT_INSTANCE = new com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth();\n    }\n\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth getDefaultInstance() {\n      return DEFAULT_INSTANCE;\n    }\n\n    private static final com.google.protobuf.Parser<ClientAuth>\n        PARSER = new com.google.protobuf.AbstractParser<ClientAuth>() {\n      @java.lang.Override\n      public ClientAuth parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new ClientAuth(input, extensionRegistry);\n      }\n    };\n\n    public static com.google.protobuf.Parser<ClientAuth> parser() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<ClientAuth> getParserForType() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth getDefaultInstanceForType() {\n      return DEFAULT_INSTANCE;\n    }\n\n  }\n\n  public interface AckOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.Ack)\n      com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <code>int32 error_code = 1;</code>\n     */\n    int getErrorCode();\n\n    /**\n     * <pre>\n     * if something like compression is not supported, erorr_message will tell about it.\n     * </pre>\n     *\n     * <code>string error_message = 2;</code>\n     */\n    java.lang.String getErrorMessage();\n    /**\n     * <pre>\n     * if something like compression is not supported, erorr_message will tell about it.\n     * </pre>\n     *\n     * <code>string error_message = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getErrorMessageBytes();\n\n    public com.alibaba.otter.canal.protocol.CanalPacket.Ack.ErrorCodePresentCase getErrorCodePresentCase();\n  }\n  /**\n   * Protobuf type {@code com.alibaba.otter.canal.protocol.Ack}\n   */\n  public  static final class Ack extends\n      com.google.protobuf.GeneratedMessageV3 implements\n      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.Ack)\n      AckOrBuilder {\n  private static final long serialVersionUID = 0L;\n    // Use Ack.newBuilder() to construct.\n    private Ack(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {\n      super(builder);\n    }\n    private Ack() {\n      errorMessage_ = \"\";\n    }\n\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n    getUnknownFields() {\n      return this.unknownFields;\n    }\n    private Ack(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      this();\n      if (extensionRegistry == null) {\n        throw new java.lang.NullPointerException();\n      }\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            case 8: {\n              errorCodePresentCase_ = 1;\n              errorCodePresent_ = input.readInt32();\n              break;\n            }\n            case 18: {\n              java.lang.String s = input.readStringRequireUtf8();\n\n              errorMessage_ = s;\n              break;\n            }\n            default: {\n              if (!parseUnknownFieldProto3(\n                  input, unknownFields, extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Ack_descriptor;\n    }\n\n    @java.lang.Override\n    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Ack_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              com.alibaba.otter.canal.protocol.CanalPacket.Ack.class, com.alibaba.otter.canal.protocol.CanalPacket.Ack.Builder.class);\n    }\n\n    private int errorCodePresentCase_ = 0;\n    private java.lang.Object errorCodePresent_;\n    public enum ErrorCodePresentCase\n        implements com.google.protobuf.Internal.EnumLite {\n      ERROR_CODE(1),\n      ERRORCODEPRESENT_NOT_SET(0);\n      private final int value;\n      private ErrorCodePresentCase(int value) {\n        this.value = value;\n      }\n      /**\n       * @deprecated Use {@link #forNumber(int)} instead.\n       */\n      @java.lang.Deprecated\n      public static ErrorCodePresentCase valueOf(int value) {\n        return forNumber(value);\n      }\n\n      public static ErrorCodePresentCase forNumber(int value) {\n        switch (value) {\n          case 1: return ERROR_CODE;\n          case 0: return ERRORCODEPRESENT_NOT_SET;\n          default: return null;\n        }\n      }\n      public int getNumber() {\n        return this.value;\n      }\n    };\n\n    public ErrorCodePresentCase\n    getErrorCodePresentCase() {\n      return ErrorCodePresentCase.forNumber(\n          errorCodePresentCase_);\n    }\n\n    public static final int ERROR_CODE_FIELD_NUMBER = 1;\n    /**\n     * <code>int32 error_code = 1;</code>\n     */\n    public int getErrorCode() {\n      if (errorCodePresentCase_ == 1) {\n        return (java.lang.Integer) errorCodePresent_;\n      }\n      return 0;\n    }\n\n    public static final int ERROR_MESSAGE_FIELD_NUMBER = 2;\n    private volatile java.lang.Object errorMessage_;\n    /**\n     * <pre>\n     * if something like compression is not supported, erorr_message will tell about it.\n     * </pre>\n     *\n     * <code>string error_message = 2;</code>\n     */\n    public java.lang.String getErrorMessage() {\n      java.lang.Object ref = errorMessage_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        errorMessage_ = s;\n        return s;\n      }\n    }\n    /**\n     * <pre>\n     * if something like compression is not supported, erorr_message will tell about it.\n     * </pre>\n     *\n     * <code>string error_message = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getErrorMessageBytes() {\n      java.lang.Object ref = errorMessage_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        errorMessage_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private byte memoizedIsInitialized = -1;\n    @java.lang.Override\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    @java.lang.Override\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      if (errorCodePresentCase_ == 1) {\n        output.writeInt32(\n            1, (int)((java.lang.Integer) errorCodePresent_));\n      }\n      if (!getErrorMessageBytes().isEmpty()) {\n        com.google.protobuf.GeneratedMessageV3.writeString(output, 2, errorMessage_);\n      }\n      unknownFields.writeTo(output);\n    }\n\n    @java.lang.Override\n    public int getSerializedSize() {\n      int size = memoizedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (errorCodePresentCase_ == 1) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(\n              1, (int)((java.lang.Integer) errorCodePresent_));\n      }\n      if (!getErrorMessageBytes().isEmpty()) {\n        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, errorMessage_);\n      }\n      size += unknownFields.getSerializedSize();\n      memoizedSize = size;\n      return size;\n    }\n\n    @java.lang.Override\n    public boolean equals(final java.lang.Object obj) {\n      if (obj == this) {\n       return true;\n      }\n      if (!(obj instanceof com.alibaba.otter.canal.protocol.CanalPacket.Ack)) {\n        return super.equals(obj);\n      }\n      com.alibaba.otter.canal.protocol.CanalPacket.Ack other = (com.alibaba.otter.canal.protocol.CanalPacket.Ack) obj;\n\n      boolean result = true;\n      result = result && getErrorMessage()\n          .equals(other.getErrorMessage());\n      result = result && getErrorCodePresentCase().equals(\n          other.getErrorCodePresentCase());\n      if (!result) return false;\n      switch (errorCodePresentCase_) {\n        case 1:\n          result = result && (getErrorCode()\n              == other.getErrorCode());\n          break;\n        case 0:\n        default:\n      }\n      result = result && unknownFields.equals(other.unknownFields);\n      return result;\n    }\n\n    @java.lang.Override\n    public int hashCode() {\n      if (memoizedHashCode != 0) {\n        return memoizedHashCode;\n      }\n      int hash = 41;\n      hash = (19 * hash) + getDescriptor().hashCode();\n      hash = (37 * hash) + ERROR_MESSAGE_FIELD_NUMBER;\n      hash = (53 * hash) + getErrorMessage().hashCode();\n      switch (errorCodePresentCase_) {\n        case 1:\n          hash = (37 * hash) + ERROR_CODE_FIELD_NUMBER;\n          hash = (53 * hash) + getErrorCode();\n          break;\n        case 0:\n        default:\n      }\n      hash = (29 * hash) + unknownFields.hashCode();\n      memoizedHashCode = hash;\n      return hash;\n    }\n\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Ack parseFrom(\n        java.nio.ByteBuffer data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Ack parseFrom(\n        java.nio.ByteBuffer data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Ack parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Ack parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Ack parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Ack parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Ack parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Ack parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Ack parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Ack parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Ack parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Ack parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    @java.lang.Override\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder() {\n      return DEFAULT_INSTANCE.toBuilder();\n    }\n    public static Builder newBuilder(com.alibaba.otter.canal.protocol.CanalPacket.Ack prototype) {\n      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n    }\n    @java.lang.Override\n    public Builder toBuilder() {\n      return this == DEFAULT_INSTANCE\n          ? new Builder() : new Builder().mergeFrom(this);\n    }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code com.alibaba.otter.canal.protocol.Ack}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.Ack)\n        com.alibaba.otter.canal.protocol.CanalPacket.AckOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Ack_descriptor;\n      }\n\n      @java.lang.Override\n      protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Ack_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                com.alibaba.otter.canal.protocol.CanalPacket.Ack.class, com.alibaba.otter.canal.protocol.CanalPacket.Ack.Builder.class);\n      }\n\n      // Construct using com.alibaba.otter.canal.protocol.CanalPacket.Ack.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessageV3\n                .alwaysUseFieldBuilders) {\n        }\n      }\n      @java.lang.Override\n      public Builder clear() {\n        super.clear();\n        errorMessage_ = \"\";\n\n        errorCodePresentCase_ = 0;\n        errorCodePresent_ = null;\n        return this;\n      }\n\n      @java.lang.Override\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Ack_descriptor;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.Ack getDefaultInstanceForType() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.Ack.getDefaultInstance();\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.Ack build() {\n        com.alibaba.otter.canal.protocol.CanalPacket.Ack result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.Ack buildPartial() {\n        com.alibaba.otter.canal.protocol.CanalPacket.Ack result = new com.alibaba.otter.canal.protocol.CanalPacket.Ack(this);\n        if (errorCodePresentCase_ == 1) {\n          result.errorCodePresent_ = errorCodePresent_;\n        }\n        result.errorMessage_ = errorMessage_;\n        result.errorCodePresentCase_ = errorCodePresentCase_;\n        onBuilt();\n        return result;\n      }\n\n      @java.lang.Override\n      public Builder clone() {\n        return (Builder) super.clone();\n      }\n      @java.lang.Override\n      public Builder setField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.setField(field, value);\n      }\n      @java.lang.Override\n      public Builder clearField(\n          com.google.protobuf.Descriptors.FieldDescriptor field) {\n        return (Builder) super.clearField(field);\n      }\n      @java.lang.Override\n      public Builder clearOneof(\n          com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n        return (Builder) super.clearOneof(oneof);\n      }\n      @java.lang.Override\n      public Builder setRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          int index, java.lang.Object value) {\n        return (Builder) super.setRepeatedField(field, index, value);\n      }\n      @java.lang.Override\n      public Builder addRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.addRepeatedField(field, value);\n      }\n      @java.lang.Override\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof com.alibaba.otter.canal.protocol.CanalPacket.Ack) {\n          return mergeFrom((com.alibaba.otter.canal.protocol.CanalPacket.Ack)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(com.alibaba.otter.canal.protocol.CanalPacket.Ack other) {\n        if (other == com.alibaba.otter.canal.protocol.CanalPacket.Ack.getDefaultInstance()) return this;\n        if (!other.getErrorMessage().isEmpty()) {\n          errorMessage_ = other.errorMessage_;\n          onChanged();\n        }\n        switch (other.getErrorCodePresentCase()) {\n          case ERROR_CODE: {\n            setErrorCode(other.getErrorCode());\n            break;\n          }\n          case ERRORCODEPRESENT_NOT_SET: {\n            break;\n          }\n        }\n        this.mergeUnknownFields(other.unknownFields);\n        onChanged();\n        return this;\n      }\n\n      @java.lang.Override\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      @java.lang.Override\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        com.alibaba.otter.canal.protocol.CanalPacket.Ack parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (com.alibaba.otter.canal.protocol.CanalPacket.Ack) e.getUnfinishedMessage();\n          throw e.unwrapIOException();\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int errorCodePresentCase_ = 0;\n      private java.lang.Object errorCodePresent_;\n      public ErrorCodePresentCase\n          getErrorCodePresentCase() {\n        return ErrorCodePresentCase.forNumber(\n            errorCodePresentCase_);\n      }\n\n      public Builder clearErrorCodePresent() {\n        errorCodePresentCase_ = 0;\n        errorCodePresent_ = null;\n        onChanged();\n        return this;\n      }\n\n\n      /**\n       * <code>int32 error_code = 1;</code>\n       */\n      public int getErrorCode() {\n        if (errorCodePresentCase_ == 1) {\n          return (java.lang.Integer) errorCodePresent_;\n        }\n        return 0;\n      }\n      /**\n       * <code>int32 error_code = 1;</code>\n       */\n      public Builder setErrorCode(int value) {\n        errorCodePresentCase_ = 1;\n        errorCodePresent_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>int32 error_code = 1;</code>\n       */\n      public Builder clearErrorCode() {\n        if (errorCodePresentCase_ == 1) {\n          errorCodePresentCase_ = 0;\n          errorCodePresent_ = null;\n          onChanged();\n        }\n        return this;\n      }\n\n      private java.lang.Object errorMessage_ = \"\";\n      /**\n       * <pre>\n       * if something like compression is not supported, erorr_message will tell about it.\n       * </pre>\n       *\n       * <code>string error_message = 2;</code>\n       */\n      public java.lang.String getErrorMessage() {\n        java.lang.Object ref = errorMessage_;\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          errorMessage_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <pre>\n       * if something like compression is not supported, erorr_message will tell about it.\n       * </pre>\n       *\n       * <code>string error_message = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getErrorMessageBytes() {\n        java.lang.Object ref = errorMessage_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          errorMessage_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <pre>\n       * if something like compression is not supported, erorr_message will tell about it.\n       * </pre>\n       *\n       * <code>string error_message = 2;</code>\n       */\n      public Builder setErrorMessage(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        errorMessage_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <pre>\n       * if something like compression is not supported, erorr_message will tell about it.\n       * </pre>\n       *\n       * <code>string error_message = 2;</code>\n       */\n      public Builder clearErrorMessage() {\n        \n        errorMessage_ = getDefaultInstance().getErrorMessage();\n        onChanged();\n        return this;\n      }\n      /**\n       * <pre>\n       * if something like compression is not supported, erorr_message will tell about it.\n       * </pre>\n       *\n       * <code>string error_message = 2;</code>\n       */\n      public Builder setErrorMessageBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  checkByteStringIsUtf8(value);\n        \n        errorMessage_ = value;\n        onChanged();\n        return this;\n      }\n      @java.lang.Override\n      public final Builder setUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.setUnknownFieldsProto3(unknownFields);\n      }\n\n      @java.lang.Override\n      public final Builder mergeUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.mergeUnknownFields(unknownFields);\n      }\n\n\n      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.Ack)\n    }\n\n    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.Ack)\n    private static final com.alibaba.otter.canal.protocol.CanalPacket.Ack DEFAULT_INSTANCE;\n    static {\n      DEFAULT_INSTANCE = new com.alibaba.otter.canal.protocol.CanalPacket.Ack();\n    }\n\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Ack getDefaultInstance() {\n      return DEFAULT_INSTANCE;\n    }\n\n    private static final com.google.protobuf.Parser<Ack>\n        PARSER = new com.google.protobuf.AbstractParser<Ack>() {\n      @java.lang.Override\n      public Ack parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new Ack(input, extensionRegistry);\n      }\n    };\n\n    public static com.google.protobuf.Parser<Ack> parser() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<Ack> getParserForType() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.alibaba.otter.canal.protocol.CanalPacket.Ack getDefaultInstanceForType() {\n      return DEFAULT_INSTANCE;\n    }\n\n  }\n\n  public interface ClientAckOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.ClientAck)\n      com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <code>string destination = 1;</code>\n     */\n    java.lang.String getDestination();\n    /**\n     * <code>string destination = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getDestinationBytes();\n\n    /**\n     * <code>string client_id = 2;</code>\n     */\n    java.lang.String getClientId();\n    /**\n     * <code>string client_id = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getClientIdBytes();\n\n    /**\n     * <code>int64 batch_id = 3;</code>\n     */\n    long getBatchId();\n  }\n  /**\n   * Protobuf type {@code com.alibaba.otter.canal.protocol.ClientAck}\n   */\n  public  static final class ClientAck extends\n      com.google.protobuf.GeneratedMessageV3 implements\n      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.ClientAck)\n      ClientAckOrBuilder {\n  private static final long serialVersionUID = 0L;\n    // Use ClientAck.newBuilder() to construct.\n    private ClientAck(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {\n      super(builder);\n    }\n    private ClientAck() {\n      destination_ = \"\";\n      clientId_ = \"\";\n      batchId_ = 0L;\n    }\n\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n    getUnknownFields() {\n      return this.unknownFields;\n    }\n    private ClientAck(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      this();\n      if (extensionRegistry == null) {\n        throw new java.lang.NullPointerException();\n      }\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            case 10: {\n              java.lang.String s = input.readStringRequireUtf8();\n\n              destination_ = s;\n              break;\n            }\n            case 18: {\n              java.lang.String s = input.readStringRequireUtf8();\n\n              clientId_ = s;\n              break;\n            }\n            case 24: {\n\n              batchId_ = input.readInt64();\n              break;\n            }\n            default: {\n              if (!parseUnknownFieldProto3(\n                  input, unknownFields, extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_ClientAck_descriptor;\n    }\n\n    @java.lang.Override\n    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_ClientAck_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              com.alibaba.otter.canal.protocol.CanalPacket.ClientAck.class, com.alibaba.otter.canal.protocol.CanalPacket.ClientAck.Builder.class);\n    }\n\n    public static final int DESTINATION_FIELD_NUMBER = 1;\n    private volatile java.lang.Object destination_;\n    /**\n     * <code>string destination = 1;</code>\n     */\n    public java.lang.String getDestination() {\n      java.lang.Object ref = destination_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        destination_ = s;\n        return s;\n      }\n    }\n    /**\n     * <code>string destination = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getDestinationBytes() {\n      java.lang.Object ref = destination_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        destination_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int CLIENT_ID_FIELD_NUMBER = 2;\n    private volatile java.lang.Object clientId_;\n    /**\n     * <code>string client_id = 2;</code>\n     */\n    public java.lang.String getClientId() {\n      java.lang.Object ref = clientId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        clientId_ = s;\n        return s;\n      }\n    }\n    /**\n     * <code>string client_id = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getClientIdBytes() {\n      java.lang.Object ref = clientId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        clientId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int BATCH_ID_FIELD_NUMBER = 3;\n    private long batchId_;\n    /**\n     * <code>int64 batch_id = 3;</code>\n     */\n    public long getBatchId() {\n      return batchId_;\n    }\n\n    private byte memoizedIsInitialized = -1;\n    @java.lang.Override\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    @java.lang.Override\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      if (!getDestinationBytes().isEmpty()) {\n        com.google.protobuf.GeneratedMessageV3.writeString(output, 1, destination_);\n      }\n      if (!getClientIdBytes().isEmpty()) {\n        com.google.protobuf.GeneratedMessageV3.writeString(output, 2, clientId_);\n      }\n      if (batchId_ != 0L) {\n        output.writeInt64(3, batchId_);\n      }\n      unknownFields.writeTo(output);\n    }\n\n    @java.lang.Override\n    public int getSerializedSize() {\n      int size = memoizedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (!getDestinationBytes().isEmpty()) {\n        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, destination_);\n      }\n      if (!getClientIdBytes().isEmpty()) {\n        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, clientId_);\n      }\n      if (batchId_ != 0L) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(3, batchId_);\n      }\n      size += unknownFields.getSerializedSize();\n      memoizedSize = size;\n      return size;\n    }\n\n    @java.lang.Override\n    public boolean equals(final java.lang.Object obj) {\n      if (obj == this) {\n       return true;\n      }\n      if (!(obj instanceof com.alibaba.otter.canal.protocol.CanalPacket.ClientAck)) {\n        return super.equals(obj);\n      }\n      com.alibaba.otter.canal.protocol.CanalPacket.ClientAck other = (com.alibaba.otter.canal.protocol.CanalPacket.ClientAck) obj;\n\n      boolean result = true;\n      result = result && getDestination()\n          .equals(other.getDestination());\n      result = result && getClientId()\n          .equals(other.getClientId());\n      result = result && (getBatchId()\n          == other.getBatchId());\n      result = result && unknownFields.equals(other.unknownFields);\n      return result;\n    }\n\n    @java.lang.Override\n    public int hashCode() {\n      if (memoizedHashCode != 0) {\n        return memoizedHashCode;\n      }\n      int hash = 41;\n      hash = (19 * hash) + getDescriptor().hashCode();\n      hash = (37 * hash) + DESTINATION_FIELD_NUMBER;\n      hash = (53 * hash) + getDestination().hashCode();\n      hash = (37 * hash) + CLIENT_ID_FIELD_NUMBER;\n      hash = (53 * hash) + getClientId().hashCode();\n      hash = (37 * hash) + BATCH_ID_FIELD_NUMBER;\n      hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n          getBatchId());\n      hash = (29 * hash) + unknownFields.hashCode();\n      memoizedHashCode = hash;\n      return hash;\n    }\n\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientAck parseFrom(\n        java.nio.ByteBuffer data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientAck parseFrom(\n        java.nio.ByteBuffer data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientAck parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientAck parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientAck parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientAck parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientAck parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientAck parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientAck parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientAck parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientAck parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientAck parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    @java.lang.Override\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder() {\n      return DEFAULT_INSTANCE.toBuilder();\n    }\n    public static Builder newBuilder(com.alibaba.otter.canal.protocol.CanalPacket.ClientAck prototype) {\n      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n    }\n    @java.lang.Override\n    public Builder toBuilder() {\n      return this == DEFAULT_INSTANCE\n          ? new Builder() : new Builder().mergeFrom(this);\n    }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code com.alibaba.otter.canal.protocol.ClientAck}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.ClientAck)\n        com.alibaba.otter.canal.protocol.CanalPacket.ClientAckOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_ClientAck_descriptor;\n      }\n\n      @java.lang.Override\n      protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_ClientAck_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                com.alibaba.otter.canal.protocol.CanalPacket.ClientAck.class, com.alibaba.otter.canal.protocol.CanalPacket.ClientAck.Builder.class);\n      }\n\n      // Construct using com.alibaba.otter.canal.protocol.CanalPacket.ClientAck.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessageV3\n                .alwaysUseFieldBuilders) {\n        }\n      }\n      @java.lang.Override\n      public Builder clear() {\n        super.clear();\n        destination_ = \"\";\n\n        clientId_ = \"\";\n\n        batchId_ = 0L;\n\n        return this;\n      }\n\n      @java.lang.Override\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_ClientAck_descriptor;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.ClientAck getDefaultInstanceForType() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.ClientAck.getDefaultInstance();\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.ClientAck build() {\n        com.alibaba.otter.canal.protocol.CanalPacket.ClientAck result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.ClientAck buildPartial() {\n        com.alibaba.otter.canal.protocol.CanalPacket.ClientAck result = new com.alibaba.otter.canal.protocol.CanalPacket.ClientAck(this);\n        result.destination_ = destination_;\n        result.clientId_ = clientId_;\n        result.batchId_ = batchId_;\n        onBuilt();\n        return result;\n      }\n\n      @java.lang.Override\n      public Builder clone() {\n        return (Builder) super.clone();\n      }\n      @java.lang.Override\n      public Builder setField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.setField(field, value);\n      }\n      @java.lang.Override\n      public Builder clearField(\n          com.google.protobuf.Descriptors.FieldDescriptor field) {\n        return (Builder) super.clearField(field);\n      }\n      @java.lang.Override\n      public Builder clearOneof(\n          com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n        return (Builder) super.clearOneof(oneof);\n      }\n      @java.lang.Override\n      public Builder setRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          int index, java.lang.Object value) {\n        return (Builder) super.setRepeatedField(field, index, value);\n      }\n      @java.lang.Override\n      public Builder addRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.addRepeatedField(field, value);\n      }\n      @java.lang.Override\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof com.alibaba.otter.canal.protocol.CanalPacket.ClientAck) {\n          return mergeFrom((com.alibaba.otter.canal.protocol.CanalPacket.ClientAck)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(com.alibaba.otter.canal.protocol.CanalPacket.ClientAck other) {\n        if (other == com.alibaba.otter.canal.protocol.CanalPacket.ClientAck.getDefaultInstance()) return this;\n        if (!other.getDestination().isEmpty()) {\n          destination_ = other.destination_;\n          onChanged();\n        }\n        if (!other.getClientId().isEmpty()) {\n          clientId_ = other.clientId_;\n          onChanged();\n        }\n        if (other.getBatchId() != 0L) {\n          setBatchId(other.getBatchId());\n        }\n        this.mergeUnknownFields(other.unknownFields);\n        onChanged();\n        return this;\n      }\n\n      @java.lang.Override\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      @java.lang.Override\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        com.alibaba.otter.canal.protocol.CanalPacket.ClientAck parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (com.alibaba.otter.canal.protocol.CanalPacket.ClientAck) e.getUnfinishedMessage();\n          throw e.unwrapIOException();\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n\n      private java.lang.Object destination_ = \"\";\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public java.lang.String getDestination() {\n        java.lang.Object ref = destination_;\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          destination_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getDestinationBytes() {\n        java.lang.Object ref = destination_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          destination_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public Builder setDestination(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        destination_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public Builder clearDestination() {\n        \n        destination_ = getDefaultInstance().getDestination();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public Builder setDestinationBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  checkByteStringIsUtf8(value);\n        \n        destination_ = value;\n        onChanged();\n        return this;\n      }\n\n      private java.lang.Object clientId_ = \"\";\n      /**\n       * <code>string client_id = 2;</code>\n       */\n      public java.lang.String getClientId() {\n        java.lang.Object ref = clientId_;\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          clientId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>string client_id = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getClientIdBytes() {\n        java.lang.Object ref = clientId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          clientId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>string client_id = 2;</code>\n       */\n      public Builder setClientId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        clientId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string client_id = 2;</code>\n       */\n      public Builder clearClientId() {\n        \n        clientId_ = getDefaultInstance().getClientId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string client_id = 2;</code>\n       */\n      public Builder setClientIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  checkByteStringIsUtf8(value);\n        \n        clientId_ = value;\n        onChanged();\n        return this;\n      }\n\n      private long batchId_ ;\n      /**\n       * <code>int64 batch_id = 3;</code>\n       */\n      public long getBatchId() {\n        return batchId_;\n      }\n      /**\n       * <code>int64 batch_id = 3;</code>\n       */\n      public Builder setBatchId(long value) {\n        \n        batchId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>int64 batch_id = 3;</code>\n       */\n      public Builder clearBatchId() {\n        \n        batchId_ = 0L;\n        onChanged();\n        return this;\n      }\n      @java.lang.Override\n      public final Builder setUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.setUnknownFieldsProto3(unknownFields);\n      }\n\n      @java.lang.Override\n      public final Builder mergeUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.mergeUnknownFields(unknownFields);\n      }\n\n\n      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.ClientAck)\n    }\n\n    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.ClientAck)\n    private static final com.alibaba.otter.canal.protocol.CanalPacket.ClientAck DEFAULT_INSTANCE;\n    static {\n      DEFAULT_INSTANCE = new com.alibaba.otter.canal.protocol.CanalPacket.ClientAck();\n    }\n\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientAck getDefaultInstance() {\n      return DEFAULT_INSTANCE;\n    }\n\n    private static final com.google.protobuf.Parser<ClientAck>\n        PARSER = new com.google.protobuf.AbstractParser<ClientAck>() {\n      @java.lang.Override\n      public ClientAck parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new ClientAck(input, extensionRegistry);\n      }\n    };\n\n    public static com.google.protobuf.Parser<ClientAck> parser() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<ClientAck> getParserForType() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.alibaba.otter.canal.protocol.CanalPacket.ClientAck getDefaultInstanceForType() {\n      return DEFAULT_INSTANCE;\n    }\n\n  }\n\n  public interface SubOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.Sub)\n      com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <code>string destination = 1;</code>\n     */\n    java.lang.String getDestination();\n    /**\n     * <code>string destination = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getDestinationBytes();\n\n    /**\n     * <code>string client_id = 2;</code>\n     */\n    java.lang.String getClientId();\n    /**\n     * <code>string client_id = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getClientIdBytes();\n\n    /**\n     * <code>string filter = 7;</code>\n     */\n    java.lang.String getFilter();\n    /**\n     * <code>string filter = 7;</code>\n     */\n    com.google.protobuf.ByteString\n        getFilterBytes();\n  }\n  /**\n   * <pre>\n   * subscription\n   * </pre>\n   *\n   * Protobuf type {@code com.alibaba.otter.canal.protocol.Sub}\n   */\n  public  static final class Sub extends\n      com.google.protobuf.GeneratedMessageV3 implements\n      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.Sub)\n      SubOrBuilder {\n  private static final long serialVersionUID = 0L;\n    // Use Sub.newBuilder() to construct.\n    private Sub(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {\n      super(builder);\n    }\n    private Sub() {\n      destination_ = \"\";\n      clientId_ = \"\";\n      filter_ = \"\";\n    }\n\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n    getUnknownFields() {\n      return this.unknownFields;\n    }\n    private Sub(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      this();\n      if (extensionRegistry == null) {\n        throw new java.lang.NullPointerException();\n      }\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            case 10: {\n              java.lang.String s = input.readStringRequireUtf8();\n\n              destination_ = s;\n              break;\n            }\n            case 18: {\n              java.lang.String s = input.readStringRequireUtf8();\n\n              clientId_ = s;\n              break;\n            }\n            case 58: {\n              java.lang.String s = input.readStringRequireUtf8();\n\n              filter_ = s;\n              break;\n            }\n            default: {\n              if (!parseUnknownFieldProto3(\n                  input, unknownFields, extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Sub_descriptor;\n    }\n\n    @java.lang.Override\n    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Sub_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              com.alibaba.otter.canal.protocol.CanalPacket.Sub.class, com.alibaba.otter.canal.protocol.CanalPacket.Sub.Builder.class);\n    }\n\n    public static final int DESTINATION_FIELD_NUMBER = 1;\n    private volatile java.lang.Object destination_;\n    /**\n     * <code>string destination = 1;</code>\n     */\n    public java.lang.String getDestination() {\n      java.lang.Object ref = destination_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        destination_ = s;\n        return s;\n      }\n    }\n    /**\n     * <code>string destination = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getDestinationBytes() {\n      java.lang.Object ref = destination_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        destination_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int CLIENT_ID_FIELD_NUMBER = 2;\n    private volatile java.lang.Object clientId_;\n    /**\n     * <code>string client_id = 2;</code>\n     */\n    public java.lang.String getClientId() {\n      java.lang.Object ref = clientId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        clientId_ = s;\n        return s;\n      }\n    }\n    /**\n     * <code>string client_id = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getClientIdBytes() {\n      java.lang.Object ref = clientId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        clientId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int FILTER_FIELD_NUMBER = 7;\n    private volatile java.lang.Object filter_;\n    /**\n     * <code>string filter = 7;</code>\n     */\n    public java.lang.String getFilter() {\n      java.lang.Object ref = filter_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        filter_ = s;\n        return s;\n      }\n    }\n    /**\n     * <code>string filter = 7;</code>\n     */\n    public com.google.protobuf.ByteString\n        getFilterBytes() {\n      java.lang.Object ref = filter_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        filter_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private byte memoizedIsInitialized = -1;\n    @java.lang.Override\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    @java.lang.Override\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      if (!getDestinationBytes().isEmpty()) {\n        com.google.protobuf.GeneratedMessageV3.writeString(output, 1, destination_);\n      }\n      if (!getClientIdBytes().isEmpty()) {\n        com.google.protobuf.GeneratedMessageV3.writeString(output, 2, clientId_);\n      }\n      if (!getFilterBytes().isEmpty()) {\n        com.google.protobuf.GeneratedMessageV3.writeString(output, 7, filter_);\n      }\n      unknownFields.writeTo(output);\n    }\n\n    @java.lang.Override\n    public int getSerializedSize() {\n      int size = memoizedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (!getDestinationBytes().isEmpty()) {\n        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, destination_);\n      }\n      if (!getClientIdBytes().isEmpty()) {\n        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, clientId_);\n      }\n      if (!getFilterBytes().isEmpty()) {\n        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(7, filter_);\n      }\n      size += unknownFields.getSerializedSize();\n      memoizedSize = size;\n      return size;\n    }\n\n    @java.lang.Override\n    public boolean equals(final java.lang.Object obj) {\n      if (obj == this) {\n       return true;\n      }\n      if (!(obj instanceof com.alibaba.otter.canal.protocol.CanalPacket.Sub)) {\n        return super.equals(obj);\n      }\n      com.alibaba.otter.canal.protocol.CanalPacket.Sub other = (com.alibaba.otter.canal.protocol.CanalPacket.Sub) obj;\n\n      boolean result = true;\n      result = result && getDestination()\n          .equals(other.getDestination());\n      result = result && getClientId()\n          .equals(other.getClientId());\n      result = result && getFilter()\n          .equals(other.getFilter());\n      result = result && unknownFields.equals(other.unknownFields);\n      return result;\n    }\n\n    @java.lang.Override\n    public int hashCode() {\n      if (memoizedHashCode != 0) {\n        return memoizedHashCode;\n      }\n      int hash = 41;\n      hash = (19 * hash) + getDescriptor().hashCode();\n      hash = (37 * hash) + DESTINATION_FIELD_NUMBER;\n      hash = (53 * hash) + getDestination().hashCode();\n      hash = (37 * hash) + CLIENT_ID_FIELD_NUMBER;\n      hash = (53 * hash) + getClientId().hashCode();\n      hash = (37 * hash) + FILTER_FIELD_NUMBER;\n      hash = (53 * hash) + getFilter().hashCode();\n      hash = (29 * hash) + unknownFields.hashCode();\n      memoizedHashCode = hash;\n      return hash;\n    }\n\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Sub parseFrom(\n        java.nio.ByteBuffer data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Sub parseFrom(\n        java.nio.ByteBuffer data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Sub parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Sub parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Sub parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Sub parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Sub parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Sub parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Sub parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Sub parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Sub parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Sub parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    @java.lang.Override\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder() {\n      return DEFAULT_INSTANCE.toBuilder();\n    }\n    public static Builder newBuilder(com.alibaba.otter.canal.protocol.CanalPacket.Sub prototype) {\n      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n    }\n    @java.lang.Override\n    public Builder toBuilder() {\n      return this == DEFAULT_INSTANCE\n          ? new Builder() : new Builder().mergeFrom(this);\n    }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * <pre>\n     * subscription\n     * </pre>\n     *\n     * Protobuf type {@code com.alibaba.otter.canal.protocol.Sub}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.Sub)\n        com.alibaba.otter.canal.protocol.CanalPacket.SubOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Sub_descriptor;\n      }\n\n      @java.lang.Override\n      protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Sub_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                com.alibaba.otter.canal.protocol.CanalPacket.Sub.class, com.alibaba.otter.canal.protocol.CanalPacket.Sub.Builder.class);\n      }\n\n      // Construct using com.alibaba.otter.canal.protocol.CanalPacket.Sub.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessageV3\n                .alwaysUseFieldBuilders) {\n        }\n      }\n      @java.lang.Override\n      public Builder clear() {\n        super.clear();\n        destination_ = \"\";\n\n        clientId_ = \"\";\n\n        filter_ = \"\";\n\n        return this;\n      }\n\n      @java.lang.Override\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Sub_descriptor;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.Sub getDefaultInstanceForType() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.Sub.getDefaultInstance();\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.Sub build() {\n        com.alibaba.otter.canal.protocol.CanalPacket.Sub result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.Sub buildPartial() {\n        com.alibaba.otter.canal.protocol.CanalPacket.Sub result = new com.alibaba.otter.canal.protocol.CanalPacket.Sub(this);\n        result.destination_ = destination_;\n        result.clientId_ = clientId_;\n        result.filter_ = filter_;\n        onBuilt();\n        return result;\n      }\n\n      @java.lang.Override\n      public Builder clone() {\n        return (Builder) super.clone();\n      }\n      @java.lang.Override\n      public Builder setField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.setField(field, value);\n      }\n      @java.lang.Override\n      public Builder clearField(\n          com.google.protobuf.Descriptors.FieldDescriptor field) {\n        return (Builder) super.clearField(field);\n      }\n      @java.lang.Override\n      public Builder clearOneof(\n          com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n        return (Builder) super.clearOneof(oneof);\n      }\n      @java.lang.Override\n      public Builder setRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          int index, java.lang.Object value) {\n        return (Builder) super.setRepeatedField(field, index, value);\n      }\n      @java.lang.Override\n      public Builder addRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.addRepeatedField(field, value);\n      }\n      @java.lang.Override\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof com.alibaba.otter.canal.protocol.CanalPacket.Sub) {\n          return mergeFrom((com.alibaba.otter.canal.protocol.CanalPacket.Sub)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(com.alibaba.otter.canal.protocol.CanalPacket.Sub other) {\n        if (other == com.alibaba.otter.canal.protocol.CanalPacket.Sub.getDefaultInstance()) return this;\n        if (!other.getDestination().isEmpty()) {\n          destination_ = other.destination_;\n          onChanged();\n        }\n        if (!other.getClientId().isEmpty()) {\n          clientId_ = other.clientId_;\n          onChanged();\n        }\n        if (!other.getFilter().isEmpty()) {\n          filter_ = other.filter_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.unknownFields);\n        onChanged();\n        return this;\n      }\n\n      @java.lang.Override\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      @java.lang.Override\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        com.alibaba.otter.canal.protocol.CanalPacket.Sub parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (com.alibaba.otter.canal.protocol.CanalPacket.Sub) e.getUnfinishedMessage();\n          throw e.unwrapIOException();\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n\n      private java.lang.Object destination_ = \"\";\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public java.lang.String getDestination() {\n        java.lang.Object ref = destination_;\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          destination_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getDestinationBytes() {\n        java.lang.Object ref = destination_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          destination_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public Builder setDestination(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        destination_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public Builder clearDestination() {\n        \n        destination_ = getDefaultInstance().getDestination();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public Builder setDestinationBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  checkByteStringIsUtf8(value);\n        \n        destination_ = value;\n        onChanged();\n        return this;\n      }\n\n      private java.lang.Object clientId_ = \"\";\n      /**\n       * <code>string client_id = 2;</code>\n       */\n      public java.lang.String getClientId() {\n        java.lang.Object ref = clientId_;\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          clientId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>string client_id = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getClientIdBytes() {\n        java.lang.Object ref = clientId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          clientId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>string client_id = 2;</code>\n       */\n      public Builder setClientId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        clientId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string client_id = 2;</code>\n       */\n      public Builder clearClientId() {\n        \n        clientId_ = getDefaultInstance().getClientId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string client_id = 2;</code>\n       */\n      public Builder setClientIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  checkByteStringIsUtf8(value);\n        \n        clientId_ = value;\n        onChanged();\n        return this;\n      }\n\n      private java.lang.Object filter_ = \"\";\n      /**\n       * <code>string filter = 7;</code>\n       */\n      public java.lang.String getFilter() {\n        java.lang.Object ref = filter_;\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          filter_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>string filter = 7;</code>\n       */\n      public com.google.protobuf.ByteString\n          getFilterBytes() {\n        java.lang.Object ref = filter_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          filter_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>string filter = 7;</code>\n       */\n      public Builder setFilter(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        filter_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string filter = 7;</code>\n       */\n      public Builder clearFilter() {\n        \n        filter_ = getDefaultInstance().getFilter();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string filter = 7;</code>\n       */\n      public Builder setFilterBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  checkByteStringIsUtf8(value);\n        \n        filter_ = value;\n        onChanged();\n        return this;\n      }\n      @java.lang.Override\n      public final Builder setUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.setUnknownFieldsProto3(unknownFields);\n      }\n\n      @java.lang.Override\n      public final Builder mergeUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.mergeUnknownFields(unknownFields);\n      }\n\n\n      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.Sub)\n    }\n\n    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.Sub)\n    private static final com.alibaba.otter.canal.protocol.CanalPacket.Sub DEFAULT_INSTANCE;\n    static {\n      DEFAULT_INSTANCE = new com.alibaba.otter.canal.protocol.CanalPacket.Sub();\n    }\n\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Sub getDefaultInstance() {\n      return DEFAULT_INSTANCE;\n    }\n\n    private static final com.google.protobuf.Parser<Sub>\n        PARSER = new com.google.protobuf.AbstractParser<Sub>() {\n      @java.lang.Override\n      public Sub parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new Sub(input, extensionRegistry);\n      }\n    };\n\n    public static com.google.protobuf.Parser<Sub> parser() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<Sub> getParserForType() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.alibaba.otter.canal.protocol.CanalPacket.Sub getDefaultInstanceForType() {\n      return DEFAULT_INSTANCE;\n    }\n\n  }\n\n  public interface UnsubOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.Unsub)\n      com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <code>string destination = 1;</code>\n     */\n    java.lang.String getDestination();\n    /**\n     * <code>string destination = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getDestinationBytes();\n\n    /**\n     * <code>string client_id = 2;</code>\n     */\n    java.lang.String getClientId();\n    /**\n     * <code>string client_id = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getClientIdBytes();\n\n    /**\n     * <code>string filter = 7;</code>\n     */\n    java.lang.String getFilter();\n    /**\n     * <code>string filter = 7;</code>\n     */\n    com.google.protobuf.ByteString\n        getFilterBytes();\n  }\n  /**\n   * <pre>\n   * Unsubscription\n   * </pre>\n   *\n   * Protobuf type {@code com.alibaba.otter.canal.protocol.Unsub}\n   */\n  public  static final class Unsub extends\n      com.google.protobuf.GeneratedMessageV3 implements\n      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.Unsub)\n      UnsubOrBuilder {\n  private static final long serialVersionUID = 0L;\n    // Use Unsub.newBuilder() to construct.\n    private Unsub(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {\n      super(builder);\n    }\n    private Unsub() {\n      destination_ = \"\";\n      clientId_ = \"\";\n      filter_ = \"\";\n    }\n\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n    getUnknownFields() {\n      return this.unknownFields;\n    }\n    private Unsub(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      this();\n      if (extensionRegistry == null) {\n        throw new java.lang.NullPointerException();\n      }\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            case 10: {\n              java.lang.String s = input.readStringRequireUtf8();\n\n              destination_ = s;\n              break;\n            }\n            case 18: {\n              java.lang.String s = input.readStringRequireUtf8();\n\n              clientId_ = s;\n              break;\n            }\n            case 58: {\n              java.lang.String s = input.readStringRequireUtf8();\n\n              filter_ = s;\n              break;\n            }\n            default: {\n              if (!parseUnknownFieldProto3(\n                  input, unknownFields, extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Unsub_descriptor;\n    }\n\n    @java.lang.Override\n    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Unsub_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              com.alibaba.otter.canal.protocol.CanalPacket.Unsub.class, com.alibaba.otter.canal.protocol.CanalPacket.Unsub.Builder.class);\n    }\n\n    public static final int DESTINATION_FIELD_NUMBER = 1;\n    private volatile java.lang.Object destination_;\n    /**\n     * <code>string destination = 1;</code>\n     */\n    public java.lang.String getDestination() {\n      java.lang.Object ref = destination_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        destination_ = s;\n        return s;\n      }\n    }\n    /**\n     * <code>string destination = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getDestinationBytes() {\n      java.lang.Object ref = destination_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        destination_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int CLIENT_ID_FIELD_NUMBER = 2;\n    private volatile java.lang.Object clientId_;\n    /**\n     * <code>string client_id = 2;</code>\n     */\n    public java.lang.String getClientId() {\n      java.lang.Object ref = clientId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        clientId_ = s;\n        return s;\n      }\n    }\n    /**\n     * <code>string client_id = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getClientIdBytes() {\n      java.lang.Object ref = clientId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        clientId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int FILTER_FIELD_NUMBER = 7;\n    private volatile java.lang.Object filter_;\n    /**\n     * <code>string filter = 7;</code>\n     */\n    public java.lang.String getFilter() {\n      java.lang.Object ref = filter_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        filter_ = s;\n        return s;\n      }\n    }\n    /**\n     * <code>string filter = 7;</code>\n     */\n    public com.google.protobuf.ByteString\n        getFilterBytes() {\n      java.lang.Object ref = filter_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        filter_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private byte memoizedIsInitialized = -1;\n    @java.lang.Override\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    @java.lang.Override\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      if (!getDestinationBytes().isEmpty()) {\n        com.google.protobuf.GeneratedMessageV3.writeString(output, 1, destination_);\n      }\n      if (!getClientIdBytes().isEmpty()) {\n        com.google.protobuf.GeneratedMessageV3.writeString(output, 2, clientId_);\n      }\n      if (!getFilterBytes().isEmpty()) {\n        com.google.protobuf.GeneratedMessageV3.writeString(output, 7, filter_);\n      }\n      unknownFields.writeTo(output);\n    }\n\n    @java.lang.Override\n    public int getSerializedSize() {\n      int size = memoizedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (!getDestinationBytes().isEmpty()) {\n        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, destination_);\n      }\n      if (!getClientIdBytes().isEmpty()) {\n        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, clientId_);\n      }\n      if (!getFilterBytes().isEmpty()) {\n        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(7, filter_);\n      }\n      size += unknownFields.getSerializedSize();\n      memoizedSize = size;\n      return size;\n    }\n\n    @java.lang.Override\n    public boolean equals(final java.lang.Object obj) {\n      if (obj == this) {\n       return true;\n      }\n      if (!(obj instanceof com.alibaba.otter.canal.protocol.CanalPacket.Unsub)) {\n        return super.equals(obj);\n      }\n      com.alibaba.otter.canal.protocol.CanalPacket.Unsub other = (com.alibaba.otter.canal.protocol.CanalPacket.Unsub) obj;\n\n      boolean result = true;\n      result = result && getDestination()\n          .equals(other.getDestination());\n      result = result && getClientId()\n          .equals(other.getClientId());\n      result = result && getFilter()\n          .equals(other.getFilter());\n      result = result && unknownFields.equals(other.unknownFields);\n      return result;\n    }\n\n    @java.lang.Override\n    public int hashCode() {\n      if (memoizedHashCode != 0) {\n        return memoizedHashCode;\n      }\n      int hash = 41;\n      hash = (19 * hash) + getDescriptor().hashCode();\n      hash = (37 * hash) + DESTINATION_FIELD_NUMBER;\n      hash = (53 * hash) + getDestination().hashCode();\n      hash = (37 * hash) + CLIENT_ID_FIELD_NUMBER;\n      hash = (53 * hash) + getClientId().hashCode();\n      hash = (37 * hash) + FILTER_FIELD_NUMBER;\n      hash = (53 * hash) + getFilter().hashCode();\n      hash = (29 * hash) + unknownFields.hashCode();\n      memoizedHashCode = hash;\n      return hash;\n    }\n\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Unsub parseFrom(\n        java.nio.ByteBuffer data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Unsub parseFrom(\n        java.nio.ByteBuffer data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Unsub parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Unsub parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Unsub parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Unsub parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Unsub parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Unsub parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Unsub parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Unsub parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Unsub parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Unsub parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    @java.lang.Override\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder() {\n      return DEFAULT_INSTANCE.toBuilder();\n    }\n    public static Builder newBuilder(com.alibaba.otter.canal.protocol.CanalPacket.Unsub prototype) {\n      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n    }\n    @java.lang.Override\n    public Builder toBuilder() {\n      return this == DEFAULT_INSTANCE\n          ? new Builder() : new Builder().mergeFrom(this);\n    }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * <pre>\n     * Unsubscription\n     * </pre>\n     *\n     * Protobuf type {@code com.alibaba.otter.canal.protocol.Unsub}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.Unsub)\n        com.alibaba.otter.canal.protocol.CanalPacket.UnsubOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Unsub_descriptor;\n      }\n\n      @java.lang.Override\n      protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Unsub_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                com.alibaba.otter.canal.protocol.CanalPacket.Unsub.class, com.alibaba.otter.canal.protocol.CanalPacket.Unsub.Builder.class);\n      }\n\n      // Construct using com.alibaba.otter.canal.protocol.CanalPacket.Unsub.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessageV3\n                .alwaysUseFieldBuilders) {\n        }\n      }\n      @java.lang.Override\n      public Builder clear() {\n        super.clear();\n        destination_ = \"\";\n\n        clientId_ = \"\";\n\n        filter_ = \"\";\n\n        return this;\n      }\n\n      @java.lang.Override\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Unsub_descriptor;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.Unsub getDefaultInstanceForType() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.Unsub.getDefaultInstance();\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.Unsub build() {\n        com.alibaba.otter.canal.protocol.CanalPacket.Unsub result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.Unsub buildPartial() {\n        com.alibaba.otter.canal.protocol.CanalPacket.Unsub result = new com.alibaba.otter.canal.protocol.CanalPacket.Unsub(this);\n        result.destination_ = destination_;\n        result.clientId_ = clientId_;\n        result.filter_ = filter_;\n        onBuilt();\n        return result;\n      }\n\n      @java.lang.Override\n      public Builder clone() {\n        return (Builder) super.clone();\n      }\n      @java.lang.Override\n      public Builder setField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.setField(field, value);\n      }\n      @java.lang.Override\n      public Builder clearField(\n          com.google.protobuf.Descriptors.FieldDescriptor field) {\n        return (Builder) super.clearField(field);\n      }\n      @java.lang.Override\n      public Builder clearOneof(\n          com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n        return (Builder) super.clearOneof(oneof);\n      }\n      @java.lang.Override\n      public Builder setRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          int index, java.lang.Object value) {\n        return (Builder) super.setRepeatedField(field, index, value);\n      }\n      @java.lang.Override\n      public Builder addRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.addRepeatedField(field, value);\n      }\n      @java.lang.Override\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof com.alibaba.otter.canal.protocol.CanalPacket.Unsub) {\n          return mergeFrom((com.alibaba.otter.canal.protocol.CanalPacket.Unsub)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(com.alibaba.otter.canal.protocol.CanalPacket.Unsub other) {\n        if (other == com.alibaba.otter.canal.protocol.CanalPacket.Unsub.getDefaultInstance()) return this;\n        if (!other.getDestination().isEmpty()) {\n          destination_ = other.destination_;\n          onChanged();\n        }\n        if (!other.getClientId().isEmpty()) {\n          clientId_ = other.clientId_;\n          onChanged();\n        }\n        if (!other.getFilter().isEmpty()) {\n          filter_ = other.filter_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.unknownFields);\n        onChanged();\n        return this;\n      }\n\n      @java.lang.Override\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      @java.lang.Override\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        com.alibaba.otter.canal.protocol.CanalPacket.Unsub parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (com.alibaba.otter.canal.protocol.CanalPacket.Unsub) e.getUnfinishedMessage();\n          throw e.unwrapIOException();\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n\n      private java.lang.Object destination_ = \"\";\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public java.lang.String getDestination() {\n        java.lang.Object ref = destination_;\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          destination_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getDestinationBytes() {\n        java.lang.Object ref = destination_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          destination_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public Builder setDestination(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        destination_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public Builder clearDestination() {\n        \n        destination_ = getDefaultInstance().getDestination();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public Builder setDestinationBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  checkByteStringIsUtf8(value);\n        \n        destination_ = value;\n        onChanged();\n        return this;\n      }\n\n      private java.lang.Object clientId_ = \"\";\n      /**\n       * <code>string client_id = 2;</code>\n       */\n      public java.lang.String getClientId() {\n        java.lang.Object ref = clientId_;\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          clientId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>string client_id = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getClientIdBytes() {\n        java.lang.Object ref = clientId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          clientId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>string client_id = 2;</code>\n       */\n      public Builder setClientId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        clientId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string client_id = 2;</code>\n       */\n      public Builder clearClientId() {\n        \n        clientId_ = getDefaultInstance().getClientId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string client_id = 2;</code>\n       */\n      public Builder setClientIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  checkByteStringIsUtf8(value);\n        \n        clientId_ = value;\n        onChanged();\n        return this;\n      }\n\n      private java.lang.Object filter_ = \"\";\n      /**\n       * <code>string filter = 7;</code>\n       */\n      public java.lang.String getFilter() {\n        java.lang.Object ref = filter_;\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          filter_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>string filter = 7;</code>\n       */\n      public com.google.protobuf.ByteString\n          getFilterBytes() {\n        java.lang.Object ref = filter_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          filter_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>string filter = 7;</code>\n       */\n      public Builder setFilter(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        filter_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string filter = 7;</code>\n       */\n      public Builder clearFilter() {\n        \n        filter_ = getDefaultInstance().getFilter();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string filter = 7;</code>\n       */\n      public Builder setFilterBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  checkByteStringIsUtf8(value);\n        \n        filter_ = value;\n        onChanged();\n        return this;\n      }\n      @java.lang.Override\n      public final Builder setUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.setUnknownFieldsProto3(unknownFields);\n      }\n\n      @java.lang.Override\n      public final Builder mergeUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.mergeUnknownFields(unknownFields);\n      }\n\n\n      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.Unsub)\n    }\n\n    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.Unsub)\n    private static final com.alibaba.otter.canal.protocol.CanalPacket.Unsub DEFAULT_INSTANCE;\n    static {\n      DEFAULT_INSTANCE = new com.alibaba.otter.canal.protocol.CanalPacket.Unsub();\n    }\n\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Unsub getDefaultInstance() {\n      return DEFAULT_INSTANCE;\n    }\n\n    private static final com.google.protobuf.Parser<Unsub>\n        PARSER = new com.google.protobuf.AbstractParser<Unsub>() {\n      @java.lang.Override\n      public Unsub parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new Unsub(input, extensionRegistry);\n      }\n    };\n\n    public static com.google.protobuf.Parser<Unsub> parser() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<Unsub> getParserForType() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.alibaba.otter.canal.protocol.CanalPacket.Unsub getDefaultInstanceForType() {\n      return DEFAULT_INSTANCE;\n    }\n\n  }\n\n  public interface GetOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.Get)\n      com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <code>string destination = 1;</code>\n     */\n    java.lang.String getDestination();\n    /**\n     * <code>string destination = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getDestinationBytes();\n\n    /**\n     * <code>string client_id = 2;</code>\n     */\n    java.lang.String getClientId();\n    /**\n     * <code>string client_id = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getClientIdBytes();\n\n    /**\n     * <code>int32 fetch_size = 3;</code>\n     */\n    int getFetchSize();\n\n    /**\n     * <pre>\n     * 默认-1时代表不控制\n     * </pre>\n     *\n     * <code>int64 timeout = 4;</code>\n     */\n    long getTimeout();\n\n    /**\n     * <pre>\n     * 数字类型，0:纳秒,1:毫秒,2:微秒,3:秒,4:分钟,5:小时,6:天\n     * </pre>\n     *\n     * <code>int32 unit = 5;</code>\n     */\n    int getUnit();\n\n    /**\n     * <pre>\n     * 是否自动ack\n     * </pre>\n     *\n     * <code>bool auto_ack = 6;</code>\n     */\n    boolean getAutoAck();\n\n    public com.alibaba.otter.canal.protocol.CanalPacket.Get.TimeoutPresentCase getTimeoutPresentCase();\n\n    public com.alibaba.otter.canal.protocol.CanalPacket.Get.UnitPresentCase getUnitPresentCase();\n\n    public com.alibaba.otter.canal.protocol.CanalPacket.Get.AutoAckPresentCase getAutoAckPresentCase();\n  }\n  /**\n   * <pre>\n   *  PullRequest\n   * </pre>\n   *\n   * Protobuf type {@code com.alibaba.otter.canal.protocol.Get}\n   */\n  public  static final class Get extends\n      com.google.protobuf.GeneratedMessageV3 implements\n      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.Get)\n      GetOrBuilder {\n  private static final long serialVersionUID = 0L;\n    // Use Get.newBuilder() to construct.\n    private Get(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {\n      super(builder);\n    }\n    private Get() {\n      destination_ = \"\";\n      clientId_ = \"\";\n      fetchSize_ = 0;\n    }\n\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n    getUnknownFields() {\n      return this.unknownFields;\n    }\n    private Get(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      this();\n      if (extensionRegistry == null) {\n        throw new java.lang.NullPointerException();\n      }\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            case 10: {\n              java.lang.String s = input.readStringRequireUtf8();\n\n              destination_ = s;\n              break;\n            }\n            case 18: {\n              java.lang.String s = input.readStringRequireUtf8();\n\n              clientId_ = s;\n              break;\n            }\n            case 24: {\n\n              fetchSize_ = input.readInt32();\n              break;\n            }\n            case 32: {\n              timeoutPresentCase_ = 4;\n              timeoutPresent_ = input.readInt64();\n              break;\n            }\n            case 40: {\n              unitPresentCase_ = 5;\n              unitPresent_ = input.readInt32();\n              break;\n            }\n            case 48: {\n              autoAckPresentCase_ = 6;\n              autoAckPresent_ = input.readBool();\n              break;\n            }\n            default: {\n              if (!parseUnknownFieldProto3(\n                  input, unknownFields, extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Get_descriptor;\n    }\n\n    @java.lang.Override\n    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Get_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              com.alibaba.otter.canal.protocol.CanalPacket.Get.class, com.alibaba.otter.canal.protocol.CanalPacket.Get.Builder.class);\n    }\n\n    private int timeoutPresentCase_ = 0;\n    private java.lang.Object timeoutPresent_;\n    public enum TimeoutPresentCase\n        implements com.google.protobuf.Internal.EnumLite {\n      TIMEOUT(4),\n      TIMEOUTPRESENT_NOT_SET(0);\n      private final int value;\n      private TimeoutPresentCase(int value) {\n        this.value = value;\n      }\n      /**\n       * @deprecated Use {@link #forNumber(int)} instead.\n       */\n      @java.lang.Deprecated\n      public static TimeoutPresentCase valueOf(int value) {\n        return forNumber(value);\n      }\n\n      public static TimeoutPresentCase forNumber(int value) {\n        switch (value) {\n          case 4: return TIMEOUT;\n          case 0: return TIMEOUTPRESENT_NOT_SET;\n          default: return null;\n        }\n      }\n      public int getNumber() {\n        return this.value;\n      }\n    };\n\n    public TimeoutPresentCase\n    getTimeoutPresentCase() {\n      return TimeoutPresentCase.forNumber(\n          timeoutPresentCase_);\n    }\n\n    private int unitPresentCase_ = 0;\n    private java.lang.Object unitPresent_;\n    public enum UnitPresentCase\n        implements com.google.protobuf.Internal.EnumLite {\n      UNIT(5),\n      UNITPRESENT_NOT_SET(0);\n      private final int value;\n      private UnitPresentCase(int value) {\n        this.value = value;\n      }\n      /**\n       * @deprecated Use {@link #forNumber(int)} instead.\n       */\n      @java.lang.Deprecated\n      public static UnitPresentCase valueOf(int value) {\n        return forNumber(value);\n      }\n\n      public static UnitPresentCase forNumber(int value) {\n        switch (value) {\n          case 5: return UNIT;\n          case 0: return UNITPRESENT_NOT_SET;\n          default: return null;\n        }\n      }\n      public int getNumber() {\n        return this.value;\n      }\n    };\n\n    public UnitPresentCase\n    getUnitPresentCase() {\n      return UnitPresentCase.forNumber(\n          unitPresentCase_);\n    }\n\n    private int autoAckPresentCase_ = 0;\n    private java.lang.Object autoAckPresent_;\n    public enum AutoAckPresentCase\n        implements com.google.protobuf.Internal.EnumLite {\n      AUTO_ACK(6),\n      AUTOACKPRESENT_NOT_SET(0);\n      private final int value;\n      private AutoAckPresentCase(int value) {\n        this.value = value;\n      }\n      /**\n       * @deprecated Use {@link #forNumber(int)} instead.\n       */\n      @java.lang.Deprecated\n      public static AutoAckPresentCase valueOf(int value) {\n        return forNumber(value);\n      }\n\n      public static AutoAckPresentCase forNumber(int value) {\n        switch (value) {\n          case 6: return AUTO_ACK;\n          case 0: return AUTOACKPRESENT_NOT_SET;\n          default: return null;\n        }\n      }\n      public int getNumber() {\n        return this.value;\n      }\n    };\n\n    public AutoAckPresentCase\n    getAutoAckPresentCase() {\n      return AutoAckPresentCase.forNumber(\n          autoAckPresentCase_);\n    }\n\n    public static final int DESTINATION_FIELD_NUMBER = 1;\n    private volatile java.lang.Object destination_;\n    /**\n     * <code>string destination = 1;</code>\n     */\n    public java.lang.String getDestination() {\n      java.lang.Object ref = destination_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        destination_ = s;\n        return s;\n      }\n    }\n    /**\n     * <code>string destination = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getDestinationBytes() {\n      java.lang.Object ref = destination_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        destination_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int CLIENT_ID_FIELD_NUMBER = 2;\n    private volatile java.lang.Object clientId_;\n    /**\n     * <code>string client_id = 2;</code>\n     */\n    public java.lang.String getClientId() {\n      java.lang.Object ref = clientId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        clientId_ = s;\n        return s;\n      }\n    }\n    /**\n     * <code>string client_id = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getClientIdBytes() {\n      java.lang.Object ref = clientId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        clientId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int FETCH_SIZE_FIELD_NUMBER = 3;\n    private int fetchSize_;\n    /**\n     * <code>int32 fetch_size = 3;</code>\n     */\n    public int getFetchSize() {\n      return fetchSize_;\n    }\n\n    public static final int TIMEOUT_FIELD_NUMBER = 4;\n    /**\n     * <pre>\n     * 默认-1时代表不控制\n     * </pre>\n     *\n     * <code>int64 timeout = 4;</code>\n     */\n    public long getTimeout() {\n      if (timeoutPresentCase_ == 4) {\n        return (java.lang.Long) timeoutPresent_;\n      }\n      return 0L;\n    }\n\n    public static final int UNIT_FIELD_NUMBER = 5;\n    /**\n     * <pre>\n     * 数字类型，0:纳秒,1:毫秒,2:微秒,3:秒,4:分钟,5:小时,6:天\n     * </pre>\n     *\n     * <code>int32 unit = 5;</code>\n     */\n    public int getUnit() {\n      if (unitPresentCase_ == 5) {\n        return (java.lang.Integer) unitPresent_;\n      }\n      return 0;\n    }\n\n    public static final int AUTO_ACK_FIELD_NUMBER = 6;\n    /**\n     * <pre>\n     * 是否自动ack\n     * </pre>\n     *\n     * <code>bool auto_ack = 6;</code>\n     */\n    public boolean getAutoAck() {\n      if (autoAckPresentCase_ == 6) {\n        return (java.lang.Boolean) autoAckPresent_;\n      }\n      return false;\n    }\n\n    private byte memoizedIsInitialized = -1;\n    @java.lang.Override\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    @java.lang.Override\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      if (!getDestinationBytes().isEmpty()) {\n        com.google.protobuf.GeneratedMessageV3.writeString(output, 1, destination_);\n      }\n      if (!getClientIdBytes().isEmpty()) {\n        com.google.protobuf.GeneratedMessageV3.writeString(output, 2, clientId_);\n      }\n      if (fetchSize_ != 0) {\n        output.writeInt32(3, fetchSize_);\n      }\n      if (timeoutPresentCase_ == 4) {\n        output.writeInt64(\n            4, (long)((java.lang.Long) timeoutPresent_));\n      }\n      if (unitPresentCase_ == 5) {\n        output.writeInt32(\n            5, (int)((java.lang.Integer) unitPresent_));\n      }\n      if (autoAckPresentCase_ == 6) {\n        output.writeBool(\n            6, (boolean)((java.lang.Boolean) autoAckPresent_));\n      }\n      unknownFields.writeTo(output);\n    }\n\n    @java.lang.Override\n    public int getSerializedSize() {\n      int size = memoizedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (!getDestinationBytes().isEmpty()) {\n        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, destination_);\n      }\n      if (!getClientIdBytes().isEmpty()) {\n        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, clientId_);\n      }\n      if (fetchSize_ != 0) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(3, fetchSize_);\n      }\n      if (timeoutPresentCase_ == 4) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(\n              4, (long)((java.lang.Long) timeoutPresent_));\n      }\n      if (unitPresentCase_ == 5) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(\n              5, (int)((java.lang.Integer) unitPresent_));\n      }\n      if (autoAckPresentCase_ == 6) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBoolSize(\n              6, (boolean)((java.lang.Boolean) autoAckPresent_));\n      }\n      size += unknownFields.getSerializedSize();\n      memoizedSize = size;\n      return size;\n    }\n\n    @java.lang.Override\n    public boolean equals(final java.lang.Object obj) {\n      if (obj == this) {\n       return true;\n      }\n      if (!(obj instanceof com.alibaba.otter.canal.protocol.CanalPacket.Get)) {\n        return super.equals(obj);\n      }\n      com.alibaba.otter.canal.protocol.CanalPacket.Get other = (com.alibaba.otter.canal.protocol.CanalPacket.Get) obj;\n\n      boolean result = true;\n      result = result && getDestination()\n          .equals(other.getDestination());\n      result = result && getClientId()\n          .equals(other.getClientId());\n      result = result && (getFetchSize()\n          == other.getFetchSize());\n      result = result && getTimeoutPresentCase().equals(\n          other.getTimeoutPresentCase());\n      if (!result) return false;\n      switch (timeoutPresentCase_) {\n        case 4:\n          result = result && (getTimeout()\n              == other.getTimeout());\n          break;\n        case 0:\n        default:\n      }\n      result = result && getUnitPresentCase().equals(\n          other.getUnitPresentCase());\n      if (!result) return false;\n      switch (unitPresentCase_) {\n        case 5:\n          result = result && (getUnit()\n              == other.getUnit());\n          break;\n        case 0:\n        default:\n      }\n      result = result && getAutoAckPresentCase().equals(\n          other.getAutoAckPresentCase());\n      if (!result) return false;\n      switch (autoAckPresentCase_) {\n        case 6:\n          result = result && (getAutoAck()\n              == other.getAutoAck());\n          break;\n        case 0:\n        default:\n      }\n      result = result && unknownFields.equals(other.unknownFields);\n      return result;\n    }\n\n    @java.lang.Override\n    public int hashCode() {\n      if (memoizedHashCode != 0) {\n        return memoizedHashCode;\n      }\n      int hash = 41;\n      hash = (19 * hash) + getDescriptor().hashCode();\n      hash = (37 * hash) + DESTINATION_FIELD_NUMBER;\n      hash = (53 * hash) + getDestination().hashCode();\n      hash = (37 * hash) + CLIENT_ID_FIELD_NUMBER;\n      hash = (53 * hash) + getClientId().hashCode();\n      hash = (37 * hash) + FETCH_SIZE_FIELD_NUMBER;\n      hash = (53 * hash) + getFetchSize();\n      switch (timeoutPresentCase_) {\n        case 4:\n          hash = (37 * hash) + TIMEOUT_FIELD_NUMBER;\n          hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n              getTimeout());\n          break;\n        case 0:\n        default:\n      }\n      switch (unitPresentCase_) {\n        case 5:\n          hash = (37 * hash) + UNIT_FIELD_NUMBER;\n          hash = (53 * hash) + getUnit();\n          break;\n        case 0:\n        default:\n      }\n      switch (autoAckPresentCase_) {\n        case 6:\n          hash = (37 * hash) + AUTO_ACK_FIELD_NUMBER;\n          hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean(\n              getAutoAck());\n          break;\n        case 0:\n        default:\n      }\n      hash = (29 * hash) + unknownFields.hashCode();\n      memoizedHashCode = hash;\n      return hash;\n    }\n\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Get parseFrom(\n        java.nio.ByteBuffer data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Get parseFrom(\n        java.nio.ByteBuffer data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Get parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Get parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Get parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Get parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Get parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Get parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Get parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Get parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Get parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Get parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    @java.lang.Override\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder() {\n      return DEFAULT_INSTANCE.toBuilder();\n    }\n    public static Builder newBuilder(com.alibaba.otter.canal.protocol.CanalPacket.Get prototype) {\n      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n    }\n    @java.lang.Override\n    public Builder toBuilder() {\n      return this == DEFAULT_INSTANCE\n          ? new Builder() : new Builder().mergeFrom(this);\n    }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * <pre>\n     *  PullRequest\n     * </pre>\n     *\n     * Protobuf type {@code com.alibaba.otter.canal.protocol.Get}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.Get)\n        com.alibaba.otter.canal.protocol.CanalPacket.GetOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Get_descriptor;\n      }\n\n      @java.lang.Override\n      protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Get_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                com.alibaba.otter.canal.protocol.CanalPacket.Get.class, com.alibaba.otter.canal.protocol.CanalPacket.Get.Builder.class);\n      }\n\n      // Construct using com.alibaba.otter.canal.protocol.CanalPacket.Get.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessageV3\n                .alwaysUseFieldBuilders) {\n        }\n      }\n      @java.lang.Override\n      public Builder clear() {\n        super.clear();\n        destination_ = \"\";\n\n        clientId_ = \"\";\n\n        fetchSize_ = 0;\n\n        timeoutPresentCase_ = 0;\n        timeoutPresent_ = null;\n        unitPresentCase_ = 0;\n        unitPresent_ = null;\n        autoAckPresentCase_ = 0;\n        autoAckPresent_ = null;\n        return this;\n      }\n\n      @java.lang.Override\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Get_descriptor;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.Get getDefaultInstanceForType() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.Get.getDefaultInstance();\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.Get build() {\n        com.alibaba.otter.canal.protocol.CanalPacket.Get result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.Get buildPartial() {\n        com.alibaba.otter.canal.protocol.CanalPacket.Get result = new com.alibaba.otter.canal.protocol.CanalPacket.Get(this);\n        result.destination_ = destination_;\n        result.clientId_ = clientId_;\n        result.fetchSize_ = fetchSize_;\n        if (timeoutPresentCase_ == 4) {\n          result.timeoutPresent_ = timeoutPresent_;\n        }\n        if (unitPresentCase_ == 5) {\n          result.unitPresent_ = unitPresent_;\n        }\n        if (autoAckPresentCase_ == 6) {\n          result.autoAckPresent_ = autoAckPresent_;\n        }\n        result.timeoutPresentCase_ = timeoutPresentCase_;\n        result.unitPresentCase_ = unitPresentCase_;\n        result.autoAckPresentCase_ = autoAckPresentCase_;\n        onBuilt();\n        return result;\n      }\n\n      @java.lang.Override\n      public Builder clone() {\n        return (Builder) super.clone();\n      }\n      @java.lang.Override\n      public Builder setField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.setField(field, value);\n      }\n      @java.lang.Override\n      public Builder clearField(\n          com.google.protobuf.Descriptors.FieldDescriptor field) {\n        return (Builder) super.clearField(field);\n      }\n      @java.lang.Override\n      public Builder clearOneof(\n          com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n        return (Builder) super.clearOneof(oneof);\n      }\n      @java.lang.Override\n      public Builder setRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          int index, java.lang.Object value) {\n        return (Builder) super.setRepeatedField(field, index, value);\n      }\n      @java.lang.Override\n      public Builder addRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.addRepeatedField(field, value);\n      }\n      @java.lang.Override\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof com.alibaba.otter.canal.protocol.CanalPacket.Get) {\n          return mergeFrom((com.alibaba.otter.canal.protocol.CanalPacket.Get)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(com.alibaba.otter.canal.protocol.CanalPacket.Get other) {\n        if (other == com.alibaba.otter.canal.protocol.CanalPacket.Get.getDefaultInstance()) return this;\n        if (!other.getDestination().isEmpty()) {\n          destination_ = other.destination_;\n          onChanged();\n        }\n        if (!other.getClientId().isEmpty()) {\n          clientId_ = other.clientId_;\n          onChanged();\n        }\n        if (other.getFetchSize() != 0) {\n          setFetchSize(other.getFetchSize());\n        }\n        switch (other.getTimeoutPresentCase()) {\n          case TIMEOUT: {\n            setTimeout(other.getTimeout());\n            break;\n          }\n          case TIMEOUTPRESENT_NOT_SET: {\n            break;\n          }\n        }\n        switch (other.getUnitPresentCase()) {\n          case UNIT: {\n            setUnit(other.getUnit());\n            break;\n          }\n          case UNITPRESENT_NOT_SET: {\n            break;\n          }\n        }\n        switch (other.getAutoAckPresentCase()) {\n          case AUTO_ACK: {\n            setAutoAck(other.getAutoAck());\n            break;\n          }\n          case AUTOACKPRESENT_NOT_SET: {\n            break;\n          }\n        }\n        this.mergeUnknownFields(other.unknownFields);\n        onChanged();\n        return this;\n      }\n\n      @java.lang.Override\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      @java.lang.Override\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        com.alibaba.otter.canal.protocol.CanalPacket.Get parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (com.alibaba.otter.canal.protocol.CanalPacket.Get) e.getUnfinishedMessage();\n          throw e.unwrapIOException();\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int timeoutPresentCase_ = 0;\n      private java.lang.Object timeoutPresent_;\n      public TimeoutPresentCase\n          getTimeoutPresentCase() {\n        return TimeoutPresentCase.forNumber(\n            timeoutPresentCase_);\n      }\n\n      public Builder clearTimeoutPresent() {\n        timeoutPresentCase_ = 0;\n        timeoutPresent_ = null;\n        onChanged();\n        return this;\n      }\n\n      private int unitPresentCase_ = 0;\n      private java.lang.Object unitPresent_;\n      public UnitPresentCase\n          getUnitPresentCase() {\n        return UnitPresentCase.forNumber(\n            unitPresentCase_);\n      }\n\n      public Builder clearUnitPresent() {\n        unitPresentCase_ = 0;\n        unitPresent_ = null;\n        onChanged();\n        return this;\n      }\n\n      private int autoAckPresentCase_ = 0;\n      private java.lang.Object autoAckPresent_;\n      public AutoAckPresentCase\n          getAutoAckPresentCase() {\n        return AutoAckPresentCase.forNumber(\n            autoAckPresentCase_);\n      }\n\n      public Builder clearAutoAckPresent() {\n        autoAckPresentCase_ = 0;\n        autoAckPresent_ = null;\n        onChanged();\n        return this;\n      }\n\n\n      private java.lang.Object destination_ = \"\";\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public java.lang.String getDestination() {\n        java.lang.Object ref = destination_;\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          destination_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getDestinationBytes() {\n        java.lang.Object ref = destination_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          destination_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public Builder setDestination(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        destination_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public Builder clearDestination() {\n        \n        destination_ = getDefaultInstance().getDestination();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public Builder setDestinationBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  checkByteStringIsUtf8(value);\n        \n        destination_ = value;\n        onChanged();\n        return this;\n      }\n\n      private java.lang.Object clientId_ = \"\";\n      /**\n       * <code>string client_id = 2;</code>\n       */\n      public java.lang.String getClientId() {\n        java.lang.Object ref = clientId_;\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          clientId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>string client_id = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getClientIdBytes() {\n        java.lang.Object ref = clientId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          clientId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>string client_id = 2;</code>\n       */\n      public Builder setClientId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        clientId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string client_id = 2;</code>\n       */\n      public Builder clearClientId() {\n        \n        clientId_ = getDefaultInstance().getClientId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string client_id = 2;</code>\n       */\n      public Builder setClientIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  checkByteStringIsUtf8(value);\n        \n        clientId_ = value;\n        onChanged();\n        return this;\n      }\n\n      private int fetchSize_ ;\n      /**\n       * <code>int32 fetch_size = 3;</code>\n       */\n      public int getFetchSize() {\n        return fetchSize_;\n      }\n      /**\n       * <code>int32 fetch_size = 3;</code>\n       */\n      public Builder setFetchSize(int value) {\n        \n        fetchSize_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>int32 fetch_size = 3;</code>\n       */\n      public Builder clearFetchSize() {\n        \n        fetchSize_ = 0;\n        onChanged();\n        return this;\n      }\n\n      /**\n       * <pre>\n       * 默认-1时代表不控制\n       * </pre>\n       *\n       * <code>int64 timeout = 4;</code>\n       */\n      public long getTimeout() {\n        if (timeoutPresentCase_ == 4) {\n          return (java.lang.Long) timeoutPresent_;\n        }\n        return 0L;\n      }\n      /**\n       * <pre>\n       * 默认-1时代表不控制\n       * </pre>\n       *\n       * <code>int64 timeout = 4;</code>\n       */\n      public Builder setTimeout(long value) {\n        timeoutPresentCase_ = 4;\n        timeoutPresent_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <pre>\n       * 默认-1时代表不控制\n       * </pre>\n       *\n       * <code>int64 timeout = 4;</code>\n       */\n      public Builder clearTimeout() {\n        if (timeoutPresentCase_ == 4) {\n          timeoutPresentCase_ = 0;\n          timeoutPresent_ = null;\n          onChanged();\n        }\n        return this;\n      }\n\n      /**\n       * <pre>\n       * 数字类型，0:纳秒,1:毫秒,2:微秒,3:秒,4:分钟,5:小时,6:天\n       * </pre>\n       *\n       * <code>int32 unit = 5;</code>\n       */\n      public int getUnit() {\n        if (unitPresentCase_ == 5) {\n          return (java.lang.Integer) unitPresent_;\n        }\n        return 0;\n      }\n      /**\n       * <pre>\n       * 数字类型，0:纳秒,1:毫秒,2:微秒,3:秒,4:分钟,5:小时,6:天\n       * </pre>\n       *\n       * <code>int32 unit = 5;</code>\n       */\n      public Builder setUnit(int value) {\n        unitPresentCase_ = 5;\n        unitPresent_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <pre>\n       * 数字类型，0:纳秒,1:毫秒,2:微秒,3:秒,4:分钟,5:小时,6:天\n       * </pre>\n       *\n       * <code>int32 unit = 5;</code>\n       */\n      public Builder clearUnit() {\n        if (unitPresentCase_ == 5) {\n          unitPresentCase_ = 0;\n          unitPresent_ = null;\n          onChanged();\n        }\n        return this;\n      }\n\n      /**\n       * <pre>\n       * 是否自动ack\n       * </pre>\n       *\n       * <code>bool auto_ack = 6;</code>\n       */\n      public boolean getAutoAck() {\n        if (autoAckPresentCase_ == 6) {\n          return (java.lang.Boolean) autoAckPresent_;\n        }\n        return false;\n      }\n      /**\n       * <pre>\n       * 是否自动ack\n       * </pre>\n       *\n       * <code>bool auto_ack = 6;</code>\n       */\n      public Builder setAutoAck(boolean value) {\n        autoAckPresentCase_ = 6;\n        autoAckPresent_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <pre>\n       * 是否自动ack\n       * </pre>\n       *\n       * <code>bool auto_ack = 6;</code>\n       */\n      public Builder clearAutoAck() {\n        if (autoAckPresentCase_ == 6) {\n          autoAckPresentCase_ = 0;\n          autoAckPresent_ = null;\n          onChanged();\n        }\n        return this;\n      }\n      @java.lang.Override\n      public final Builder setUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.setUnknownFieldsProto3(unknownFields);\n      }\n\n      @java.lang.Override\n      public final Builder mergeUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.mergeUnknownFields(unknownFields);\n      }\n\n\n      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.Get)\n    }\n\n    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.Get)\n    private static final com.alibaba.otter.canal.protocol.CanalPacket.Get DEFAULT_INSTANCE;\n    static {\n      DEFAULT_INSTANCE = new com.alibaba.otter.canal.protocol.CanalPacket.Get();\n    }\n\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Get getDefaultInstance() {\n      return DEFAULT_INSTANCE;\n    }\n\n    private static final com.google.protobuf.Parser<Get>\n        PARSER = new com.google.protobuf.AbstractParser<Get>() {\n      @java.lang.Override\n      public Get parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new Get(input, extensionRegistry);\n      }\n    };\n\n    public static com.google.protobuf.Parser<Get> parser() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<Get> getParserForType() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.alibaba.otter.canal.protocol.CanalPacket.Get getDefaultInstanceForType() {\n      return DEFAULT_INSTANCE;\n    }\n\n  }\n\n  public interface MessagesOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.Messages)\n      com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <code>int64 batch_id = 1;</code>\n     */\n    long getBatchId();\n\n    /**\n     * <code>repeated bytes messages = 2;</code>\n     */\n    java.util.List<com.google.protobuf.ByteString> getMessagesList();\n    /**\n     * <code>repeated bytes messages = 2;</code>\n     */\n    int getMessagesCount();\n    /**\n     * <code>repeated bytes messages = 2;</code>\n     */\n    com.google.protobuf.ByteString getMessages(int index);\n  }\n  /**\n   * <pre>\n   * </pre>\n   *\n   * Protobuf type {@code com.alibaba.otter.canal.protocol.Messages}\n   */\n  public  static final class Messages extends\n      com.google.protobuf.GeneratedMessageV3 implements\n      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.Messages)\n      MessagesOrBuilder {\n  private static final long serialVersionUID = 0L;\n    // Use Messages.newBuilder() to construct.\n    private Messages(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {\n      super(builder);\n    }\n    private Messages() {\n      batchId_ = 0L;\n      messages_ = java.util.Collections.emptyList();\n    }\n\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n    getUnknownFields() {\n      return this.unknownFields;\n    }\n    private Messages(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      this();\n      if (extensionRegistry == null) {\n        throw new java.lang.NullPointerException();\n      }\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            case 8: {\n\n              batchId_ = input.readInt64();\n              break;\n            }\n            case 18: {\n              if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) {\n                messages_ = new java.util.ArrayList<com.google.protobuf.ByteString>();\n                mutable_bitField0_ |= 0x00000002;\n              }\n              messages_.add(input.readBytes());\n              break;\n            }\n            default: {\n              if (!parseUnknownFieldProto3(\n                  input, unknownFields, extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) {\n          messages_ = java.util.Collections.unmodifiableList(messages_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Messages_descriptor;\n    }\n\n    @java.lang.Override\n    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Messages_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              com.alibaba.otter.canal.protocol.CanalPacket.Messages.class, com.alibaba.otter.canal.protocol.CanalPacket.Messages.Builder.class);\n    }\n\n    private int bitField0_;\n    public static final int BATCH_ID_FIELD_NUMBER = 1;\n    private long batchId_;\n    /**\n     * <code>int64 batch_id = 1;</code>\n     */\n    public long getBatchId() {\n      return batchId_;\n    }\n\n    public static final int MESSAGES_FIELD_NUMBER = 2;\n    private java.util.List<com.google.protobuf.ByteString> messages_;\n    /**\n     * <code>repeated bytes messages = 2;</code>\n     */\n    public java.util.List<com.google.protobuf.ByteString>\n        getMessagesList() {\n      return messages_;\n    }\n    /**\n     * <code>repeated bytes messages = 2;</code>\n     */\n    public int getMessagesCount() {\n      return messages_.size();\n    }\n    /**\n     * <code>repeated bytes messages = 2;</code>\n     */\n    public com.google.protobuf.ByteString getMessages(int index) {\n      return messages_.get(index);\n    }\n\n    private byte memoizedIsInitialized = -1;\n    @java.lang.Override\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    @java.lang.Override\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      if (batchId_ != 0L) {\n        output.writeInt64(1, batchId_);\n      }\n      for (int i = 0; i < messages_.size(); i++) {\n        output.writeBytes(2, messages_.get(i));\n      }\n      unknownFields.writeTo(output);\n    }\n\n    @java.lang.Override\n    public int getSerializedSize() {\n      int size = memoizedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (batchId_ != 0L) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(1, batchId_);\n      }\n      {\n        int dataSize = 0;\n        for (int i = 0; i < messages_.size(); i++) {\n          dataSize += com.google.protobuf.CodedOutputStream\n            .computeBytesSizeNoTag(messages_.get(i));\n        }\n        size += dataSize;\n        size += 1 * getMessagesList().size();\n      }\n      size += unknownFields.getSerializedSize();\n      memoizedSize = size;\n      return size;\n    }\n\n    @java.lang.Override\n    public boolean equals(final java.lang.Object obj) {\n      if (obj == this) {\n       return true;\n      }\n      if (!(obj instanceof com.alibaba.otter.canal.protocol.CanalPacket.Messages)) {\n        return super.equals(obj);\n      }\n      com.alibaba.otter.canal.protocol.CanalPacket.Messages other = (com.alibaba.otter.canal.protocol.CanalPacket.Messages) obj;\n\n      boolean result = true;\n      result = result && (getBatchId()\n          == other.getBatchId());\n      result = result && getMessagesList()\n          .equals(other.getMessagesList());\n      result = result && unknownFields.equals(other.unknownFields);\n      return result;\n    }\n\n    @java.lang.Override\n    public int hashCode() {\n      if (memoizedHashCode != 0) {\n        return memoizedHashCode;\n      }\n      int hash = 41;\n      hash = (19 * hash) + getDescriptor().hashCode();\n      hash = (37 * hash) + BATCH_ID_FIELD_NUMBER;\n      hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n          getBatchId());\n      if (getMessagesCount() > 0) {\n        hash = (37 * hash) + MESSAGES_FIELD_NUMBER;\n        hash = (53 * hash) + getMessagesList().hashCode();\n      }\n      hash = (29 * hash) + unknownFields.hashCode();\n      memoizedHashCode = hash;\n      return hash;\n    }\n\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Messages parseFrom(\n        java.nio.ByteBuffer data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Messages parseFrom(\n        java.nio.ByteBuffer data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Messages parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Messages parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Messages parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Messages parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Messages parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Messages parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Messages parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Messages parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Messages parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Messages parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    @java.lang.Override\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder() {\n      return DEFAULT_INSTANCE.toBuilder();\n    }\n    public static Builder newBuilder(com.alibaba.otter.canal.protocol.CanalPacket.Messages prototype) {\n      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n    }\n    @java.lang.Override\n    public Builder toBuilder() {\n      return this == DEFAULT_INSTANCE\n          ? new Builder() : new Builder().mergeFrom(this);\n    }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * <pre>\n     * </pre>\n     *\n     * Protobuf type {@code com.alibaba.otter.canal.protocol.Messages}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.Messages)\n        com.alibaba.otter.canal.protocol.CanalPacket.MessagesOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Messages_descriptor;\n      }\n\n      @java.lang.Override\n      protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Messages_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                com.alibaba.otter.canal.protocol.CanalPacket.Messages.class, com.alibaba.otter.canal.protocol.CanalPacket.Messages.Builder.class);\n      }\n\n      // Construct using com.alibaba.otter.canal.protocol.CanalPacket.Messages.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessageV3\n                .alwaysUseFieldBuilders) {\n        }\n      }\n      @java.lang.Override\n      public Builder clear() {\n        super.clear();\n        batchId_ = 0L;\n\n        messages_ = java.util.Collections.emptyList();\n        bitField0_ = (bitField0_ & ~0x00000002);\n        return this;\n      }\n\n      @java.lang.Override\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Messages_descriptor;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.Messages getDefaultInstanceForType() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.Messages.getDefaultInstance();\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.Messages build() {\n        com.alibaba.otter.canal.protocol.CanalPacket.Messages result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.Messages buildPartial() {\n        com.alibaba.otter.canal.protocol.CanalPacket.Messages result = new com.alibaba.otter.canal.protocol.CanalPacket.Messages(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        result.batchId_ = batchId_;\n        if (((bitField0_ & 0x00000002) == 0x00000002)) {\n          messages_ = java.util.Collections.unmodifiableList(messages_);\n          bitField0_ = (bitField0_ & ~0x00000002);\n        }\n        result.messages_ = messages_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      @java.lang.Override\n      public Builder clone() {\n        return (Builder) super.clone();\n      }\n      @java.lang.Override\n      public Builder setField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.setField(field, value);\n      }\n      @java.lang.Override\n      public Builder clearField(\n          com.google.protobuf.Descriptors.FieldDescriptor field) {\n        return (Builder) super.clearField(field);\n      }\n      @java.lang.Override\n      public Builder clearOneof(\n          com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n        return (Builder) super.clearOneof(oneof);\n      }\n      @java.lang.Override\n      public Builder setRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          int index, java.lang.Object value) {\n        return (Builder) super.setRepeatedField(field, index, value);\n      }\n      @java.lang.Override\n      public Builder addRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.addRepeatedField(field, value);\n      }\n      @java.lang.Override\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof com.alibaba.otter.canal.protocol.CanalPacket.Messages) {\n          return mergeFrom((com.alibaba.otter.canal.protocol.CanalPacket.Messages)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(com.alibaba.otter.canal.protocol.CanalPacket.Messages other) {\n        if (other == com.alibaba.otter.canal.protocol.CanalPacket.Messages.getDefaultInstance()) return this;\n        if (other.getBatchId() != 0L) {\n          setBatchId(other.getBatchId());\n        }\n        if (!other.messages_.isEmpty()) {\n          if (messages_.isEmpty()) {\n            messages_ = other.messages_;\n            bitField0_ = (bitField0_ & ~0x00000002);\n          } else {\n            ensureMessagesIsMutable();\n            messages_.addAll(other.messages_);\n          }\n          onChanged();\n        }\n        this.mergeUnknownFields(other.unknownFields);\n        onChanged();\n        return this;\n      }\n\n      @java.lang.Override\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      @java.lang.Override\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        com.alibaba.otter.canal.protocol.CanalPacket.Messages parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (com.alibaba.otter.canal.protocol.CanalPacket.Messages) e.getUnfinishedMessage();\n          throw e.unwrapIOException();\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      private long batchId_ ;\n      /**\n       * <code>int64 batch_id = 1;</code>\n       */\n      public long getBatchId() {\n        return batchId_;\n      }\n      /**\n       * <code>int64 batch_id = 1;</code>\n       */\n      public Builder setBatchId(long value) {\n        \n        batchId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>int64 batch_id = 1;</code>\n       */\n      public Builder clearBatchId() {\n        \n        batchId_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      private java.util.List<com.google.protobuf.ByteString> messages_ = java.util.Collections.emptyList();\n      private void ensureMessagesIsMutable() {\n        if (!((bitField0_ & 0x00000002) == 0x00000002)) {\n          messages_ = new java.util.ArrayList<com.google.protobuf.ByteString>(messages_);\n          bitField0_ |= 0x00000002;\n         }\n      }\n      /**\n       * <code>repeated bytes messages = 2;</code>\n       */\n      public java.util.List<com.google.protobuf.ByteString>\n          getMessagesList() {\n        return java.util.Collections.unmodifiableList(messages_);\n      }\n      /**\n       * <code>repeated bytes messages = 2;</code>\n       */\n      public int getMessagesCount() {\n        return messages_.size();\n      }\n      /**\n       * <code>repeated bytes messages = 2;</code>\n       */\n      public com.google.protobuf.ByteString getMessages(int index) {\n        return messages_.get(index);\n      }\n      /**\n       * <code>repeated bytes messages = 2;</code>\n       */\n      public Builder setMessages(\n          int index, com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  ensureMessagesIsMutable();\n        messages_.set(index, value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated bytes messages = 2;</code>\n       */\n      public Builder addMessages(com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  ensureMessagesIsMutable();\n        messages_.add(value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated bytes messages = 2;</code>\n       */\n      public Builder addAllMessages(\n          java.lang.Iterable<? extends com.google.protobuf.ByteString> values) {\n        ensureMessagesIsMutable();\n        com.google.protobuf.AbstractMessageLite.Builder.addAll(\n            values, messages_);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated bytes messages = 2;</code>\n       */\n      public Builder clearMessages() {\n        messages_ = java.util.Collections.emptyList();\n        bitField0_ = (bitField0_ & ~0x00000002);\n        onChanged();\n        return this;\n      }\n      @java.lang.Override\n      public final Builder setUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.setUnknownFieldsProto3(unknownFields);\n      }\n\n      @java.lang.Override\n      public final Builder mergeUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.mergeUnknownFields(unknownFields);\n      }\n\n\n      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.Messages)\n    }\n\n    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.Messages)\n    private static final com.alibaba.otter.canal.protocol.CanalPacket.Messages DEFAULT_INSTANCE;\n    static {\n      DEFAULT_INSTANCE = new com.alibaba.otter.canal.protocol.CanalPacket.Messages();\n    }\n\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Messages getDefaultInstance() {\n      return DEFAULT_INSTANCE;\n    }\n\n    private static final com.google.protobuf.Parser<Messages>\n        PARSER = new com.google.protobuf.AbstractParser<Messages>() {\n      @java.lang.Override\n      public Messages parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new Messages(input, extensionRegistry);\n      }\n    };\n\n    public static com.google.protobuf.Parser<Messages> parser() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<Messages> getParserForType() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.alibaba.otter.canal.protocol.CanalPacket.Messages getDefaultInstanceForType() {\n      return DEFAULT_INSTANCE;\n    }\n\n  }\n\n  public interface DumpOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.Dump)\n      com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <code>string journal = 1;</code>\n     */\n    java.lang.String getJournal();\n    /**\n     * <code>string journal = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getJournalBytes();\n\n    /**\n     * <code>int64 position = 2;</code>\n     */\n    long getPosition();\n\n    /**\n     * <code>int64 timestamp = 3;</code>\n     */\n    long getTimestamp();\n\n    public com.alibaba.otter.canal.protocol.CanalPacket.Dump.TimestampPresentCase getTimestampPresentCase();\n  }\n  /**\n   * <pre>\n   * TBD when new packets are required\n   * </pre>\n   *\n   * Protobuf type {@code com.alibaba.otter.canal.protocol.Dump}\n   */\n  public  static final class Dump extends\n      com.google.protobuf.GeneratedMessageV3 implements\n      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.Dump)\n      DumpOrBuilder {\n  private static final long serialVersionUID = 0L;\n    // Use Dump.newBuilder() to construct.\n    private Dump(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {\n      super(builder);\n    }\n    private Dump() {\n      journal_ = \"\";\n      position_ = 0L;\n    }\n\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n    getUnknownFields() {\n      return this.unknownFields;\n    }\n    private Dump(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      this();\n      if (extensionRegistry == null) {\n        throw new java.lang.NullPointerException();\n      }\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            case 10: {\n              java.lang.String s = input.readStringRequireUtf8();\n\n              journal_ = s;\n              break;\n            }\n            case 16: {\n\n              position_ = input.readInt64();\n              break;\n            }\n            case 24: {\n              timestampPresentCase_ = 3;\n              timestampPresent_ = input.readInt64();\n              break;\n            }\n            default: {\n              if (!parseUnknownFieldProto3(\n                  input, unknownFields, extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Dump_descriptor;\n    }\n\n    @java.lang.Override\n    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Dump_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              com.alibaba.otter.canal.protocol.CanalPacket.Dump.class, com.alibaba.otter.canal.protocol.CanalPacket.Dump.Builder.class);\n    }\n\n    private int timestampPresentCase_ = 0;\n    private java.lang.Object timestampPresent_;\n    public enum TimestampPresentCase\n        implements com.google.protobuf.Internal.EnumLite {\n      TIMESTAMP(3),\n      TIMESTAMPPRESENT_NOT_SET(0);\n      private final int value;\n      private TimestampPresentCase(int value) {\n        this.value = value;\n      }\n      /**\n       * @deprecated Use {@link #forNumber(int)} instead.\n       */\n      @java.lang.Deprecated\n      public static TimestampPresentCase valueOf(int value) {\n        return forNumber(value);\n      }\n\n      public static TimestampPresentCase forNumber(int value) {\n        switch (value) {\n          case 3: return TIMESTAMP;\n          case 0: return TIMESTAMPPRESENT_NOT_SET;\n          default: return null;\n        }\n      }\n      public int getNumber() {\n        return this.value;\n      }\n    };\n\n    public TimestampPresentCase\n    getTimestampPresentCase() {\n      return TimestampPresentCase.forNumber(\n          timestampPresentCase_);\n    }\n\n    public static final int JOURNAL_FIELD_NUMBER = 1;\n    private volatile java.lang.Object journal_;\n    /**\n     * <code>string journal = 1;</code>\n     */\n    public java.lang.String getJournal() {\n      java.lang.Object ref = journal_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        journal_ = s;\n        return s;\n      }\n    }\n    /**\n     * <code>string journal = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getJournalBytes() {\n      java.lang.Object ref = journal_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        journal_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int POSITION_FIELD_NUMBER = 2;\n    private long position_;\n    /**\n     * <code>int64 position = 2;</code>\n     */\n    public long getPosition() {\n      return position_;\n    }\n\n    public static final int TIMESTAMP_FIELD_NUMBER = 3;\n    /**\n     * <code>int64 timestamp = 3;</code>\n     */\n    public long getTimestamp() {\n      if (timestampPresentCase_ == 3) {\n        return (java.lang.Long) timestampPresent_;\n      }\n      return 0L;\n    }\n\n    private byte memoizedIsInitialized = -1;\n    @java.lang.Override\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    @java.lang.Override\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      if (!getJournalBytes().isEmpty()) {\n        com.google.protobuf.GeneratedMessageV3.writeString(output, 1, journal_);\n      }\n      if (position_ != 0L) {\n        output.writeInt64(2, position_);\n      }\n      if (timestampPresentCase_ == 3) {\n        output.writeInt64(\n            3, (long)((java.lang.Long) timestampPresent_));\n      }\n      unknownFields.writeTo(output);\n    }\n\n    @java.lang.Override\n    public int getSerializedSize() {\n      int size = memoizedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (!getJournalBytes().isEmpty()) {\n        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, journal_);\n      }\n      if (position_ != 0L) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(2, position_);\n      }\n      if (timestampPresentCase_ == 3) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(\n              3, (long)((java.lang.Long) timestampPresent_));\n      }\n      size += unknownFields.getSerializedSize();\n      memoizedSize = size;\n      return size;\n    }\n\n    @java.lang.Override\n    public boolean equals(final java.lang.Object obj) {\n      if (obj == this) {\n       return true;\n      }\n      if (!(obj instanceof com.alibaba.otter.canal.protocol.CanalPacket.Dump)) {\n        return super.equals(obj);\n      }\n      com.alibaba.otter.canal.protocol.CanalPacket.Dump other = (com.alibaba.otter.canal.protocol.CanalPacket.Dump) obj;\n\n      boolean result = true;\n      result = result && getJournal()\n          .equals(other.getJournal());\n      result = result && (getPosition()\n          == other.getPosition());\n      result = result && getTimestampPresentCase().equals(\n          other.getTimestampPresentCase());\n      if (!result) return false;\n      switch (timestampPresentCase_) {\n        case 3:\n          result = result && (getTimestamp()\n              == other.getTimestamp());\n          break;\n        case 0:\n        default:\n      }\n      result = result && unknownFields.equals(other.unknownFields);\n      return result;\n    }\n\n    @java.lang.Override\n    public int hashCode() {\n      if (memoizedHashCode != 0) {\n        return memoizedHashCode;\n      }\n      int hash = 41;\n      hash = (19 * hash) + getDescriptor().hashCode();\n      hash = (37 * hash) + JOURNAL_FIELD_NUMBER;\n      hash = (53 * hash) + getJournal().hashCode();\n      hash = (37 * hash) + POSITION_FIELD_NUMBER;\n      hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n          getPosition());\n      switch (timestampPresentCase_) {\n        case 3:\n          hash = (37 * hash) + TIMESTAMP_FIELD_NUMBER;\n          hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n              getTimestamp());\n          break;\n        case 0:\n        default:\n      }\n      hash = (29 * hash) + unknownFields.hashCode();\n      memoizedHashCode = hash;\n      return hash;\n    }\n\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Dump parseFrom(\n        java.nio.ByteBuffer data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Dump parseFrom(\n        java.nio.ByteBuffer data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Dump parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Dump parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Dump parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Dump parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Dump parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Dump parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Dump parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Dump parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Dump parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Dump parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    @java.lang.Override\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder() {\n      return DEFAULT_INSTANCE.toBuilder();\n    }\n    public static Builder newBuilder(com.alibaba.otter.canal.protocol.CanalPacket.Dump prototype) {\n      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n    }\n    @java.lang.Override\n    public Builder toBuilder() {\n      return this == DEFAULT_INSTANCE\n          ? new Builder() : new Builder().mergeFrom(this);\n    }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * <pre>\n     * TBD when new packets are required\n     * </pre>\n     *\n     * Protobuf type {@code com.alibaba.otter.canal.protocol.Dump}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.Dump)\n        com.alibaba.otter.canal.protocol.CanalPacket.DumpOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Dump_descriptor;\n      }\n\n      @java.lang.Override\n      protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Dump_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                com.alibaba.otter.canal.protocol.CanalPacket.Dump.class, com.alibaba.otter.canal.protocol.CanalPacket.Dump.Builder.class);\n      }\n\n      // Construct using com.alibaba.otter.canal.protocol.CanalPacket.Dump.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessageV3\n                .alwaysUseFieldBuilders) {\n        }\n      }\n      @java.lang.Override\n      public Builder clear() {\n        super.clear();\n        journal_ = \"\";\n\n        position_ = 0L;\n\n        timestampPresentCase_ = 0;\n        timestampPresent_ = null;\n        return this;\n      }\n\n      @java.lang.Override\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_Dump_descriptor;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.Dump getDefaultInstanceForType() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.Dump.getDefaultInstance();\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.Dump build() {\n        com.alibaba.otter.canal.protocol.CanalPacket.Dump result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.Dump buildPartial() {\n        com.alibaba.otter.canal.protocol.CanalPacket.Dump result = new com.alibaba.otter.canal.protocol.CanalPacket.Dump(this);\n        result.journal_ = journal_;\n        result.position_ = position_;\n        if (timestampPresentCase_ == 3) {\n          result.timestampPresent_ = timestampPresent_;\n        }\n        result.timestampPresentCase_ = timestampPresentCase_;\n        onBuilt();\n        return result;\n      }\n\n      @java.lang.Override\n      public Builder clone() {\n        return (Builder) super.clone();\n      }\n      @java.lang.Override\n      public Builder setField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.setField(field, value);\n      }\n      @java.lang.Override\n      public Builder clearField(\n          com.google.protobuf.Descriptors.FieldDescriptor field) {\n        return (Builder) super.clearField(field);\n      }\n      @java.lang.Override\n      public Builder clearOneof(\n          com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n        return (Builder) super.clearOneof(oneof);\n      }\n      @java.lang.Override\n      public Builder setRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          int index, java.lang.Object value) {\n        return (Builder) super.setRepeatedField(field, index, value);\n      }\n      @java.lang.Override\n      public Builder addRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.addRepeatedField(field, value);\n      }\n      @java.lang.Override\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof com.alibaba.otter.canal.protocol.CanalPacket.Dump) {\n          return mergeFrom((com.alibaba.otter.canal.protocol.CanalPacket.Dump)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(com.alibaba.otter.canal.protocol.CanalPacket.Dump other) {\n        if (other == com.alibaba.otter.canal.protocol.CanalPacket.Dump.getDefaultInstance()) return this;\n        if (!other.getJournal().isEmpty()) {\n          journal_ = other.journal_;\n          onChanged();\n        }\n        if (other.getPosition() != 0L) {\n          setPosition(other.getPosition());\n        }\n        switch (other.getTimestampPresentCase()) {\n          case TIMESTAMP: {\n            setTimestamp(other.getTimestamp());\n            break;\n          }\n          case TIMESTAMPPRESENT_NOT_SET: {\n            break;\n          }\n        }\n        this.mergeUnknownFields(other.unknownFields);\n        onChanged();\n        return this;\n      }\n\n      @java.lang.Override\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      @java.lang.Override\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        com.alibaba.otter.canal.protocol.CanalPacket.Dump parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (com.alibaba.otter.canal.protocol.CanalPacket.Dump) e.getUnfinishedMessage();\n          throw e.unwrapIOException();\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int timestampPresentCase_ = 0;\n      private java.lang.Object timestampPresent_;\n      public TimestampPresentCase\n          getTimestampPresentCase() {\n        return TimestampPresentCase.forNumber(\n            timestampPresentCase_);\n      }\n\n      public Builder clearTimestampPresent() {\n        timestampPresentCase_ = 0;\n        timestampPresent_ = null;\n        onChanged();\n        return this;\n      }\n\n\n      private java.lang.Object journal_ = \"\";\n      /**\n       * <code>string journal = 1;</code>\n       */\n      public java.lang.String getJournal() {\n        java.lang.Object ref = journal_;\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          journal_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>string journal = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getJournalBytes() {\n        java.lang.Object ref = journal_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          journal_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>string journal = 1;</code>\n       */\n      public Builder setJournal(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        journal_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string journal = 1;</code>\n       */\n      public Builder clearJournal() {\n        \n        journal_ = getDefaultInstance().getJournal();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string journal = 1;</code>\n       */\n      public Builder setJournalBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  checkByteStringIsUtf8(value);\n        \n        journal_ = value;\n        onChanged();\n        return this;\n      }\n\n      private long position_ ;\n      /**\n       * <code>int64 position = 2;</code>\n       */\n      public long getPosition() {\n        return position_;\n      }\n      /**\n       * <code>int64 position = 2;</code>\n       */\n      public Builder setPosition(long value) {\n        \n        position_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>int64 position = 2;</code>\n       */\n      public Builder clearPosition() {\n        \n        position_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      /**\n       * <code>int64 timestamp = 3;</code>\n       */\n      public long getTimestamp() {\n        if (timestampPresentCase_ == 3) {\n          return (java.lang.Long) timestampPresent_;\n        }\n        return 0L;\n      }\n      /**\n       * <code>int64 timestamp = 3;</code>\n       */\n      public Builder setTimestamp(long value) {\n        timestampPresentCase_ = 3;\n        timestampPresent_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>int64 timestamp = 3;</code>\n       */\n      public Builder clearTimestamp() {\n        if (timestampPresentCase_ == 3) {\n          timestampPresentCase_ = 0;\n          timestampPresent_ = null;\n          onChanged();\n        }\n        return this;\n      }\n      @java.lang.Override\n      public final Builder setUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.setUnknownFieldsProto3(unknownFields);\n      }\n\n      @java.lang.Override\n      public final Builder mergeUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.mergeUnknownFields(unknownFields);\n      }\n\n\n      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.Dump)\n    }\n\n    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.Dump)\n    private static final com.alibaba.otter.canal.protocol.CanalPacket.Dump DEFAULT_INSTANCE;\n    static {\n      DEFAULT_INSTANCE = new com.alibaba.otter.canal.protocol.CanalPacket.Dump();\n    }\n\n    public static com.alibaba.otter.canal.protocol.CanalPacket.Dump getDefaultInstance() {\n      return DEFAULT_INSTANCE;\n    }\n\n    private static final com.google.protobuf.Parser<Dump>\n        PARSER = new com.google.protobuf.AbstractParser<Dump>() {\n      @java.lang.Override\n      public Dump parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new Dump(input, extensionRegistry);\n      }\n    };\n\n    public static com.google.protobuf.Parser<Dump> parser() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<Dump> getParserForType() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.alibaba.otter.canal.protocol.CanalPacket.Dump getDefaultInstanceForType() {\n      return DEFAULT_INSTANCE;\n    }\n\n  }\n\n  public interface ClientRollbackOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.ClientRollback)\n      com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <code>string destination = 1;</code>\n     */\n    java.lang.String getDestination();\n    /**\n     * <code>string destination = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getDestinationBytes();\n\n    /**\n     * <code>string client_id = 2;</code>\n     */\n    java.lang.String getClientId();\n    /**\n     * <code>string client_id = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getClientIdBytes();\n\n    /**\n     * <code>int64 batch_id = 3;</code>\n     */\n    long getBatchId();\n  }\n  /**\n   * Protobuf type {@code com.alibaba.otter.canal.protocol.ClientRollback}\n   */\n  public  static final class ClientRollback extends\n      com.google.protobuf.GeneratedMessageV3 implements\n      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.ClientRollback)\n      ClientRollbackOrBuilder {\n  private static final long serialVersionUID = 0L;\n    // Use ClientRollback.newBuilder() to construct.\n    private ClientRollback(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {\n      super(builder);\n    }\n    private ClientRollback() {\n      destination_ = \"\";\n      clientId_ = \"\";\n      batchId_ = 0L;\n    }\n\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n    getUnknownFields() {\n      return this.unknownFields;\n    }\n    private ClientRollback(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      this();\n      if (extensionRegistry == null) {\n        throw new java.lang.NullPointerException();\n      }\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            case 10: {\n              java.lang.String s = input.readStringRequireUtf8();\n\n              destination_ = s;\n              break;\n            }\n            case 18: {\n              java.lang.String s = input.readStringRequireUtf8();\n\n              clientId_ = s;\n              break;\n            }\n            case 24: {\n\n              batchId_ = input.readInt64();\n              break;\n            }\n            default: {\n              if (!parseUnknownFieldProto3(\n                  input, unknownFields, extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_ClientRollback_descriptor;\n    }\n\n    @java.lang.Override\n    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_ClientRollback_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback.class, com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback.Builder.class);\n    }\n\n    public static final int DESTINATION_FIELD_NUMBER = 1;\n    private volatile java.lang.Object destination_;\n    /**\n     * <code>string destination = 1;</code>\n     */\n    public java.lang.String getDestination() {\n      java.lang.Object ref = destination_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        destination_ = s;\n        return s;\n      }\n    }\n    /**\n     * <code>string destination = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getDestinationBytes() {\n      java.lang.Object ref = destination_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        destination_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int CLIENT_ID_FIELD_NUMBER = 2;\n    private volatile java.lang.Object clientId_;\n    /**\n     * <code>string client_id = 2;</code>\n     */\n    public java.lang.String getClientId() {\n      java.lang.Object ref = clientId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        clientId_ = s;\n        return s;\n      }\n    }\n    /**\n     * <code>string client_id = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getClientIdBytes() {\n      java.lang.Object ref = clientId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        clientId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    public static final int BATCH_ID_FIELD_NUMBER = 3;\n    private long batchId_;\n    /**\n     * <code>int64 batch_id = 3;</code>\n     */\n    public long getBatchId() {\n      return batchId_;\n    }\n\n    private byte memoizedIsInitialized = -1;\n    @java.lang.Override\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    @java.lang.Override\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      if (!getDestinationBytes().isEmpty()) {\n        com.google.protobuf.GeneratedMessageV3.writeString(output, 1, destination_);\n      }\n      if (!getClientIdBytes().isEmpty()) {\n        com.google.protobuf.GeneratedMessageV3.writeString(output, 2, clientId_);\n      }\n      if (batchId_ != 0L) {\n        output.writeInt64(3, batchId_);\n      }\n      unknownFields.writeTo(output);\n    }\n\n    @java.lang.Override\n    public int getSerializedSize() {\n      int size = memoizedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (!getDestinationBytes().isEmpty()) {\n        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, destination_);\n      }\n      if (!getClientIdBytes().isEmpty()) {\n        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, clientId_);\n      }\n      if (batchId_ != 0L) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(3, batchId_);\n      }\n      size += unknownFields.getSerializedSize();\n      memoizedSize = size;\n      return size;\n    }\n\n    @java.lang.Override\n    public boolean equals(final java.lang.Object obj) {\n      if (obj == this) {\n       return true;\n      }\n      if (!(obj instanceof com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback)) {\n        return super.equals(obj);\n      }\n      com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback other = (com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback) obj;\n\n      boolean result = true;\n      result = result && getDestination()\n          .equals(other.getDestination());\n      result = result && getClientId()\n          .equals(other.getClientId());\n      result = result && (getBatchId()\n          == other.getBatchId());\n      result = result && unknownFields.equals(other.unknownFields);\n      return result;\n    }\n\n    @java.lang.Override\n    public int hashCode() {\n      if (memoizedHashCode != 0) {\n        return memoizedHashCode;\n      }\n      int hash = 41;\n      hash = (19 * hash) + getDescriptor().hashCode();\n      hash = (37 * hash) + DESTINATION_FIELD_NUMBER;\n      hash = (53 * hash) + getDestination().hashCode();\n      hash = (37 * hash) + CLIENT_ID_FIELD_NUMBER;\n      hash = (53 * hash) + getClientId().hashCode();\n      hash = (37 * hash) + BATCH_ID_FIELD_NUMBER;\n      hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n          getBatchId());\n      hash = (29 * hash) + unknownFields.hashCode();\n      memoizedHashCode = hash;\n      return hash;\n    }\n\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback parseFrom(\n        java.nio.ByteBuffer data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback parseFrom(\n        java.nio.ByteBuffer data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input);\n    }\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessageV3\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    @java.lang.Override\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder() {\n      return DEFAULT_INSTANCE.toBuilder();\n    }\n    public static Builder newBuilder(com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback prototype) {\n      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n    }\n    @java.lang.Override\n    public Builder toBuilder() {\n      return this == DEFAULT_INSTANCE\n          ? new Builder() : new Builder().mergeFrom(this);\n    }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code com.alibaba.otter.canal.protocol.ClientRollback}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.ClientRollback)\n        com.alibaba.otter.canal.protocol.CanalPacket.ClientRollbackOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_ClientRollback_descriptor;\n      }\n\n      @java.lang.Override\n      protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_ClientRollback_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback.class, com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback.Builder.class);\n      }\n\n      // Construct using com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessageV3\n                .alwaysUseFieldBuilders) {\n        }\n      }\n      @java.lang.Override\n      public Builder clear() {\n        super.clear();\n        destination_ = \"\";\n\n        clientId_ = \"\";\n\n        batchId_ = 0L;\n\n        return this;\n      }\n\n      @java.lang.Override\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.internal_static_com_alibaba_otter_canal_protocol_ClientRollback_descriptor;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback getDefaultInstanceForType() {\n        return com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback.getDefaultInstance();\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback build() {\n        com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      @java.lang.Override\n      public com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback buildPartial() {\n        com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback result = new com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback(this);\n        result.destination_ = destination_;\n        result.clientId_ = clientId_;\n        result.batchId_ = batchId_;\n        onBuilt();\n        return result;\n      }\n\n      @java.lang.Override\n      public Builder clone() {\n        return (Builder) super.clone();\n      }\n      @java.lang.Override\n      public Builder setField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.setField(field, value);\n      }\n      @java.lang.Override\n      public Builder clearField(\n          com.google.protobuf.Descriptors.FieldDescriptor field) {\n        return (Builder) super.clearField(field);\n      }\n      @java.lang.Override\n      public Builder clearOneof(\n          com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n        return (Builder) super.clearOneof(oneof);\n      }\n      @java.lang.Override\n      public Builder setRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          int index, java.lang.Object value) {\n        return (Builder) super.setRepeatedField(field, index, value);\n      }\n      @java.lang.Override\n      public Builder addRepeatedField(\n          com.google.protobuf.Descriptors.FieldDescriptor field,\n          java.lang.Object value) {\n        return (Builder) super.addRepeatedField(field, value);\n      }\n      @java.lang.Override\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback) {\n          return mergeFrom((com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback other) {\n        if (other == com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback.getDefaultInstance()) return this;\n        if (!other.getDestination().isEmpty()) {\n          destination_ = other.destination_;\n          onChanged();\n        }\n        if (!other.getClientId().isEmpty()) {\n          clientId_ = other.clientId_;\n          onChanged();\n        }\n        if (other.getBatchId() != 0L) {\n          setBatchId(other.getBatchId());\n        }\n        this.mergeUnknownFields(other.unknownFields);\n        onChanged();\n        return this;\n      }\n\n      @java.lang.Override\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      @java.lang.Override\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback) e.getUnfinishedMessage();\n          throw e.unwrapIOException();\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n\n      private java.lang.Object destination_ = \"\";\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public java.lang.String getDestination() {\n        java.lang.Object ref = destination_;\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          destination_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getDestinationBytes() {\n        java.lang.Object ref = destination_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          destination_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public Builder setDestination(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        destination_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public Builder clearDestination() {\n        \n        destination_ = getDefaultInstance().getDestination();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string destination = 1;</code>\n       */\n      public Builder setDestinationBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  checkByteStringIsUtf8(value);\n        \n        destination_ = value;\n        onChanged();\n        return this;\n      }\n\n      private java.lang.Object clientId_ = \"\";\n      /**\n       * <code>string client_id = 2;</code>\n       */\n      public java.lang.String getClientId() {\n        java.lang.Object ref = clientId_;\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          clientId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>string client_id = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getClientIdBytes() {\n        java.lang.Object ref = clientId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          clientId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>string client_id = 2;</code>\n       */\n      public Builder setClientId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  \n        clientId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string client_id = 2;</code>\n       */\n      public Builder clearClientId() {\n        \n        clientId_ = getDefaultInstance().getClientId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>string client_id = 2;</code>\n       */\n      public Builder setClientIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  checkByteStringIsUtf8(value);\n        \n        clientId_ = value;\n        onChanged();\n        return this;\n      }\n\n      private long batchId_ ;\n      /**\n       * <code>int64 batch_id = 3;</code>\n       */\n      public long getBatchId() {\n        return batchId_;\n      }\n      /**\n       * <code>int64 batch_id = 3;</code>\n       */\n      public Builder setBatchId(long value) {\n        \n        batchId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>int64 batch_id = 3;</code>\n       */\n      public Builder clearBatchId() {\n        \n        batchId_ = 0L;\n        onChanged();\n        return this;\n      }\n      @java.lang.Override\n      public final Builder setUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.setUnknownFieldsProto3(unknownFields);\n      }\n\n      @java.lang.Override\n      public final Builder mergeUnknownFields(\n          final com.google.protobuf.UnknownFieldSet unknownFields) {\n        return super.mergeUnknownFields(unknownFields);\n      }\n\n\n      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.ClientRollback)\n    }\n\n    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.ClientRollback)\n    private static final com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback DEFAULT_INSTANCE;\n    static {\n      DEFAULT_INSTANCE = new com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback();\n    }\n\n    public static com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback getDefaultInstance() {\n      return DEFAULT_INSTANCE;\n    }\n\n    private static final com.google.protobuf.Parser<ClientRollback>\n        PARSER = new com.google.protobuf.AbstractParser<ClientRollback>() {\n      @java.lang.Override\n      public ClientRollback parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new ClientRollback(input, extensionRegistry);\n      }\n    };\n\n    public static com.google.protobuf.Parser<ClientRollback> parser() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<ClientRollback> getParserForType() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback getDefaultInstanceForType() {\n      return DEFAULT_INSTANCE;\n    }\n\n  }\n\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_com_alibaba_otter_canal_protocol_Packet_descriptor;\n  private static final \n    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n      internal_static_com_alibaba_otter_canal_protocol_Packet_fieldAccessorTable;\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_com_alibaba_otter_canal_protocol_HeartBeat_descriptor;\n  private static final \n    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n      internal_static_com_alibaba_otter_canal_protocol_HeartBeat_fieldAccessorTable;\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_com_alibaba_otter_canal_protocol_Handshake_descriptor;\n  private static final \n    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n      internal_static_com_alibaba_otter_canal_protocol_Handshake_fieldAccessorTable;\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_com_alibaba_otter_canal_protocol_ClientAuth_descriptor;\n  private static final \n    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n      internal_static_com_alibaba_otter_canal_protocol_ClientAuth_fieldAccessorTable;\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_com_alibaba_otter_canal_protocol_Ack_descriptor;\n  private static final \n    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n      internal_static_com_alibaba_otter_canal_protocol_Ack_fieldAccessorTable;\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_com_alibaba_otter_canal_protocol_ClientAck_descriptor;\n  private static final \n    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n      internal_static_com_alibaba_otter_canal_protocol_ClientAck_fieldAccessorTable;\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_com_alibaba_otter_canal_protocol_Sub_descriptor;\n  private static final \n    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n      internal_static_com_alibaba_otter_canal_protocol_Sub_fieldAccessorTable;\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_com_alibaba_otter_canal_protocol_Unsub_descriptor;\n  private static final \n    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n      internal_static_com_alibaba_otter_canal_protocol_Unsub_fieldAccessorTable;\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_com_alibaba_otter_canal_protocol_Get_descriptor;\n  private static final \n    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n      internal_static_com_alibaba_otter_canal_protocol_Get_fieldAccessorTable;\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_com_alibaba_otter_canal_protocol_Messages_descriptor;\n  private static final \n    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n      internal_static_com_alibaba_otter_canal_protocol_Messages_fieldAccessorTable;\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_com_alibaba_otter_canal_protocol_Dump_descriptor;\n  private static final \n    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n      internal_static_com_alibaba_otter_canal_protocol_Dump_fieldAccessorTable;\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_com_alibaba_otter_canal_protocol_ClientRollback_descriptor;\n  private static final \n    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n      internal_static_com_alibaba_otter_canal_protocol_ClientRollback_fieldAccessorTable;\n\n  public static com.google.protobuf.Descriptors.FileDescriptor\n      getDescriptor() {\n    return descriptor;\n  }\n  private static  com.google.protobuf.Descriptors.FileDescriptor\n      descriptor;\n  static {\n    java.lang.String[] descriptorData = {\n      \"\\n\\023CanalProtocol.proto\\022 com.alibaba.otter\" +\n      \".canal.protocol\\\"\\205\\002\\n\\006Packet\\022\\026\\n\\014magic_numb\" +\n      \"er\\030\\001 \\001(\\005H\\000\\022\\021\\n\\007version\\030\\002 \\001(\\005H\\001\\022:\\n\\004type\\030\\003 \" +\n      \"\\001(\\0162,.com.alibaba.otter.canal.protocol.P\" +\n      \"acketType\\022D\\n\\013compression\\030\\004 \\001(\\0162-.com.ali\" +\n      \"baba.otter.canal.protocol.CompressionH\\002\\022\" +\n      \"\\014\\n\\004body\\030\\005 \\001(\\014B\\026\\n\\024magic_number_presentB\\021\\n\" +\n      \"\\017version_presentB\\025\\n\\023compression_present\\\"\" +\n      \"<\\n\\tHeartBeat\\022\\026\\n\\016send_timestamp\\030\\001 \\001(\\003\\022\\027\\n\\017\" +\n      \"start_timestamp\\030\\002 \\001(\\003\\\"\\255\\001\\n\\tHandshake\\022 \\n\\026c\" +\n      \"ommunication_encoding\\030\\001 \\001(\\tH\\000\\022\\r\\n\\005seeds\\030\\002\" +\n      \" \\001(\\014\\022M\\n\\026supported_compressions\\030\\003 \\001(\\0162-.c\" +\n      \"om.alibaba.otter.canal.protocol.Compress\" +\n      \"ionB \\n\\036communication_encoding_present\\\"\\363\\001\" +\n      \"\\n\\nClientAuth\\022\\020\\n\\010username\\030\\001 \\001(\\t\\022\\020\\n\\010passwo\" +\n      \"rd\\030\\002 \\001(\\014\\022\\032\\n\\020net_read_timeout\\030\\003 \\001(\\005H\\000\\022\\033\\n\\021\" +\n      \"net_write_timeout\\030\\004 \\001(\\005H\\001\\022\\023\\n\\013destination\" +\n      \"\\030\\005 \\001(\\t\\022\\021\\n\\tclient_id\\030\\006 \\001(\\t\\022\\016\\n\\006filter\\030\\007 \\001(\" +\n      \"\\t\\022\\027\\n\\017start_timestamp\\030\\010 \\001(\\003B\\032\\n\\030net_read_t\" +\n      \"imeout_presentB\\033\\n\\031net_write_timeout_pres\" +\n      \"ent\\\"H\\n\\003Ack\\022\\024\\n\\nerror_code\\030\\001 \\001(\\005H\\000\\022\\025\\n\\rerro\" +\n      \"r_message\\030\\002 \\001(\\tB\\024\\n\\022error_code_present\\\"E\\n\" +\n      \"\\tClientAck\\022\\023\\n\\013destination\\030\\001 \\001(\\t\\022\\021\\n\\tclien\" +\n      \"t_id\\030\\002 \\001(\\t\\022\\020\\n\\010batch_id\\030\\003 \\001(\\003\\\"=\\n\\003Sub\\022\\023\\n\\013d\" +\n      \"estination\\030\\001 \\001(\\t\\022\\021\\n\\tclient_id\\030\\002 \\001(\\t\\022\\016\\n\\006f\" +\n      \"ilter\\030\\007 \\001(\\t\\\"?\\n\\005Unsub\\022\\023\\n\\013destination\\030\\001 \\001(\" +\n      \"\\t\\022\\021\\n\\tclient_id\\030\\002 \\001(\\t\\022\\016\\n\\006filter\\030\\007 \\001(\\t\\\"\\257\\001\\n\" +\n      \"\\003Get\\022\\023\\n\\013destination\\030\\001 \\001(\\t\\022\\021\\n\\tclient_id\\030\\002\" +\n      \" \\001(\\t\\022\\022\\n\\nfetch_size\\030\\003 \\001(\\005\\022\\021\\n\\007timeout\\030\\004 \\001(\" +\n      \"\\003H\\000\\022\\016\\n\\004unit\\030\\005 \\001(\\005H\\001\\022\\022\\n\\010auto_ack\\030\\006 \\001(\\010H\\002B\" +\n      \"\\021\\n\\017timeout_presentB\\016\\n\\014unit_presentB\\022\\n\\020au\" +\n      \"to_ack_present\\\".\\n\\010Messages\\022\\020\\n\\010batch_id\\030\\001\" +\n      \" \\001(\\003\\022\\020\\n\\010messages\\030\\002 \\003(\\014\\\"S\\n\\004Dump\\022\\017\\n\\007journa\" +\n      \"l\\030\\001 \\001(\\t\\022\\020\\n\\010position\\030\\002 \\001(\\003\\022\\023\\n\\ttimestamp\\030\\003\" +\n      \" \\001(\\003H\\000B\\023\\n\\021timestamp_present\\\"J\\n\\016ClientRol\" +\n      \"lback\\022\\023\\n\\013destination\\030\\001 \\001(\\t\\022\\021\\n\\tclient_id\\030\" +\n      \"\\002 \\001(\\t\\022\\020\\n\\010batch_id\\030\\003 \\001(\\003*U\\n\\013Compression\\022\\037\" +\n      \"\\n\\033COMPRESSIONCOMPATIBLEPROTO2\\020\\000\\022\\010\\n\\004NONE\\020\" +\n      \"\\001\\022\\010\\n\\004ZLIB\\020\\002\\022\\010\\n\\004GZIP\\020\\003\\022\\007\\n\\003LZF\\020\\004*\\346\\001\\n\\nPacke\" +\n      \"tType\\022\\037\\n\\033PACKAGETYPECOMPATIBLEPROTO2\\020\\000\\022\\r\" +\n      \"\\n\\tHANDSHAKE\\020\\001\\022\\030\\n\\024CLIENTAUTHENTICATION\\020\\002\\022\" +\n      \"\\007\\n\\003ACK\\020\\003\\022\\020\\n\\014SUBSCRIPTION\\020\\004\\022\\022\\n\\016UNSUBSCRIP\" +\n      \"TION\\020\\005\\022\\007\\n\\003GET\\020\\006\\022\\014\\n\\010MESSAGES\\020\\007\\022\\r\\n\\tCLIENTA\" +\n      \"CK\\020\\010\\022\\014\\n\\010SHUTDOWN\\020\\t\\022\\010\\n\\004DUMP\\020\\n\\022\\r\\n\\tHEARTBEA\" +\n      \"T\\020\\013\\022\\022\\n\\016CLIENTROLLBACK\\020\\014B1\\n com.alibaba.o\" +\n      \"tter.canal.protocolB\\013CanalPacketH\\001b\\006prot\" +\n      \"o3\"\n    };\n    com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =\n        new com.google.protobuf.Descriptors.FileDescriptor.    InternalDescriptorAssigner() {\n          public com.google.protobuf.ExtensionRegistry assignDescriptors(\n              com.google.protobuf.Descriptors.FileDescriptor root) {\n            descriptor = root;\n            return null;\n          }\n        };\n    com.google.protobuf.Descriptors.FileDescriptor\n      .internalBuildGeneratedFileFrom(descriptorData,\n        new com.google.protobuf.Descriptors.FileDescriptor[] {\n        }, assigner);\n    internal_static_com_alibaba_otter_canal_protocol_Packet_descriptor =\n      getDescriptor().getMessageTypes().get(0);\n    internal_static_com_alibaba_otter_canal_protocol_Packet_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n        internal_static_com_alibaba_otter_canal_protocol_Packet_descriptor,\n        new java.lang.String[] { \"MagicNumber\", \"Version\", \"Type\", \"Compression\", \"Body\", \"MagicNumberPresent\", \"VersionPresent\", \"CompressionPresent\", });\n    internal_static_com_alibaba_otter_canal_protocol_HeartBeat_descriptor =\n      getDescriptor().getMessageTypes().get(1);\n    internal_static_com_alibaba_otter_canal_protocol_HeartBeat_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n        internal_static_com_alibaba_otter_canal_protocol_HeartBeat_descriptor,\n        new java.lang.String[] { \"SendTimestamp\", \"StartTimestamp\", });\n    internal_static_com_alibaba_otter_canal_protocol_Handshake_descriptor =\n      getDescriptor().getMessageTypes().get(2);\n    internal_static_com_alibaba_otter_canal_protocol_Handshake_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n        internal_static_com_alibaba_otter_canal_protocol_Handshake_descriptor,\n        new java.lang.String[] { \"CommunicationEncoding\", \"Seeds\", \"SupportedCompressions\", \"CommunicationEncodingPresent\", });\n    internal_static_com_alibaba_otter_canal_protocol_ClientAuth_descriptor =\n      getDescriptor().getMessageTypes().get(3);\n    internal_static_com_alibaba_otter_canal_protocol_ClientAuth_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n        internal_static_com_alibaba_otter_canal_protocol_ClientAuth_descriptor,\n        new java.lang.String[] { \"Username\", \"Password\", \"NetReadTimeout\", \"NetWriteTimeout\", \"Destination\", \"ClientId\", \"Filter\", \"StartTimestamp\", \"NetReadTimeoutPresent\", \"NetWriteTimeoutPresent\", });\n    internal_static_com_alibaba_otter_canal_protocol_Ack_descriptor =\n      getDescriptor().getMessageTypes().get(4);\n    internal_static_com_alibaba_otter_canal_protocol_Ack_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n        internal_static_com_alibaba_otter_canal_protocol_Ack_descriptor,\n        new java.lang.String[] { \"ErrorCode\", \"ErrorMessage\", \"ErrorCodePresent\", });\n    internal_static_com_alibaba_otter_canal_protocol_ClientAck_descriptor =\n      getDescriptor().getMessageTypes().get(5);\n    internal_static_com_alibaba_otter_canal_protocol_ClientAck_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n        internal_static_com_alibaba_otter_canal_protocol_ClientAck_descriptor,\n        new java.lang.String[] { \"Destination\", \"ClientId\", \"BatchId\", });\n    internal_static_com_alibaba_otter_canal_protocol_Sub_descriptor =\n      getDescriptor().getMessageTypes().get(6);\n    internal_static_com_alibaba_otter_canal_protocol_Sub_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n        internal_static_com_alibaba_otter_canal_protocol_Sub_descriptor,\n        new java.lang.String[] { \"Destination\", \"ClientId\", \"Filter\", });\n    internal_static_com_alibaba_otter_canal_protocol_Unsub_descriptor =\n      getDescriptor().getMessageTypes().get(7);\n    internal_static_com_alibaba_otter_canal_protocol_Unsub_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n        internal_static_com_alibaba_otter_canal_protocol_Unsub_descriptor,\n        new java.lang.String[] { \"Destination\", \"ClientId\", \"Filter\", });\n    internal_static_com_alibaba_otter_canal_protocol_Get_descriptor =\n      getDescriptor().getMessageTypes().get(8);\n    internal_static_com_alibaba_otter_canal_protocol_Get_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n        internal_static_com_alibaba_otter_canal_protocol_Get_descriptor,\n        new java.lang.String[] { \"Destination\", \"ClientId\", \"FetchSize\", \"Timeout\", \"Unit\", \"AutoAck\", \"TimeoutPresent\", \"UnitPresent\", \"AutoAckPresent\", });\n    internal_static_com_alibaba_otter_canal_protocol_Messages_descriptor =\n      getDescriptor().getMessageTypes().get(9);\n    internal_static_com_alibaba_otter_canal_protocol_Messages_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n        internal_static_com_alibaba_otter_canal_protocol_Messages_descriptor,\n        new java.lang.String[] { \"BatchId\", \"Messages\", });\n    internal_static_com_alibaba_otter_canal_protocol_Dump_descriptor =\n      getDescriptor().getMessageTypes().get(10);\n    internal_static_com_alibaba_otter_canal_protocol_Dump_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n        internal_static_com_alibaba_otter_canal_protocol_Dump_descriptor,\n        new java.lang.String[] { \"Journal\", \"Position\", \"Timestamp\", \"TimestampPresent\", });\n    internal_static_com_alibaba_otter_canal_protocol_ClientRollback_descriptor =\n      getDescriptor().getMessageTypes().get(11);\n    internal_static_com_alibaba_otter_canal_protocol_ClientRollback_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n        internal_static_com_alibaba_otter_canal_protocol_ClientRollback_descriptor,\n        new java.lang.String[] { \"Destination\", \"ClientId\", \"BatchId\", });\n  }\n\n  // @@protoc_insertion_point(outer_class_scope)\n}\n"
  },
  {
    "path": "protocol/src/main/java/com/alibaba/otter/canal/protocol/CanalProtocol.proto",
    "content": "syntax = \"proto3\";\npackage com.alibaba.otter.canal.protocol;\n\noption java_package = \"com.alibaba.otter.canal.protocol\";\noption java_outer_classname = \"CanalPacket\";\noption optimize_for = SPEED;\n\nenum Compression {\n    COMPRESSIONCOMPATIBLEPROTO2 = 0;\n    NONE = 1;\n    ZLIB = 2;\n    GZIP = 3;\n    LZF = 4;\n}\n\nenum PacketType {\n    //compatible\n    PACKAGETYPECOMPATIBLEPROTO2 = 0;\n    HANDSHAKE = 1;\n    CLIENTAUTHENTICATION = 2;\n    ACK = 3;\n    SUBSCRIPTION = 4;\n    UNSUBSCRIPTION = 5;\n    GET = 6;\n    MESSAGES = 7;\n    CLIENTACK = 8;\n    // management part\n    SHUTDOWN = 9;\n    // integration\n    DUMP = 10;\n    HEARTBEAT = 11;\n    CLIENTROLLBACK = 12;\n}\n\nmessage Packet {\n     //[default = 17];\n     oneof magic_number_present {\n         int32 magic_number = 1;\n     }\n     //[default = 1];\n     oneof version_present {\n          int32 version = 2;\n     };\n     PacketType type = 3;\n     //[default = NONE];\n     oneof compression_present {\n          Compression compression = 4;\n     }\n\n     bytes body = 5;\n}\n\nmessage HeartBeat {\n     int64 send_timestamp = 1;\n     int64 start_timestamp = 2;\n}\n\nmessage Handshake {\n    //  [default = \"utf8\"];\n    oneof communication_encoding_present {\n        string communication_encoding = 1;\n    }\n     bytes seeds = 2;\n     Compression supported_compressions = 3;\n}\n\n// client authentication\nmessage ClientAuth {\n    string username = 1;\n    bytes password = 2; // hashed password with seeds from Handshake message\n    // [default = 0]\n    oneof net_read_timeout_present {\n         int32 net_read_timeout = 3; // in seconds\n    }\n    // [default = 0];\n    oneof net_write_timeout_present {\n        int32 net_write_timeout = 4; // in seconds\n    }\n    string destination = 5;\n    string client_id = 6;\n    string filter = 7;\n    int64 start_timestamp = 8;\n}\n\nmessage Ack {\n    //[default = 0]\n    oneof error_code_present {\n        int32 error_code = 1;\n    }\n    string error_message = 2; // if something like compression is not supported, erorr_message will tell about it.\n}\n\nmessage ClientAck {\n    string destination = 1;\n    string client_id = 2;\n    int64 batch_id = 3;\n}\n\n// subscription\nmessage Sub {\n    string destination = 1;\n    string client_id = 2;\n    string filter = 7;\n}\n\n// Unsubscription\nmessage Unsub {\n    string destination = 1;\n    string client_id = 2;\n    string filter = 7;\n}\n\n//  PullRequest\nmessage Get {\n    string destination = 1;\n    string client_id = 2;\n    int32 fetch_size = 3;\n    //[default = -1]\n    oneof timeout_present {\n        int64 timeout = 4; // 默认-1时代表不控制\n    }\n    //[default = 2]\n    oneof unit_present {\n        int32 unit = 5;// 数字类型，0:纳秒,1:微秒,2:毫秒,3:秒,4:分钟,5:小时,6:天\n    }\n    //[default = false]\n    oneof auto_ack_present {\n        bool auto_ack = 6; // 是否自动ack\n    }\n\n}\n\n//\nmessage Messages {\n\tint64 batch_id = 1;\n    repeated bytes messages = 2;\n}\n\n// TBD when new packets are required\nmessage Dump{\n    string journal = 1;\n    int64  position = 2;\n    // [default = 0]\n    oneof timestamp_present {\n        int64 timestamp = 3;\n    }\n\n}\n\nmessage ClientRollback{\n    string destination = 1;\n    string client_id = 2;\n    int64 batch_id = 3;\n}\n"
  },
  {
    "path": "protocol/src/main/java/com/alibaba/otter/canal/protocol/ClientIdentity.java",
    "content": "package com.alibaba.otter.canal.protocol;\n\nimport java.io.Serializable;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.commons.lang.builder.ToStringBuilder;\n\nimport com.alibaba.otter.canal.common.utils.CanalToStringStyle;\n\n/**\n * @author zebin.xuzb @ 2012-6-20\n * @version 1.0.0\n */\npublic class ClientIdentity implements Serializable {\n\n    private static final long serialVersionUID = -8262100681930834834L;\n    private String            destination;\n    private short             clientId;\n    private String            filter;\n\n    public ClientIdentity(){\n\n    }\n\n    public ClientIdentity(String destination, short clientId){\n        this.clientId = clientId;\n        this.destination = destination;\n    }\n\n    public ClientIdentity(String destination, short clientId, String filter){\n        this.clientId = clientId;\n        this.destination = destination;\n        this.filter = filter;\n    }\n\n    public Boolean hasFilter() {\n        if (filter == null) {\n            return false;\n        }\n        return StringUtils.isNotBlank(filter);\n    }\n\n    // ======== setter =========\n\n    public String getDestination() {\n        return destination;\n    }\n\n    public short getClientId() {\n        return clientId;\n    }\n\n    public void setClientId(short clientId) {\n        this.clientId = clientId;\n    }\n\n    public void setDestination(String destination) {\n        this.destination = destination;\n    }\n\n    public String getFilter() {\n        return filter;\n    }\n\n    public void setFilter(String filter) {\n        this.filter = filter;\n    }\n\n    public String toString() {\n        return ToStringBuilder.reflectionToString(this, CanalToStringStyle.DEFAULT_STYLE);\n    }\n\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + clientId;\n        result = prime * result + ((destination == null) ? 0 : destination.hashCode());\n        return result;\n    }\n\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (!(obj instanceof ClientIdentity)) {\n            return false;\n        }\n        ClientIdentity other = (ClientIdentity) obj;\n        if (clientId != other.clientId) {\n            return false;\n        }\n        if (destination == null) {\n            if (other.destination != null) {\n                return false;\n            }\n        } else if (!destination.equals(other.destination)) {\n            return false;\n        }\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "protocol/src/main/java/com/alibaba/otter/canal/protocol/EntryProtocol.proto",
    "content": "syntax = \"proto3\";\r\npackage com.alibaba.otter.canal.protocol;\r\n\r\noption java_package = \"com.alibaba.otter.canal.protocol\";\r\noption java_outer_classname = \"CanalEntry\";\r\noption optimize_for = SPEED;\r\n\r\n/****************************************************************\r\n * message model\r\n *如果要在Enum中新增类型，确保以前的类型的下标值不变.\r\n ****************************************************************/\r\nmessage Entry {\r\n\t/**协议头部信息**/\r\n     Header\t\t\t\t\t\theader \t\t\t\t= 1;\r\n\t///**打散后的事件类型**/ [default = ROWDATA]\r\n\toneof entryType_present{\r\n\t\tEntryType\t\t\t\t\tentryType\t\t\t= 2;\r\n\t}\r\n\r\n\t/**传输的二进制数组**/\r\n\tbytes\t\t\t\t\t\tstoreValue\t\t\t= 3;\r\n}\r\n\r\n/**message Header**/\r\nmessage Header {\r\n\t/**协议的版本号**/  //[default = 1]\r\n\toneof version_present {\r\n\t\tint32 \t\t\t\t\tversion\t\t\t\t= 1;\r\n\t}\r\n\r\n\r\n\t/**binlog/redolog 文件名**/\r\n\tstring\t\t\t\t\tlogfileName\t\t\t= 2;\r\n\r\n\t/**binlog/redolog 文件的偏移位置**/\r\n\tint64 \t\t\t\t\tlogfileOffset\t\t= 3;\r\n\r\n\t/**服务端serverId**/\r\n\tint64\t\t\t\tserverId         \t= 4;\r\n\r\n\t/** 变更数据的编码 **/\r\n\tstring\t\t\t\t\tserverenCode\t\t= 5;\r\n\r\n\t/**变更数据的执行时间 **/\r\n\tint64\t\t\t\t\texecuteTime\t\t\t= 6;\r\n\r\n\t/** 变更数据的来源**/ //[default = MYSQL]\r\n\toneof sourceType_present {\r\n\t\tType\t\t\t\t\tsourceType\t\t\t= 7;\r\n\t}\r\n\r\n\r\n\t/** 变更数据的schemaname**/\r\n\tstring\t\t\t\t\tschemaName\t\t\t= 8;\r\n\r\n\t/**变更数据的tablename**/\r\n\tstring\t\t\t\t\ttableName\t\t\t= 9;\r\n\r\n\t/**每个event的长度**/\r\n\tint64\t\t\t\t\teventLength         = 10;\r\n\r\n\t/**数据变更类型**/  // [default = UPDATE]\r\n\toneof eventType_present {\r\n\t\tEventType \t\t\t\teventType\t\t\t= 11;\r\n\t}\r\n\r\n\r\n\t/**预留扩展**/\r\n\trepeated Pair\t\t\t\t\tprops\t\t\t\t= 12;\r\n\r\n    /**当前事务的gitd**/\r\n\tstring                 gtid                = 13;\r\n}\r\n\r\n/**每个字段的数据结构**/\r\nmessage Column {\r\n\t/**字段下标**/\r\n\tint32\t\tindex\t\t\t= \t\t1;\r\n\r\n\t/**字段java中类型**/\r\n\tint32 \t\tsqlType\t\t\t= \t\t2;\r\n\r\n\t/**字段名称(忽略大小写)，在mysql中是没有的**/\r\n\tstring\t\tname\t\t\t=\t\t3;\r\n\r\n\t/**是否是主键**/\r\n\tbool \t\tisKey\t\t\t= \t\t4;\r\n\r\n\t/**如果EventType=UPDATE,用于标识这个字段值是否有修改**/\r\n\tbool\t\tupdated\t\t\t= \t\t5;\r\n\r\n\t/** 标识是否为空  **/ //[default = false]\r\n\toneof isNull_present {\r\n\t\tbool\t\tisNull\t\t\t= \t\t6;\r\n\t}\r\n\r\n\r\n\t/**预留扩展**/\r\n\trepeated Pair\t\tprops\t\t\t=\t\t7;\r\n\r\n\t/** 字段值,timestamp,Datetime是一个时间格式的文本 **/\r\n\tstring\t\tvalue\t\t\t= \t\t8;\r\n\r\n\t/** 对应数据对象原始长度 **/\r\n\tint32\t\tlength\t\t\t= \t\t9;\r\n\r\n\t/**字段mysql类型**/\r\n\tstring\t\tmysqlType\t\t= \t\t10;\r\n}\r\n\r\nmessage RowData {\r\n\r\n\t/** 字段信息，增量数据(修改前,删除前) **/\r\n\trepeated Column\t\t\tbeforeColumns  \t= \t\t1;\r\n\r\n\t/** 字段信息，增量数据(修改后,新增后)  **/\r\n\trepeated Column\t\t\tafterColumns\t= \t\t2;\r\n\r\n\t/**预留扩展**/\r\n\trepeated Pair\t\t\tprops\t\t\t=\t\t3;\r\n}\r\n\r\n/**message row 每行变更数据的数据结构**/\r\nmessage RowChange {\r\n\r\n\t/**tableId,由数据库产生**/\r\n\tint64\t \t\ttableId\t\t\t=\t\t1;\r\n\r\n\r\n\t/**数据变更类型**/ //[default = UPDATE]\r\n\toneof eventType_present {\r\n\t\tEventType \t\teventType\t\t= \t\t2;\r\n\t}\r\n\r\n\r\n\t/** 标识是否是ddl语句  **/ // [default = false]\r\n\toneof isDdl_present {\r\n\t\tbool\t\t\tisDdl\t\t\t= \t\t10;\r\n\t}\r\n\r\n\r\n\t/** ddl/query的sql语句  **/\r\n\tstring\t\t\tsql \t\t\t= \t\t11;\r\n\r\n\t/** 一次数据库变更可能存在多行  **/\r\n\trepeated RowData\t\trowDatas\t\t= \t\t12;\r\n\r\n\t/**预留扩展**/\r\n\trepeated Pair\t\t\tprops\t\t\t=\t\t13;\r\n\r\n\t/** ddl/query的schemaName，会存在跨库ddl，需要保留执行ddl的当前schemaName  **/\r\n\tstring\t\t\tddlSchemaName \t= \t\t14;\r\n}\r\n\r\n/**开始事务的一些信息**/\r\nmessage TransactionBegin{\r\n\r\n\t/**已废弃，请使用header里的executeTime**/\r\n\tint64\t\t\texecuteTime\t\t=\t\t1;\r\n\r\n\t/**已废弃，Begin里不提供事务id**/\r\n\tstring\t\t\ttransactionId\t=\t\t2;\r\n\r\n\t/**预留扩展**/\r\n\trepeated Pair\t\t\tprops\t\t\t=\t\t3;\r\n\r\n\t/**执行的thread Id**/\r\n\tint64\t\t\tthreadId\t\t=\t\t4;\r\n}\r\n\r\n/**结束事务的一些信息**/\r\nmessage TransactionEnd{\r\n\r\n\t/**已废弃，请使用header里的executeTime**/\r\n\tint64\t\t\texecuteTime\t\t=\t\t1;\r\n\r\n\t/**事务号**/\r\n\tstring\t\t\ttransactionId\t=\t\t2;\r\n\r\n\t/**预留扩展**/\r\n\trepeated Pair\t\t\tprops\t\t\t=\t\t3;\r\n}\r\n\r\n/**预留扩展**/\r\nmessage Pair{\r\n\tstring \t\tkey\t\t\t\t= \t\t\t1;\r\n\tstring \t\tvalue\t\t\t= \t\t\t2;\r\n}\r\n\r\n/**打散后的事件类型，主要用于标识事务的开始，变更数据，结束**/\r\nenum EntryType{\r\n\tENTRYTYPECOMPATIBLEPROTO2 = 0;\r\n\tTRANSACTIONBEGIN \t\t=\t\t1;\r\n\tROWDATA\t\t\t\t\t=\t\t2;\r\n\tTRANSACTIONEND\t\t\t=\t\t3;\r\n\t/** 心跳类型，内部使用，外部暂不可见，可忽略 **/\r\n\tHEARTBEAT\t\t\t\t=\t\t4;\r\n\tGTIDLOG                 =       5;\r\n}\r\n\r\n/** 事件类型 **/\r\nenum EventType {\r\n\tEVENTTYPECOMPATIBLEPROTO2 = 0;\r\n    INSERT \t\t= \t\t1;\r\n    UPDATE \t\t= \t\t2;\r\n    DELETE \t\t= \t\t3;\r\n    CREATE\t\t= \t\t4;\r\n    ALTER\t\t= \t\t5;\r\n    ERASE\t\t= \t\t6;\r\n    QUERY\t\t=\t\t7;\r\n    TRUNCATE\t=\t\t8;\r\n    RENAME \t\t= \t\t9;\r\n    /**CREATE INDEX**/\r\n    CINDEX\t\t= \t\t10;\r\n    DINDEX \t\t= \t\t11;\r\n    GTID        =       12;\r\n    /** XA **/\r\n    XACOMMIT    =       13;\r\n    XAROLLBACK  =\t\t14;\r\n    /** MASTER HEARTBEAT **/\r\n    MHEARTBEAT  =       15;\r\n}\r\n\r\n/**数据库类型**/\r\nenum Type {\r\n\tTYPECOMPATIBLEPROTO2 = 0;\r\n    ORACLE\t\t= \t\t1;\r\n    MYSQL\t\t= \t\t2;\r\n    PGSQL\t\t= \t\t3;\r\n}\r\n"
  },
  {
    "path": "protocol/src/main/java/com/alibaba/otter/canal/protocol/FlatMessage.java",
    "content": "package com.alibaba.otter.canal.protocol;\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * @author machengyuan 2018-9-13 下午10:31:14\n * @version 1.0.0\n */\npublic class FlatMessage implements Serializable {\n\n    private static final long         serialVersionUID = -3386650678735860050L;\n    private long                      id;\n    private String                    database;\n    private String                    table;\n    private List<String>              pkNames;\n    private Boolean                   isDdl;\n    private String                    type;\n    // binlog executeTime\n    private Long                      es;\n    // dml build timeStamp\n    private Long                      ts;\n    private String                    sql;\n    private Map<String, Integer>      sqlType;\n    private Map<String, String>       mysqlType;\n    private List<Map<String, String>> data;\n    private List<Map<String, String>> old;\n    private String                    gtid;\n\n    public FlatMessage() {\n    }\n\n    public FlatMessage(long id){\n        this.id = id;\n    }\n\n    public long getId() {\n        return id;\n    }\n\n    public void setId(long id) {\n        this.id = id;\n    }\n\n    public String getDatabase() {\n        return database;\n    }\n\n    public void setDatabase(String database) {\n        this.database = database;\n    }\n\n    public String getTable() {\n        return table;\n    }\n\n    public void setTable(String table) {\n        this.table = table;\n    }\n\n    public List<String> getPkNames() {\n        return pkNames;\n    }\n\n    public void addPkName(String pkName) {\n        if (this.pkNames == null) {\n            this.pkNames = new ArrayList<>();\n        }\n        this.pkNames.add(pkName);\n    }\n\n    public void setPkNames(List<String> pkNames) {\n        this.pkNames = pkNames;\n    }\n\n    public Boolean getIsDdl() {\n        return isDdl;\n    }\n\n    public void setIsDdl(Boolean isDdl) {\n        this.isDdl = isDdl;\n    }\n\n    public String getType() {\n        return type;\n    }\n\n    public void setType(String type) {\n        this.type = type;\n    }\n\n    public Long getTs() {\n        return ts;\n    }\n\n    public void setTs(Long ts) {\n        this.ts = ts;\n    }\n\n    public String getSql() {\n        return sql;\n    }\n\n    public void setSql(String sql) {\n        this.sql = sql;\n    }\n\n    public Map<String, Integer> getSqlType() {\n        return sqlType;\n    }\n\n    public void setSqlType(Map<String, Integer> sqlType) {\n        this.sqlType = sqlType;\n    }\n\n    public Map<String, String> getMysqlType() {\n        return mysqlType;\n    }\n\n    public void setMysqlType(Map<String, String> mysqlType) {\n        this.mysqlType = mysqlType;\n    }\n\n    public List<Map<String, String>> getData() {\n        return data;\n    }\n\n    public void setData(List<Map<String, String>> data) {\n        this.data = data;\n    }\n\n    public List<Map<String, String>> getOld() {\n        return old;\n    }\n\n    public void setOld(List<Map<String, String>> old) {\n        this.old = old;\n    }\n\n    public Long getEs() {\n        return es;\n    }\n\n    public void setEs(Long es) {\n        this.es = es;\n    }\n\n    public String getGtid() {\n        return gtid;\n    }\n\n    public void setGtid(String gtid) {\n        this.gtid = gtid;\n    }\n\n    @Override\n    public String toString() {\n        return \"FlatMessage [id=\" + id + \", database=\" + database + \", table=\" + table + \", isDdl=\" + isDdl + \", type=\"\n               + type + \", es=\" + es + \", ts=\" + ts + \", sql=\" + sql + \", sqlType=\" + sqlType + \", mysqlType=\"\n               + mysqlType + \", data=\" + data + \", old=\" + old + \", gtid=\" + gtid +\"]\";\n    }\n}\n"
  },
  {
    "path": "protocol/src/main/java/com/alibaba/otter/canal/protocol/Message.java",
    "content": "package com.alibaba.otter.canal.protocol;\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.apache.commons.lang.builder.ToStringBuilder;\n\nimport com.alibaba.otter.canal.common.utils.CanalToStringStyle;\nimport com.alibaba.otter.canal.protocol.CanalEntry.Entry;\nimport com.google.protobuf.ByteString;\n\n/**\n * @author zebin.xuzb @ 2012-6-19\n * @version 1.0.0\n */\npublic class Message implements Serializable {\n\n    private static final long      serialVersionUID = 1234034768477580009L;\n    private long                   id;\n    private List<CanalEntry.Entry> entries          = new ArrayList<>();\n    // row data for performance, see:\n    // https://github.com/alibaba/canal/issues/726\n    private boolean                raw              = true;\n    private List<ByteString>       rawEntries       = new ArrayList<>();\n\n    public Message(long id, List<Entry> entries){\n        this.id = id;\n        this.entries = entries == null ? new ArrayList<>() : entries;\n        this.raw = false;\n    }\n\n    public Message(long id, boolean raw, List entries){\n        this.id = id;\n        if (raw) {\n            this.rawEntries = entries == null ? new ArrayList<>() : entries;\n        } else {\n            this.entries = entries == null ? new ArrayList<>() : entries;\n        }\n        this.raw = raw;\n    }\n\n    public Message(long id){\n        this.id = id;\n    }\n\n    public long getId() {\n        return id;\n    }\n\n    public void setId(long id) {\n        this.id = id;\n    }\n\n    public List<Entry> getEntries() {\n        return entries;\n    }\n\n    public void setEntries(List<CanalEntry.Entry> entries) {\n        this.entries = entries;\n    }\n\n    public void addEntry(CanalEntry.Entry entry) {\n        this.entries.add(entry);\n    }\n\n    public void setRawEntries(List<ByteString> rawEntries) {\n        this.rawEntries = rawEntries;\n    }\n\n    public void addRawEntry(ByteString rawEntry) {\n        this.rawEntries.add(rawEntry);\n    }\n\n    public List<ByteString> getRawEntries() {\n        return rawEntries;\n    }\n\n    public boolean isRaw() {\n        return raw;\n    }\n\n    public void setRaw(boolean raw) {\n        this.raw = raw;\n    }\n\n    public String toString() {\n        return ToStringBuilder.reflectionToString(this, CanalToStringStyle.DEFAULT_STYLE);\n    }\n\n}\n"
  },
  {
    "path": "protocol/src/main/java/com/alibaba/otter/canal/protocol/SecurityUtil.java",
    "content": "package com.alibaba.otter.canal.protocol;\n\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * <pre>\n * 1、client\n *    stage1_hash = SHA1(明文密码).\n *    token = SHA1(scramble + SHA1(stage1_hash)) XOR stage1_hash\n * 2. server\n *    token = SHA1(token XOR SHA1(scramble + password))\n * 3. checktoken vs password\n * </pre>\n * \n * @author agapple 2019年8月26日 下午4:58:15\n * @since 1.1.4\n */\npublic class SecurityUtil {\n\n    private static char[]                  digits  = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c',\n            'd', 'e', 'f'                         };\n\n    private static Map<Character, Integer> rDigits = new HashMap<>(16);\n    static {\n        for (int i = 0; i < digits.length; ++i) {\n            rDigits.put(digits[i], i);\n        }\n    }\n\n    public static String md5String(String content) throws NoSuchAlgorithmException {\n        MessageDigest md = MessageDigest.getInstance(\"md5\");\n        byte[] bt = md.digest(content.getBytes());\n        if (null == bt || bt.length != 16) {\n            throw new IllegalArgumentException(\"md5 need\");\n        }\n        return byte2HexStr(bt);\n    }\n\n    public static final String scrambleGenPass(byte[] pass) throws NoSuchAlgorithmException {\n        MessageDigest md = MessageDigest.getInstance(\"SHA-1\");\n        byte[] pass1 = md.digest(pass);\n        md.reset();\n        byte[] pass2 = md.digest(pass1);\n        return SecurityUtil.byte2HexStr(pass2);\n    }\n\n    /**\n     * server auth check\n     */\n    public static final boolean scrambleServerAuth(byte[] token, byte[] pass, byte[] seed)\n                                                                                          throws NoSuchAlgorithmException {\n        MessageDigest md = MessageDigest.getInstance(\"SHA-1\");\n        md.update(seed);\n        byte[] pass1 = md.digest(pass);\n        for (int i = 0; i < pass1.length; i++) {\n            pass1[i] = (byte) (token[i] ^ pass1[i]);\n        }\n\n        md = MessageDigest.getInstance(\"SHA-1\");\n        byte[] pass2 = md.digest(pass1);\n        return Arrays.equals(pass, pass2);\n    }\n\n    public static final byte[] scramble411(byte[] pass, byte[] seed) throws NoSuchAlgorithmException {\n        MessageDigest md = MessageDigest.getInstance(\"SHA-1\");\n        byte[] pass1 = md.digest(pass);\n        md.reset();\n        byte[] pass2 = md.digest(pass1);\n        md.reset();\n        md.update(seed);\n        byte[] pass3 = md.digest(pass2);\n        for (int i = 0; i < pass3.length; i++) {\n            pass3[i] = (byte) (pass3[i] ^ pass1[i]);\n        }\n        return pass3;\n    }\n\n    /**\n     * bytes转换成十六进制字符串\n     */\n    public static String byte2HexStr(byte[] b) {\n        StringBuilder hs = new StringBuilder();\n        for (byte value : b) {\n            String hex = (Integer.toHexString(value & 0XFF));\n            if (hex.length() == 1) {\n                hs.append(\"0\" + hex);\n            } else {\n                hs.append(hex);\n            }\n        }\n\n        return hs.toString();\n    }\n\n    /**\n     * bytes转换成十六进制字符串\n     */\n    public static byte[] hexStr2Bytes(String src) {\n        if (src == null) {\n            return null;\n        }\n        int offset = 0;\n        int length = src.length();\n        if (length == 0) {\n            return new byte[0];\n        }\n\n        boolean odd = length << 31 == Integer.MIN_VALUE;\n        byte[] bs = new byte[odd ? (length + 1) >> 1 : length >> 1];\n        for (int i = offset, limit = offset + length; i < limit; ++i) {\n            char high, low;\n            if (i == offset && odd) {\n                high = '0';\n                low = src.charAt(i);\n            } else {\n                high = src.charAt(i);\n                low = src.charAt(++i);\n            }\n            int b;\n            switch (high) {\n                case '0':\n                    b = 0;\n                    break;\n                case '1':\n                    b = 0x10;\n                    break;\n                case '2':\n                    b = 0x20;\n                    break;\n                case '3':\n                    b = 0x30;\n                    break;\n                case '4':\n                    b = 0x40;\n                    break;\n                case '5':\n                    b = 0x50;\n                    break;\n                case '6':\n                    b = 0x60;\n                    break;\n                case '7':\n                    b = 0x70;\n                    break;\n                case '8':\n                    b = 0x80;\n                    break;\n                case '9':\n                    b = 0x90;\n                    break;\n                case 'a':\n                case 'A':\n                    b = 0xa0;\n                    break;\n                case 'b':\n                case 'B':\n                    b = 0xb0;\n                    break;\n                case 'c':\n                case 'C':\n                    b = 0xc0;\n                    break;\n                case 'd':\n                case 'D':\n                    b = 0xd0;\n                    break;\n                case 'e':\n                case 'E':\n                    b = 0xe0;\n                    break;\n                case 'f':\n                case 'F':\n                    b = 0xf0;\n                    break;\n                default:\n                    throw new IllegalArgumentException(\"illegal hex-string: \" + src);\n            }\n            switch (low) {\n                case '0':\n                    break;\n                case '1':\n                    b += 1;\n                    break;\n                case '2':\n                    b += 2;\n                    break;\n                case '3':\n                    b += 3;\n                    break;\n                case '4':\n                    b += 4;\n                    break;\n                case '5':\n                    b += 5;\n                    break;\n                case '6':\n                    b += 6;\n                    break;\n                case '7':\n                    b += 7;\n                    break;\n                case '8':\n                    b += 8;\n                    break;\n                case '9':\n                    b += 9;\n                    break;\n                case 'a':\n                case 'A':\n                    b += 10;\n                    break;\n                case 'b':\n                case 'B':\n                    b += 11;\n                    break;\n                case 'c':\n                case 'C':\n                    b += 12;\n                    break;\n                case 'd':\n                case 'D':\n                    b += 13;\n                    break;\n                case 'e':\n                case 'E':\n                    b += 14;\n                    break;\n                case 'f':\n                case 'F':\n                    b += 15;\n                    break;\n                default:\n                    throw new IllegalArgumentException(\"illegal hex-string: \" + src);\n            }\n            bs[(i - offset) >> 1] = (byte) b;\n        }\n        return bs;\n    }\n\n}\n"
  },
  {
    "path": "protocol/src/main/java/com/alibaba/otter/canal/protocol/exception/CanalClientException.java",
    "content": "package com.alibaba.otter.canal.protocol.exception;\n\nimport org.apache.commons.lang.exception.NestableRuntimeException;\n\n/**\n * @author zebin.xuzb @ 2012-6-20\n * @version 1.0.0\n */\npublic class CanalClientException extends NestableRuntimeException {\n\n    private static final long serialVersionUID = -7545341502620139031L;\n\n    public CanalClientException(String errorCode){\n        super(errorCode);\n    }\n\n    public CanalClientException(String errorCode, Throwable cause){\n        super(errorCode, cause);\n    }\n\n    public CanalClientException(String errorCode, String errorDesc){\n        super(errorCode + \":\" + errorDesc);\n    }\n\n    public CanalClientException(String errorCode, String errorDesc, Throwable cause){\n        super(errorCode + \":\" + errorDesc, cause);\n    }\n\n    public CanalClientException(Throwable cause){\n        super(cause);\n    }\n}\n"
  },
  {
    "path": "protocol/src/main/java/com/alibaba/otter/canal/protocol/position/EntryPosition.java",
    "content": "package com.alibaba.otter.canal.protocol.position;\n\n/**\n * 数据库对象的唯一标示\n * \n * @author jianghang 2012-6-14 下午09:20:07\n * @version 1.0.0\n */\npublic class EntryPosition extends TimePosition {\n\n    private static final long serialVersionUID      = 81432665066427482L;\n    public static final int   EVENTIDENTITY_SEGMENT = 3;\n    public static final char  EVENTIDENTITY_SPLIT   = (char) 5;\n\n    private boolean           included              = false;\n    private String            journalName;\n    private Long              position;\n    // add by agapple at 2016-06-28\n    private Long              serverId              = null;              // 记录一下位点对应的serverId\n    private String            gtid                  = null;\n\n    public EntryPosition(){\n        super(null);\n    }\n\n    public EntryPosition(Long timestamp){\n        this(null, null, timestamp);\n    }\n\n    public EntryPosition(String journalName, Long position){\n        this(journalName, position, null);\n    }\n\n    public EntryPosition(String journalName, Long position, Long timestamp){\n        super(timestamp);\n        this.journalName = journalName;\n        this.position = position;\n    }\n\n    public EntryPosition(String journalName, Long position, Long timestamp, Long serverId){\n        this(journalName, position, timestamp);\n        this.serverId = serverId;\n    }\n\n    public String getJournalName() {\n        return journalName;\n    }\n\n    public void setJournalName(String journalName) {\n        this.journalName = journalName;\n    }\n\n    public Long getPosition() {\n        return position;\n    }\n\n    public void setPosition(Long position) {\n        this.position = position;\n    }\n\n    public boolean isIncluded() {\n        return included;\n    }\n\n    public void setIncluded(boolean included) {\n        this.included = included;\n    }\n\n    public Long getServerId() {\n        return serverId;\n    }\n\n    public void setServerId(Long serverId) {\n        this.serverId = serverId;\n    }\n\n    public String getGtid() {\n        return gtid;\n    }\n\n    public void setGtid(String gtid) {\n        this.gtid = gtid;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = super.hashCode();\n        result = prime * result + ((journalName == null) ? 0 : journalName.hashCode());\n        result = prime * result + ((position == null) ? 0 : position.hashCode());\n        // 手写equals，自动生成时需注意\n        result = prime * result + ((timestamp == null) ? 0 : timestamp.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!super.equals(obj)) {\n            return false;\n        }\n        if (!(obj instanceof EntryPosition)) {\n            return false;\n        }\n        EntryPosition other = (EntryPosition) obj;\n        if (journalName == null) {\n            if (other.journalName != null) {\n                return false;\n            }\n        } else if (!journalName.equals(other.journalName)) {\n            return false;\n        }\n        if (position == null) {\n            if (other.position != null) {\n                return false;\n            }\n        } else if (!position.equals(other.position)) {\n            return false;\n        }\n        // 手写equals，自动生成时需注意\n        if (timestamp == null) {\n            if (other.timestamp != null) {\n                return false;\n            }\n        } else if (!timestamp.equals(other.timestamp)) {\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * {@inheritDoc}\n     * \n     * @see java.lang.Comparable#compareTo(java.lang.Object)\n     */\n    public int compareTo(EntryPosition o) {\n        final int val = journalName.compareTo(o.journalName);\n\n        if (val == 0) {\n            return (int) (position - o.position);\n        }\n        return val;\n    }\n\n}\n"
  },
  {
    "path": "protocol/src/main/java/com/alibaba/otter/canal/protocol/position/LogIdentity.java",
    "content": "package com.alibaba.otter.canal.protocol.position;\n\nimport java.net.InetSocketAddress;\n\nimport org.apache.commons.lang.builder.ToStringBuilder;\n\nimport com.alibaba.otter.canal.common.utils.CanalToStringStyle;\n\n/**\n * @author jianghang 2012-6-21 上午10:52:02\n * @version 1.0.0\n */\npublic class LogIdentity extends Position {\n\n    private static final long serialVersionUID = 5530225131455662581L;\n    private InetSocketAddress sourceAddress;                          // 链接服务器的地址\n    private Long              slaveId;                                // 对应的slaveId\n\n    public LogIdentity(){\n    }\n\n    public LogIdentity(InetSocketAddress sourceAddress, Long slaveId){\n        this.sourceAddress = sourceAddress;\n        this.slaveId = slaveId;\n    }\n\n    public InetSocketAddress getSourceAddress() {\n        return sourceAddress;\n    }\n\n    public void setSourceAddress(InetSocketAddress sourceAddress) {\n        this.sourceAddress = sourceAddress;\n    }\n\n    public Long getSlaveId() {\n        return slaveId;\n    }\n\n    public void setSlaveId(Long slaveId) {\n        this.slaveId = slaveId;\n    }\n\n    @Override\n    public String toString() {\n        return ToStringBuilder.reflectionToString(this, CanalToStringStyle.DEFAULT_STYLE);\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + ((slaveId == null) ? 0 : slaveId.hashCode());\n        result = prime * result + ((sourceAddress == null) ? 0 : sourceAddress.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) return true;\n        if (obj == null) return false;\n        if (getClass() != obj.getClass()) return false;\n        LogIdentity other = (LogIdentity) obj;\n        if (slaveId == null) {\n            if (other.slaveId != null) return false;\n        } else if (slaveId.longValue() != (other.slaveId.longValue())) return false;\n        if (sourceAddress == null) {\n            if (other.sourceAddress != null) return false;\n        } else if (!sourceAddress.equals(other.sourceAddress)) return false;\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "protocol/src/main/java/com/alibaba/otter/canal/protocol/position/LogPosition.java",
    "content": "package com.alibaba.otter.canal.protocol.position;\n\n/**\n * 基于mysql/oracle log位置标示\n * \n * @author jianghang 2012-6-21 上午10:52:41\n * @version 1.0.0\n */\npublic class LogPosition extends Position {\n\n    private static final long serialVersionUID = 3875012010277005819L;\n    private LogIdentity       identity;\n    private EntryPosition     postion;\n\n    public LogIdentity getIdentity() {\n        return identity;\n    }\n\n    public void setIdentity(LogIdentity identity) {\n        this.identity = identity;\n    }\n\n    public EntryPosition getPostion() {\n        return postion;\n    }\n\n    public void setPostion(EntryPosition postion) {\n        this.postion = postion;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + ((identity == null) ? 0 : identity.hashCode());\n        result = prime * result + ((postion == null) ? 0 : postion.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (!(obj instanceof LogPosition)) {\n            return false;\n        }\n        LogPosition other = (LogPosition) obj;\n        if (identity == null) {\n            if (other.identity != null) {\n                return false;\n            }\n        } else if (!identity.equals(other.identity)) {\n            return false;\n        }\n        if (postion == null) {\n            if (other.postion != null) {\n                return false;\n            }\n        } else if (!postion.equals(other.postion)) {\n            return false;\n        }\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "protocol/src/main/java/com/alibaba/otter/canal/protocol/position/MetaqPosition.java",
    "content": "package com.alibaba.otter.canal.protocol.position;\n\n/**\n * @author zebin.xuzb 2012-11-3 上午12:23:01\n * @since 1.0.0\n */\npublic class MetaqPosition extends Position {\n\n    private static final long serialVersionUID = -8673508769040569273L;\n\n    private String            topic;\n    private String            msgNewId;\n    private long              offset;\n\n    public MetaqPosition(String topic, String msgNewId, long offset){\n        super();\n        this.topic = topic;\n        this.msgNewId = msgNewId;\n        this.offset = offset;\n    }\n\n    public String getTopic() {\n        return topic;\n    }\n\n    public String getMsgNewId() {\n        return msgNewId;\n    }\n\n    public void setTopic(String topic) {\n        this.topic = topic;\n    }\n\n    public void setMsgNewId(String msgNewId) {\n        this.msgNewId = msgNewId;\n    }\n\n    public long getOffset() {\n        return offset;\n    }\n\n    public void setOffset(long offset) {\n        this.offset = offset;\n    }\n\n}\n"
  },
  {
    "path": "protocol/src/main/java/com/alibaba/otter/canal/protocol/position/Position.java",
    "content": "package com.alibaba.otter.canal.protocol.position;\n\nimport java.io.Serializable;\n\nimport org.apache.commons.lang.builder.ToStringBuilder;\n\nimport com.alibaba.otter.canal.common.utils.CanalToStringStyle;\n\n/**\n * 事件唯一标示\n */\npublic abstract class Position implements Serializable {\n\n    private static final long serialVersionUID = 2332798099928474975L;\n\n    public String toString() {\n        return ToStringBuilder.reflectionToString(this, CanalToStringStyle.DEFAULT_STYLE);\n    }\n\n}\n"
  },
  {
    "path": "protocol/src/main/java/com/alibaba/otter/canal/protocol/position/PositionRange.java",
    "content": "package com.alibaba.otter.canal.protocol.position;\n\nimport java.io.Serializable;\n\nimport org.apache.commons.lang.builder.ToStringBuilder;\n\nimport com.alibaba.otter.canal.common.utils.CanalToStringStyle;\n\n/**\n * 描述一个position范围\n * \n * @author jianghang 2012-7-10 下午05:28:38\n * @version 1.0.0\n */\npublic class PositionRange<T extends Position> implements Serializable {\n\n    private static final long serialVersionUID = -9162037079815694784L;\n    private T                 start;\n    // add by ljh at 2012-09-05，用于记录一个可被ack的位置，保证每次提交到cursor中的位置是一个完整事务的结束\n    private T                 ack;\n    private T                 end;\n    // add by ljh at 2019-06-25，用于精确记录ringbuffer中的位点\n    private Long              endSeq           = -1L;\n\n    public PositionRange(){\n    }\n\n    public PositionRange(T start, T end){\n        this.start = start;\n        this.end = end;\n    }\n\n    public T getStart() {\n        return start;\n    }\n\n    public void setStart(T start) {\n        this.start = start;\n    }\n\n    public T getEnd() {\n        return end;\n    }\n\n    public void setEnd(T end) {\n        this.end = end;\n    }\n\n    public T getAck() {\n        return ack;\n    }\n\n    public void setAck(T ack) {\n        this.ack = ack;\n    }\n\n    public Long getEndSeq() {\n        return endSeq;\n    }\n\n    public void setEndSeq(Long endSeq) {\n        this.endSeq = endSeq;\n    }\n\n    @Override\n    public String toString() {\n        return ToStringBuilder.reflectionToString(this, CanalToStringStyle.DEFAULT_STYLE);\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + ((ack == null) ? 0 : ack.hashCode());\n        result = prime * result + ((end == null) ? 0 : end.hashCode());\n        result = prime * result + ((start == null) ? 0 : start.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (!(obj instanceof PositionRange)) {\n            return false;\n        }\n        PositionRange other = (PositionRange) obj;\n        if (ack == null) {\n            if (other.ack != null) {\n                return false;\n            }\n        } else if (!ack.equals(other.ack)) {\n            return false;\n        }\n        if (end == null) {\n            if (other.end != null) {\n                return false;\n            }\n        } else if (!end.equals(other.end)) {\n            return false;\n        }\n        if (start == null) {\n            if (other.start != null) {\n                return false;\n            }\n        } else if (!start.equals(other.start)) {\n            return false;\n        }\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "protocol/src/main/java/com/alibaba/otter/canal/protocol/position/TimePosition.java",
    "content": "package com.alibaba.otter.canal.protocol.position;\n\n/**\n * 基于时间的位置，position数据不唯一\n * \n * @author jianghang 2012-6-14 下午09:22:04\n * @version 1.0.0\n */\npublic class TimePosition extends Position {\n\n    private static final long serialVersionUID = 6185261261064226380L;\n    protected Long            timestamp;\n\n    public TimePosition(Long timestamp){\n        this.timestamp = timestamp;\n    }\n\n    public Long getTimestamp() {\n        return timestamp;\n    }\n\n    public void setTimestamp(Long timestamp) {\n        this.timestamp = timestamp;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + ((timestamp == null) ? 0 : timestamp.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (!(obj instanceof TimePosition)) {\n            return false;\n        }\n        TimePosition other = (TimePosition) obj;\n        if (timestamp == null) {\n            if (other.timestamp != null) {\n                return false;\n            }\n        } else if (!timestamp.equals(other.timestamp)) {\n            return false;\n        }\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "protocol/src/test/java/com/alibaba/otter/canal/protocol/ProtocolTest.java",
    "content": "package com.alibaba.otter.canal.protocol;\n\nimport com.alibaba.otter.canal.protocol.CanalEntry.Entry;\nimport com.alibaba.otter.canal.protocol.CanalEntry.EntryType;\nimport com.alibaba.otter.canal.protocol.CanalEntry.Header;\nimport com.alibaba.otter.canal.protocol.CanalPacket.Compression;\nimport com.alibaba.otter.canal.protocol.CanalPacket.Messages;\nimport com.alibaba.otter.canal.protocol.CanalPacket.Packet;\nimport com.alibaba.otter.canal.protocol.CanalPacket.PacketType;\nimport com.alibaba.otter.canal.protocol.Message;\nimport com.alibaba.otter.canal.protocol.exception.CanalClientException;\nimport com.google.protobuf.ByteString;\nimport com.google.protobuf.CodedOutputStream;\nimport com.google.protobuf.WireFormat;\nimport org.junit.Test;\n\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class ProtocolTest {\n\n    @Test(expected = CanalClientException.class)\n    public void testSimple() throws IOException {\n        Header.Builder headerBuilder = Header.newBuilder();\n        headerBuilder.setLogfileName(\"mysql-bin.000001\");\n        headerBuilder.setLogfileOffset(1024);\n        headerBuilder.setExecuteTime(1024);\n        Entry.Builder entryBuilder = Entry.newBuilder();\n        entryBuilder.setHeader(headerBuilder.build());\n        entryBuilder.setEntryType(EntryType.ROWDATA);\n        Entry entry = entryBuilder.build();\n        Message message = new Message(3, true, Arrays.asList(entry.toByteString()));\n\n        byte[] body = buildData(message);\n        Packet packet = Packet.parseFrom(body);\n        switch (packet.getType()) {\n            case MESSAGES: {\n                if (!packet.getCompression().equals(Compression.NONE)) {\n                    throw new CanalClientException(\"compression is not supported in this connector\");\n                }\n\n                Messages messages = Messages.parseFrom(packet.getBody());\n                Message result = new Message(messages.getBatchId());\n                for (ByteString byteString : messages.getMessagesList()) {\n                    result.addEntry(Entry.parseFrom(byteString));\n                }\n\n                System.out.println(result);\n                break;\n            }\n            default: {\n                throw new CanalClientException(\"unexpected packet type: \" + packet.getType());\n            }\n        }\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    private byte[] buildData(Message message) throws IOException {\n        List<ByteString> rowEntries = message.getRawEntries();\n        // message size\n        int messageSize = 0;\n        messageSize += com.google.protobuf.CodedOutputStream.computeInt64Size(1, message.getId());\n\n        int dataSize = 0;\n        for (ByteString rowEntry : rowEntries) {\n            dataSize += CodedOutputStream.computeBytesSizeNoTag(rowEntry);\n        }\n        messageSize += dataSize;\n        messageSize += 1 * rowEntries.size();\n        // packet size\n        int size = 0;\n        size += com.google.protobuf.CodedOutputStream.computeEnumSize(3, PacketType.MESSAGES.getNumber());\n        size += com.google.protobuf.CodedOutputStream.computeTagSize(5)\n                + com.google.protobuf.CodedOutputStream.computeRawVarint32Size(messageSize) + messageSize;\n        // TODO recyle bytes[]\n        byte[] body = new byte[size];\n        CodedOutputStream output = CodedOutputStream.newInstance(body);\n        output.writeEnum(3, PacketType.MESSAGES.getNumber());\n\n        output.writeTag(5, WireFormat.WIRETYPE_LENGTH_DELIMITED);\n        output.writeRawVarint32(messageSize);\n        // message\n        output.writeInt64(1, message.getId());\n        for (ByteString rowEntry : rowEntries) {\n            output.writeBytes(2, rowEntry);\n        }\n        output.checkNoSpaceLeft();\n\n        return body;\n    }\n}\n"
  },
  {
    "path": "protocol/src/test/java/com/alibaba/otter/canal/protocol/SecurityUtilTest.java",
    "content": "package com.alibaba.otter.canal.protocol;\n\nimport java.security.NoSuchAlgorithmException;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.protocol.SecurityUtil;\n\npublic class SecurityUtilTest {\n\n    @Test\n    public void testSimple() throws NoSuchAlgorithmException {\n        byte[] seed = { 1, 2, 3, 4, 5, 6, 7, 8 };\n        // String str = \"e3619321c1a937c46a0d8bd1dac39f93b27d4458\"; // canal\n        // passwd\n        String str = SecurityUtil.scrambleGenPass(\"canal\".getBytes());\n        byte[] client = SecurityUtil.scramble411(\"canal\".getBytes(), seed);\n        boolean check = SecurityUtil.scrambleServerAuth(client, SecurityUtil.hexStr2Bytes(str), seed);\n        Assert.assertTrue(check);\n    }\n}\n"
  },
  {
    "path": "server/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>com.alibaba.otter</groupId>\n\t\t<artifactId>canal</artifactId>\n\t\t<version>1.1.9-SNAPSHOT</version>\n\t\t<relativePath>../pom.xml</relativePath>\n\t</parent>\n\t<artifactId>canal.server</artifactId>\n\t<packaging>jar</packaging>\n\t<name>canal server module for otter ${project.version}</name>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.instance.core</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.instance.spring</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.instance.manager</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>connector.core</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.commons</groupId>\n\t\t\t<artifactId>commons-lang3</artifactId>\n\t\t</dependency>\n\t\t\n\t\t<!-- test dependency -->\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "server/src/main/java/com/alibaba/otter/canal/admin/CanalAdmin.java",
    "content": "package com.alibaba.otter.canal.admin;\n\n/**\n * Canal Admin动态管理接口\n * \n * @author agapple 2019年8月24日 下午9:45:49\n * @since 1.1.4\n */\npublic interface CanalAdmin {\n\n    /**\n     * 校验账号密码\n     */\n    boolean auth(String user, String passwd, byte[] seed);\n\n    /**\n     * 获取Canal Server状态, 1代表运行/0代表不运行\n     *\n     * @return 状态代码\n     */\n    boolean check();\n\n    /**\n     * 启动Canal Server\n     *\n     * @return 是否成功\n     */\n    boolean start();\n\n    /**\n     * 停止Canal Server\n     *\n     * @return 是否成功\n     */\n    boolean stop();\n\n    /**\n     * 重启Canal Server\n     *\n     * @return 是否成功\n     */\n    boolean restart();\n\n    /**\n     * 获取所有当前节点下运行中的实例\n     *\n     * @return 实例信息\n     */\n    String getRunningInstances();\n\n    /**\n     * 通过实例名检查\n     * \n     * @param destination\n     * @return\n     */\n    boolean checkInstance(String destination);\n\n    /**\n     * 通过实例名启动实例\n     *\n     * @param destination 实例名\n     * @return 是否成功\n     */\n    boolean startInstance(String destination);\n\n    /**\n     * 通过实例名关闭实例\n     *\n     * @param destination 实例名\n     * @return 是否成功\n     */\n    boolean stopInstance(String destination);\n\n    /**\n     * 通过实例名释放,主要针对cluster模式有效(通知当前主机释放instance运行交给其他人来抢占)\n     *\n     * @param destination 实例名\n     * @return 是否成功\n     */\n    boolean releaseInstance(String destination);\n\n    /**\n     * 通过实例名重启实例\n     *\n     * @param destination 实例名\n     * @return 是否成功\n     */\n    boolean restartInstance(String destination);\n\n    /**\n     * 获取Canal Server日志列表\n     *\n     * @return 日志信息\n     */\n    String listCanalLog();\n\n    /**\n     * 获取Canal Server日志\n     *\n     * @return 日志信息\n     */\n    String canalLog(int lines);\n\n    /**\n     * 获取Instance的机器日志列表\n     * \n     * @param destination\n     */\n    String listInstanceLog(String destination);\n\n    /**\n     * 通过实例名获取实例日志\n     *\n     * @return 日志信息\n     */\n    String instanceLog(String destination, String fileName, int lines);\n}\n"
  },
  {
    "path": "server/src/main/java/com/alibaba/otter/canal/admin/handler/ClientAuthenticationHandler.java",
    "content": "package com.alibaba.otter.canal.admin.handler;\n\nimport java.util.concurrent.TimeUnit;\n\nimport org.jboss.netty.buffer.ChannelBuffer;\nimport org.jboss.netty.channel.ChannelHandlerContext;\nimport org.jboss.netty.channel.MessageEvent;\nimport org.jboss.netty.channel.SimpleChannelHandler;\nimport org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler;\nimport org.jboss.netty.handler.timeout.IdleStateEvent;\nimport org.jboss.netty.handler.timeout.IdleStateHandler;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.slf4j.helpers.MessageFormatter;\n\nimport com.alibaba.otter.canal.admin.CanalAdmin;\nimport com.alibaba.otter.canal.admin.netty.AdminNettyUtils;\nimport com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth;\nimport com.alibaba.otter.canal.protocol.AdminPacket.Packet;\nimport com.alibaba.otter.canal.server.netty.NettyUtils;\n\n/**\n * 客户端身份认证处理\n * \n * @author agapple 2019年8月24日 下午10:58:53\n * @since 1.1.4\n */\npublic class ClientAuthenticationHandler extends SimpleChannelHandler {\n\n    private static final Logger logger                                  = LoggerFactory.getLogger(ClientAuthenticationHandler.class);\n    private final int           SUPPORTED_VERSION                       = 3;\n    private final int           defaultSubscriptorDisconnectIdleTimeout = 60 * 60 * 1000;\n    private CanalAdmin          canalAdmin;\n    private byte[]              seed;\n\n    public ClientAuthenticationHandler(){\n\n    }\n\n    public ClientAuthenticationHandler(CanalAdmin canalAdmin){\n        this.canalAdmin = canalAdmin;\n    }\n\n    public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) throws Exception {\n        ChannelBuffer buffer = (ChannelBuffer) e.getMessage();\n        final Packet packet = Packet.parseFrom(buffer.readBytes(buffer.readableBytes()).array());\n        switch (packet.getVersion()) {\n            case SUPPORTED_VERSION:\n            default:\n                final ClientAuth clientAuth = ClientAuth.parseFrom(packet.getBody());\n                if (seed == null) {\n                    byte[] errorBytes = AdminNettyUtils.errorPacket(300,\n                        MessageFormatter.format(\"auth failed for seed is null\", clientAuth.getUsername()).getMessage());\n                    AdminNettyUtils.write(ctx.getChannel(), errorBytes);\n                }\n\n                if (!canalAdmin.auth(clientAuth.getUsername(), clientAuth.getPassword().toStringUtf8(), seed)) {\n                    byte[] errorBytes = AdminNettyUtils.errorPacket(300,\n                        MessageFormatter.format(\"auth failed for user:{}\", clientAuth.getUsername()).getMessage());\n                    AdminNettyUtils.write(ctx.getChannel(), errorBytes);\n                }\n\n                byte[] ackBytes = AdminNettyUtils.ackPacket();\n                AdminNettyUtils.write(ctx.getChannel(), ackBytes, future -> {\n                    logger.info(\"remove unused channel handlers after authentication is done successfully.\");\n                    ctx.getPipeline().remove(HandshakeInitializationHandler.class.getName());\n                    ctx.getPipeline().remove(ClientAuthenticationHandler.class.getName());\n\n                    int readTimeout = defaultSubscriptorDisconnectIdleTimeout;\n                    int writeTimeout = defaultSubscriptorDisconnectIdleTimeout;\n                    if (clientAuth.getNetReadTimeout() > 0) {\n                        readTimeout = clientAuth.getNetReadTimeout();\n                    }\n                    if (clientAuth.getNetWriteTimeout() > 0) {\n                        writeTimeout = clientAuth.getNetWriteTimeout();\n                    }\n                    // fix bug: soTimeout parameter's unit from connector is\n                    // millseconds.\n                    IdleStateHandler idleStateHandler = new IdleStateHandler(NettyUtils.hashedWheelTimer,\n                        readTimeout,\n                        writeTimeout,\n                        0,\n                        TimeUnit.MILLISECONDS);\n                    ctx.getPipeline().addBefore(SessionHandler.class.getName(),\n                        IdleStateHandler.class.getName(),\n                        idleStateHandler);\n\n                    IdleStateAwareChannelHandler idleStateAwareChannelHandler = new IdleStateAwareChannelHandler() {\n\n                        public void channelIdle(ChannelHandlerContext ctx1, IdleStateEvent e1) throws Exception {\n                            logger.warn(\"channel:{} idle timeout exceeds, close channel to save server resources...\",\n                                ctx1.getChannel());\n                            ctx1.getChannel().close();\n                        }\n\n                    };\n                    ctx.getPipeline().addBefore(SessionHandler.class.getName(),\n                        IdleStateAwareChannelHandler.class.getName(),\n                        idleStateAwareChannelHandler);\n                });\n                break;\n        }\n    }\n\n    public void setCanalAdmin(CanalAdmin canalAdmin) {\n        this.canalAdmin = canalAdmin;\n    }\n\n    public void setSeed(byte[] seed) {\n        this.seed = seed;\n    }\n\n}\n"
  },
  {
    "path": "server/src/main/java/com/alibaba/otter/canal/admin/handler/HandshakeInitializationHandler.java",
    "content": "package com.alibaba.otter.canal.admin.handler;\n\nimport org.jboss.netty.channel.ChannelHandlerContext;\nimport org.jboss.netty.channel.ChannelStateEvent;\nimport org.jboss.netty.channel.SimpleChannelHandler;\nimport org.jboss.netty.channel.group.ChannelGroup;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.admin.netty.AdminNettyUtils;\nimport com.alibaba.otter.canal.protocol.AdminPacket;\nimport com.alibaba.otter.canal.protocol.AdminPacket.Handshake;\nimport com.alibaba.otter.canal.protocol.AdminPacket.Packet;\nimport com.google.protobuf.ByteString;\n\n/**\n * handshake交互\n * \n * @author agapple 2019年8月24日 下午10:58:34\n * @since 1.1.4\n */\npublic class HandshakeInitializationHandler extends SimpleChannelHandler {\n\n    // support to maintain socket channel.\n    private ChannelGroup childGroups;\n\n    public HandshakeInitializationHandler(ChannelGroup childGroups){\n        this.childGroups = childGroups;\n    }\n\n    private static final Logger logger = LoggerFactory.getLogger(HandshakeInitializationHandler.class);\n\n    public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {\n        // add new socket channel in channel container, used to manage sockets.\n        if (childGroups != null) {\n            childGroups.add(ctx.getChannel());\n        }\n\n        final byte[] seed = org.apache.commons.lang3.RandomUtils.nextBytes(8);\n        byte[] body = Packet.newBuilder()\n            .setType(AdminPacket.PacketType.HANDSHAKE)\n            .setVersion(AdminNettyUtils.VERSION)\n            .setBody(Handshake.newBuilder().setSeeds(ByteString.copyFrom(seed)).build().toByteString())\n            .build()\n            .toByteArray();\n\n        AdminNettyUtils.write(ctx.getChannel(), body, future -> {\n            logger.info(\"remove unused channel handlers after authentication is done successfully.\");\n            ctx.getPipeline().get(HandshakeInitializationHandler.class.getName());\n            ClientAuthenticationHandler handler = (ClientAuthenticationHandler) ctx.getPipeline()\n                .get(ClientAuthenticationHandler.class.getName());\n            handler.setSeed(seed);\n        });\n        logger.info(\"send handshake initialization packet to : {}\", ctx.getChannel());\n    }\n}\n"
  },
  {
    "path": "server/src/main/java/com/alibaba/otter/canal/admin/handler/SessionHandler.java",
    "content": "package com.alibaba.otter.canal.admin.handler;\n\nimport org.apache.commons.lang.exception.ExceptionUtils;\nimport org.jboss.netty.buffer.ChannelBuffer;\nimport org.jboss.netty.channel.*;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.admin.CanalAdmin;\nimport com.alibaba.otter.canal.admin.netty.AdminNettyUtils;\nimport com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin;\nimport com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin;\nimport com.alibaba.otter.canal.protocol.AdminPacket.Packet;\nimport com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin;\n\npublic class SessionHandler extends SimpleChannelHandler {\n\n    private static final Logger logger = LoggerFactory.getLogger(SessionHandler.class);\n    private CanalAdmin          canalAdmin;\n\n    public SessionHandler(){\n    }\n\n    public SessionHandler(CanalAdmin canalAdmin){\n        this.canalAdmin = canalAdmin;\n    }\n\n    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {\n        ChannelBuffer buffer = (ChannelBuffer) e.getMessage();\n        Packet packet = Packet.parseFrom(buffer.readBytes(buffer.readableBytes()).array());\n        try {\n            switch (packet.getType()) {\n                case SERVER:\n                    ServerAdmin sa = ServerAdmin.parseFrom(packet.getBody());\n                    logger.info(\"received {} SERVER request in session handler...\", sa.getAction());\n                    byte[] svrResp = null;\n                    switch (sa.getAction()) {\n                        case \"check\":\n                            svrResp = AdminNettyUtils.ackPacket(canalAdmin.check() ? \"1\" : \"0\");\n                            break;\n                        case \"start\":\n                            svrResp = AdminNettyUtils.ackPacket(canalAdmin.start() ? \"1\" : \"0\");\n                            break;\n                        case \"stop\":\n                            svrResp = AdminNettyUtils.ackPacket(canalAdmin.stop() ? \"1\" : \"0\");\n                            break;\n                        case \"restart\":\n                            svrResp = AdminNettyUtils.ackPacket(canalAdmin.restart() ? \"1\" : \"0\");\n                            break;\n                        case \"list\":\n                            svrResp = AdminNettyUtils.ackPacket(canalAdmin.getRunningInstances());\n                            break;\n                        default:\n                            svrResp = AdminNettyUtils.errorPacket(301,\n                                \"ServerAdmin action: \" + sa.getAction() + \"  is unknown\");\n                            break;\n                    }\n                    AdminNettyUtils.write(ctx.getChannel(), svrResp);\n                    break;\n\n                case INSTANCE:\n                    InstanceAdmin ia = InstanceAdmin.parseFrom(packet.getBody());\n                    logger.info(\"received {} INSTANCE request in session handler...\", ia.getAction());\n                    byte[] instResp = null;\n                    switch (ia.getAction()) {\n                        case \"check\":\n                            instResp = AdminNettyUtils\n                                .ackPacket(canalAdmin.checkInstance(ia.getDestination()) ? \"1\" : \"0\");\n                            break;\n                        case \"start\":\n                            instResp = AdminNettyUtils\n                                .ackPacket(canalAdmin.startInstance(ia.getDestination()) ? \"1\" : \"0\");\n                            break;\n                        case \"stop\":\n                            instResp = AdminNettyUtils\n                                .ackPacket(canalAdmin.stopInstance(ia.getDestination()) ? \"1\" : \"0\");\n                            break;\n                        case \"release\":\n                            instResp = AdminNettyUtils\n                                .ackPacket(canalAdmin.releaseInstance(ia.getDestination()) ? \"1\" : \"0\");\n                            break;\n                        case \"restart\":\n                            instResp = AdminNettyUtils\n                                .ackPacket(canalAdmin.restartInstance(ia.getDestination()) ? \"1\" : \"0\");\n                            break;\n                        default:\n                            instResp = AdminNettyUtils.errorPacket(301,\n                                \"InstanceAdmin action: \" + ia.getAction() + \" is unknown\");\n                            break;\n                    }\n                    AdminNettyUtils.write(ctx.getChannel(), instResp);\n                    break;\n\n                case LOG:\n                    LogAdmin la = LogAdmin.parseFrom(packet.getBody());\n                    logger.info(\"received {} LOG request in session handler...\", la.getType());\n                    byte[] logResp = null;\n                    switch (la.getType()) {\n                        case \"server\":\n                            if (\"list\".equalsIgnoreCase(la.getAction())) {\n                                logResp = AdminNettyUtils.ackPacket(canalAdmin.listCanalLog());\n                            } else {\n                                logResp = AdminNettyUtils.ackPacket(canalAdmin.canalLog(la.getCount()));\n                            }\n                            break;\n                        case \"instance\":\n                            if (\"list\".equalsIgnoreCase(la.getAction())) {\n                                logResp = AdminNettyUtils.ackPacket(canalAdmin.listInstanceLog(la.getDestination()));\n                            } else {\n                                logResp = AdminNettyUtils.ackPacket(\n                                    canalAdmin.instanceLog(la.getDestination(), la.getFile(), la.getCount()));\n                            }\n                            break;\n                        default:\n                            logResp = AdminNettyUtils.errorPacket(301,\n                                \"LogAdmin type: \" + la.getType() + \" is unknown\");\n                            break;\n                    }\n                    AdminNettyUtils.write(ctx.getChannel(), logResp);\n                    break;\n\n                default:\n                    logResp = AdminNettyUtils.errorPacket(300,\n                        \"packet type: \" + packet.getType() + \" is NOT supported!\");\n                    AdminNettyUtils.write(ctx.getChannel(), logResp);\n                    break;\n            }\n\n        } catch (Throwable exception) {\n            String error = \"something goes wrong with channel: \" + ctx.getChannel() + \", exception: \"\n                           + ExceptionUtils.getStackTrace(exception);\n            AdminNettyUtils.write(ctx.getChannel(), AdminNettyUtils.errorPacket(400, error));\n        }\n    }\n\n    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {\n        logger.error(\"something goes wrong with channel:{}, exception={}\",\n            ctx.getChannel(),\n            ExceptionUtils.getStackTrace(e.getCause()));\n        ctx.getChannel().close();\n    }\n\n    public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {\n    }\n\n    public void setCanalAdmin(CanalAdmin canalAdmin) {\n        this.canalAdmin = canalAdmin;\n    }\n\n}\n"
  },
  {
    "path": "server/src/main/java/com/alibaba/otter/canal/admin/netty/AdminNettyUtils.java",
    "content": "package com.alibaba.otter.canal.admin.netty;\n\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.jboss.netty.buffer.ChannelBuffer;\nimport org.jboss.netty.buffer.ChannelBuffers;\nimport org.jboss.netty.buffer.CompositeChannelBuffer;\nimport org.jboss.netty.channel.Channel;\nimport org.jboss.netty.channel.ChannelFutureListener;\nimport org.jboss.netty.channel.Channels;\n\nimport com.alibaba.otter.canal.protocol.AdminPacket;\nimport com.alibaba.otter.canal.protocol.AdminPacket.Ack;\nimport com.alibaba.otter.canal.protocol.AdminPacket.Packet;\n\npublic class AdminNettyUtils {\n\n    public static int HEADER_LENGTH = 4;\n    public static int VERSION       = 1;\n\n    public static void write(Channel channel, ByteBuffer body) {\n        byte[] header = ByteBuffer.allocate(HEADER_LENGTH).order(ByteOrder.BIG_ENDIAN).putInt(body.limit()).array();\n        List<ChannelBuffer> components = new ArrayList<>(2);\n        components.add(ChannelBuffers.wrappedBuffer(ByteOrder.BIG_ENDIAN, header));\n        components.add(ChannelBuffers.wrappedBuffer(body));\n        Channels.write(channel, new CompositeChannelBuffer(ByteOrder.BIG_ENDIAN, components));\n    }\n\n    public static void write(Channel channel, byte[] body) {\n        byte[] header = ByteBuffer.allocate(HEADER_LENGTH).order(ByteOrder.BIG_ENDIAN).putInt(body.length).array();\n        Channels.write(channel, ChannelBuffers.wrappedBuffer(header, body));\n    }\n\n    public static void write(Channel channel, byte[] body, ChannelFutureListener channelFutureListner) {\n        byte[] header = ByteBuffer.allocate(HEADER_LENGTH).order(ByteOrder.BIG_ENDIAN).putInt(body.length).array();\n        Channels.write(channel, ChannelBuffers.wrappedBuffer(header, body)).addListener(channelFutureListner);\n    }\n\n    public static byte[] ackPacket() {\n        return ackPacket(null);\n    }\n\n    public static byte[] ackPacket(String message) {\n        return Packet.newBuilder()\n            .setType(AdminPacket.PacketType.ACK)\n            .setVersion(VERSION)\n            .setBody(Ack.newBuilder().setCode(0).setMessage(message == null ? \"\" : message).build().toByteString())\n            .build()\n            .toByteArray();\n    }\n\n    public static byte[] errorPacket(int errorCode, String errorMessage) {\n        return Packet.newBuilder()\n            .setType(AdminPacket.PacketType.ACK)\n            .setVersion(VERSION)\n            .setBody(Ack.newBuilder().setCode(errorCode).setMessage(errorMessage).build().toByteString())\n            .build()\n            .toByteArray();\n    }\n}\n"
  },
  {
    "path": "server/src/main/java/com/alibaba/otter/canal/admin/netty/CanalAdminWithNetty.java",
    "content": "package com.alibaba.otter.canal.admin.netty;\n\nimport java.net.InetSocketAddress;\nimport java.util.concurrent.Executors;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.jboss.netty.bootstrap.ServerBootstrap;\nimport org.jboss.netty.channel.Channel;\nimport org.jboss.netty.channel.ChannelPipeline;\nimport org.jboss.netty.channel.Channels;\nimport org.jboss.netty.channel.group.ChannelGroup;\nimport org.jboss.netty.channel.group.DefaultChannelGroup;\nimport org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;\n\nimport com.alibaba.otter.canal.admin.CanalAdmin;\nimport com.alibaba.otter.canal.admin.handler.ClientAuthenticationHandler;\nimport com.alibaba.otter.canal.admin.handler.HandshakeInitializationHandler;\nimport com.alibaba.otter.canal.admin.handler.SessionHandler;\nimport com.alibaba.otter.canal.common.AbstractCanalLifeCycle;\nimport com.alibaba.otter.canal.server.netty.handler.FixedHeaderFrameDecoder;\n\n/**\n * 基于netty网络服务的server实现\n * \n * @author jianghang 2012-7-12 下午01:34:49\n * @version 1.0.0\n */\npublic class CanalAdminWithNetty extends AbstractCanalLifeCycle {\n\n    private String          ip;\n    private int             port;\n    private Channel         serverChannel = null;\n    private ServerBootstrap bootstrap     = null;\n    private ChannelGroup    childGroups   = null; // socket channel\n                                                  // container, used to\n                                                  // close sockets\n                                                  // explicitly.\n    private CanalAdmin      canalAdmin;\n\n    private static class SingletonHolder {\n\n        private static final CanalAdminWithNetty CANAL_ADMIN_WITH_NETTY = new CanalAdminWithNetty();\n    }\n\n    private CanalAdminWithNetty(){\n        this.childGroups = new DefaultChannelGroup();\n    }\n\n    public static CanalAdminWithNetty instance() {\n        return SingletonHolder.CANAL_ADMIN_WITH_NETTY;\n    }\n\n    public void start() {\n        super.start();\n\n        this.bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(Executors.newCachedThreadPool(),\n            Executors.newCachedThreadPool()));\n        /*\n         * enable keep-alive mechanism, handle abnormal network connection\n         * scenarios on OS level. the threshold parameters are depended on OS.\n         * e.g. On Linux: net.ipv4.tcp_keepalive_time = 300\n         * net.ipv4.tcp_keepalive_probes = 2 net.ipv4.tcp_keepalive_intvl = 30\n         */\n        bootstrap.setOption(\"child.keepAlive\", true);\n        /*\n         * optional parameter.\n         */\n        bootstrap.setOption(\"child.tcpNoDelay\", true);\n\n        // 构造对应的pipeline\n        bootstrap.setPipelineFactory(() -> {\n            ChannelPipeline pipelines = Channels.pipeline();\n            pipelines.addLast(FixedHeaderFrameDecoder.class.getName(), new FixedHeaderFrameDecoder());\n            // support to maintain child socket channel.\n            pipelines.addLast(HandshakeInitializationHandler.class.getName(),\n                new HandshakeInitializationHandler(childGroups));\n            pipelines.addLast(ClientAuthenticationHandler.class.getName(),\n                new ClientAuthenticationHandler(canalAdmin));\n\n            SessionHandler sessionHandler = new SessionHandler(canalAdmin);\n            pipelines.addLast(SessionHandler.class.getName(), sessionHandler);\n            return pipelines;\n        });\n\n        // 启动\n        if (StringUtils.isNotEmpty(ip)) {\n            this.serverChannel = bootstrap.bind(new InetSocketAddress(this.ip, this.port));\n        } else {\n            this.serverChannel = bootstrap.bind(new InetSocketAddress(this.port));\n        }\n    }\n\n    public void stop() {\n        super.stop();\n\n        if (this.serverChannel != null) {\n            this.serverChannel.close().awaitUninterruptibly(1000);\n        }\n\n        // close sockets explicitly to reduce socket channel hung in complicated\n        // network environment.\n        if (this.childGroups != null) {\n            this.childGroups.close().awaitUninterruptibly(5000);\n        }\n\n        if (this.bootstrap != null) {\n            this.bootstrap.releaseExternalResources();\n        }\n    }\n\n    public void setIp(String ip) {\n        this.ip = ip;\n    }\n\n    public void setPort(int port) {\n        this.port = port;\n    }\n\n    public void setCanalAdmin(CanalAdmin canalAdmin) {\n        this.canalAdmin = canalAdmin;\n    }\n\n}\n"
  },
  {
    "path": "server/src/main/java/com/alibaba/otter/canal/server/CanalMQStarter.java",
    "content": "package com.alibaba.otter.canal.server;\n\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.concurrent.*;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.slf4j.MDC;\n\nimport com.alibaba.otter.canal.connector.core.config.MQProperties;\nimport com.alibaba.otter.canal.connector.core.producer.MQDestination;\nimport com.alibaba.otter.canal.connector.core.spi.CanalMQProducer;\nimport com.alibaba.otter.canal.connector.core.util.Callback;\nimport com.alibaba.otter.canal.instance.core.CanalInstance;\nimport com.alibaba.otter.canal.instance.core.CanalMQConfig;\nimport com.alibaba.otter.canal.protocol.ClientIdentity;\nimport com.alibaba.otter.canal.protocol.Message;\nimport com.alibaba.otter.canal.server.embedded.CanalServerWithEmbedded;\n\npublic class CanalMQStarter {\n\n    private static final Logger          logger         = LoggerFactory.getLogger(CanalMQStarter.class);\n\n    private volatile boolean             running        = false;\n\n    private ExecutorService              executorService;\n\n    private CanalMQProducer              canalMQProducer;\n\n    private MQProperties                 mqProperties;\n\n    private CanalServerWithEmbedded      canalServer;\n\n    private Map<String, CanalMQRunnable> canalMQWorks   = new ConcurrentHashMap<>();\n\n    private static Thread                shutdownThread = null;\n\n    public CanalMQStarter(CanalMQProducer canalMQProducer){\n        this.canalMQProducer = canalMQProducer;\n    }\n\n    public synchronized void start(String destinations) {\n        try {\n            if (running) {\n                return;\n            }\n            mqProperties = canalMQProducer.getMqProperties();\n            // set filterTransactionEntry\n            if (mqProperties.isFilterTransactionEntry()) {\n                System.setProperty(\"canal.instance.filter.transaction.entry\", \"true\");\n            }\n\n            canalServer = CanalServerWithEmbedded.instance();\n\n            // 对应每个instance启动一个worker线程\n            executorService = Executors.newCachedThreadPool();\n            logger.info(\"## start the MQ workers.\");\n\n            String[] dsts = StringUtils.split(destinations, \",\");\n            for (String destination : dsts) {\n                destination = destination.trim();\n                CanalMQRunnable canalMQRunnable = new CanalMQRunnable(destination);\n                canalMQWorks.put(destination, canalMQRunnable);\n                executorService.execute(canalMQRunnable);\n            }\n\n            running = true;\n            logger.info(\"## the MQ workers is running now ......\");\n\n            shutdownThread = new Thread(() -> {\n                try {\n                    logger.info(\"## stop the MQ workers\");\n                    running = false;\n                    executorService.shutdown();\n                    canalMQProducer.stop();\n                } catch (Throwable e) {\n                    logger.warn(\"##something goes wrong when stopping MQ workers:\", e);\n                } finally {\n                    logger.info(\"## canal MQ is down.\");\n                }\n            });\n\n            Runtime.getRuntime().addShutdownHook(shutdownThread);\n        } catch (Throwable e) {\n            logger.error(\"## Something goes wrong when starting up the canal MQ workers:\", e);\n        }\n    }\n\n    public synchronized void destroy() {\n        running = false;\n        if (executorService != null) {\n            executorService.shutdown();\n        }\n        if (canalMQProducer != null) {\n            canalMQProducer.stop();\n        }\n        if (shutdownThread != null) {\n            Runtime.getRuntime().removeShutdownHook(shutdownThread);\n            shutdownThread = null;\n        }\n    }\n\n    public synchronized void startDestination(String destination) {\n        CanalInstance canalInstance = canalServer.getCanalInstances().get(destination);\n        if (canalInstance != null) {\n            CanalMQRunnable canalMQRunnable = canalMQWorks.get(destination);\n            if (Objects.isNull(canalMQRunnable)) {\n                canalMQRunnable = new CanalMQRunnable(destination);\n                canalMQWorks.put(canalInstance.getDestination(), canalMQRunnable);\n                // 触发一下任务启动\n                Future future = executorService.submit(canalMQRunnable);\n                canalMQRunnable.setFuture(future);\n                logger.info(\"## Start the MQ work of destination:\" + destination);\n            } else {\n                // 主段时间内的zk出现session time out，会默认优先当前节点抢占成功\n                // 如果没有出发过stop动作，这里可以忽略start的启动\n                logger.info(\"## Start the MQ work of destination:\" + destination + \" , ignore stop\");\n            }\n        }\n    }\n\n    public synchronized void stopDestination(String destination) {\n        CanalMQRunnable canalMQRunnable = canalMQWorks.get(destination);\n        if (canalMQRunnable != null) {\n            canalMQRunnable.stop(true);\n            canalMQWorks.remove(destination);\n            logger.info(\"## Stop the MQ work of destination:\" + destination);\n        }\n    }\n\n    private void worker(String destination, AtomicBoolean destinationRunning, CountDownLatch latch) {\n        while (!running || !destinationRunning.get()) {\n            try {\n                Thread.sleep(100);\n            } catch (InterruptedException e) {\n                // ignore\n            }\n        }\n\n        logger.info(\"## start the MQ producer: {}.\", destination);\n        MDC.put(\"destination\", destination);\n        final ClientIdentity clientIdentity = new ClientIdentity(destination, (short) 1001, \"\");\n        while (running && destinationRunning.get()) {\n            try {\n                CanalInstance canalInstance = canalServer.getCanalInstances().get(destination);\n                if (canalInstance == null) {\n                    try {\n                        Thread.sleep(3000);\n                    } catch (InterruptedException e) {\n                        // ignore\n                    }\n                    continue;\n                }\n                MQDestination canalDestination = new MQDestination();\n                canalDestination.setCanalDestination(destination);\n                CanalMQConfig mqConfig = canalInstance.getMqConfig();\n                canalDestination.setTopic(mqConfig.getTopic());\n                canalDestination.setPartition(mqConfig.getPartition());\n                canalDestination.setDynamicTopic(mqConfig.getDynamicTopic());\n                canalDestination.setPartitionsNum(mqConfig.getPartitionsNum());\n                canalDestination.setPartitionHash(mqConfig.getPartitionHash());\n                canalDestination.setDynamicTopicPartitionNum(mqConfig.getDynamicTopicPartitionNum());\n                canalDestination.setEnableDynamicQueuePartition(mqConfig.getEnableDynamicQueuePartition());\n\n                canalServer.subscribe(clientIdentity);\n                logger.info(\"## the MQ producer: {} is running now ......\", destination);\n\n                Integer getTimeout = mqProperties.getFetchTimeout();\n                Integer getBatchSize = mqProperties.getBatchSize();\n                while (running && destinationRunning.get()) {\n                    Message message;\n                    if (getTimeout != null && getTimeout > 0) {\n                        message = canalServer.getWithoutAck(clientIdentity,\n                            getBatchSize,\n                            getTimeout.longValue(),\n                            TimeUnit.MILLISECONDS);\n                    } else {\n                        message = canalServer.getWithoutAck(clientIdentity, getBatchSize);\n                    }\n\n                    final long batchId = message.getId();\n                    try {\n                        int size = message.isRaw() ? message.getRawEntries().size() : message.getEntries().size();\n                        if (batchId != -1 && size != 0) {\n                            canalMQProducer.send(canalDestination, message, new Callback() {\n\n                                @Override\n                                public void commit() {\n                                    canalServer.ack(clientIdentity, batchId); // 提交确认\n                                }\n\n                                @Override\n                                public void rollback() {\n                                    canalServer.rollback(clientIdentity, batchId);\n                                }\n                            }); // 发送message到topic\n                        } else {\n                            try {\n                                Thread.sleep(100);\n                            } catch (InterruptedException e) {\n                                // ignore\n                            }\n                        }\n\n                    } catch (Exception e) {\n                        logger.error(e.getMessage(), e);\n                    }\n                }\n            } catch (Exception e) {\n                logger.error(\"process error!\", e);\n            }\n        }\n\n        // 确保一下关闭\n        latch.countDown();\n    }\n\n    private class CanalMQRunnable implements Runnable {\n\n        private String destination;\n\n        CanalMQRunnable(String destination){\n            this.destination = destination;\n        }\n\n        private AtomicBoolean running = new AtomicBoolean(true);\n\n        private CountDownLatch latch   = new CountDownLatch(1);\n\n        private Future         future;\n\n        @Override\n        public void run() {\n            worker(destination, running, latch);\n        }\n\n        public void stop(boolean wait) {\n            running.set(false);\n            if (wait) {\n                try {\n                    // 触发一下interrupt\n                    future.cancel(true);\n                    // 等待MQ发送线程的正常退出\n                    latch.await();\n                } catch (InterruptedException e) {\n                    // ignore\n                }\n            }\n        }\n\n        public void setFuture(Future future) {\n            this.future = future;\n        }\n    }\n}\n"
  },
  {
    "path": "server/src/main/java/com/alibaba/otter/canal/server/CanalServer.java",
    "content": "package com.alibaba.otter.canal.server;\n\nimport com.alibaba.otter.canal.common.CanalLifeCycle;\nimport com.alibaba.otter.canal.server.exception.CanalServerException;\n\n/**\n * 对应canal整个服务实例，一个jvm实例只有一份server\n * \n * @author jianghang 2012-7-12 下午01:32:29\n * @version 1.0.0\n */\npublic interface CanalServer extends CanalLifeCycle {\n\n    void start() throws CanalServerException;\n\n    void stop() throws CanalServerException;\n}\n"
  },
  {
    "path": "server/src/main/java/com/alibaba/otter/canal/server/CanalServerStarter.java",
    "content": "package com.alibaba.otter.canal.server;\n\n/**\n * 外部服务如Kafka, RocketMQ启动接口\n *\n * @author machengyuan 2018-8-23 下午05:20:29\n * @version 1.0.0\n */\npublic interface CanalServerStarter {\n\n    void init();\n}\n"
  },
  {
    "path": "server/src/main/java/com/alibaba/otter/canal/server/CanalService.java",
    "content": "package com.alibaba.otter.canal.server;\n\nimport java.util.concurrent.TimeUnit;\n\nimport com.alibaba.otter.canal.protocol.ClientIdentity;\nimport com.alibaba.otter.canal.protocol.Message;\nimport com.alibaba.otter.canal.server.exception.CanalServerException;\n\npublic interface CanalService {\n\n    void subscribe(ClientIdentity clientIdentity) throws CanalServerException;\n\n    void unsubscribe(ClientIdentity clientIdentity) throws CanalServerException;\n\n    Message get(ClientIdentity clientIdentity, int batchSize) throws CanalServerException;\n\n    Message get(ClientIdentity clientIdentity, int batchSize, Long timeout, TimeUnit unit) throws CanalServerException;\n\n    Message getWithoutAck(ClientIdentity clientIdentity, int batchSize) throws CanalServerException;\n\n    Message getWithoutAck(ClientIdentity clientIdentity, int batchSize, Long timeout, TimeUnit unit)\n                                                                                                    throws CanalServerException;\n\n    void ack(ClientIdentity clientIdentity, long batchId) throws CanalServerException;\n\n    void rollback(ClientIdentity clientIdentity) throws CanalServerException;\n\n    void rollback(ClientIdentity clientIdentity, Long batchId) throws CanalServerException;\n}\n"
  },
  {
    "path": "server/src/main/java/com/alibaba/otter/canal/server/embedded/CanalServerWithEmbedded.java",
    "content": "package com.alibaba.otter.canal.server.embedded;\n\nimport java.security.NoSuchAlgorithmException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.ServiceLoader;\nimport java.util.concurrent.TimeUnit;\nimport java.util.stream.Collectors;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.slf4j.MDC;\nimport org.springframework.util.CollectionUtils;\n\nimport com.alibaba.otter.canal.common.AbstractCanalLifeCycle;\nimport com.alibaba.otter.canal.instance.core.CanalInstance;\nimport com.alibaba.otter.canal.instance.core.CanalInstanceGenerator;\nimport com.alibaba.otter.canal.protocol.ClientIdentity;\nimport com.alibaba.otter.canal.protocol.Message;\nimport com.alibaba.otter.canal.protocol.SecurityUtil;\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\nimport com.alibaba.otter.canal.protocol.position.Position;\nimport com.alibaba.otter.canal.protocol.position.PositionRange;\nimport com.alibaba.otter.canal.server.CanalServer;\nimport com.alibaba.otter.canal.server.CanalService;\nimport com.alibaba.otter.canal.server.exception.CanalServerException;\nimport com.alibaba.otter.canal.spi.CanalMetricsProvider;\nimport com.alibaba.otter.canal.spi.CanalMetricsService;\nimport com.alibaba.otter.canal.spi.NopCanalMetricsService;\nimport com.alibaba.otter.canal.store.CanalEventStore;\nimport com.alibaba.otter.canal.store.memory.MemoryEventStoreWithBuffer;\nimport com.alibaba.otter.canal.store.model.Event;\nimport com.alibaba.otter.canal.store.model.Events;\nimport com.google.common.collect.Lists;\nimport com.google.common.collect.Maps;\nimport com.google.common.collect.MigrateMap;\n\n/**\n * 嵌入式版本实现\n *\n * @author jianghang 2012-7-12 下午01:34:00\n * @author zebin.xuzb\n * @version 1.0.0\n */\npublic class CanalServerWithEmbedded extends AbstractCanalLifeCycle implements CanalServer, CanalService {\n\n    private static final Logger        logger  = LoggerFactory.getLogger(CanalServerWithEmbedded.class);\n    private Map<String, CanalInstance> canalInstances;\n    // private Map<ClientIdentity, Position> lastRollbackPostions;\n    private CanalInstanceGenerator     canalInstanceGenerator;\n    private int                        metricsPort;\n    private CanalMetricsService        metrics = NopCanalMetricsService.NOP;\n    private String                     user;\n    private String                     passwd;\n\n    private static class SingletonHolder {\n\n        private static final CanalServerWithEmbedded CANAL_SERVER_WITH_EMBEDDED = new CanalServerWithEmbedded();\n    }\n\n    public CanalServerWithEmbedded(){\n        // 希望也保留用户new单独实例的需求,兼容历史\n    }\n\n    public static CanalServerWithEmbedded instance() {\n        return SingletonHolder.CANAL_SERVER_WITH_EMBEDDED;\n    }\n\n    public void start() {\n        if (!isStart()) {\n            super.start();\n            // 如果存在provider,则启动metrics service\n            if(metricsPort > 0) {\n                loadCanalMetrics();\n                metrics.setServerPort(metricsPort);\n                metrics.initialize();\n            }\n            canalInstances = MigrateMap.makeComputingMap(destination -> canalInstanceGenerator.generate(destination));\n            // lastRollbackPostions = new MapMaker().makeMap();\n        }\n    }\n\n    public void stop() {\n        super.stop();\n        for (Map.Entry<String, CanalInstance> entry : canalInstances.entrySet()) {\n            try {\n                CanalInstance instance = entry.getValue();\n                if (instance.isStart()) {\n                    try {\n                        String destination = entry.getKey();\n                        MDC.put(\"destination\", destination);\n                        entry.getValue().stop();\n                        logger.info(\"stop CanalInstances[{}] successfully\", destination);\n                    } finally {\n                        MDC.remove(\"destination\");\n                    }\n                }\n            } catch (Exception e) {\n                logger.error(String.format(\"stop CanalInstance[%s] has an error\", entry.getKey()), e);\n            }\n        }\n        metrics.terminate();\n    }\n\n    public boolean auth(String user, String passwd, byte[] seed) {\n        // 如果user/passwd密码为空,则任何用户账户都能登录\n        if ((StringUtils.isEmpty(this.user) || StringUtils.equals(this.user, user))) {\n            if (StringUtils.isEmpty(this.passwd)) {\n                return true;\n            } else if (StringUtils.isEmpty(passwd)) {\n                // 如果server密码有配置,客户端密码为空,则拒绝\n                return false;\n            }\n\n            try {\n                byte[] passForClient = SecurityUtil.hexStr2Bytes(passwd);\n                return SecurityUtil.scrambleServerAuth(passForClient, SecurityUtil.hexStr2Bytes(this.passwd), seed);\n            } catch (NoSuchAlgorithmException e) {\n                return false;\n            }\n        }\n\n        return false;\n    }\n\n    public void start(final String destination) {\n        final CanalInstance canalInstance = canalInstances.get(destination);\n        if (!canalInstance.isStart()) {\n            try {\n                MDC.put(\"destination\", destination);\n                if (metrics.isRunning()) {\n                    metrics.register(canalInstance);\n                }\n                canalInstance.start();\n                logger.info(\"start CanalInstances[{}] successfully\", destination);\n            } finally {\n                MDC.remove(\"destination\");\n            }\n        }\n    }\n\n    public void stop(String destination) {\n        CanalInstance canalInstance = canalInstances.remove(destination);\n        if (canalInstance != null) {\n            if (canalInstance.isStart()) {\n                try {\n                    MDC.put(\"destination\", destination);\n                    canalInstance.stop();\n                    if (metrics.isRunning()) {\n                        metrics.unregister(canalInstance);\n                    }\n                    logger.info(\"stop CanalInstances[{}] successfully\", destination);\n                } finally {\n                    MDC.remove(\"destination\");\n                }\n            }\n        }\n    }\n\n    public boolean isStart(String destination) {\n        return canalInstances.containsKey(destination) && canalInstances.get(destination).isStart();\n    }\n\n    /**\n     * 客户端订阅，重复订阅时会更新对应的filter信息\n     */\n    @Override\n    public void subscribe(ClientIdentity clientIdentity) throws CanalServerException {\n        checkStart(clientIdentity.getDestination());\n\n        CanalInstance canalInstance = canalInstances.get(clientIdentity.getDestination());\n        if (!canalInstance.getMetaManager().isStart()) {\n            canalInstance.getMetaManager().start();\n        }\n\n        canalInstance.getMetaManager().subscribe(clientIdentity); // 执行一下meta订阅\n\n        Position position = canalInstance.getMetaManager().getCursor(clientIdentity);\n        if (position == null) {\n            position = canalInstance.getEventStore().getFirstPosition();// 获取一下store中的第一条\n            if (position != null) {\n                canalInstance.getMetaManager().updateCursor(clientIdentity, position); // 更新一下cursor\n            }\n            logger.info(\"subscribe successfully, {} with first position:{} \", clientIdentity, position);\n        } else {\n            logger.info(\"subscribe successfully, {} use last cursor position:{} \", clientIdentity, position);\n        }\n\n        // 通知下订阅关系变化\n        canalInstance.subscribeChange(clientIdentity);\n    }\n\n    /**\n     * 取消订阅\n     */\n    @Override\n    public void unsubscribe(ClientIdentity clientIdentity) throws CanalServerException {\n        CanalInstance canalInstance = canalInstances.get(clientIdentity.getDestination());\n        canalInstance.getMetaManager().unsubscribe(clientIdentity); // 执行一下meta订阅\n\n        logger.info(\"unsubscribe successfully, {}\", clientIdentity);\n    }\n\n    /**\n     * 查询所有的订阅信息\n     */\n    public List<ClientIdentity> listAllSubscribe(String destination) throws CanalServerException {\n        CanalInstance canalInstance = canalInstances.get(destination);\n        return canalInstance.getMetaManager().listAllSubscribeInfo(destination);\n    }\n\n    /**\n     * 获取数据\n     *\n     * <pre>\n     * 注意： meta获取和数据的获取需要保证顺序性，优先拿到meta的，一定也会是优先拿到数据，所以需要加同步. (不能出现先拿到meta，拿到第二批数据，这样就会导致数据顺序性出现问题)\n     * </pre>\n     */\n    @Override\n    public Message get(ClientIdentity clientIdentity, int batchSize) throws CanalServerException {\n        return get(clientIdentity, batchSize, null, null);\n    }\n\n    /**\n     * 获取数据，可以指定超时时间.\n     *\n     * <pre>\n     * 几种case:\n     * a. 如果timeout为null，则采用tryGet方式，即时获取\n     * b. 如果timeout不为null\n     *    1. timeout为0，则采用get阻塞方式，获取数据，不设置超时，直到有足够的batchSize数据才返回\n     *    2. timeout不为0，则采用get+timeout方式，获取数据，超时还没有batchSize足够的数据，有多少返回多少\n     * \n     * 注意： meta获取和数据的获取需要保证顺序性，优先拿到meta的，一定也会是优先拿到数据，所以需要加同步. (不能出现先拿到meta，拿到第二批数据，这样就会导致数据顺序性出现问题)\n     * </pre>\n     */\n    @Override\n    public Message get(ClientIdentity clientIdentity, int batchSize, Long timeout, TimeUnit unit)\n                                                                                                 throws CanalServerException {\n        checkStart(clientIdentity.getDestination());\n        checkSubscribe(clientIdentity);\n        CanalInstance canalInstance = canalInstances.get(clientIdentity.getDestination());\n        synchronized (canalInstance) {\n            // 获取到流式数据中的最后一批获取的位置\n            PositionRange<LogPosition> positionRanges = canalInstance.getMetaManager().getLastestBatch(clientIdentity);\n\n            if (positionRanges != null) {\n                throw new CanalServerException(String.format(\"clientId:%s has last batch:[%s] isn't ack , maybe loss data\",\n                    clientIdentity.getClientId(),\n                    positionRanges));\n            }\n\n            Events<Event> events = null;\n            Position start = canalInstance.getMetaManager().getCursor(clientIdentity);\n            events = getEvents(canalInstance.getEventStore(), start, batchSize, timeout, unit);\n\n            if (CollectionUtils.isEmpty(events.getEvents())) {\n                logger.debug(\"get successfully, clientId:{} batchSize:{} but result is null\",\n                    clientIdentity.getClientId(),\n                    batchSize);\n                return new Message(-1, true, new ArrayList()); // 返回空包，避免生成batchId，浪费性能\n            } else {\n                // 记录到流式信息\n                Long batchId = canalInstance.getMetaManager().addBatch(clientIdentity, events.getPositionRange());\n                boolean raw = isRaw(canalInstance.getEventStore());\n                List entrys = null;\n                if (raw) {\n                    // new list\n                    entrys = events.getEvents().stream().map(Event::getRawEntry).collect(Collectors.toList());\n                } else {\n                    entrys = events.getEvents().stream().map(Event::getEntry).collect(Collectors.toList());\n                }\n                if (logger.isInfoEnabled()) {\n                    logger.info(\"get successfully, clientId:{} batchSize:{} real size is {} and result is [batchId:{} , position:{}]\",\n                        clientIdentity.getClientId(),\n                        batchSize,\n                        entrys.size(),\n                        batchId,\n                        events.getPositionRange());\n                }\n                // 直接提交ack\n                ack(clientIdentity, batchId);\n                return new Message(batchId, raw, entrys);\n            }\n        }\n    }\n\n    /**\n     * 不指定 position 获取事件。canal 会记住此 client 最新的 position。 <br/>\n     * 如果是第一次 fetch，则会从 canal 中保存的最老一条数据开始输出。\n     *\n     * <pre>\n     * 注意： meta获取和数据的获取需要保证顺序性，优先拿到meta的，一定也会是优先拿到数据，所以需要加同步. (不能出现先拿到meta，拿到第二批数据，这样就会导致数据顺序性出现问题)\n     * </pre>\n     */\n    @Override\n    public Message getWithoutAck(ClientIdentity clientIdentity, int batchSize) throws CanalServerException {\n        return getWithoutAck(clientIdentity, batchSize, null, null);\n    }\n\n    /**\n     * 不指定 position 获取事件。canal 会记住此 client 最新的 position。 <br/>\n     * 如果是第一次 fetch，则会从 canal 中保存的最老一条数据开始输出。\n     *\n     * <pre>\n     * 几种case:\n     * a. 如果timeout为null，则采用tryGet方式，即时获取\n     * b. 如果timeout不为null\n     *    1. timeout为0，则采用get阻塞方式，获取数据，不设置超时，直到有足够的batchSize数据才返回\n     *    2. timeout不为0，则采用get+timeout方式，获取数据，超时还没有batchSize足够的数据，有多少返回多少\n     * \n     * 注意： meta获取和数据的获取需要保证顺序性，优先拿到meta的，一定也会是优先拿到数据，所以需要加同步. (不能出现先拿到meta，拿到第二批数据，这样就会导致数据顺序性出现问题)\n     * </pre>\n     */\n    @Override\n    public Message getWithoutAck(ClientIdentity clientIdentity, int batchSize, Long timeout, TimeUnit unit)\n                                                                                                           throws CanalServerException {\n        checkStart(clientIdentity.getDestination());\n        checkSubscribe(clientIdentity);\n\n        CanalInstance canalInstance = canalInstances.get(clientIdentity.getDestination());\n        synchronized (canalInstance) {\n            // 获取到流式数据中的最后一批获取的位置\n            PositionRange<LogPosition> positionRanges = canalInstance.getMetaManager().getLastestBatch(clientIdentity);\n\n            Events<Event> events = null;\n            if (positionRanges != null) { // 存在流数据\n                events = getEvents(canalInstance.getEventStore(), positionRanges.getStart(), batchSize, timeout, unit);\n            } else {// ack后第一次获取\n                Position start = canalInstance.getMetaManager().getCursor(clientIdentity);\n                if (start == null) { // 第一次，还没有过ack记录，则获取当前store中的第一条\n                    start = canalInstance.getEventStore().getFirstPosition();\n                }\n\n                events = getEvents(canalInstance.getEventStore(), start, batchSize, timeout, unit);\n            }\n\n            if (CollectionUtils.isEmpty(events.getEvents())) {\n                // logger.debug(\"getWithoutAck successfully, clientId:{}\n                // batchSize:{} but result\n                // is null\",\n                // clientIdentity.getClientId(),\n                // batchSize);\n                return new Message(-1, true, new ArrayList()); // 返回空包，避免生成batchId，浪费性能\n            } else {\n                // 记录到流式信息\n                Long batchId = canalInstance.getMetaManager().addBatch(clientIdentity, events.getPositionRange());\n                boolean raw = isRaw(canalInstance.getEventStore());\n                List entrys = null;\n                if (raw) {\n                    // new list\n                    entrys = events.getEvents().stream().map(Event::getRawEntry).collect(Collectors.toList());\n                } else {\n                    entrys = events.getEvents().stream().map(Event::getEntry).collect(Collectors.toList());\n                }\n                if (logger.isInfoEnabled()) {\n                    logger.info(\"getWithoutAck successfully, clientId:{} batchSize:{}  real size is {} and result is [batchId:{} , position:{}]\",\n                        clientIdentity.getClientId(),\n                        batchSize,\n                        entrys.size(),\n                        batchId,\n                        events.getPositionRange());\n                }\n                return new Message(batchId, raw, entrys);\n            }\n\n        }\n    }\n\n    /**\n     * 查询当前未被ack的batch列表，batchId会按照从小到大进行返回\n     */\n    public List<Long> listBatchIds(ClientIdentity clientIdentity) throws CanalServerException {\n        checkStart(clientIdentity.getDestination());\n        checkSubscribe(clientIdentity);\n\n        CanalInstance canalInstance = canalInstances.get(clientIdentity.getDestination());\n        Map<Long, PositionRange> batchs = canalInstance.getMetaManager().listAllBatchs(clientIdentity);\n        List<Long> result = new ArrayList<>(batchs.keySet());\n        Collections.sort(result);\n        return result;\n    }\n\n    /**\n     * 进行 batch id 的确认。确认之后，小于等于此 batchId 的 Message 都会被确认。\n     *\n     * <pre>\n     * 注意：进行反馈时必须按照batchId的顺序进行ack(需有客户端保证)\n     * </pre>\n     */\n    @Override\n    public void ack(ClientIdentity clientIdentity, long batchId) throws CanalServerException {\n        checkStart(clientIdentity.getDestination());\n        checkSubscribe(clientIdentity);\n\n        CanalInstance canalInstance = canalInstances.get(clientIdentity.getDestination());\n        PositionRange<LogPosition> positionRanges = null;\n        positionRanges = canalInstance.getMetaManager().removeBatch(clientIdentity, batchId); // 更新位置\n        if (positionRanges == null) { // 说明是重复的ack/rollback\n            throw new CanalServerException(String.format(\"ack error , clientId:%s batchId:%d is not exist , please check\",\n                clientIdentity.getClientId(),\n                batchId));\n        }\n\n        // 更新cursor最好严格判断下位置是否有跳跃更新\n        // Position position = lastRollbackPostions.get(clientIdentity);\n        // if (position != null) {\n        // // Position position =\n        // canalInstance.getMetaManager().getCursor(clientIdentity);\n        // LogPosition minPosition =\n        // CanalEventUtils.min(positionRanges.getStart(), (LogPosition)\n        // position);\n        // if (minPosition == position) {// ack的position要晚于该最后ack的位置，可能有丢数据\n        // throw new CanalServerException(\n        // String.format(\n        // \"ack error , clientId:%s batchId:%d %s is jump ack , last ack:%s\",\n        // clientIdentity.getClientId(), batchId, positionRanges,\n        // position));\n        // }\n        // }\n\n        // 更新cursor\n        if (positionRanges.getAck() != null) {\n            canalInstance.getMetaManager().updateCursor(clientIdentity, positionRanges.getAck());\n            if (logger.isInfoEnabled()) {\n                logger.info(\"ack successfully, clientId:{} batchId:{} position:{}\",\n                    clientIdentity.getClientId(),\n                    batchId,\n                    positionRanges);\n            }\n        }\n\n        // 可定时清理数据\n        canalInstance.getEventStore().ack(positionRanges.getEnd(), positionRanges.getEndSeq());\n    }\n\n    /**\n     * 回滚到未进行 {@link #ack} 的地方，下次fetch的时候，可以从最后一个没有 {@link #ack} 的地方开始拿\n     */\n    @Override\n    public void rollback(ClientIdentity clientIdentity) throws CanalServerException {\n        checkStart(clientIdentity.getDestination());\n        CanalInstance canalInstance = canalInstances.get(clientIdentity.getDestination());\n        // 因为存在第一次链接时自动rollback的情况，所以需要忽略未订阅\n        boolean hasSubscribe = canalInstance.getMetaManager().hasSubscribe(clientIdentity);\n        if (!hasSubscribe) {\n            return;\n        }\n\n        synchronized (canalInstance) {\n            // 清除batch信息\n            canalInstance.getMetaManager().clearAllBatchs(clientIdentity);\n            // rollback eventStore中的状态信息\n            canalInstance.getEventStore().rollback();\n            logger.info(\"rollback successfully, clientId:{}\", new Object[] { clientIdentity.getClientId() });\n        }\n    }\n\n    /**\n     * 回滚到未进行 {@link #ack} 的地方，下次fetch的时候，可以从最后一个没有 {@link #ack} 的地方开始拿\n     */\n    @Override\n    public void rollback(ClientIdentity clientIdentity, Long batchId) throws CanalServerException {\n        checkStart(clientIdentity.getDestination());\n        CanalInstance canalInstance = canalInstances.get(clientIdentity.getDestination());\n\n        // 因为存在第一次链接时自动rollback的情况，所以需要忽略未订阅\n        boolean hasSubscribe = canalInstance.getMetaManager().hasSubscribe(clientIdentity);\n        if (!hasSubscribe) {\n            return;\n        }\n        synchronized (canalInstance) {\n            // 清除batch信息\n            PositionRange<LogPosition> positionRanges = canalInstance.getMetaManager().removeBatch(clientIdentity,\n                batchId);\n            if (positionRanges == null) { // 说明是重复的ack/rollback\n                throw new CanalServerException(String.format(\"rollback error, clientId:%s batchId:%d is not exist , please check\",\n                    clientIdentity.getClientId(),\n                    batchId));\n            }\n\n            // lastRollbackPostions.put(clientIdentity,\n            // positionRanges.getEnd());// 记录一下最后rollback的位置\n            // TODO 后续rollback到指定的batchId位置\n            canalInstance.getEventStore().rollback();// rollback\n                                                     // eventStore中的状态信息\n            logger.info(\"rollback successfully, clientId:{} batchId:{} position:{}\",\n                clientIdentity.getClientId(),\n                batchId,\n                positionRanges);\n        }\n    }\n\n    public Map<String, CanalInstance> getCanalInstances() {\n        return Maps.newHashMap(canalInstances);\n    }\n\n    // ======================== helper method =======================\n\n    /**\n     * 根据不同的参数，选择不同的方式获取数据\n     */\n    private Events<Event> getEvents(CanalEventStore eventStore, Position start, int batchSize, Long timeout,\n                                    TimeUnit unit) {\n        if (timeout == null) {\n            return eventStore.tryGet(start, batchSize);\n        } else {\n            try {\n                if (timeout <= 0) {\n                    return eventStore.get(start, batchSize);\n                } else {\n                    return eventStore.get(start, batchSize, timeout, unit);\n                }\n            } catch (Exception e) {\n                throw new CanalServerException(e);\n            }\n        }\n    }\n\n    private void checkSubscribe(ClientIdentity clientIdentity) {\n        CanalInstance canalInstance = canalInstances.get(clientIdentity.getDestination());\n        boolean hasSubscribe = canalInstance.getMetaManager().hasSubscribe(clientIdentity);\n        if (!hasSubscribe) {\n            throw new CanalServerException(String.format(\"ClientIdentity:%s should subscribe first\",\n                clientIdentity.toString()));\n        }\n    }\n\n    private void checkStart(String destination) {\n        if (!isStart(destination)) {\n            throw new CanalServerException(String.format(\"destination:%s should start first\", destination));\n        }\n    }\n\n    private void loadCanalMetrics() {\n        ServiceLoader<CanalMetricsProvider> providers = ServiceLoader.load(CanalMetricsProvider.class);\n        List<CanalMetricsProvider> list = new ArrayList<>();\n        for (CanalMetricsProvider provider : providers) {\n            list.add(provider);\n        }\n\n        if (list.isEmpty()) {\n            return;\n        }\n\n        // only allow ONE provider\n        if (list.size() > 1) {\n            logger.warn(\"Found more than one CanalMetricsProvider, use the first one.\");\n            // 报告冲突\n            for (CanalMetricsProvider p : list) {\n                logger.warn(\"Found CanalMetricsProvider: {}.\", p.getClass().getName());\n            }\n        }\n\n        CanalMetricsProvider provider = list.get(0);\n        this.metrics = provider.getService();\n    }\n\n    private boolean isRaw(CanalEventStore eventStore) {\n        if (eventStore instanceof MemoryEventStoreWithBuffer) {\n            return ((MemoryEventStoreWithBuffer) eventStore).isRaw();\n        }\n\n        return true;\n    }\n\n    // ========= setter ==========\n\n    public void setCanalInstanceGenerator(CanalInstanceGenerator canalInstanceGenerator) {\n        this.canalInstanceGenerator = canalInstanceGenerator;\n    }\n\n    public void setMetricsPort(int metricsPort) {\n        this.metricsPort = metricsPort;\n    }\n\n    public void setUser(String user) {\n        this.user = user;\n    }\n\n    public void setPasswd(String passwd) {\n        this.passwd = passwd;\n    }\n\n}\n"
  },
  {
    "path": "server/src/main/java/com/alibaba/otter/canal/server/exception/CanalServerException.java",
    "content": "package com.alibaba.otter.canal.server.exception;\r\n\r\nimport com.alibaba.otter.canal.common.CanalException;\r\n\r\n/**\r\n * canal 异常定义\r\n * \r\n * @author jianghang 2012-6-15 下午04:57:35\r\n * @version 1.0.0\r\n */\r\npublic class CanalServerException extends CanalException {\r\n\r\n    private static final long serialVersionUID = -7288830284122672209L;\r\n\r\n    public CanalServerException(String errorCode){\r\n        super(errorCode);\r\n    }\r\n\r\n    public CanalServerException(String errorCode, Throwable cause){\r\n        super(errorCode, cause);\r\n    }\r\n\r\n    public CanalServerException(String errorCode, String errorDesc){\r\n        super(errorCode + \":\" + errorDesc);\r\n    }\r\n\r\n    public CanalServerException(String errorCode, String errorDesc, Throwable cause){\r\n        super(errorCode + \":\" + errorDesc, cause);\r\n    }\r\n\r\n    public CanalServerException(Throwable cause){\r\n        super(cause);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "server/src/main/java/com/alibaba/otter/canal/server/netty/CanalServerWithNetty.java",
    "content": "package com.alibaba.otter.canal.server.netty;\n\nimport java.net.InetSocketAddress;\nimport java.util.concurrent.Executors;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.jboss.netty.bootstrap.ServerBootstrap;\nimport org.jboss.netty.channel.Channel;\nimport org.jboss.netty.channel.ChannelPipeline;\nimport org.jboss.netty.channel.Channels;\nimport org.jboss.netty.channel.group.ChannelGroup;\nimport org.jboss.netty.channel.group.DefaultChannelGroup;\nimport org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;\n\nimport com.alibaba.otter.canal.common.AbstractCanalLifeCycle;\nimport com.alibaba.otter.canal.server.CanalServer;\nimport com.alibaba.otter.canal.server.embedded.CanalServerWithEmbedded;\nimport com.alibaba.otter.canal.server.netty.handler.ClientAuthenticationHandler;\nimport com.alibaba.otter.canal.server.netty.handler.FixedHeaderFrameDecoder;\nimport com.alibaba.otter.canal.server.netty.handler.HandshakeInitializationHandler;\nimport com.alibaba.otter.canal.server.netty.handler.SessionHandler;\n\n/**\n * 基于netty网络服务的server实现\n * \n * @author jianghang 2012-7-12 下午01:34:49\n * @version 1.0.0\n */\npublic class CanalServerWithNetty extends AbstractCanalLifeCycle implements CanalServer {\n\n    private CanalServerWithEmbedded embeddedServer;      // 嵌入式server\n    private String                  ip;\n    private int                     port;\n    private Channel                 serverChannel = null;\n    private ServerBootstrap         bootstrap     = null;\n    private ChannelGroup            childGroups   = null; // socket channel\n                                                          // container, used to\n                                                          // close sockets\n                                                          // explicitly.\n\n    private static class SingletonHolder {\n\n        private static final CanalServerWithNetty CANAL_SERVER_WITH_NETTY = new CanalServerWithNetty();\n    }\n\n    private CanalServerWithNetty(){\n        this.embeddedServer = CanalServerWithEmbedded.instance();\n        this.childGroups = new DefaultChannelGroup();\n    }\n\n    public static CanalServerWithNetty instance() {\n        return SingletonHolder.CANAL_SERVER_WITH_NETTY;\n    }\n\n    public void start() {\n        super.start();\n\n        if (!embeddedServer.isStart()) {\n            embeddedServer.start();\n        }\n\n        this.bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(Executors.newCachedThreadPool(),\n            Executors.newCachedThreadPool()));\n        /*\n         * enable keep-alive mechanism, handle abnormal network connection\n         * scenarios on OS level. the threshold parameters are depended on OS.\n         * e.g. On Linux: net.ipv4.tcp_keepalive_time = 300\n         * net.ipv4.tcp_keepalive_probes = 2 net.ipv4.tcp_keepalive_intvl = 30\n         */\n        bootstrap.setOption(\"child.keepAlive\", true);\n        /*\n         * optional parameter.\n         */\n        bootstrap.setOption(\"child.tcpNoDelay\", true);\n\n        // 构造对应的pipeline\n        bootstrap.setPipelineFactory(() -> {\n            ChannelPipeline pipelines = Channels.pipeline();\n            pipelines.addLast(FixedHeaderFrameDecoder.class.getName(), new FixedHeaderFrameDecoder());\n            // support to maintain child socket channel.\n            pipelines.addLast(HandshakeInitializationHandler.class.getName(),\n                new HandshakeInitializationHandler(childGroups));\n            pipelines.addLast(ClientAuthenticationHandler.class.getName(),\n                new ClientAuthenticationHandler(embeddedServer));\n\n            SessionHandler sessionHandler = new SessionHandler(embeddedServer);\n            pipelines.addLast(SessionHandler.class.getName(), sessionHandler);\n            return pipelines;\n        });\n\n        // 启动\n        if (StringUtils.isNotEmpty(ip)) {\n            this.serverChannel = bootstrap.bind(new InetSocketAddress(this.ip, this.port));\n        } else {\n            this.serverChannel = bootstrap.bind(new InetSocketAddress(this.port));\n        }\n    }\n\n    public void stop() {\n        super.stop();\n\n        if (this.serverChannel != null) {\n            this.serverChannel.close().awaitUninterruptibly(1000);\n        }\n\n        // close sockets explicitly to reduce socket channel hung in complicated\n        // network environment.\n        if (this.childGroups != null) {\n            this.childGroups.close().awaitUninterruptibly(5000);\n        }\n\n        if (this.bootstrap != null) {\n            this.bootstrap.releaseExternalResources();\n        }\n\n        if (embeddedServer.isStart()) {\n            embeddedServer.stop();\n        }\n    }\n\n    public void setIp(String ip) {\n        this.ip = ip;\n    }\n\n    public void setPort(int port) {\n        this.port = port;\n    }\n\n    public void setEmbeddedServer(CanalServerWithEmbedded embeddedServer) {\n        this.embeddedServer = embeddedServer;\n    }\n\n}\n"
  },
  {
    "path": "server/src/main/java/com/alibaba/otter/canal/server/netty/CanalServerWithNettyProfiler.java",
    "content": "package com.alibaba.otter.canal.server.netty;\n\nimport com.alibaba.otter.canal.common.AbstractCanalLifeCycle;\nimport com.alibaba.otter.canal.server.netty.listener.ChannelFutureAggregator.ClientRequestResult;\n\n/**\n * @author Chuanyi Li\n */\npublic class CanalServerWithNettyProfiler {\n\n    public static final ClientInstanceProfiler NOP               = new DefaultClientInstanceProfiler();\n    private ClientInstanceProfiler             instanceProfiler;\n\n    private static class SingletonHolder {\n        private static CanalServerWithNettyProfiler SINGLETON = new CanalServerWithNettyProfiler();\n    }\n\n    private CanalServerWithNettyProfiler() {\n        this.instanceProfiler = NOP;\n    }\n\n    public static CanalServerWithNettyProfiler profiler() {\n        return SingletonHolder.SINGLETON;\n    }\n\n    public void profiling(ClientRequestResult result) {\n        instanceProfiler.profiling(result);\n    }\n\n    public void setInstanceProfiler(ClientInstanceProfiler instanceProfiler) {\n        this.instanceProfiler = instanceProfiler;\n    }\n\n    private static class DefaultClientInstanceProfiler extends AbstractCanalLifeCycle implements ClientInstanceProfiler {\n        @Override\n        public void profiling(ClientRequestResult result) {}\n    }\n\n}\n"
  },
  {
    "path": "server/src/main/java/com/alibaba/otter/canal/server/netty/ClientInstanceProfiler.java",
    "content": "package com.alibaba.otter.canal.server.netty;\n\nimport com.alibaba.otter.canal.common.CanalLifeCycle;\nimport com.alibaba.otter.canal.server.netty.listener.ChannelFutureAggregator.ClientRequestResult;\n\n/**\n * @author Chuanyi Li\n */\npublic interface ClientInstanceProfiler extends CanalLifeCycle {\n\n    void profiling(ClientRequestResult result);\n\n}\n"
  },
  {
    "path": "server/src/main/java/com/alibaba/otter/canal/server/netty/NettyUtils.java",
    "content": "package com.alibaba.otter.canal.server.netty;\n\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.jboss.netty.buffer.ChannelBuffer;\nimport org.jboss.netty.buffer.ChannelBuffers;\nimport org.jboss.netty.buffer.CompositeChannelBuffer;\nimport org.jboss.netty.channel.Channel;\nimport org.jboss.netty.channel.ChannelFutureListener;\nimport org.jboss.netty.channel.Channels;\nimport org.jboss.netty.util.HashedWheelTimer;\nimport org.jboss.netty.util.Timer;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.protocol.CanalPacket;\nimport com.alibaba.otter.canal.protocol.CanalPacket.Ack;\nimport com.alibaba.otter.canal.protocol.CanalPacket.Packet;\n\npublic class NettyUtils {\n\n    private static final Logger logger           = LoggerFactory.getLogger(NettyUtils.class);\n    public static int           HEADER_LENGTH    = 4;\n    public static Timer         hashedWheelTimer = new HashedWheelTimer();\n    public static int           VERSION          = 1;\n\n    public static void write(Channel channel, ByteBuffer body, ChannelFutureListener channelFutureListner) {\n        byte[] header = ByteBuffer.allocate(HEADER_LENGTH).order(ByteOrder.BIG_ENDIAN).putInt(body.limit()).array();\n        List<ChannelBuffer> components = new ArrayList<>(2);\n        components.add(ChannelBuffers.wrappedBuffer(ByteOrder.BIG_ENDIAN, header));\n        components.add(ChannelBuffers.wrappedBuffer(body));\n\n        if (channelFutureListner == null) {\n            Channels.write(channel, new CompositeChannelBuffer(ByteOrder.BIG_ENDIAN, components));\n        } else {\n            Channels.write(channel, new CompositeChannelBuffer(ByteOrder.BIG_ENDIAN, components))\n                .addListener(channelFutureListner);\n        }\n    }\n\n    public static void write(Channel channel, byte[] body, ChannelFutureListener channelFutureListner) {\n        byte[] header = ByteBuffer.allocate(HEADER_LENGTH).order(ByteOrder.BIG_ENDIAN).putInt(body.length).array();\n        if (channelFutureListner == null) {\n            Channels.write(channel, ChannelBuffers.wrappedBuffer(header, body));\n        } else {\n            Channels.write(channel, ChannelBuffers.wrappedBuffer(header, body)).addListener(channelFutureListner);\n        }\n    }\n\n    public static void ack(Channel channel, ChannelFutureListener channelFutureListner) {\n        write(channel,\n            Packet.newBuilder()\n                .setType(CanalPacket.PacketType.ACK)\n                .setVersion(VERSION)\n                .setBody(Ack.newBuilder().build().toByteString())\n                .build()\n                .toByteArray(),\n            channelFutureListner);\n    }\n\n    public static void error(int errorCode, String errorMessage, Channel channel,\n                             ChannelFutureListener channelFutureListener) {\n        if (channelFutureListener == null) {\n            channelFutureListener = ChannelFutureListener.CLOSE;\n        }\n\n        logger.error(\"ErrotCode:{} , Caused by : \\n{}\", errorCode, errorMessage);\n        write(channel,\n            Packet.newBuilder()\n                .setType(CanalPacket.PacketType.ACK)\n                .setVersion(VERSION)\n                .setBody(Ack.newBuilder().setErrorCode(errorCode).setErrorMessage(errorMessage).build().toByteString())\n                .build()\n                .toByteArray(),\n            channelFutureListener);\n    }\n\n    public static byte[] ackPacket() {\n        return Packet.newBuilder()\n            .setType(CanalPacket.PacketType.ACK)\n            .setVersion(VERSION)\n            .setBody(Ack.newBuilder().build().toByteString())\n            .build()\n            .toByteArray();\n    }\n\n    public static byte[] errorPacket(int errorCode, String errorMessage) {\n        return Packet.newBuilder()\n            .setType(CanalPacket.PacketType.ACK)\n            .setVersion(VERSION)\n            .setBody(Ack.newBuilder().setErrorCode(errorCode).setErrorMessage(errorMessage).build().toByteString())\n            .build()\n            .toByteArray();\n    }\n}\n"
  },
  {
    "path": "server/src/main/java/com/alibaba/otter/canal/server/netty/handler/ClientAuthenticationHandler.java",
    "content": "package com.alibaba.otter.canal.server.netty.handler;\n\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.jboss.netty.buffer.ChannelBuffer;\nimport org.jboss.netty.channel.ChannelHandlerContext;\nimport org.jboss.netty.channel.MessageEvent;\nimport org.jboss.netty.channel.SimpleChannelHandler;\nimport org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler;\nimport org.jboss.netty.handler.timeout.IdleStateEvent;\nimport org.jboss.netty.handler.timeout.IdleStateHandler;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.slf4j.MDC;\nimport org.slf4j.helpers.MessageFormatter;\n\nimport com.alibaba.otter.canal.common.zookeeper.running.ServerRunningMonitor;\nimport com.alibaba.otter.canal.common.zookeeper.running.ServerRunningMonitors;\nimport com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth;\nimport com.alibaba.otter.canal.protocol.CanalPacket.Packet;\nimport com.alibaba.otter.canal.protocol.ClientIdentity;\nimport com.alibaba.otter.canal.server.embedded.CanalServerWithEmbedded;\nimport com.alibaba.otter.canal.server.netty.NettyUtils;\n\n/**\n * 客户端身份认证处理\n * \n * @author jianghang 2012-10-24 上午11:12:45\n * @version 1.0.0\n */\npublic class ClientAuthenticationHandler extends SimpleChannelHandler {\n\n    private static final Logger     logger                                  = LoggerFactory.getLogger(ClientAuthenticationHandler.class);\n    private final int               SUPPORTED_VERSION                       = 3;\n    private final int               defaultSubscriptorDisconnectIdleTimeout = 60 * 60 * 1000;\n    private CanalServerWithEmbedded embeddedServer;\n    private byte[]                  seed;\n\n    public ClientAuthenticationHandler(){\n\n    }\n\n    public ClientAuthenticationHandler(CanalServerWithEmbedded embeddedServer){\n        this.embeddedServer = embeddedServer;\n    }\n\n    public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) throws Exception {\n        ChannelBuffer buffer = (ChannelBuffer) e.getMessage();\n        final Packet packet = Packet.parseFrom(buffer.readBytes(buffer.readableBytes()).array());\n        switch (packet.getVersion()) {\n            case SUPPORTED_VERSION:\n            default:\n                final ClientAuth clientAuth = ClientAuth.parseFrom(packet.getBody());\n                if (seed == null) {\n                    byte[] errorBytes = NettyUtils.errorPacket(400,\n                        MessageFormatter.format(\"auth failed for seed is null\", clientAuth.getUsername()).getMessage());\n                    NettyUtils.write(ctx.getChannel(), errorBytes, null);\n                    break;\n                }\n\n                if (!embeddedServer.auth(clientAuth.getUsername(), clientAuth.getPassword().toStringUtf8(), seed)) {\n                    byte[] errorBytes = NettyUtils.errorPacket(400,\n                        MessageFormatter.format(\"auth failed for user:{}\", clientAuth.getUsername()).getMessage());\n                    NettyUtils.write(ctx.getChannel(), errorBytes, null);\n                    break;\n                }\n\n                // 如果存在订阅信息\n                if (StringUtils.isNotEmpty(clientAuth.getDestination())\n                    && StringUtils.isNotEmpty(clientAuth.getClientId())) {\n                    ClientIdentity clientIdentity = new ClientIdentity(clientAuth.getDestination(),\n                        Short.valueOf(clientAuth.getClientId()),\n                        clientAuth.getFilter());\n                    try {\n                        MDC.put(\"destination\", clientIdentity.getDestination());\n                        embeddedServer.subscribe(clientIdentity);\n                        // 尝试启动，如果已经启动，忽略\n                        if (!embeddedServer.isStart(clientIdentity.getDestination())) {\n                            ServerRunningMonitor runningMonitor = ServerRunningMonitors.getRunningMonitor(clientIdentity.getDestination());\n                            if (!runningMonitor.isStart()) {\n                                runningMonitor.start();\n                            }\n                        }\n                    } finally {\n                        MDC.remove(\"destination\");\n                    }\n                }\n                // 鉴权一次性，暂不统计\n                NettyUtils.ack(ctx.getChannel(), future -> {\n                    logger.info(\"remove unused channel handlers after authentication is done successfully.\");\n                    ctx.getPipeline().remove(HandshakeInitializationHandler.class.getName());\n                    ctx.getPipeline().remove(ClientAuthenticationHandler.class.getName());\n\n                    int readTimeout = defaultSubscriptorDisconnectIdleTimeout;\n                    int writeTimeout = defaultSubscriptorDisconnectIdleTimeout;\n                    if (clientAuth.getNetReadTimeout() > 0) {\n                        readTimeout = clientAuth.getNetReadTimeout();\n                    }\n                    if (clientAuth.getNetWriteTimeout() > 0) {\n                        writeTimeout = clientAuth.getNetWriteTimeout();\n                    }\n                    // fix bug: soTimeout parameter's unit from connector is\n                    // millseconds.\n                    IdleStateHandler idleStateHandler = new IdleStateHandler(NettyUtils.hashedWheelTimer,\n                        readTimeout,\n                        writeTimeout,\n                        0,\n                        TimeUnit.MILLISECONDS);\n                    ctx.getPipeline().addBefore(SessionHandler.class.getName(),\n                        IdleStateHandler.class.getName(),\n                        idleStateHandler);\n\n                    IdleStateAwareChannelHandler idleStateAwareChannelHandler = new IdleStateAwareChannelHandler() {\n\n                        public void channelIdle(ChannelHandlerContext ctx1, IdleStateEvent e1) throws Exception {\n                            logger.warn(\"channel:{} idle timeout exceeds, close channel to save server resources...\",\n                                ctx1.getChannel());\n                            ctx1.getChannel().close();\n                        }\n\n                    };\n                    ctx.getPipeline().addBefore(SessionHandler.class.getName(),\n                        IdleStateAwareChannelHandler.class.getName(),\n                        idleStateAwareChannelHandler);\n                });\n                break;\n        }\n    }\n\n    public void setEmbeddedServer(CanalServerWithEmbedded embeddedServer) {\n        this.embeddedServer = embeddedServer;\n    }\n\n    public void setSeed(byte[] seed) {\n        this.seed = seed;\n    }\n\n}\n"
  },
  {
    "path": "server/src/main/java/com/alibaba/otter/canal/server/netty/handler/FixedHeaderFrameDecoder.java",
    "content": "package com.alibaba.otter.canal.server.netty.handler;\n\nimport org.jboss.netty.buffer.ChannelBuffer;\nimport org.jboss.netty.channel.Channel;\nimport org.jboss.netty.channel.ChannelHandlerContext;\nimport org.jboss.netty.handler.codec.replay.ReplayingDecoder;\nimport org.jboss.netty.handler.codec.replay.VoidEnum;\n\n/**\n * 解析对应的header信息\n * \n * @author jianghang 2012-10-24 上午11:31:39\n * @version 1.0.0\n */\npublic class FixedHeaderFrameDecoder extends ReplayingDecoder<VoidEnum> {\n\n    protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, VoidEnum state)\n                                                                                                             throws Exception {\n        return buffer.readBytes(buffer.readInt());\n    }\n}\n"
  },
  {
    "path": "server/src/main/java/com/alibaba/otter/canal/server/netty/handler/HandshakeInitializationHandler.java",
    "content": "package com.alibaba.otter.canal.server.netty.handler;\n\nimport org.jboss.netty.channel.ChannelHandlerContext;\nimport org.jboss.netty.channel.ChannelStateEvent;\nimport org.jboss.netty.channel.SimpleChannelHandler;\nimport org.jboss.netty.channel.group.ChannelGroup;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.otter.canal.protocol.CanalPacket;\nimport com.alibaba.otter.canal.protocol.CanalPacket.Handshake;\nimport com.alibaba.otter.canal.protocol.CanalPacket.Packet;\nimport com.alibaba.otter.canal.server.netty.NettyUtils;\nimport com.google.protobuf.ByteString;\n\n/**\n * handshake交互\n * \n * @author jianghang 2012-10-24 上午11:39:54\n * @version 1.0.0\n */\npublic class HandshakeInitializationHandler extends SimpleChannelHandler {\n\n    // support to maintain socket channel.\n    private ChannelGroup childGroups;\n\n    public HandshakeInitializationHandler(ChannelGroup childGroups){\n        this.childGroups = childGroups;\n    }\n\n    private static final Logger logger = LoggerFactory.getLogger(HandshakeInitializationHandler.class);\n\n    public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {\n        // add new socket channel in channel container, used to manage sockets.\n        if (childGroups != null) {\n            childGroups.add(ctx.getChannel());\n        }\n\n        final byte[] seed = org.apache.commons.lang3.RandomUtils.nextBytes(8);\n        byte[] body = Packet.newBuilder()\n            .setType(CanalPacket.PacketType.HANDSHAKE)\n            .setVersion(NettyUtils.VERSION)\n            .setBody(Handshake.newBuilder().setSeeds(ByteString.copyFrom(seed)).build().toByteString())\n            .build()\n            .toByteArray();\n\n        NettyUtils.write(ctx.getChannel(), body, future -> {\n            ctx.getPipeline().get(HandshakeInitializationHandler.class.getName());\n            ClientAuthenticationHandler handler = (ClientAuthenticationHandler) ctx.getPipeline()\n                .get(ClientAuthenticationHandler.class.getName());\n            handler.setSeed(seed);\n        });\n        logger.info(\"send handshake initialization packet to : {}\", ctx.getChannel());\n    }\n}\n"
  },
  {
    "path": "server/src/main/java/com/alibaba/otter/canal/server/netty/handler/SessionHandler.java",
    "content": "package com.alibaba.otter.canal.server.netty.handler;\n\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.commons.lang.exception.ExceptionUtils;\nimport org.jboss.netty.buffer.ChannelBuffer;\nimport org.jboss.netty.channel.*;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.slf4j.MDC;\nimport org.springframework.util.CollectionUtils;\n\nimport com.alibaba.otter.canal.common.zookeeper.running.ServerRunningMonitor;\nimport com.alibaba.otter.canal.common.zookeeper.running.ServerRunningMonitors;\nimport com.alibaba.otter.canal.protocol.CanalEntry.Entry;\nimport com.alibaba.otter.canal.protocol.CanalPacket;\nimport com.alibaba.otter.canal.protocol.ClientIdentity;\nimport com.alibaba.otter.canal.protocol.Message;\nimport com.alibaba.otter.canal.protocol.CanalPacket.*;\nimport com.alibaba.otter.canal.server.embedded.CanalServerWithEmbedded;\nimport com.alibaba.otter.canal.server.netty.NettyUtils;\nimport com.alibaba.otter.canal.server.netty.listener.ChannelFutureAggregator;\nimport com.google.protobuf.ByteString;\nimport com.google.protobuf.CodedOutputStream;\nimport com.google.protobuf.WireFormat;\n\npublic class SessionHandler extends SimpleChannelHandler {\n\n    private static final Logger     logger = LoggerFactory.getLogger(SessionHandler.class);\n    private CanalServerWithEmbedded embeddedServer;\n\n    public SessionHandler(){\n    }\n\n    public SessionHandler(CanalServerWithEmbedded embeddedServer){\n        this.embeddedServer = embeddedServer;\n    }\n\n    @SuppressWarnings({ \"deprecation\" })\n    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {\n        long start = System.nanoTime();\n        ChannelBuffer buffer = (ChannelBuffer) e.getMessage();\n        Packet packet = Packet.parseFrom(buffer.readBytes(buffer.readableBytes()).array());\n        try {\n            switch (packet.getType()) {\n                case SUBSCRIPTION:\n                    Sub sub = Sub.parseFrom(packet.getBody());\n                    if (StringUtils.isNotEmpty(sub.getDestination()) && StringUtils.isNotEmpty(sub.getClientId())) {\n                        ClientIdentity clientIdentity = new ClientIdentity(sub.getDestination(), Short.parseShort(sub.getClientId()), sub.getFilter());\n                        MDC.put(\"destination\", clientIdentity.getDestination());\n\n                        // 尝试启动，如果已经启动，忽略\n                        if (!embeddedServer.isStart(clientIdentity.getDestination())) {\n                            ServerRunningMonitor runningMonitor = ServerRunningMonitors.getRunningMonitor(clientIdentity.getDestination());\n                            if (!runningMonitor.isStart()) {\n                                runningMonitor.start();\n                            }\n                        }\n\n                        embeddedServer.subscribe(clientIdentity);\n                        // ctx.setAttachment(clientIdentity);// 设置状态数据\n                        byte[] ackBytes = NettyUtils.ackPacket();\n                        NettyUtils.write(ctx.getChannel(), ackBytes, new ChannelFutureAggregator(sub.getDestination(),\n                            sub,\n                            packet.getType(),\n                            ackBytes.length,\n                            System.nanoTime() - start));\n                    } else {\n                        byte[] errorBytes = NettyUtils.errorPacket(401, \"destination or clientId is null. Sub: \" + sub);\n                        NettyUtils.write(ctx.getChannel(),\n                            errorBytes,\n                            new ChannelFutureAggregator(sub.getDestination(),\n                                sub,\n                                packet.getType(),\n                                errorBytes.length,\n                                System.nanoTime() - start,\n                                (short) 401));\n                    }\n                    break;\n                case UNSUBSCRIPTION:\n                    Unsub unsub = Unsub.parseFrom(packet.getBody());\n                    if (StringUtils.isNotEmpty(unsub.getDestination()) && StringUtils.isNotEmpty(unsub.getClientId())) {\n                        ClientIdentity clientIdentity = new ClientIdentity(unsub.getDestination(), Short.parseShort(unsub.getClientId()), unsub.getFilter());\n                        MDC.put(\"destination\", clientIdentity.getDestination());\n\n                        embeddedServer.unsubscribe(clientIdentity);\n                        stopCanalInstanceIfNecessary(clientIdentity);// 尝试关闭\n\n                        byte[] ackBytes = NettyUtils.ackPacket();\n                        NettyUtils.write(ctx.getChannel(),\n                            ackBytes,\n                            new ChannelFutureAggregator(unsub.getDestination(),\n                                unsub,\n                                packet.getType(),\n                                ackBytes.length,\n                                System.nanoTime() - start));\n                    } else {\n                        String error = \"destination or clientId is null. Unsub: \" + unsub;\n                        byte[] errorBytes = NettyUtils.errorPacket(401, error);\n                        NettyUtils.write(ctx.getChannel(),\n                            errorBytes,\n                            new ChannelFutureAggregator(unsub.getDestination(),\n                                unsub,\n                                packet.getType(),\n                                errorBytes.length,\n                                System.nanoTime() - start,\n                                (short) 401));\n                    }\n                    break;\n                case GET:\n                    Get get = CanalPacket.Get.parseFrom(packet.getBody());\n                    if (StringUtils.isNotEmpty(get.getDestination()) && StringUtils.isNotEmpty(get.getClientId())) {\n                        ClientIdentity clientIdentity = new ClientIdentity(get.getDestination(), Short.parseShort(get.getClientId()));\n                        MDC.put(\"destination\", clientIdentity.getDestination());\n\n                        Message message = null;\n\n                        // if (get.getAutoAck()) {\n                        // if (get.getTimeout() == -1) {//是否是初始值\n                        // message = embeddedServer.get(clientIdentity,\n                        // get.getFetchSize());\n                        // } else {\n                        // TimeUnit unit = convertTimeUnit(get.getUnit());\n                        // message = embeddedServer.get(clientIdentity,\n                        // get.getFetchSize(), get.getTimeout(), unit);\n                        // }\n                        // } else {\n                        if (get.getTimeout() == -1) {// 是否是初始值\n                            message = embeddedServer.getWithoutAck(clientIdentity, get.getFetchSize());\n                        } else {\n                            TimeUnit unit = convertTimeUnit(get.getUnit());\n                            message = embeddedServer.getWithoutAck(clientIdentity, get.getFetchSize(), get.getTimeout(), unit);\n                        }\n                        // }\n\n                        if (message.getId() != -1 && message.isRaw()) {\n                            List<ByteString> rowEntries = message.getRawEntries();\n                            // message size\n                            int messageSize = 0;\n                            messageSize += com.google.protobuf.CodedOutputStream.computeInt64Size(1, message.getId());\n\n                            int dataSize = 0;\n                            for (ByteString rowEntry : rowEntries) {\n                                dataSize += CodedOutputStream.computeBytesSizeNoTag(rowEntry);\n                            }\n                            messageSize += dataSize;\n                            // messageSize += 1 * rowEntries.size();\n                            messageSize += rowEntries.size();\n\n                            // packet size\n                            int size = 0;\n                            size += com.google.protobuf.CodedOutputStream.computeEnumSize(3,\n                                PacketType.MESSAGES.getNumber());\n                            size += com.google.protobuf.CodedOutputStream.computeTagSize(5)\n                                    + com.google.protobuf.CodedOutputStream.computeRawVarint32Size(messageSize)\n                                    + messageSize;\n\n                            // recyle bytes\n                            // ByteBuffer byteBuffer = (ByteBuffer)\n                            // ctx.getAttachment();\n                            // if (byteBuffer != null && size <=\n                            // byteBuffer.capacity()) {\n                            // byteBuffer.clear();\n                            // } else {\n                            // byteBuffer =\n                            // ByteBuffer.allocate(size).order(ByteOrder.BIG_ENDIAN);\n                            // ctx.setAttachment(byteBuffer);\n                            // }\n                            // CodedOutputStream output =\n                            // CodedOutputStream.newInstance(byteBuffer);\n                            byte[] body = new byte[size];\n                            CodedOutputStream output = CodedOutputStream.newInstance(body);\n                            output.writeEnum(3, PacketType.MESSAGES.getNumber());\n\n                            output.writeTag(5, WireFormat.WIRETYPE_LENGTH_DELIMITED);\n                            output.writeRawVarint32(messageSize);\n                            // message\n                            output.writeInt64(1, message.getId());\n                            for (ByteString rowEntry : rowEntries) {\n                                output.writeBytes(2, rowEntry);\n                            }\n                            output.checkNoSpaceLeft();\n                            NettyUtils.write(ctx.getChannel(), body, new ChannelFutureAggregator(get.getDestination(),\n                                get,\n                                packet.getType(),\n                                body.length,\n                                System.nanoTime() - start,\n                                message.getId() == -1));\n\n                            // output.flush();\n                            // byteBuffer.flip();\n                            // NettyUtils.write(ctx.getChannel(), byteBuffer,\n                            // null);\n                        } else {\n                            Messages.Builder messageBuilder = CanalPacket.Messages.newBuilder();\n                            messageBuilder.setBatchId(message.getId());\n                            if (message.getId() != -1) {\n                                if (message.isRaw() && !CollectionUtils.isEmpty(message.getRawEntries())) {\n                                    messageBuilder.addAllMessages(message.getRawEntries());\n                                } else if (!CollectionUtils.isEmpty(message.getEntries())) {\n                                    for (Entry entry : message.getEntries()) {\n                                        messageBuilder.addMessages(entry.toByteString());\n                                    }\n                                }\n                            }\n\n                            Packet.Builder packetBuilder = CanalPacket.Packet.newBuilder();\n                            packetBuilder.setType(PacketType.MESSAGES).setVersion(NettyUtils.VERSION);\n                            byte[] body = packetBuilder.setBody(messageBuilder.build().toByteString()).build().toByteArray();\n                            NettyUtils.write(ctx.getChannel(), body, new ChannelFutureAggregator(get.getDestination(),\n                                get,\n                                packet.getType(),\n                                body.length,\n                                System.nanoTime() - start,\n                                message.getId() == -1));// 输出数据\n                        }\n                    } else {\n                        byte[] errorBytes = NettyUtils.errorPacket(401, \"destination or clientId is null. Get: \" + get);\n                        NettyUtils.write(ctx.getChannel(),\n                            errorBytes,\n                            new ChannelFutureAggregator(get.getDestination(),\n                                get,\n                                packet.getType(),\n                                errorBytes.length,\n                                System.nanoTime() - start,\n                                (short) 401));\n                    }\n                    break;\n                case CLIENTACK:\n                    ClientAck ack = CanalPacket.ClientAck.parseFrom(packet.getBody());\n                    if (StringUtils.isNotEmpty(ack.getDestination()) && StringUtils.isNotEmpty(ack.getClientId())) {\n                        MDC.put(\"destination\", ack.getDestination());\n                        if (ack.getBatchId() == 0L) {\n                            byte[] errorBytes = NettyUtils.errorPacket(402, \"batchId should assign value. Ack: \"+ack);\n                            NettyUtils.write(ctx.getChannel(),\n                                errorBytes,\n                                new ChannelFutureAggregator(ack.getDestination(),\n                                    ack,\n                                    packet.getType(),\n                                    errorBytes.length,\n                                    System.nanoTime() - start,\n                                    (short) 402));\n                        } else if (ack.getBatchId() == -1L) { // -1代表上一次get没有数据，直接忽略之\n                            // donothing\n                        } else {\n                            ClientIdentity clientIdentity = new ClientIdentity(ack.getDestination(), Short.parseShort(ack.getClientId()));\n                            embeddedServer.ack(clientIdentity, ack.getBatchId());\n                            new ChannelFutureAggregator(ack.getDestination(),\n                                ack,\n                                packet.getType(),\n                                0,\n                                System.nanoTime() - start).operationComplete(null);\n                        }\n                    } else {\n                        byte[] errorBytes = NettyUtils.errorPacket(401, \"destination or clientId is null. Ack: \" + ack);\n                        NettyUtils.write(ctx.getChannel(),\n                            errorBytes,\n                            new ChannelFutureAggregator(ack.getDestination(),\n                                ack,\n                                packet.getType(),\n                                errorBytes.length,\n                                System.nanoTime() - start,\n                                (short) 401));\n                    }\n                    break;\n                case CLIENTROLLBACK:\n                    ClientRollback rollback = CanalPacket.ClientRollback.parseFrom(packet.getBody());\n                    if (StringUtils.isNotEmpty(rollback.getDestination()) && StringUtils.isNotEmpty(rollback.getClientId())) {\n                        ClientIdentity clientIdentity = new ClientIdentity(rollback.getDestination(), Short.parseShort(rollback.getClientId()));\n                        MDC.put(\"destination\", rollback.getDestination());\n\n                        if (rollback.getBatchId() == 0L) {\n                            embeddedServer.rollback(clientIdentity);// 回滚所有批次\n                        } else {\n                            embeddedServer.rollback(clientIdentity, rollback.getBatchId()); // 只回滚单个批次\n                        }\n\n                        new ChannelFutureAggregator(rollback.getDestination(),\n                            rollback,\n                            packet.getType(),\n                            0,\n                            System.nanoTime() - start).operationComplete(null);\n                    } else {\n                        byte[] errorBytes = NettyUtils.errorPacket(401, \"destination or clientId is null. Rollback: \" + rollback);\n                        NettyUtils.write(ctx.getChannel(),\n                            errorBytes,\n                            new ChannelFutureAggregator(rollback.getDestination(),\n                                rollback,\n                                packet.getType(),\n                                errorBytes.length,\n                                System.nanoTime() - start,\n                                (short) 401));\n                    }\n                    break;\n                default:\n                    byte[] errorBytes = NettyUtils.errorPacket(400, \"packet type: \" + packet.getType() + \" is NOT supported!\");\n                    NettyUtils.write(ctx.getChannel(), errorBytes, new ChannelFutureAggregator(ctx.getChannel()\n                        .getRemoteAddress()\n                        .toString(), null, packet.getType(), errorBytes.length, System.nanoTime() - start, (short) 400));\n                    break;\n            }\n        } catch (Throwable exception) {\n            String error = \"something goes wrong with channel: \" + ctx.getChannel() + \", exception: \" + ExceptionUtils.getStackTrace(exception);\n            byte[] errorBytes = NettyUtils.errorPacket(400, error);\n            NettyUtils.write(ctx.getChannel(), errorBytes, new ChannelFutureAggregator(ctx.getChannel()\n                .getRemoteAddress().toString(), null, packet.getType(), errorBytes.length, System.nanoTime() - start, (short) 400));\n        } finally {\n            MDC.remove(\"destination\");\n        }\n    }\n\n    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {\n        logger.error(\"something goes wrong with channel:{}, exception={}\",\n            ctx.getChannel(),\n            ExceptionUtils.getStackTrace(e.getCause()));\n\n        ctx.getChannel().close();\n    }\n\n    public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {\n        // logger.info(\"remove binding subscription value object if any...\");\n        // ClientIdentity clientIdentity = (ClientIdentity) ctx.getAttachment();\n        // // 如果唯一的订阅者都取消了订阅，直接关闭服务，针对内部版本模式下可以减少资源浪费\n        // if (clientIdentity != null) {\n        // stopCanalInstanceIfNecessary(clientIdentity);\n        // }\n    }\n\n    private void stopCanalInstanceIfNecessary(ClientIdentity clientIdentity) {\n        List<ClientIdentity> clientIdentitys = embeddedServer.listAllSubscribe(clientIdentity.getDestination());\n        if (clientIdentitys != null && clientIdentitys.size() == 1 && clientIdentitys.contains(clientIdentity)) {\n            ServerRunningMonitor runningMonitor = ServerRunningMonitors.getRunningMonitor(clientIdentity.getDestination());\n            if (runningMonitor.isStart()) {\n                runningMonitor.release();\n            }\n        }\n    }\n\n    private TimeUnit convertTimeUnit(int unit) {\n        switch (unit) {\n            case 0:\n                return TimeUnit.NANOSECONDS;\n            case 1:\n                return TimeUnit.MICROSECONDS;\n            case 2:\n                return TimeUnit.MILLISECONDS;\n            case 3:\n                return TimeUnit.SECONDS;\n            case 4:\n                return TimeUnit.MINUTES;\n            case 5:\n                return TimeUnit.HOURS;\n            case 6:\n                return TimeUnit.DAYS;\n            default:\n                return TimeUnit.MILLISECONDS;\n        }\n    }\n\n    public void setEmbeddedServer(CanalServerWithEmbedded embeddedServer) {\n        this.embeddedServer = embeddedServer;\n    }\n\n}\n"
  },
  {
    "path": "server/src/main/java/com/alibaba/otter/canal/server/netty/listener/ChannelFutureAggregator.java",
    "content": "package com.alibaba.otter.canal.server.netty.listener;\n\nimport com.alibaba.otter.canal.protocol.CanalPacket;\nimport com.google.common.base.Preconditions;\nimport com.google.protobuf.GeneratedMessageV3;\nimport org.jboss.netty.channel.ChannelFuture;\nimport org.jboss.netty.channel.ChannelFutureListener;\n\nimport static com.alibaba.otter.canal.server.netty.CanalServerWithNettyProfiler.profiler;\nimport static com.alibaba.otter.canal.server.netty.NettyUtils.HEADER_LENGTH;\n\n/**\n * @author Chuanyi Li\n */\npublic class ChannelFutureAggregator implements ChannelFutureListener {\n\n    private ClientRequestResult result;\n\n    public ChannelFutureAggregator(String destination, GeneratedMessageV3 request, CanalPacket.PacketType type, int amount, long latency, boolean empty) {\n        this(destination, request, type, amount, latency, empty, (short) 0);\n    }\n\n    public ChannelFutureAggregator(String destination, GeneratedMessageV3 request, CanalPacket.PacketType type, int amount, long latency) {\n        this(destination, request, type, amount, latency, false, (short) 0);\n    }\n\n    public ChannelFutureAggregator(String destination, GeneratedMessageV3 request, CanalPacket.PacketType type, int amount, long latency, short errorCode) {\n        this(destination, request, type, amount, latency, false, errorCode);\n    }\n\n    private ChannelFutureAggregator(String destination, GeneratedMessageV3 request, CanalPacket.PacketType type, int amount, long latency, boolean empty, short errorCode) {\n        this.result = new ClientRequestResult.Builder()\n                .destination(destination)\n                .type(type)\n                .request(request)\n                .amount(amount + HEADER_LENGTH)\n                .latency(latency)\n                .errorCode(errorCode)\n                .empty(empty)\n                .build();\n    }\n\n    @Override\n    public void operationComplete(ChannelFuture future) {\n        // profiling after I/O operation\n        if (future != null && future.getCause() != null) {\n            result.channelError = future.getCause();\n        }\n        profiler().profiling(result);\n    }\n\n    /**\n     * Client request result pojo\n     */\n    public static class ClientRequestResult {\n\n        private String                 destination;\n        private CanalPacket.PacketType type;\n        private GeneratedMessageV3       request;\n        private int                    amount;\n        private long                   latency;\n        private short                  errorCode;\n        private boolean                empty;\n        private Throwable              channelError;\n\n        private ClientRequestResult() {}\n\n        private ClientRequestResult(Builder builder) {\n            this.destination = Preconditions.checkNotNull(builder.destination);\n            this.type = Preconditions.checkNotNull(builder.type);\n            this.request = builder.request;\n            this.amount = builder.amount;\n            this.latency = builder.latency;\n            this.errorCode = builder.errorCode;\n            this.empty = builder.empty;\n            this.channelError = builder.channelError;\n        }\n\n        // auto-generated\n        public static class Builder {\n\n            private String                 destination;\n            private CanalPacket.PacketType type;\n            private GeneratedMessageV3       request;\n            private int                    amount;\n            private long                   latency;\n            private short                  errorCode;\n            private boolean                empty;\n            private Throwable              channelError;\n\n            Builder destination(String destination) {\n                this.destination = destination;\n                return this;\n            }\n\n            Builder type(CanalPacket.PacketType type) {\n                this.type = type;\n                return this;\n            }\n\n            Builder request(GeneratedMessageV3 request) {\n                this.request = request;\n                return this;\n            }\n\n            Builder amount(int amount) {\n                this.amount = amount;\n                return this;\n            }\n\n            Builder latency(long latency) {\n                this.latency = latency;\n                return this;\n            }\n\n            Builder errorCode(short errorCode) {\n                this.errorCode = errorCode;\n                return this;\n            }\n\n            Builder empty(boolean empty) {\n                this.empty = empty;\n                return this;\n            }\n\n            public Builder channelError(Throwable channelError) {\n                this.channelError = channelError;\n                return this;\n            }\n\n            public Builder fromPrototype(ClientRequestResult prototype) {\n                destination = prototype.destination;\n                type = prototype.type;\n                request = prototype.request;\n                amount = prototype.amount;\n                latency = prototype.latency;\n                errorCode = prototype.errorCode;\n                empty = prototype.empty;\n                channelError = prototype.channelError;\n                return this;\n            }\n\n            ClientRequestResult build() {\n                return new ClientRequestResult(this);\n            }\n        }\n        // getters\n        public String getDestination() {\n            return destination;\n        }\n\n        public CanalPacket.PacketType getType() {\n            return type;\n        }\n\n        public GeneratedMessageV3 getRequest() {\n            return request;\n        }\n\n        public int getAmount() {\n            return amount;\n        }\n\n        public long getLatency() {\n            return latency;\n        }\n\n        public short getErrorCode() {\n            return errorCode;\n        }\n\n        public boolean getEmpty() {\n            return empty;\n        }\n\n        public Throwable getChannelError() {\n            return channelError;\n        }\n    }\n}\n"
  },
  {
    "path": "server/src/main/java/com/alibaba/otter/canal/spi/CanalMetricsProvider.java",
    "content": "package com.alibaba.otter.canal.spi;\n\n/**\n * Use java service provider mechanism to provide {@link CanalMetricsService}.\n * <pre>\n * Example:\n * {@code\n *     ServiceLoader<CanalMetricsProvider> providers = ServiceLoader.load(CanalMetricsProvider.class);\n *     List<CanalMetricsProvider> list = new ArrayList<CanalMetricsProvider>();\n *     for (CanalMetricsProvider provider : providers) {\n *         list.add(provider);\n *     }\n * }\n * </pre>\n * @author Chuanyi Li\n */\npublic interface CanalMetricsProvider {\n\n    /**\n     * @return Impl of {@link CanalMetricsService}\n     */\n    CanalMetricsService getService();\n\n}\n"
  },
  {
    "path": "server/src/main/java/com/alibaba/otter/canal/spi/CanalMetricsService.java",
    "content": "package com.alibaba.otter.canal.spi;\n\nimport com.alibaba.otter.canal.instance.core.CanalInstance;\n\n/**\n * Canal server/instance metrics for export.\n * <strong>\n *     Designed to be created by service provider.\n * </strong>\n * @see CanalMetricsProvider\n * @author Chuanyi Li\n */\npublic interface CanalMetricsService {\n\n    /**\n     * Initialization on canal server startup.\n     */\n    void initialize();\n\n    /**\n     * Clean-up at canal server stop phase.\n     */\n    void terminate();\n\n    /**\n     * @return {@code true} if the metrics service is running, otherwise {@code false}.\n     */\n    boolean isRunning();\n\n    /**\n     * Register instance level metrics for specified instance.\n     * @param instance {@link CanalInstance}\n     */\n    void register(CanalInstance instance);\n\n    /**\n     * Unregister instance level metrics for specified instance.\n     * @param instance {@link CanalInstance}\n     */\n    void unregister(CanalInstance instance);\n\n    /**\n     * @param port server port for pull\n     */\n    void setServerPort(int port);\n\n}\n"
  },
  {
    "path": "server/src/main/java/com/alibaba/otter/canal/spi/NopCanalMetricsService.java",
    "content": "package com.alibaba.otter.canal.spi;\n\nimport com.alibaba.otter.canal.instance.core.CanalInstance;\n\n/**\n * @author Chuanyi Li\n */\npublic class NopCanalMetricsService implements CanalMetricsService {\n\n    public static final NopCanalMetricsService NOP = new NopCanalMetricsService();\n\n    private NopCanalMetricsService() {}\n\n    @Override\n    public void initialize() {\n\n    }\n\n    @Override\n    public void terminate() {\n\n    }\n\n    @Override\n    public boolean isRunning() {\n        return false;\n    }\n\n    @Override\n    public void register(CanalInstance instance) {\n\n    }\n\n    @Override\n    public void unregister(CanalInstance instance) {\n\n    }\n\n    @Override\n    public void setServerPort(int port) {\n\n    }\n}\n"
  },
  {
    "path": "server/src/test/java/com/alibaba/otter/canal/server/CanalServerTest.java",
    "content": "package com.alibaba.otter.canal.server;\n\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.SocketChannel;\nimport java.util.Arrays;\n\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.instance.manager.CanalInstanceWithManager;\nimport com.alibaba.otter.canal.instance.manager.model.Canal;\nimport com.alibaba.otter.canal.instance.manager.model.CanalParameter;\nimport com.alibaba.otter.canal.instance.manager.model.CanalParameter.HAMode;\nimport com.alibaba.otter.canal.instance.manager.model.CanalParameter.IndexMode;\nimport com.alibaba.otter.canal.instance.manager.model.CanalParameter.MetaMode;\nimport com.alibaba.otter.canal.instance.manager.model.CanalParameter.SourcingType;\nimport com.alibaba.otter.canal.instance.manager.model.CanalParameter.StorageMode;\nimport com.alibaba.otter.canal.protocol.CanalPacket.Ack;\nimport com.alibaba.otter.canal.protocol.CanalPacket.ClientAck;\nimport com.alibaba.otter.canal.protocol.CanalPacket.ClientAuth;\nimport com.alibaba.otter.canal.protocol.CanalPacket.ClientRollback;\nimport com.alibaba.otter.canal.protocol.CanalPacket.Get;\nimport com.alibaba.otter.canal.protocol.CanalPacket.Handshake;\nimport com.alibaba.otter.canal.protocol.CanalPacket.Messages;\nimport com.alibaba.otter.canal.protocol.CanalPacket.Packet;\nimport com.alibaba.otter.canal.protocol.CanalPacket.PacketType;\nimport com.alibaba.otter.canal.protocol.CanalPacket.Sub;\nimport com.alibaba.otter.canal.protocol.CanalPacket.Unsub;\nimport com.alibaba.otter.canal.server.embedded.CanalServerWithEmbedded;\nimport com.alibaba.otter.canal.server.netty.CanalServerWithNetty;\nimport com.alibaba.otter.canal.server.netty.NettyUtils;\n\n@Ignore\npublic class CanalServerTest {\n\n    protected static final String cluster1      = \"127.0.0.1:2188\";\n    protected static final String DESTINATION   = \"ljhtest1\";\n    protected static final String DETECTING_SQL = \"insert into retl.xdual values(1,now()) on duplicate key update x=now()\";\n    protected static final String MYSQL_ADDRESS = \"127.0.0.1\";\n    protected static final String USERNAME      = \"retl\";\n    protected static final String PASSWORD      = \"retl\";\n    protected static final String FILTER        = \"retl\\\\..*,erosa.canaltable1s,erosa.canaltable1t\";\n\n    private final ByteBuffer      header        = ByteBuffer.allocate(4);\n    private CanalServerWithNetty  nettyServer;\n\n    @Before\n    public void setUp() {\n        CanalServerWithEmbedded embeddedServer = new CanalServerWithEmbedded();\n        embeddedServer.setCanalInstanceGenerator(destination -> {\n            Canal canal = buildCanal();\n            return new CanalInstanceWithManager(canal, FILTER);\n        });\n\n        nettyServer = CanalServerWithNetty.instance();\n        nettyServer.setEmbeddedServer(embeddedServer);\n        nettyServer.setPort(1088);\n        nettyServer.start();\n    }\n\n    @Test\n    public void testAuth() {\n\n        try {\n            SocketChannel channel = SocketChannel.open();\n            channel.connect(new InetSocketAddress(\"127.0.0.1\", 1088));\n            Packet p = Packet.parseFrom(readNextPacket(channel));\n\n            if (p.getVersion() != 1) {\n                throw new Exception(\"unsupported version at this client.\");\n            }\n\n            if (p.getType() != PacketType.HANDSHAKE) {\n                throw new Exception(\"expect handshake but found other type.\");\n            }\n            //\n            Handshake handshake = Handshake.parseFrom(p.getBody());\n            System.out.println(handshake.getSupportedCompressions());\n            //\n            ClientAuth ca = ClientAuth.newBuilder()\n                .setUsername(\"\")\n                .setNetReadTimeout(10000)\n                .setNetWriteTimeout(10000)\n                .build();\n            writeWithHeader(channel,\n                Packet.newBuilder()\n                    .setType(PacketType.CLIENTAUTHENTICATION)\n                    .setVersion(NettyUtils.VERSION)\n                    .setBody(ca.toByteString())\n                    .build()\n                    .toByteArray());\n            //\n            p = Packet.parseFrom(readNextPacket(channel));\n            if (p.getType() != PacketType.ACK) {\n                throw new Exception(\"unexpected packet type when ack is expected\");\n            }\n\n            Ack ack = Ack.parseFrom(p.getBody());\n            if (ack.getErrorCode() > 0) {\n                throw new Exception(\"something goes wrong when doing authentication: \" + ack.getErrorMessage());\n            }\n\n            writeWithHeader(channel, Packet.newBuilder()\n                .setType(PacketType.SUBSCRIPTION)\n                .setVersion(NettyUtils.VERSION)\n                .setBody(Sub.newBuilder().setDestination(DESTINATION).setClientId(\"1\").build().toByteString())\n                .build()\n                .toByteArray());\n            //\n            p = Packet.parseFrom(readNextPacket(channel));\n            ack = Ack.parseFrom(p.getBody());\n            if (ack.getErrorCode() > 0) {\n                throw new Exception(\"failed to subscribe with reason: \" + ack.getErrorMessage());\n            }\n\n            for (int i = 0; i < 10; i++) {\n                writeWithHeader(channel,\n                    Packet.newBuilder()\n                        .setType(PacketType.GET)\n                        .setVersion(NettyUtils.VERSION)\n                        .setBody(Get.newBuilder()\n                            .setDestination(DESTINATION)\n                            .setClientId(\"1\")\n                            .setFetchSize(10)\n                            .build()\n                            .toByteString())\n                        .build()\n                        .toByteArray());\n                p = Packet.parseFrom(readNextPacket(channel));\n\n                long batchId = -1L;\n                switch (p.getType()) {\n                    case MESSAGES: {\n                        Messages messages = Messages.parseFrom(p.getBody());\n                        batchId = messages.getBatchId();\n                        break;\n                    }\n                    case ACK: {\n                        ack = Ack.parseFrom(p.getBody());\n                        if (ack.getErrorCode() > 0) {\n                            throw new Exception(\"failed to subscribe with reason: \" + ack.getErrorMessage());\n                        }\n                        break;\n                    }\n                    default: {\n                        throw new Exception(\"unexpected packet type: \" + p.getType());\n                    }\n                }\n\n                System.out.println(\"!!!!!!!!!!!!!!!!! \" + batchId);\n                Thread.sleep(1000L);\n                writeWithHeader(channel,\n                    Packet.newBuilder()\n                        .setType(PacketType.CLIENTACK)\n                        .setVersion(NettyUtils.VERSION)\n                        .setBody(ClientAck.newBuilder()\n                            .setDestination(DESTINATION)\n                            .setClientId(\"1\")\n                            .setBatchId(batchId)\n                            .build()\n                            .toByteString())\n                        .build()\n                        .toByteArray());\n            }\n\n            writeWithHeader(channel,\n                Packet.newBuilder()\n                    .setType(PacketType.CLIENTROLLBACK)\n                    .setVersion(NettyUtils.VERSION)\n                    .setBody(ClientRollback.newBuilder()\n                        .setDestination(DESTINATION)\n                        .setClientId(\"1\")\n                        .build()\n                        .toByteString())\n                    .build()\n                    .toByteArray());\n\n            writeWithHeader(channel,\n                Packet.newBuilder()\n                    .setType(PacketType.UNSUBSCRIPTION)\n                    .setVersion(NettyUtils.VERSION)\n                    .setBody(Unsub.newBuilder().setDestination(DESTINATION).setClientId(\"1\").build().toByteString())\n                    .build()\n                    .toByteArray());\n\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    @After\n    public void tearDown() {\n        nettyServer.stop();\n    }\n\n    private byte[] readNextPacket(SocketChannel channel) throws IOException {\n        header.clear();\n        read(channel, header);\n        int bodyLen = header.getInt(0);\n        ByteBuffer bodyBuf = ByteBuffer.allocate(bodyLen);\n        read(channel, bodyBuf);\n        return bodyBuf.array();\n    }\n\n    private void writeWithHeader(SocketChannel channel, byte[] body) throws IOException {\n        ByteBuffer header = ByteBuffer.allocate(4);\n        header.putInt(body.length);\n        header.flip();\n        int len = channel.write(header);\n        assert (len == header.capacity());\n\n        channel.write(ByteBuffer.wrap(body));\n    }\n\n    private void read(SocketChannel channel, ByteBuffer buffer) throws IOException {\n        while (buffer.hasRemaining()) {\n            int r = channel.read(buffer);\n            if (r == -1) {\n                throw new IOException(\"end of stream when reading header\");\n            }\n        }\n    }\n\n    private Canal buildCanal() {\n        Canal canal = new Canal();\n        canal.setId(1L);\n        canal.setName(DESTINATION);\n        canal.setDesc(\"test\");\n\n        CanalParameter parameter = new CanalParameter();\n\n        parameter.setZkClusters(Arrays.asList(\"127.0.0.1:2188\"));\n        parameter.setMetaMode(MetaMode.MEMORY);\n        parameter.setHaMode(HAMode.HEARTBEAT);\n        parameter.setIndexMode(IndexMode.MEMORY);\n\n        parameter.setStorageMode(StorageMode.MEMORY);\n        parameter.setMemoryStorageBufferSize(32 * 1024);\n\n        parameter.setSourcingType(SourcingType.MYSQL);\n        parameter.setDbAddresses(Arrays.asList(new InetSocketAddress(MYSQL_ADDRESS, 3306),\n            new InetSocketAddress(MYSQL_ADDRESS, 3306)));\n        parameter.setDbUsername(USERNAME);\n        parameter.setDbPassword(PASSWORD);\n        parameter.setPositions(Arrays.asList(\"{\\\"journalName\\\":\\\"mysql-bin.000001\\\",\\\"position\\\":6163L,\\\"timestamp\\\":1322803601000L}\",\n            \"{\\\"journalName\\\":\\\"mysql-bin.000001\\\",\\\"position\\\":6163L,\\\"timestamp\\\":1322803601000L}\"));\n\n        parameter.setSlaveId(1234L);\n\n        parameter.setDefaultConnectionTimeoutInSeconds(30);\n        parameter.setConnectionCharset(\"UTF-8\");\n        parameter.setReceiveBufferSize(8 * 1024);\n        parameter.setSendBufferSize(8 * 1024);\n\n        parameter.setDetectingEnable(false);\n        parameter.setDetectingIntervalInSeconds(10);\n        parameter.setDetectingRetryTimes(3);\n        parameter.setDetectingSQL(DETECTING_SQL);\n\n        canal.setCanalParameter(parameter);\n        return canal;\n    }\n}\n"
  },
  {
    "path": "server/src/test/java/com/alibaba/otter/canal/server/embedded/BaseCanalServerWithEmbededTest.java",
    "content": "package com.alibaba.otter.canal.server.embedded;\n\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.springframework.util.CollectionUtils;\n\nimport com.alibaba.otter.canal.instance.manager.CanalInstanceWithManager;\nimport com.alibaba.otter.canal.instance.manager.model.Canal;\nimport com.alibaba.otter.canal.parse.CanalEventParser;\nimport com.alibaba.otter.canal.parse.CanalHASwitchable;\nimport com.alibaba.otter.canal.protocol.ClientIdentity;\nimport com.alibaba.otter.canal.protocol.Message;\nimport com.alibaba.otter.canal.server.embedded.CanalServerWithEmbedded;\n@Ignore\npublic abstract class BaseCanalServerWithEmbededTest {\n\n    protected static final String   cluster1       = \"127.0.0.1:2188\";\n    protected static final String   DESTINATION    = \"example\";\n    protected static final String   DETECTING_SQL  = \"insert into retl.xdual values(1,now()) on duplicate key update x=now()\";\n    protected static final String   MYSQL_ADDRESS  = \"127.0.0.1\";\n    protected static final String   USERNAME       = \"canal\";\n    protected static final String   PASSWORD       = \"canal\";\n    protected static final String   FILTER         = \".*\\\\\\\\..*\";\n\n    private CanalServerWithEmbedded server;\n    private ClientIdentity          clientIdentity = new ClientIdentity(DESTINATION, (short) 1);                               ;\n\n    @Before\n    public void setUp() {\n        server = CanalServerWithEmbedded.instance();\n        server.setCanalInstanceGenerator(destination -> {\n            Canal canal = buildCanal();\n            return new CanalInstanceWithManager(canal, FILTER);\n        });\n        server.start();\n        server.start(DESTINATION);\n    }\n\n    @After\n    public void tearDown() {\n        server.stop();\n    }\n\n    @Test\n    public void testGetWithoutAck() {\n        int maxEmptyCount = 10;\n        int emptyCount = 0;\n        int totalCount = 0;\n        server.subscribe(clientIdentity);\n        while (emptyCount < maxEmptyCount) {\n            Message message = server.getWithoutAck(clientIdentity, 11);\n            if (CollectionUtils.isEmpty(message.getEntries())) {\n                emptyCount++;\n                try {\n                    Thread.sleep(emptyCount * 300L);\n                } catch (InterruptedException e) {\n                    Assert.fail();\n                }\n\n                System.out.println(\"empty count : \" + emptyCount);\n            } else {\n                emptyCount = 0;\n                totalCount += message.getEntries().size();\n                server.ack(clientIdentity, message.getId());\n            }\n        }\n\n        System.out.println(\"!!!!!! testGetWithoutAck totalCount : \" + totalCount);\n        server.unsubscribe(clientIdentity);\n    }\n\n    @Test\n    public void testGet() {\n        int maxEmptyCount = 10;\n        int emptyCount = 0;\n        int totalCount = 0;\n        server.subscribe(clientIdentity);\n        while (emptyCount < maxEmptyCount) {\n            Message message = server.get(clientIdentity, 11);\n            if (CollectionUtils.isEmpty(message.getEntries())) {\n                emptyCount++;\n                try {\n                    Thread.sleep(emptyCount * 300L);\n                } catch (InterruptedException e) {\n                    Assert.fail();\n                }\n\n                System.out.println(\"empty count : \" + emptyCount);\n            } else {\n                emptyCount = 0;\n                totalCount += message.getEntries().size();\n            }\n        }\n\n        System.out.println(\"!!!!!! testGet totalCount : \" + totalCount);\n        server.unsubscribe(clientIdentity);\n    }\n\n    // @Test\n    public void testRollback() {\n        int maxEmptyCount = 10;\n        int emptyCount = 0;\n        int totalCount = 0;\n        server.subscribe(clientIdentity);\n        while (emptyCount < maxEmptyCount) {\n            Message message = server.getWithoutAck(clientIdentity, 11);\n            if (CollectionUtils.isEmpty(message.getEntries())) {\n                emptyCount++;\n                try {\n                    Thread.sleep(emptyCount * 300L);\n                } catch (InterruptedException e) {\n                    Assert.fail();\n                }\n\n                System.out.println(\"empty count : \" + emptyCount);\n            } else {\n                emptyCount = 0;\n                totalCount += message.getEntries().size();\n            }\n        }\n        System.out.println(\"!!!!!! testRollback totalCount : \" + totalCount);\n\n        server.rollback(clientIdentity);// 直接rollback掉，再取一次\n        emptyCount = 0;\n        totalCount = 0;\n        while (emptyCount < maxEmptyCount) {\n            Message message = server.getWithoutAck(clientIdentity, 11);\n            if (CollectionUtils.isEmpty(message.getEntries())) {\n                emptyCount++;\n                try {\n                    Thread.sleep(emptyCount * 300L);\n                } catch (InterruptedException e) {\n                    Assert.fail();\n                }\n\n                System.out.println(\"empty count : \" + emptyCount);\n            } else {\n                emptyCount = 0;\n                totalCount += message.getEntries().size();\n            }\n        }\n\n        System.out.println(\"!!!!!! testRollback after rollback ,  totalCount : \" + totalCount);\n        server.unsubscribe(clientIdentity);\n    }\n\n    // @Test\n    public void testSwitch() {\n        int maxEmptyCount = 10;\n        int emptyCount = 0;\n        int totalCount = 0;\n\n        int thresold = 50;\n        int batchSize = 11;\n        server.subscribe(clientIdentity);\n        while (emptyCount < maxEmptyCount) {\n            Message message = server.get(clientIdentity, batchSize);\n            if (CollectionUtils.isEmpty(message.getEntries())) {\n                emptyCount++;\n                try {\n                    Thread.sleep(emptyCount * 300L);\n                } catch (InterruptedException e) {\n                    Assert.fail();\n                }\n\n                System.out.println(\"empty count : \" + emptyCount);\n            } else {\n                emptyCount = 0;\n                totalCount += message.getEntries().size();\n\n                if ((totalCount + 1) % 100 >= thresold && (totalCount + 1) % 100 <= thresold + batchSize) {\n                    CanalEventParser eventParser = server.getCanalInstances().get(DESTINATION).getEventParser();\n                    if (eventParser instanceof CanalHASwitchable) {\n                        ((CanalHASwitchable) eventParser).doSwitch();// 执行切换\n                        try {\n                            Thread.sleep(5 * 1000); // 等待parser启动\n                        } catch (InterruptedException e) {\n                            Assert.fail();\n                        }\n                    }\n                }\n            }\n        }\n\n        System.out.println(\"!!!!!! testGet totalCount : \" + totalCount);\n        server.unsubscribe(clientIdentity);\n    }\n\n    abstract protected Canal buildCanal();\n}\n"
  },
  {
    "path": "server/src/test/java/com/alibaba/otter/canal/server/embedded/CanalServerWithEmbedded_FileModeTest.java",
    "content": "package com.alibaba.otter.canal.server.embedded;\n\nimport java.net.InetSocketAddress;\nimport java.util.Arrays;\n\nimport com.alibaba.otter.canal.instance.manager.model.Canal;\nimport com.alibaba.otter.canal.instance.manager.model.CanalParameter;\nimport com.alibaba.otter.canal.instance.manager.model.CanalParameter.*;\nimport org.junit.Ignore;\n\n@Ignore\npublic class CanalServerWithEmbedded_FileModeTest extends BaseCanalServerWithEmbededTest {\n\n    protected Canal buildCanal() {\n        Canal canal = new Canal();\n        canal.setId(1L);\n        canal.setName(DESTINATION);\n        canal.setDesc(\"my standalone server test \");\n\n        CanalParameter parameter = new CanalParameter();\n\n        parameter.setMetaMode(MetaMode.LOCAL_FILE);\n        parameter.setDataDir(\"./conf\");\n        parameter.setMetaFileFlushPeriod(1000);\n        parameter.setHaMode(HAMode.HEARTBEAT);\n        parameter.setIndexMode(IndexMode.MEMORY_META_FAILBACK);\n\n        parameter.setStorageMode(StorageMode.MEMORY);\n        parameter.setMemoryStorageBufferSize(32 * 1024);\n\n        parameter.setSourcingType(SourcingType.MYSQL);\n        parameter.setDbAddresses(Arrays.asList(new InetSocketAddress(MYSQL_ADDRESS, 3306),\n            new InetSocketAddress(MYSQL_ADDRESS, 3306)));\n        parameter.setDbUsername(USERNAME);\n        parameter.setDbPassword(PASSWORD);\n        parameter.setPositions(Arrays.asList(\"{\\\"journalName\\\":\\\"mysql-bin.000001\\\",\\\"position\\\":332L,\\\"timestamp\\\":\\\"1505998863000\\\"}\",\n            \"{\\\"journalName\\\":\\\"mysql-bin.000001\\\",\\\"position\\\":332L,\\\"timestamp\\\":\\\"1505998863000\\\"}\"));\n\n        parameter.setSlaveId(1234L);\n\n        parameter.setDefaultConnectionTimeoutInSeconds(30);\n        parameter.setConnectionCharset(\"UTF-8\");\n        parameter.setReceiveBufferSize(8 * 1024);\n        parameter.setSendBufferSize(8 * 1024);\n\n        parameter.setDetectingEnable(false);\n        parameter.setDetectingIntervalInSeconds(10);\n        parameter.setDetectingRetryTimes(3);\n        parameter.setDetectingSQL(DETECTING_SQL);\n\n        canal.setCanalParameter(parameter);\n        return canal;\n    }\n}\n"
  },
  {
    "path": "server/src/test/java/com/alibaba/otter/canal/server/embedded/CanalServerWithEmbedded_StandaloneTest.java",
    "content": "package com.alibaba.otter.canal.server.embedded;\n\nimport java.net.InetSocketAddress;\nimport java.util.Arrays;\n\nimport com.alibaba.otter.canal.instance.manager.model.Canal;\nimport com.alibaba.otter.canal.instance.manager.model.CanalParameter;\nimport com.alibaba.otter.canal.instance.manager.model.CanalParameter.HAMode;\nimport com.alibaba.otter.canal.instance.manager.model.CanalParameter.IndexMode;\nimport com.alibaba.otter.canal.instance.manager.model.CanalParameter.MetaMode;\nimport com.alibaba.otter.canal.instance.manager.model.CanalParameter.SourcingType;\nimport com.alibaba.otter.canal.instance.manager.model.CanalParameter.StorageMode;\nimport org.junit.Ignore;\n\n@Ignore\npublic class CanalServerWithEmbedded_StandaloneTest extends BaseCanalServerWithEmbededTest {\n\n    protected Canal buildCanal() {\n        Canal canal = new Canal();\n        canal.setId(1L);\n        canal.setName(DESTINATION);\n        canal.setDesc(\"test\");\n\n        CanalParameter parameter = new CanalParameter();\n\n        parameter.setZkClusters(Arrays.asList(\"127.0.0.1:2188\"));\n        parameter.setMetaMode(MetaMode.MEMORY);\n        parameter.setHaMode(HAMode.HEARTBEAT);\n        parameter.setIndexMode(IndexMode.MEMORY);\n\n        parameter.setStorageMode(StorageMode.MEMORY);\n        parameter.setMemoryStorageBufferSize(32 * 1024);\n\n        parameter.setSourcingType(SourcingType.MYSQL);\n        parameter.setDbAddresses(Arrays.asList(new InetSocketAddress(MYSQL_ADDRESS, 3306),\n            new InetSocketAddress(MYSQL_ADDRESS, 3306)));\n        parameter.setDbUsername(USERNAME);\n        parameter.setDbPassword(PASSWORD);\n        parameter.setPositions(Arrays.asList(\"{\\\"journalName\\\":\\\"mysql-bin.000003\\\",\\\"position\\\":14217L,\\\"timestamp\\\":\\\"1505998863000\\\"}\",\n            \"{\\\"journalName\\\":\\\"mysql-bin.000003\\\",\\\"position\\\":14377L,\\\"timestamp\\\":\\\"1505998863000\\\"}\"));\n\n        parameter.setSlaveId(1234L);\n\n        parameter.setDefaultConnectionTimeoutInSeconds(30);\n        parameter.setConnectionCharset(\"UTF-8\");\n        parameter.setReceiveBufferSize(8 * 1024);\n        parameter.setSendBufferSize(8 * 1024);\n\n        parameter.setDetectingEnable(false);\n        parameter.setDetectingIntervalInSeconds(10);\n        parameter.setDetectingRetryTimes(3);\n        parameter.setDetectingSQL(DETECTING_SQL);\n\n        canal.setCanalParameter(parameter);\n        return canal;\n    }\n}\n"
  },
  {
    "path": "server/src/test/java/com/alibaba/otter/canal/server/embedded/CanalServerWithEmbedded_StandbyTest.java",
    "content": "package com.alibaba.otter.canal.server.embedded;\n\nimport java.net.InetSocketAddress;\nimport java.util.Arrays;\n\nimport org.I0Itec.zkclient.ZkClient;\nimport org.junit.Before;\n\nimport com.alibaba.otter.canal.common.zookeeper.ZookeeperPathUtils;\nimport com.alibaba.otter.canal.instance.manager.model.Canal;\nimport com.alibaba.otter.canal.instance.manager.model.CanalParameter;\nimport com.alibaba.otter.canal.instance.manager.model.CanalParameter.HAMode;\nimport com.alibaba.otter.canal.instance.manager.model.CanalParameter.IndexMode;\nimport com.alibaba.otter.canal.instance.manager.model.CanalParameter.MetaMode;\nimport com.alibaba.otter.canal.instance.manager.model.CanalParameter.SourcingType;\nimport com.alibaba.otter.canal.instance.manager.model.CanalParameter.StorageMode;\nimport org.junit.Ignore;\n\n@Ignore\npublic class CanalServerWithEmbedded_StandbyTest extends BaseCanalServerWithEmbededTest {\n\n    private ZkClient zkClient = new ZkClient(cluster1);\n\n    @Before\n    public void setUp() {\n        zkClient.deleteRecursive(ZookeeperPathUtils.CANAL_ROOT_NODE);\n        super.setUp();\n    }\n\n    protected Canal buildCanal() {\n        Canal canal = new Canal();\n        canal.setId(1L);\n        canal.setName(DESTINATION);\n        canal.setDesc(\"test\");\n\n        CanalParameter parameter = new CanalParameter();\n\n        parameter.setZkClusters(Arrays.asList(\"127.0.0.1:2188\"));\n        parameter.setMetaMode(MetaMode.MIXED); // 冷备，可选择混合模式\n        parameter.setHaMode(HAMode.HEARTBEAT);\n        parameter.setIndexMode(IndexMode.META);// 内存版store，需要选择meta做为index\n\n        parameter.setStorageMode(StorageMode.MEMORY);\n        parameter.setMemoryStorageBufferSize(32 * 1024);\n\n        parameter.setSourcingType(SourcingType.MYSQL);\n        parameter.setDbAddresses(Arrays.asList(new InetSocketAddress(MYSQL_ADDRESS, 3306),\n            new InetSocketAddress(MYSQL_ADDRESS, 3306)));\n        parameter.setDbUsername(USERNAME);\n        parameter.setDbPassword(PASSWORD);\n        parameter.setPositions(Arrays.asList(\"{\\\"journalName\\\":\\\"mysql-bin.000001\\\",\\\"position\\\":6163L,\\\"timestamp\\\":1322803601000L}\",\n            \"{\\\"journalName\\\":\\\"mysql-bin.000001\\\",\\\"position\\\":6163L,\\\"timestamp\\\":1322803601000L}\"));\n\n        parameter.setSlaveId(1234L);\n\n        parameter.setDefaultConnectionTimeoutInSeconds(30);\n        parameter.setConnectionCharset(\"UTF-8\");\n        parameter.setReceiveBufferSize(8 * 1024);\n        parameter.setSendBufferSize(8 * 1024);\n\n        parameter.setDetectingEnable(false);\n        parameter.setDetectingIntervalInSeconds(10);\n        parameter.setDetectingRetryTimes(3);\n        parameter.setDetectingSQL(DETECTING_SQL);\n\n        canal.setCanalParameter(parameter);\n        return canal;\n    }\n}\n"
  },
  {
    "path": "sink/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>com.alibaba.otter</groupId>\n\t\t<artifactId>canal</artifactId>\n\t\t<version>1.1.9-SNAPSHOT</version>\n\t\t<relativePath>../pom.xml</relativePath>\n\t</parent>\n\t<groupId>com.alibaba.otter</groupId>\n\t<artifactId>canal.sink</artifactId>\n\t<packaging>jar</packaging>\n\t<name>canal sink module for otter ${project.version}</name>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.common</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.protocol</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.filter</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.store</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<!-- test dependency -->\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "sink/src/main/java/com/alibaba/otter/canal/sink/AbstractCanalEventDownStreamHandler.java",
    "content": "package com.alibaba.otter.canal.sink;\n\nimport com.alibaba.otter.canal.common.AbstractCanalLifeCycle;\n\n/**\n * 默认的实现\n * \n * @author jianghang 2013-10-8 下午8:35:29\n * @since 1.0.12\n */\npublic class AbstractCanalEventDownStreamHandler<T> extends AbstractCanalLifeCycle implements CanalEventDownStreamHandler<T> {\n\n    public T before(T events) {\n        return events;\n    }\n\n    public T retry(T events) {\n        return events;\n    }\n\n    public T after(T events) {\n        return events;\n    }\n\n}\n"
  },
  {
    "path": "sink/src/main/java/com/alibaba/otter/canal/sink/AbstractCanalEventSink.java",
    "content": "package com.alibaba.otter.canal.sink;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport com.alibaba.otter.canal.common.AbstractCanalLifeCycle;\nimport com.alibaba.otter.canal.filter.CanalEventFilter;\n\n/**\n * @author jianghang 2012-7-23 下午01:02:45\n */\npublic abstract class AbstractCanalEventSink<T> extends AbstractCanalLifeCycle implements CanalEventSink<T> {\n\n    protected CanalEventFilter                  filter;\n    protected List<CanalEventDownStreamHandler> handlers = new ArrayList<>();\n\n    public void setFilter(CanalEventFilter filter) {\n        this.filter = filter;\n    }\n\n    public void addHandler(CanalEventDownStreamHandler handler) {\n        this.handlers.add(handler);\n    }\n\n    public CanalEventDownStreamHandler getHandler(int index) {\n        return this.handlers.get(index);\n    }\n\n    public void addHandler(CanalEventDownStreamHandler handler, int index) {\n        this.handlers.add(index, handler);\n    }\n\n    public void removeHandler(int index) {\n        this.handlers.remove(index);\n    }\n\n    public void removeHandler(CanalEventDownStreamHandler handler) {\n        this.handlers.remove(handler);\n    }\n\n    public CanalEventFilter getFilter() {\n        return filter;\n    }\n\n    public List<CanalEventDownStreamHandler> getHandlers() {\n        return handlers;\n    }\n\n    public void interrupt() {\n        // do nothing\n    }\n\n}\n"
  },
  {
    "path": "sink/src/main/java/com/alibaba/otter/canal/sink/CanalEventDownStreamHandler.java",
    "content": "package com.alibaba.otter.canal.sink;\n\nimport com.alibaba.otter.canal.common.CanalLifeCycle;\n\n/**\n * 处理下sink时的数据流\n * \n * @author jianghang 2012-7-31 下午03:06:26\n * @version 1.0.0\n */\npublic interface CanalEventDownStreamHandler<T> extends CanalLifeCycle {\n\n    /**\n     * 提交到store之前做一下处理，允许替换Event\n     */\n    public T before(T events);\n\n    /**\n     * store处于full后，retry时处理做一下处理\n     */\n    public T retry(T events);\n\n    /**\n     * 提交store成功后做一下处理\n     */\n    public T after(T events);\n}\n"
  },
  {
    "path": "sink/src/main/java/com/alibaba/otter/canal/sink/CanalEventSink.java",
    "content": "package com.alibaba.otter.canal.sink;\n\nimport java.net.InetSocketAddress;\n\nimport com.alibaba.otter.canal.common.CanalLifeCycle;\nimport com.alibaba.otter.canal.sink.entry.group.GroupEventSink;\nimport com.alibaba.otter.canal.sink.exception.CanalSinkException;\n\n/**\n * event事件消费者\n * \n * <pre>\n * 1. 剥离filter/sink为独立的两个动作，方便在快速判断数据是否有效\n * </pre>\n * \n * @author jianghang 2012-6-21 下午05:03:40\n * @version 1.0.0\n */\npublic interface CanalEventSink<T> extends CanalLifeCycle {\n\n    /**\n     * 提交数据\n     * \n     * @param event\n     * @param remoteAddress\n     * @param destination\n     * @throws CanalSinkException\n     * @throws InterruptedException\n     */\n    boolean sink(T event, InetSocketAddress remoteAddress, String destination) throws CanalSinkException,\n                                                                              InterruptedException;\n\n    /**\n     * 中断消费，比如解析模块发生了切换，想临时中断当前的merge请求，清理对应的上下文状态，可见{@linkplain GroupEventSink}\n     */\n    void interrupt();\n\n}\n"
  },
  {
    "path": "sink/src/main/java/com/alibaba/otter/canal/sink/entry/EntryEventSink.java",
    "content": "package com.alibaba.otter.canal.sink.entry;\n\nimport java.net.InetSocketAddress;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.concurrent.locks.LockSupport;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\n\nimport com.alibaba.otter.canal.protocol.CanalEntry;\nimport com.alibaba.otter.canal.protocol.CanalEntry.Entry;\nimport com.alibaba.otter.canal.protocol.CanalEntry.EntryType;\nimport com.alibaba.otter.canal.protocol.position.LogIdentity;\nimport com.alibaba.otter.canal.sink.AbstractCanalEventSink;\nimport com.alibaba.otter.canal.sink.CanalEventDownStreamHandler;\nimport com.alibaba.otter.canal.sink.CanalEventSink;\nimport com.alibaba.otter.canal.sink.exception.CanalSinkException;\nimport com.alibaba.otter.canal.store.CanalEventStore;\nimport com.alibaba.otter.canal.store.memory.MemoryEventStoreWithBuffer;\nimport com.alibaba.otter.canal.store.model.Event;\n\n/**\n * mysql binlog数据对象输出\n * \n * @author jianghang 2012-7-4 下午03:23:16\n * @version 1.0.0\n */\npublic class EntryEventSink extends AbstractCanalEventSink<List<CanalEntry.Entry>> implements CanalEventSink<List<CanalEntry.Entry>> {\n\n    private static final Logger    logger                        = LoggerFactory.getLogger(EntryEventSink.class);\n    private static final int       maxFullTimes                  = 10;\n    private CanalEventStore<Event> eventStore;\n    protected boolean              filterTransactionEntry        = false;                                        // 是否需要尽可能过滤事务头/尾\n    protected boolean              filterEmtryTransactionEntry   = true;                                         // 是否需要过滤空的事务头/尾\n    protected long                 emptyTransactionInterval      = 5 * 1000;                                     // 空的事务输出的频率\n    protected long                 emptyTransctionThresold       = 8192;                                         // 超过8192个事务头，输出一个\n\n    protected volatile long        lastTransactionTimestamp      = 0L;\n    protected AtomicLong           lastTransactionCount          = new AtomicLong(0L);\n    protected volatile long        lastEmptyTransactionTimestamp = 0L;\n    protected AtomicLong           lastEmptyTransactionCount     = new AtomicLong(0L);\n    protected AtomicLong           eventsSinkBlockingTime        = new AtomicLong(0L);\n    protected boolean              raw;\n\n    public EntryEventSink(){\n        addHandler(new HeartBeatEntryEventHandler());\n    }\n\n    public void start() {\n        super.start();\n        Assert.notNull(eventStore);\n\n        if (eventStore instanceof MemoryEventStoreWithBuffer) {\n            this.raw = ((MemoryEventStoreWithBuffer) eventStore).isRaw();\n        }\n\n        for (CanalEventDownStreamHandler handler : getHandlers()) {\n            if (!handler.isStart()) {\n                handler.start();\n            }\n        }\n    }\n\n    public void stop() {\n        super.stop();\n\n        for (CanalEventDownStreamHandler handler : getHandlers()) {\n            if (handler.isStart()) {\n                handler.stop();\n            }\n        }\n    }\n\n    public boolean filter(List<Entry> event, InetSocketAddress remoteAddress, String destination) {\n\n        return false;\n    }\n\n    public boolean sink(List<CanalEntry.Entry> entrys, InetSocketAddress remoteAddress, String destination)\n                                                                                                           throws CanalSinkException,\n                                                                                                           InterruptedException {\n        return sinkData(entrys, remoteAddress);\n    }\n\n    private boolean sinkData(List<CanalEntry.Entry> entrys, InetSocketAddress remoteAddress)\n                                                                                            throws InterruptedException {\n        boolean hasRowData = false;\n        boolean hasHeartBeat = false;\n        List<Event> events = new ArrayList<>();\n        for (CanalEntry.Entry entry : entrys) {\n            if (!doFilter(entry)) {\n                continue;\n            }\n\n            if (filterTransactionEntry\n                && (entry.getEntryType() == EntryType.TRANSACTIONBEGIN || entry.getEntryType() == EntryType.TRANSACTIONEND)) {\n                long currentTimestamp = entry.getHeader().getExecuteTime();\n                // 基于一定的策略控制，放过空的事务头和尾，便于及时更新数据库位点，表明工作正常\n                if (lastTransactionCount.incrementAndGet() <= emptyTransctionThresold\n                    && Math.abs(currentTimestamp - lastTransactionTimestamp) <= emptyTransactionInterval) {\n                    continue;\n                } else {\n                    // fixed issue https://github.com/alibaba/canal/issues/2616\n                    // 主要原因在于空事务只发送了begin，没有同步发送commit信息，这里修改为只对commit事件做计数更新，确保begin/commit成对出现\n                    if (entry.getEntryType() == EntryType.TRANSACTIONEND) {\n                        lastTransactionCount.set(0L);\n                        lastTransactionTimestamp = currentTimestamp;\n                    }\n                }\n            }\n\n            hasRowData |= (entry.getEntryType() == EntryType.ROWDATA);\n            hasHeartBeat |= (entry.getEntryType() == EntryType.HEARTBEAT);\n            Event event = new Event(new LogIdentity(remoteAddress, -1L), entry, raw);\n            events.add(event);\n        }\n\n        if (hasRowData || hasHeartBeat) {\n            // 存在row记录 或者 存在heartbeat记录，直接跳给后续处理\n            return doSink(events);\n        } else {\n            // 需要过滤的数据\n            if (filterEmtryTransactionEntry && !CollectionUtils.isEmpty(events)) {\n                long currentTimestamp = events.get(0).getExecuteTime();\n                // 基于一定的策略控制，放过空的事务头和尾，便于及时更新数据库位点，表明工作正常\n                if (Math.abs(currentTimestamp - lastEmptyTransactionTimestamp) > emptyTransactionInterval\n                    || lastEmptyTransactionCount.incrementAndGet() > emptyTransctionThresold) {\n                    lastEmptyTransactionCount.set(0L);\n                    lastEmptyTransactionTimestamp = currentTimestamp;\n                    return doSink(events);\n                }\n            }\n\n            // 直接返回true，忽略空的事务头和尾\n            return true;\n        }\n    }\n\n    protected boolean doFilter(CanalEntry.Entry entry) {\n        if (filter != null && entry.getEntryType() == EntryType.ROWDATA) {\n            String name = getSchemaNameAndTableName(entry);\n            boolean need = filter.filter(name);\n            if (!need) {\n                logger.debug(\"filter name[{}] entry : {}:{}\",\n                    name,\n                    entry.getHeader().getLogfileName(),\n                    entry.getHeader().getLogfileOffset());\n            }\n\n            return need;\n        } else {\n            return true;\n        }\n    }\n\n    protected boolean doSink(List<Event> events) {\n        for (CanalEventDownStreamHandler<List<Event>> handler : getHandlers()) {\n            events = handler.before(events);\n        }\n        long blockingStart = 0L;\n        int fullTimes = 0;\n        do {\n            if (eventStore.tryPut(events)) {\n                if (fullTimes > 0) {\n                    eventsSinkBlockingTime.addAndGet(System.nanoTime() - blockingStart);\n                }\n                for (CanalEventDownStreamHandler<List<Event>> handler : getHandlers()) {\n                    events = handler.after(events);\n                }\n                return true;\n            } else {\n                if (fullTimes == 0) {\n                    blockingStart = System.nanoTime();\n                }\n                applyWait(++fullTimes);\n                if (fullTimes % 100 == 0) {\n                    long nextStart = System.nanoTime();\n                    eventsSinkBlockingTime.addAndGet(nextStart - blockingStart);\n                    blockingStart = nextStart;\n                }\n            }\n\n            for (CanalEventDownStreamHandler<List<Event>> handler : getHandlers()) {\n                events = handler.retry(events);\n            }\n\n        } while (running && !Thread.interrupted());\n        return false;\n    }\n\n    // 处理无数据的情况，避免空循环挂死\n    private void applyWait(int fullTimes) {\n        int newFullTimes = fullTimes > maxFullTimes ? maxFullTimes : fullTimes;\n        if (fullTimes <= 3) { // 3次以内\n            Thread.yield();\n        } else { // 超过3次，最多只sleep 10ms\n            LockSupport.parkNanos(1000 * 1000L * newFullTimes);\n        }\n\n    }\n\n    private String getSchemaNameAndTableName(CanalEntry.Entry entry) {\n        return entry.getHeader().getSchemaName() + \".\" + entry.getHeader().getTableName();\n    }\n\n    public void setEventStore(CanalEventStore<Event> eventStore) {\n        this.eventStore = eventStore;\n    }\n\n    public void setFilterTransactionEntry(boolean filterTransactionEntry) {\n        this.filterTransactionEntry = filterTransactionEntry;\n    }\n\n    public void setFilterEmtryTransactionEntry(boolean filterEmtryTransactionEntry) {\n        this.filterEmtryTransactionEntry = filterEmtryTransactionEntry;\n    }\n\n    public void setEmptyTransactionInterval(long emptyTransactionInterval) {\n        this.emptyTransactionInterval = emptyTransactionInterval;\n    }\n\n    public void setEmptyTransctionThresold(long emptyTransctionThresold) {\n        this.emptyTransctionThresold = emptyTransctionThresold;\n    }\n\n    public AtomicLong getEventsSinkBlockingTime() {\n        return eventsSinkBlockingTime;\n    }\n\n}\n"
  },
  {
    "path": "sink/src/main/java/com/alibaba/otter/canal/sink/entry/HeartBeatEntryEventHandler.java",
    "content": "package com.alibaba.otter.canal.sink.entry;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport com.alibaba.otter.canal.protocol.CanalEntry.EntryType;\nimport com.alibaba.otter.canal.sink.AbstractCanalEventDownStreamHandler;\nimport com.alibaba.otter.canal.store.model.Event;\n\n/**\n * 处理一下一下heartbeat数据\n * \n * @author jianghang 2013-10-8 下午6:03:53\n * @since 1.0.12\n */\npublic class HeartBeatEntryEventHandler extends AbstractCanalEventDownStreamHandler<List<Event>> {\n\n    public List<Event> before(List<Event> events) {\n        boolean existHeartBeat = false;\n        for (Event event : events) {\n            if (event.getEntryType() == EntryType.HEARTBEAT) {\n                existHeartBeat = true;\n                break;\n            }\n        }\n\n        if (!existHeartBeat) {\n            return events;\n        } else {\n            // 目前heartbeat和其他事件是分离的，保险一点还是做一下检查处理\n            List<Event> result = new ArrayList<>();\n            for (Event event : events) {\n                if (event.getEntryType() != EntryType.HEARTBEAT) {\n                    result.add(event);\n                }\n            }\n\n            return result;\n        }\n    }\n\n}\n"
  },
  {
    "path": "sink/src/main/java/com/alibaba/otter/canal/sink/entry/group/GroupBarrier.java",
    "content": "package com.alibaba.otter.canal.sink.entry.group;\n\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\n\n/**\n * 针对group合并的barrier接口，控制多个sink操作的合并处理\n * \n * @author jianghang 2012-10-18 下午05:07:35\n * @version 1.0.0\n */\npublic interface GroupBarrier<T> {\n\n    /**\n     * 判断当前的数据对象是否允许通过\n     * \n     * @param event\n     * @throws InterruptedException\n     */\n    public void await(T event) throws InterruptedException;\n\n    /**\n     * 判断当前的数据对象是否允许通过，带超时控制\n     * \n     * @param event\n     * @param timeout\n     * @param unit\n     * @throws InterruptedException\n     * @throws TimeoutException\n     */\n    public void await(T event, long timeout, TimeUnit unit) throws InterruptedException, TimeoutException;\n\n    /**\n     * sink成功，清理对应barrier的状态\n     */\n    public void clear(T event);\n\n    /**\n     * 出现切换，发起interrupt，清理对应的上下文\n     */\n    public void interrupt();\n}\n"
  },
  {
    "path": "sink/src/main/java/com/alibaba/otter/canal/sink/entry/group/GroupEventSink.java",
    "content": "package com.alibaba.otter.canal.sink.entry.group;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport com.alibaba.otter.canal.sink.CanalEventDownStreamHandler;\nimport com.alibaba.otter.canal.sink.entry.EntryEventSink;\nimport com.alibaba.otter.canal.store.model.Event;\n\n/**\n * 基于归并排序的sink处理\n * \n * <pre>\n * 几点设计说明：\n * 1. 多库合并时，需要控制不满足groupSize的条件，就会阻塞其他库的合并操作.  (比如刚启动时会所有通道正常工作才开始合并，或者中间过程出现主备切换)\n * 2. 库解析出现问题，但没有进行主备切换，此时需要通过{@linkplain CanalEventDownStreamHandler}进行定时监听合并数据的产生时间间隔 \n *    a. 因为一旦库解析异常，就不会再sink数据，此时groupSize就会一直缺少，就会阻塞其他库的合并，也就是不会有数据写入到store中\n * </pre>\n * \n * @author jianghang 2012-10-15 下午09:54:18\n * @version 1.0.0\n */\npublic class GroupEventSink extends EntryEventSink {\n\n    private int          groupSize;\n    private GroupBarrier barrier;  // 归并排序需要预先知道组的大小，用于判断是否组内所有的sink都已经开始正常取数据\n\n    public GroupEventSink(){\n        this(1);\n    }\n\n    public GroupEventSink(int groupSize){\n        super();\n        this.groupSize = groupSize;\n    }\n\n    public void start() {\n        super.start();\n\n        if (filterTransactionEntry) {\n            barrier = new TimelineBarrier(groupSize);\n        } else {\n            barrier = new TimelineTransactionBarrier(groupSize);// 支持事务保留\n        }\n    }\n\n    protected boolean doSink(List<Event> events) {\n        int size = events.size();\n        for (int i = 0; i < events.size(); i++) {\n            Event event = events.get(i);\n            try {\n                barrier.await(event);// 进行timeline的归并调度处理\n                if (filterTransactionEntry) {\n                    super.doSink(Arrays.asList(event));\n                } else if (i == size - 1) {\n                    // 针对事务数据，只有到最后一条数据都通过后，才进行sink操作，保证原子性\n                    // 同时批量sink，也要保证在最后一条数据释放状态之前写出数据，否则就有并发问题\n                    return super.doSink(events);\n                }\n            } catch (InterruptedException e) {\n                return false;\n            } finally {\n                barrier.clear(event);\n            }\n        }\n\n        return false;\n    }\n\n    public void interrupt() {\n        super.interrupt();\n        barrier.interrupt();\n    }\n\n}\n"
  },
  {
    "path": "sink/src/main/java/com/alibaba/otter/canal/sink/entry/group/TimelineBarrier.java",
    "content": "package com.alibaba.otter.canal.sink.entry.group;\n\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.PriorityBlockingQueue;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\nimport java.util.concurrent.locks.Condition;\nimport java.util.concurrent.locks.ReentrantLock;\n\nimport com.alibaba.otter.canal.store.model.Event;\n\n/**\n * 时间归并控制\n * \n * <pre>\n * 大致设计：\n *  1. 多个队列都提交一个timestamp，判断出最小的一个timestamp做为通过的条件，然后唤醒<=该最小时间的线程通过\n *  2. 只有当多个队列都提交了一个timestamp，缺少任何一个提交，都会阻塞其他队列通过。(解决当一个库启动过慢或者发生主备切换时出现延迟等问题)\n * \n * 存在一个假定，认为提交的timestamp是一个顺序递增，但是在两种case下会出现时间回退\n * a. 大事务时，事务头的时间会晚于事务当中数据的时间，相当于出现一个时间回退\n * b. 出现主备切换，从备机上发过来的数据会回退几秒钟\n * \n * </pre>\n * \n * @author jianghang 2012-10-15 下午10:01:53\n * @version 1.0.0\n */\npublic class TimelineBarrier implements GroupBarrier<Event> {\n\n    protected int                 groupSize;\n    protected ReentrantLock       lock           = new ReentrantLock();\n    protected Condition           condition      = lock.newCondition();\n    protected volatile long       threshold;\n    protected BlockingQueue<Long> lastTimestamps = new PriorityBlockingQueue<>(); // 当前通道最后一次single的时间戳\n\n    public TimelineBarrier(int groupSize){\n        this.groupSize = groupSize;\n        threshold = Long.MIN_VALUE;\n    }\n\n    /**\n     * 判断自己的timestamp是否可以通过\n     * \n     * @throws InterruptedException\n     */\n    public void await(Event event) throws InterruptedException {\n        long timestamp = getTimestamp(event);\n        try {\n            lock.lockInterruptibly();\n            single(timestamp);\n            while (isPermit(event, timestamp) == false) {\n                condition.await();\n            }\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    /**\n     * 判断自己的timestamp是否可以通过,带超时控制\n     * \n     * @throws InterruptedException\n     * @throws TimeoutException\n     */\n    public void await(Event event, long timeout, TimeUnit unit) throws InterruptedException, TimeoutException {\n        long timestamp = getTimestamp(event);\n        try {\n            lock.lockInterruptibly();\n            single(timestamp);\n            while (isPermit(event, timestamp) == false) {\n                condition.await(timeout, unit);\n            }\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    public void clear(Event event) {\n        // 出现中断有两种可能：\n        // 1.出现主备切换，需要剔除到Timeline中的时间占位(这样合并时就会小于groupSize，不满足调度条件，直到主备切换完成后才能重新开启合并处理)\n        // 2.出现关闭操作，退出即可\n        lastTimestamps.remove(getTimestamp(event));\n    }\n\n    public void interrupt() {\n        // do nothing，没有需要清理的上下文状态\n    }\n\n    public long state() {\n        return threshold;\n    }\n\n    /**\n     * 判断是否允许通过\n     */\n    protected boolean isPermit(Event event, long state) {\n        return state <= state();\n    }\n\n    /**\n     * 通知一下\n     */\n    protected void notify(long minTimestamp) {\n        // 通知阻塞的线程恢复, 这里采用single all操作，当group中的几个时间都相同时，一次性触发通过多个\n        condition.signalAll();\n    }\n\n    /**\n     * 通知下一个minTimestamp数据出队列\n     * \n     * @throws InterruptedException\n     */\n    private void single(long timestamp) throws InterruptedException {\n        lastTimestamps.add(timestamp);\n\n        if (timestamp < state()) {\n            // 针对mysql事务中会出现时间跳跃\n            // 例子：\n            // 2012-08-08 16:24:26 事务头\n            // 2012-08-08 16:24:24 变更记录\n            // 2012-08-08 16:24:25 变更记录\n            // 2012-08-08 16:24:26　事务尾\n\n            // 针对这种case，一旦发现timestamp有回退的情况，直接更新threshold，强制阻塞其他的操作，等待最小数据优先处理完成\n            threshold = timestamp; // 更新为最小值\n        }\n\n        if (lastTimestamps.size() >= groupSize) {// 判断队列是否需要触发\n            // 触发下一个出队列的数据\n            Long minTimestamp = this.lastTimestamps.peek();\n            if (minTimestamp != null) {\n                threshold = minTimestamp;\n                notify(minTimestamp);\n            }\n        } else {\n            threshold = Long.MIN_VALUE;// 如果不满足队列长度，需要阻塞等待\n        }\n    }\n\n    private Long getTimestamp(Event event) {\n        return event.getExecuteTime();\n    }\n\n}\n"
  },
  {
    "path": "sink/src/main/java/com/alibaba/otter/canal/sink/entry/group/TimelineTransactionBarrier.java",
    "content": "package com.alibaba.otter.canal.sink.entry.group;\n\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport com.alibaba.otter.canal.protocol.CanalEntry.EntryType;\nimport com.alibaba.otter.canal.sink.exception.CanalSinkException;\nimport com.alibaba.otter.canal.store.model.Event;\n\n/**\n * 相比于{@linkplain TimelineBarrier}，增加了按事务支持，会按照事务进行分库合并处理\n * \n * @author jianghang 2012-10-18 下午05:18:38\n * @version 1.0.0\n */\npublic class TimelineTransactionBarrier extends TimelineBarrier {\n\n    private ThreadLocal<Boolean> inTransaction = ThreadLocal.withInitial(() -> false);\n\n    /**\n     * <pre>\n     * 几种状态：\n     * 0：初始状态，允许大家竞争\n     * 1: 事务数据处理中\n     * 2: 非事务数据处理中\n     * </pre>\n     */\n    private AtomicInteger        txState       = new AtomicInteger(0);\n\n    public TimelineTransactionBarrier(int groupSize){\n        super(groupSize);\n    }\n\n    public void await(Event event) throws InterruptedException {\n        try {\n            super.await(event);\n        } catch (InterruptedException e) {\n            // 出现线程中断，可能是因为关闭或者主备切换\n            // 主备切换对应的事务尾会未正常发送，需要强制设置为事务结束，允许其他队列通过\n            reset();\n            throw e;\n        }\n    }\n\n    public void await(Event event, long timeout, TimeUnit unit) throws InterruptedException, TimeoutException {\n        try {\n            super.await(event, timeout, unit);\n        } catch (InterruptedException e) {\n            // 出现线程中断，可能是因为关闭或者主备切换\n            // 主备切换对应的事务尾会未正常发送，需要强制设置为事务结束，允许其他队列通过\n            reset();\n            throw e;\n        }\n    }\n\n    public void clear(Event event) {\n        super.clear(event);\n\n        // 应该先判断2，再判断是否是事务尾，因为事务尾也可以导致txState的状态为2\n        // 如果先判断事务尾，那么2的状态可能永远没机会被修改了，系统出现死锁\n        // CanalSinkException被注释的代码是不是可以放开？？我们内部使用的时候已经放开了，从代码逻辑的分析上以及实践效果来看，应该抛异常\n        if (txState.intValue() == 2) {// 非事务中\n            boolean result = txState.compareAndSet(2, 0);\n            if (result == false) {\n                throw new CanalSinkException(\"state is not correct in non-transaction\");\n            }\n        } else if (isTransactionEnd(event)) {\n            inTransaction.set(false); // 事务结束并且已经成功写入store，清理标记，进入重新排队判断，允许新的事务进入\n            boolean result = txState.compareAndSet(1, 0);\n            if (result == false) {\n                throw new CanalSinkException(\"state is not correct in transaction\");\n            }\n        }\n    }\n\n    protected boolean isPermit(Event event, long state) {\n        if (txState.intValue() == 1 && inTransaction.get()) { // 如果处于事务中，直接允许通过。因为事务头已经做过判断\n            return true;\n        } else if (txState.intValue() == 0) {\n            boolean result = super.isPermit(event, state);\n            if (result) {\n                // 可能第一条送过来的数据不为Begin，需要做判断处理，如果非事务，允许直接通过，比如DDL语句\n                if (isTransactionBegin(event)) {\n                    if (txState.compareAndSet(0, 1)) {\n                        inTransaction.set(true);\n                        return true; // 事务允许通过\n                    }\n                } else if (txState.compareAndSet(0, 2)) { // 非事务保护中\n                    // 当基于zk-cursor启动的时候，拿到的第一个Event是TransactionEnd\n                    return true; // DDL/DCL/TransactionEnd允许通过\n                }\n            }\n        }\n\n        return false;\n    }\n\n    public void interrupt() {\n        super.interrupt();\n        reset();\n    }\n\n    // 重新设置状态\n    private void reset() {\n        inTransaction.remove();\n        txState.set(0);// 重新置位\n    }\n\n    private boolean isTransactionBegin(Event event) {\n        return event.getEntryType() == EntryType.TRANSACTIONBEGIN;\n    }\n\n    private boolean isTransactionEnd(Event event) {\n        return event.getEntryType() == EntryType.TRANSACTIONEND;\n    }\n\n}\n"
  },
  {
    "path": "sink/src/main/java/com/alibaba/otter/canal/sink/exception/CanalSinkException.java",
    "content": "package com.alibaba.otter.canal.sink.exception;\r\n\r\nimport com.alibaba.otter.canal.common.CanalException;\r\n\r\n/**\r\n * canal 异常定义\r\n * \r\n * @author jianghang 2012-6-15 下午04:57:35\r\n * @version 1.0.0\r\n */\r\npublic class CanalSinkException extends CanalException {\r\n\r\n    private static final long serialVersionUID = -7288830284122672209L;\r\n\r\n    public CanalSinkException(String errorCode){\r\n        super(errorCode);\r\n    }\r\n\r\n    public CanalSinkException(String errorCode, Throwable cause){\r\n        super(errorCode, cause);\r\n    }\r\n\r\n    public CanalSinkException(String errorCode, String errorDesc){\r\n        super(errorCode + \":\" + errorDesc);\r\n    }\r\n\r\n    public CanalSinkException(String errorCode, String errorDesc, Throwable cause){\r\n        super(errorCode + \":\" + errorDesc, cause);\r\n    }\r\n\r\n    public CanalSinkException(Throwable cause){\r\n        super(cause);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "sink/src/test/java/com/alibaba/otter/canal/sink/GroupEventSinkTest.java",
    "content": "package com.alibaba.otter.canal.sink;\n\nimport java.net.InetSocketAddress;\nimport java.util.Arrays;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport org.apache.commons.lang.math.RandomUtils;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.protocol.CanalEntry.Entry;\nimport com.alibaba.otter.canal.protocol.CanalEntry.Header;\nimport com.alibaba.otter.canal.sink.entry.group.GroupEventSink;\nimport com.alibaba.otter.canal.sink.stub.DummyEventStore;\n\npublic class GroupEventSinkTest {\n\n    private final InetSocketAddress address = new InetSocketAddress(\"127.0.0.1\", 3306);\n\n    @Test\n    public void testGroupTwo() {\n        final DummyEventStore eventStore = new DummyEventStore();\n        final GroupEventSink eventSink = new GroupEventSink(3);\n        eventSink.setFilterTransactionEntry(true);\n        eventSink.setEventStore(eventStore);\n        eventSink.start();\n\n        ExecutorService executor = Executors.newFixedThreadPool(3);\n        final CountDownLatch latch = new CountDownLatch(1);\n        executor.submit(() -> {\n            for (int i = 0; i < 50; i++) {\n                try {\n                    eventSink.sink(Arrays.asList(buildEntry(\"1\", 1L + i, 1L + i)), address, \"ljhtest1\");\n                    Thread.sleep(50L + RandomUtils.nextInt(50));\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n\n            for (int i = 0; i < 50; i++) {\n                try {\n                    eventSink.sink(Arrays.asList(buildEntry(\"1\", 1L + i, 30L + i)), address, \"ljhtest1\");\n                    Thread.sleep(50L + RandomUtils.nextInt(50));\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n\n            System.out.println(\"one sink finished!\");\n            latch.countDown();\n        });\n\n        executor.submit(() -> {\n            for (int i = 0; i < 50; i++) {\n                try {\n                    eventSink.sink(Arrays.asList(buildEntry(\"1\", 1L + i, 10L + i)), address, \"ljhtest2\");\n                    Thread.sleep(50L + RandomUtils.nextInt(50));\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n\n            for (int i = 0; i < 50; i++) {\n                try {\n                    eventSink.sink(Arrays.asList(buildEntry(\"1\", 1L + i, 40L + i)), address, \"ljhtest2\");\n                    Thread.sleep(50L + RandomUtils.nextInt(50));\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n            System.out.println(\"tow sink finished!\");\n            latch.countDown();\n        });\n\n        executor.submit(() -> {\n            for (int i = 0; i < 100; i++) {\n                try {\n                    eventSink.sink(Arrays.asList(buildEntry(\"1\", 1L + i, 30L + i)), address, \"ljhtest3\");\n                    Thread.sleep(50L + RandomUtils.nextInt(50));\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n            System.out.println(\"tow sink finished!\");\n            latch.countDown();\n        });\n\n        try {\n            latch.await();\n            Thread.sleep(200L);\n        } catch (InterruptedException e) {\n        }\n\n        eventSink.stop();\n        executor.shutdownNow();\n    }\n\n    private static Entry buildEntry(String binlogFile, long offset, long timestamp) {\n        Header.Builder headerBuilder = Header.newBuilder();\n        headerBuilder.setLogfileName(binlogFile);\n        headerBuilder.setLogfileOffset(offset);\n        headerBuilder.setExecuteTime(timestamp);\n        Entry.Builder entryBuilder = Entry.newBuilder();\n        entryBuilder.setHeader(headerBuilder.build());\n        return entryBuilder.build();\n    }\n}\n"
  },
  {
    "path": "sink/src/test/java/com/alibaba/otter/canal/sink/stub/DummyEventStore.java",
    "content": "package com.alibaba.otter.canal.sink.stub;\n\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport com.alibaba.otter.canal.protocol.position.Position;\nimport com.alibaba.otter.canal.store.CanalEventStore;\nimport com.alibaba.otter.canal.store.CanalStoreException;\nimport com.alibaba.otter.canal.store.model.Event;\nimport com.alibaba.otter.canal.store.model.Events;\n\npublic class DummyEventStore implements CanalEventStore<Event> {\n\n    public void ack(Position position) throws CanalStoreException {\n\n    }\n\n    public void ack(Position position, Long seqId) throws CanalStoreException {\n\n    }\n\n    public Events get(Position start, int batchSize) throws InterruptedException, CanalStoreException {\n        return null;\n    }\n\n    public Events get(Position start, int batchSize, long timeout, TimeUnit unit) throws InterruptedException,\n                                                                                 CanalStoreException {\n        return null;\n    }\n\n    public Position getFirstPosition() throws CanalStoreException {\n        return null;\n    }\n\n    public Position getLatestPosition() throws CanalStoreException {\n        return null;\n    }\n\n    public void rollback() throws CanalStoreException {\n\n    }\n\n    public Events tryGet(Position start, int batchSize) throws CanalStoreException {\n        return null;\n    }\n\n    public boolean isStart() {\n        return false;\n    }\n\n    public void start() {\n\n    }\n\n    public void stop() {\n\n    }\n\n    public void cleanAll() throws CanalStoreException {\n    }\n\n    public void cleanUntil(Position position) throws CanalStoreException {\n\n    }\n\n    public void put(Event data) throws InterruptedException, CanalStoreException {\n        System.out.println(\"time:\" + data.getExecuteTime());\n    }\n\n    public boolean put(Event data, long timeout, TimeUnit unit) throws InterruptedException, CanalStoreException {\n        System.out.println(\"time:\" + data.getExecuteTime());\n        return true;\n    }\n\n    public boolean tryPut(Event data) throws CanalStoreException {\n        System.out.println(\"time:\" + data.getExecuteTime());\n        return true;\n    }\n\n    public void put(List<Event> datas) throws InterruptedException, CanalStoreException {\n        Event data = datas.get(0);\n        System.out.println(\"time:\" + data.getExecuteTime());\n    }\n\n    public boolean put(List<Event> datas, long timeout, TimeUnit unit) throws InterruptedException, CanalStoreException {\n        Event data = datas.get(0);\n        System.out.println(\"time:\" + data.getExecuteTime());\n        return true;\n    }\n\n    public boolean tryPut(List<Event> datas) throws CanalStoreException {\n        Event data = datas.get(0);\n        System.out.println(\"time:\" + data.getExecuteTime());\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "store/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>com.alibaba.otter</groupId>\n\t\t<artifactId>canal</artifactId>\n\t\t<version>1.1.9-SNAPSHOT</version>\n\t\t<relativePath>../pom.xml</relativePath>\n\t</parent>\n\t<groupId>com.alibaba.otter</groupId>\n\t<artifactId>canal.store</artifactId>\n\t<packaging>jar</packaging>\n\t<name>canal store module for otter ${project.version}</name>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.common</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.protocol</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.otter</groupId>\n\t\t\t<artifactId>canal.meta</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<!-- test dependency -->\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "store/src/main/java/com/alibaba/otter/canal/store/AbstractCanalGroupStore.java",
    "content": "package com.alibaba.otter.canal.store;\n\nimport java.util.Map;\n\nimport org.springframework.util.Assert;\n\nimport com.alibaba.otter.canal.common.AbstractCanalLifeCycle;\nimport com.google.common.collect.MapMaker;\n\n/**\n * @author zebin.xuzb 2012-10-30 下午3:45:17\n * @since 1.0.0\n */\npublic abstract class AbstractCanalGroupStore<T> extends AbstractCanalLifeCycle implements CanalGroupEventStore<T> {\n\n    protected Map<String, StoreInfo> stores = new MapMaker().makeMap();\n\n    @Override\n    public void addStoreInfo(StoreInfo info) {\n        checkInfo(info);\n        stores.put(info.getStoreName(), info);\n    }\n\n    protected void checkInfo(StoreInfo info) {\n        Assert.notNull(info);\n        Assert.hasText(info.getStoreName());\n    }\n\n}\n"
  },
  {
    "path": "store/src/main/java/com/alibaba/otter/canal/store/AbstractCanalStoreScavenge.java",
    "content": "package com.alibaba.otter.canal.store;\n\nimport java.util.List;\n\nimport org.springframework.util.CollectionUtils;\n\nimport com.alibaba.otter.canal.common.AbstractCanalLifeCycle;\nimport com.alibaba.otter.canal.meta.CanalMetaManager;\nimport com.alibaba.otter.canal.protocol.ClientIdentity;\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\nimport com.alibaba.otter.canal.protocol.position.Position;\n\n/**\n * store回收机制\n * \n * @author jianghang 2012-8-8 下午12:57:36\n * @version 1.0.0\n */\npublic abstract class AbstractCanalStoreScavenge extends AbstractCanalLifeCycle implements CanalStoreScavenge {\n\n    protected String           destination;\n    protected CanalMetaManager canalMetaManager;\n    protected boolean          onAck            = true;\n    protected boolean          onFull           = false;\n    protected boolean          onSchedule       = false;\n    protected String           scavengeSchedule = null;\n\n    public void scavenge() {\n        Position position = getLatestAckPosition(destination);\n        cleanUntil(position);\n    }\n\n    /**\n     * 找出该destination中可被清理掉的position位置\n     * \n     * @param destination\n     */\n    private Position getLatestAckPosition(String destination) {\n        List<ClientIdentity> clientIdentitys = canalMetaManager.listAllSubscribeInfo(destination);\n        LogPosition result = null;\n        if (!CollectionUtils.isEmpty(clientIdentitys)) {\n            // 尝试找到一个最小的logPosition\n            for (ClientIdentity clientIdentity : clientIdentitys) {\n                LogPosition position = (LogPosition) canalMetaManager.getCursor(clientIdentity);\n                if (position == null) {\n                    continue;\n                }\n\n                if (result == null) {\n                    result = position;\n                } else {\n                    result = min(result, position);\n                }\n            }\n        }\n\n        return result;\n    }\n\n    /**\n     * 找出一个最小的position位置\n     */\n    private LogPosition min(LogPosition position1, LogPosition position2) {\n        if (position1.getIdentity().equals(position2.getIdentity())) {\n            // 首先根据文件进行比较\n            if (position1.getPostion().getJournalName().compareTo(position2.getPostion().getJournalName()) < 0) {\n                return position2;\n            } else if (position1.getPostion().getJournalName().compareTo(position2.getPostion().getJournalName()) > 0) {\n                return position1;\n            } else {\n                // 根据offest进行比较\n                if (position1.getPostion().getPosition() < position2.getPostion().getPosition()) {\n                    return position2;\n                } else {\n                    return position1;\n                }\n            }\n        } else {\n            // 不同的主备库，根据时间进行比较\n            if (position1.getPostion().getTimestamp() < position2.getPostion().getTimestamp()) {\n                return position2;\n            } else {\n                return position1;\n            }\n        }\n    }\n\n    public void setOnAck(boolean onAck) {\n        this.onAck = onAck;\n    }\n\n    public void setOnFull(boolean onFull) {\n        this.onFull = onFull;\n    }\n\n    public void setOnSchedule(boolean onSchedule) {\n        this.onSchedule = onSchedule;\n    }\n\n    public String getScavengeSchedule() {\n        return scavengeSchedule;\n    }\n\n    public void setScavengeSchedule(String scavengeSchedule) {\n        this.scavengeSchedule = scavengeSchedule;\n    }\n\n    public void setDestination(String destination) {\n        this.destination = destination;\n    }\n\n    public void setCanalMetaManager(CanalMetaManager canalMetaManager) {\n        this.canalMetaManager = canalMetaManager;\n    }\n\n}\n"
  },
  {
    "path": "store/src/main/java/com/alibaba/otter/canal/store/CanalEventStore.java",
    "content": "package com.alibaba.otter.canal.store;\r\n\r\nimport java.util.List;\r\nimport java.util.concurrent.TimeUnit;\r\n\r\nimport com.alibaba.otter.canal.common.CanalLifeCycle;\r\nimport com.alibaba.otter.canal.protocol.position.Position;\r\nimport com.alibaba.otter.canal.store.model.Events;\r\n\r\n/**\r\n * canel数据存储接口\r\n * \r\n * @author jianghang 2012-6-14 下午08:44:52\r\n * @version 1.0.0\r\n */\r\npublic interface CanalEventStore<T> extends CanalLifeCycle, CanalStoreScavenge {\r\n\r\n    /**\r\n     * 添加一组数据对象，阻塞等待其操作完成 (比如一次性添加一个事务数据)\r\n     */\r\n    void put(List<T> data) throws InterruptedException, CanalStoreException;\r\n\r\n    /**\r\n     * 添加一组数据对象，阻塞等待其操作完成或者时间超时 (比如一次性添加一个事务数据)\r\n     */\r\n    boolean put(List<T> data, long timeout, TimeUnit unit) throws InterruptedException, CanalStoreException;\r\n\r\n    /**\r\n     * 添加一组数据对象 (比如一次性添加一个事务数据)\r\n     */\r\n    boolean tryPut(List<T> data) throws CanalStoreException;\r\n\r\n    /**\r\n     * 添加一个数据对象，阻塞等待其操作完成\r\n     */\r\n    void put(T data) throws InterruptedException, CanalStoreException;\r\n\r\n    /**\r\n     * 添加一个数据对象，阻塞等待其操作完成或者时间超时\r\n     */\r\n    boolean put(T data, long timeout, TimeUnit unit) throws InterruptedException, CanalStoreException;\r\n\r\n    /**\r\n     * 添加一个数据对象\r\n     */\r\n    boolean tryPut(T data) throws CanalStoreException;\r\n\r\n    /**\r\n     * 获取指定大小的数据，阻塞等待其操作完成\r\n     */\r\n    Events<T> get(Position start, int batchSize) throws InterruptedException, CanalStoreException;\r\n\r\n    /**\r\n     * 获取指定大小的数据，阻塞等待其操作完成或者时间超时\r\n     */\r\n    Events<T> get(Position start, int batchSize, long timeout, TimeUnit unit) throws InterruptedException,\r\n                                                                             CanalStoreException;\r\n\r\n    /**\r\n     * 根据指定位置，获取一个指定大小的数据\r\n     */\r\n    Events<T> tryGet(Position start, int batchSize) throws CanalStoreException;\r\n\r\n    /**\r\n     * 获取最后一条数据的position\r\n     */\r\n    Position getLatestPosition() throws CanalStoreException;\r\n\r\n    /**\r\n     * 获取第一条数据的position，如果没有数据返回为null\r\n     */\r\n    Position getFirstPosition() throws CanalStoreException;\r\n\r\n    /**\r\n     * 删除{@linkplain Position}之前的数据\r\n     */\r\n    void ack(Position position) throws CanalStoreException;\r\n\r\n    /**\r\n     * 删除指定seqId之前的数据\r\n     * \r\n     * @Since 1.1.4\r\n     */\r\n    void ack(Position position, Long seqId) throws CanalStoreException;\r\n\r\n    /**\r\n     * 出错时执行回滚操作(未提交ack的所有状态信息重新归位，减少出错时数据全部重来的成本)\r\n     */\r\n    void rollback() throws CanalStoreException;\r\n\r\n}\r\n"
  },
  {
    "path": "store/src/main/java/com/alibaba/otter/canal/store/CanalGroupEventStore.java",
    "content": "package com.alibaba.otter.canal.store;\n\n/**\n * 提供给上层统一的 store 视图，内部则支持多种store混合，并且维持着多个store供上层进行路由\n * \n * @author zebin.xuzb 2012-10-30 下午12:17:26\n * @since 1.0.0\n */\npublic interface CanalGroupEventStore<T> extends CanalEventStore<T> {\n\n    void addStoreInfo(StoreInfo info);\n}\n"
  },
  {
    "path": "store/src/main/java/com/alibaba/otter/canal/store/CanalStoreConstants.java",
    "content": "package com.alibaba.otter.canal.store;\r\n\r\n/**\r\n * 常量值\r\n * \r\n * @author jianghang 2012-6-14 下午09:40:33\r\n * @version 1.0.0\r\n */\r\npublic interface CanalStoreConstants {\r\n\r\n    public static final String CODE_POSITION_NOT_FOUND    = \"position:%s not found\";\r\n\r\n    public static final String CODE_POSITION_NOT_IN_ORDER = \"position:%s not in order\";\r\n\r\n    public static final String ENCODING                   = \"utf8\";\r\n\r\n    public static final int    MAX_STORECOUNT             = 100;\r\n\r\n    public static final int    ROLLOVERCOUNT              = 100;\r\n\r\n}\r\n"
  },
  {
    "path": "store/src/main/java/com/alibaba/otter/canal/store/CanalStoreException.java",
    "content": "package com.alibaba.otter.canal.store;\r\n\r\nimport com.alibaba.otter.canal.common.CanalException;\r\n\r\n/**\r\n * canal 异常定义\r\n * \r\n * @author jianghang 2012-6-15 下午04:57:35\r\n * @version 1.0.0\r\n */\r\npublic class CanalStoreException extends CanalException {\r\n\r\n    private static final long serialVersionUID = -7288830284122672209L;\r\n\r\n    public CanalStoreException(String errorCode){\r\n        super(errorCode);\r\n    }\r\n\r\n    public CanalStoreException(String errorCode, Throwable cause){\r\n        super(errorCode, cause);\r\n    }\r\n\r\n    public CanalStoreException(String errorCode, String errorDesc){\r\n        super(errorCode + \":\" + errorDesc);\r\n    }\r\n\r\n    public CanalStoreException(String errorCode, String errorDesc, Throwable cause){\r\n        super(errorCode + \":\" + errorDesc, cause);\r\n    }\r\n\r\n    public CanalStoreException(Throwable cause){\r\n        super(cause);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "store/src/main/java/com/alibaba/otter/canal/store/CanalStoreScavenge.java",
    "content": "package com.alibaba.otter.canal.store;\n\nimport com.alibaba.otter.canal.protocol.position.Position;\n\n/**\n * store空间回收机制，信息采集以及控制何时调用{@linkplain CanalEventStore}.cleanUtil()接口\n * \n * @author jianghang 2012-8-8 上午11:57:42\n * @version 1.0.0\n */\npublic interface CanalStoreScavenge {\n\n    /**\n     * 清理position之前的数据\n     */\n    void cleanUntil(Position position) throws CanalStoreException;\n\n    /**\n     * 删除所有的数据\n     */\n    void cleanAll() throws CanalStoreException;\n}\n"
  },
  {
    "path": "store/src/main/java/com/alibaba/otter/canal/store/StoreInfo.java",
    "content": "package com.alibaba.otter.canal.store;\n\n/**\n * @author zebin.xuzb 2012-10-30 下午1:05:13\n * @since 1.0.0\n */\npublic class StoreInfo {\n\n    private String storeName;\n    private String filter;\n\n    public String getStoreName() {\n        return storeName;\n    }\n\n    public String getFilter() {\n        return filter;\n    }\n\n    public void setStoreName(String storeName) {\n        this.storeName = storeName;\n    }\n\n    public void setFilter(String filter) {\n        this.filter = filter;\n    }\n\n}\n"
  },
  {
    "path": "store/src/main/java/com/alibaba/otter/canal/store/helper/CanalEventUtils.java",
    "content": "package com.alibaba.otter.canal.store.helper;\n\nimport org.apache.commons.lang.StringUtils;\n\nimport com.alibaba.otter.canal.protocol.position.EntryPosition;\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\nimport com.alibaba.otter.canal.store.model.Event;\n\n/**\n * 相关的操作工具\n * \n * @author jianghang 2012-6-19 下午05:49:21\n * @version 1.0.0\n */\npublic class CanalEventUtils {\n\n    /**\n     * 找出一个最小的position位置，相等的情况返回position1\n     */\n    public static LogPosition min(LogPosition position1, LogPosition position2) {\n        if (position1.getIdentity().equals(position2.getIdentity())) {\n            // 首先根据文件进行比较\n            if (position1.getPostion().getJournalName().compareTo(position2.getPostion().getJournalName()) > 0) {\n                return position2;\n            } else if (position1.getPostion().getJournalName().compareTo(position2.getPostion().getJournalName()) < 0) {\n                return position1;\n            } else {\n                // 根据offest进行比较\n                if (position1.getPostion().getPosition() > position2.getPostion().getPosition()) {\n                    return position2;\n                } else {\n                    return position1;\n                }\n            }\n        } else {\n            // 不同的主备库，根据时间进行比较\n            if (position1.getPostion().getTimestamp() > position2.getPostion().getTimestamp()) {\n                return position2;\n            } else {\n                return position1;\n            }\n        }\n    }\n\n    /**\n     * 根据entry创建对应的Position对象\n     */\n    public static LogPosition createPosition(Event event) {\n        EntryPosition position = new EntryPosition();\n        position.setJournalName(event.getJournalName());\n        position.setPosition(event.getPosition());\n        position.setTimestamp(event.getExecuteTime());\n        // add serverId at 2016-06-28\n        position.setServerId(event.getServerId());\n        // add gtid\n        position.setGtid(event.getGtid());\n\n        LogPosition logPosition = new LogPosition();\n        logPosition.setPostion(position);\n        logPosition.setIdentity(event.getLogIdentity());\n        return logPosition;\n    }\n\n    /**\n     * 根据entry创建对应的Position对象\n     */\n    public static LogPosition createPosition(Event event, boolean included) {\n        EntryPosition position = new EntryPosition();\n        position.setJournalName(event.getJournalName());\n        position.setPosition(event.getPosition());\n        position.setTimestamp(event.getExecuteTime());\n        position.setIncluded(included);\n        // add serverId at 2016-06-28\n        position.setServerId(event.getServerId());\n        // add gtid\n        position.setGtid(event.getGtid());\n\n        LogPosition logPosition = new LogPosition();\n        logPosition.setPostion(position);\n        logPosition.setIdentity(event.getLogIdentity());\n        return logPosition;\n    }\n\n    /**\n     * 判断当前的entry和position是否相同\n     */\n    public static boolean checkPosition(Event event, LogPosition logPosition) {\n        EntryPosition position = logPosition.getPostion();\n        boolean result = position.getTimestamp().equals(event.getExecuteTime());\n\n        boolean exactely = (StringUtils.isBlank(position.getJournalName()) && position.getPosition() == null);\n        if (!exactely) {// 精确匹配\n            result &= position.getPosition().equals(event.getPosition());\n            if (result) {// short path\n                result &= StringUtils.equals(event.getJournalName(), position.getJournalName());\n            }\n        }\n\n        return result;\n    }\n}\n"
  },
  {
    "path": "store/src/main/java/com/alibaba/otter/canal/store/memory/MemoryEventStoreWithBuffer.java",
    "content": "package com.alibaba.otter.canal.store.memory;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.concurrent.locks.Condition;\nimport java.util.concurrent.locks.ReentrantLock;\n\nimport org.apache.commons.lang.StringUtils;\n\nimport com.alibaba.otter.canal.protocol.CanalEntry;\nimport com.alibaba.otter.canal.protocol.CanalEntry.EventType;\nimport com.alibaba.otter.canal.protocol.position.LogPosition;\nimport com.alibaba.otter.canal.protocol.position.Position;\nimport com.alibaba.otter.canal.protocol.position.PositionRange;\nimport com.alibaba.otter.canal.store.AbstractCanalStoreScavenge;\nimport com.alibaba.otter.canal.store.CanalEventStore;\nimport com.alibaba.otter.canal.store.CanalStoreException;\nimport com.alibaba.otter.canal.store.CanalStoreScavenge;\nimport com.alibaba.otter.canal.store.helper.CanalEventUtils;\nimport com.alibaba.otter.canal.store.model.BatchMode;\nimport com.alibaba.otter.canal.store.model.Event;\nimport com.alibaba.otter.canal.store.model.Events;\n\n/**\n * 基于内存buffer构建内存memory store\n * \n * <pre>\n * 变更记录：\n * 1. 新增BatchMode类型，支持按内存大小获取批次数据，内存大小更加可控.\n *   a. put操作，会首先根据bufferSize进行控制，然后再进行bufferSize * bufferMemUnit进行控制. 因存储的内容是以Event，如果纯依赖于memsize进行控制，会导致RingBuffer出现动态伸缩\n * </pre>\n * \n * @author jianghang 2012-6-20 上午09:46:31\n * @version 1.0.0\n */\npublic class MemoryEventStoreWithBuffer extends AbstractCanalStoreScavenge implements CanalEventStore<Event>, CanalStoreScavenge {\n\n    private static final long INIT_SEQUENCE = -1;\n    private int               bufferSize    = 16 * 1024;\n    private int               bufferMemUnit = 1024;                                      // memsize的单位，默认为1kb大小\n    private int               indexMask;\n    private Event[]           entries;\n\n    // 记录下put/get/ack操作的三个下标\n    private AtomicLong        putSequence   = new AtomicLong(INIT_SEQUENCE);             // 代表当前put操作最后一次写操作发生的位置\n    private AtomicLong        getSequence   = new AtomicLong(INIT_SEQUENCE);             // 代表当前get操作读取的最后一条的位置\n    private AtomicLong        ackSequence   = new AtomicLong(INIT_SEQUENCE);             // 代表当前ack操作的最后一条的位置\n\n    // 记录下put/get/ack操作的三个memsize大小\n    private AtomicLong        putMemSize    = new AtomicLong(0);\n    private AtomicLong        getMemSize    = new AtomicLong(0);\n    private AtomicLong        ackMemSize    = new AtomicLong(0);\n\n    // 记录下put/get/ack操作的三个execTime\n    private AtomicLong        putExecTime   = new AtomicLong(System.currentTimeMillis());\n    private AtomicLong        getExecTime   = new AtomicLong(System.currentTimeMillis());\n    private AtomicLong        ackExecTime   = new AtomicLong(System.currentTimeMillis());\n\n    // 记录下put/get/ack操作的三个table rows\n    private AtomicLong        putTableRows  = new AtomicLong(0);\n    private AtomicLong        getTableRows  = new AtomicLong(0);\n    private AtomicLong        ackTableRows  = new AtomicLong(0);\n\n    // 阻塞put/get操作控制信号\n    private ReentrantLock     lock          = new ReentrantLock();\n    private Condition         notFull       = lock.newCondition();\n    private Condition         notEmpty      = lock.newCondition();\n\n    private BatchMode         batchMode     = BatchMode.ITEMSIZE;                        // 默认为内存大小模式\n    private boolean           ddlIsolation  = false;\n    private boolean           raw           = true;                                      // 针对entry是否开启raw模式\n\n    public MemoryEventStoreWithBuffer(){\n\n    }\n\n    public MemoryEventStoreWithBuffer(BatchMode batchMode){\n        this.batchMode = batchMode;\n    }\n\n    public void start() throws CanalStoreException {\n        super.start();\n        if (Integer.bitCount(bufferSize) != 1) {\n            throw new IllegalArgumentException(\"bufferSize must be a power of 2\");\n        }\n\n        indexMask = bufferSize - 1;\n        entries = new Event[bufferSize];\n    }\n\n    public void stop() throws CanalStoreException {\n        super.stop();\n\n        cleanAll();\n    }\n\n    public void put(List<Event> data) throws InterruptedException, CanalStoreException {\n        if (data == null || data.isEmpty()) {\n            return;\n        }\n\n        final ReentrantLock lock = this.lock;\n        lock.lockInterruptibly();\n        try {\n            try {\n                while (!checkFreeSlotAt(putSequence.get() + data.size())) { // 检查是否有空位\n                    notFull.await(); // wait until not full\n                }\n            } catch (InterruptedException ie) {\n                notFull.signal(); // propagate to non-interrupted thread\n                throw ie;\n            }\n            doPut(data);\n            if (Thread.interrupted()) {\n                throw new InterruptedException();\n            }\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    public boolean put(List<Event> data, long timeout, TimeUnit unit) throws InterruptedException, CanalStoreException {\n        if (data == null || data.isEmpty()) {\n            return true;\n        }\n\n        long nanos = unit.toNanos(timeout);\n        final ReentrantLock lock = this.lock;\n        lock.lockInterruptibly();\n        try {\n            for (;;) {\n                if (checkFreeSlotAt(putSequence.get() + data.size())) {\n                    doPut(data);\n                    return true;\n                }\n                if (nanos <= 0) {\n                    return false;\n                }\n\n                try {\n                    nanos = notFull.awaitNanos(nanos);\n                } catch (InterruptedException ie) {\n                    notFull.signal(); // propagate to non-interrupted thread\n                    throw ie;\n                }\n            }\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    public boolean tryPut(List<Event> data) throws CanalStoreException {\n        if (data == null || data.isEmpty()) {\n            return true;\n        }\n\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n            if (!checkFreeSlotAt(putSequence.get() + data.size())) {\n                return false;\n            } else {\n                doPut(data);\n                return true;\n            }\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    public void put(Event data) throws InterruptedException, CanalStoreException {\n        put(Arrays.asList(data));\n    }\n\n    public boolean put(Event data, long timeout, TimeUnit unit) throws InterruptedException, CanalStoreException {\n        return put(Arrays.asList(data), timeout, unit);\n    }\n\n    public boolean tryPut(Event data) throws CanalStoreException {\n        return tryPut(Arrays.asList(data));\n    }\n\n    /**\n     * 执行具体的put操作\n     */\n    private void doPut(List<Event> data) {\n        long current = putSequence.get();\n        long end = current + data.size();\n\n        // 先写数据，再更新对应的cursor,并发度高的情况，putSequence会被get请求可见，拿出了ringbuffer中的老的Entry值\n        for (long next = current + 1; next <= end; next++) {\n            entries[getIndex(next)] = data.get((int) (next - current - 1));\n        }\n\n        putSequence.set(end);\n\n        // 记录一下gets memsize信息，方便快速检索\n        if (batchMode.isMemSize()) {\n            long size = 0;\n            for (Event event : data) {\n                size += calculateSize(event);\n            }\n\n            putMemSize.getAndAdd(size);\n        }\n        profiling(data, OP.PUT);\n        // tell other threads that store is not empty\n        notEmpty.signal();\n    }\n\n    public Events<Event> get(Position start, int batchSize) throws InterruptedException, CanalStoreException {\n        final ReentrantLock lock = this.lock;\n        lock.lockInterruptibly();\n        try {\n            try {\n                while (!checkUnGetSlotAt((LogPosition) start, batchSize))\n                    notEmpty.await();\n            } catch (InterruptedException ie) {\n                notEmpty.signal(); // propagate to non-interrupted thread\n                throw ie;\n            }\n\n            return doGet(start, batchSize);\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    public Events<Event> get(Position start, int batchSize, long timeout, TimeUnit unit) throws InterruptedException,\n                                                                                        CanalStoreException {\n        long nanos = unit.toNanos(timeout);\n        final ReentrantLock lock = this.lock;\n        lock.lockInterruptibly();\n        try {\n            for (;;) {\n                if (checkUnGetSlotAt((LogPosition) start, batchSize)) {\n                    return doGet(start, batchSize);\n                }\n\n                if (nanos <= 0) {\n                    // 如果时间到了，有多少取多少\n                    return doGet(start, batchSize);\n                }\n\n                try {\n                    nanos = notEmpty.awaitNanos(nanos);\n                } catch (InterruptedException ie) {\n                    notEmpty.signal(); // propagate to non-interrupted thread\n                    throw ie;\n                }\n\n            }\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    public Events<Event> tryGet(Position start, int batchSize) throws CanalStoreException {\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n            return doGet(start, batchSize);\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    private Events<Event> doGet(Position start, int batchSize) throws CanalStoreException {\n        LogPosition startPosition = (LogPosition) start;\n\n        long current = getSequence.get();\n        long maxAbleSequence = putSequence.get();\n        long next = current;\n        long end = current;\n        // 如果startPosition为null，说明是第一次，默认+1处理\n        if (startPosition == null || !startPosition.getPostion().isIncluded()) { // 第一次订阅之后，需要包含一下start位置，防止丢失第一条记录\n            next = next + 1;\n        }\n\n        if (current >= maxAbleSequence) {\n            return new Events<>();\n        }\n\n        Events<Event> result = new Events<>();\n        List<Event> entrys = result.getEvents();\n        long memsize = 0;\n        if (batchMode.isItemSize()) {\n            end = (next + batchSize - 1) < maxAbleSequence ? (next + batchSize - 1) : maxAbleSequence;\n            // 提取数据并返回\n            for (; next <= end; next++) {\n                Event event = entries[getIndex(next)];\n                if (ddlIsolation && isDdl(event.getEventType())) {\n                    // 如果是ddl隔离，直接返回\n                    if (entrys.size() == 0) {\n                        entrys.add(event);// 如果没有DML事件，加入当前的DDL事件\n                        end = next; // 更新end为当前\n                    } else {\n                        // 如果之前已经有DML事件，直接返回了，因为不包含当前next这记录，需要回退一个位置\n                        end = next - 1; // next-1一定大于current，不需要判断\n                    }\n                    break;\n                } else {\n                    entrys.add(event);\n                }\n            }\n        } else {\n            long maxMemSize = batchSize * bufferMemUnit;\n            for (; memsize <= maxMemSize && next <= maxAbleSequence; next++) {\n                // 永远保证可以取出第一条的记录，避免死锁\n                Event event = entries[getIndex(next)];\n                if (ddlIsolation && isDdl(event.getEventType())) {\n                    // 如果是ddl隔离，直接返回\n                    if (entrys.size() == 0) {\n                        entrys.add(event);// 如果没有DML事件，加入当前的DDL事件\n                        end = next; // 更新end为当前\n                    } else {\n                        // 如果之前已经有DML事件，直接返回了，因为不包含当前next这记录，需要回退一个位置\n                        end = next - 1; // next-1一定大于current，不需要判断\n                    }\n                    break;\n                } else {\n                    entrys.add(event);\n                    memsize += calculateSize(event);\n                    end = next;// 记录end位点\n                }\n            }\n\n        }\n\n        PositionRange<LogPosition> range = new PositionRange<>();\n        result.setPositionRange(range);\n\n        range.setStart(CanalEventUtils.createPosition(entrys.get(0)));\n        range.setEnd(CanalEventUtils.createPosition(entrys.get(result.getEvents().size() - 1)));\n        range.setEndSeq(end);\n        // 记录一下是否存在可以被ack的点\n\n        for (int i = entrys.size() - 1; i >= 0; i--) {\n            Event event = entrys.get(i);\n            // GTID模式,ack的位点必须是事务结尾,因为下一次订阅的时候mysql会发送这个gtid之后的next,如果在事务头就记录了会丢这最后一个事务\n            if ((CanalEntry.EntryType.TRANSACTIONBEGIN == event.getEntryType() && StringUtils.isEmpty(event.getGtid()))\n                || CanalEntry.EntryType.TRANSACTIONEND == event.getEntryType() || isDdl(event.getEventType())) {\n                // 将事务头/尾设置可被为ack的点\n                range.setAck(CanalEventUtils.createPosition(event));\n                break;\n            }\n        }\n\n        if (getSequence.compareAndSet(current, end)) {\n            getMemSize.addAndGet(memsize);\n            notFull.signal();\n            profiling(result.getEvents(), OP.GET);\n            return result;\n        } else {\n            return new Events<>();\n        }\n    }\n\n    public LogPosition getFirstPosition() throws CanalStoreException {\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n            long firstSeqeuence = ackSequence.get();\n            if (firstSeqeuence == INIT_SEQUENCE && firstSeqeuence < putSequence.get()) {\n                // 没有ack过数据\n                Event event = entries[getIndex(firstSeqeuence + 1)]; // 最后一次ack为-1，需要移动到下一条,included\n                                                                     // = false\n                return CanalEventUtils.createPosition(event, false);\n            } else if (firstSeqeuence > INIT_SEQUENCE && firstSeqeuence < putSequence.get()) {\n                // ack未追上put操作\n                Event event = entries[getIndex(firstSeqeuence)]; // 最后一次ack的位置数据,需要移动到下一条,included\n                // = false\n                return CanalEventUtils.createPosition(event, false);\n            } else if (firstSeqeuence > INIT_SEQUENCE && firstSeqeuence == putSequence.get()) {\n                // 已经追上，store中没有数据\n                Event event = entries[getIndex(firstSeqeuence)]; // 最后一次ack的位置数据，和last为同一条，included\n                                                                 // = false\n                return CanalEventUtils.createPosition(event, false);\n            } else {\n                // 没有任何数据\n                return null;\n            }\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    public LogPosition getLatestPosition() throws CanalStoreException {\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n            long latestSequence = putSequence.get();\n            if (latestSequence > INIT_SEQUENCE && latestSequence != ackSequence.get()) {\n                Event event = entries[(int) putSequence.get() & indexMask]; // 最后一次写入的数据，最后一条未消费的数据\n                return CanalEventUtils.createPosition(event, true);\n            } else if (latestSequence > INIT_SEQUENCE && latestSequence == ackSequence.get()) {\n                // ack已经追上了put操作\n                Event event = entries[(int) putSequence.get() & indexMask]; // 最后一次写入的数据，included\n                                                                            // =\n                                                                            // false\n                return CanalEventUtils.createPosition(event, false);\n            } else {\n                // 没有任何数据\n                return null;\n            }\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    public void ack(Position position) throws CanalStoreException {\n        cleanUntil(position, -1L);\n    }\n\n    public void ack(Position position, Long seqId) throws CanalStoreException {\n        cleanUntil(position, seqId);\n    }\n\n    @Override\n    public void cleanUntil(Position position) throws CanalStoreException {\n        cleanUntil(position, -1L);\n    }\n\n    public void cleanUntil(Position position, Long seqId) throws CanalStoreException {\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n            long sequence = ackSequence.get();\n            long maxSequence = getSequence.get();\n\n            boolean hasMatch = false;\n            long memsize = 0;\n            // ack没有list，但有已存在的foreach，还是节省一下list的开销\n            long localExecTime = 0L;\n            int deltaRows = 0;\n            if (seqId > 0) {\n                maxSequence = seqId;\n            }\n            for (long next = sequence + 1; next <= maxSequence; next++) {\n                Event event = entries[getIndex(next)];\n                if (localExecTime == 0 && event.getExecuteTime() > 0) {\n                    localExecTime = event.getExecuteTime();\n                }\n                deltaRows += event.getRowsCount();\n                memsize += calculateSize(event);\n                if ((seqId < 0 || next == seqId) && CanalEventUtils.checkPosition(event, (LogPosition) position)) {\n                    // 找到对应的position，更新ack seq\n                    hasMatch = true;\n\n                    if (batchMode.isMemSize()) {\n                        ackMemSize.addAndGet(memsize);\n                        // 尝试清空buffer中的内存，将ack之前的内存全部释放掉\n                        for (long index = sequence + 1; index < next; index++) {\n                            entries[getIndex(index)] = null;// 设置为null\n                        }\n\n                        // 考虑getFirstPosition/getLastPosition会获取最后一次ack的position信息\n                        // ack清理的时候只处理entry=null，释放内存\n                        Event lastEvent = entries[getIndex(next)];\n                        lastEvent.setEntry(null);\n                        lastEvent.setRawEntry(null);\n                    }\n\n                    if (ackSequence.compareAndSet(sequence, next)) {// 避免并发ack\n                        notFull.signal();\n                        ackTableRows.addAndGet(deltaRows);\n                        if (localExecTime > 0) {\n                            ackExecTime.lazySet(localExecTime);\n                        }\n                        return;\n                    }\n                }\n            }\n            if (!hasMatch) {// 找不到对应需要ack的position\n                throw new CanalStoreException(\"no match ack position\" + position.toString());\n            }\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    public void rollback() throws CanalStoreException {\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n            getSequence.set(ackSequence.get());\n            getMemSize.set(ackMemSize.get());\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    public void cleanAll() throws CanalStoreException {\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n            putSequence.set(INIT_SEQUENCE);\n            getSequence.set(INIT_SEQUENCE);\n            ackSequence.set(INIT_SEQUENCE);\n\n            putMemSize.set(0);\n            getMemSize.set(0);\n            ackMemSize.set(0);\n            entries = null;\n            // for (int i = 0; i < entries.length; i++) {\n            // entries[i] = null;\n            // }\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    // =================== helper method =================\n\n    private long getMinimumGetOrAck() {\n        long get = getSequence.get();\n        long ack = ackSequence.get();\n        return ack <= get ? ack : get;\n    }\n\n    /**\n     * 查询是否有空位\n     */\n    private boolean checkFreeSlotAt(final long sequence) {\n        final long wrapPoint = sequence - bufferSize;\n        final long minPoint = getMinimumGetOrAck();\n        if (wrapPoint > minPoint) { // 刚好追上一轮\n            return false;\n        } else {\n            // 在bufferSize模式上，再增加memSize控制\n            if (batchMode.isMemSize()) {\n                final long memsize = putMemSize.get() - ackMemSize.get();\n                if (memsize < bufferSize * bufferMemUnit) {\n                    return true;\n                } else {\n                    return false;\n                }\n            } else {\n                return true;\n            }\n        }\n    }\n\n    /**\n     * 检查是否存在需要get的数据,并且数量>=batchSize\n     */\n    private boolean checkUnGetSlotAt(LogPosition startPosition, int batchSize) {\n        if (batchMode.isItemSize()) {\n            long current = getSequence.get();\n            long maxAbleSequence = putSequence.get();\n            long next = current;\n            if (startPosition == null || !startPosition.getPostion().isIncluded()) { // 第一次订阅之后，需要包含一下start位置，防止丢失第一条记录\n                next = next + 1;// 少一条数据\n            }\n\n            if (current < maxAbleSequence && next + batchSize - 1 <= maxAbleSequence) {\n                return true;\n            } else {\n                return false;\n            }\n        } else {\n            // 处理内存大小判断\n            long currentSize = getMemSize.get();\n            long maxAbleSize = putMemSize.get();\n\n            if (maxAbleSize - currentSize >= batchSize * bufferMemUnit) {\n                return true;\n            } else {\n                return false;\n            }\n        }\n    }\n\n    private long calculateSize(Event event) {\n        // 直接返回binlog中的事件大小\n        return event.getRawLength();\n    }\n\n    private int getIndex(long sequcnce) {\n        return (int) sequcnce & indexMask;\n    }\n\n    private boolean isDdl(EventType type) {\n        return type == EventType.ALTER || type == EventType.CREATE || type == EventType.ERASE\n               || type == EventType.RENAME || type == EventType.TRUNCATE || type == EventType.CINDEX\n               || type == EventType.DINDEX;\n    }\n\n    private void profiling(List<Event> events, OP op) {\n        long localExecTime = 0L;\n        int deltaRows = 0;\n        if (events != null && !events.isEmpty()) {\n            for (Event e : events) {\n                if (localExecTime == 0 && e.getExecuteTime() > 0) {\n                    localExecTime = e.getExecuteTime();\n                }\n                deltaRows += e.getRowsCount();\n            }\n        }\n        switch (op) {\n            case PUT:\n                putTableRows.addAndGet(deltaRows);\n                if (localExecTime > 0) {\n                    putExecTime.lazySet(localExecTime);\n                }\n                break;\n            case GET:\n                getTableRows.addAndGet(deltaRows);\n                if (localExecTime > 0) {\n                    getExecTime.lazySet(localExecTime);\n                }\n                break;\n            case ACK:\n                ackTableRows.addAndGet(deltaRows);\n                if (localExecTime > 0) {\n                    ackExecTime.lazySet(localExecTime);\n                }\n                break;\n            default:\n                break;\n        }\n    }\n\n    private enum OP {\n        PUT, GET, ACK\n    }\n\n    // ================ setter / getter ==================\n    public int getBufferSize() {\n        return this.bufferSize;\n    }\n\n    public void setBufferSize(int bufferSize) {\n        this.bufferSize = bufferSize;\n    }\n\n    public void setBufferMemUnit(int bufferMemUnit) {\n        this.bufferMemUnit = bufferMemUnit;\n    }\n\n    public void setBatchMode(BatchMode batchMode) {\n        this.batchMode = batchMode;\n    }\n\n    public void setDdlIsolation(boolean ddlIsolation) {\n        this.ddlIsolation = ddlIsolation;\n    }\n\n    public boolean isRaw() {\n        return raw;\n    }\n\n    public void setRaw(boolean raw) {\n        this.raw = raw;\n    }\n\n    public AtomicLong getPutSequence() {\n        return putSequence;\n    }\n\n    public AtomicLong getAckSequence() {\n        return ackSequence;\n    }\n\n    public AtomicLong getPutMemSize() {\n        return putMemSize;\n    }\n\n    public AtomicLong getAckMemSize() {\n        return ackMemSize;\n    }\n\n    public BatchMode getBatchMode() {\n        return batchMode;\n    }\n\n    public AtomicLong getPutExecTime() {\n        return putExecTime;\n    }\n\n    public AtomicLong getGetExecTime() {\n        return getExecTime;\n    }\n\n    public AtomicLong getAckExecTime() {\n        return ackExecTime;\n    }\n\n    public AtomicLong getPutTableRows() {\n        return putTableRows;\n    }\n\n    public AtomicLong getGetTableRows() {\n        return getTableRows;\n    }\n\n    public AtomicLong getAckTableRows() {\n        return ackTableRows;\n    }\n\n}\n"
  },
  {
    "path": "store/src/main/java/com/alibaba/otter/canal/store/model/BatchMode.java",
    "content": "package com.alibaba.otter.canal.store.model;\n\n/**\n * 批处理模式\n * \n * @author jianghang 2013-3-18 上午11:51:15\n * @version 1.0.3\n */\npublic enum BatchMode {\n\n    /** 对象数量 */\n    ITEMSIZE,\n\n    /** 内存大小 */\n    MEMSIZE;\n\n    public boolean isItemSize() {\n        return this == BatchMode.ITEMSIZE;\n    }\n\n    public boolean isMemSize() {\n        return this == BatchMode.MEMSIZE;\n    }\n}\n"
  },
  {
    "path": "store/src/main/java/com/alibaba/otter/canal/store/model/Event.java",
    "content": "package com.alibaba.otter.canal.store.model;\n\nimport java.io.Serializable;\nimport java.util.List;\n\nimport org.apache.commons.lang.builder.ToStringBuilder;\n\nimport com.alibaba.otter.canal.common.utils.CanalToStringStyle;\nimport com.alibaba.otter.canal.protocol.CanalEntry;\nimport com.alibaba.otter.canal.protocol.CanalEntry.EntryType;\nimport com.alibaba.otter.canal.protocol.CanalEntry.EventType;\nimport com.alibaba.otter.canal.protocol.position.LogIdentity;\nimport com.google.protobuf.ByteString;\n\n/**\n * store存储数据对象\n * \n * @author jianghang 2012-7-13 下午03:03:03\n */\npublic class Event implements Serializable {\n\n    private static final long serialVersionUID = 1333330351758762739L;\n\n    private LogIdentity       logIdentity;                            // 记录数据产生的来源\n    private ByteString        rawEntry;\n\n    private long              executeTime;\n    private EntryType         entryType;\n    private String            journalName;\n    private long              position;\n    private long              serverId;\n    private EventType         eventType;\n    private String            gtid;\n    private long              rawLength;\n    private int               rowsCount;\n\n    // ==== https://github.com/alibaba/canal/issues/1019\n    private CanalEntry.Entry  entry;\n\n    public Event(){\n    }\n\n    public Event(LogIdentity logIdentity, CanalEntry.Entry entry){\n        this(logIdentity, entry, true);\n    }\n\n    public Event(LogIdentity logIdentity, CanalEntry.Entry entry, boolean raw){\n        this.logIdentity = logIdentity;\n        this.entryType = entry.getEntryType();\n        this.executeTime = entry.getHeader().getExecuteTime();\n        this.journalName = entry.getHeader().getLogfileName();\n        this.position = entry.getHeader().getLogfileOffset();\n        this.serverId = entry.getHeader().getServerId();\n        this.gtid = entry.getHeader().getGtid();\n        this.eventType = entry.getHeader().getEventType();\n        if (entryType == EntryType.ROWDATA) {\n            List<CanalEntry.Pair> props = entry.getHeader().getPropsList();\n            if (props != null) {\n                for (CanalEntry.Pair p : props) {\n                    if (\"rowsCount\".equals(p.getKey())) {\n                        rowsCount = Integer.parseInt(p.getValue());\n                        break;\n                    }\n                }\n            }\n        }\n\n        if (raw) {\n            // build raw\n            this.rawEntry = entry.toByteString();\n            this.rawLength = rawEntry.size();\n        } else {\n            this.entry = entry;\n            // 按照6倍的event length预估\n            this.rawLength = entry.getHeader().getEventLength() * 6;\n        }\n    }\n\n    public LogIdentity getLogIdentity() {\n        return logIdentity;\n    }\n\n    public void setLogIdentity(LogIdentity logIdentity) {\n        this.logIdentity = logIdentity;\n    }\n\n    public ByteString getRawEntry() {\n        return rawEntry;\n    }\n\n    public void setRawEntry(ByteString rawEntry) {\n        this.rawEntry = rawEntry;\n    }\n\n    public long getExecuteTime() {\n        return executeTime;\n    }\n\n    public void setExecuteTime(long executeTime) {\n        this.executeTime = executeTime;\n    }\n\n    public EntryType getEntryType() {\n        return entryType;\n    }\n\n    public void setEntryType(EntryType entryType) {\n        this.entryType = entryType;\n    }\n\n    public String getJournalName() {\n        return journalName;\n    }\n\n    public void setJournalName(String journalName) {\n        this.journalName = journalName;\n    }\n\n    public long getPosition() {\n        return position;\n    }\n\n    public void setPosition(long position) {\n        this.position = position;\n    }\n\n    public long getServerId() {\n        return serverId;\n    }\n\n    public void setServerId(long serverId) {\n        this.serverId = serverId;\n    }\n\n    public String getGtid() {\n        return gtid;\n    }\n\n    public void setGtid(String gtid) {\n        this.gtid = gtid;\n    }\n\n    public long getRawLength() {\n        return rawLength;\n    }\n\n    public void setRawLength(long rawLength) {\n        this.rawLength = rawLength;\n    }\n\n    public EventType getEventType() {\n        return eventType;\n    }\n\n    public void setEventType(EventType eventType) {\n        this.eventType = eventType;\n    }\n\n    public int getRowsCount() {\n        return rowsCount;\n    }\n\n    public void setRowsCount(int rowsCount) {\n        this.rowsCount = rowsCount;\n    }\n\n    public CanalEntry.Entry getEntry() {\n        return entry;\n    }\n\n    public void setEntry(CanalEntry.Entry entry) {\n        this.entry = entry;\n    }\n\n    public String toString() {\n        return ToStringBuilder.reflectionToString(this, CanalToStringStyle.DEFAULT_STYLE);\n    }\n\n}\n"
  },
  {
    "path": "store/src/main/java/com/alibaba/otter/canal/store/model/Events.java",
    "content": "package com.alibaba.otter.canal.store.model;\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.apache.commons.lang.builder.ToStringBuilder;\n\nimport com.alibaba.otter.canal.common.utils.CanalToStringStyle;\nimport com.alibaba.otter.canal.protocol.position.PositionRange;\n\n/**\n * 代表一组数据对象的集合\n * \n * @author jianghang 2012-6-14 下午09:07:41\n * @version 1.0.0\n */\npublic class Events<EVENT> implements Serializable {\n\n    private static final long serialVersionUID = -7337454954300706044L;\n\n    private PositionRange     positionRange    = new PositionRange();\n    private List<EVENT>       events           = new ArrayList<>();\n\n    public List<EVENT> getEvents() {\n        return events;\n    }\n\n    public void setEvents(List<EVENT> events) {\n        this.events = events;\n    }\n\n    public PositionRange getPositionRange() {\n        return positionRange;\n    }\n\n    public void setPositionRange(PositionRange positionRange) {\n        this.positionRange = positionRange;\n    }\n\n    public String toString() {\n        return ToStringBuilder.reflectionToString(this, CanalToStringStyle.DEFAULT_STYLE);\n    }\n}\n"
  },
  {
    "path": "store/src/test/java/com/alibaba/otter/canal/store/memory/buffer/MemoryEventStoreBase.java",
    "content": "package com.alibaba.otter.canal.store.memory.buffer;\n\nimport java.net.InetSocketAddress;\n\nimport org.junit.Assert;\n\nimport com.alibaba.otter.canal.protocol.CanalEntry.Entry;\nimport com.alibaba.otter.canal.protocol.CanalEntry.Header;\nimport com.alibaba.otter.canal.protocol.position.LogIdentity;\nimport com.alibaba.otter.canal.store.model.Event;\n\npublic class MemoryEventStoreBase {\n\n    private static final String MYSQL_ADDRESS = \"127.0.0.1\";\n\n    protected void sleep(Long time) {\n        try {\n            Thread.sleep(time);\n        } catch (InterruptedException e) {\n            Assert.fail();\n        }\n    }\n\n    protected Event buildEvent(String binlogFile, long offset, long timestamp) {\n        Header.Builder headerBuilder = Header.newBuilder();\n        headerBuilder.setLogfileName(binlogFile);\n        headerBuilder.setLogfileOffset(offset);\n        headerBuilder.setExecuteTime(timestamp);\n        headerBuilder.setEventLength(1024);\n        Entry.Builder entryBuilder = Entry.newBuilder();\n        entryBuilder.setHeader(headerBuilder.build());\n        Entry entry = entryBuilder.build();\n\n        return new Event(new LogIdentity(new InetSocketAddress(MYSQL_ADDRESS, 3306), 1234L), entry);\n    }\n\n    protected Event buildEvent(String binlogFile, long offset, long timestamp, long eventLenght) {\n        Header.Builder headerBuilder = Header.newBuilder();\n        headerBuilder.setLogfileName(binlogFile);\n        headerBuilder.setLogfileOffset(offset);\n        headerBuilder.setExecuteTime(timestamp);\n        headerBuilder.setEventLength(eventLenght);\n        Entry.Builder entryBuilder = Entry.newBuilder();\n        entryBuilder.setHeader(headerBuilder.build());\n        Entry entry = entryBuilder.build();\n\n        return new Event(new LogIdentity(new InetSocketAddress(MYSQL_ADDRESS, 3306), 1234L), entry);\n    }\n}\n"
  },
  {
    "path": "store/src/test/java/com/alibaba/otter/canal/store/memory/buffer/MemoryEventStoreMemBatchTest.java",
    "content": "package com.alibaba.otter.canal.store.memory.buffer;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.TimeUnit;\n\nimport org.junit.Assert;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.protocol.position.Position;\nimport com.alibaba.otter.canal.store.CanalStoreException;\nimport com.alibaba.otter.canal.store.helper.CanalEventUtils;\nimport com.alibaba.otter.canal.store.memory.MemoryEventStoreWithBuffer;\nimport com.alibaba.otter.canal.store.model.BatchMode;\nimport com.alibaba.otter.canal.store.model.Event;\nimport com.alibaba.otter.canal.store.model.Events;\n\npublic class MemoryEventStoreMemBatchTest extends MemoryEventStoreBase {\n\n    @Test\n    public void testOnePut() {\n        MemoryEventStoreWithBuffer eventStore = new MemoryEventStoreWithBuffer();\n        eventStore.setBatchMode(BatchMode.MEMSIZE);\n        eventStore.start();\n        // 尝试阻塞\n        try {\n            eventStore.put(buildEvent(\"1\", 1L, 1L, 1024));\n        } catch (Exception e) {\n            Assert.fail(e.getMessage());\n        }\n        // 尝试阻塞+超时\n        boolean result = false;\n        try {\n            result = eventStore.put(buildEvent(\"1\", 1L, 1L), 1000L, TimeUnit.MILLISECONDS);\n            Assert.assertTrue(result);\n        } catch (Exception e) {\n            Assert.fail(e.getMessage());\n        }\n        // 尝试\n        result = eventStore.tryPut(buildEvent(\"1\", 1L, 1L));\n        Assert.assertTrue(result);\n\n        eventStore.stop();\n    }\n\n    @Test\n    public void testOnePutExceedLimit() {\n        MemoryEventStoreWithBuffer eventStore = new MemoryEventStoreWithBuffer();\n        eventStore.setBufferSize(1);\n        eventStore.setBatchMode(BatchMode.MEMSIZE);\n        eventStore.start();\n        // 尝试阻塞\n        try {\n            boolean result = eventStore.tryPut(buildEvent(\"1\", 1L, 1L, 1025));// 只有一条记录，第一条超过也允许放入\n            Assert.assertTrue(result);\n        } catch (Exception e) {\n            Assert.fail(e.getMessage());\n        }\n\n        eventStore.stop();\n    }\n\n    @Test\n    public void testFullPut() {\n        int bufferSize = 16;\n        MemoryEventStoreWithBuffer eventStore = new MemoryEventStoreWithBuffer();\n        eventStore.setBufferSize(bufferSize);\n        eventStore.setBatchMode(BatchMode.MEMSIZE);\n        eventStore.start();\n\n        for (int i = 0; i < bufferSize; i++) {\n            boolean result = eventStore.tryPut(buildEvent(\"1\", 1L, 1L + i));\n            Assert.assertTrue(result);\n        }\n\n        boolean result = eventStore.tryPut(buildEvent(\"1\", 1L, 1L + bufferSize));\n        Assert.assertFalse(result);\n\n        try {\n            result = eventStore.put(buildEvent(\"1\", 1L, 1L + bufferSize), 1000L, TimeUnit.MILLISECONDS);\n        } catch (CanalStoreException | InterruptedException e) {\n            Assert.fail(e.getMessage());\n        }\n\n        Assert.assertFalse(result);\n\n        eventStore.stop();\n    }\n\n    @Test\n    public void testOnePutOneGet() {\n        MemoryEventStoreWithBuffer eventStore = new MemoryEventStoreWithBuffer();\n        eventStore.setBatchMode(BatchMode.MEMSIZE);\n        eventStore.start();\n\n        boolean result = eventStore.tryPut(buildEvent(\"1\", 1L, 1L));\n        Assert.assertTrue(result);\n\n        Position position = eventStore.getFirstPosition();\n        Events<Event> entrys = eventStore.tryGet(position, 1);\n        Assert.assertTrue(entrys.getEvents().size() == 1);\n        Assert.assertEquals(position, entrys.getPositionRange().getStart());\n        Assert.assertEquals(position, entrys.getPositionRange().getEnd());\n\n        eventStore.stop();\n    }\n\n    @Test\n    public void testFullPutBatchGet() {\n        int bufferSize = 16;\n        MemoryEventStoreWithBuffer eventStore = new MemoryEventStoreWithBuffer();\n        eventStore.setBufferSize(bufferSize);\n        eventStore.setBatchMode(BatchMode.MEMSIZE);\n        eventStore.start();\n\n        for (int i = 0; i < bufferSize; i++) {\n            boolean result = eventStore.tryPut(buildEvent(\"1\", 1L, 1L + i));\n            sleep(100L);\n            Assert.assertTrue(result);\n        }\n\n        Position first = eventStore.getFirstPosition();\n        Position lastest = eventStore.getLatestPosition();\n        Assert.assertEquals(first, CanalEventUtils.createPosition(buildEvent(\"1\", 1L, 1L)));\n        Assert.assertEquals(lastest, CanalEventUtils.createPosition(buildEvent(\"1\", 1L, 1L + bufferSize - 1)));\n\n        System.out.println(\"start get\");\n        Events<Event> entrys1 = eventStore.tryGet(first, bufferSize);\n        System.out.println(\"first get size : \" + entrys1.getEvents().size());\n\n        Assert.assertTrue(entrys1.getEvents().size() == bufferSize);\n        Assert.assertEquals(first, entrys1.getPositionRange().getStart());\n        Assert.assertEquals(lastest, entrys1.getPositionRange().getEnd());\n\n        Assert.assertEquals(first, CanalEventUtils.createPosition(entrys1.getEvents().get(0)));\n        Assert.assertEquals(lastest, CanalEventUtils.createPosition(entrys1.getEvents().get(bufferSize - 1)));\n        eventStore.stop();\n    }\n\n    @Ignore\n    @Test\n    public void testBlockPutOneGet() {\n        final MemoryEventStoreWithBuffer eventStore = new MemoryEventStoreWithBuffer();\n        eventStore.setBufferSize(16);\n        eventStore.setBatchMode(BatchMode.MEMSIZE);\n        eventStore.start();\n\n        final int batchSize = 10;\n        for (int i = 0; i < batchSize; i++) {\n            boolean result = eventStore.tryPut(buildEvent(\"1\", 1L, 1L));\n            Assert.assertTrue(result);\n        }\n\n        final Position position = eventStore.getFirstPosition();\n        try {\n            Events<Event> entrys = eventStore.get(position, batchSize);\n            Assert.assertTrue(entrys.getEvents().size() == batchSize);\n            Assert.assertEquals(position, entrys.getPositionRange().getStart());\n            Assert.assertEquals(position, entrys.getPositionRange().getEnd());\n        } catch (CanalStoreException | InterruptedException e) {\n        }\n\n        ExecutorService executor = Executors.newFixedThreadPool(1);\n        executor.submit(() -> {\n            boolean result = false;\n            try {\n                eventStore.get(position, batchSize);\n            } catch (CanalStoreException e) {\n            } catch (InterruptedException e) {\n                System.out.println(\"interrupt occured.\");\n                result = true;\n            }\n            Assert.assertTrue(result);\n        });\n\n        try {\n            Thread.sleep(1000L);\n        } catch (InterruptedException e) {\n            Assert.fail(e.getMessage());\n        }\n        executor.shutdownNow();\n\n        try {\n            Thread.sleep(1000L);\n        } catch (InterruptedException e) {\n            Assert.fail(e.getMessage());\n        }\n        eventStore.stop();\n    }\n\n    @Test\n    public void testRollback() {\n        int bufferSize = 16;\n        MemoryEventStoreWithBuffer eventStore = new MemoryEventStoreWithBuffer();\n        eventStore.setBufferSize(bufferSize);\n        eventStore.setBatchMode(BatchMode.MEMSIZE);\n        eventStore.start();\n\n        for (int i = 0; i < bufferSize / 2; i++) {\n            boolean result = eventStore.tryPut(buildEvent(\"1\", 1L, 1L + i));\n            sleep(100L);\n            Assert.assertTrue(result);\n        }\n\n        sleep(50L);\n        Position first = eventStore.getFirstPosition();\n        Position lastest = eventStore.getLatestPosition();\n        Assert.assertEquals(first, CanalEventUtils.createPosition(buildEvent(\"1\", 1L, 1L)));\n        Assert.assertEquals(lastest, CanalEventUtils.createPosition(buildEvent(\"1\", 1L, 1L + bufferSize / 2 - 1)));\n\n        System.out.println(\"start get\");\n        Events<Event> entrys1 = eventStore.tryGet(first, bufferSize);\n        System.out.println(\"first get size : \" + entrys1.getEvents().size());\n\n        eventStore.rollback();\n\n        entrys1 = eventStore.tryGet(first, bufferSize);\n        System.out.println(\"after rollback get size : \" + entrys1.getEvents().size());\n        Assert.assertTrue(entrys1.getEvents().size() == bufferSize / 2);\n\n        // 继续造数据\n        for (int i = bufferSize / 2; i < bufferSize; i++) {\n            boolean result = eventStore.tryPut(buildEvent(\"1\", 1L, 1L + i));\n            sleep(100L);\n            Assert.assertTrue(result);\n        }\n\n        Events<Event> entrys2 = eventStore.tryGet(entrys1.getPositionRange().getEnd(), bufferSize);\n        System.out.println(\"second get size : \" + entrys2.getEvents().size());\n\n        eventStore.rollback();\n\n        entrys2 = eventStore.tryGet(entrys1.getPositionRange().getEnd(), bufferSize);\n        System.out.println(\"after rollback get size : \" + entrys2.getEvents().size());\n        Assert.assertTrue(entrys2.getEvents().size() == bufferSize);\n\n        first = eventStore.getFirstPosition();\n        lastest = eventStore.getLatestPosition();\n        List<Event> entrys = new ArrayList<>(entrys2.getEvents());\n        Assert.assertTrue(entrys.size() == bufferSize);\n        Assert.assertEquals(first, entrys2.getPositionRange().getStart());\n        Assert.assertEquals(lastest, entrys2.getPositionRange().getEnd());\n\n        Assert.assertEquals(first, CanalEventUtils.createPosition(entrys.get(0)));\n        Assert.assertEquals(lastest, CanalEventUtils.createPosition(entrys.get(bufferSize - 1)));\n        eventStore.stop();\n    }\n\n    @Test\n    public void testAck() {\n        int bufferSize = 16;\n        MemoryEventStoreWithBuffer eventStore = new MemoryEventStoreWithBuffer();\n        eventStore.setBufferSize(bufferSize);\n        eventStore.setBatchMode(BatchMode.MEMSIZE);\n        eventStore.start();\n\n        for (int i = 0; i < bufferSize / 2; i++) {\n            boolean result = eventStore.tryPut(buildEvent(\"1\", 1L, 1L + i));\n            sleep(100L);\n            Assert.assertTrue(result);\n        }\n\n        sleep(50L);\n        Position first = eventStore.getFirstPosition();\n        Position lastest = eventStore.getLatestPosition();\n        Assert.assertEquals(first, CanalEventUtils.createPosition(buildEvent(\"1\", 1L, 1L)));\n        Assert.assertEquals(lastest, CanalEventUtils.createPosition(buildEvent(\"1\", 1L, 1L + bufferSize / 2 - 1)));\n\n        System.out.println(\"start get\");\n        Events<Event> entrys1 = eventStore.tryGet(first, bufferSize);\n        System.out.println(\"first get size : \" + entrys1.getEvents().size());\n\n        eventStore.cleanUntil(entrys1.getPositionRange().getEnd());\n        sleep(50L);\n\n        // 继续造数据\n        for (int i = bufferSize / 2; i < bufferSize; i++) {\n            boolean result = eventStore.tryPut(buildEvent(\"1\", 1L, 1L + i));\n            sleep(100L);\n            Assert.assertTrue(result);\n        }\n\n        Events<Event> entrys2 = eventStore.tryGet(entrys1.getPositionRange().getEnd(), bufferSize);\n        System.out.println(\"second get size : \" + entrys2.getEvents().size());\n\n        eventStore.rollback();\n\n        entrys2 = eventStore.tryGet(entrys1.getPositionRange().getEnd(), bufferSize);\n        System.out.println(\"after rollback get size : \" + entrys2.getEvents().size());\n\n        first = eventStore.getFirstPosition();\n        lastest = eventStore.getLatestPosition();\n        List<Event> entrys = new ArrayList<>(entrys2.getEvents());\n        // Assert.assertEquals(first, entrys2.getPositionRange().getStart());\n        Assert.assertEquals(lastest, entrys2.getPositionRange().getEnd());\n\n        // Assert.assertEquals(first,\n        // CanalEventUtils.createPosition(entrys.get(0)));\n        Assert.assertEquals(lastest, CanalEventUtils.createPosition(entrys.get(entrys.size() - 1)));\n\n        // 全部ack掉\n        eventStore.cleanUntil(entrys2.getPositionRange().getEnd());\n\n        // 最后就拿不到数据\n        Events<Event> entrys3 = eventStore.tryGet(entrys1.getPositionRange().getEnd(), bufferSize);\n        System.out.println(\"third get size : \" + entrys3.getEvents().size());\n        Assert.assertEquals(0, entrys3.getEvents().size());\n\n        eventStore.stop();\n    }\n}\n"
  },
  {
    "path": "store/src/test/java/com/alibaba/otter/canal/store/memory/buffer/MemoryEventStoreMultiThreadTest.java",
    "content": "package com.alibaba.otter.canal.store.memory.buffer;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.commons.lang.math.RandomUtils;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.springframework.util.CollectionUtils;\n\nimport com.alibaba.otter.canal.common.utils.BooleanMutex;\nimport com.alibaba.otter.canal.protocol.position.Position;\nimport com.alibaba.otter.canal.store.CanalStoreException;\nimport com.alibaba.otter.canal.store.memory.MemoryEventStoreWithBuffer;\nimport com.alibaba.otter.canal.store.model.BatchMode;\nimport com.alibaba.otter.canal.store.model.Event;\nimport com.alibaba.otter.canal.store.model.Events;\n\n/**\n * 多线程的put/get/ack/rollback测试\n *\n * @author jianghang 2012-6-20 下午02:50:36\n * @version 1.0.0\n */\npublic class MemoryEventStoreMultiThreadTest extends MemoryEventStoreBase {\n\n    private ExecutorService            executor = Executors.newFixedThreadPool(2); // 1\n                                                                                   // producer\n                                                                                   // ,1\n                                                                                   // cousmer\n    private MemoryEventStoreWithBuffer eventStore;\n\n    @Before\n    public void setUp() {\n        eventStore = new MemoryEventStoreWithBuffer();\n        eventStore.setBufferSize(16 * 16);\n        eventStore.setBatchMode(BatchMode.MEMSIZE);\n        eventStore.start();\n    }\n\n    @After\n    public void tearDown() {\n        eventStore.stop();\n    }\n    @Ignore\n    @Test\n    public void test() {\n        CountDownLatch latch = new CountDownLatch(1);\n        BooleanMutex mutex = new BooleanMutex(true);\n        Producer producer = new Producer(mutex, 10);\n        Cosumer cosumer = new Cosumer(latch, 20, 50);\n\n        executor.submit(producer);\n        executor.submit(cosumer);\n\n        try {\n            Thread.sleep(30 * 1000L);\n        } catch (InterruptedException e) {\n        }\n\n        mutex.set(false);\n        try {\n            latch.await();\n        } catch (InterruptedException e) {\n        }\n        executor.shutdown();\n\n        List<Long> result = cosumer.getResult();\n\n        Long last = -1L;\n        for (Long offest : result) {\n            Assert.assertTrue(last + 1 == offest);// 取出来的数据一定是递增的\n            last = offest;\n        }\n    }\n\n    class Producer implements Runnable {\n\n        private BooleanMutex mutex;\n        private int          freq;\n\n        public Producer(BooleanMutex mutex, int freq){\n            this.mutex = mutex;\n            this.freq = freq;\n        }\n\n        public void run() {\n            long offest = 0;\n            while (true) {\n                try {\n                    mutex.get();\n                    Thread.sleep(RandomUtils.nextInt(freq));\n                } catch (InterruptedException e) {\n                    return;\n                }\n                Event event = buildEvent(\"1\", offest++, 1L);\n\n                try {\n                    Thread.sleep(RandomUtils.nextInt(freq));\n                } catch (InterruptedException e) {\n                    return;\n                }\n                try {\n                    eventStore.put(event);\n                } catch (CanalStoreException | InterruptedException e) {\n                }\n            }\n        }\n    }\n\n    class Cosumer implements Runnable {\n\n        private CountDownLatch latch;\n        private int            freq;\n        private int            batchSize;\n        private List<Long>     result = new ArrayList<>();\n\n        public Cosumer(CountDownLatch latch, int freq, int batchSize){\n            this.latch = latch;\n            this.freq = freq;\n            this.batchSize = batchSize;\n        }\n\n        public void run() {\n            Position first = eventStore.getFirstPosition();\n            while (first == null) {\n                try {\n                    Thread.sleep(RandomUtils.nextInt(freq));\n                } catch (InterruptedException e) {\n                    latch.countDown();\n                    return;\n                }\n\n                first = eventStore.getFirstPosition();\n            }\n\n            int ackCount = 0;\n            int emptyCount = 0;\n            while (emptyCount < 10) {\n                try {\n                    Thread.sleep(RandomUtils.nextInt(freq));\n                } catch (InterruptedException e) {\n                }\n\n                try {\n                    Events<Event> entrys = eventStore.get(first, batchSize, 1000L, TimeUnit.MILLISECONDS);\n                    // Events<Event> entrys = eventStore.tryGet(first,\n                    // batchSize);\n                    if (!CollectionUtils.isEmpty(entrys.getEvents())) {\n                        if (entrys.getEvents().size() != batchSize) {\n                            System.out.println(\"get size:\" + entrys.getEvents().size() + \" with not full batchSize:\"\n                                               + batchSize);\n                        }\n\n                        first = entrys.getPositionRange().getEnd();\n                        for (Event event : entrys.getEvents()) {\n                            this.result.add(event.getPosition());\n                        }\n                        emptyCount = 0;\n\n                        System.out.println(\"offest : \" + entrys.getEvents().get(0).getPosition() + \" , count :\"\n                                           + entrys.getEvents().size());\n                        ackCount++;\n                        if (ackCount == 1) {\n                            eventStore.cleanUntil(entrys.getPositionRange().getEnd());\n                            System.out.println(\"first position : \" + eventStore.getFirstPosition());\n                            ackCount = 0;\n                        }\n                    } else {\n                        emptyCount++;\n                        System.out.println(\"empty events for \" + emptyCount);\n                    }\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n\n            latch.countDown();\n        }\n\n        public List<Long> getResult() {\n            return result;\n        }\n\n    }\n}\n"
  },
  {
    "path": "store/src/test/java/com/alibaba/otter/canal/store/memory/buffer/MemoryEventStorePutAndGetTest.java",
    "content": "package com.alibaba.otter.canal.store.memory.buffer;\n\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.TimeUnit;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.protocol.position.Position;\nimport com.alibaba.otter.canal.store.CanalStoreException;\nimport com.alibaba.otter.canal.store.helper.CanalEventUtils;\nimport com.alibaba.otter.canal.store.memory.MemoryEventStoreWithBuffer;\nimport com.alibaba.otter.canal.store.model.Event;\nimport com.alibaba.otter.canal.store.model.Events;\n\n/**\n * 测试普通的put / get操作\n * \n * @author jianghang 2012-6-19 下午09:50:08\n * @version 1.0.0\n */\npublic class MemoryEventStorePutAndGetTest extends MemoryEventStoreBase {\n\n    @Test\n    public void testOnePut() {\n        MemoryEventStoreWithBuffer eventStore = new MemoryEventStoreWithBuffer();\n        eventStore.start();\n        // 尝试阻塞\n        try {\n            eventStore.put(buildEvent(\"1\", 1L, 1L));\n        } catch (Exception e) {\n            Assert.fail(e.getMessage());\n        }\n        // 尝试阻塞+超时\n        boolean result = false;\n        try {\n            result = eventStore.put(buildEvent(\"1\", 1L, 1L), 1000L, TimeUnit.MILLISECONDS);\n            Assert.assertTrue(result);\n        } catch (Exception e) {\n            Assert.fail(e.getMessage());\n        }\n        // 尝试\n        result = eventStore.tryPut(buildEvent(\"1\", 1L, 1L));\n        Assert.assertTrue(result);\n\n        eventStore.stop();\n    }\n\n    @Test\n    public void testFullPut() {\n        int bufferSize = 16;\n        MemoryEventStoreWithBuffer eventStore = new MemoryEventStoreWithBuffer();\n        eventStore.setBufferSize(bufferSize);\n        eventStore.start();\n\n        for (int i = 0; i < bufferSize; i++) {\n            boolean result = eventStore.tryPut(buildEvent(\"1\", 1L, 1L + i));\n            Assert.assertTrue(result);\n        }\n\n        boolean result = eventStore.tryPut(buildEvent(\"1\", 1L, 1L + bufferSize));\n        Assert.assertFalse(result);\n\n        try {\n            result = eventStore.put(buildEvent(\"1\", 1L, 1L + bufferSize), 1000L, TimeUnit.MILLISECONDS);\n        } catch (CanalStoreException | InterruptedException e) {\n            Assert.fail(e.getMessage());\n        }\n\n        Assert.assertFalse(result);\n\n        eventStore.stop();\n    }\n\n    @Test\n    public void testOnePutOneGet() {\n        MemoryEventStoreWithBuffer eventStore = new MemoryEventStoreWithBuffer();\n        eventStore.start();\n\n        boolean result = eventStore.tryPut(buildEvent(\"1\", 1L, 1L));\n        Assert.assertTrue(result);\n\n        Position position = eventStore.getFirstPosition();\n        Events<Event> entrys = eventStore.tryGet(position, 1);\n        Assert.assertTrue(entrys.getEvents().size() == 1);\n        Assert.assertEquals(position, entrys.getPositionRange().getStart());\n        Assert.assertEquals(position, entrys.getPositionRange().getEnd());\n\n        eventStore.stop();\n    }\n\n    @Test\n    public void testFullPutBatchGet() {\n        int bufferSize = 16;\n        MemoryEventStoreWithBuffer eventStore = new MemoryEventStoreWithBuffer();\n        eventStore.setBufferSize(bufferSize);\n        eventStore.start();\n\n        for (int i = 0; i < bufferSize; i++) {\n            boolean result = eventStore.tryPut(buildEvent(\"1\", 1L, 1L + i));\n            sleep(100L);\n            Assert.assertTrue(result);\n        }\n\n        Position first = eventStore.getFirstPosition();\n        Position lastest = eventStore.getLatestPosition();\n        Assert.assertEquals(first, CanalEventUtils.createPosition(buildEvent(\"1\", 1L, 1L)));\n        Assert.assertEquals(lastest, CanalEventUtils.createPosition(buildEvent(\"1\", 1L, 1L + bufferSize - 1)));\n\n        System.out.println(\"start get\");\n        Events<Event> entrys1 = eventStore.tryGet(first, bufferSize);\n        System.out.println(\"first get size : \" + entrys1.getEvents().size());\n\n        Assert.assertTrue(entrys1.getEvents().size() == bufferSize);\n        Assert.assertEquals(first, entrys1.getPositionRange().getStart());\n        Assert.assertEquals(lastest, entrys1.getPositionRange().getEnd());\n\n        Assert.assertEquals(first, CanalEventUtils.createPosition(entrys1.getEvents().get(0)));\n        Assert.assertEquals(lastest, CanalEventUtils.createPosition(entrys1.getEvents().get(bufferSize - 1)));\n        eventStore.stop();\n    }\n\n    @Test\n    public void testBlockPutOneGet() {\n        final MemoryEventStoreWithBuffer eventStore = new MemoryEventStoreWithBuffer();\n        eventStore.start();\n\n        final int batchSize = 10;\n        for (int i = 0; i < batchSize; i++) {\n            boolean result = eventStore.tryPut(buildEvent(\"1\", 1L, 1L));\n            Assert.assertTrue(result);\n        }\n\n        final Position position = eventStore.getFirstPosition();\n        try {\n            Events<Event> entrys = eventStore.get(position, batchSize);\n            Assert.assertTrue(entrys.getEvents().size() == batchSize);\n            Assert.assertEquals(position, entrys.getPositionRange().getStart());\n            Assert.assertEquals(position, entrys.getPositionRange().getEnd());\n        } catch (CanalStoreException | InterruptedException e) {\n        }\n\n        ExecutorService executor = Executors.newFixedThreadPool(1);\n        executor.submit(() -> {\n            boolean result = false;\n            try {\n                eventStore.get(position, batchSize);\n            } catch (CanalStoreException e) {\n            } catch (InterruptedException e) {\n                System.out.println(\"interrupt occured.\");\n                result = true;\n            }\n            Assert.assertTrue(result);\n        });\n\n        try {\n            Thread.sleep(1000L);\n        } catch (InterruptedException e) {\n            Assert.fail(e.getMessage());\n        }\n        executor.shutdownNow();\n\n        try {\n            Thread.sleep(1000L);\n        } catch (InterruptedException e) {\n            Assert.fail(e.getMessage());\n        }\n        eventStore.stop();\n    }\n}\n"
  },
  {
    "path": "store/src/test/java/com/alibaba/otter/canal/store/memory/buffer/MemoryEventStoreRollbackAndAckTest.java",
    "content": "package com.alibaba.otter.canal.store.memory.buffer;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport com.alibaba.otter.canal.protocol.position.Position;\nimport com.alibaba.otter.canal.store.helper.CanalEventUtils;\nimport com.alibaba.otter.canal.store.memory.MemoryEventStoreWithBuffer;\nimport com.alibaba.otter.canal.store.model.Event;\nimport com.alibaba.otter.canal.store.model.Events;\n\n/**\n * 测试下rollback / ack的操作\n * \n * @author jianghang 2012-6-19 下午09:49:28\n * @version 1.0.0\n */\npublic class MemoryEventStoreRollbackAndAckTest extends MemoryEventStoreBase {\n\n    @Test\n    public void testRollback() {\n        int bufferSize = 16;\n        MemoryEventStoreWithBuffer eventStore = new MemoryEventStoreWithBuffer();\n        eventStore.setBufferSize(bufferSize);\n        eventStore.start();\n\n        for (int i = 0; i < bufferSize / 2; i++) {\n            boolean result = eventStore.tryPut(buildEvent(\"1\", 1L, 1L + i));\n            sleep(100L);\n            Assert.assertTrue(result);\n        }\n\n        sleep(50L);\n        Position first = eventStore.getFirstPosition();\n        Position lastest = eventStore.getLatestPosition();\n        Assert.assertEquals(first, CanalEventUtils.createPosition(buildEvent(\"1\", 1L, 1L)));\n        Assert.assertEquals(lastest, CanalEventUtils.createPosition(buildEvent(\"1\", 1L, 1L + bufferSize / 2 - 1)));\n\n        System.out.println(\"start get\");\n        Events<Event> entrys1 = eventStore.tryGet(first, bufferSize);\n        System.out.println(\"first get size : \" + entrys1.getEvents().size());\n\n        eventStore.rollback();\n\n        entrys1 = eventStore.tryGet(first, bufferSize);\n        System.out.println(\"after rollback get size : \" + entrys1.getEvents().size());\n        Assert.assertTrue(entrys1.getEvents().size() == bufferSize / 2);\n\n        // 继续造数据\n        for (int i = bufferSize / 2; i < bufferSize; i++) {\n            boolean result = eventStore.tryPut(buildEvent(\"1\", 1L, 1L + i));\n            sleep(100L);\n            Assert.assertTrue(result);\n        }\n\n        Events<Event> entrys2 = eventStore.tryGet(entrys1.getPositionRange().getEnd(), bufferSize);\n        System.out.println(\"second get size : \" + entrys2.getEvents().size());\n\n        eventStore.rollback();\n\n        entrys2 = eventStore.tryGet(entrys1.getPositionRange().getEnd(), bufferSize);\n        System.out.println(\"after rollback get size : \" + entrys2.getEvents().size());\n        Assert.assertTrue(entrys2.getEvents().size() == bufferSize);\n\n        first = eventStore.getFirstPosition();\n        lastest = eventStore.getLatestPosition();\n        List<Event> entrys = new ArrayList<>(entrys2.getEvents());\n        Assert.assertTrue(entrys.size() == bufferSize);\n        Assert.assertEquals(first, entrys2.getPositionRange().getStart());\n        Assert.assertEquals(lastest, entrys2.getPositionRange().getEnd());\n\n        Assert.assertEquals(first, CanalEventUtils.createPosition(entrys.get(0)));\n        Assert.assertEquals(lastest, CanalEventUtils.createPosition(entrys.get(bufferSize - 1)));\n        eventStore.stop();\n    }\n\n    @Test\n    public void testAck() {\n        int bufferSize = 16;\n        MemoryEventStoreWithBuffer eventStore = new MemoryEventStoreWithBuffer();\n        eventStore.setBufferSize(bufferSize);\n        eventStore.start();\n\n        for (int i = 0; i < bufferSize / 2; i++) {\n            boolean result = eventStore.tryPut(buildEvent(\"1\", 1L, 1L + i));\n            sleep(100L);\n            Assert.assertTrue(result);\n        }\n\n        sleep(50L);\n        Position first = eventStore.getFirstPosition();\n        Position lastest = eventStore.getLatestPosition();\n        Assert.assertEquals(first, CanalEventUtils.createPosition(buildEvent(\"1\", 1L, 1L)));\n        Assert.assertEquals(lastest, CanalEventUtils.createPosition(buildEvent(\"1\", 1L, 1L + bufferSize / 2 - 1)));\n\n        System.out.println(\"start get\");\n        Events<Event> entrys1 = eventStore.tryGet(first, bufferSize);\n        System.out.println(\"first get size : \" + entrys1.getEvents().size());\n\n        eventStore.cleanUntil(entrys1.getPositionRange().getEnd());\n        sleep(50L);\n\n        // 继续造数据\n        for (int i = bufferSize / 2; i < bufferSize; i++) {\n            boolean result = eventStore.tryPut(buildEvent(\"1\", 1L, 1L + i));\n            sleep(100L);\n            Assert.assertTrue(result);\n        }\n\n        Events<Event> entrys2 = eventStore.tryGet(entrys1.getPositionRange().getEnd(), bufferSize);\n        System.out.println(\"second get size : \" + entrys2.getEvents().size());\n\n        eventStore.rollback();\n\n        entrys2 = eventStore.tryGet(entrys1.getPositionRange().getEnd(), bufferSize);\n        System.out.println(\"after rollback get size : \" + entrys2.getEvents().size());\n\n        first = eventStore.getFirstPosition();\n        lastest = eventStore.getLatestPosition();\n        List<Event> entrys = new ArrayList<>(entrys2.getEvents());\n        // because doGet() contains the logic about whether include first event , so not to compare\n        //Assert.assertEquals(first, entrys2.getPositionRange().getStart());\n        Assert.assertEquals(lastest, entrys2.getPositionRange().getEnd());\n\n        // the reason same as above\n        //Assert.assertEquals(first, CanalEventUtils.createPosition(entrys.get(0)));\n        Assert.assertEquals(lastest, CanalEventUtils.createPosition(entrys.get(entrys.size() - 1)));\n\n        // 全部ack掉\n        eventStore.cleanUntil(entrys2.getPositionRange().getEnd());\n\n        // 最后就拿不到数据\n        Events<Event> entrys3 = eventStore.tryGet(entrys1.getPositionRange().getEnd(), bufferSize);\n        System.out.println(\"third get size : \" + entrys3.getEvents().size());\n        Assert.assertEquals(0, entrys3.getEvents().size());\n\n        eventStore.stop();\n    }\n\n}\n"
  }
]